[关闭]
@liayun 2016-10-04T00:35:43.000000Z 字数 11539 阅读 1573

Struts2框架进阶(七)

Struts2框架学习


这是Struts2框架进阶七,本文将讲解使用<s:token />标签防止表单重复提交。
首先,我们不打算使用<s:token />标签防止表单重复提交。
我们先在WebRoot根目录下创建网站首页——index.jsp。

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%@ taglib uri="/struts-tags" prefix="s"%>
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  8. <title>Insert title here</title>
  9. </head>
  10. <body>
  11. <s:form action="itcast" namespace="/test" method="post">
  12. 姓名:<s:textfield name="name" />
  13. <input type="submit" value="发送" />
  14. <%-- <s:submit></s:submit> --%> <!-- 使用这个标签有一点不好的地方,该标签是在服务器端解析的,服务器在解析这段标签时要执行一段代码,这时会影响性能 -->
  15. </s:form>
  16. </body>
  17. </html>

注意:form表单中写一个提交按钮,建议使用input。因为<s:submit>会在服务端解析一段代码,影响性能。
接着,我们在cn.itcast.action包下创建一个Action——PersonAction.java,该Action类的具体代码如下:

  1. public class PersonAction {
  2. private String name;
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. public String execute() {
  10. // 保存数据到数据库
  11. return "success";
  12. }
  13. }

然后,我们要在struts.xml配置文件中配置该action了。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <!-- Struts2有一个名为主题的技术,它会在输入项外面生成一些html标签 -->
  7. <!-- 默认的视图主题,不使用就不会帮我们生成乱七八糟的代码了 -->
  8. <constant name="struts.ui.theme" value="simple" />
  9. <package name="itcast" namespace="/test" extends="struts-default">
  10. <action name="itcast" class="cn.itcast.action.PersonAction">
  11. <result>/WEB-INF/page/message.jsp</result>
  12. </action>
  13. </package>
  14. </struts>

最后我们在WEB-INF/page/目录下新建一个message.jsp页面。

  1. <%@page import="java.util.Date"%>
  2. <%@ page language="java" contentType="text/html; charset=UTF-8"
  3. pageEncoding="UTF-8"%>
  4. <%@ taglib uri="/struts-tags" prefix="s"%>
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  6. <html>
  7. <head>
  8. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  9. <title>Insert title here</title>
  10. </head>
  11. <body>
  12. <s:property value="name" />
  13. <br/><%=new Date() %>
  14. </body>
  15. </html>

测试,效果为:
记得插入.GIF图片
从中可以看出点击刷新按钮,表单重复提交了。现在到了我们使用<s:token />标签防止表单重复提交的时刻了。
<s:token />标签防止重复提交,用法如下:
第一步:在表单中加入<s:token />标签。

  1. <%@ page language="java" contentType="text/html; charset=UTF-8"
  2. pageEncoding="UTF-8"%>
  3. <%@ taglib uri="/struts-tags" prefix="s"%>
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  8. <title>Insert title here</title>
  9. </head>
  10. <body>
  11. <s:form action="itcast" namespace="/test" method="post">
  12. 姓名:<s:textfield name="name" /><s:token></s:token>
  13. <input type="submit" value="发送" />
  14. </s:form>
  15. </body>
  16. </html>

<s:token />标签会自动生成这样的html代码:

  1. <input type="hidden" name="struts.token" value="这是cookieid(由英文和数字组成)">

此cookieid号在服务端也会存在一份。
第二步,修改struts.xml配置文件如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <!-- Struts2有一个名为主题的技术,它会在输入项外面生成一些html标签 -->
  7. <!-- 默认的视图主题,不使用就不会帮我们生成乱七八糟的代码了 -->
  8. <constant name="struts.ui.theme" value="simple" />
  9. <package name="itcast" namespace="/test" extends="struts-default">
  10. <action name="itcast" class="cn.itcast.action.PersonAction">
  11. <interceptor-ref name="defaultStack" /> <!-- 千万别忘了 -->
  12. <interceptor-ref name="token" /> <!-- token为系统提供的拦截器 -->
  13. <result name="invalid.token">/index.jsp</result>
  14. <result>/WEB-INF/page/message.jsp</result>
  15. </action>
  16. </package>
  17. </struts>

以上配置加入了"token"拦截器和"invalid.token"结果,因为"token"拦截器在会话的token与请求的token不一致时,将会直接返回"invalid.token"结果。

  1. <interceptor-ref name="token" />

此拦截器拦截到请求后,会判断接收到的表单提交过来的cookieid,是否和保存在session中的cookieid相等,如果相等,为及时提交,拦截器会将存放在session中的cookieid进行变更,如果用户点击刷新按钮重复提交,它就会检测到两者不同,不同,拦截器会把这个请求返回给名为invalid.token的视图。
此时,我们进行测试,会看到如下结果:
记得插入.GIF图片
发现会报如下异常:

  1. java.lang.NullPointerException
  2. at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:640)
  3. at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:616)
  4. at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:210)
  5. at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:139)
  6. at org.apache.struts2.interceptor.TokenInterceptor.getErrorMessage(TokenInterceptor.java:182)
  7. at org.apache.struts2.interceptor.TokenInterceptor.handleInvalidToken(TokenInterceptor.java:166)
  8. at org.apache.struts2.interceptor.TokenInterceptor.handleToken(TokenInterceptor.java:151)
  9. at org.apache.struts2.interceptor.TokenInterceptor.doIntercept(TokenInterceptor.java:142)
  10. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  11. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  12. at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
  13. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  14. at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
  15. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  16. at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
  17. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  18. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  19. at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
  20. at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76)
  21. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  22. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  23. at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
  24. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  25. at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
  26. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  27. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  28. at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
  29. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  30. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  31. at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
  32. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  33. at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
  34. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  35. at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
  36. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  37. at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
  38. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  39. at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253)
  40. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  41. at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
  42. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  43. at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
  44. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  45. at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
  46. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  47. at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
  48. at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
  49. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  50. at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139)
  51. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  52. at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
  53. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  54. at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
  55. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  56. at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
  57. at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
  58. at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
  59. at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
  60. at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
  61. at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
  62. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
  63. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
  64. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
  65. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
  66. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
  67. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
  68. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
  69. at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
  70. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
  71. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
  72. at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
  73. at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
  74. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
  75. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
  76. at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
  77. at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
  78. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
  79. at java.lang.Thread.run(Unknown Source)

为了解决这个问题,我在网上找到了一篇文章——java.lang.NullPointerException at com.opensymphony.xwork2.util.Localize 来自戎码一生,我能力还不够,所以看的不是很懂,但是我还是从中找到了解决办法。我们可以从文章中找到这样一段话:

如果上面的getErrorMessage方法中执行了if语句里面的内容就不会走到textProvider.getText方法那里去,所以可以尝试让action的类型属于TextProvider,在TextProvider上ctrl+T可以看到其实现类上有ActionSupport类,所以这就知道了只需要让action类继承ActionSupport类即可避免抛出上面的空指针异常

因此解决办法就是:让action类继承ActionSupport类。这样,我们就要修改PersonAction类的代码为:

  1. public class PersonAction extends ActionSupport {
  2. private String name;
  3. public String getName() {
  4. return name;
  5. }
  6. public void setName(String name) {
  7. this.name = name;
  8. }
  9. public String execute() {
  10. // 保存数据到数据库
  11. return "success";
  12. }
  13. }

现在我们再来测试,结果为:

可以发现当表单重复提交时,跳回到了首页。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注