mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-11-04 08:06:12 +08:00 
			
		
		
		
	实现 request body 重复读取的功能
This commit is contained in:
		@ -44,15 +44,4 @@ public class FilterConfig {
 | 
				
			|||||||
        return registration;
 | 
					        return registration;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @SuppressWarnings({"rawtypes", "unchecked"})
 | 
					 | 
				
			||||||
    @Bean
 | 
					 | 
				
			||||||
    public FilterRegistrationBean someFilterRegistration() {
 | 
					 | 
				
			||||||
        FilterRegistrationBean registration = new FilterRegistrationBean();
 | 
					 | 
				
			||||||
        registration.setFilter(new RepeatableFilter());
 | 
					 | 
				
			||||||
        registration.addUrlPatterns("/*");
 | 
					 | 
				
			||||||
        registration.setName("repeatableFilter");
 | 
					 | 
				
			||||||
        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
 | 
					 | 
				
			||||||
        return registration;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,45 +0,0 @@
 | 
				
			|||||||
package com.ruoyi.common.filter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import javax.servlet.Filter;
 | 
					 | 
				
			||||||
import javax.servlet.FilterChain;
 | 
					 | 
				
			||||||
import javax.servlet.FilterConfig;
 | 
					 | 
				
			||||||
import javax.servlet.ServletException;
 | 
					 | 
				
			||||||
import javax.servlet.ServletRequest;
 | 
					 | 
				
			||||||
import javax.servlet.ServletResponse;
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.springframework.http.MediaType;
 | 
					 | 
				
			||||||
import com.ruoyi.common.utils.StringUtils;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Repeatable 过滤器
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author ruoyi
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class RepeatableFilter implements Filter {
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void init(FilterConfig filterConfig) throws ServletException {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
 | 
					 | 
				
			||||||
            throws IOException, ServletException {
 | 
					 | 
				
			||||||
        ServletRequest requestWrapper = null;
 | 
					 | 
				
			||||||
        if (request instanceof HttpServletRequest
 | 
					 | 
				
			||||||
                && StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
 | 
					 | 
				
			||||||
            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (null == requestWrapper) {
 | 
					 | 
				
			||||||
            chain.doFilter(request, response);
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            chain.doFilter(requestWrapper, response);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void destroy() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,64 +0,0 @@
 | 
				
			|||||||
package com.ruoyi.common.filter;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.io.BufferedReader;
 | 
					 | 
				
			||||||
import java.io.ByteArrayInputStream;
 | 
					 | 
				
			||||||
import java.io.IOException;
 | 
					 | 
				
			||||||
import java.io.InputStreamReader;
 | 
					 | 
				
			||||||
import javax.servlet.ReadListener;
 | 
					 | 
				
			||||||
import javax.servlet.ServletInputStream;
 | 
					 | 
				
			||||||
import javax.servlet.ServletResponse;
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequest;
 | 
					 | 
				
			||||||
import javax.servlet.http.HttpServletRequestWrapper;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import com.ruoyi.common.utils.http.HttpHelper;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * 构建可重复读取inputStream的request
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @author ruoyi
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
 | 
					 | 
				
			||||||
    private final byte[] body;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
 | 
					 | 
				
			||||||
        super(request);
 | 
					 | 
				
			||||||
        request.setCharacterEncoding("UTF-8");
 | 
					 | 
				
			||||||
        response.setCharacterEncoding("UTF-8");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        body = HttpHelper.getBodyString(request).getBytes("UTF-8");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public BufferedReader getReader() throws IOException {
 | 
					 | 
				
			||||||
        return new BufferedReader(new InputStreamReader(getInputStream()));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public ServletInputStream getInputStream() throws IOException {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return new ServletInputStream() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @Override
 | 
					 | 
				
			||||||
            public int read() throws IOException {
 | 
					 | 
				
			||||||
                return bais.read();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @Override
 | 
					 | 
				
			||||||
            public boolean isFinished() {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @Override
 | 
					 | 
				
			||||||
            public boolean isReady() {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            @Override
 | 
					 | 
				
			||||||
            public void setReadListener(ReadListener readListener) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
package cn.iocoder.dashboard.framework.web.config;
 | 
					package cn.iocoder.dashboard.framework.web.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.iocoder.dashboard.framework.web.core.filter.RequestBodyCacheFilter;
 | 
				
			||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
					import org.springframework.boot.context.properties.EnableConfigurationProperties;
 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
@ -50,4 +51,13 @@ public class WebConfiguration implements WebMvcConfigurer {
 | 
				
			|||||||
        return new CorsFilter(source);
 | 
					        return new CorsFilter(source);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 创建 RequestBodyCacheFilter Bean,可重复读取请求内容
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Bean
 | 
				
			||||||
 | 
					    @Order(Integer.MIN_VALUE)
 | 
				
			||||||
 | 
					    public RequestBodyCacheFilter requestBodyCacheFilter() {
 | 
				
			||||||
 | 
					        return new RequestBodyCacheFilter();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					package cn.iocoder.dashboard.framework.web.core.filter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import cn.hutool.core.util.StrUtil;
 | 
				
			||||||
 | 
					import org.springframework.http.MediaType;
 | 
				
			||||||
 | 
					import org.springframework.web.filter.OncePerRequestFilter;
 | 
				
			||||||
 | 
					import org.springframework.web.util.ContentCachingRequestWrapper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.servlet.FilterChain;
 | 
				
			||||||
 | 
					import javax.servlet.ServletException;
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletRequest;
 | 
				
			||||||
 | 
					import javax.servlet.http.HttpServletResponse;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Request Body 缓存 Filter,实现它的可重复读取
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 基于 Spring 提供的 {@link org.springframework.web.util.ContentCachingRequestWrapper} 实现
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @author 芋道源码
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class RequestBodyCacheFilter extends OncePerRequestFilter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
 | 
				
			||||||
 | 
					            throws IOException, ServletException {
 | 
				
			||||||
 | 
					        filterChain.doFilter(new ContentCachingRequestWrapper(request), response);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected boolean shouldNotFilter(HttpServletRequest request) {
 | 
				
			||||||
 | 
					        // 只处理 json 请求内容
 | 
				
			||||||
 | 
					        return !StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user