struts令牌机制
来源:互联网 发布:淘宝医药商城 编辑:程序博客网 时间:2024/06/04 19:14
struts令牌机制
在提交表单后,刷新或者后退重新点击保存,如果没有处理的话,可能会造成表单的重复提交,struts的令牌(token)机制可以方便的避免这种现象。
主要方法
- 在表单提交页面增加一个隐藏域
<input type="hidden" name="TOKEN" value="14c425db7657e2bd0b415b0661df5ef7"/>
- 同时在session域中放置一份
session.setAttribute("TOKEN", "14c425db7657e2bd0b415b0661df5ef7");
- 提交表单时,获取session中TOKEN的值,同时获取隐藏域中的值
request.getParameter("TOKEN");
如果两者相同,则调用dao层对数据进行保存,并从session中删除TOKEN的值; 否则表单重复提交
struts令牌(Token)机制
- 在跳转到表单提交页面之前,使用
this.saveToken(request)
方法,会自动在表单提交页面添加一个隐藏域,如下
同时该token的值也会在session中保存一份.
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("执行EmployeeAction中add方法"); this.saveToken(request); return mapping.findForward("add");}
- 保存表单时, 使用
this.TokenValid(request)
来判断token是否有效,如果true, 则dao层对数据处理,并且调用this.resetToken(request)
从session中删除token, 如果返回false, 则说明表单重复提交,不再使用dao层对数据进行处理。
public ActionForward save(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { // TODO Auto-generated method stub System.out.println("> 执行EmployeeAction中save方法...."); if(!this.isTokenValid(request)){ System.out.println("表单重复提交"); //这里, 表单重复提交时,仍会跳转到保存成功页面,但是不会对数据进行处理 return mapping.findForward("success"); } this.resetToken(request); //dao层处理省略 return mapping.findForward("success"); }
源码查看
//org.apache.struts.action.Actionpublic class Action { //这里只是复制了一些会用到的方法,详细的看源代码 private static TokenProcessor token = TokenProcessor.getInstance(); //给token赋值,就是那个很长的字符串 protected String generateToken(HttpServletRequest request) { return token.generateToken(request); } //判断是否有效 protected boolean isTokenValid(HttpServletRequest request, boolean reset) { return token.isTokenValid(request, reset); } //重置 protected void resetToken(HttpServletRequest request) { token.resetToken(request); } //保存 protected void saveToken(HttpServletRequest request) { token.saveToken(request); }//org.apache.struts.util.TokenProcessorpublic class TokenProcessor { //可以看出这个就是session和hidden中token的比较过程 public synchronized boolean isTokenValid(HttpServletRequest request, boolean reset) { // Retrieve the current session for this request HttpSession session = request.getSession(false); if (session == null) { return false; } // Retrieve the transaction token from this session, and // reset it if requested String saved = (String) session.getAttribute(Globals.TRANSACTION_TOKEN_KEY); if (saved == null) { return false; } if (reset) { this.resetToken(request); } // Retrieve the transaction token included in this request String token = request.getParameter(Globals.TOKEN_KEY); if (token == null) { return false; } return saved.equals(token); } //从session域中删除token public synchronized void resetToken(HttpServletRequest request) { HttpSession session = request.getSession(false); if (session == null) { return; } session.removeAttribute(Globals.TRANSACTION_TOKEN_KEY); } }public class Globals implements Serializable {//session保存时,域的key值 public static final String TRANSACTION_TOKEN_KEY = "org.apache.struts.action.TOKEN";//view层隐藏域hidden的name public static final String TOKEN_KEY = "org.apache.struts.taglib.html.TOKEN"}
关于token的长字符串的生成过程,感觉这个算法,人家写的很有水平,这里复制过来,学习一下
public class TokenProcessor { 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是java自带的加密算法,经过update方法收集数据,之后使用digest完成哈希计算,生成固定长度的字节数组(本人测试的是16) MessageDigest md = MessageDigest.getInstance("MD5"); md.update(id.getBytes()); md.update(now); return toHex(md.digest()); } catch (NoSuchAlgorithmException e) { return null; } } //这里使用将字节数组转化为一个字符串(长度为原字节数组大小的2倍) //byte大小为-128到127, 为8位二进制数据,这里将其高4位和低4位分别转化为一个字符char(范围是从0-f),比如字节92=0x5c,可以得到字符5和c private String toHex(byte[] buffer) { StringBuffer sb = new StringBuffer(buffer.length * 2); for (int i = 0; i < buffer.length; i++) { sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16)); sb.append(Character.forDigit(buffer[i] & 0x0f, 16)); } return sb.toString(); }}//Character中的forDigit方法public static char forDigit(int digit, int radix) { if ((digit >= radix) || (digit < 0)) { return '\0'; } if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) { return '\0'; } if (digit < 10) { return (char)('0' + digit); } return (char)('a' - 10 + digit); }
0 0
- 关于struts令牌机制
- struts令牌机制
- Struts的令牌机制
- struts令牌机制
- 关于Struts的令牌机制
- 关于struts令牌机制(Token)
- 对于Struts框架中的令牌机制
- Struts的Token(令牌)机制
- struts令牌
- 使用struts同步令牌机制避免表单的重复提交
- 使用struts同步令牌机制避免表单的重复提交
- 使用struts同步令牌机制避免表单的重复提交
- struts令牌机制防止重复提交 savetoken(request) resetToken(request)
- 使用struts同步令牌机制避免表单的重复提交
- Struts 1.2 令牌
- struts中的令牌token
- 令牌机制,校验码
- struts2令牌机制
- Android Bluetooth(蓝牙)实例
- leetcode 24. Swap Nodes in Pairs
- 两个链表的第一个公共节点
- SGU 223 little kings BSOJ2772 状压DP
- leetcode 167 Two Sum II - Input array is sorted C++
- struts令牌机制
- Java中反射知识的理解介绍
- Scala10
- poj 3348 Cows
- Hive安装
- transaction简介
- 2016年之年中总结
- Best Time to Buy and Sell Stock II
- 用Java语言写的万年历的小程序