编辑
2023-11-06
学习记录
00
请注意,本文编写于 514 天前,最后修改于 484 天前,其中某些信息可能已经过时。

目录

前提
WebMvcConfig代码
拦截器代码
HttpServlet包装类代码
过滤器代码

前提

业务需要,得对特定的请求进行拦截,判断能不能满足状态,满足后才放行,不满足的话就抛出异常,过程主要分为四部分,首页是webMvcConfg配置,如何是拦截器的拦截逻辑编写,然后是对于json类型的消息头需要重写HttpServletRequestWrapper方法,实现多次对流的读取,不然拦截器读取后,放行请求路径对应的方法就获取不到请求体了,因为流只能读一次,所以还需要过滤器将对应的请求再塞回去

WebMvcConfig代码

java
@Configuration public class WebConfig implements WebMvcConfigurer { @Resource private IRecSealService iRecSealService; /** * 添加拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { //添加拦截器,并且指定需要拦截的请求路径 registry.addInterceptor(new URLInterceptor(iRecSealService)) .addPathPatterns("/recMrIndex/aaa" , "/recMrIndex/bbb" , "/recMrIndex/ccc" , "/recUpperShelf/ddd" ); WebMvcConfigurer.super.addInterceptors(registry); } /** * 对指定请求的 HttpServletRequest 进行重新注册返回 * */ @Bean public FilterRegistrationBean setLogServiceFilter() { //使用过滤器将请求体塞回去避免流只能读一次造成的错误 FilterRegistrationBean registrationBean = new FilterRegistrationBean(); RequestBodyFilter requestBodyFilter = new RequestBodyFilter(); registrationBean.setFilter(requestBodyFilter); registrationBean.setName("interceptor filter body params"); registrationBean.addUrlPatterns("/recMrIndex/aaa" , "/recMrIndex/bbb" , "/recMrIndex/ccc" , "/recUpperShelf/ddd" ); registrationBean.setOrder(1); return registrationBean; } }

拦截器代码

java
/** * * <p> * 对特定的url进行拦截, 按添加的路径进行拦截,获取 各种参数,进行验证 * </p> * * @author lihaowei * @since: 2023/11/6 15:23 * */ @Component public class URLInterceptor implements HandlerInterceptor { @Resource private IRecSealService iRecSealService; public URLInterceptor(private IRecSealService iRecSealService) { this.iRecSealService = iRecSealService; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String contentType="application/json"; if (request.getContentType().contains(contentType)){ String methodName = request.getRequestURI().substring(request.getRequestURI().lastIndexOf("/") + 1); RequestReaderHttpServletRequestWrapper requestWrapper=new RequestReaderHttpServletRequestWrapper(request); String body = requestWrapper.inputStream2String(requestWrapper.getInputStream()); switch (methodName) { //aaa case "aaa": ObjectRequest receiveRequest = JSON.parseObject(body,ObjectRequest.class); if (ObjectUtil.isNull(receiveRequest)) { return true; } return getSealPatientStatusByList(receiveRequest.getList,ObjectRequest.class); //bbb case "bbb": List<ObjectRequest> sends = JSON.parseArray(body, ObjectRequest.class); return getSealPatientStatusByList(receiveRequest.getList,ObjectRequest.class); //ccc case "ccc": List<ObjectRequest> bindRequest = JSON.parseArray(body, ObjectRequest.class); return getSealPatientStatusByList(receiveRequest.getList,ObjectRequest.class); //ddd case "ddd": ObjectRequest onShelf = JSON.parseObject(body, ObjectRequest.class); if (ObjectUtil.isEmpty(onShelf)) { return true; } List<patientRequest> patients=new ArrayList<>(); ..... return getSealPatientStatus(patients); } } return HandlerInterceptor.super.preHandle(request, response, handler); } public boolean getSealPatientStatus(List<PatientRequest> patients){ for (PatientRequest request : patients) { QueryWrapper<RecSealEntity> queryWrapper=new QueryWrapper<>(); ..... RecSealEntity recSeal = iRecSealService.getOne(queryWrapper); if (ObjectUtil.isNull(recSeal)){ return true; } if () { //判断业务逻辑 } else { //判断业务逻辑 } } return true; } public <T> boolean getSealPatientStatusByList(List<T> list,Class<T> clazz) { if (CollUtil.isEmpty(list)) { return true; } List<PatientRequest> patients= new ArrayList<>(); try { for (T t:list){ PatientRequest patient=new PatientRequest(); Field patientId=clazz.getDeclaredField("patientId"); Field visitNo=clazz.getDeclaredField("visitNo"); //允许访问私有属性值 patientId.setAccessible(true); visitNo.setAccessible(true); patient.setPatientId((String) patientId.get(t)); patient.setVisitNo((String) visitNo.get(t)); patients.add(patient); } }catch (NoSuchFieldException e) { e.printStackTrace(); throw new BusinessException(ResultCodeEnum.ERR_0x1000.getCode(),"拦截器获取属性出错属性值为空:"+e.getMessage()); } catch (IllegalAccessException e) { e.printStackTrace(); throw new BusinessException(ResultCodeEnum.ERR_0x1000.getCode(),"拦截器获取属性出错"); } if (CollUtil.isEmpty(patients)){ return true; } return getSealPatientStatus(patients); } }

HttpServlet包装类代码

java
/** * 解决拦截器从流中获取完整的 body 请求参数后,无法再次调用流中数据的问题,否则报以下错误信息 * <p> * I/O error while reading input message; nested exception is java.io.IOException: Stream closed */ public class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final Logger LOGGER = LoggerFactory.getLogger(this.getClass()); private final byte[] body; public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = inputStream2String(request.getInputStream()).getBytes(Charset.forName("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) { } }; } /** * 将 inputStream 里的数据读取出来并转换成字符串 * * @param inputStream inputStream * @return String */ public String inputStream2String(InputStream inputStream) { StringBuilder sb = new StringBuilder(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { sb.append("get body params fail"); LOGGER.error(e.getMessage()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { LOGGER.error(e.getMessage()); } } } return sb.toString(); } }

过滤器代码

java
/** * * <p> * 重新组装 HttpServletRequest 返回, 解决拦截器中从流中获取完 post 请求中的 body 参数,controller 层无法再次获取的问题 * </p> * * @author lihaowei * @since: 2023/11/6 15:21 * */ public class RequestBodyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; String method = httpServletRequest.getMethod(); String contentType = httpServletRequest.getContentType() == null ? "" : httpServletRequest.getContentType(); // 如果是POST请求并且不是文件上传 if (HttpMethod.POST.name().equals(method) && !contentType.equals(MediaType.MULTIPART_FORM_DATA_VALUE)) { // 重新生成ServletRequest 这个新的 ServletRequest 获取流时会将流的数据重写进流里面 requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request); } } if (requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { Filter.super.destroy(); } }

本文作者:Weee

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!