自定义Spring结果包装类 HandlerMethodReturnValueHandler

  • Post author:
  • Post category:其他


自定义结果包装类要实现接口

HandlerMethodReturnValueHandler

public interface HandlerMethodReturnValueHandler {
    boolean supportsReturnType(MethodParameter var1);
    void handleReturnValue(@Nullable Object var1, MethodParameter var2, ModelAndViewContainer var3, NativeWebRequest var4) throws Exception;
}
  • supportsReturnType 表示是否支持该返回类型
  • handleReturnValue 对于返回值的处理

spring的默认处理类是

RequestResponseBodyMethodProcessor

,它是根据判断是否有

@ResponseBody

注解来处理的。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
                returnType.hasMethodAnnotation(ResponseBody.class));
    }
    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

        mavContainer.setRequestHandled(true);
        ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

        // Try even with null return value. ResponseBodyAdvice could get involved.
        writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
    }
}

看一下

RequestResponseBodyMethodProcessor

的注入方式:

在这里插入图片描述

可以看到

RequestResponseBodyMethodProcessor



RequestMappingHandlerAdapter

通过new直接创建的。我们是不是可以通过在

customReturnValueHandlers

添加自定义返回处理类呢,但是spring在选择handler的时候是根据顺序进行选取的,所以自定义包装处理类肯定在

RequestResponseBodyMethodProcessor

后面,达不到我们的要求。

所以我们的做法就是把handlers里的

RequestResponseBodyMethodProcessor

替换成我们的自定义包装类。

首先我们看我们的自定义包装类:

@Slf4j
public class ExampleHandler implements HandlerMethodReturnValueHandler {
    /**
     * 表示是否支持该返回类型
     */
    @Override
    public boolean supportsReturnType(MethodParameter methodParameter) {
        boolean hasJSONAnno = methodParameter.getMethodAnnotation(ResponseJson.class) != null || methodParameter.getMethodAnnotation(ResponseJson.class) != null;
        return hasJSONAnno;
    }
    /**
     * o    就是接口返回值
     * methodParameter  方法参数
     */
    @Override
    public void  handleReturnValue(Object o, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest)throws Exception {
    modelAndViewContainer.setRequestHandled(true);

    HttpServletResponse response =  (HttpServletResponse)nativeWebRequest.getNativeResponse(HttpServletResponse.class);
    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
    response.setCharacterEncoding("UTF-8");

    this.log.info("请求成功,返回消息转换");

    Map<String, Object> rsp = new HashMap();

    rsp.put("code", "0");
    rsp.put("message", "成功");
    if (o != null)
        rsp.put("data", o);

    this.returnMsg(rsp, response);
    }

    private void returnMsg(Object msg, HttpServletResponse response) {

        try(PrintWriter writer = response.getWriter();){
            response.setContentType("text/plain;charset=UTF-8");
            writer.write(this.objToJsonString(msg));
            writer.flush();
        } catch (IOException var8) {
            this.log.error("统一格式返回", var8);
        }

    }

    private String objToJsonString(Object msg) {
        return JSON.toJSONString(msg, new SerializerFeature[]{SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.WriteNullNumberAsZero, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.WriteNullBooleanAsFalse});
    }
}

自己写一个配置类,注入

RequestMappingHandlerAdapter

把其中的handlers中的

RequestResponseBodyMethodProcessor

替换成我们自定义的包装类就可以了

/**
 * @创建人 liuzhihui
 * @创建时间 2019/11/27
 * @描述  把spingmvc 自带的ReturnValueHandlersList(含@ResponseBody的handler) 替换成带自定义的ReturnValueHandlersList
 */
@Configuration
public class ReturnValueConfig implements InitializingBean {
    @Autowired
    RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @Override
    public void afterPropertiesSet() throws Exception {
        List<HandlerMethodReturnValueHandler> handlerMethodReturnValueHandlers=requestMappingHandlerAdapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> handlerMethodReturnValueHandlers1=new ArrayList<>(handlerMethodReturnValueHandlers.size());
        handlerMethodReturnValueHandlers.forEach(handlerMethodReturnValueHandler -> {
            if (handlerMethodReturnValueHandler instanceof RequestResponseBodyMethodProcessor )
                handlerMethodReturnValueHandlers1.add(new ExampleHandler());
            else
                handlerMethodReturnValueHandlers1.add(handlerMethodReturnValueHandler);
        });
        requestMappingHandlerAdapter.setReturnValueHandlers(handlerMethodReturnValueHandlers1);
    }
}

注解:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseJson {
}

测试:

@RestController
public class HandlerController {
    @ResponseJson
    @GetMapping("/test")
    public Teacher test(@RequestParam(value="name") String name){
    // 处理逻辑
    Teacher student  = new Teacher();
    student.setName(name);
    return student;
    }
}

结果:

{“code”:“0”,“data”:{“age”:0,“id”:0,“name”:“123”},“message”:“成功”}

具体代码:

https://github.com/lzhharvey/ReturnValueDemo

参考:

https://www.jianshu.com/p/bad06d4fe9df