SpringMVC的项目架构思想

一、DO和Model的区别

DO是对数据库表的映射。Model是处理业务逻辑的模型(领域模型)。例如:用户信息表和用户密码表分别是两个DO,但是对于实体用户来说,密码表的字段也属于用户,所以需要在Service层使用Model来处理业务逻辑,Model包含了两张表的字段的并集。在Mapper层使用DO,在Service层使用Model。

public class UserDO {
    private Integer id;
    private String name;
    private Boolean gender;
    private Integer age;
    private String telphone;
    private String registerType;
    private String thirdPartyId;
    //getter、setter
public class UserPasswordDO {
    private Integer id;
    private String encrptPassword;
    private Integer userId;
    //getter、setter

二、VO和Model的区别

VO(View Object视图对象),用于前端展示。Model中包含了用户的密码数据,不应该通过Controller层返回给前端,这是不安全的操作。在Controller层通过VO返回部分可以展示到前端的数据即可。

public class UserModel {
    private Integer id;
    private String name;
    private Boolean gender;
    private Integer age;
    private String telphone;
    private String registerMode;
    private String thirdPartyId;
    private String encrptPassword;
    //getter、setter
public class UserVO {
    private Integer id;
    private String name;
    private Boolean gender;
    private Integer age;
    private String telphone;
    //getter、setter

三、层次结构

  1. dao层:定义XXXMapper接口、对应的XXXMapper.xml在resource目录下的mapper文件夹里,使用数据模型DO(Data Object)

  2. service层:定义XXXService接口、实现类XXXServiceImpl、领域模型Model

    @Service
    public class UserServiceImpl implements UserService {
    ​
        @Autowired
        private UserDOMapper userDOMapper;
        @Autowired
        private UserPasswordDOMapper userPasswordDOMapper;
    ​
        @Override
        public UserModel getUserById(Integer id) {
            UserDO userDO = userDOMapper.selectByPrimaryKey(id);
            if (userDO == null) {
                return null;
            }
            UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUid(userDO.getId());
            return covertFromDataObject(userDO, userPasswordDO);
        }
    ​
        private UserModel covertFromDataObject(UserDO userDO, UserPasswordDO userPasswordDO) {
            if (userDO == null) {
                return null;
            }
            UserModel userModel = new UserModel();
            BeanUtils.copyProperties(userDO, userModel);
            if (userPasswordDO != null) {
                userModel.setEncrptPassword(userPasswordDO.getEncrptPassword());
            }
            return userModel;
        }
    }
  3. controller层:定义XXXController类、视图模型VO(View Object)

    @RestController("user")
    @RequestMapping("/user")
    public class UserController {
        @Autowired
        private UserService userService;
    ​
        @RequestMapping("/get")
        public UserVO getUser(@RequestParam(name = "id") Integer id){
            UserModel userModel = userService.getUserById(id);
            //将核心的领域模型对象转化为可供UI使用的VO
            return convertFromModel(userModel);
        }
    ​
        private UserVO convertFromModel(UserModel userModel){
            if(userModel == null){
                return null;
            }
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(userModel, userVO);
            return userVO;
        }
    }

四、归一化Controller层的响应信息

  1. 定义一个公共的返回值类型

    public class CommonReturnType {
        //处理结果 success/fail
        //fail 返回通用的错误码格式
        //success 返回数据
        private String status;
        private Object data;
    ​
        public static CommonReturnType create(Object result, String status) {
            CommonReturnType returnType = new CommonReturnType();
            returnType.setStatus(status);
            returnType.setData(result);
            return returnType;
        }
    ​
        public static CommonReturnType create(Object result) {
            return CommonReturnType.create(result, "success");
        }
    ​
        public String getStatus() {
            return status;
        }
    ​
        public void setStatus(String status) {
            this.status = status;
        }
    ​
        public Object getData() {
            return data;
        }
    ​
        public void setData(Object data) {
            this.data = data;
        }
    }
  2. 在Controller层返回CommonResultType

    @RequestMapping("/get")
    public CommonReturnType getUser(@RequestParam(name = "id") Integer id){
        UserModel userModel = userService.getUserById(id);
        //将核心的领域模型对象转化为可供UI使用的VO
        UserVO userVO =  convertFromModel(userModel);
        //返回通用对象
        return CommonReturnType.create(userVO);
    }
  3. 前端得到的返回正确的结果

    {
        "status":"success",
        "data":{
            "id":1,
            "name":"张三",
            "gender":false,
            "age":12,
            "telphone":"123456"
        }
    }
  4. 异常结果的处理(见下一Part)

五、 包装器业务异常类的实现

  1. 定义一个公共错误接口/error

    public interface CommonError {
        public int getErrCode();
        public String getErrMsg();
        public CommonError setErrMsg(String errMsg);
    }
  2. 定义一个枚举错误类/error

    public enum EmBusinessError implements CommonError {
        //通用错误类型 00001
        PARAMETER_VALIDATION_ERROR(00001,"参数不合法"),
        //用户信息相关 1000X
        USER_NOT_EXIST(10001,"用户不存在")
        //
        ;
        private EmBusinessError(int errCode, String errMsg){
            this.errCode = errCode;
            this.errMsg = errMsg;
        }
        private int errCode;
        private String errMsg;
        @Override
        public int getErrCode() {
            return this.errCode;
        }
    ​
        @Override
        public String getErrMsg() {
            return this.errMsg;
        }
    ​
        @Override
        public CommonError setErrMsg(String errMsg) {
            this.errMsg = errMsg;
            return this;
        }
    }
  3. 定义异常包装类/exception

    //包装器业务异常类的实现
    public class BusinessException extends Exception implements CommonError {
        private CommonError commonError;
    ​
        //直接接收EmBusinessError的传参用于构造业务异常
        public BusinessException(CommonError commonError){
            super();
            this.commonError = commonError;
        }
    ​
        //接收自定义errMsg的方式构造业务异常
        public BusinessException(CommonError commonError, String errMsg){
            super();
            this.commonError = commonError;
            this.commonError.setErrMsg(errMsg);
        }
        @Override
        public int getErrCode() {
            return this.commonError.getErrCode();
        }
    ​
        @Override
        public String getErrMsg() {
            return this.commonError.getErrMsg();
        }
    ​
        @Override
        public CommonError setErrMsg(String errMsg) {
            this.commonError.setErrMsg(errMsg);
            return this;
        }
    }
  4. 在Controller层抛出异常

    @RequestMapping("/get")
    public CommonReturnType getUser(@RequestParam(name = "id") Integer id) throws BusinessException {
        UserModel userModel = userService.getUserById(id);
        if(userModel == null){
            throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
        }
        //将核心的领域模型对象转化为可供UI使用的VO
        UserVO userVO =  convertFromModel(userModel);
        //返回通用对象
        return CommonReturnType.create(userVO);
    }

六、异常的处理

  1. 定义exceptionHandler解决未被Controller层吸收的exception

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.OK)
    public Object handlerException(HttpServletRequest request, Exception ex){
        BusinessException businessException = (BusinessException) ex;
        CommonReturnType commonReturnType = new CommonReturnType();
        commonReturnType.setStatus("fail");
        Map<String, Object> responseData = new HashMap<>();
        responseData.put("errCode",businessException.getErrCode());
        responseData.put("errMsg",businessException.getErrMsg());
        commonReturnType.setData(responseData);
        return commonReturnType;
    }
  2. 前端得到的JSON数据

    {"status":"fail",
     "data":{
         "errCode":10001,
         "errMsg":"用户不存在"
     }
    }
  3. 优化异常处理,定义BaseController,其余Controller继承基类。

    @RestController
    public class BaseController {
        @ExceptionHandler(Exception.class)
        @ResponseStatus(HttpStatus.OK)
        public Object handlerException(HttpServletRequest request, Exception ex){
            Map<String, Object> responseData = new HashMap<>();
            if(ex instanceof BusinessException){
                BusinessException businessException = (BusinessException) ex;
                CommonReturnType commonReturnType = new CommonReturnType();
                commonReturnType.setStatus("fail");
                responseData.put("errCode",businessException.getErrCode());
                responseData.put("errMsg",businessException.getErrMsg());
            }
            else{
                responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
                responseData.put("errMsg",EmBusinessError.UNKNOWN_ERROR.getErrMsg());
            }
            return CommonReturnType.create(responseData,"fail");
        }
    }
07-03 17:09