Spring Boot统一接口返回及全局异常处理

网友投稿 387 2022-08-03


Spring Boot统一接口返回及全局异常处理

目录1、解决方案2、具体实现2.1 定义状态码统一接口2.2 公共模块状态码枚举类2.3 定义全局自定义异常2.4 定义统一接口格式输出类2.5 定义统一接口格式输出类2.6 接口统一输出优化2.7 子系统如何实现3、子系统定义状态码,实现BaseResultCode接口

前言:

前段时间接手了一个老项目,现在需要在此项目中添加一些新的需求,同事在开发过程中遇到了一些问题?

1.成功的状态到底是200还是0啊,订单系统200代表成功,而会员系统却是0代表成功。2.接口返回的结果中,有些是用msg字段表示描述,有些又是用desc字段描述,前段处理起来比较麻烦能不能统一。3.错误提示信息需要支持国际化。

其实这些问题,归根究底还是代码规范问题,我们需要将接口定义和全局异常统一处理,历史项目10多个工程,难道每个工程都去实现一遍,答案可定是不可能的。

1、解决方案

定义公共模块,实现统一接口定义规范和异常处理,其他的系统进行依赖和扩展即可。

2、具体实现

2.1 定义状态码统一接口

public interface BaseResultCode

{

/**

* 状态码

* @return

*/

int getCode();

/**

* 提示信息

* @return

*/

String getMsg();

}

2.2 公共模块状态码枚举类

public enum ResultCode implements BaseResultCode

{

OK(200, "成功"),

ERROR(300,"系统异常"),

NEED_AUTH(301, "非法请求,请重新登录"),

PARAMTER_ERROR(302, "参数错误");

//省略其他定义错误码

private int code;

private String msg;

private ResultCode(int code, String msg)

{

this.code = code;

this.msg = msg;

}

public static ResultCode getValue(int code)

{

for (ResultCode errorCode : values())

{

if (errorCode.getCode() == code)

{

return errorCode;

}

}

return null;

}

//省略Get、Set方法

}

2.3 定义全局自定义异常

public class SysException extends RuntimeException

{

private static final long serialVersionUID = 5225171867523879342L;

private int code;

private String msg;

private Object[] params;

private BaseResultCode errorCode;

public SysException()

{

super();

}

public SysException(String message)

{

super(message);

}

public SysException(Throwable cause)

{

super(cause);

}

public SysException(int code ,String message)

{

this.code = code;

this.msg = message;

}

public SysException(int code ,String message, Object[] params)

{

this(code, message);

this.params= params;

}

public SysException(String message, Throwable cause)

{

super(message, cause);

}

public SysException(BaseResultCode errorCode)

{

this.errorCode = errorCode;

}

public SysException(String message, Object[] params)

{

super(message);

this.params = params;

}

public SysException(BaseResultCode errorCode, String message, Object[] params)

{

this(message, params);

this.errorCode = errorCode;

}

/**

* Construct by default

*

* @param message

* message

* @param parameters

* parameters

* @param cause

* cause

*/

public SysException(String message, Object[] params, Throwable cause)

{

super(message, cause);

this.params = params;

}

public int getCode()

{

return code;

}

public void setCode(int code)

{

this.code = code;

}

public String getMsg()

{

return msg;

}

public void setMsg(String msg)

{

this.msg = msg;

}

/**

* @return the params

*/

public Object[] getParams()

{

return params;

}

/**

* @param params

* the params to set

*/

public void setParams(Object[] params)

{

this.params = params;

}

public BaseResultCode getErrorCode()

{

return errorCode;

}

public void setErrorCode(BaseResultCode errorCode)

{

this.errorCode = errorCode;

}

}

2.4 定义统一接口格式输出类

public class Result implements Serializable

{

private static final long serialVersionUID = -1773941471021475043L;

private Object data;

private int code;

private String msg;

public Result()

{

}

public Result(int code, Object data, String msg)

{

this.code = code;

this.data = data;

this.msg = msg;

}

public Result(int code, String desc)

{

this(code, null, desc);

}

public Result(BaseResultCode errorCode)

{

this(errorCode.getCode(), null, errorCode.gettxofppLZUMsg());

}

public static Result success()

{

return success(null);

}

public static Result success(Object data)

{

Result result = new Result();

result.setData(data);

result.setCode(ResultCode.OK.getCode());

return result;

}

public static Result error(String msg)

{

Result result = new Result();

result.setCode(ResultCode.ERROR.getCode());

result.setMsg(msg);

return result;

}

public static Result error(BaseResultCode baseCode)

{

Result result = new Result();

result.setCode(baseCode.getCode());

result.setMsg(baseCode.getMsg());

return result;

}

}

个人建议:统一接口输出类不要定义为泛型类型

2.5 定义统一接口格式输出类

@RestControllerAdvice

public class SysExceptionHandler

{

public static Log logger = LogManager.getLogger(SysExceptionHandler.class);

@ExceptionHandler(Exception.class)

public Result handleException(HttpServletRequest request,

Exception ex)

{

logger.error("Handle Exception Request Url:{},Exception:{}",request.getRequestURL(),ex);

Result result = new Result();

//系统异常

if (ex instanceof SysException)

{

SysException se = (SysException) ex;

BaseResultCode resultCode =se.getErrorCode();

if(resultCode==null)

{

result = Result.error(se.getMessage());

}

else

{

result = new Result(resultCode.getCode(),

StringUtil.isNotEmpty(se.getMessage())?se.getMessage():resultCode.getMsg());

}

}

//参数错误

else if (ex instanceof ConstraintViolationException)

{

ConstraintViolationException v = (ConstraintViolationException) ex;

String message = v.getConstraintViolations().iterator().next()

.getMessage();

result.setCode(ResultCode.PARAMTER_ERROR.getCode());

result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

}

//参数错误

else if (ex instanceof BindException)

{

BindException v = (BindException) ex;

String message = v.getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));

result.setCode(ResultCode.PARAMTER_ERROR.getCode());

result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

}

//参数错误

else if (ex instanceof MethodArgumentNotValidException)

{

MethodArgumentNotValidException v = (MethodArgumentNotValidException) ex;

String message = v.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));

result.setCode(ResultCode.PARAMTER_ERROR.getCode());

result.setMsg(ResultCode.PARAMTER_ERROR.getMsg() + ":" + message);

}

else

{

result = new Result(ResultCode.ERROR.getCode(),ExceptionUtil.getErrorMsg(ex));

}

logger.info("exception handle reuslt:" + result);

return result;

}

}

上述定义已经可以实现全局接口和异常的统一处理,但是存在的如下问题

每个controller都需要返回Reesult类型,且每个方法都需要返回Result.success()或者Result.success(data)的结果,有点重复,需要进行优化。

@GetMapping("addUser")

public Result add()

{

for(int i=0;i<10;i++)

{

TUser user = new TUser();

//user.setOid(IdWorker.getId());

user.setName("shareing_"+i);

user.setAge(i);

userService.addUser(user);

}

return Result.success();

}

2.6 接口统一输出优化

实现方式只需要实现ResponseBodyAdvice接口,重写beforeBodyWrite方法接口。

@RestControllerAdvice

public class ResponseAdvice implements ResponseBodyAdvice

{

private Logger logger = LoggerFactory.getLogger(ResponseAdvice.class);

@Override

public boolean supports(MethodParameter returnType,

Class extends HttpMessageConverter>> converterType)

{

return true;

}

@Override

public Object beforeBodyWrite(Object o, MethodParameter returnType,

MediaType selectedContentType,

Class extends HttpMessageConverter>> selectedConverterType,

ServerHttpRequest request, ServerHttpResponse response)

{

logger.info("before body write param:{}",o);

if(o instanceof String)

{

//序列化结果输出

return FastjsonUtil.toJSONString(Result.success(o));

}

else if (o instanceof Result)

{

return o;

}

return Result.success(o);

}

}

经过优化后,controller输出可以根据业务的需求定义输出对象。

@GetMapping("getUserByName")

public TUser getUserByName1(@RequestParam String name)

{

logger.info("getUserByName paramter name:"+name);

return userService.getUserByName(name);

}

2.7 子系统如何实现

子系统引入common的jar包,

com.xx

xx-common

2.0

3、子系统定义状态码,实现BaseResultCode接口

public enum OrderModelErrorCode implements BaseResultCode

{

ORDER_STATUS_ERROR(1000, "订单状态不正确");

private int code;

private String msg;

private UserModelErrorCode(int code, String msg)

{

this.code = code;

this.msg = msg;

}

@Override

public int getCode()

{

return code;

}

@Override

public String getMsg()

{

return msg;

}

}

定义异常处理类,继承公共异常处理类SysExceptionHandler

@RestControllerAdvice

public class OrderModalExceptionHandle extends SysExceptionHandler

{

@Override

public Result handleException(HttpServletRequest request, Exception ex)

{

return super.handleException(request, ex);

//子系统可以扩展异常处理

}

}

子系统使用示例:

@Override

public Order getOrder(String orderId)

{

Order order =getOrder(orderId);

//相关伪代码

if(order.getStatus()>120)

{

throw new SysException(OrderModelErrorCode.ORDER_STATUS_ERROR);

}

return order;

}

经过相关项目的重构,已经解决了第一个和第二问题,关于第三个国际化问题,将在后续的文章中讲解。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Spring boot 集成 MQTT详情
下一篇:Spring Boot 集成PageHelper的使用方法
相关文章

 发表评论

暂时没有评论,来抢沙发吧~