java通过拦截器校验进行参数校验,在接口调用前进行校验,解决jar包中class文件无法修改,但不想修改源码的场景
1.定义参数拦截接口ParamsCheckInter.java
package cn.togeek.config; public interface ParamsCheckInter<T> { T doCheck(Object... args); }
2.定义参数校验实现逻辑 ScContractDecomposeWayInterHandler.java
package cn.togeek.config; import cn.togeek.entity.ScContractDecomposeWay; import cn.togeek.exception.ClientError; import org.springframework.util.Assert; import org.springframework.util.StringUtils; public class ScContractDecomposeWayInterHandler implements ParamsCheckInter<Boolean> { @Override public Boolean doCheck(Object... args) { ScContractDecomposeWay way = (ScContractDecomposeWay) args[0]; String info = way.getInfo(); Assert.isTrue(StringUtils.hasLength(info),()->{throw new ClientError("分解方式不能为空");}); return way.isInfoOk(); } }
3.重写过滤器,避免request对象读取流后,controller层参数失效,原因是流只能读取一次
3.1 request包装类RequestWrapper.java
package cn.togeek.config; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.Charset; /** * @author wangyan * @description 获取请求参数并处理 * @date 2019/7/18 18:38 */ public class RequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public RequestWrapper(HttpServletRequest request) { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(Charset.forName("UTF-8")); } public String getBodyString(){ return new String(body,Charset.forName("UTF-8")); } /** * 获取请求Body * * @param request * @return */ 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, Charset.forName("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(); } } } return sb.toString(); } /** * Description: 复制输入流</br> * * @param inputStream * @return</br> */ 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(); } InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return byteArrayInputStream; } @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) { } }; } }
3.2.重新对request对象进行封装,放入到过滤器链中 RequestParamsFilter.java
package cn.togeek.config; 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.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; /** * * @Author TCL * @Date 2021/4/26 15:30 * @Version 1.0 */ @WebFilter(filterName="bodyReaderFilter",urlPatterns="/*") public class RequestParamsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // do nothing } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper=null; if(request instanceof HttpServletRequest) { requestWrapper=new RequestWrapper((HttpServletRequest)request); } if(requestWrapper==null) { chain.doFilter(request, response); }else { chain.doFilter(requestWrapper, response); } } }
3.3.拦截器 ParamsCheckIntercepter.java
package cn.togeek.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import cn.togeek.util.EmpSpringContextUtil;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.Environment;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 参数过滤拦截器
*/
@Slf4j
public class ParamsCheckIntercepter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod = (HandlerMethod) handler;
String method = request.getMethod();
Environment environment = EmpSpringContextUtil.getBean(Environment.class);
String requestUrl = request.getRequestURI();
List<RequestInfos> list = IntercepterList.getList();
Map<String, String[]> originRequestMap = request.getParameterMap();
Map<String,Object> requestMap = new HashMap<>();
for (String key : originRequestMap.keySet()) {
String[] values = originRequestMap.get(key);
requestMap.put(key,values[0]);
}
String param;
String contextPath = environment.getProperty("server.servlet.context-path");
if(StringUtils.isNotEmpty(contextPath)) {
requestUrl = requestUrl.replaceAll(contextPath,"");
}
for(RequestInfos requestInfo : list) {
String url = requestInfo.getUrl();
String infoMethod = requestInfo.getMethod();
String fullClassName = requestInfo.getFullClassName();
if(infoMethod.equalsIgnoreCase(method) && url.equals(requestUrl)) {
log.info("ParamsCheckIntercepter#preHandle contextPath:{},requestInfo:{}",contextPath,JSON.toJSONString(requestInfo));
try {
String body = new RequestWrapper(request).getBodyString();
MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
int length = methodParameters.length;
Object args[] = new Object[length];
if(StringUtils.isNotBlank(body)){
LinkedHashMap<String,String> map = JSONObject.parseObject(body, LinkedHashMap.class);
requestMap.putAll(map);
}
JSONObject info = new JSONObject(requestMap);
param = JSON.toJSONString(requestMap);
System.out.println("拦截器参数:"+param);
for(int i = 0; i < methodParameters.length; i++) {
MethodParameter methodParameter = methodParameters[i];
try {
args[i] = info.toJavaObject(methodParameter.getParameterType());
}
catch(Exception e) {
e.printStackTrace();
}
}
if(StringUtils.isNotEmpty(fullClassName)) {
Class<?> aClass = Class.forName(fullClassName);
Object bean = aClass.newInstance();
if(bean instanceof ParamsCheckInter) {
ParamsCheckInter<Boolean> interBean = (ParamsCheckInter<Boolean>) bean;
return interBean.doCheck(args);
}
}
return true;
} catch (Exception e) {
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.write(e.getMessage());
writer.flush();
writer.close();
return false;
}
}
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception
{
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception
{
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
4.过滤器和拦截器注册AdminWebConfig.java
package cn.togeek.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class AdminWebConfig implements WebMvcConfigurer { /** * 配置拦截器 * @param registry 相当于拦截器的注册中心 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 下面这句代码相当于添加一个拦截器 添加的拦截器就是我们刚刚创建的 registry.addInterceptor(new ParamsCheckIntercepter()) // addPathPatterns()配置我们要拦截哪些路径 addPathPatterns("/**")表示拦截所有请求,包括我们的静态资源 .addPathPatterns() // excludePathPatterns()表示我们要放行哪些(表示不用经过拦截器) // excludePathPatterns("/","/login")表示放行“/”与“/login”请求 // 如果有静态资源的时候可以在这个地方放行 .excludePathPatterns("/","/login"); } @Bean public FilterRegistrationBean<RequestParamsFilter> Filters() { FilterRegistrationBean<RequestParamsFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new RequestParamsFilter()); registrationBean.addUrlPatterns("/*"); return registrationBean; } }
5.辅助类RequestInfos.java 对配置进行封装
package cn.togeek.config; import lombok.Data; @Data public class RequestInfos { //请求待拦截的url,不带项目名server.servlet.context-path部分 private String url; //待拦截的方法 private String method; //拦截器实现,需继承ParamsCheckInter private String fullClassName; }
6.application.yml配置文件中配置
config:
intercepters:
list:
- {url: /sc/contract, method: PUT}
- {url: /sc/contract/decomposeway, method: PUT, fullClassName: cn.togeek.config.ScContractDecomposeWayInterHandler}
7.配置类 IntercepterList.java
package cn.togeek.config; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "config.intercepters") public class IntercepterList { private static List<RequestInfos> list; public static List<RequestInfos> getList() { return list; } public void setList(List<RequestInfos> list) { this.list = list; } }

浙公网安备 33010602011771号