spring boot 定制返回结果json格式

对于spring boot 使用@RestController 注解,使得controller 方法的返回结果最后会是json格式,但是json格式并不固定,如何才嫩定制呢?

由于本人未对spring mvc进行深度了解,不晓得spring是否是这样的扩展接口,也曾尝试通过看源码寻找,但是很遗憾并没有找到,

因此在这里提供一个个人看过源码后的一个小小的思路:

自定义一个HandlerMethodReturnValueHandler实现类,这是spring开放的扩展接口,用于处理controller返回结果,因此实现的目的是将结果封装成固定的对象,然后转成json,仅针对@RestController注解有效,其他注解则继续使用spring原生的默认机制

具体代码如下:

public class JsonResultReturnValueHandler implements HandlerMethodReturnValueHandler {


    private static final Logger logger = LoggerFactory.getLogger(JsonResultReturnValueHandler.class);


    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        Class cls = returnType.getContainingClass();
        return cls.isAnnotationPresent(RestController.class);

    }


    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        mavContainer.setRequestHandled(true);
        HttpServletRequest request = getNativeRequest(webRequest);
        HttpServletResponse response = getNativeResponse(webRequest);
        writeWithMessageConverters(returnValue, returnType, request, response);
    }


    private void writeWithMessageConverters(Object returnValue, MethodParameter returnType, HttpServletRequest request, HttpServletResponse response) {
        JsonResult jr = JsonResultFactory.create(returnValue);
        String rs = Utils.toJson(jr);
        String encoding = request.getCharacterEncoding();
        try {
            response.setCharacterEncoding(encoding);
            response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(rs);
            response.getWriter().flush();
        } catch (Exception e) {
            logger.error("HttpServletResponse 写数据失败,ERROR:{}",e.getMessage(),e);
            throw new BizException("Response 写数据失败",e);
        } finally {
            try {
                response.getWriter().close();
            } catch (Exception e) {
                logger.error("[HttpResponse-ERROR-Witer close failure-ERRPR:{}]",e.getMessage(),e);
            }
        }

    }


    private HttpServletRequest getNativeRequest(NativeWebRequest webRequest){
        return webRequest.getNativeRequest(HttpServletRequest.class);
    }


    private HttpServletResponse getNativeResponse(NativeWebRequest webRequest){
        return webRequest.getNativeResponse(HttpServletResponse.class);
    }

}


红色标记就是主要的代码,这里还有一个问题 ,spring默认将自定义的方法结果处理器放在最后的位置,而spring是按照顺序从前到后一次进行选择判断的,如果不将自定义放到第一个位置,则自定义的类将不会被选择到(仅针对此种方式实现,因未对spring做过度的修改,因此会有这样的问题),接下来就是要讲自定义的方法结果处理器设置到第一个位置,持有方法结果处理器的类,经过调试发现默认是RequestMappingHandlerAdapter,由于其属性final类型,不可修改且没有暴露修改接口,因此需要通过反射进行重新设置,

具体代码如下:


@Component
public class ApplicationContextExtension implements BeanFactoryPostProcessor {


    private static final Logger logger = LoggerFactory.getLogger(ApplicationContextExtension.class);


    private ConfigurableListableBeanFactory beanFactory;


    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }


    public void init() {
        // RequestMappingHandlerAdapter 扩展
        extensionRequestMappingHandlerAdapter();
    }


    private void extensionRequestMappingHandlerAdapter() {
        logger.info("[自定义HandlerAdapter初始化.....]");
        RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) beanFactory.getBean("requestMappingHandlerAdapter");
        handleRequestMappingHandlerAdapter(requestMappingHandlerAdapter);
    }


    private void handleRequestMappingHandlerAdapter(RequestMappingHandlerAdapter ha) {
        try {
            Field customReturnValueHandlersField = getField(ha.getClass(),"customReturnValueHandlers");
            Field returnValueHandlersField = getField(ha.getClass(),"returnValueHandlers");
            ReflectionUtils.makeAccessible(customReturnValueHandlersField);
            ReflectionUtils.makeAccessible(returnValueHandlersField);
            List<HandlerMethodReturnValueHandler> nativeCustomePropertyValue = (List<HandlerMethodReturnValueHandler>) ReflectionUtils.getField(customReturnValueHandlersField,ha);
            HandlerMethodReturnValueHandlerComposite nativeDefaultPropertyValue = (HandlerMethodReturnValueHandlerComposite) ReflectionUtils.getField(returnValueHandlersField,ha);
            if(Utils.isNotEmpty(nativeCustomePropertyValue)){
                Field realField = getField(HandlerMethodReturnValueHandlerComposite.class,"returnValueHandlers");
                ReflectionUtils.makeAccessible(realField);
                List<HandlerMethodReturnValueHandler> realValue = (List<HandlerMethodReturnValueHandler>) ReflectionUtils.getField(realField,nativeDefaultPropertyValue);


                for (HandlerMethodReturnValueHandler hma : nativeCustomePropertyValue){
                    if(realValue.contains(hma)){
                        realValue.remove(hma);
                    }
                }


                /**
                 * 因{@link HandlerMethodReturnValueHandlerComposite#returnValueHandlers}是final类型,因此new一个新对象替换
                 */
                HandlerMethodReturnValueHandlerComposite newHandlerComposite = new HandlerMethodReturnValueHandlerComposite();
                newHandlerComposite.addHandlers(nativeCustomePropertyValue);// 自定义HandlerMethodReturnValueHandler
                newHandlerComposite.addHandlers(realValue);// spring 默认HandlerMethodReturnValueHandler


                ReflectionUtils.setField(returnValueHandlersField,ha,newHandlerComposite);

                logger.info("[自定义HandlerAdapter初始化success");
            }


        } catch (Exception e) {
            logger.error(ApplicationContextExtension.class.getName()+" extension failure,detail info is {}",e.getMessage(),e);
        }
    }


    private Field getField(Class type,String fieldName) throws Exception {
        return type.getDeclaredField(fieldName);
    }


}


红色标记为主代码,

The End!

猜你喜欢

转载自blog.csdn.net/awei1024/article/details/80261602
今日推荐