不灭的焱

革命尚未成功,同志仍须努力下载JDK17

作者:Albert.Wen  添加时间:2021-06-03 14:40:29  修改时间:2024-10-07 07:45:23  分类:06.Java框架/系统  编辑

通常情况下,如果我们的API接口需要返回 JSON、XML 等格式化的数据时,只需要在控制器上注解@ResponseBody且指定produces = "application/json;charset=UTF-8"数据类型即可,参考代码如下:

/**
 * 登录提交
 */
@RequestMapping(value = "loginSubmit", produces = "application/json;charset=UTF-8")
@ResponseBody
public String loginSubmit(LoginRequest loginRequest) {
    // 登录的业务逻辑
    //......
    
    return "{"\code\": \"0\", \"msg\": \"登录成功\"}"
}

但是每个接口都加上这段代码:produces = "application/json;charset=UTF-8",貌似不那么清爽,于是想到是否能在“拦截器”里做些手脚,让它自动输出这个JSON文档类型(即 Http Json头信息),但实践证明,针对 @ResponseBody,在“拦截器”中的设置是无效的,如:

package com.wenjianbao.interceptor;

import cn.hutool.core.util.StrUtil;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 系统拦截器
 */
public class SystemInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 针对 @ResponseBody 标注的控制器,这段代码是无效的!
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        // 针对 @ResponseBody 标注的控制器,这段代码是无效的!
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
    }
    
}

通过这篇文章:SpringBoot ResponseBodyAdvice 接口实现自定义返回数据类型(响应头)学习到,

通过实现ResponseBodyAdvice接口,可对返回的字符串(json/xml等)对象,做一些强制篡改,包括 Http头信息的修改,参考代码如下:

package com.wanma.printer.interceptor;

import cn.hutool.core.util.StrUtil;
import com.wanma.printer.util.RequestUtil;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

@ControllerAdvice
public class ResponseBodyInterceptor implements ResponseBodyAdvice<Object> {
    /**
     *  判断哪些需要拦截
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof String) {
            String bodyStr = String.valueOf(body);
            
            // 输出 XML 头信息
            String inAjax = RequestUtil.getRequest().getParameter("inAjax");
            if (inAjax != null && inAjax.equals("1")) {
                response.getHeaders().setContentType(MediaType.TEXT_XML);
            }

            // 输出 JSON 头信息
            if (StrUtil.startWith(bodyStr, "{") && StrUtil.endWith(bodyStr, "}")) {
                response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            }
        }
        
        return body;
    }
}

以后,Api控制器,就无需加上:produces = "application/json;charset=UTF-8",简化如下:

/**
 * 登录提交
 */
@RequestMapping(value = "loginSubmit")
@ResponseBody
public String loginSubmit(LoginRequest loginRequest) {
    // 登录的业务逻辑
    //......
    
    return "{"\code\": \"0\", \"msg\": \"登录成功\"}"
}