一、前言
这个项目主要是使用SpringBoot实现一个电商的秒杀功能,项目很简单,服务器使用的也是本地电脑,因为是使用了SpringBoot,其实对于想要学习SpringMVC或其他基础的同学来说其实并不合适。该项目的主要收获是从业务层面理解一下MVC的架构思想, 还有就是体会一下一些业务常见问题的解决方法。
课程地址:SpringBoot构建电商秒杀项目 仓库地址:SpringBoot构建电商秒杀项目
系统架构
各层数据的对应关系
一般一个对象在数据库中的存储形式是最单纯 的,领域模型和返回前端的模型可能会聚合一些其他的属性。以Item对象说,数据库中对Item的存储分了两个表,stock单独存为一个表,所有属性都是基本属性,而在业务层的ItemModel聚合了秒杀活动模型,返回前端的数据类型ItemVO聚合了秒杀活动的具体信息。
对象名 | 所属层级 | 字段名 |
ItemVO | 前端数据 | id、title、price、stock、description、sales、imgUrl、promoStatus、promoPrice、promoId、startDate |
ItemModel | 业务层 | id、title、price、stock、description、sales、promoModel |
ItemDO | 数据层 | id、title、price、description、sales |
ItemStockDO | 数据层 | id、itemId、stock |
接入层(Controller) & 业务层(Service)
接入层直接处理来自前端的请求,对数据的操作只在Model跟VO之间,不直接接触数据层的东西,所有涉及到数据库的操作都交给对应的Service去实现,业务层对数据的操作只在Model跟DO之间。这种分层的模型功能区分清晰,也保证了系统的扩展性,排查错误也比较方便。
数据层
数据层使用mybatis基本都是自动生成的DataObject、Mapper和XML文件,根据业务需求可能会需要加入或更改一些SQL语句,这部分的难度不是很大,但是很需要注意细节。下面是在项目中遇到的一些问题:
- MySQL5.6之后,设置datetime类型的默认值不能为 ‘00-00-00 00:00:00’,需设置为大于1000的年数,使用高版本的MySQL需要注意;
- 在对应的Mapper文件中设置了对应函数后务必保证对应的XML文件中写了对应的SQL实现
- 数据库某表id字段忘记设置自增,出现错误:DataIntegrityViolationException异常
- 在使用自增主键的表的insert方法中,在对应的XM文件加入 keyProperty=“id” useGeneratedKeys="true"保证可以获取自增id
- 务必保证数据库字段、模型字段等名称的书写正确
异常处理
项目里使用了在BaseController中定义handlerException方法来处理全局的异常,考虑到项目简单和其他Controller还要使用一个全局的变量(定义前端POST方法中数据的编码格式):
CONTENT_TYPE_FORMED="application/x-www-form-urlencoded"
其他Controller都继承BaseController这种处理可以接受。
一种更加方便的做法是:使用加强Controller做全局异常处理
所谓加强Controller就是@ControllerAdvice注解,有这个注解的类中的方法的某些注解会应用到所有的Controller里,其中就包括@ExceptionHandler注解。
@ControllerAdvice
public class BaseController {
//后端要消费的前端的数据类型,http请求post方法中提交的数据的编码格式
public static final String CONTENT_TYPE_FORMED="application/x-www-form-urlencoded";
/**
定义解决未被业务controller层吸收的exception
*/
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Object handlerException(HttpServletRequest request, Exception ex) {
Map<String, Object> responseData = new HashMap<>();
if (ex instanceof BusinessException) {
BusinessException businessException = (BusinessException)ex;
responseData.put("errCode", businessException.getErrCode());
responseData.put("errMsg", businessException.getErrMsg());
}else {
responseData.put("errCode", UNKNOWN_ERROR.getErrCode());
responseData.put("errMsg", UNKNOWN_ERROR.getErrMsg());
}
return CommonReturnType.create(responseData, "fail");
}
}
参考:Spring异常处理 ExceptionHandler的使用