本文最后更新于:September 2, 2022 pm
SpringBoot框架中有两个非常重要的策略:开箱即用和约定优于配置。其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。
目录
统一返回结果类
返回状态码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.tothefor.DBTest;
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString;
@Getter @AllArgsConstructor @NoArgsConstructor @ToString public enum RCode {
SUCCESS(200, "成功"),
FAIL(500, "失败"),
;
private Integer code;
private String message;
}
|
统一返回结果类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
| package com.tothefor.DBTest;
import lombok.*;
import java.io.Serializable;
@Data @Builder @AllArgsConstructor @NoArgsConstructor @ToString public class R<T> implements Serializable {
private Boolean success; private Integer code; private String message;
private long timestamp;
private T data;
public static <T> R<T> SUCCESS() { return SUCCESS(null); }
public static <T> R<T> SUCCESS(T data) { return R.<T>builder().data(data) .success(true) .code(RCode.SUCCESS.getCode()) .message(RCode.SUCCESS.getMessage()) .timestamp(System.currentTimeMillis()) .build(); }
public static <T extends Serializable> R<T> FAIL() { return FAIL(null); }
public static <T> R<T> FAIL(T data) { return R.<T>builder().data(data) .success(false) .code(RCode.FAIL.getCode()) .message(RCode.FAIL.getMessage()) .timestamp(System.currentTimeMillis()) .build(); }
public static <T> R<T> FAIL(Integer code, String msg) { return FAIL(code, msg, null); }
public static <T> R<T> FAIL(Integer code, String msg, T data) { return R.<T>builder().data(data) .success(false) .code(code) .message(msg) .timestamp(System.currentTimeMillis()) .build(); }
}
|
全局异常处理
异常状态码接口(*)
这作为一个异常状态码的父类,如果需要自定义异常状态码,建议实现此接口。(面向接口编程)当然了,也可以根据自己的需要不要此接口也是可以的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.tothefor.DBTest;
public interface BizError {
default BizError of(int code,String msg){ return new BizError() { @Override public int code() { return code; }
@Override public String exception() { return msg; } }; }
int code(); String exception(); }
|
自定义异常状态码
自定义异常状态码时建议单独定义枚举类实现异常状态码接口 (BizError)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.tothefor.DBTest;
import lombok.AllArgsConstructor;
@AllArgsConstructor public enum BizErrors implements BizError { ERROR_SYSTEM(1000000,"系统异常"), ;
int code;
String exception;
@Override public int code() { return code; }
@Override public String exception() { return exception; } }
|
自定义异常处理类
自定义异常通常是继承RuntimeException。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.tothefor.DBTest;
import lombok.Data;
@Data public class BizErrorException extends RuntimeException{ private int code; private String exception;
public BizErrorException(BizError errors) { this.code = errors.code(); this.exception = errors.exception(); } }
|
通过提供的异常状态码将其封装成一个自定义异常类。
添加自定义异常处理到全局异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.tothefor.DBTest;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice public class GlobalExceptionHandler {
@ExceptionHandler(BizErrorException.class) public BizErrorException handler(BizErrorException e, HttpServletRequest request){ return e; } }
|
需要注意的是:这里的异常捕获返回值根据个人情况!!但是在后面处理判断Controller类的返回结果时(beforeBodyWrite),需要修改为这里的返回值!
统一封装Controller结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.tothefor.DBTest;
import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice(basePackages = "com.tothefor.DBTest") public class ResponseBody implements ResponseBodyAdvice<Object> {
@Autowired private ObjectMapper objectMapper;
@Override public boolean supports(MethodParameter methodParameter, Class aClass) { return true; }
@SneakyThrows @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { if(o==null){ return R.SUCCESS(); } if(o instanceof BizErrorException){ BizErrorException eO = (BizErrorException) o; return R.FAIL(eO.getCode(),eO.getException()); } if(o instanceof String){ return objectMapper.writeValueAsString(R.SUCCESS(o)); } return R.SUCCESS(o); } }
|
ControllerAdvice中的值表示要拦截的Controller,必须要写,否则不会生效!!!
实现ResponseBodyAdvice接口,其实是对加了@RestController(也就是@Controller+@ResponseBody)注解的处理器将要返回的值进行增强处理。其实也就是采用了AOP的思想,对返回值进行一次修改。
使用示例
| @RequestMapping("/gete") public int gete(){ int i =0; try { i/=0; }catch (Exception e){ throw new BizErrorException(BizErrors.ERROR_SYSTEM); } return i; }
|