在开发一个基于MVC框架的web项目中,不可避免的要写Controller层,在Controller层中实现对请求值的解析以及封装返回值,每个接口在完成业务逻辑后将得到的结果传给前端,由前端完成页面渲染以及业务办理。整体看上去没什么问题,但是随着业务复杂度越来越高,如果不对每个接口的返回值作一些约束,那整个系统会变得越来越复杂,很难维护,这里我要介绍的就是如何优雅的统一处理Controller层的返回值,让整个项目的返回值变的统一易于维护和后期问题排查。
首先我们要定义一个统一的返回体,用于约定前后端处理值类型,可以这样来定义:
public class ResponseResult implements Serializable {
private static final long serialVersionUID = 1L;
private int code;
private boolean success;
private String message;
private T value;
}
其中个参数含义,code:响应值,success:请求是否成功响应;message:详细错误信息,value:则是返回值。
其中我们在定义code的时候可以设置一下枚举类,用于记录常规的一些接口返回失败码
public enum FailCodeEnum {
PARAMS_ERROR(400, "请求参数错误"),
SERVER_ERROR(500, "服务内部错误");
private int code;
private String message;
FailCodeEnum(int errorCode, String message) {
this.code = errorCode;
this.message = message;
}
这时候我们的Controller层代码可以写成这样:
@PostMapping(value = "save/{msgId}")
public ResponseResult saveSms(@PathVariable(value = "msgId") String msgId, @RequestBody String body){
log.info("== msgId: {}; body: {}", msgId, body);
return new ResponseResult(System.currentTimeMillis());
}
这样后端就会有一个统一的返回体了,但是这样每个接口都需要返回ResponseResult的方式对开发不怎么友好,我们可以对代码再进行优化。
通过@ControllerAdvice注解对Controller层的返回体作统一处理,我们的代码优化后如下:
@Slf4j
@ControllerAdvice
public class ResponseSupportAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
ServletRequestAttributes request = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
Object testAtt = request.getAttribute(Consts.WARP_REQUEST, 0);
log.info("class'name: {}, testAtt: {}", name, testAtt);
return Boolean.parseString(testAtt);
}
@Override
public Object beforeBodyWrite(Object o, MethodParameter methodParameter,
MediaType mediaType, Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
log.info("return value: {}", o.toString());
return new ResponseResult<>(o);
}
}
Controller层的代码优化如下了:
@PostMapping(value = "save/{msgId}")
public Object saveSms(@PathVariable(value = "msgId") String msgId, @RequestBody String body){
log.info("== msgId: {}; body: {}", msgId, body);
// 设置请求值是否需要封装
httpRequest.setAttribute(Consts.WARP_REQUEST, "true");
return System.currentTimeMillis();
}
这样就ok了,简单吧。到此返回的设计思路完成,是不是又简洁,又优雅。