SpringBoot使用Filter对Controller返回数据进行修改,例如jsonp格式返回

需求描述,Controller接口定义的返回实体类型,但是前端需要jsonp格式,就是传入callback参数时,对返回的数据进行包裹::形如callback(data),现在需要一个统一的方法对所有的Controller添加返回数据格式修改,尝试使用了AOP,但是AOP的返回值会转型为Controller接口定义的类型,对于JSONP返回的字符串类型来说肯定是不行的,于是有了以下方法


import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Map;

@WebFilter(urlPatterns = "/*", filterName = "callbackFilter")
public class ResponseFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        //获取参数
        Map<String, String[]> params = request.getParameterMap();
        String key;
        //查找有没有callback或者cb参数
        if (!params.containsKey("callback")) {
            if (!params.containsKey("cb")) {
                filterChain.doFilter(request, response);
                return;
            }
            key = "cb";
        } else {
            key = "callback";
        }
        String callback = "";
        String[] param = params.get(key);
        if (param != null && param.length > 0) {
            callback = param[0];
        }

        MyResponseWrapper responseWrapper = new MyResponseWrapper((HttpServletResponse) response);
        // 这里只拦截返回,直接让请求过去,如果在请求前有处理,可以在这里处理
        filterChain.doFilter(request, responseWrapper);
        byte[] content = responseWrapper.getContent();
        String str = new String(content, "UTF-8");
//        System.out.println(str);
        str = callback + "(" + str + ")";
        //把返回值输出到客户端
        ServletOutputStream out = response.getOutputStream();
        byte[] re = str.getBytes("UTF-8");
        response.setContentLength(re.length);//重新设置返回长度
        out.write(re);
    }


    private class MyResponseWrapper extends HttpServletResponseWrapper {
        private ByteArrayOutputStream buffer;

        private ServletOutputStream out;

        public MyResponseWrapper(HttpServletResponse httpServletResponse) {
            super(httpServletResponse);
            buffer = new ByteArrayOutputStream();
            out = new WrapperOutputStream(buffer);
        }

        @Override
        public ServletOutputStream getOutputStream()
                throws IOException {
            return out;
        }

        @Override
        public void flushBuffer()
                throws IOException {
            if (out != null) {
                out.flush();
            }
        }

        public byte[] getContent()
                throws IOException {
            flushBuffer();
            return buffer.toByteArray();
        }

        class WrapperOutputStream extends ServletOutputStream {
            private ByteArrayOutputStream bos;

            public WrapperOutputStream(ByteArrayOutputStream bos) {
                this.bos = bos;
            }

            @Override
            public void write(int b)
                    throws IOException {
                bos.write(b);
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setWriteListener(WriteListener arg0) {
            }
        }
    }

    @Override
    public void init(FilterConfig arg0)
            throws ServletException {
    }

    @Override
    public void destroy() {
    }

}

使用@WebFilter 注解时,需要在启动类加上@ServletComponentScan

不使用@WebFilter 注解也可以使用手动注册,实现自定义扫描路径

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class ResponseFilterConfig {
    @Value("${jsonp-filter-urlPatterns:/*}")
    private String patterns;
    @Bean
    public FilterRegistrationBean setFilter(){

        FilterRegistrationBean filterBean = new FilterRegistrationBean();
        filterBean.setFilter(new ResponseFilter());
        filterBean.setName("callbackFilter");
        String[] patternStr=patterns.split(",");
        filterBean.addUrlPatterns(patternStr);
        return filterBean;
    }
}

yml添加参数设置扫描路径,不设置时缺省值为 /*,即扫描全路径

jsonp-filter-urlPatterns: /user/getList,/user/get

修改Response参考博客:https://blog.csdn.net/u011974797/article/details/81315503
Filter两种实现参考博客: https://blog.csdn.net/qq_27905183/article/details/79078561


版权声明:本文为rui15111原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。