导火索:发生表单重复提交,数据库中多次插入多条空数据
1.springmvc的配置文件xml的相关的配置的位置要注意,拦截器的配置位置必须放置在扫描controller的配置后面,否则不能启用拦截方法。
<!--扫描@Controller--> <context:component-scan base-package="boss.net.controller"> </context:component-scan>
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="boss.net.controller.Interceptor.SameUrlDataInterceptor"/> </mvc:interceptor> </mvc:interceptors>
2.拦截器中的方法先判断controller的方法是否有相应的注解,如果没有注解,直接返回true;
如果有注解,再判断session存的url和参数是否相同,如果不同返回true,如果相同返回false;
package boss.net.controller.Interceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * 一个用户 相同url 同时提交 相同数据 验证 * 主要通过 session中保存到的url 和 请求参数。如果和上次相同,则是重复提交表单 * @author Administrator * */ public class SameUrlDataInterceptor extends HandlerInterceptorAdapter { private final static Logger logger = LoggerFactory.getLogger(SameUrlDataInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{ //System.out.println("###########拦截器preHandle#####################"); logger.info("###########拦截器preHandle#####################"); logger.info("#############session:"+request.getSession()); try { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); SameUrlData annotation = method.getAnnotation(SameUrlData.class); if (annotation != null) { if (repeatDataValidator(request))//如果重复相同数据 return false; else return true; } return true; } else { return super.preHandle(request, response, handler); } }catch (Exception e){ e.printStackTrace(); return false; } } /** * 验证同一个url数据是否相同提交 ,相同返回true * @param httpServletRequest * @return */ public boolean repeatDataValidator(HttpServletRequest httpServletRequest) throws IOException { // System.out.println("###########拦截器repeatDataValidator#####################"); //logger.info("###########拦截器repeatDataValidatore#####################"); RequestWrapper myRequestWrapper = new RequestWrapper((HttpServletRequest) httpServletRequest); String params = myRequestWrapper.getBody(); // BufferedReader streamReader = new BufferedReader( new InputStreamReader(httpServletRequest.getInputStream(), "UTF-8")); // StringBuilder responseStrBuilder = new StringBuilder(); // String inputStr; // while ((inputStr = streamReader.readLine()) != null) // responseStrBuilder.append(inputStr); //Map<String ,String> map1 = JSON.parseObject(Base64.decode(responseStrBuilder.toString()),Map.class); //String userToken = map1.get("token"); //String params=responseStrBuilder.toString(); //String params= JsonMapper.toJsonString(httpServletRequest.getParameterMap()); //logger.info("拦截器repeatDataValidatore:请求入参转换字符串:"+params); String url=httpServletRequest.getRequestURI(); Map<String,String> map=new HashMap<String,String>(); map.put(url, params); String nowUrlParams=map.toString();// Object preUrlParams=httpServletRequest.getSession().getAttribute("repeatData"); if(preUrlParams==null)//如果上一个数据为null,表示还没有访问页面 { httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); return false; } else//否则,已经访问过页面 { if(preUrlParams.toString().equals(nowUrlParams))//如果上次url+数据和本次url+数据相同,则表示城府添加数据 { return true; } else//如果上次 url+数据 和本次url加数据不同,则不是重复提交 { httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams); return false; } } } }
3.拦截器的判断是否重复提交的方法中,第一次使用的是获取请求的输入流来判断的,出现了不能流不能重复读的问题
解决方法:在拦截器之前加上了过滤器,将流转换成字节缓存下来,再把读取流的bufferedReader.close()
package boss.net.controller.Interceptor; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; public class RequestWrapper extends HttpServletRequestWrapper { private final String body; public RequestWrapper(HttpServletRequest request) throws IOException { super(request); StringBuilder stringBuilder = new StringBuilder(); BufferedReader bufferedReader = null; try { InputStream inputStream = request.getInputStream(); if (inputStream != null) { bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); char[] charBuffer = new char[128]; int bytesRead = -1; while ((bytesRead = bufferedReader.read(charBuffer)) > 0) { stringBuilder.append(charBuffer, 0, bytesRead); } } else { stringBuilder.append(""); } } catch (IOException ex) { throw ex; } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException ex) { throw ex; } } } body = stringBuilder.toString(); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes()); ServletInputStream servletInputStream = new ServletInputStream() { public boolean isFinished() { return false; } public boolean isReady() { return false; } public void setReadListener(ReadListener readListener) {} public int read() throws IOException { return byteArrayInputStream.read(); } }; return servletInputStream; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(this.getInputStream())); } public String getBody() { return this.body; } }