1.DispatcherServlet


    SpringMVC具有统一的入口DispatcherServlet,所有的请求都通过DispatcherServlet。


    DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据XX规则分发到目标Controller层来处理。  所以我们现在

web.xml 中加入以下配置:


<!-- spring mvc的核心类 -->
<servlet>
	<servlet-name>mvc</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		
	<!-- 可以指定扫描的spring.xml文件 -->
	<!--<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:cn/et/lesson07/resource/spring.xml</param-value>
	</init-param>
		--><!-- 启动实例化 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>mvc</servlet-name>
	<url-pattern>/</url-pattern>   所有的请求都会被DispatcherServlet处理
</servlet-mapping>





2、静态资源不用拦截

  如果只配置拦截类似于*.do格式或其他格式的url(<url-pattern>*.do</url-pattern>),则对静态资源的访问是没有问题的,但是如果配置拦截了所有的请求(如我们上面配置的“/”),就会造成js文件、css文件、图片文件等静态资源无法访问。
      一般实现拦截器主要是为了权限管理,主要是拦截一些url请求,所以不对静态资源进行拦截。要过滤掉静态资源一般在

DispatcherServlet之前添加    <mvc:default-servlet-handler />把所有的静态资源交给servlet处理   这样导致Springmvc无法运行   需要在springmvc中添加   <mvc:annotation-driven></mvc:annotation-driven>

        或是直接在springmvc.xml中添加静态资源的映射

                                      <mvc:resources location="/WEB-INF/imgs/" mapping="/img/**"></mvc:resources>




3、拦截器

SpringMVC的拦截器HandlerInterceptorAdapter对应提供了三个preHandle,postHandle,afterCompletion方法。

      preHandle在业务处理器处理请求之前被调用,
     postHandle在业务处理器处理请求执行完成后,生成视图之前执行,

     afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等 。

      所以要想实现自己的权限管理逻辑,需要继承HandlerInterceptorAdapter并重写其三个方法。



使用拦截器实现防止重复提交

表单的重复提交:

一、重复提交的情况:

①.在表单提交到一个Servlet中,而Servlet又通过请求转发的方式响应一个JSP页面,此时地址栏还保留着Servlet的那个路径,在相应页面点击"刷新"

②.由于网络原因在相应页面没有到达是重复点击提交表单

③.点击"返回",然后再次点击"提交"

④.重定向还会重现上面②③点描述的情况,但是重定向后地址栏路径会发生改变,故不会出现①的情况

二、不是重复提交的情况

点击"返回","刷新"原表单页面,再"提交",不属于重复提交情况


解决表单的重复提交


使用session设置令牌

产生页面时,服务器为每次产生的Form分配唯一的随机标识号,并且在form的一个隐藏字段中设置这个标识号,

同时在当前用户的Session中保存这个标识号。当提交表单时,服务器比较hidden和session中的标识号是否相同,

相同则继续,处理完后清空Session,否则服务器忽略请求。


案例

自定义实现一个拦截器

实现HandlerInterceptor接口   重写public boolean preHandle(HttpServletRequestrequest,HttpServletResponseresponse, Object handler)方法


package cn.et.springmvc.lesson05;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;




public class KInteractor implements HandlerInterceptor{

	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		
	}
	
	
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		// TODO Auto-generated method stub
		
	}
	
	//会在action被调用之前执行   返回true通过  返回false不通过
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		
		//获取请求中的myToken的随机值
		String m=request.getParameter("myToken");
		
		//获取第一次访问页面时在session中设的值 (在自定义标签中做的操作)
		Object m1=request.getSession().getAttribute("myToken");
		//当m不为空   说明表单提交   需要判断是否是重复提交
		if(m!=null){
			//当m1不为空  session中有值   表单不是重复提交
			if(m1!=null){
				//为了防止表单参数被篡改   需要判断隐藏表单和session中的值是否相等
				if(m.equals(m1)){
					//把session中的唯一表示符清除
					request.getSession().removeAttribute("myToken");
					return true;
				}else{
					return false;
				}
			}else{
				return false;
			}
		}else{
			return true;
		}
	}
}



dao层

package cn.et.springmvc.lesson05;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class MoneyDaoImpl {
	@Autowired
	JdbcTemplate jdbc;
	//扣钱
	public void trasnateMoney(int money){
		String sql="update mymoney set lostedmoney=lostedmoney-"+money+" where id=1";
		jdbc.execute(sql);
	}
	
	//查询余额
	public int selectMoney(){
		String sql="select lostedmoney from mymoney where id=1";
		Integer i=jdbc.queryForObject(sql,Integer.class);
		return i;
	}
}




controller层

package cn.et.springmvc.lesson05;

import java.io.IOException;
import java.io.OutputStream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
 * 
 */
@Controller
public class ViewController {
	@Autowired
	MoneyDaoImpl did;
	
	@RequestMapping(value="/pppp",method=RequestMethod.GET)
	public String ty(Integer m,OutputStream os) throws IOException{
		//执行扣钱
		did.trasnateMoney(m);
		//查询余额
		os.write(("mmmm"+did.selectMoney()).getBytes());
		return null;
	}
}




在springmvc.xml中 配置以下内容

<mvc:interceptors>
      拦截pppp路径
      <mvc:interceptor>
        <mvc:mapping path="/pppp"/>
        <bean class="cn.et.springmvc.lesson05.KInteractor"></bean>      //拦截此路径   执行cn.et.springmvc.lesson05.KInteractor
      </mvc:interceptor>
</mvc:interceptors>





在WEB-INF中创建一个tags文件夹 放自定义标签 (token.tag) 包含生成一个随机数  把随机数放入session中

<%@ tag language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!-- tokenName值是选填项 -->
<%@attribute name="tokenName" required="false" %>
<%
	//产生一个随机数
	String ranStr=UUID.randomUUID().toString();
	//当tokenName值为空时使用myToken
	String key=(tokenName==null?"myToken":tokenName);
	//把随机数放入session中
	session.setAttribute(key,ranStr);
%>
<!-- 隐藏表单域 -->
<input type='hidden' name='<%=key %>' value='<%=ranStr %>'>



1、在表单页面引入自定义标签
<%@taglib tagdir="/WEB-INF/tags" prefix="my" %>
2、在form中引入
<form action="${pageContext.request.contextPath}/pppp">
    扣款:<input name="m">
	引入自定义标签
    <my:token></my:token>
    <input type="submit">
</form>


简单的页面效果

Java防止重复提交 用filter aop interceptor_spring



查看网页源代码  可知myToken中有值    在session中设置了与myToken中一样的值(在自定义标签中)

Java防止重复提交 用filter aop interceptor_重复提交_02