首页 > 其他分享 >jFinal避免表单重复提交

jFinal避免表单重复提交

时间:2024-03-31 16:14:09浏览次数:10  
标签:repeatInterceptor url 表单 提交 jFinal 注解 log4j

前言

流程思路

(同Spring MVC一样)

sessionId:是Request.getSession().getId() 获取session里面的id

url:是 Request.getRequestURI() 获取的网址的url

params:是Request.getParameterMap()转的json字符串再转的String

表单第一次提交数据:

进入拦截器,从redis 缓存中获取key(sessionId+url)为空,会把sessionId+url为key,url+param为value存入redis缓存,返回为true,进入对应 Action

表单第二次提交数据:

进入拦截器,从redis 缓存中获取key(sessionId+url)不为空,然后拿从缓存中获取的值和上一个进行判断,如果相同则为表单重复提交,返回false;如果不相同,返回为true,进入对应 Action

涉及环境

Jfinal 框架

Tomcat (暂无限制版本) 或 jFinal 的核心服务器

Redis 缓存

jFinal避免表单重复提交配置

表单重复提交拦截器配置

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;

import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;

import net.sf.json.JSONObject;

/**
 * @author 马家立
 * @version 创建时间:2018年12月27日下午5:01:37
 * @Description: 提交时校验页面中url和提交的参数数据并与redis缓存中的url校验,一致通过,时间过期无效
 */
public class RepeatSaveInterceptor implements Interceptor {
    private static Logger logger = Logger.getLogger("repeatInterceptor");
    //redis 缓存的存储过期时间(单位/s)
    static int overTime = 60;
    /**
     * 表单重复提交拦截器
     */
    @Override
    public void intercept(Invocation inv) {
        //  Auto-generated method stub
        logger.info("进入重复提交表单拦截器:RepeatSaveInterceptor的intercept");
        Controller controller= inv.getController();
        //验证同一个url数据是否相同提交 ,相同返回false  
        boolean token = repeatDataValidator(controller.getRequest());
        if(token){
            inv.invoke(); // 继续执行action中的方法
        }
    }

    /**
     * @Title:repeatDataValidator
     * @author:马家立
     * @date:2018年12月28日 上午10:37:35
     * @Description: 验证同一个url数据是否相同提交 ,相同返回false
     * @param:@param httpServletRequest
     * @param:@return true:url或者提交的参数数据不同;false:url相同,提交的参数数据相同
     * @return:boolean
     */
    public boolean repeatDataValidator(HttpServletRequest httpServletRequest) {
        logger.info("进入RepeatSaveInterceptor的repeatDataValidator");
        try {
            RedisUtil redis = new RedisUtil();
            String sessionId = httpServletRequest.getSession().getId();
            logger.info("获得sessionId:" + sessionId);
            //获取参数的map,然后转为json字符串
            Map<String, String[]> mapa = httpServletRequest.getParameterMap();
            JSONObject jsonObject = JSONObject.fromObject(mapa);
            logger.info("jsonObject的输出结果是:" + jsonObject);
            //将json对象转化为json字符串
            String params = jsonObject.toString();
            String url = httpServletRequest.getRequestURI();
            logger.info("url是:" + url);
            //创建一个新的map用于存储新的url和提交的参数数据,用于和session里面的相比较
            Map<String, String> map = new HashMap<String, String>();
            map.put(url, params);
            String nowUrlParams = map.toString();
            Object preUrlParams = redis.get(sessionId + url);
            logger.info("表单拦截器配置成功");
            // 如果上一个数据为null,表示还没有访问页面
            if (preUrlParams == null) {
                redis.setex(sessionId + url, overTime, nowUrlParams);
                return true;
            } else {// 否则,已经访问过页面
                // 如果上次url+数据和本次url+数据相同,则表示重复添加数据
                if (preUrlParams.toString().equals(nowUrlParams)) {
                    return false;
                } else { //如果上次 url+数据 和本次url加数据不同,则不是重复提交
                    redis.setex(sessionId + url, overTime, nowUrlParams);
                    return true;
                }
            }
        } catch (Exception e) {
            logger.error("进入SameUrlDataInterceptor的repeatDataValidator");
            e.printStackTrace();
            return false;
        }
    }
}

表单重复提交日志配置

#避免表单重复提交
log4j.logger.repeatInterceptor = info,repeatInterceptor
log4j.appender.repeatInterceptor=org.apache.log4j.RollingFileAppender
log4j.appender.repeatInterceptor.File=D:\\ProjectLog\\OASystem\\repeatInterceptor.log
log4j.appender.repeatInterceptor.MaxFileSize=200MB
log4j.appender.repeatInterceptor.MaxBackupIndex=10
log4j.appender.repeatInterceptor.layout=org.apache.log4j.PatternLayout
log4j.appender.repeatInterceptor.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss,SSS}[%p] [%l][%t]%n \u3010%m\u3011%n%n
log4j.additivity.repeatInterceptor=false

image

Action或 Controller 注解方式使用

在需要进行重复表单验证的方法上面加上@Before(RepeatSaveInterceptor.java)注解即可,这个注解即是第一步写的自定义注解

image

验证是否配置成功

查看log4j的配置路径下是否生成 repeatInterceptor.log 文件

image

关于注解

java中元注解有四个: @Retention @Target @Document @Inherited;

@Retention:注解的保留位置
@Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到

@Target:注解的作用目标
@Target(ElementType.TYPE)   //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR)  //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包

@Document:说明该注解将被包含在javadoc中

@Inherited:说明子类可以继承父类中的该注解

标签:repeatInterceptor,url,表单,提交,jFinal,注解,log4j
From: https://www.cnblogs.com/mjtabu/p/18106836

相关文章

  • MySQL 事务的两阶段提交--转
    什么是事务事务是数据库中一组原子性的操作,要么全部成功,要么全部失败。事务具有四个特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),简称ACID。在MySQL中,我们可以使用 begin 或 starttransaction 命令开启一个事务,使用 commit 命令提交......
  • yii2表单使用
    yii2表单使用模型models/form/EntryForm.php<?phpnamespaceapp\models\form;useyii\base\Model;classEntryFormextendsModel{public$name;public$email;publicfunctionrules(){return[[['name',&......
  • FLASK学习记录-Flask表单(一)
     Form表单是一个包含表单元素的区域,允许用户在表单中输入各种信息元素,是前后端交互的重要标签,Form标签常用属性如下:  常用表单控件: 实例:app.pyfromflaskimportFlask,render_template,requestapp=Flask(__name__)@app.route('/',methods=["get","post"]......
  • 某物登录表单加密
    之前分析过某物h5的以及小程序的搜索接口,就是一个aes,秘钥不固定,表单里把秘钥以及密文一起发过去,服务器解密后再把数据加密返回,客户端解密展示到页面上.这期是关于app的登录,密码登录声明本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容......
  • WPF中实现动态表单-来自GPT4的回答
    实现C#和WPF项目中的动态表单功能,需要在后端设计灵活的数据结构来存储表单配置(例如字段名、字段类型等),同时前端需要能够解析这些配置并据此生成相应的控件。以下是一种可能的实现方法:1.数据库设计你的数据库需要至少包含两个表:一个用于存储表单字段的配置,另一个用于存储用户输......
  • elementUI——el-form表单数据校验(包含数组循环)
    一、普通的值类型的数据校验①设置el-form-item的prop值与formdata中定义的key保持一致`②如果rules需要通过el-form统一设置,rules的key定义也与prop保持一致(如果不一致,需要在el-form-item中手动指定)③复杂的校验函数可通过validator单独定义<el-form......
  • element-ui表单校验:有值却不通过 el-form validate
    解决:新增/编辑赋值的时候,所有明明有值校验不通过的属性使用$set赋值this.$set(this.form,"属性名","");//新增置空this.$set(this.form,"属性名",row.shuxing);//编辑赋值 ......
  • husky配置实现代码提交前校验与规范提交信息
    husky是一个GitHook管理工具,主要用于实现提交前eslint校验和commit信息的规范校验。Husky的原理是让我们在项目根目录中写一个配置文件,然后在安装Husky的时候把配置文件和GitHook关联起来,这样我们就能在团队中使用GitHook了。首先,确保已经安装了husky和commitlint......
  • 微软应用商店第三次提交失败
    第二修改提交,继续失败。失败理由如下Theproductcrasheswhenselecting日语五十音图表,练习模式or挑战模式.TheissuewasobservedonmultipledevicesrunningWindowsbuild22621.1105ObservedOn:DellLatitude5502, MicrosoftsurfacelaptopGoTestedOn:De......
  • Gitlab 实现仓库完全迁移,包括所有提交记录、分支、标签
    1方案一:命令cd<项目目录>gitfetch--allgitfetch--tagsgitremoterenameoriginold-origin#可以不保留gitremoteaddoriginhttp://***(项目的新仓库地址)#gitremoteset-urlorigin<项目的新仓库地址>gitpushorigin--allgitpush--tags有多个分支的话......