日常开发中,防表单重复提交是一项必须的工作
我们可以利用javascript防止表单重复提交,但是利用javascript防止表单重复提交会出现一个新的问题
因为某些用户可能会绕过script代码直接提交给服务器,这样就做不到防止表单重复提交了
所以我们要在服务器后端进行拦截
拦截的原理就是利用hidden这个隐藏域进行表单提交,并且hidden携带了服务器随机生成的字符串
我们可以把服务器端随机生成的字符串放入session作用域
这样,当我们进入servlet进行验证的时候就能取出我们随机生成的字符串
再和hidden提交过来的字符串进行比较
下面来看代码部分,首先是登录页面,我们需要进行一点处理,因为要生成一个随机字符串
我们利用servlet进行生成并且在jsp页面得到这个生成的随机字符串
看代码,这里利用TokenProsessor单例类生成
import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; import sun.misc.BASE64Encoder; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @SuppressWarnings({ "serial", "restriction" }) public class FormServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); String token = TokenProcessor.getInstance().generateToken(); session.setAttribute("token", token); request.getRequestDispatcher("/index.jsp").forward(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } } /** * 设置成单例类,降低产生的随机数的重复概率 * @author Scorpion * */ class TokenProcessor { private static TokenProcessor instance = new TokenProcessor(); private TokenProcessor(){} public static TokenProcessor getInstance() { return instance; } @SuppressWarnings("restriction") public String generateToken() { Random random = new Random(); String randomStr = System.currentTimeMillis() + random.nextInt(999999999) + ""; try { MessageDigest md = MessageDigest.getInstance("md5"); byte[] md5 = md.digest(randomStr.getBytes()); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(md5); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }
接下来跳转到jsp页面,下面是一个简单的表单,其中hidden中的value遍是我们生成的并且放到session作用域的随机字符串
<form action="/DoFormServlet" method="post"> username:<input type="text" id="username" name="username"/></br> password:<input type="password" id="password" name="password"/><br> <input type="hidden" value="${token}" id="token" name="token"/> <input type="submit" value="submit"/> </form>
表单提交后再把流程转到DoFormServlet
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @SuppressWarnings("serial") public class DoFormServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); boolean b = isToken(req); if(!b) { out.write("请不要重复提交表单"); return; } req.getSession().removeAttribute("token"); out.write("欢迎你:" + username); } private boolean isToken(HttpServletRequest req) { String client_token = req.getParameter("token"); if(client_token==null){ return false; } String server_token = (String) req.getSession().getAttribute("token"); if(server_token==null){ return false; } if(!client_token.equals(server_token)){ return false; } return true; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }
至此,本例完成。。。