修改Springboot 响应过程,包装返回值

您所在的位置:网站首页 getcolumntype返回值 修改Springboot 响应过程,包装返回值

修改Springboot 响应过程,包装返回值

2023-04-09 07:09| 来源: 网络整理| 查看: 265

问题 前端一直不太认同http status(状态码)表达操作成功与否的方式,强烈要求所有接口都返回200,在响应体中增加code来表示操作是否成功。

比如当使用POST方式请求接口/api/user/2 时 当没有操作权限时两种响应 请求接口: /api/user/2 请求方法: POST 请求体:......(json格式的参数)

原响应格式: http status: 403 响应体:

{ msg: '没有操作权限' } 复制代码

前端想要的响应格式: http status: 200 响应体:

{ code: 403, msg: '没有操作权限' } 复制代码 办法 1. 修改每个接口的返回值

最简单粗暴的方式:定义一个类如下:

@Data public class Res{ private Integer code; private String msg; private Object content; } 复制代码

将每个service的返回值都set给content,set相应的code和msg,然后controller将该对象返回给前端。

也可以每个接口都返回JSONObject的实例json

@GetMapping("/{id}") public JSONObject getOne((@PathVariable Integer id){ Person person = personService.findById(id); JSONObject json = new JSONObject(); json.put("code", 200); json.put("msg", "成功"); json.put("content", person); return json; } 复制代码

功能完成,但是看到满屏的Res或者JSONObject操作,这么多重复代码,实在不应该。

2. 改进,修改SpringBoot原有流程

SpringBoot的请求处理过程如下:

882980-20170729131340722-226542134.png 请求处理大致流程 4702716-793d55323dd8cd66.jpg 请求处理具体流程

在第二张图中可以看到HandlerMethodReturnValueHandler在处理所有响应的内容,只要干预他的处理过程就能将原有数据包装起来 下面是该类的源码

public interface HandlerMethodReturnValueHandler { /** * Whether the given {@linkplain MethodParameter method return type} is * supported by this handler. * @param returnType the method return type to check * @return {@code true} if this handler supports the supplied return type; * {@code false} otherwise */ boolean supportsReturnType(MethodParameter returnType); /** * Handle the given return value by adding attributes to the model and * setting a view or setting the * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true} * to indicate the response has been handled directly. * @param returnValue the value returned from the handler method * @param returnType the type of the return value. This type must have * previously been passed to {@link #supportsReturnType} which must * have returned {@code true}. * @param mavContainer the ModelAndViewContainer for the current request * @param webRequest the current request * @throws Exception if the return value handling results in an error */ void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception; } 复制代码

实现该类的两个方法就能自定义处理过程。

首先还是要定义一个工具类: public class Res { // protected final static Res OK = new Res( HttpStatus.OK.value(),"成功",""); private Integer code; private String msg; private String message; /** * 返回正常信息时,将数据放入该字段 */ private Object content; /** * 成功响应并需要返回数据时,使用该构造方法 * @param data */ protected Res(Object data) { this.code = 200; this.msg = "成功"; this.message = "success"; this.content = data; } Res(Integer code,String msg, String message){ this.msg = msg; this.code = code; this.message = message; } public Integer getCode() { return code; } public String getMsg() { return msg; } public String getMessage() { return message; } public Object getContent() { return content; } } 复制代码 然后实现 HandlerMethodReturnValueHandler public class WrapReturnValueHandler implements HandlerMethodReturnValueHandler { private Res ok = new Res(null); private RequestResponseBodyMethodProcessor target; public WrapReturnValueHandler(RequestResponseBodyMethodProcessor target) { this.target = target; } @Override public boolean supportsReturnType(MethodParameter methodParameter) { return true; } @Override public void handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception { Executable executable = methodParameter.getExecutable(); Method method = (Method) executable; Class returnType = method.getReturnType(); if (returnType.equals(Void.class)) { target.handleReturnValue(ok, methodParameter, modelAndViewContainer, nativeWebRequest); } else if ( returnType.equals( Res.class )) { target.handleReturnValue(o, methodParameter, modelAndViewContainer, nativeWebRequest); else { target.handleReturnValue(new Res(o), methodParameter, modelAndViewContainer, nativeWebRequest); } } } 复制代码 最后将这个实现类加入到SpringBoot流程中 @Configuration public class InitializingAdvice implements InitializingBean { private final static Logger log = LoggerFactory.getLogger( InitializingAdvice.class ); @Resource private RequestMappingHandlerAdapter adapter; @Override public void afterPropertiesSet() { List returnValueHandlers = adapter.getReturnValueHandlers(); List handlers = new ArrayList(returnValueHandlers); this.decorateHandlers(handlers); adapter.setReturnValueHandlers(handlers); } private void decorateHandlers(List handlers) { for (HandlerMethodReturnValueHandler handler : handlers) { if (handler instanceof RequestResponseBodyMethodProcessor) { WrapReturnValueHandler decorator = new WrapReturnValueHandler( (RequestResponseBodyMethodProcessor) handler); int index = handlers.indexOf(handler); handlers.set(index, decorator); break; } } } } 复制代码

这样所有的响应在转化为流之前就能将内容包装成预期格式 当然抛出异常可以使用注解@ControllerAdvice捕获控制,以控制http status,然后主动将响应构造成Res实例



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3