一、前言

这个项目主要是使用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语句,这部分的难度不是很大,但是很需要注意细节。下面是在项目中遇到的一些问题:

  1. MySQL5.6之后,设置datetime类型的默认值不能为 ‘00-00-00 00:00:00’,需设置为大于1000的年数,使用高版本的MySQL需要注意;
  2. 在对应的Mapper文件中设置了对应函数后务必保证对应的XML文件中写了对应的SQL实现
  3. 数据库某表id字段忘记设置自增,出现错误:DataIntegrityViolationException异常
  4. 在使用自增主键的表的insert方法中,在对应的XM文件加入 keyProperty=“id” useGeneratedKeys="true"保证可以获取自增id
  5. 务必保证数据库字段、模型字段等名称的书写正确

异常处理

项目里使用了在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的使用