首页 java

Spring Boot如何优雅实现结果统一封装和异常统一处理

发布于: 2024-04-29

Lombok(Project Lombok)是一个用于 Java 编程语言的开源库,旨在减少 Java 代码中的冗余和样板代码,提高开发人员的生产力。它通过使用注解来自动生成 Java 类的常见方法和代码,从而使开发人员能够编写更简洁、更具可读性和更易维护的代码。Lombok 的主要目标是简化 Java 开发,减少样板代码,使代码更加精炼,从而提高开发效率。

它利用注解方式自动生成 java bean 中 getter、setter、equals 等方法,还能自动生成 logger、toString、hashCode、builder 等 日志相关变量、Object 类方法或设计模式相关的方法,能够让你的 代码更简洁,更美观。

https://github.com/projectlombok/lombok

https://projectlombok.org/

依赖下载

1
2
3
4
5
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>

使用以下方式注意代码目录,并把需要的包进行导入

定义返回统一结构体ResponseVO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;

@Data
@AllArgsConstructor
public class ResponseVO<T> implements Serializable {
private Integer code;
private String Message;
private T data;
public ResponseVO(Integer code, String message) {
this.code = code;
this.Message = message;
}
public static <T> ResponseVO<T> success(T data) {
return new ResponseVO<>(0, "success", data);
}
public static <T> ResponseVO<T> error( String message) {
return new ResponseVO<>(1, message, null);
}
}

定义一个注解@ResponseResultBody

1
2
3
4
5
6
7
8
9
10
11
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//可以标识类上也可以标识在方法上
@Target({ElementType.TYPE, ElementType.METHOD})
//运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface ResponseResultBody {
}

实现统一结果封装ResponseBodyAdvice

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

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class ResponseBodyAdvice implements org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object> {
@Override
@SuppressWarnings("all")
//是否支持advice功能
//true 支持,false 不支持
public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
// 拿到类声明,判断是否被IgnoreResponseAdvice进行标识
if (methodParameter.getDeclaringClass().isAnnotationPresent(ResponseResultBody.class)) {
return false;
}
if (methodParameter.getMethod().isAnnotationPresent(ResponseResultBody.class)) {
return false;
}
return true;
}

@Override
@SuppressWarnings("all")
//对返回的数据进行处理
public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
ResponseVO<Object> response = ResponseVO.success("");
if (o == null) {
return response;
} else if (o instanceof ResponseVO) {
response = (ResponseVO<Object>) o;
} else {
response.setData(o);
}
return response;
}
}

全局异常统一处理

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
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
@Slf4j
public class ExceptionResponseHandler {
@ExceptionHandler(value = Exception.class)
public ResponseVO<String> handlerException(HttpServletRequest req, Exception e) {
//自定义异常
if (e instanceof BusinessException) {
BusinessException bizException = (BusinessException) e;
ResponseVO<String> response = ResponseVO.withCodeMessage(bizException.getCode(),bizException.getMessage());
response.setData(e.getMessage());
return response;
} else if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException methodArgumentNotValidException = (MethodArgumentNotValidException) e;
Map<String, String> map = new HashMap<>();
BindingResult result = methodArgumentNotValidException.getBindingResult();
result.getFieldErrors().forEach((item) -> {
String message = item.getDefaultMessage();
String field = item.getField();
map.put(field, message);
});
log.error("数据校验出现错误:", e);
return ResponseVO.error(map.toString());
} else if (e instanceof HttpRequestMethodNotSupportedException) {
return ResponseVO.error("请求方法不正确");
} else if (e instanceof MissingServletRequestParameterException) {
log.error("请求参数缺失:", e);
MissingServletRequestParameterException ex = (MissingServletRequestParameterException) e;
return ResponseVO.error("请求参数缺少: " + ex.getParameterName());
} else if (e instanceof MethodArgumentTypeMismatchException) {
log.error("请求参数类型错误:", e);
MethodArgumentTypeMismatchException ex = (MethodArgumentTypeMismatchException) e;
return ResponseVO.error("请求参数类型不正确:" + ex.getName());
} else if (e instanceof NoHandlerFoundException) {
NoHandlerFoundException ex = (NoHandlerFoundException) e;
log.error("请求地址不存在:", e);
return ResponseVO.error(ex.getRequestURL());
} else {
ResponseVO<String> response = ResponseVO.error("The server has run away");
response.setData(e.getMessage());
return response;
}
}
}

统一响应下划线配置

1
2
3
4
spring:
# 设置响应返回数据统一为下划线
jackson:
property-naming-strategy: SNAKE_CASE