SpringBoot聚合项目:达内知道(四)-Spring Validation、学生首页标签列表显示
1.Spring 验证框架
1.1 什么是Spring验证框架?
Spring验证框架能约束控制器接收到用户填写数据的格式,一般有非空 / 正则表达式等常见要求。Spring 验证框架的英文是Spring Validation,它常用于Spring项目接收到数据的验证。
1.2 为什么需要Spring Validation?
我们在前端(html)页面中已经编写了对数据格式的验证?为什么java还要写呢?
因为黑客是可以直接绕过浏览器向服务器发请求的(有专门的软件可以向服务器发出请求),如果服务器端没有验证,任何数据都直接增加到数据库,使服务器崩溃。
如果添加了服务器验证,相当于加锁,这样才能保证服务器安全。由于我们自己写服务器验证比较麻烦,所以使用Spring Validation框架进行快速实现。
1.3 怎么使用Spring Validation?
先在portal项目的pom.xml文件中添加依赖:
<!-- 验证框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
我们到需要进行验证的封装数据的类中(vo/RegisterVo.java)进行格式设置,代码如下:
package cn.tedu.knows.portal.vo;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
Spring Validation常用注解含义:
-
@NotBlank:只能作用在字符串上,判断当前属性不能为null,而且对当前属性调用trim方法后length()必须大于0 ;
-
@Pattern:只能作用在字符串上,可以指定一个正则表达式,判断属性值是否满足正则表达式要求;
-
@NotNull:可以作用在任何引用类型上,判断当前属性不能为null;
-
@NotEmpty:一般作用在集合(或数组)类型上,判断当前集合(或数组)不能为空且长度不能为0。
最终使用时,在控制器SystemController中编写代码,代码如下:
package cn.tedu.knows.portal.controller;
import cn.tedu.knows.portal.exception.ServiceException;
import cn.tedu.knows.portal.service.IUserService;
import cn.tedu.knows.portal.vo.RegisterVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
编写完毕后,重启服务进行测试,可以先将前端代码index_student.html中表单属性的required和pattern(正则表达式)去掉,然后测试后端代码是否可以正常提示错误信息,两者同时存在时,只会显示前端验证信息。
测试结果:
(1)邀请码错误
(2)手机号格式不正确
(3)手机号重复注册
(4)昵称格式不正确
(5)密码格式不正确
(6)确认密码格式不正确
(7)注册成功
(8)登录成功
2.开发学生首页标签列表
学生首页如下:
标签列表开发流程:
-
用户在显示首页之后,页面加载完毕时,立即调用查询所有tag标签的方法
-
控制器运行调用查询返回所有标签List的业务逻辑层方法
-
业务逻辑层利用Mybatis Plus提供的全查Tag的方法,进行返回所有标签的操作
-
返回到页面上进行v-for的绑定,最终显示
2.1 开发全查所有标签的业务逻辑层
先编写接口:在ITagService添加查询所有标签的方法
package cn.tedu.knows.portal.service;
import cn.tedu.knows.portal.model.Tag;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author tedu.cn
* @since 2021-08-23
*/
public interface ITagService extends IService<Tag> {
//查询返回所有标签的方法
List<Tag> getTags();
}
接口上Ctrl+Alt+B,跳到TagServiceImpl实现类重写方法代码如下:
package cn.tedu.knows.portal.service.impl;
import cn.tedu.knows.portal.model.Tag;
import cn.tedu.knows.portal.mapper.TagMapper;
import cn.tedu.knows.portal.service.ITagService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author tedu.cn
* @since 2021-08-23
*/
2.2 编写控制层代码
TagController添加查询并返回所有标签的方法,代码如下:
package cn.tedu.knows.portal.controller;
import cn.tedu.knows.portal.model.Tag;
import cn.tedu.knows.portal.service.ITagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author tedu.cn
* @since 2021-08-23
*/
2.3 完成页面绑定
最后还要将页面绑定和引用写好,就能显示了。
在index_student.html 的head标签结束前引入axios框架:ax+Tab
<!--引入axios框架-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
</head>
164行 附近id为tagsApp的div:
<!--引入标签的导航栏-->
<div class="container-fluid" th:fragment="tags_nav" >
<div class="nav font-weight-light" id="tagsApp">
<a href="tag/tag_question.html" class="nav-item nav-link text-info"><small>全部</small></a>
<a href="tag/tag_question.html"
class="nav-item nav-link text-info"
v-for="tag in tags">
<small v-text="tag.name">Java基础</small><!--添加内容-->
</a>
</div>
</div>
页面末尾添加引用:
</body>
<script src="js/utils.js"></script>
<script src="js/tags_nav.js"></script>
</html>
编写完成后,重启服务,测试,注意要登录后才能正常加载首页标签列表,下次课解决这个登录后才能加载的问题。
2.4 完善放行设置
经过业务分析,我们得出,达内知道首页需要根据当前登录用户来显示具体信息,所以首页是登录之后才能访问的。因为上述原因,我们将/index_student.html的放行设置从Spring-Security的配置中取消。
SecurityConfig类中放行设置修改如下:
.antMatchers( //匹配路径
// "/index_student.html", //学生首页,需要登录后才能查看
"/js/*", //当前目录下的所有文件
"/css/*", //当前目录下的所有文件
"/img/**", //当前目录及子目录下的所有文件
"/bower_components/**", //当前目录及子目录下的所有文件
"/login.html", //放行自定义登录页面路径
"/register.html", //放行注册页面
"/register" //放行注册路径
).permitAll() //上述路径全部允许直接访问
2.5 设置标签的缓存
每个登录用户首页上标签列表中的所有标签信息都是一样的,每个登录的用户都需要查询,如果都从数据库中查询的话,效率会低。我们可以将所有标签都保存在内存中,需要时直接从内存中取,提高效率,这样的做法就算是缓存标签信息。
适合做缓存的数据需要同时满足如下3种特征:
-
数据量不大
-
经常被访问
-
不频繁修改,或对修改不敏感的
那么我们上次课编写的查询所有标签就应该使用缓存来处理,处理思路是:项目启动后,第一次查询数据库,然后将查询出的所有标签保存在内存中,之后的所有请求都从内存中获得,不再查询数据库,提高效率。
修改TagServiceImpl类中获得所有标签的方法,代码如下:
//声明一个List保存所有标签,用作缓存
private List<Tag> tags=new CopyOnWriteArrayList<>();//CopyOnWriteArrayList为线程安全的集合
//从Spring容器中取TagMapper
重启服务,感受缓存的效率提高(人眼几乎察觉不到其中的差别,相对之前,刷新后加载的更快了)。