因为我的项目须要应用拦截器对申请参数进行操作,可是申请流只能操作一次,导致前面办法不能再获取流了。
新建 SpringBoot 我的项目
1. 新建拦截器 WebConfig.java
/**
* @date: 2023/2/6 11:21
* @author: zhouzhaodong
* @description:
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 增加 Web 我的项目的拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 对所有拜访门路,都通过 MyInterceptor 类型的拦截器进行拦挡
// 放行登录页,登陆操作,动态资源
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/", "/login", "/index.html", "/user/login", "/css/**", "/images/**", "/js/**", "/fonts/**");
}
}
2. 获取申请参数并解决逻辑
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 获取申请参数并解决
*/
public class RequestWrapper extends HttpServletRequestWrapper {private final Logger logger = LoggerFactory.getLogger(RequestWrapper.class);
private final byte[] body;
public RequestWrapper(HttpServletRequest request) {super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(StandardCharsets.UTF_8);
}
public String getBodyString() {return new String(body, StandardCharsets.UTF_8);
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 获取申请 Body
*/
public String getBodyString(final ServletRequest request) {StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {inputStream = cloneInputStream(request.getInputStream());
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = "";
while ((line = reader.readLine()) != null) {sb.append(line);
}
} catch (IOException e) {e.printStackTrace();
} finally {if (inputStream != null) {
try {inputStream.close();
} catch (IOException e) {e.printStackTrace();
}
}
if (reader != null) {
try {reader.close();
} catch (IOException e) {e.printStackTrace();
}
}
}
logger.info("获取 body 申请参数:" + sb);
return sb.toString();}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 复制输出流
*/
public InputStream cloneInputStream(ServletInputStream inputStream) {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {while ((len = inputStream.read(buffer)) > -1) {byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();} catch (IOException e) {e.printStackTrace();
}
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
@Override
public BufferedReader getReader() {return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {return bais.read();
}
@Override
public boolean isFinished() {return false;}
@Override
public boolean isReady() {return false;}
@Override
public void setReadListener(ReadListener readListener) {}};
}
}
3. 实现 HandlerInterceptor 接口
/**
* @date: 2023/2/6 11:19
* @author: zhouzhaodong
* @description: 实现 HandlerInterceptor 接口
*/
public class MyInterceptor implements HandlerInterceptor {private final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
/**
* @date: 2023/2/6 11:19
* @author: zhouzhaodong
* @description: 拜访控制器办法前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {logger.info("================ 进入拦截器 ======================");
logger.info(new Date() + "--preHandle:" + request.getRequestURL());
logger.info("***************************【RequestBeginning】***************************");
logger.info("----------------StartProcessingRequest----------------");
try {long currentTime = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date(currentTime);
logger.info("CurrentTime: {}", formatter.format(date));
logger.info("ResponseTime: {}", (System.currentTimeMillis() - currentTime) + "ms");
String requestUrl = request.getRequestURI();
logger.info("RequestURL: {}", requestUrl);
logger.info("GetMethod: {}", handler);
String method = request.getMethod();
logger.info("Method: {}", method);
// 获取申请参数
RequestWrapper requestWrapper = new RequestWrapper(request);
// 这里 getBodyString() 办法无参数
logger.info("RequestBody: {}", requestWrapper.getBodyString());
} catch (Exception e) {logger.error("MVC 业务解决 - 拦截器异样:", e);
}
logger.info("-------------------------End-------------------------");
return true;
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: 拜访控制器办法后执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {logger.info(new Date() + "--postHandle:" + request.getRequestURL());
}
/**
* @date: 2023/2/6 12:46
* @author: zhouzhaodong
* @description: postHandle 办法执行实现后执行,个别用于开释资源
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {logger.info(new Date() + "--afterCompletion:" + request.getRequestURL());
}
}
4. application.yml
spring:
main:
# 当呈现雷同名字的类进行注册时,准许笼罩注册
allow-bean-definition-overriding: true
5. 启动类增加 @ServletComponentScan 注解
6. 新建 TestController.java
/**
* @date: 2023/2/6 12:24
* @author: zhouzhaodong
* @description: 测试
*/
@RestController
public class TestController {@PostMapping("/one/abc")
public String abc(@RequestBody User user){return user.getName();
}
}
7. 不进行解决先测试看后果
申请后果:
控制台输入:
能够看出,流被读取了一次而后后盾就获取不到了。
8. 通过过滤器获取参数而后传到前面程序中
/**
* @date: 2023/2/6 12:47
* @author: zhouzhaodong
* @description:
*/
@Component
@WebFilter(urlPatterns = "/*", filterName = "channelFilter")
public class ChannelFilter implements Filter {private final Logger logger = LoggerFactory.getLogger(ChannelFilter.class);
@Override
public void init(FilterConfig filterConfig) { }
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {logger.info("================ 进入过滤器 ======================");
// 避免流读取一次后就没有了, 所以须要将流持续写出去
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void destroy() {}
}
9. 流解决后再进行测试
申请后果:
控制台输入:
解决啦!!!
源代码门路
https://github.com/zhouzhaodo…