feat(common): add exception handling and response utilities
backend project initial!!!
This commit is contained in:
@@ -15,4 +15,6 @@ dependencies {
|
||||
implementation("com.fasterxml.jackson.core:jackson-core")
|
||||
// aop
|
||||
implementation("org.springframework.boot:spring-boot-starter-aop")
|
||||
// web
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.hanserwei.common.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.TimeZone;
|
||||
|
||||
@Configuration
|
||||
public class JacksonConfig {
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
// 初始化一个 ObjectMapper 对象,用于自定义 Jackson 的行为
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// 忽略未知字段(前端有传入某个字段,但是后端未定义接受该字段值,则一律忽略掉)
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
|
||||
// JavaTimeModule 用于指定序列化和反序列化规则
|
||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
||||
|
||||
// 支持 LocalDateTime、LocalDate、LocalTime
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
|
||||
|
||||
objectMapper.registerModule(javaTimeModule);
|
||||
|
||||
// 设置时区
|
||||
objectMapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
|
||||
// 设置凡是为 null 的字段,返参中均不返回,请根据项目组约定是否开启
|
||||
// objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.hanserwei.common.enums;
|
||||
|
||||
import com.hanserwei.common.exception.BaseExceptionInterface;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ResponseCodeEnum implements BaseExceptionInterface {
|
||||
|
||||
// ----------- 通用异常状态码 -----------
|
||||
SYSTEM_ERROR("10000", "出错啦,后台小哥正在努力修复中..."),
|
||||
PARAM_NOT_VALID("10001", "参数错误"),
|
||||
|
||||
// ----------- 业务异常状态码 -----------
|
||||
;
|
||||
|
||||
// 异常码
|
||||
private final String errorCode;
|
||||
// 错误信息
|
||||
private final String errorMsg;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.hanserwei.common.exception;
|
||||
|
||||
public interface BaseExceptionInterface {
|
||||
String getErrorCode();
|
||||
|
||||
String getErrorMsg();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hanserwei.common.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class BizException extends RuntimeException {
|
||||
// 异常码
|
||||
private String errorCode;
|
||||
// 错误信息
|
||||
private String errorMsg;
|
||||
|
||||
public BizException(BaseExceptionInterface baseExceptionInterface) {
|
||||
this.errorCode = baseExceptionInterface.getErrorCode();
|
||||
this.errorMsg = baseExceptionInterface.getErrorMsg();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.hanserwei.common.exception;
|
||||
|
||||
import com.hanserwei.common.enums.ResponseCodeEnum;
|
||||
import com.hanserwei.common.utils.Response;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@ControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 捕获自定义业务异常
|
||||
*
|
||||
* @return 错误信息
|
||||
*/
|
||||
@ExceptionHandler({BizException.class})
|
||||
@ResponseBody
|
||||
public Response<Object> handleBizException(HttpServletRequest request, BizException e) {
|
||||
log.warn("{} request fail, errorCode: {}, errorMessage: {}", request.getRequestURI(), e.getErrorCode(), e.getErrorMsg());
|
||||
return Response.fail(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 其他类型异常
|
||||
*
|
||||
* @param request 请求
|
||||
* @param e 异常
|
||||
* @return 错误信息
|
||||
*/
|
||||
@ExceptionHandler({Exception.class})
|
||||
@ResponseBody
|
||||
public Response<Object> handleOtherException(HttpServletRequest request, Exception e) {
|
||||
log.error("{} request error, ", request.getRequestURI(), e);
|
||||
return Response.fail(ResponseCodeEnum.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获参数校验异常
|
||||
*
|
||||
* @return 错误信息
|
||||
*/
|
||||
@ExceptionHandler({MethodArgumentNotValidException.class})
|
||||
@ResponseBody
|
||||
public Response<Object> handleMethodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException e) {
|
||||
// 参数错误异常码
|
||||
String errorCode = ResponseCodeEnum.PARAM_NOT_VALID.getErrorCode();
|
||||
|
||||
// 获取 BindingResult
|
||||
BindingResult bindingResult = e.getBindingResult();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// 获取校验不通过的字段,并组合错误信息,格式为: email 邮箱格式不正确, 当前值: '123124qq.com';
|
||||
Optional.of(bindingResult.getFieldErrors()).ifPresent(errors -> errors.forEach(error ->
|
||||
sb.append(error.getField())
|
||||
.append(" ")
|
||||
.append(error.getDefaultMessage())
|
||||
.append(", 当前值: '")
|
||||
.append(error.getRejectedValue())
|
||||
.append("'; ")
|
||||
));
|
||||
|
||||
// 错误信息
|
||||
String errorMessage = sb.toString();
|
||||
|
||||
log.warn("{} request error, errorCode: {}, errorMessage: {}", request.getRequestURI(), errorCode, errorMessage);
|
||||
|
||||
return Response.fail(errorCode, errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.hanserwei.common.utils;
|
||||
|
||||
import com.hanserwei.common.exception.BaseExceptionInterface;
|
||||
import com.hanserwei.common.exception.BizException;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class Response<T> implements Serializable {
|
||||
|
||||
// 是否成功,默认为 true
|
||||
private boolean success = true;
|
||||
// 响应消息
|
||||
private String message;
|
||||
// 异常码
|
||||
private String errorCode;
|
||||
// 响应数据
|
||||
private T data;
|
||||
|
||||
// =================================== 成功响应 ===================================
|
||||
public static <T> Response<T> success() {
|
||||
return new Response<>();
|
||||
}
|
||||
|
||||
public static <T> Response<T> success(T data) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setData(data);
|
||||
return response;
|
||||
}
|
||||
|
||||
// =================================== 失败响应 ===================================
|
||||
public static <T> Response<T> fail() {
|
||||
Response<T> response = new Response<>();
|
||||
response.setSuccess(false);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(String errorMessage) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setSuccess(false);
|
||||
response.setMessage(errorMessage);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(String errorCode, String errorMessage) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setSuccess(false);
|
||||
response.setErrorCode(errorCode);
|
||||
response.setMessage(errorMessage);
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(BizException bizException) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setSuccess(false);
|
||||
response.setErrorCode(bizException.getErrorCode());
|
||||
response.setMessage(bizException.getErrorMsg());
|
||||
return response;
|
||||
}
|
||||
|
||||
public static <T> Response<T> fail(BaseExceptionInterface baseExceptionInterface) {
|
||||
Response<T> response = new Response<>();
|
||||
response.setSuccess(false);
|
||||
response.setErrorCode(baseExceptionInterface.getErrorCode());
|
||||
response.setMessage(baseExceptionInterface.getErrorMsg());
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user