struts1(6)-----表单防重复提交

本文介绍如何使用Struts框架内置的功能防止表单重复提交,通过生成随机数并保存于session中,确保每次表单提交的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传统servlet对于防止表单重复提交的办法是,在提交前生成一个随机数,这个随机数将添加到request域中,同时检验要是session域中没有存这么一个随机数,则将其存入session域,否则不存。这样服务器端在收到request请求后,将其request域中的随机数取出,同时也将session域中的随机数取出。要是两者相同,则认为表单是正常提交,要是不一致则认为是重复提交。若是处理正常的表单提交时,则在提交成功后,将这个session域中的随机数清除,这样不会将下次正常的表单提交也误认为是重复提交。

struts框架对此问题进行了专门的处理,不需要开发者手动编写相关代码来生成随机数。struts提供了专门的方法来生成随机数,开发者只需要调用相关方法就可以解决这方面的问题。使用struts框架,处理表单重复提交的问题变得简单了很多。struts利用tokenProcess类的方法来完成此功能。

下面是一个例子: 它在跳转到表单提交页面前,先会会跳转到一个action上,此action负责生成一个随机数,同时将这个随机数存入到session域中,之后在跳转到表单提交的页面。struts框架利用tokenProcess类中的savaToken(request)来完成此功能。

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>
	<form-beans>
		<form-bean name="UserFormBean" type="cn.itcast.web.formbean.UserFormBean"></form-bean>
	</form-beans>

	<!-- 配置struts收到请求后找一个action处理 -->

	<action-mappings>
		<action path="/RegisterUI"
				type="cn.itcast.action.RegisterUIAction" 
				input="/WEB-INF/jsp/Register.jsp"/>
		
		<action path="/Register" 
				type="cn.itcast.action.RegisterAction"
				name="UserFormBean"
				scope="request"
				validate="true"
				input="/WEB-INF/jsp/Register.jsp"
				>
				
			<forward name="success" path="/success.jsp"></forward>	
			<forward name="message" path="/message.jsp"></forward>	
				
				
		</action>
		
	</action-mappings>
	
	<controller processorClass="org.apache.struts.action.RequestProcessor"></controller>
	<message-resources parameter="cn.itcast.resource.MessageResource"></message-resources>
</struts-config>
RegisterUIAction用来生成一个随机数。

public class RegisterUIAction extends Action {

	@Override
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// TODO Auto-generated method stub
		saveToken(request);
		
		return mapping.getInputForward();
	}

}
其中saveToken(request)方法底层的源码如下所示:

public synchronized void saveToken(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String token = generateToken(request); //负责生成一个随机数

        if (token != null) {
            session.setAttribute(Globals.TRANSACTION_TOKEN_KEY, token);//将其存到
        }
    }
从上面的方法可以看到,generateToken负责生成一个随机数,当生成的随机数不为空时,则将其以org.apache.struts.action.TOKEN key值存入到session域中。下面是generateToken(request)方法的源码中的核心代码:

public synchronized String generateToken(String id) {
        try {
            long current = System.currentTimeMillis();

            if (current == previous) {
                current++;
            }

            previous = current;

            byte[] now = new Long(current).toString().getBytes();
            MessageDigest md = MessageDigest.getInstance("MD5");

            md.update(id.getBytes());
            md.update(now);

            return toHex(md.digest());
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
当RegisterUIAction生成一个随机数后,将会跳转到表单提交页面,由于采用的是struts的html标签,其form标签将会根据session域中是否有org.apache.struts.action.TOKEN属性来生成一个隐藏表单,其意义是,当存在这个属性后,证明要防表单重复提交。这是form标签会自动生成一个<input type="hiden"/>的标签,其存入的值为此session与中存入的随机数,将用来与session中的值进行比较,要是一致,则认为是正常表单提交,否则认为是重复提交,下面是<html:form>标签中生成此隐藏标签的源代码:

results.append(this.renderToken());
protected String renderToken() {
        StringBuffer results = new StringBuffer();
        HttpSession session = pageContext.getSession();

        if (session != null) {
            String token =
                (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY);

            if (token != null) {//要是存在,则生成一个隐藏字段
                results.append("<div><input type=\"hidden\" name=\"");
                results.append(Constants.TOKEN_KEY);
                results.append("\" value=\"");
                results.append(token);

                if (this.isXhtml()) {
                    results.append("\" />");
                } else {
                    results.append("\">");
                }

                results.append("</div>");
            }
        }

        return results.toString();
    }
从上面代码可以看出,它将会以org.apache.struts.taglib.html.TOKEN为属性名,以session中的token值为值,生成一个隐藏字段.这个字段将会在处理注册页面时取出并与session域中的存入的值进行校验,要是相等,则认为是有效提交,之后需要将此session域中的org.apache.struts.taglib.html.TOKEN删除,这样在继续刷新页面时,session域中将不会存在此域,从而爆出重复提交。删除指定session属性,TokenProces类也有一个函数完成此功能。如下所示:

resetToken(request);

其源码如下:

public synchronized void resetToken(HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        if (session == null) {
            return;
        }

        session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY);
    }
下面是处理registerAction源码:

public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// TODO Auto-generated method stub
		
		UserFormBean ufb = (UserFormBean)form;
		ufb.setUsername("zhangshan");
		ufb.setCity("beijing");
		ufb.setGender("male");
		
		
		if(isTokenValid(request)){
			request.setAttribute("message", "注册成功!!!");
			resetToken(request); //删除session域中的随机数
		}else{
			request.setAttribute("message", "不能重复提交!!!");
		}
		return mapping.getInputForward();
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值