统一返回对象和异常处理(二)

1,574 阅读3分钟
统一返回对象类型
package com.miaosha.response;

public class CommonReturnType {
    //表明对应请求的返回处理结果"success"或"fail"
    private String status;
    //若status=success,则data内为前端需要的json数据
    //若status=fail,则data使用通用的错误码格式
    private Object data;

    //定义一个通用的创建方法
    //返回正确信息
    public static CommonReturnType create(Object result){
        return CommonReturnType.create(result,"success");
    }

    //返回错误信息,这里的result为通用错误信息
    public static CommonReturnType create(Object result,String status){
        CommonReturnType type = new CommonReturnType();
        type.setStatus(status);
        type.setData(result);
        return  type;
    }

    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;
    }
}

使用例:

return CommonReturnType.create(itemVO);//成功,有返回信息
return CommonReturnType.create(null);//成功,无返回信息
return CommonReturnType.create(responseData,"fail");//失败,返回错误信息
统一返回错误信息

包装器业务异常类实现:BusinessException和EmBusinessError共同继承CommonError,以至于外部不仅可以通过new EmBusinessError或new BusinessException都可以有errCode、errMsg对应的组装定义,并且共同实现了一个setErrMsg方法,可以用于将原本EmBusinessError中定义的errMsg给覆盖掉。

上代码:

package com.miaosha.error;

public interface CommonError {
    public int getErrCode();
    public String getErrMsg();
    public CommonError serErrMsg(String errMsg);
}
package com.miaosha.error;

public enum EmBusinessError implements CommonError {
    //通用错误类型10001
    PARAMETER_VALIDATION_ERROR(10001,"参数不合法"),
    UNKNOW_ERROR(10002,"未知错误"),

    //20000开头为用户信息相关错误定义
    USER_NOT_EXIST(20001,"用户不存在"),
    USER_LOGIN_FAIL(20002,"用户手机号或密码不正确"),
    USER_NOT_LOGIN(20003,"用户还未登录"),

    //30000开头为交易信息错误定义
    STOCK_NOT_ENOUGH(30001,"库存不足"),
    ;

    //构造函数
    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 serErrMsg(String errMsg) {
        this.errMsg = errMsg;
        return this;
    }
}
package com.miaosha.error;

//包装器业务异常类实现
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.serErrMsg(errMsg);
    }

    @Override
    public int getErrCode() {
        return this.commonError.getErrCode();
    }

    @Override
    public String getErrMsg() {
        return this.commonError.getErrMsg();
    }

    @Override
    public CommonError serErrMsg(String errMsg) {//用来更改通用错误类型的错误信息
        this.commonError.serErrMsg(errMsg);
        return this;
    }
}

使用用户注册服务实现为例:

	@Override
    @Transactional
    public void register(UserModel userModel) throws BusinessException {
        if (userModel==null){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
        }
        ValidationResult result = validator.validate(userModel);
        if (result.isHasErrors()){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,result.getErrMsg());
        }

目前new出来的BusinessException直接被抛到Tomcat的容器层,Tomcat的容器层对应处理这样一个异常的方式为返回500的错误页。

有没有一种机制可以拦截掉对应Tomcat的异常处理的方式,然后去解决掉对应的问题?

这里使用Spring Boot自带的一个Spring MVC的handlerException去解决这个问题。

异常处理

定义exceptionhandler解决未被controller层吸收的exception(为业务逻辑处理上的问题或业务逻辑错误而并非服务端不能处理的错误)

package com.miaosha.controller;

import com.miaosha.error.BusinessException;
import com.miaosha.error.EmBusinessError;
import com.miaosha.response.CommonReturnType;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

public class BaseController {
    //定义exceptionhandler解决未被controller层吸收的exception(为业务逻辑处理上的问题或业务逻辑错误而并非服务端不能处理的错误)
    @ExceptionHandler(Exception.class)//需要指明收到什么样的exception之后才会进入它的处理环节,此处定义为根类
    @ResponseStatus(HttpStatus.OK)//捕获到controller抛出的exception,并返回HttpStatus.OK,即status=200
    @ResponseBody //handler exception使用这种方式(Object会寻找本地页面文件)仅仅只能返回页面路径,无法处理viewobject类对应的@ResponseBody形式,加上@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", EmBusinessError.UNKNOW_ERROR.getErrCode());
            responseData.put("errMsg",EmBusinessError.UNKNOW_ERROR.getErrMsg());
        }
        return CommonReturnType.create(responseData,"fail");
    }
}

其作为所有Controller的公用逻辑,所以所有Controller都要继承它。

参考:

慕课课程《SpringBoot构建电商基础秒杀项目》

推荐刚入手SpringBoot的同学观看,老师基础讲的特别好