Struts2自定义拦截器实现防止重复提交
防止表单重复提交的几种方法总结
防止表单重复提交的几种方法总结
防止表单重复提交有几种方法,以下是几种常见的方法总结:
1. 使用“单个提交”和“多个提交”选项:在表单中,提供一个“单个提交”或“多个提交”的选项,选择只在单个记录中修改(“单个提交”)或在所有记录中修改(“多个提交”)。
这可以防止表单被重复提交,因为用户必须选择一次。
2. 使用“提交表单数据”按钮:在表单中添加一个“提交表单数据”按钮,这样用户点击按钮时将提交表单数据,而不是表单本身。
这可以防止表单被重复提交,因为用户不需要再次点击表单按钮来提交表单数据。
3. 使用验证码:在表单中添加一个验证码,每次用户提交表单时,验证码将过期并提示用户重新输入。
这可以防止表单被重复提交,因为用户必须等待验证码输入完成后才能继续操作。
4. 使用“唯一标识符”:在表单中添加一个唯一标识符(例如,
用户名或密码),并将该标识符与表单数据关联。
这样,每次用户提交表单时,都将唯一标识符与表单数据对应。
如果同一用户多次提交相同的表单数据,则可以使用唯一标识符来区分它们,防止表单被重复
提交。
5. 使用JavaScript实现异步提交:在表单中添加JavaScript代码,使用户可以在提交表单数据之前暂停表单的提交。
然
后,JavaScript代码可以将数据更改通知服务器,然后将表单重新设置为“可重复提交”。
这可以防止表单被重复提交,因为用户可以在提交表单数据之前暂停表单的提交。
struts2
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
搭建Struts2开发环境
搭建Struts2环境时,我们一般需要做以下几个步骤的工作: 1》找到开发Struts2应用需要使用到的jar文件. 2》编写Struts2的配置文件 3》在web.xml中加入Struts2 MVC框架启动配置
北京传智播客教育
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
搭建Struts2开发环境--Struts2在web中的启动配置
在struts1.x中, struts框架是通过Servlet启动的.在struts2中, struts框架是通过Filter启动的.他在web.xml中的配置如下:
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
Struts2
讲师: 讲师:黎活明
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
Struts2
Struts2是在WebWork2基础发展而来的.和struts1一样, Struts2也属于MVC框架. 不过有一点大家需要注意的是:尽管Struts2和struts1在名字上的差别不是很大,但 Struts2和struts1在代码编写风格上几乎是不一样的.那么既然有了struts1,为何还要 推出struts2.主要是因为struts2有以下优点:
北京传智播客教育
—高级软件人才实作培训专家! 高级软件人才实作培训专家!
第一个Struts2应用--HelloWorld
在默认的配置文件struts.xml 中加入如下配置:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "/dtds/struts-2.0.dtd"> <struts> <package name="itcast" namespace="/test" extends="struts-default"> <action name="helloworld" class="cn.itcast.action.HelloWorldAction" method="execute" > <result name="success">/WEB-INF/page/hello.jsp</result> </action> </package> </struts>
8种解决重复提交的方案你知道哪几种
8种解决重复提交的方案你知道哪几种解决重复提交是一个常见的问题,在数据提交和处理的过程中可能出现重复提交的情况,这会导致数据的异常或者不一致。
为了避免这种问题的发生,我们可以采取以下八种解决方案。
这些方案包括使用前端验证、后端验证、token机制、订单号生成、防止表单重复提交、避免重复提交下载、限制提交频率和使用消息队列。
1. 前端验证前端验证是指在用户提交表单之前,使用JavaScript等前端技术对数据进行验证。
这样可以在客户端就避免一些简单的错误,比如是否填写了必填项、手机号格式是否正确等。
通过前端验证可以减轻服务器的压力,并且提升用户体验。
2. 后端验证除了前端验证,后端也需要对提交过来的数据进行验证。
前端验证只是对一些基本的数据格式进行验证,而后端验证可以对更复杂的数据逻辑进行验证,比如判断某个用户是否已经存在,或者某个商品是否可以购买等。
3. Token机制Token机制可以用来验证用户的身份和请求的合法性。
每次用户提交请求时,服务端会生成一个Token并返回给客户端,在下一次请求中,客户端需要带上该Token。
服务端可以验证该Token的合法性,从而防止重复提交的问题。
4. 订单号生成在某些需要用户支付或者生成唯一标识的场景下,可以使用订单号来避免重复提交。
订单号可以使用时间戳、用户ID等信息生成,并且在生成订单时需要保证其唯一性,从而避免重复提交。
5. 防止表单重复提交有些场景下,用户可能会重复提交表单,比如快速点击提交按钮多次。
为了避免这种情况,可以通过前端禁用提交按钮或者设置提交标志位来防止表单的重复提交。
6. 避免重复提交下载在下载文件的过程中,可能会出现用户多次点击下载按钮的情况,从而导致重复下载同一个文件。
为了解决这个问题,可以在下载开始时生成一个唯一的下载标识,服务端保存该标识并检查是否已经下载过该文件,从而避免重复下载。
7. 限制提交频率为了防止频繁的提交请求,可以通过限制提交的频率来解决。
.net core validateantiforgerytoken 重复提交
.net core validateantiforgerytoken 重复提交在.net中,可以使用 AntiForgeryToken来防止重复提交。
AntiForgeryToken是 MVC框架提供的功能,用于防止跨站请求伪造(CSRF)攻击和重复提交。
要使用 AntiForgeryToken,可以按照以下步骤进行操作:
1. 启用 session:在 services 方法中使用
Configure<CookiePolicyOptions>方法启用 session。
2. 生成 AntiForgeryToken:在控制器的相应方法中,使用 ValidateAntiForgeryToken 注解来生成 AntiForgeryToken。
3. 验证 AntiForgeryToken:在控制器的相应方法中,验证请求中的 AntiForgeryToken 是否与存储在 session 中的 AntiForgeryToken 匹配。
请注意,具体的实现方式可能会因项目需求而有所不同,你可以根据实际情况进行调整。
如果你需要进一步的帮助,请提供更多的上下文或代码示例,以便我能够更好地理解你的问题并提供更具体的解决方案。
8.传智struts-模型驱动、防重复提交、数据回显
情景: 有一个用来处理客户的 CustomerAction 类, 该动作类实现 了 ModelDriven 接口. 当用户触发CustomerAction 动作时, ModelDriven 拦截器将调用 相关CustomerAction 对象的 getModel() 方法, 并把返回的模型 (Customer实例)压入到 ValueStack 栈. 接下来 Parameters 拦截 器将把表单字段映射到 ValueStack 栈的栈顶对象的各个属性中 . 因为此时 ValueStack 栈的栈顶元素是刚被压入的模型 (Product)对象, 所以该模型将被填充. 如果某个字段在模型里没有 匹配的属性, Param 拦截器将尝试 ValueStack 栈中的下一个对 象. 一个模型类必须有一个不带任何参数的构造器.
北京传智播客教育
—高级软件人才实作培训专家!
3. 数据回显:
// 模拟: 从service中查询获取一个user对象,显示数据到编辑页面 public String edit() throws Excபைடு நூலகம்ption { User db_user = new User("Tom",29); // 数据回显技术, 方式1: // user.setName(db_user.getName()); // user.setAge(db_user.getAge()); // 这样? //user = db_user;
}
—高级软件人才实作培训专家!
<s:token />标签防止重复提交
<s:token />标签防止重复提交,用法如下: 第一步:在表单中加入<s:token /> <s:form action="helloworld_other" method="post" namespace="/test"> <s:textfield name=""/><s:token/><s:submit/> </s:form> 第二步: <action name="helloworld_*" class="cn.itcast.action.HelloWorldAction" method="{1}"> <interceptor-ref name="defaultStack"/> <!-- 增加令牌拦截器 --> <interceptor-ref name="token"> <!-- 哪些方法被令牌拦截器拦截 --> <param name=“includeMethods">save</param> </interceptor-ref> <!-- 当表单重复提交转向的页面 --> <result name="invalid.token">/WEB-INF/page/message.jsp</result> </action> 以上配置加入了“token”拦截器和“invalid.token”结果,因为“token”拦截器在会话的token与 请求的token不一致时,将会直接返回“invalid.token”结果。
Struts2教程2:处理一个form多个submit
在很多Web应用中,为了完成不同的工作,一个HTML form标签中可能有两个或多个submit 按钮,如下面的代码所示:<!--[if !supportLineBreakNewLine]--><ht ml action="" method="post"><input type="submit" value="保存"/><input type="submit" value="打印"/></ht ml>由于在<form>中的多个提交按钮都向一个action提交,使用Struts2 Action的execute 方法就无法判断用户点击了哪一个提交按钮。
如果大家使用过Struts1.x就会知道在Struts1.2.9之前的版本需要使用一个LookupDispatchAction动作来处理含有多个submit 的form。
但使用LookupDispatchAction动作需要访问属性文件,还需要映射,比较麻烦。
从Struts1.2.9开始,加入了一个Event DispatchAction动作。
这个类可以通过java反射来调用通过request参数指定的动作(实际上只是判断某个请求参数是不存在,如果存在,就调用在action类中和这个参数同名的方法)。
使用EventDispatchAction必须将submit的name 属性指定不同的值以区分每个submit。
而在Struts2中将更容易实现这个功能。
当然,我们也可以模拟Event DispatchAction的方法通过request获得和处理参数信息。
但这样比较麻烦。
在Struts2中提供了另外一种方法,使得无需要配置可以在同一个action类中执行不同的方法(默认执行的是execute方法)。
strusts2课堂总结
一、1、struts2struts2是mvc设计思想的一个实现,可以将项目低耦合,提高扩展性2、struts2和struts1的区别struts2不是struts1的升级,而是继承的下xwork的血统,它吸收了struts1和webwork 的优势。
struts2的action是原型,安全的,struts2的action是单例,非安全3、步骤:1、导入包2、在web.xml文件中,加入struts2的核心拦截器3、在src下放入struts2的xml struts.xml4、urlhttp://localhost:8080/Struts2_01_HelloWorld/demo/hello.action二、1、默认值2、转发和重定向的区别转发:url显示的依然是上一个的url,共享上一次的请求重定向:url显示的是下一个的url,不共享3、urlhttp://localhost:8080/Struts2_02_Default/demo/hello.action4、路径http://localhost:8080/Struts2_02_Default/demo/a/b/c/hello.action1、原路径找不到,http://localhost:8080/Struts2_02_Default/demo/a/b/hello.action2、如果1找不到,http://localhost:8080/Struts2_02_Default/demo/a/hello.action3、如果2找不到,http://localhost:8080/Struts2_02_Default/demo/hello.action3、如果3找不到,http://localhost:8080/Struts2_02_Default/hello.action三、11、自定义action继承ActionSupport2、功能方法必须满足格式public String 名字()throws Exception{....};3、urlhttp://localhost:8080/Struts2_03_Action/demo/a.action四、1、如何给action传入参数注意:赋值的必须有封装的set方法,通过el表达式获取的时候,必须有封装的get 方法1、直接给单个参数赋值,在action里建立一个变量,名字与参数的名字一样2、为对象的某个属性赋值,在action里建立一个对象,将参数改为对象名.属性的格式五、1、转发和重定向的区别转发到下一次的时候,url依然是上一次的url,共享上一次的request重定向到下一次的时候,url是下一次的url,不共享上一次的request2、struts2的result的type转发:共享上一次action重定向:不共享上一次action1、转发到下一个jsp,html:dispatcher2、重定向到下一个jsp,html:redirect3、转发到下一个action:chain转到同一个包下的action转发到不同包下的action4、重定向到下一个action:redirectAction转到同一个包下的action转发到不同包下的action六、1、为了分模块开发,可以设置多个xmL文件。
Java开发框架中的重复提交处理技巧
Java开发框架中的重复提交处理技巧随着互联网和移动互联网的快速发展,越来越多的企业开始使用Java开发框架来构建自己的应用程序。
Java开发框架具有高效性和可重用性等优点,让软件开发人员在开发过程中节省了很多时间和精力。
但是,在Java开发框架中存在一些常见的问题,其中最突出的一个问题就是重复提交。
重复提交是指用户在不知情的情况下或者网络延迟等情况下,多次向服务器提交了相同的数据请求。
如果我们不加以处理,这些重复的请求可能会引发很多问题,例如重复加入购物车、重复交易等。
为了处理这个问题,Java开发框架中采取了一些技巧,本文将对这些技巧进行详细介绍。
1. Token机制Token机制是一种常用的防止重复提交的技术。
当客户端第一次请求服务器时,服务器会生成一个Token并返还给客户端,在客户端请求数据时将该Token携带一同提交到服务器,服务器负责验证Token的唯一性和有效性。
在Java开发框架中,Token机制最常用于Web应用程序中,可以通过在http请求中添加Token参数来确保数据的唯一性。
在Spring框架中,我们可以使用Spring的@Token注解来声明Token机制。
2. 多次提交间隔时间限制许多Java开发框架也采用了限制多次提交的时间间隔的方法。
这种策略可以在服务器端生成一个唯一的标识符,并将其存储在Session中,然后在相同标识符的请求之间加入一个间隔时间,如果两次请求之间的时间间隔小于指定的时间,则视为重复提交。
在Spring框架中,我们可以使用Intercepter拦截器来实现此技术。
通过在请求前检查Session中的标识符,然后在处理之前设置新的标识符,这样可以保证每个请求都是唯一的。
3. 数据库表锁数据库表锁是另一种有效的防止重复提交的技术。
在此策略中,当一个请求到达服务器时,它会创建并锁定一个表,防止其他请求进一步更新或访问此表。
如果重复请求同一操作,则由于表已被锁定,导致操作无效。
Struts2的拦截器配置
拦截器实例
public class SimpleInterceptor extends AbstractInterceptor { private String name; public void setName(String name) { = name; } public String intercept(ActionInvocation invocation) throws Exception { LoginAction action = (LoginAction)invocation.getAction(); ......... String result = invocation.invoke(); ...... return result; } }
Struts 专题篇
第九章 Struts 2 的拦截器 主讲:陈宝峰
内容描述
● ● ● ● ● ●
拦截器概述 拦截器配置 使用拦截器的配置 使用默认拦截器的配置 拦截器实例 方法过滤
拦截器概述
● ●
拦截器是 Struts 2 中的重要组成部分 大量的内建拦截器完成了大部分的 Struts2 框架的工作
结束
使用默认拦截器的配置
<package name=” 包名” > <interceptors> <interceptor name=” 拦截器名 1” class=”......” /> ...... <interceptor-stack name=” 拦截器栈名 1”> <interceptor-ref name=” 拦截器名 1” /> ...... </interceptor-stack> </interceptors> <default-interceptor-ref name=” 拦截器名或拦截器栈名” /> <action ...... /> </package>
Struts2项目操作手册
前言其实神马都是浮云。
相关软件下载1.下载Struts2.2.1.1 /download.cgi#struts217(选择下载fulldistribution)2.下载eclipse,/downloads/(选择下载Eclipse IDE for Java EEDevelopers Windows 32 Bit)3.下载tomcat6.0,4.下载JDK1.6,/download/jdk6安装与设置1.解压struts-2.2.1.1-all.zip2.安装Eclipse(解压即可)3.假设你已经安装好jdk和tomcat了,如C:\JAVA_TOOLS\apache-tomcat-6.0.16和C:\JAVA_TOOLS\JDK\ jdk1.6.0_02HelloWorld1.Eclipse中设定servera)Window –Preferences –Server –Runtime Environments –Add –Apache –ApacheTomcat v6.0(注意选中对话框下方的Create a new local server复选框)b)选择Tomcat installation directoryc)选择JREd)Finishe)双击下方Servers选项卡中的Tomcat v6.0 Server at localhost,设置Server Locations中的Deploy path为Tomcat安装目录下的webapps目录,注意保存文件。
2.Eclipse中建立项目a)打开eclipseb)新建项目c)选择web节点下的Dynamic Web Projectd)项目名称:struts2HelloWorld(注意选中Target runtime为设定好的Server)3.Eclipse中部署运行项目a)右击Servers选项卡中的Tomcat v6.0 Server at localhost,选择Add and Remove添加需要部署的Java web项目。
java中防重复提交,加注解的方法
一、问题引入在Java应用程序开发过程中,常常会遇到用户重复提交表单或者请求的问题。
用户在进行网上支付时重复点击提交按钮,导致系统重复处理支付请求。
这种重复提交会导致用户账单异常、数据错误等问题,给系统带来不必要的压力和风险。
如何有效地防止Java应用程序中的重复提交成为了一个重要的技术问题。
二、重复提交的原因分析1. 用户操作失误:用户在进行网页操作时,可能由于网络延迟、页面加载速度等原因多次点击提交按钮,导致表单或请求重复提交。
2. 系统性能问题:如果系统处理请求的速度较慢,可能会导致用户误以为操作未成功而重复提交请求。
三、解决重复提交的一般思路针对重复提交问题,一般可以采取以下几种方法进行处理:1. 在页面端使用JavaScript控制:在用户提交表单后,立即禁用提交按钮,或者在提交过程中显示加载提示等,阻止用户重复提交操作。
2. 在服务端使用Token机制:在用户请求前生成一个唯一的Token,并将其保存在Session或者隐藏域中,用户提交请求时同时提交Token,服务器端进行Token验证,有效则处理请求,无效则拒绝。
3. 利用数据库的唯一性约束:针对具体的业务场景,可以利用数据库的唯一性约束来阻止重复提交。
四、基于注解的防重复提交实现1. 定义注解我们可以定义一个NoRepeatSubmit注解,用于标记需要防止重复提交的请求方法。
注解的定义如下:```javaTarget(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)public interface NoRepeatSubmit {}```2. 编写拦截器实现一个拦截器,拦截带有NoRepeatSubmit注解的请求,并进行重复提交的验证。
拦截器的实现如下:```javaComponentpublic class NoRepeatSubmitInterceptor extends HandlerInterceptorAdapter {Autowiredprivate RedisTemplate<String, String> redisTemplate;Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {// 获取请求的URL和用户ID等信息,构造唯一标识String requestUrl = request.getRequestURI();String userId = request.getParameter("userId");String key = "submit:token:" + requestUrl + ":" + userId;// 利用Redis的原子操作实现重复提交的验证Boolean ifAbsent =redisTemplate.opsForValue().setIfAbsent(key, "0", 10, TimeUnit.SECONDS);if (ifAbsent) {return true;} else {throw new RuntimeException("请勿重复提交");}}}```3. 配置拦截器在Spring Boot的配置类中配置拦截器,将NoRepeatSubmit注解与拦截器进行关联,示例如下:```javaConfigurationpublic class WebConfig extends WebMvcConfigurerAdapter {Autowiredprivate NoRepeatSubmitInterceptor noRepeatSubmitInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(noRepeatSubmitInterceptor);}}```五、总结通过上述基于注解的防重复提交实现,可以在Java应用程序中有效地防止重复提交问题。
js 避免发送重复请求的方法
js 避免发送重复请求的方法随着互联网的发展和应用场景的不断扩大,我们的前端开发逐渐从简单的页面展示转向了更加复杂的交互式应用程序。
这些应用程序需要和后端进行交互,获取和处理数据。
在这个过程中,我们有时需要发送重复的请求,这会导致服务器的负担增加,同时也会占用更多的带宽和资源。
那么,如何避免发送重复请求呢?本文将为大家介绍一些实用的方法。
1. 防止异步请求重复提交在前端开发中,我们经常需要使用异步请求来获取数据。
如果用户频繁点击按钮或者发送请求,就会导致重复的请求。
为了避免这种情况发生,我们可以采用以下方法:1) 在发送请求前禁用按钮或者元素,以避免重复点击;2) 在每次请求前,检查当前是否有请求正在进行,如果有,则不再发送新的请求;3) 在请求成功或者失败后,恢复按钮或者元素的状态,以便用户重新操作。
2. 利用缓存机制缓存是一种常用的优化方式,可以提高数据获取的速度和效率。
在前端开发中,我们可以利用浏览器的缓存机制来避免发送重复请求。
具体来说,我们可以通过设置响应头中的Cache-Control、Expires和Last-Modified等字段,告诉浏览器该资源的缓存策略和有效期。
这样,当用户再次请求该资源时,浏览器就可以直接从缓存中获取,而不需要再次发送请求。
3. 利用防抖和节流防抖和节流是前端开发中常用的两种优化方法。
防抖指的是在用户频繁触发某个事件时,只执行最后一次操作。
节流则是在一定时间内只执行一次操作。
这两种方法都可以有效地避免发送重复请求。
具体来说,我们可以在用户触发某个事件时,设置一个定时器,如果在一定时间内没有再次触发该事件,则执行相应的操作。
如果用户频繁触发该事件,则清除定时器,重新设置一个新的定时器。
4. 利用队列来控制请求发送顺序有些时候,我们需要按照一定的顺序发送请求,以保证数据的正确性。
为了避免发送重复请求,我们可以利用队列来控制请求的发送顺序。
具体来说,我们可以将所有的请求都放入一个队列中,按照一定的顺序依次发送请求。
自定义拦截器实现防止重复提交
由于struts2标签的性能不好,项目组决定不使用,但是如果用struts2自带的拦截器防止重复提交又必须struts标签,所以只好自定拦器实现,具体步骤如下:新建拦截器类:public class TokenAtionInterceptor extends AbstractInterceptor {public String intercept(ActionInvocation invocation) throws Exception {Map<String, Object> session =invocation.getInvocationContext().getSession();HttpServletRequest request = ServletActionContext.getRequest();String strGUID = RandomGUIDUtil.newGuid();//生成令牌String strRequestToken = (String)session.get("request_token");//取出会话中的令牌String strToken = request.getParameter("token"); //页面中的令牌if(strRequestToken != null&& !strRequestToken.equals(strToken)){ //重复提交,重置令牌session.put("request_token", strGUID);request.setAttribute("token", strGUID);return"invalidToken";}session.put("request_token", strGUID);request.setAttribute("token", strGUID);return invocation.invoke(); //否则正常运行}}建一个生成令牌的工具类:public class RandomGUIDUtil extends Object {/**日志管理类对象*/private Logger logger= Logger.getLogger(this.getClass().getName());public String valueBeforeMD5 = "";public String valueAfterMD5 = "";private static Random myRand;private static SecureRandom mySecureRand;private static String s_id;/** 静态块初始化*/static {mySecureRand = new SecureRandom();long secureInitializer = mySecureRand.nextLong();myRand = new Random(secureInitializer);try {s_id = InetAddress.getLocalHost().toString();} catch (UnknownHostException e) {System.out.println("构造带指定详细消息和嵌入异常!");}}public RandomGUIDUtil() throws Exception {getRandomGUID(false);}public RandomGUIDUtil(boolean secure) throws Exception { getRandomGUID(secure);}/** 随机生成GUID*/private void getRandomGUID(boolean secure) throws Exception { MessageDigest md5 = null;StringBuffer sbValueBeforeMD5 = new StringBuffer();try {md5 = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {logger.error("初始化MD5出错!");throw new NoSuchAlgorithmException("初始化MD5出错!");}try {long time = System.currentTimeMillis();long rand = 0;if (secure) {rand = mySecureRand.nextLong();} else {rand = myRand.nextLong();}sbValueBeforeMD5.append(s_id);sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(time));sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(rand));valueBeforeMD5 = sbValueBeforeMD5.toString();md5.update(valueBeforeMD5.getBytes());byte[] array = md5.digest();StringBuffer sb = new StringBuffer();for (int j = 0; j < array.length; ++j) {int b = array[j] & 0xFF;if (b < 0x10) sb.append('0');sb.append(Integer.toHexString(b));}valueAfterMD5 = sb.toString();} catch (Exception e) {logger.error("获得MD5加密码出错!");throw new Exception("初始化MD5出错!");}}/***生成一个GUID串*@return GUID*@throws Exception*/public static String newGuid() throws Exception{ RandomGUIDUtil rdmGUID = new RandomGUIDUtil();return rdmGUID.toString();}/** 生成以主机串号、显卡串号、主板号,以保证唯一性的32位编码*/public String toString() {String raw = valueAfterMD5.toUpperCase();StringBuffer sb = new StringBuffer();sb.append(raw.substring(0, 8));sb.append(raw.substring(8, 12));sb.append(raw.substring(12, 16));sb.append(raw.substring(16, 20));sb.append(raw.substring(20));return sb.toString();}}在struts配置文件中对应的包下定义拦截器,注意顺序,package里元素必须按照一定的顺序排列。
struts2的token实现
Struts2中使用token避免重复提交的方法作者: 佚名, 出处:IT专家网,责任编辑: 谢妍妍,2009-09-22 13:00本文Struts2中使用token避免重复提交的方法1.在struts.xml中<action name="register" class="org.sunxin.struts2.action.RegisterAction"> <!-- 配置异常映射,当RegisterAction抛出Exception异常时,向用户显示error.jsp页面--><exception-mapping result="error" exception="ng.Exception"/><result name="input">/pages/register.jsp</result><result name="success">/pages/success.jsp</result><result name="error">/pages/error.jsp</result><result name="invalid.token">/pages/register.jsp</result><result name="wait">wait.jsp</result><interceptor-ref name="defaultStack"></interceptor-ref><interceptor-ref name="token"><param name="excludeMethods">input</param></interceptor-ref></action>2.在页面中加<s:actionerror/><s:form action="register" method="post"><s:token></s:token></s:form>3..<interceptor-ref name="token"/><interceptor-ref name="token-session"/><!--注意struts2.0 拦截器名字为token-session struts2.1.2 已经更改为tokenSession -->token: 在活动中检查合法令牌(token), 防止表单的重复提交; 在会产生提示信息token-session: 同上, 但是在接到非法令牌时将提交的数据保存在session中; 不会在会产生提示信息只会在后台发出警告并处理,如下:警告: Form token KO80SIJW4F84034NG5HM1ZBUGOVNY64D does not match the session token null.编辑推荐:1. Struts2拦截器execAndWait简介2. Struts2教程:第一个Struts2程序3. Struts2对WebWork的改进struts2使用拦截器来检查表单是否重复提交,它采用同步令牌的方式来实现对表单重复提交的判断。
使用redirect避免重复提交
使用redirect避免重复提交使用redirect避免重复提交避免重复提交这个问题在Web应用开发领域应该是一个老生常谈的问题了,主流的一些Web应用框架也提供了方便使用的功能来实现这个需求,比如Struts的Token。
但是有些时候,可能用户确实需要刷新提交之后所转到的页面,比如假设如下的需求:用户注册了一个账号,但是这个账号需要管理员批准才可以进行工作,于是,用户在注册页面填写了详细信息之后,提交,转到详细信息页面,然后刷新这个页面来查看自己的状态。
此时,我觉得使用redirect是非常方便的。
以下是redirect在Struts1和Struts2中的实现:Struts1:在Struts1中,有一个org.apache.struts.action.ActionRedirect的类,这个类是ActionForward类的子类,是专门用来做redirect跳转的。
使用起来非常的简单,只需在你的Action类的方法中,返回一个ActionRedirect类的实例即可。
----------------------------------------------------ActionRedirect redirect = newActionRedirect(mapping.findForward("detailAction")); // 这里是在struts-config.xml文件中定义的<forward>节点的name属性redirect.addParameter("id", user.getId()); //这里是要在url后面附加的参数名称及其值return redirect;----------------------------------------------------Struts2:在Struts2中,情况有所不同。
通过实例跟我学Struts2从入门到精通——如何应用Struts2中的“上传文件拦截器”限制上传文件的类型和大小
1.1通过代码实例跟我学Struts2框架从入门到精通——如何应用Struts2框架中的“上传文件拦截器”限制上传文件的类型和大小的应用实例1.1.1应用Struts2框架中的“上传文件拦截器”限制上传文件的类型和大小上述例子尽管是实现图片上传的功能,但用户实际可以上传任何类型的文件。
如果在应用中需要限制上传文件的类型,应该怎么实现呢?比如,只能够上传图片类型的文件。
1、首先修改upLoadProductImage.jsp页面在<body>与<s:form>之间加入“<s:fielderror />”,用于在页面上输出错误信息。
同时添加<%@ taglib prefix="s" uri="/struts-tags"%>标签的引用。
2、然后修改struts.xml文件,将UpLoadProductImageAction的定义改为如下所示<action name="upLoadProductImageAction"class="com.px1987.sshwebcrm.action.UpLoadProductImageAction"><interceptor-ref name ="fileUpload"><param name ="allowedTypes" >image/bmp,image/png,image/x-png,image/gif,image/pjpeg,image/jp eg</param><param name="maximumSize">5000000</param></interceptor-ref><interceptor-ref name ="defaultStack" /><param name="savePath">/uploadImages</param><result>/productManage/showUploadInfo.jsp</result><result name="input">/productManage/upLoadProductImage.jsp</result> </action>或者<interceptor-ref name="basicStack"/> 。
struts2
一、Struts2入门1.概念什么是Struts2Struts2 是一个用来开发 MVC 应用程序的框架.它提供了 Web 应用程序开发过程中的一些常见问题的解决方案:对页面导航活动进行管理对来自用户的输入数据进行合法性验证统一的布局可扩展性国际化和本地化支持 Ajax表单的重复提交Struts2 VS Struts1Struts2与Struts1 相比,在体系结构方面更优秀,具体表现在类更少,更高效,扩展更容易等。
struts2 不是从 Struts1 扩展而来的, 说它是一个换了品牌标签的 WebWork 更合适。
2.程序Struts2 核心就是一个 Filter,该Filter会对所有的请求进行拦截(/*) StrutsPrepareAndExecuteFilterStrutsPrepareFilter + StrutsExecuteFilterStruts2 将所有的请求拦截下来,具体去访问哪个java类的方法需要读取配置文件 struts.xmlstruts.xml 文件需位于工程的类路径下实现一个 Struts 的 HelloWorld 程序1) 将 %struts2-blank例子%\WEB-INF\lib 目录下所有jar包拷贝至 webproject\WEB-INF\lib 中拷贝至webproject/WEB-INF/web.xml 中3) %struts2-blank例子%\将WEB-INF\classes 下的struts.xml 文件拷贝至工程src下清空 <struts></ struts> 标签之间的内容4) 新建 Action 实例, HelloWorldAction.javaAction可以不必是实现任何接口,它是一个普通java类(pojo),从这点可以看出 Struts2 是非侵入式设计,Action可以不依赖struts和Servlet 而独立存在Action中至少需要定义一个方法,且方法的返回值类型必须为Stringpublic String sayHello() {return "success";}6) 在 WEB-INF 下新建jsp页面hello.jsphello动手练习:用 struts2 实现最简单的mvc二、Struts2 细节1.package 元素配置action的组织包name:配置包名,用于被继承namespace: 配置访问路径以 /a/b/c/action 为例搜索action的顺序为 /a/b/c -- /a/b -- /a -- /extends: 指定继承的包2. action 元素1) name属性配置action的访问名称后缀默认为 action和””可以通过常量进行配置<constant name="struts.action.extension" value="do"></constant>2) class属性配置action对应的java类,必须为完整类名如果继承struts-default 包,默认class 为ActionSupport,该类的 execute方法默认返回 success我们在写 Action 类时通常会选择继承ActionSupport,也就自动继承了 execute 方法,同时可以使用父类定义的常量 SUCCESS、ERROR 等3) method属性配置action的访问方法名,默认访问execute方法4) 通配符映射一个 Web 应用可能有成百上千个 action 声明. 可以利用 struts 提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系通配符的映射规则●若找到多个匹配, 没有通配符的那个将胜出●若指定的Action不存在, Struts 将会尝试把这个URI与任何一个包含着通配符 * 的Action名及进行匹配●若 Struts 找到的带有通配符的匹配不止一个, 最后一个匹配将胜出●被通配符匹配到的 URI 字符串的子串可以用 {1}, {2} 来引用. {1} 匹配第一个子串, {2} 匹配第二个子串…{0} 匹配整个 URI●* 可以匹配零个或多个字符, 但不包括 / 字符. 如果想把 / 字符包括在内, 需要使用 **. 如果需要对某个字符进行转义, 需要使用 \.例:<action name="*_add" class="cn.itcast.action.Girl" method="add"></action>匹配路径 Boy_add.action Girl_add.action<action name="Boy_*_*" class="cn.itcast.action.Boy" method="{1}"><result name="success"><param name="location">/WEB-INF/jsp/{2}.jsp</param></result></action>Boy_add_delete 会调用 Boy的add方法,转发给 delete.jsp5) 动态方法调用通过 url 动态调用 Action 中的方法<action name="Boy" class="cn.itcast.action.Boy">/strutsdemo/Boy!add.action 会调用Boy类的add方法默认情况下, Struts 的动态方法调用处于激活状态, 若想禁用该功能, 则可以在 struts.xml 文件中配置常量3. Action 类概念:action: 应用程序可以完成的每一个操作(用户的一个动作) 例如:显示一个登陆表单,保存商品信息Action类:Struts2中的Action是pojo(Plain Old Java Objects一个普通的java类)的,可以定义属性和方法,但需要遵循一些规则:●属性的名字必须遵守与 JavaBeans 属性名相同的命名规则. 属性的类型可以是任意类型. 从字符串到非字符串(基本数据库类型)之间的数据转换可以自动发生●必须有一个不带参的构造器●至少有一个供 struts 在执行这个 action 时调用的方法,方法的返回值为String类型(即视图名称)●同一个 Action 类可以包含多个 action.●Struts2 会为每一个 HTTP 请求创建一个新的 Action 实例4. result 元素配置 action 的执行结果name: 配置result结果名称,根据action执行方法的返回值决定找那个 result默认为 successtype: result 结果类型,默认为 dispatcher 类型常用的result类型●dispatcherdispatcher 结果类型是最常用的结果类型, 也是 struts 框架默认的结果类型用于将控制权转发给web应用中的其他资源默认参数:location 用于指定转发的资源路径,通常为一个jsp页面●redirect用于将响应重定向到另一个资源参数:location : 指定重定向的资源路径parse : 指定是否将location的值视为一个 OGNL 表达式来解析默认值为true●redirectAction用于将响应重定向给另一个Action参数:actionName : 指定目标action, 该属性为默认属性namespace : 指定目标 action 所在的 package●chain用于构成一个 Action 链,前一个action将控制权转发给下一个action,并且前一个action的状态在后一个action中继续保持参数:actionName : 指定目标action, 该属性为默认属性namespace : 指定目标 action 所在的 packagemethod :指定调用action的方法,默认调用 execute 方法●httpheader用于将把一个 HTTP 状态发送到浏览器默认参数 status :指定状态码●plaintext将转发的资源作为文本输出 , 不常用。
Struts2 中拦截器和Action的调用关系
</action>
<action name="action2" class="com.suo.actions.Action2">
this.password = password;
}
public String execute()
{
System.out.println("action2 invoke !");
return SUCCESS;
}
public String execute()
{
System.out.println("action1 invoke !");
return SUCCESS;
}
}
复制代码
复制代码
Action2.java:
public class MyInterceptor implements Interceptor {
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("destroy invoke !");
}
@Override
public void init() {
// TODO Auto-generated method stub
System.out.println("init invoke !");
struts2 parametersinterceptor 过滤
struts2 parametersinterceptor 过滤
Struts2 ParametersInterceptor过滤器的主要功能是将ActionContext中的请求参数设置到ValueStack中。
如果ValueStack的栈顶是当前Action,那么将会把请求参数设置到Action中;如果栈顶是一个Model(Action实现了ModelDriven接口),那么将会把参数设置到Model中。
拦截器是Struts的一个概念,与过滤器类似,它可以近似地看作是过滤器。
拦截器的设计基于组件设计的应用,可以实现横切功能,并使这些实现相对Action甚至Struts2框架保持独立。
它提供了一种机制,使得开发者可以定义在一个Action执行的前后执行的代码,也可以在一个Action执行前阻止其操作。
同时,它也提供了一种可以提取Action中可重用部分的方式。
在Struts2框架中,默认的拦截器栈包含了18个拦截器,其中 ParametersInterceptor 用于实现数据自动封装。
防止重复提交的方法
防止重复提交的方法在网络应用中,重复提交是一种常见的问题,它可能会导致数据的混乱、用户体验的下降以及服务器资源的浪费。
为了解决这个问题,我们可以采取一些有效的方法来防止重复提交。
首先,可以使用前端技术来防止重复提交。
在用户点击提交按钮后,可以通过将按钮设置为禁用状态来阻止用户再次点击。
这样即使用户多次点击提交按钮,也只会提交一次请求。
另外,我们还可以使用JavaScript来进行验证,在提交表单之前,通过检查表单是否已经提交过来阻止重复提交。
其次,使用后端技术也是防止重复提交的重要手段之一、可以通过生成一个唯一的标识符,并将其存储在用户的会话中。
每次用户提交请求时,先检查该标识符是否存在。
如果存在,则说明该请求已经提交过,可以拒绝处理。
如果不存在,则表示该请求是新的,可以进行处理,并将该标识符保存起来,以便后续的请求进行验证。
另外,还可以使用token机制来防止重复提交。
在用户请求页面时,服务器会为用户生成一个唯一的token,并将其存储在用户的会话或者cookie中。
用户在提交表单时,会将这个token作为一个隐藏字段或者请求的参数之一,服务器在接收到请求后,会检查token的有效性,如果token无效,则拒绝处理该请求,从而防止重复提交。
此外,我们还可以通过设置请求的有效期来防止重复提交。
每次用户提交请求时,在服务器端记录当前时间,并在处理请求的时候判断请求的时间是否超过一定的时间范围。
如果超过了有效期,则拒绝处理该请求,以避免重复提交。
除了上述方法,还可以采用一些其他的技术手段来防止重复提交。
例如,使用图形验证码来验证用户的身份,只有验证码正确才能提交请求;使用令牌桶算法来限制用户的请求频率,防止恶意的重复提交;使用分布式锁或者数据库的唯一约束来保证数据的一致性等等。
总结起来,防止重复提交是一个涉及前后端技术的综合性问题。
在设计和开发过程中,我们需要结合具体的业务场景和技术要求来选择合适的方法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
由于struts2标签的性能不好,项目组决定不使用,但是如果用struts2自带的拦截器防止重复提交又必须struts标签,所以只好自定拦器实现,具体步骤如下:新建拦截器类:public class TokenAtionInterceptor extends AbstractInterceptor {public String intercept(ActionInvocation invocation) throws Exception {Map<String, Object> session =invocation.getInvocationContext().getSession();HttpServletRequest request = ServletActionContext.getRequest();String strGUID = RandomGUIDUtil.newGuid();//生成令牌String strRequestToken = (String)session.get("request_token");//取出会话中的令牌String strToken = request.getParameter("token"); //页面中的令牌if(strRequestToken != null&& !strRequestToken.equals(strToken)){ //重复提交,重置令牌session.put("request_token", strGUID);request.setAttribute("token", strGUID);return"invalidToken";}session.put("request_token", strGUID);request.setAttribute("token", strGUID);return invocation.invoke(); //否则正常运行}}建一个生成令牌的工具类:public class RandomGUIDUtil extends Object {/**日志管理类对象*/private Logger logger= Logger.getLogger(this.getClass().getName());public String valueBeforeMD5 = "";public String valueAfterMD5 = "";private static Random myRand;private static SecureRandom mySecureRand;private static String s_id;/** 静态块初始化*/static {mySecureRand = new SecureRandom();long secureInitializer = mySecureRand.nextLong();myRand = new Random(secureInitializer);try {s_id = InetAddress.getLocalHost().toString();} catch (UnknownHostException e) {System.out.println("构造带指定详细消息和嵌入异常!");}}public RandomGUIDUtil() throws Exception {getRandomGUID(false);}public RandomGUIDUtil(boolean secure) throws Exception { getRandomGUID(secure);}/** 随机生成GUID*/private void getRandomGUID(boolean secure) throws Exception { MessageDigest md5 = null;StringBuffer sbValueBeforeMD5 = new StringBuffer();try {md5 = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {logger.error("初始化MD5出错!");throw new NoSuchAlgorithmException("初始化MD5出错!");}try {long time = System.currentTimeMillis();long rand = 0;if (secure) {rand = mySecureRand.nextLong();} else {rand = myRand.nextLong();}sbValueBeforeMD5.append(s_id);sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(time));sbValueBeforeMD5.append(":");sbValueBeforeMD5.append(Long.toString(rand));valueBeforeMD5 = sbValueBeforeMD5.toString();md5.update(valueBeforeMD5.getBytes());byte[] array = md5.digest();StringBuffer sb = new StringBuffer();for (int j = 0; j < array.length; ++j) {int b = array[j] & 0xFF;if (b < 0x10) sb.append('0');sb.append(Integer.toHexString(b));}valueAfterMD5 = sb.toString();} catch (Exception e) {logger.error("获得MD5加密码出错!");throw new Exception("初始化MD5出错!");}}/***生成一个GUID串*@return GUID*@throws Exception*/public static String newGuid() throws Exception{ RandomGUIDUtil rdmGUID = new RandomGUIDUtil();return rdmGUID.toString();}/** 生成以主机串号、显卡串号、主板号,以保证唯一性的32位编码*/public String toString() {String raw = valueAfterMD5.toUpperCase();StringBuffer sb = new StringBuffer();sb.append(raw.substring(0, 8));sb.append(raw.substring(8, 12));sb.append(raw.substring(12, 16));sb.append(raw.substring(16, 20));sb.append(raw.substring(20));return sb.toString();}}在struts配置文件中对应的包下定义拦截器,注意顺序,package里元素必须按照一定的顺序排列。
这个顺序就是result-typesinterceptorsdefault-interceptor-refdefault-action-refdefault-class-refglobal-resultsglobal-exception-mappingsaction*(就是所有的action放到最后)<action>配置中加上名为” invalidToken”的result,就是拦截器中,重复提交跳转的路径如:<package name="template" extends="struts-default" namespace="/"> <interceptors><interceptor name="invocationToken"class="com.tydic.ppm.util.TokenAtionInterceptor"></interceptor> </interceptors><global-results><result name="error">/error.jsp</result><result name="openError">/openError.jsp</result> </global-results><action name="addTemplate" class="templateConfigAction"> <interceptor-ref name="defaultStack"></interceptor-ref><interceptor-ref name="invocationToken"></interceptor-ref><result name="input">/content/templateManage/configTemplate/templateBaseInfo.jsp </result><result name="success">/content/templateManage/configTemplate/templateBaseInfo.jsp </result><result name="invalidToken">/content/templateManage/configTemplate/templateBaseInfo.jsp </result></action></package>最后在页面上加一个隐藏域,用来保存页面令牌的,如:<input type="hidden" name="token" value="${token }"/><!-- 防止重复提交所用 -->经过上面的步骤就可以实现防止重复提交了,要注意拦截器在struts配置文件中定义的位置。