Spring-boot全局异常处理解决方案

一、自定义返回结果类

考虑到不同项目差异,对于后端返回结果需求可能有细微不同,因此我们在设计返回结果类是应为可定制的,而HashMap正好具有这种特性。我们可以针对不同的项目需求,灵活地追加字段。

package com.example.jiakao.pojo.response;

import com.example.jiakao.common.enhance.Jsonable;

import java.util.HashMap;

public class R extends HashMap<String,Object> implements Jsonable {
    private static final String K_CODE = "code";
    private static final String K_MSG = "msg";
    private static final String K_DATA = "data";
    private static final int CODE_SUCCESS = 200;
    private static final int CODE_ERROR_DEFAULT = 400;
    public R setSuccess(){
        return setCode(CODE_SUCCESS);
    }
    public R setError(){
        return setCode(CODE_ERROR_DEFAULT);
    }
    public R setCode(int code){
        put(K_CODE, code);
        return this;
    }
    public R setMsg(String msg){
        put(K_MSG,msg);
        return this;
    }
    public R setData(Object data){
        put(K_DATA,data);
        return this;
    }

}

Jsonable接口提供一个通用序列化方法

package com.example.jiakao.common.enhance;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public interface Jsonable {
    default String json() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(this);
    }
}

定制项目返回结果类,项目返回结果通过Rs的静态方法进行构造,此处就可以对不同项目所需字段进行定制追加。如此处,我对异常接口追加一个method字段,用来记录接口路径。

package com.example.jiakao.common.util;

import com.example.jiakao.pojo.response.R;

public class Rs {
    private static final String DEFAULT_SUCCESS_MSG = "操作成功";
    private static final String DEFAULT_ERROR_MSG = "操作失败";
    private static final String K_METHOD = "method";

    public static R error(String method){
        R r = new R();
        r.put(K_METHOD, method);
        return r.setError().setMsg(DEFAULT_ERROR_MSG);
    }
    public static R error(String msg,String method){
        R r = new R();
        r.put(K_METHOD, method);
        return r.setError().setMsg(msg);
    }
    public static R error(int code, String msg,String method){
        R r = new R();
        r.put(K_METHOD, method);
        return r.setCode(code).setMsg(msg);
    }

    public static R ok(){
        return new R().setSuccess().setMsg(DEFAULT_SUCCESS_MSG);
    }
    public static R ok(String msg){
        return new R().setSuccess().setMsg(msg);
    }
    public static R ok(String msg, Object data){
        return new R().setSuccess().setMsg(msg).setData(data);
    }
    public static R ok(Object data){
        return new R().setSuccess().setMsg(DEFAULT_SUCCESS_MSG).setData(data);
    }
}

二、封装HttpException,便于异常捕获

package com.example.jiakao.Exception.http;

import lombok.Data;

@Data
public class HttpException extends RuntimeException {
    protected Integer code;
//    服务器内部错误
    protected Integer httpStatusCode = 500;
    public HttpException(int code) {
        this.code = code;
    }
}

常用的400、401、403、404都继承自HttpException设置对应的状态码。

package com.example.jiakao.Exception.http;

public class ArgumentsException extends HttpException {
    public ArgumentsException(int code) {
        super(code);
//        参数错误、请求出错
        this.httpStatusCode = 400;
    }
}
package com.example.jiakao.Exception.http;

public class UnauthorizedException extends HttpException{
    public UnauthorizedException(int code) {
        super(code);
//        未授权
        this.httpStatusCode = 403;
    }
}
package com.example.jiakao.Exception.http;

public class ForbiddenException extends HttpException{
    public ForbiddenException(int code) {
        super(code);
//        禁止访问
        this.httpStatusCode = 403;
    }
}
package com.example.jiakao.Exception.http;

public class NotFoundException extends HttpException{
    public NotFoundException(int code) {
        super(code);
//        资源不存在
        this.httpStatusCode = 404;
    }
}

三、编写异常code对应中文消息的properties文件,便于统一管理

# 通用异常状态码
exception.codes[400] = 请求出错
exception.codes[401] = 未授权
exception.codes[403] = 禁止访问
exception.codes[404] = 资源不存在
exception.codes[500] = 服务器内部错误

# 自定义异常码
exception.codes[40000] = 参数错误
exception.codes[40001] = 用户已存在

四、异常码消息读取注入类

用来读取自定义的异常消息,这样我们在抛出异常时,只需要传入code,就可以获取到对应的异常消息。

package com.example.jiakao.Exception.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@ConfigurationProperties(prefix = "exception")
@PropertySource(value = "classpath:config/exception-code.properties")
@Component
@Data
public class ExceptionCodeConfiguration {
    private Map<Integer,String> codes = new HashMap<>();

    public String getMessage(int code) {
        String message = codes.get(code);
        if(message == null){
            message = "未定义错误";
        }
        return message;
    }
}

五、全局异常捕获

这里对自定义的HttpException进行单独捕获处理,通过handleHttpException处理,对于不是HttpException的异常,用handleException方法进行统一处理。

package com.example.jiakao.Exception;

import com.example.jiakao.Exception.config.ExceptionCodeConfiguration;
import com.example.jiakao.Exception.http.HttpException;
import com.example.jiakao.common.util.Rs;
import com.example.jiakao.pojo.response.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
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;

@ControllerAdvice
public class GlobalExceptionAdvice {
    @Autowired
    private ExceptionCodeConfiguration codeConfiguration;

    @ExceptionHandler(value=Exception.class)
    @ResponseBody
    @ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
    public R handleException(HttpServletRequest req, Exception e) {
        e.printStackTrace();
        String reqUrl = req.getRequestURI();
        String method = req.getMethod();
        return Rs.error(9999,"未知异常",method + " " + reqUrl);
    }

    @ExceptionHandler(HttpException.class)
    public ResponseEntity<R> handleHttpException(HttpServletRequest req, HttpException e){
        String reqUrl = req.getRequestURI();
        String method = req.getMethod();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpStatus httpStatus = HttpStatus.resolve(e.getHttpStatusCode());
        ResponseEntity<R> r = new ResponseEntity<>(Rs.error(e.getCode(), codeConfiguration.getMessage(e.getCode()),method + " " + reqUrl), headers,httpStatus);
        return r;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33235279/article/details/129790624
今日推荐