一、常见场景
目前主流开发方式都是前后端分离的,定义一种统一的返回格式,在前后端进行沟通时是非常有必要的,减少大家的沟通成本,大家基于这个约定去理解,出现问题能够快速定位。 格式统一规范,也是减少联调挨骂的基本保障。接下来就介绍一下如何优雅实现统一的】、响应对象。
二、统一的响应对象一般包括哪些字段呢,根据我之前的项目经验,一般有以下几个字段,如下所示:
{
"code": 0,
"message": "成功",
"detailMessage": "成功",
"data": true,
"traceId": "8bca519e60b35b",
"spanId": "1540451004024094720",
"env": "dev"
}
code: 返回结果的状态码,通常都是6位,比如A业务:100000-199999,B业务:200000-299999,C业务:300000-399999,不同的数字开头代表不同的业务
message: 返回结果的描述消息,展示给用户看的
detailMessage: 内部开发人员看的消息(详细的错误信息,主要方便问题定位)
data: 返回给调用方的业务数据(通常都是json数据)
traceId: 分布式链路跟踪-traceId(通常与日志平台结合使用)
spanId: 分布式链路跨度-spanId,spanId组合在一起就是整个链路的trace
env: 当前服务部署的环境(比如dev、sit、uat、prod)
三、实现方案及实现步骤
1、定义一个通用的统一返回码接口:IRespResultCode.java,接口里面规范子类对象要实现的方法,例如:getCode(),getMessage(),getDetailMessage()。
2、定义一个通用的统一返回码对象:RespResultCode.java实现IRespResultCode接口 ,主要放通用的返回结果信息,例如:请求成功、系统异常、网络异常、参数不合法等信息。
3、定义一个处理返回结果的工具类RespResult.java,定义一些通用的返回结果的方法,例如返回成功结果的success方法、返回失败结果的error方法。
4、封装业务异常类BusinessException.java,继承运行时异常,业务层出现一些逻辑的错误可以抛出BusinessException异常。
5、定义通过全局异常拦截器GlobalExceptionHandler拦截各类异常,对返回结果的code和message做二次加工。
5.1 Springboot的全局异常查是通过两个注解@RestControllerAdvice和@ExceptionHandler来实现的。只有代码出错或者throw出来的异常才会被捕捉处理,如果被catch的异常,就不会被捕捉,除非catch之后再throw异常。@RestControllerAdvice:增强型控制器,对于控制器的全局配置放在同一个位置,全局异常的注解,放在类上。@RestControllerAdvice默认只会处理controller层抛出的异常,如果需要处理service层的异常,需要定义一个自定义的MyException来继承RuntimeException类,然后@ExceptionHandler(MyException.class)即可。
5.2 @ExceptionHandler:指明需要处理的异常类型以及子类。注解放在方法上面。
5.3 一般对业务方法,比如controller层返回的code通常有两种做法:
1)返回http code 200,对所有异常进行捕获,返回的message二次加工展示给调用方。
2)返回不同的http code,通过ResponseStatus对象控制不同的异常展示不同的status code。不好的地方,status code比较有限,使用起来不是很方便。GlobalExceptionHandler处理异常规则是:
.@ExceptionHandler(RuntimeException.class): 会先查看异常是否属于RuntimeException异常以及其子类,如果是的话,就用这个方法进行处理。
. 一个方法处理多个异常类的异常: @ExceptionHandler(value = {Exception.class, Throwable.class})
. 有多个@ExceptionHandler注解的方法时,会根据抛出异常类去寻找处理方法, 如果没有,就往上找父类,直到找到为止。
四、代码案例
controller层
package com.litian.dancechar.core.biz.blacklist.controller;
import com.litian.dancechar.core.biz.blacklist.conf.EnvConfig;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListAddOrEditDTO;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListReqDTO;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListRespDTO;
import com.litian.dancechar.core.biz.blacklist.service.SysBlackListService;
import com.litian.dancechar.framework.common.base.PageWrapperDTO;
import com.litian.dancechar.framework.common.base.RespResult;
import com.litian.dancechar.framework.common.validator.ValidatorUtil;
import com.litian.dancechar.framework.common.validator.groups.Update;
import com.litian.dancechar.framework.cache.redis.constants.LockConstant;
import com.litian.dancechar.framework.cache.redis.distributelock.annotation.Lock;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 黑名单地址业务处理
*
* @author kyle0432
* @date 2024/03/06 11:17
*/
@Api(tags = "黑名单相关api")
@RestController
@Slf4j
@RequestMapping(value = "/sys/blacklist/")
public class SysBlackListController {
@Resource
private SysBlackListService sysBlackListService;
@Resource
private EnvConfig envConfig;
@ApiOperation(value = "分页查询黑名单列表", notes = "分页查询黑名单列表")
@PostMapping("listPaged")
public RespResult<PageWrapperDTO<SysBlackListRespDTO>> listPaged(@RequestBody SysBlackListReqDTO req) {
return sysBlackListService.listPaged(req);
}
@ApiOperation(value = "查询黑名单列表", notes = "查询黑名单列表")
@PostMapping("findList")
public RespResult<List<SysBlackListRespDTO>> findList(@RequestBody SysBlackListReqDTO req) {
return sysBlackListService.findList(req);
}
@ApiOperation(value = "新增黑名单保存", notes = "新增黑名单保存")
@PostMapping("add")
@Lock(keyPrefix = "mybatis/actinfo", lockFailMsg = LockConstant.REPEATED_SUBMIT, value = "#req.reqUrl")
public RespResult<Boolean> add(@Validated @RequestBody SysBlackListAddOrEditDTO req) {
log.info("进入新增黑名单....");
return sysBlackListService.save(req);
}
@ApiOperation(value = "修改黑名单保存", notes = "修改黑名单保存")
@PostMapping("update")
public RespResult<Boolean> update(@RequestBody SysBlackListAddOrEditDTO req) {
log.info("进入修改黑名单....");
ValidatorUtil.validate(req, Update.class);
return sysBlackListService.save(req);
}
}
service层
package com.litian.dancechar.core.biz.blacklist.service;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.litian.dancechar.core.biz.blacklist.dao.entity.SysBlackListDO;
import com.litian.dancechar.core.biz.blacklist.dao.inf.SysBlackListDao;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListAddOrEditDTO;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListReqDTO;
import com.litian.dancechar.core.biz.blacklist.dto.SysBlackListRespDTO;
import com.litian.dancechar.core.init.ThreadPoolInit;
import com.litian.dancechar.framework.common.base.PageWrapperDTO;
import com.litian.dancechar.framework.common.base.RespResult;
import com.litian.dancechar.framework.common.util.DCBeanUtil;
import com.litian.dancechar.framework.common.util.PageResultUtil;
import com.litian.dancechar.framework.encrypt.util.EncryptUtil;
import com.litian.dancechar.framework.cache.redis.util.RedisHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
/**
* 黑名单请求url服務
*
* @author kyle0432
* @date 2024/03/06 13:13
*/
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class SysBlackListService {
@Resource
private SysBlackListDao sysBlackListDao;
@Resource
private RedisHelper redisHelper;
/**
* 功能: 分页查询黑名单列表
*/
public RespResult<PageWrapperDTO<SysBlackListRespDTO>> listPaged(SysBlackListReqDTO req) {
PageHelper.startPage(req.getPageNo(), req.getPageSize());
PageWrapperDTO<SysBlackListRespDTO> pageCommon = new PageWrapperDTO<>();
PageResultUtil.setPageResult(EncryptUtil.handleDecryptList(sysBlackListDao.findList(req)), pageCommon);
redisHelper.set("hello", "sgsg");
System.out.println(redisHelper.get("hello"));
for(int i=0; i<5;i++){
ThreadPoolInit.getThreadPoolTaskExecutor().execute(()->{
log.info("验证黑名单异步traceId不丢失");
});
}
return RespResult.success(pageCommon);
}
/**
* 功能:查询黑名单列表
*/
public RespResult<List<SysBlackListRespDTO>> findList(SysBlackListReqDTO req) {
return RespResult.success(sysBlackListDao.findList(req));
}
/**
* 保存黑名单(新增或修改)
*
* @param req 黑名单对象
* @return 保存结果
*/
public RespResult<Boolean> save(SysBlackListAddOrEditDTO req) {
if (StrUtil.isNotEmpty(req.getId())) {
SysBlackListDO sysBlackListDO = sysBlackListDao.selectById(req.getId());
if (sysBlackListDO != null) {
DCBeanUtil.copyNotNull(sysBlackListDO, req);
sysBlackListDao.updateById(sysBlackListDO);
}
} else {
SysBlackListDO sysBlackListDO = new SysBlackListDO();
DCBeanUtil.copyNotNull(sysBlackListDO, req);
sysBlackListDao.insert(sysBlackListDO);
}
return RespResult.success(true);
}
}
通用返回结果对象
package com.litian.dancechar.framework.common.base;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.litian.dancechar.framework.common.trace.TraceHelper;
import com.litian.dancechar.framework.common.util.SystemConfigUtil;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 通用返回结果对象
*
* @author kyle0432
* @date 2024/03/05 21:25
*/
@Data
public class RespResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 结果码
*/
private Integer code = RespResultCode.OK.getCode();
/**
* 结果信息
*/
private String message = RespResultCode.OK.getMessage();
/**
* 详细的错误消息(开发看)
*/
private String detailMessage = RespResultCode.OK.getDetailMessage();
/**
* 返回结果的数据对象
*/
private T data;
/**
* 分布式链路traceId
*/
private String traceId;
/**
* 分布式链路spanId
*/
private String spanId;
/**
* 服务部署的环境
*/
private String env;
public RespResult() {
}
public RespResult(Integer code) {
this.code = code;
}
public RespResult(Integer code, String message) {
this.code = code;
this.message = message;
this.traceId = TraceHelper.getCurrentTrace().getTraceId();
this.spanId = TraceHelper.getCurrentTrace().getSpanId();
this.env = SystemConfigUtil.getEnv();
}
public RespResult(Integer code, String message, String detailMessage) {
this.code = code;
this.message = message;
this.detailMessage = detailMessage;
this.traceId = TraceHelper.getCurrentTrace().getTraceId();
this.spanId = TraceHelper.getCurrentTrace().getSpanId();
this.env = SystemConfigUtil.getEnv();
}
public RespResult(Integer code, String message, String detailMessage, String traceId, String spanId, String env) {
this.code = code;
this.message = message;
this.detailMessage = detailMessage;
this.traceId = traceId;
this.spanId = spanId;
this.env = env;
}
public RespResult(IRespResultCode respResultCode) {
this.code = respResultCode.getCode();
this.message = respResultCode.getMessage();
this.detailMessage = respResultCode.getDetailMessage();
this.traceId = TraceHelper.getCurrentTrace().getTraceId();
this.spanId = TraceHelper.getCurrentTrace().getSpanId();
this.env = SystemConfigUtil.getEnv();
}
public RespResult(IRespResultCode respResultCode, String traceId, String spanId, String env) {
this.code = respResultCode.getCode();
this.message = respResultCode.getMessage();
this.detailMessage = respResultCode.getDetailMessage();
this.traceId = traceId;
this.spanId = spanId;
this.env = env;
}
@JsonIgnore
public boolean isOk() {
return RespResultCode.OK.getCode().equals(code);
}
@JsonIgnore
public boolean isNotOk() {
return !this.isOk();
}
public static <T> RespResult<T> error(IRespResultCode apiResultCode) {
return new RespResult<T>(apiResultCode);
}
public static <T> RespResult<T> error(IRespResultCode apiResultCode, T data) {
return new RespResult<T>(apiResultCode).setData(data);
}
public static <T> RespResult<T> error(IRespResultCode apiResultCode, Object... params) {
return new RespResult<T>(apiResultCode.getCode(), String.format(apiResultCode.getMessage(), params));
}
public static <T> RespResult<T> error(IRespResultCode apiResultCode, T data, Object... params) {
return new RespResult<T>(apiResultCode.getCode(), String.format(apiResultCode.getMessage(), params))
.setData(data);
}
public static <T> RespResult<T> error(String msg) {
return new RespResult<T>(RespResultCode.SYS_EXCEPTION.getCode(), msg, msg);
}
public static <T> RespResult<T> error(String msg, String detailMessage) {
return new RespResult<T>(RespResultCode.SYS_EXCEPTION.getCode(), msg, detailMessage);
}
public static <T> RespResult<T> error(String msg, T data) {
return new RespResult<T>(RespResultCode.SYS_EXCEPTION.getCode(), msg, msg).setData(data);
}
public static <T> RespResult<T> error(String msg, String detailMessage, T data) {
return new RespResult<T>(RespResultCode.SYS_EXCEPTION.getCode(), msg, detailMessage).setData(data);
}
public static <T> RespResult<T> error(Integer code, String msg) {
return new RespResult<T>(code, msg, msg);
}
public static <T> RespResult<T> error(Integer code, String msg, String detailMessage) {
return new RespResult<T>(code, msg, detailMessage);
}
public static <T> RespResult<T> error(Integer code, String msg, T data) {
return new RespResult<T>(code, msg, msg).setData(data);
}
public static <T> RespResult<T> error(Integer code, String msg, String detailMessage, T data) {
return new RespResult<T>(code, msg, detailMessage).setData(data);
}
public static <T> RespResult<T> error(List<Object> codeAndMsgList) {
return new RespResult<>(Integer.valueOf(codeAndMsgList.get(0).toString()),
codeAndMsgList.get(1).toString(), codeAndMsgList.get(1).toString());
}
public static <T> RespResult<T> error(List<Object> codeAndMsgList, T data) {
RespResult<T> ar = error(codeAndMsgList);
ar.setData(data);
return ar;
}
public static RespResult<Void> success() {
return new RespResult<>(RespResultCode.OK);
}
public static <T> RespResult<T> success(T data) {
RespResult<T> ar = new RespResult<T>(RespResultCode.OK);
ar.setData(data);
return ar;
}
public RespResult<T> setRespMessage(IRespResultCode respResultCode) {
this.code = respResultCode.getCode();
this.message = respResultCode.getMessage();
this.detailMessage = respResultCode.getDetailMessage();
return this;
}
public String getMessage() {
return message;
}
public RespResult<T> setMessage(String msg) {
this.message = msg;
return this;
}
public String getDetailMessage() {
return detailMessage;
}
public RespResult<T> setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
public RespResult<T> setMessage(String msg, Object... params) {
this.message = String.format(msg, params);
return this;
}
public T getData() {
return data;
}
public RespResult<T> setData(T data) {
this.data = data;
return this;
}
}
通用返回码对象
package com.litian.dancechar.framework.common.base;
/**
* 通用返回码对象
*
* @author kyle0432
* @date 2024/03/05 21:25
*/
public enum RespResultCode implements IRespResultCode {
/**
* 成功
*/
OK(0, "成功", "成功"),
/**
* socket超时异常
*/
SOCKET_TIMEOUT_EXCEPTION(-2, "socket 超时异常", "socket 超时异常"),
/**
* io异常
*/
IO_EXCEPTION(-3, "io 异常", "io 异常"),
/**
* 系统异常
*/
SYS_EXCEPTION(-1, "服务发生了一点小故障,请稍后重试", "系统异常"),
/**
* 参数不合法
*/
ERR_PARAM_NOT_LEGAL(100000, "参数不合法", "参数不合法"),
/**
* 请勿重复操作
*/
REPEATED_OPERATE(100001, "请勿重复操作", "请勿重复操作"),
/**
* 请求太频繁,请稍后重试
*/
REPEATED_BUSY(100002, "请求太频繁,请稍后重试", "请求繁忙,请稍后重试"),
/**
* 远程接口频繁异常,系统熔断
*/
EXTERNAL_SERVICE_EXCEPTION(100003, "远程接口频繁异常,系统熔断", "远程接口频繁异常,系统熔断"),
/**
* 数据库有重复的记录
*/
ERR_CONSTRAINT_VIOLATION(100004, "数据库记录重复", "数据库记录重复");
/**
* 错误码
*/
private Integer code;
/**
* 错误消息
*/
private String message;
/**
* 详细的错误消息(开发看)
*/
private String detailMessage;
RespResultCode(Integer code, String message, String detailMessage) {
this.code = code;
this.message = message;
this.detailMessage = detailMessage;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
@Override
public String getDetailMessage() {
return detailMessage;
}
}
基础的返回码对象
package com.litian.dancechar.framework.common.base;
/**
* 基础的返回码对象
*
* @author kyle0432
* @date 2024/03/06 9:25
*/
public interface IRespResultCode {
/**
* 结果码
*/
Integer getCode();
/**
* 返回消息
*/
String getMessage();
/**
* 详细的错误消息(开发看)
*/
String getDetailMessage();
}
base模块返回码对象枚举
package com.litian.dancechar.base.enums;
import com.litian.dancechar.framework.common.base.IRespResultCode;
/**
* base模块返回码对象枚举
*
* @author kyle0432
* @date 2024/03/05 21:25
*/
public enum BaseRespResultCode implements IRespResultCode {
ERR_SOURCE_NOT_EMPTY(200000, "渠道不能为空", "渠道不能为空");
/**
* 错误码
*/
private Integer code;
/**
* 错误消息
*/
private String message;
/**
* 详细的错误消息(开发看)
*/
private String detailMessage;
BaseRespResultCode(Integer code, String message, String detailMessage) {
this.code = code;
this.message = message;
this.detailMessage = detailMessage;
}
@Override
public Integer getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
@Override
public String getDetailMessage() {
return detailMessage;
}
}
traceId和spanId工具类
package com.litian.dancechar.framework.common.trace;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.generator.SnowflakeGenerator;
import cn.hutool.core.util.StrUtil;
import com.litian.dancechar.framework.common.util.DCMd5Util;
import org.slf4j.MDC;
import org.springframework.core.NamedThreadLocal;
import java.util.UUID;
/**
* traceId和spanId工具类
*
* @author kyle0432
* @date 2024/03/05 23:15
*/
public class TraceHelper {
public static final ThreadLocal<Trace> CURRENT_SPAN = new NamedThreadLocal<>("TraceId Context");
public static String genTraceId(){
return DCMd5Util.getTraceId(UUID.randomUUID().toString());
}
public static String genSpanId(){
return Convert.toStr(new SnowflakeGenerator().next());
}
public static String getTraceId(){
return MDC.get(Trace.TRACE);
}
/**
* 设置traceId
*/
public static void setCurrentTrace(String traceId) {
if (StrUtil.isBlank(traceId)) {
traceId = genTraceId();
}
Trace trace = new Trace();
trace.setTraceId(traceId);
trace.setSpanId(genSpanId());
MDC.put(Trace.TRACE, trace.getTraceId());
MDC.put(Trace.PARENT_SPAN, trace.getSpanId());
CURRENT_SPAN.set(trace);
}
/**
* 获取traceId
*/
public static Trace getCurrentTrace() {
Trace trace = CURRENT_SPAN.get();
if (trace == null) {
trace = new Trace();
trace.setTraceId(genTraceId());
trace.setSpanId(genSpanId());
MDC.put(Trace.TRACE, trace.getTraceId());
MDC.put(Trace.PARENT_SPAN, trace.getSpanId());
CURRENT_SPAN.set(trace);
} else{
// spanId每次不一样,重新生成
trace.setSpanId(genSpanId());
MDC.put(Trace.PARENT_SPAN, trace.getSpanId());
CURRENT_SPAN.set(trace);
}
return trace;
}
/**
* 清空traceId
*/
public static void clearCurrentTrace() {
CURRENT_SPAN.set(null);
CURRENT_SPAN.remove();
}
}
获取系统配置工具类
package com.litian.dancechar.framework.common.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.spring.SpringUtil;
import com.litian.dancechar.framework.common.config.SystemEnvConfig;
import org.springframework.stereotype.Component;
/**
* 获取系统配置工具类
*
* @author kyle0432
* @date 2024/03/05 18:57
*/
@Component
public class SystemConfigUtil {
/**
* 获取部署环境信息
*/
public static String getEnv() {
if( SpringUtil.getApplicationContext() != null){
return Convert.toStr(SpringUtil.getBean(SystemEnvConfig.class).getEnv(), "dev");
}
return "dev";
}
}
定义业务异常类
package com.litian.dancechar.framework.common.exception;
/**
* 业务异常类
*
* @author kyle0432
* @date 2024/03/05 21:15
*/
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BusinessException(String msg) {
super(msg);
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause) {
super(message,cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writeableStackTrace) {
super(message,cause, enableSuppression, writeableStackTrace);
}
}
全局异常类
package com.litian.dancechar.framework.common.exception;
import com.litian.dancechar.framework.common.base.RespResult;
import com.litian.dancechar.framework.common.base.RespResultCode;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;
/**
* 全局异常类
*
* @author kyle
* @date 2024/03/06 14:15
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public RespResult<Void> handleError(MethodArgumentTypeMismatchException e) {
log.error("Method Argument Type Mismatch:{}", e.getMessage(), e);
return RespResult.error("Method Argument Type Mismatch");
}
@ExceptionHandler(MissingServletRequestParameterException.class)
public RespResult<Void> handleError(MissingServletRequestParameterException e) {
log.error("Method Request Parameter :{}", e.getMessage(), e);
return RespResult.error("Method Request Parameter");
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public RespResult<Void> handleError(MethodArgumentNotValidException e) {
log.error("Method Request Not Valid :{}", e.getMessage(), e);
BindingResult bindingResult = e.getBindingResult();
FieldError fieldError = bindingResult.getFieldError();
String message = String.format("%s:%s", fieldError.getField(), fieldError.getDefaultMessage());
return RespResult.error(RespResultCode.ERR_PARAM_NOT_LEGAL.getCode(),
RespResultCode.ERR_PARAM_NOT_LEGAL.getMessage(),
message);
}
@ExceptionHandler(BindException.class)
public RespResult<Void> handleError(BindException e) {
log.error("Bind Exception :{}", e.getMessage(), e);
FieldError fieldError = e.getFieldError();
String message = String.format("%s:%s", fieldError.getField(), fieldError.getDefaultMessage());
return RespResult.error(RespResultCode.ERR_PARAM_NOT_LEGAL.getCode(), message);
}
@ExceptionHandler(ConstraintViolationException.class)
public RespResult<Void> handleError(ConstraintViolationException e) {
log.error("Constraint Exception :{}", e.getMessage(), e);
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
ConstraintViolation<?> violation = violations.iterator().next();
String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
String message = String.format("%s:%s", path, violation.getMessage());
return RespResult.error(RespResultCode.ERR_CONSTRAINT_VIOLATION.getCode(), message);
}
@ExceptionHandler(HttpMessageNotReadableException.class)
public RespResult<Void> handleError(HttpMessageNotReadableException e) {
log.error("Http Message Not Readable Exception :{}", e.getMessage(), e);
return RespResult.error("请求的参数类型与方法接收的参数类型不匹配, 请检查!");
}
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public RespResult<Void> handleError(HttpRequestMethodNotSupportedException e) {
log.error("Http Request Method Not Support Exception :{}", e.getMessage(), e);
String message = String.format("%s方法类型不支持,请检查!", e.getMethod());
return RespResult.error(message);
}
@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
public RespResult<Void> handleError(HttpMediaTypeNotSupportedException e) {
log.error("Http Media Type Not Support Exception :{}", e.getMessage(), e);
String message = String.format("不支持%s content-type,请检查!", e.getContentType());
return RespResult.error(message);
}
@ExceptionHandler(ParamException.class)
public RespResult<Void> handleError(ParamException e) {
log.error("参数不合法 :{}", e.getMessage(), e);
return RespResult.error(RespResultCode.ERR_PARAM_NOT_LEGAL.getCode(),
RespResultCode.ERR_PARAM_NOT_LEGAL.getMessage(), e.getMessage());
}
@ExceptionHandler(DistributeLockException.class)
public RespResult<Void> handleError(DistributeLockException e) {
log.error("分布式锁Distribute Lock Exception :{}", e.getMessage(), e);
return RespResult.error(RespResultCode.REPEATED_OPERATE.getCode(),
RespResultCode.REPEATED_OPERATE.getMessage(), e.getMessage());
}
@ExceptionHandler(BusinessException.class)
public RespResult<Void> handleError(BusinessException e) {
log.error("业务出现异常 :{}", e.getMessage(), e);
return RespResult.error(RespResultCode.SYS_EXCEPTION.getCode(),
RespResultCode.SYS_EXCEPTION.getMessage(), e.getMessage());
}
@ExceptionHandler(Exception.class)
//@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "系统内部错误")
public RespResult<Void> handleError(Exception e) {
log.error("全局异常信息,异常堆栈信息 :{}", e.getMessage(), e);
return RespResult.error(RespResultCode.SYS_EXCEPTION.getCode(),
RespResultCode.SYS_EXCEPTION.getMessage(), e.getMessage());
}
@ExceptionHandler(Throwable.class)
public RespResult<Void> handleError(Throwable e) {
log.error("Throwable Server Exception :{}", e.getMessage(), e);
return RespResult.error(RespResultCode.SYS_EXCEPTION.getCode(),
RespResultCode.SYS_EXCEPTION.getMessage(), e.getMessage());
}
}
五、结果演示
成功响应结果集
失败响应结果集
tranceId的记录,方便根据tranceId追踪日志
当前环境配置