@liayun
2016-10-04T08:35:43.000000Z
字数 11539
阅读 1711
Struts2框架学习
这是Struts2框架进阶七,本文将讲解使用<s:token />
标签防止表单重复提交。
首先,我们不打算使用<s:token />
标签防止表单重复提交。
我们先在WebRoot根目录下创建网站首页——index.jsp。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="itcast" namespace="/test" method="post">
姓名:<s:textfield name="name" />
<input type="submit" value="发送" />
<%-- <s:submit></s:submit> --%> <!-- 使用这个标签有一点不好的地方,该标签是在服务器端解析的,服务器在解析这段标签时要执行一段代码,这时会影响性能 -->
</s:form>
</body>
</html>
注意:form表单中写一个提交按钮,建议使用input。因为<s:submit>
会在服务端解析一段代码,影响性能。
接着,我们在cn.itcast.action包下创建一个Action——PersonAction.java,该Action类的具体代码如下:
public class PersonAction {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String execute() {
// 保存数据到数据库
return "success";
}
}
然后,我们要在struts.xml配置文件中配置该action了。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- Struts2有一个名为主题的技术,它会在输入项外面生成一些html标签 -->
<!-- 默认的视图主题,不使用就不会帮我们生成乱七八糟的代码了 -->
<constant name="struts.ui.theme" value="simple" />
<package name="itcast" namespace="/test" extends="struts-default">
<action name="itcast" class="cn.itcast.action.PersonAction">
<result>/WEB-INF/page/message.jsp</result>
</action>
</package>
</struts>
最后我们在WEB-INF/page/目录下新建一个message.jsp页面。
<%@page import="java.util.Date"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:property value="name" />
<br/><%=new Date() %>
</body>
</html>
测试,效果为:
记得插入.GIF图片
从中可以看出点击刷新按钮,表单重复提交了。现在到了我们使用<s:token />
标签防止表单重复提交的时刻了。
<s:token />
标签防止重复提交,用法如下:
第一步:在表单中加入<s:token />
标签。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:form action="itcast" namespace="/test" method="post">
姓名:<s:textfield name="name" /><s:token></s:token>
<input type="submit" value="发送" />
</s:form>
</body>
</html>
<s:token />
标签会自动生成这样的html代码:
<input type="hidden" name="struts.token" value="这是cookieid(由英文和数字组成)">
此cookieid号在服务端也会存在一份。
第二步,修改struts.xml配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- Struts2有一个名为主题的技术,它会在输入项外面生成一些html标签 -->
<!-- 默认的视图主题,不使用就不会帮我们生成乱七八糟的代码了 -->
<constant name="struts.ui.theme" value="simple" />
<package name="itcast" namespace="/test" extends="struts-default">
<action name="itcast" class="cn.itcast.action.PersonAction">
<interceptor-ref name="defaultStack" /> <!-- 千万别忘了 -->
<interceptor-ref name="token" /> <!-- token为系统提供的拦截器 -->
<result name="invalid.token">/index.jsp</result>
<result>/WEB-INF/page/message.jsp</result>
</action>
</package>
</struts>
以上配置加入了"token"拦截器和"invalid.token"结果,因为"token"拦截器在会话的token与请求的token不一致时,将会直接返回"invalid.token"结果。
<interceptor-ref name="token" />
此拦截器拦截到请求后,会判断接收到的表单提交过来的cookieid,是否和保存在session中的cookieid相等,如果相等,为及时提交,拦截器会将存放在session中的cookieid进行变更,如果用户点击刷新按钮重复提交,它就会检测到两者不同,不同,拦截器会把这个请求返回给名为invalid.token的视图。
此时,我们进行测试,会看到如下结果:
记得插入.GIF图片
发现会报如下异常:
java.lang.NullPointerException
at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:640)
at com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:616)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:210)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:139)
at org.apache.struts2.interceptor.TokenInterceptor.getErrorMessage(TokenInterceptor.java:182)
at org.apache.struts2.interceptor.TokenInterceptor.handleInvalidToken(TokenInterceptor.java:166)
at org.apache.struts2.interceptor.TokenInterceptor.handleToken(TokenInterceptor.java:151)
at org.apache.struts2.interceptor.TokenInterceptor.doIntercept(TokenInterceptor.java:142)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:139)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1099)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:670)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
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类的代码为:
public class PersonAction extends ActionSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String execute() {
// 保存数据到数据库
return "success";
}
}
现在我们再来测试,结果为:
可以发现当表单重复提交时,跳回到了首页。