1. 预备知识:
a) 拦截器配置
在struts-default.xml中定义了很多拦截器,这些拦截器就是用来完成许多强劲功能的保证,而且可以根据已定义的若干拦截器中的某几个拦截器构建成interceptor-stack拦截器栈,其实拦截器栈还可以由拦截器栈组成。即从Struts2高层的角度来看,二者没有什么区别。
我们可以在<package/>中增加这样一行<default-interceptor-ref name="拦截器的名字"/>即表示将该拦截器作为整个包的默认拦截器,它会自动附加到我们的每一个Action中。并且在一个<package/>中只能使用<default-interceptor-ref/>定义一个默认的拦截器。
若<action/>没有引用任何一个拦截器,那么默认的defaultStack会自动附加到<action/>中
若<action/>手工引用任何一个拦截器,那么默认的defaultStack就不会附加到<action/>中
若还想使用默认拦截器,则只能再通过手工方式导入<interceptor-ref name="defaultStack"/>
如果没有引用Struts2的默认拦截器,那么就会影响到整体的输入校验即其它的一些功能
Struts2拦截器的配置和使用都很easy,这得益于其底层的良好架构以及它的AOP的思想
该拦截器即标准的AOP思想,代码不写死到Action里,而是根据配置灵活附加到Action中
使用上,Struts2拦截器并不复杂。但实现上,是很复杂的,其底层用到了动态代理的机制
b) 造成重复提交主要的两个原因:
1) 一是,服务器处理时间久。当用户在表单中填完信息,点击“提交”按钮后,由于服务器反应时间过长没能及时看到响应信息,或者出于其它目的,再次点击“提交”按钮,从而导致在服务器端接收到两条或多条相同的信息。如果信息需要存储到后台数据库中,如此以来就会产生数据库操作异常提示信息,以至于给用户带来错误信息提示,从而给用户的使用带来不便。
2) 二是,forward跳转引起的重复提交。当用户将信息提交到服务器,服务器响应采用forward方式调转到下一个页面后,此时地址栏中显示的是上个页面的URL,若刷新当前页面,浏览器会将再次提交用户先前输入的数据,就会再次出现表单重复提交的问题。当然你可以选择redirect方式跳转页面,这样就不会出现重复提交的问题;但有时为了达到某种效果或式。者出于网站安全的目的需要隐藏网页跳转,而不得不采用forward跳转方
c) 对token的简单理解:
1)当用户首次访问包含表单的页面时,服务器会在这次会话中创建一个session对象,并产生一个令牌值,然后将这个令牌值作为隐藏输入域的值,随表单一起发送到服务器端,同时将令牌值保存到Session中。
2) 当用户提交页面时,服务器首先判断请求参数中的令牌值和Session中保存的令牌值是否相等,若相等,则清楚Session中的令牌值,然后执行数据处理操作。如果不相等,则提示用户已经提交过了表单,同时产生一个新的令牌值,保存到Session中。当用户重新访问提交数据页面时,将新产生的令牌值作为隐藏输入域的值。
注意问题:请简述客户端跳转和服务器端跳转之间的区别
客户端跳转时用HttPservletResopse对象的sendRedirect函数实现,服务器端跳转是使用RequestDispather对象的forward方法实现的。这两者之间的区别主要体现在三个方面:
1. 使用服务器端跳转时,客户浏览器的地址栏并不会显示目标地址的URL,而是用客户端跳转时,地址栏当中会显示目标资源的URL;
2. 服务器端跳转是由客户端发送一个请求,请求一个服务器资源——如JSP和Servlet——,这个资源又将请求转到另一个服务器资源,然后再给客户端发送一个响应,也就是说服务器端跳转是客户端发送一次请求,服务器端给出一次响应;而客户端跳转的流程则不同。客户端同样是发送一个请求给服务器端资源,这个服务器资源会首先给客户端一个响应,客户端再根据这个响应当中所包含的地址,再次向服务器端发送一个请求,也就是说客户端跳转是两次请求,两次响应;
3. 在进行客户端跳转和服务器端跳转时,都需要指定目标资源的URL,如果这个路径以“/”开始。在客户端跳转当中“/”代表的是应用服务器根目录,而在服务器端跳转当中代表的是应用程序根目录。
2.开始解决
使用struts2 token拦截器
struts2的拦截器实现了防止表单重复提交的功能,即token拦截器,在表单提交页面写上<s:token/>,在struts.xml配置文件中相应的action上配置拦截器。此拦截器只能用在有form的提交请求上。
Jsp页面部分代码:
在表单提交页面写上<s:token/>
<s:form action="add" method="post">
<s:token /><!-- 防止表单重复提交 -->
<s:textfield name="userName" label="用户名"></s:textfield><br/>
<s:password name="password" label="密码"></s:password><br/>
<s:submit />
</s:form>
在struts.xml配置文件中相应的action上配置拦截器
<action name="*" class="tutorial.UploadFiles" method="{1}">
<interceptor-ref name="token"></interceptor-ref>
<result name="filesShow">
/filesShow.jsp
</result>
Struts2的内置拦截器:
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="externalRef" class="com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor"/>
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="sessionAutowiring" class="org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="jsonValidation" class="org.apache.struts2.interceptor.validation.JSONValidationInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
核心提示:名称 描述 alias 实现在不同请求中相似参数别名的转换。 autowiring 这是个自动装配的拦截器,主要用于当Struts2和Spring整合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean。 chain 构建一个Action链,使当前Action可以访问前一个Action的属性
名称
描述
alias
实现 在不同请求中相似参数别名的转换。
autowiring
这是个自动装配的拦截器,主要用于当Struts2和Spring整 合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean。
chain
构建一个Action链,使当 前Action可以访问前一个Action的属性,一般和<result type="chain" .../>一起使用。
conversionError
这 是一个负责处理类型转换错误的拦截器,它负责将类型转换错误从ActionContext中取出,并转换成Action的FieldError错误。
createSession
该 拦截器负责创建一个HttpSession对象,主要用于那些需要有HttpSession对象才能正常工作的拦截器中。
debugging
当 使用Struts2的开发模式时,这个拦截器会提供更多的调试信息。
execAndWait
后台执行Action,负责将等 待画面发送给用户。
exception
这个拦截器负责处理异常,它将异常映射为结果。
fileUpload
这 个拦截器主要用于文件上传,它负责解析表单中文件域的内容。
i18n
这是支持国际化的拦截器,它负责把所选的语言、区域放入 用户Session中。
logger
这是一个负责日志记录的拦截器,主要是输出Action的名字。
model-driven
这 是一个用于模型驱动的拦截器,当某个Action类实现了ModelDriven接口时,它负责把getModel()方法的结果堆入 ValueStack中。
scoped-model-driven
如果一个Action实现了一个 ScopedModelDriven接口,该拦截器负责从指定生存范围中找出指定的Modol,并将通过setModel方法将该Model传给 Action实例。
params
这是最基本的一个拦截器,它负责解析HTTP请求中的参数,并将参数值设置成Action对 应的属性值。
prepare
如果action实现了Preparable接口,将会调用该拦截器的prepare()方法。
static-params
这 个拦截器负责将xml中<action>标签下<param>标签中的参数传入action。
scope
这 是范围转换拦截器,它可以将Action状态信息保存到HttpSession范围,或者保存到ServletContext范围内。
servlet-config
如 果某个Action需要直接访问Servlet API,就是通过这个拦截器实现的。注意:尽量避免在Action中直接访问Servlet API,这样会导致Action与Servlet的高耦合。
roles
这是一个JAAS(Java Authentication and Authorization Service,Java授权和认证服务)拦截器,只有当浏览者取得合适的授权后,才可以调用被该拦截器拦截的Action。
timer
这 个拦截器负责输出Action的执行时间,这个拦截器在分析该Action的性能瓶颈时比较有用。
token
这个拦截器主要 用于阻止重复提交,它检查传到Action中的token,从而防止多次提交。
token-session
这个拦截器的作用 与前一个基本类似,只是它把token保存在HttpSession中。
validation
通过执行在 xxxAction-validation.xml中定义的校验器,从而完成数据校验。
workflow
这个拦截器负责调用 Action类中的validate方法,如果校验失败,则返回input的逻辑视图。
大部分时候,开发者无需手动控制这些拦截器,因为struts-default.xml文件中已经配置了这些拦截器,只要我们定义的包继承 了系统的struts-default包,就可以直接使用这些拦截器。