day68(Validation框架,跨域问题,关于客户端提交请求参数的格式,处理登录,开发流程)
2022/6/7 23:21:11
本文主要是介绍day68(Validation框架,跨域问题,关于客户端提交请求参数的格式,处理登录,开发流程),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
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
:可以配置min
和max
属性,同时限制最小值和最大值 -
@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.创建或配置(第一次开发)
-
配置(Spring Boot项目)
-
使用@MapperScan配置接口所在的根包
-
在配置文件中通过mybatis.mapper-locations配置XML文件的位置
-
-
处理某种类型数据的持久层访问,需要:
-
创建接口
-
创建XML文件
-
2.规划需要执行的SQL语句
-
SQL大致语句:
select * from ams_admin where username=?
-
由于不允许使用*号,因此细分为:
select id,username,password,nickname,avatar,is_enable from ams_admin username=?
-
提示:理论上,还应该查出
login_count
,当登录成功后,还应该更新login_count
、gmt_last_login
等数据,此次暂不考虑。
3.在接口中添加抽象方法(含创建必要的VO类)
1.所有查询结果都应该使用VO类
-
不要使用实体类,根据阿里的开发规范,每张数据表中都应该有
id
、gmt_create
、gmt_modified
这3个字段,而gmt_create
、gmt_modified
这2个字段都是用于特殊情况下排查问题的,一般情况下均不会使用,所以,如果使用实体类,必然存在多余的属性,同时,由于不使用星号作为字段列表,则一般也不会查询这2个字段的值,会导致实体类对象中永远至少存在2个属性为null
。 -
根据以上提示,以前已经写好的
getByUsername()
是不规范的,应该调整已存在此方法,本次并不需要添加新的抽象方法。 -
创建
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接口文件
-
将Admin getByUsername(String username)改为
AdminSimpleVO getByUsername(String username);
-
因为修改了源代码,所以调用了原方法的代码都会出现错误,包括:
-
测试
-
业务逻辑层的实现类
-
-
因及时修改,但是由于未完成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
-
-
创建统一的响应结果类型及相关类型
-
例如:
JsonResult
及State
-
如果第1次处理某种类型数据的控制器层访问,需要:
-
创建控制器类
-
添加
@RestController
-
添加
@RequestMapping
-
本次需要开发的“管理员登录”并不需要再做以上操作
2.添加处理请求的方法
3.处理异常(按需)
4.测试
5.管理员登录-前端页面
这篇关于day68(Validation框架,跨域问题,关于客户端提交请求参数的格式,处理登录,开发流程)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南
- 2024-09-30Dnd-Kit学习:新手快速入门指南