ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

day68(Validation框架,跨域问题,关于客户端提交请求参数的格式,处理登录,开发流程)

2022-06-07 22:01:29  阅读:178  来源: 互联网

标签:username password 跨域 ruleForm 添加 NotNull day68 Validation String


day68(Validation框架,跨域问题,关于客户端提交请求参数的格式,处理登录,开发流程)

1. Validation框架

1.validation作用

当客户端向服务器提交请求时,如果请求数据出现明显的问题(例如关键数据为null、字符串的长度不在可接受范围内、其它格式错误),应该直接响应错误,而不是将明显错误的请求参数传递到Service!

关于判断错误,只有涉及数据库中的数据才能判断出结果的,都由Service进行判断,而基本的格式判断,都由Controller进行判断。

Validation框架是专门用于解决检查数据基本格式有效性的,最早并不是Spring系列的框架,目前,Spring Boot提供了更好的支持,所以,通常结合在一起使用。

2.添加依赖

在Spring Boot项目中,需要添加spring-boot-starter-validation依赖项,例如:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

3.添加注解

在控制器中,首先,对需要检查数据格式的请求参数添加@Valid@Validated注解(这2个注解没有区别),例如:

@RequestMapping("/add-new")
public JsonResult<Void> addNew(@Validated AdminAddNewDTO adminAddNewDTO) {
   adminService.addNew(adminAddNewDTO);
   return JsonResult.ok();
}

真正需要检查的是AdminAddNewDTO中各属性的值,所以,接下来需要在此类的各属性上通过注解来配置检查的规则,例如:

@Data
public class AdminAddNewDTO implements Serializable {

   @NotNull // 验证规则为:不允许为null
   private String username;
   
   // ===== 原有其它代码 =====
   
}

4.处理报错

重启项目,通过不提交用户名的URL(例如:http://localhost:8080/admins/add-new)进行访问,在浏览器上会出现400错误页面,并且,在IntelliJ IDEA的控制台会出现以下警告:

2022-06-07 11:37:53.424  WARN 6404 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [
org.springframework.validation.BindException:
org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'adminAddNewDTO' on field 'username': rejected value [null]; codes [NotNull.adminAddNewDTO.username,NotNull.username,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [adminAddNewDTO.username,username]; arguments []; default message [username]]; default message [不能为null]]

从警告信息中可以看到,当验证失败时(不符合所使用的注解对应的规则时),会出现org.springframework.validation.BindException异常,则自行处理此异常即可!

1.添加枚举

首先,在State中添加新的枚举:

public enum State {

   OK(200),
   ERR_USERNAME(201),
   ERR_PASSWORD(202),
   ERR_BAD_REQUEST(400), // 新增
   ERR_INSERT(500);

   // ===== 原有其它代码 =====
}

2.添加异常处理方法

然后,在GlobalExceptionHandler中添加新的处理异常的方法:

@ExceptionHandler(BindException.class)
public JsonResult<Void> handleBindException(BindException e) {
   return JsonResult.fail(State.ERR_BAD_REQUEST, e.getMessage());
}

完成后,再次重启项目,继续使用为null的用户名提交请求时,可以看到异常已经被处理,此时,响应的JSON数据例如:

{
   "state":400,
   "message":"org.springframework.validation.BeanPropertyBindingResult: 2 errors\nField error in object 'adminAddNewDTO' on field 'username': rejected value [null]; codes [NotNull.adminAddNewDTO.username,NotNull.username,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [adminAddNewDTO.username,username]; arguments []; default message [username]]; default message [不能为null]\nField error in object 'adminAddNewDTO' on field 'password': rejected value [null]; codes [NotNull.adminAddNewDTO.password,NotNull.password,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [adminAddNewDTO.password,password]; arguments []; default message [password]]; default message [不能为null]"
}

3.@NotNull注解

关于错误提示信息,以上内容中出现了不能为null的字样,是默认的提示文本,可以通过@NotNull注解的message属性进行配置,例如:

@Data
public class AdminAddNewDTO implements Serializable {

   @NotNull(message = "添加管理员失败,请提交用户名!")
   private String username;

   @NotNull(message = "添加管理员失败,请提交密码!")
   private String password;
   
   // ===== 原有其它代码 =====
   
}

4.自定义提示文本

然后,在处理异常时,通过异常信息获取自定义的提示文本:

@ExceptionHandler(BindException.class)
public JsonResult<Void> handleBindException(BindException e) {
   BindingResult bindingResult = e.getBindingResult();
   String defaultMessage = bindingResult.getFieldError().getDefaultMessage();
   return JsonResult.fail(State.ERR_BAD_REQUEST, defaultMessage);
}

再次运行,在不提交用户名和密码的情况下,会随机的提示用户名或密码验证失败的提示文本中的某1条。

5.validation注解

在Validation框架中,还有其它许多注解,用于进行不同格式的验证,例如:

  • @NotEmpty:只能添加在String类型上,不许为空字符串,例如""即视为空字符串

  • @NotBlank:只能添加在String类型上,不允许为空白,例如普通的空格可视为空白,使用TAB键输入的内容也是空白,(虽然不太可能在此处出现)换行产生的空白区域也是空白

  • @Size:限制大小

  • @Min:限制最小值

  • @Max:限制最大值

  • @Range:可以配置minmax属性,同时限制最小值和最大值

  • @Pattern:只能添加在String类型上,自行指定正则表达式进行验证

  • 其它

以上注解,包括@NotNull是允许叠加使用的,即允许在同一个参数属性上添加多个注解!

以上注解均可以配置message属性,用于指定验证失败的提示文本。

通常:

  • 对于必须提交的属性,都会添加@NotNull

  • 对于数值类型的,需要考虑是否添加@Range(则不需要使用@Min@Max

  • 对于字符串类型,都添加@Pattern注解进行验证

2.跨域问题

1.出现原因

因为现在开发大部分都是前后端分离开发,两个作为独立的项目,独立开发与部署。所以前端直接向后端发送异步请求,前端会出现以下错误

Access to XMLHttpRequest at 'http://localhost:8080/admins/add-new' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这种问题被称为跨域问题,关键字是CORS

2.解决方法

1.配置配置类

基于SpringMVC项目框架中,需要一个SpringMVC的配置类(实现了WebMvcConfigurer接口的类),并重新方法,以允许指定符合条件的进行跨域

package cn.tedu.boot.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {

   @Override
   public void addCorsMappings(CorsRegistry registry) {
       registry.addMapping("/**")
              .allowedOriginPatterns("*")
              .allowedMethods("*")
              .allowedHeaders("*")
              .allowCredentials(true)
              .maxAge(3600);
  }

}

3.关于客户端提交请求参数的格式

1.直接通过&拼接各参数与值

例如:

// username=root&password=123456&nickname=jackson&phone=13800138001&email=jackson@baidu.com&description=none
let data = 'username=' + this.ruleForm.username
             + '&password=' + this.ruleForm.password
             + '&nickname=' + this.ruleForm.nickname
             + '&phone=' + this.ruleForm.phone
             + '&email=' + this.ruleForm.email
             + '&description=' + this.ruleForm.description;

2.使用JSON语法来组织各参数与值

例如:

let data = {
   'username': this.ruleForm.username, // 'root'
   'password': this.ruleForm.password, // '123456'
   'nickname': this.ruleForm.nickname, // 'jackson'
   'phone': this.ruleForm.phone, // '13800138001'
   'email': this.ruleForm.email, // 'jackson@baidu.com'
   'description': this.ruleForm.description // 'none'
};

3.使用场景

具体使用哪种做法,取决于服务器端的设计:

  • 如果服务器端处理请求的方法中,在参数前添加了@RequestBody,则允许使用以上第2种做法(JSON数据)提交请求参数,不允许使用以上第1种做法(使用&拼接)

  • 如果没有使用@RequestBody,则只能使用以上第1种做法

4.处理登录

1.开发流程

1.先整理出当前项目涉及的数据的类型

  • 例如:电商类包含用户、商品、购物车、订单等

2.再列举各种数据类型涉及的数据操作

  • 例如:用户类型涉及注册、登陆等

3.再挑选相对简单的数据类型先处理

  • 简单的易于实现,且可以积累经验

4.在各类数据涉及到的数据操作中,大致遵循增、查、删、改的开发顺序

  • 只有先增,还可能查、删、改

  • 只有查了以后,才能明确有哪些数据,才便于实现删、改

  • 删和改相比,删一般更加简单,所以先开发删,再开发改

5.在开发具体的数据操作时,应该大致遵循持久层 >> 业务逻辑层 >> 控制器层 >> 前端页面的开发顺序

2.管理员登陆-持久层

1.创建或配置(第一次开发)

  1. 配置(Spring Boot项目)

    1. 使用@MapperScan配置接口所在的根包

    2. 在配置文件中通过mybatis.mapper-locations配置XML文件的位置

  2. 处理某种类型数据的持久层访问,需要:

    1. 创建接口

    2. 创建XML文件

2.规划需要执行的SQL语句

  1. SQL大致语句:

    select * from ams_admin where username=?
  2. 由于不允许使用*号,因此细分为:

    select id,username,password,nickname,avatar,is_enable from ams_admin username=?
  3. 提示:理论上,还应该查出login_count,当登录成功后,还应该更新login_countgmt_last_login等数据,此次暂不考虑。

3.在接口中添加抽象方法(含创建必要的VO类)

1.所有查询结果都应该使用VO类

  1. 不要使用实体类,根据阿里的开发规范,每张数据表中都应该有idgmt_creategmt_modified这3个字段,而gmt_creategmt_modified这2个字段都是用于特殊情况下排查问题的,一般情况下均不会使用,所以,如果使用实体类,必然存在多余的属性,同时,由于不使用星号作为字段列表,则一般也不会查询这2个字段的值,会导致实体类对象中永远至少存在2个属性为null

  2. 根据以上提示,以前已经写好的getByUsername()是不规范的,应该调整已存在此方法,本次并不需要添加新的抽象方法。

  3. 创建cn.tedu.boot.demo.pojo.vo.AdminSimpleVO类,添加此次查询时需要的属性:

    package cn.tedu.boot.demo.pojo.vo;

    @Data
    public class AdminSimpleVO implements Serializable {
       private Long id;
       private String username;
       private String password;
       private String nickname;
       private String avatar;
       private Integer isEnable;
    }

2.修改AdminMapper接口文件

  1. 将Admin getByUsername(String username)改为

AdminSimpleVO getByUsername(String username);
  1. 因为修改了源代码,所以调用了原方法的代码都会出现错误,包括:

    1. 测试

    2. 业务逻辑层的实现类

  2. 因及时修改,但是由于未完成SQL配置,相关代码暂时不能运行

4.在XML中的配置SQL

1.调整AdminMapper.xml

  • 删除<sql>中不必查询的字段,注意:此字段不要有多余的逗号

  • 修改<resultMap>节点的type属性值

  • <resultMap>节点下,删除不必要的配置

    <select id="getByUsername" resultMap="BaseResultMap">
       select
           <include refid="BaseQueryFields" />
       from
            ams_admin
       where
            username=#{username}
    </select>

    <sql id="BaseQueryFields">
       <if test="true">
           id,
           username,
           password,
           nickname,
           avatar,
           is_enable
       </if>
    </sql>

    <resultMap id="BaseResultMap" type="cn.tedu.boot.demo.pojo.vo.AdminSimpleVO">
       <id column="id" property="id" />
       <result column="username" property="username" />
       <result column="password" property="password" />
       <result column="nickname" property="nickname" />
       <result column="avatar" property="avatar" />
       <result column="is_enable" property="isEnable" />
    </resultMap>

5.编写并执行测试

此次并不需要编写新的测试,使用原有的测试即可!

注意:由于本次是修改了原“增加管理员”就已经使用的功能,应该检查原功能是否可以正常运行。

3.管理员登录-业务逻辑层

1.创建

如果第1次处理某种类型数据的业务逻辑层访问,需要:

  • 创建接口

  • 创建类,实现接口,并在类上添加@Service注解

本次需要开发的“管理员登录”并不需要再做以上操作

2.在接口中添加抽象方法(含创建必要的DTO类)

3.在实现类中设计(打草稿)业务流程与业务逻辑(含创建必要的异常类)

4.在实现类中实现业务

5.编写并执行测试

4.管理员登录-控制器层

1.创建

如果是整个项目第1次开发控制器层,需要:

  • 创建统一处理异常的类

    • 添加@RestControllerAdvice

  • 创建统一的响应结果类型及相关类型

    • 例如:JsonResultState

如果第1次处理某种类型数据的控制器层访问,需要:

  • 创建控制器类

    • 添加@RestController

    • 添加@RequestMapping

本次需要开发的“管理员登录”并不需要再做以上操作

2.添加处理请求的方法

3.处理异常(按需)

4.测试

5.管理员登录-前端页面

标签:username,password,跨域,ruleForm,添加,NotNull,day68,Validation,String
来源: https://www.cnblogs.com/xiaoyezilei/p/16353556.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有