springboot curd(2)

一,添加页面

问题一:

如果直接跳转到页面上,无法取得在session域内的值。

解决方法:需要跳转到后台页面用方法获取后跳转到指定的添加页面


@RequestMapping("/add.do")
public String queryDepartmentAll(HttpSession session, Model model) {
    Object employees = session.getAttribute("employees");
    if (employees != null) {
        System.out.println("部门数量:" + ((List<Employee>) employees).size());
    } else {
        System.err.println("session中的数据丢失");
        departmentList = departmentDao.getDepartments();
        model.addAttribute("departments", departmentList);
    }
    return "add";
}
问题二:

spring boot 表单的实体提交错误:Validation failed for object='book'. Error count: 2

解决方案:

在方法的实体类前面添加@Valid ,在后面添加BindingResult bindingResult

问题三:添加页面时,日期转换问题

解决方法:在下面类中添加Converter类


@Bean
public Converter<String, Date> addNewConvert() {
    return new Converter<String, Date>() {
        @Override
        public Date convert(String source) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = null;
            try {
                date = sdf.parse(source);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return date;
        }
    };
}

问题四:添加与修改页面的提交方法不一致

处理办法:1.





 问题五:springboot 表单重复提交

处理办法:

拦截器
Spring 拦截器有两种实现方法。一种是继承HandlerInterceptorAdapter,拥有preHandle(业务处理器处理请求之前被调用),postHandle(在业务处理器处理请求执行完成后,生成视图之前执行),afterCompletion(在完全处理完请求后被调用,可用于清理资源等)三个方法。
另一种就是调用 Spring AOP 的方法来实现。而且,我觉得这种方法更加灵活方便,所以我比较经常使用这种方法。

AOP( AspectJ— 注解 风格)
AOP 就是 Aspect Oriented Programming(面向方面编程)。
1. 连接点(Joinpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点
2. 前置通知(@Before):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
3. 抛出异常后通知(@AfterThrowing):方法抛出异常退出时执行的通知

解决问题

表单重复提交

服务器认为是同一个表单,在短时间内重复(不止一次)提交,或者提交异常。比如,在服务器还没有响应前我们不断点击刷新网页上一个提交按钮,或者通过 ajax 不断对服务器发送请求报文!

防止情况
不通过正常路径访问页面表单; session 失效情况下提交表单; 短时间内不止一次提交表单。
解决方案

一般情况下,是在服务器利用 session 来防止这个问题的。
流程图:
这里写图片描述
1. 网页点击事件,网页提交发送申请;
2. 服务器收到申请,并产生令牌(Token),并存于 Session 中;
3. 服务器将令牌返回给页面,页面将令牌与表单真正提交给服务器。

这种就是 structs 的令牌方式。还有其他方法,就是重定向方法或设置页面过期(前端部分不太了解),不过还是感觉强制跳转不是特别友好,同时也不够灵活多用。

前期准备

新建一个 spring boot 项目(建议 1.3.X 以上版本)。
加入 aop 依赖,默认设置就行了:

?
1
2
3
4
<dependency>
     <groupid>org.springframework.boot</groupid>
     spring-boot-starter-aop</artifactid>
</dependency>
正式开工
注解类 Token.java
?
1
2
3
4
5
6
7
8
9
@Retention (RetentionPolicy.RUNTIME)
@Target (ElementType.METHOD)
@Documented
public @interface Token {
     //生成 Token 标志
     boolean save() default false ;
     //移除 Token 值
     boolean remove() default false ;
}
表单异常类 FormRepeatException.java
?
1
2
3
4
5
6
public class FormRepeatException extends RuntimeException {
 
     public FormRepeatException(String message){ super (message);}
 
     public FormRepeatException(String message, Throwable cause){ super (message, cause);}
}
拦截器 TokenContract.java
注意:@Aspect与@Component两个注解!
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@Aspect
@Component
public class TokenContract {
 
     private static final Logger logger = LoggerFactory.getLogger(TokenContract. class );
 
     @Before ( "within(@org.springframework.stereotype.Controller *) && @annotation(token)" )
     public void testToken( final JoinPoint joinPoint, Token token){
         try {
             if (token != null ) {
                 //获取 joinPoint 的全部参数
                 Object[] args = joinPoint.getArgs();
                 HttpServletRequest request = null ;
                 HttpServletResponse response = null ;
                 for ( int i = 0 ; i < args.length; i++) {
                     //获得参数中的 request && response
                     if (args[i] instanceof HttpServletRequest) {
                         request = (HttpServletRequest) args[i];
                     }
                     if (args[i] instanceof HttpServletResponse) {
                         response = (HttpServletResponse) args[i];
                     }
                 }
 
                 boolean needSaveSession = token.save();
                 if (needSaveSession){
                     String uuid = UUID.randomUUID().toString();
                     request.getSession().setAttribute( "token" , uuid);
                     logger.debug( "进入表单页面,Token值为:" +uuid);
                 }
 
                 boolean needRemoveSession = token.remove();
                 if (needRemoveSession) {
                     if (isRepeatSubmit(request)) {
                         logger.error( "表单重复提交" );
                         throw new FormRepeatException( "表单重复提交" );
                     }
                     request.getSession( false ).removeAttribute( "token" );
                 }
             }
 
         } catch (FormRepeatException e){
             throw e;
         } catch (Exception e){
             logger.error( "token 发生异常 : " +e);
         }
     }
 
     private boolean isRepeatSubmit(HttpServletRequest request) throws FormRepeatException {
         String serverToken = (String) request.getSession( false ).getAttribute( "token" );
         if (serverToken == null ) {
             //throw new FormRepeatException("session 为空");
             return true ;
         }
         String clinetToken = request.getParameter( "token" );
         if (clinetToken == null || clinetToken.equals( "" )) {
             //throw new FormRepeatException("请从正常页面进入!");
             return true ;
         }
         if (!serverToken.equals(clinetToken)) {
             //throw new FormRepeatException("重复表单提交!");
             return true ;
         }
         logger.debug( "校验是否重复提交:表单页面Token值为:" +clinetToken + ",Session中的Token值为:" +serverToken);
         return false ;
     }
}
Controller类
访问 https://localhost:8080/savetoken 来获得令牌值
访问 https://localhost:8080/removetoken?token=XXX 来提交真正的表单
?
1
2
3
4
5
6
7
8
9
10
11
12
13
@Token (save = true )
@RequestMapping ( "/savetoken" )
@ResponseBody
public String getToken(HttpServletRequest request, HttpServletResponse response){
     return (String) request.getSession().getAttribute( "token" );
}
 
@Token (remove = true )
@RequestMapping ( "/removetoken" )
@ResponseBody
public String removeToken(HttpServletRequest request, HttpServletResponse response){
     return "success" ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值