栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

根据Spring-Security安全框架搭建问答论坛系统(更新中.....)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

根据Spring-Security安全框架搭建问答论坛系统(更新中.....)

Spring安全框架
  • 什么是Spring安全框架
  • 为什么需要Spring-Security
  • 启动Spring-Security
  • 访问控制器方法
    • 密码加密
    • Spring-Security的权限管理功能
  • 实现数据库中的用户登录
    • 设置放行页面
    • 自定义登录页面
  • 注册功能流程分析
    • 注册业务流程
    • 注册业务准备
    • 业务逻辑层概述
    • 开发注册业务逻辑层代码
    • 开发控制层代码
    • 修改为异步测试
  • Spring验证框架
    • 表单验证基本概念
    • 什么是Spring验证框架
    • Spring Validation的使用
  • 随笔

什么是Spring安全框架

Spring安全:Spring-Security

是Spring提供的安全管理框架,功能是提供一个安全可靠的登录功能,并且支持权限管理功能,而且自带判断当前用户是否登录的过滤器,如果用户没有登录会跳转到登录页面

为什么需要Spring-Security

使用Spring-Security框架能够使新手程序也能写出企业级别安全的登录功能

Spring-Security包含了权限管理的功能,能够方便的保存一个用户的各种权限,使用简单地方式判断这个用户是否包含这些权限,决定是否允许访问

能够帮助程序员提升编写登录和权限管理功能的开发效率

启动Spring-Security

启动Spring-Security非常的简单
只需要添加依赖即可


    org.springframework.boot
    spring-boot-starter-security


加好这个依赖Spring-Security这个框架就会在项目中生效了

现在所有项目中的资源都会被Spring-Security保护

也就是说默认情况下,要想访问当前项目的任何资源,都需要先登录。

而登录方法是:
用户名:user
密码:启动服务时idea控制台出现的随机密码

访问控制器方法

打开创建好的UserController在其中添加一个方法

代码如下:

@RestController
//在类上编写@RequestMapping注解,表示当前控制器中的方法都需要以本注解
//添加的路径前缀来访问
@RequestMapping("/v1/users")
public class UserController {
    //编写控制器方法
    //结合类上面的注解,访问笨方法的最终路径是
    //localhost:8080/v1/users/get   
    @GetMapping("/get")
    public String get(){
        return "Hello html";
    }
}

重启服务,访问localhost:8080/v1/users/get
也是需要登录的,因为控制器的响应也属于网站资源,受到Spring-Security保护

密码加密

上面我们登录只能使用user这个用户,而且密码每次都要到控制台复制,比较麻烦

Spring-Security允许我们自定义的用户名和密码配置到application.properties中配置

#配置Spring-Security的自定义用户名和密码
spring.security.user.name=admin
spring.security.user.password=123456

但是这样配置的话,任何可以看到配置文件的人都可以登陆这个网站

所以我们需要学习密码加密,加密之后即使别人看到密码,也不能登录

我们可以使用市面上流星的安全加密算法:bcrypt

这个加密算法可以将任何数据进行加密保存,保证安全

在测试类中进行一个加密操作,代码如下:

@SpringBootTest
public class PasswordTest {
    //对Bcrypt加密对象实例化
    PasswordEncoder encoder = new BCryptPasswordEncoder();

    //执行加密测试
    @Test
    public void test(){
        //利用加密对象将str字符串加密为pwd
        String str = "123456";
        String pwd = encoder.encode(str);
        System.out.println(pwd);
    }

}

运行输出了一个加密结果后发现每次结果都不同,因为每次加密秘结果相同的话安全性较低,bcrypt加密算法采用了"随机校验"技术,让每次生成结果都不同.
加密结果
加密完成下面进行验证的代码,bcrypt提供了验证的方法,可以判断一个字符串是否匹配一个加密结果

// 执行验证测试
@Test
public void match(){
// 下面的方法验证一个字符串是否匹配一个加密结果
// 返回boolean类型
boolean b=encoder.matches("123456",
"$2a$10$B5Ba4G77NuxAcRJ/iucipOaXjc/3uranz.lMW008IVxRdG
BATv8d2");
System.out.println("匹配结果:"+b);
}

最终目的是将加密结果配置在配置文件中application.properties文件修改为

#配置Spring-Security的自定义用户名和密码
spring.security.user.name=admin
spring.security.user.password={bcrypt}$2a$10$.6XmtLGrTwxO/JWWJCoc4OjoBQ7RG6cZ1WEHtYNbbYQWzVaqjTj2i
Spring-Security的权限管理功能

我们最终的登录是要支持现有数据库中所有user的数据

现在只能支持配置文件中的用户

如果要实现数据库登录,首先要有机会在java代码中设置用户名密码

创建一个security包,包中创建SecurityConfig,代码如下:

@Configuration
//启用spring-security提供的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //当前类继承WebSecurityConfigurerAdapter
    //能够重写这个父类中的方法,这个父类中的方法都是用于设置权限管理的

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("tom")
                .password("{bcrpt}$2a$10$.6XmtLGrTwxO/JWWJCoc4OjoBQ7RG6cZ1WEHtYNbbYQWzVaqjTj2i")
                .authorities("test");
        //上面代码的含义是在Spring-Security框架中定义了一个用户
        //用户名是tom,密码是123456
        //具有"test"这个资格可以使当前用户具有访问test资格资源的访问权限
        //当我们设置这个用户之后,配置文件中设置的用户admin就失效了
    }
}

控制器方法可以设定当前方法需要什么特殊权限才能访问,如果不设置默认情况下登录就可以访问

修改UserController代码如下:

@RestController
// 在类上编写下面注解,表示当前控制器中的方法都需要
// 以本注解添加的路径前缀来访问
@RequestMapping("/v1/users")
public class UserController {
// 编写控制器方法
// 结合类上面的注解,访问本方法的最终路径是
// localhost:8080/v1/users/get
@GetMapping("/get")
public String get(){
return "Hello html";
}
// 上面的方法没有设置特殊权限登录就可以访问
// 下面方法设置特殊权限,必须有匹配的资格才能访问
@GetMapping("/list")
// 当前这个方法必须是拥有test资格的用户才能访问
@PreAuthorize("hasAuthority('run')")
public String list(){
return "get list";
}
}


实现数据库中的用户登录

通过之前的部分,现在知道在Java代码中,要想让用户登录至少要提供用户名,密码,和当前用户权限

数据库用户表中没有直接提供当前用户的权限,那么我们就要根据对当前用户的id查询当前用户的权限

这个查询可能涉及上面的5张表

因为用户对角色和角色对权限都是多对多

今后面试时如果问到权限数据的实现方式,需要回答上面的5张表

我们需要编写一个根据用户id查询所有权限的5表联查的sql语句

SELECt p.id , p.name
FROM user u
LEFT JOIN user_role ur ON u.id=ur.user_id
LEFT JOIN role r ON r.id=ur.role_id
LEFT JOIN role_permission rp ON r.id=rp.role_id
LEFT JOIN permission p ON p.id=rp.permission_id
WHERe u.id=11

我们需要在数据访问层编写这个方法,在登录业务中需要时调用

打开UserMapper编写代码如下

@Repository
public interface UserMapper extends baseMapper {

    //根据用户id 查询用户所有权限的方法
    @Select("SELECT p.id , p.namen" +
            "FROM user un" +
            "LEFT JOIN user_role ur ON u.id=ur.user_idn" +
            "LEFT JOIN role r ON r.id=ur.role_idn" +
            "LEFT JOIN role_permission rp ON r.id=rp.role_idn" +
            "LEFT JOIN permission p ON p.id=rp.permission_idn" +
            "WHERe u.id=#{id}")
    List findUserPermissionsById(Integer id);

    //根据用户名查询用户对象
    @Select("select * from user where username=#{username}")
    User findUserByUsername(String username);
}

有了用户名,密码和用户权限等信息

下面就可以按照Spring-Security规定方式进行登录代码的编写了

我们需要自己编写一个类,这个类实现Spring-Security提供的恶一个接口UserDetailsService,而这个接口中需要实现一个方法,这个方法的功能是根据用户输入在登录框中的用户名进行用户信息(用户名密码权限)的查询,返回值必须是UserDetails,我们需要将这个类型对象实例化后赋值最后返回以完成登录

在service.impl包中新建一个类UserDetailsServiceImpl

代码如下

@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;
    //当前类需要保存到Spring容器@Component不能少
    //需要基于Spring-Security设计的方法进行登录,实现UserDetailsService接口
    //下面方法是接口提供的,我们来实现
    //方法的参数是用户在登录表单编写的用户名
    //方法的返回值是UserDetails类型对象包含登录需要的用户名密码权限等
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.根据用户名查询用户对象
        User user= userMapper.findUserByUsername(username);
        //2.判断是否能够查询到用户,没有该用户表示用户名不存在
        if (user==null){
            return null;
        }
        //3.根据用户id查询用户的所有权限
        List permissions=
                userMapper.findUserPermissionsById(user.getId());
        //4.将权限的集合转换为String类型数组进行赋值
        String[] auth = new String[permissions.size()];
        int i =0;
        for (Permission p : permissions){
            auth[i]=p.getName();
            i++;
        }
        //5.构建UserDetails对象
        UserDetails details =
                org.springframework.security.core.userdetails.User.builder()
                .username(user.getUsername())
                .password(user.getPassword())
                .authorities(auth).accountLocked(user.getLocked()==1)//设置当前用户是否锁定
                .disabled(user.getEnabled()==0)//设置当前用户是否可用 false表示可用
                .build();
        //6.返回
        return details;
    }
}

上面的代码是Spring-Security要求我们编写的完成登录功能的代码

我们要想登录成功,还要将这个类型对象和Spring-Security建立关系

回到security包中的SecurityConfig类

将我们之前编写的configure方法修改为

// 表示当前配置类是配置Spring框架的
@Configuration
// 启动Spring-Security提供的权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends
                        WebSecurityConfigurerAdapter {
    //当前类继承WebSecurityConfigurerAdapter
    // 能够重写这个父类中的方法,这个父类中的方法都是用于设置权限管理的

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);

    }
}
设置放行页面

当今流行的网站都是有些页面允许不登录就能访问

而我们现在的Spring-Security下所有资源都需要登录才能访问

我们如果想放行一些页面需要配置下面代码

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests() // 设置网站的访问及放行规则
            // 下面的方法开始指定路径
            .antMatchers(
                    "/index_student.html",
                    "/css/*",
                    "/js/*",
                    "/img/**",
                    "/bower_components/**")
            .permitAll() // 上面的路径是全部允许的(不需要登录就能访问)
            .anyRequest() // 除上面之外的其他路径
            .authenticated() // 需要登录才能访问
            .and()  //上面的配置完成了,开始配置下面的
            .formLogin(); // 使用表单进行登录
}
自定义登录页面

Spring-Security提供的默认登录页面不能体现当前网站的特征,也不能编写其他功能或连接,很受限制,我们希望能够使用自定义的login.html页面进行登录操作

也是需要进行对应的配置

SecurityConfig继续配置

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable() //禁用防跨域攻击功能
            .authorizeRequests() // 设置网站的访问及放行规则
            // 下面的方法开始指定路径
            .antMatchers(
                    "/index_student.html",
                    "/css/*",
                    "/js/*",
                    "/img/**",
                    "/bower_components/**",
                    "/login.html")
            .permitAll() // 上面的路径是全部允许的(不需要登录就能访问)
            .anyRequest() // 除上面之外的其他路径
            .authenticated() // 需要登录才能访问
            .and()  //上面的配置完成了,开始配置下面的
            .formLogin() // 使用表单进行登录
            .loginPage("/login.html") //配置登录时显示的页面
            .loginProcessingUrl("/login") //配置处理登录的路径
            .failureUrl("/login.html?error")// 登录失败跳转的页面
            .defaultSuccessUrl("/index_student.html")// 登录成功跳转的页面
            .and()
            .logout()
            .logoutUrl("/logout") // 配置登出的链接
            .logoutSuccessUrl("/login.html?logout");// 登出后跳转回登录页

}
注册功能流程分析 注册业务流程
  1. 学生填写注册表单信息
  2. 提交注册信息到控制器
  3. 控制器接收到信息调佣业务逻辑层方法
  4. 业务逻辑层中判断邀请码,手机号并对密码加密后进行数据库新增
  5. mapper层执行新增方法,返回到业务逻辑层
  6. 业务逻辑层将注册结果返回给控制鞥
  7. 控制层将最终信息显示在页面上
注册业务准备

首设置注册页面和控制器路径的放行

打开SecurityConfig配置类,进行放行配置

http.csrf().disable() //禁用防跨域攻击功能
                .authorizeRequests() // 设置网站的访问及放行规则
                // 下面的方法开始指定路径
                .antMatchers(
                        "/index_student.html",
                        "/css/*",
                        "/js/*",
                        "/img/**",
                        "/bower_components/**",
                        "/login.html",
                        "/register.html",
                        "/register")
                .permitAll() // 上面的路径是全部允许的(不需要登录就能访问)
                .anyRequest() // 除上面之外的其他路径
                .authenticated() // 需要登录才能访问
                .and()  //上面的配置完成了,开始配置下面的
                .formLogin() // 使用表单进行登录
                .loginPage("/login.html") //配置登录时显示的页面
                .loginProcessingUrl("/login") //配置处理登录的路径
                .failureUrl("/login.html?error")// 登录失败跳转的页面
                .defaultSuccessUrl("/index_student.html")// 登录成功跳转的页面
                .and()
                .logout()
                .logoutUrl("/logout") // 配置登出的链接
                .logoutSuccessUrl("/login.html?logout");// 登出后跳转回登录页

根据表单参数创建vo类

@Data
public class RegisterVo implements Serializable {
private String inviteCode; //邀请码
private String phone; //手机号用户名
private String nickname; //昵称
private String password; //密码
private String /confirm/i; //确认密码
}

还需要自定义异常类

在我们编写的业务发生异常不能继续运行时,使用抛出异常的方式反馈
错误信息

我们定义一个自定义异常类,ServiceException

来表示业务逻辑运行过程中发生的各种不能继续运行程序的异常

例如:邀请码不正确手机号已经被注册

新建一个包exception,新建类代码如下

public class ServiceException extends RuntimeException{
private int code = 500;
public ServiceException() { }
public ServiceException(String message) {
super(message);
}
public ServiceException(String message, Throwable
cause) {
super(message, cause);
}
public ServiceException(Throwable cause) {
super(cause);
}
public ServiceException(String message, Throwable
cause,
boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression,
writableStackTrace);
}
public ServiceException(int code) {
this.code = code;
}
public ServiceException(String message, int code) {
super(message);
this.code = code;
}
public ServiceException(String message, Throwable
cause,
int code) {
super(message, cause);
this.code = code;
}
public ServiceException(Throwable cause, int code)
{
super(cause);
this.code = code;
}
public ServiceException(String message, Throwable
cause,
boolean enableSuppression,
boolean writableStackTrace, int code) {
super(message, cause, enableSuppression,
writableStackTrace);
this.code = code;
}
public int getCode() {
return code;
}
}

还可以设置简单条件,适合偶尔一次查询数据库使用
我们在测试类中编写一个测试,按邀请码查询班级信息
代码如下

// 根据邀请码查询班级信息
// 如果写sql语句:
// select * from classroom where invite_code='JSD2001-
706246'
// 如果使用QueryWrapper进行查询 代码如下
@Autowired
ClassroomMapper classroomMapper;
@Test
public void query(){
// 我们实例化一个QueryWrapper的对象
// 这个对象其实就是代表查询的条件,泛型是实体类的类型
QueryWrapper query=new QueryWrapper<>();
// 设置查询条件 query.eq([列名],[值])
query.eq("invite_code","JSD2001-70624");
// 按QueryWrapper对象设置好的条件进行查询的操作
// selectOne方法只支持最多返回1行数据,否则报错,返回值是实
体类型
Classroom
classroom=classroomMapper.selectOne(query);
System.out.println(classroom);
}

业务逻辑层概述

Vrd项目中完成一次请求响应流程一般会由两个部分组成
请求->控制器(controller)->数据访问层(mapper)
上面的执行流程只能处理相对简单的业务逻辑层
如果遇到企业中的相对复杂的业务逻辑就不能很好的处理了
每个类都应该有自己的职责
// 根据邀请码查询班级信息
// 如果写sql语句:
// select * from classroom where invite_code=‘JSD2001-
706246’
// 如果使用QueryWrapper进行查询 代码如下
@Autowired
ClassroomMapper classroomMapper;
@Test
public void query(){
// 我们实例化一个QueryWrapper的对象
// 这个对象其实就是代表查询的条件,泛型是实体类的类型
QueryWrapper query=new QueryWrapper<>();
// 设置查询条件 query.eq([列名],[值])
query.eq(“invite_code”,“JSD2001-70624”);
// 按QueryWrapper对象设置好的条件进行查询的操作
// selectOne方法只支持最多返回1行数据,否则报错,返回值是实
体类型
Classroom
classroom=classroomMapper.selectOne(query);
System.out.println(classroom);
}
controller:职责就是接收前端页面的信息和将结果响应给页面,其他的事
情尽量不管
mapper:完成对数据库的增删改查操作,其他的操作也不管
如果出现了既不属于controller的也不属于mapper职责的工作,就需要
写在业务逻辑层中
service(业务逻辑层):职责就是将前端发送来的信息经过处理再调用数据
访问层的功能,例如我们接收了用户输入的邀请码但是需要判断是否正

企业标准中,service又由两个部分组成
service和service.impl
service中保存业务逻辑层接口:一般命名为IXXXService(开头的I表示
Interface)
service.impl中保存业务逻辑层实现类:一般命名为
XXXServiceImpl(Impl表示实现的缩写)
之所以采用接口配实现类的形式,是为了解耦
所以在需要业务逻辑层代码时,我们都声明接口类型
再今后我们开发程序的模型中,控制层,业务逻辑层,数据访问层这三层结
构如下

开发注册业务逻辑层代码

实际开发中,应该先完成数据访问层的编写,但是当前业务中,所有数据库
操作都是基本增删改查,已经由MybatisPlus提供了,所以Mapper层不需
要编写代码
先编写业务逻辑层接口
IUserService添加方法如下

public interface IUserService extends IService {
// 在接口中如果想转到实现类快捷键Ctrl+Alt+B
void registerStudent(RegisterVo registerVo);
}

UserServiceImpl实现类代码如下

@Service
public class UserServiceImpl extends
ServiceImpl implements IUserService {
//注入注册需要的各种依赖
@Autowired
private UserMapper userMapper;
@Autowired
private ClassroomMapper classroomMapper;
@Autowired
private UserRoleMapper userRoleMapper;
@Override
public void registerStudent(RegisterVo registerVo)
{
// 1.根据用户输入的邀请码获得班级信息
QueryWrapper query=new
QueryWrapper<>();
query.eq("invite_code",registerVo.getInviteCode());
Classroom
classroom=classroomMapper.selectOne(query);
// 2.判断班级信息是否存在,不存在直接抛异常
if(classroom==null){
throw new ServiceException("邀请码错误!");
}
// 3.根据用户输入的手机号,获得用户信息
User user=userMapper.findUserByUsername(
registerVo.getPhone());
// 4.如果能够获得用户信息,表示当前手机号已经被注册,抛出
异常
if(user!=null){
throw new ServiceException("手机号已经被注
册!");
}
// 5.对用户输入的密码进行加密
PasswordEncoder encoder=new
BCryptPasswordEncoder();
String pwd="
{bcrypt}"+encoder.encode(registerVo.getPassword());
// 6.实例化用户对象,为各个属性赋值,收集用户信息
User u=new User()
.setUsername(registerVo.getPhone())
.setNickname(registerVo.getNickname())
.setPassword(pwd)
.setClassroomId(classroom.getId())
.setCreatetime(LocalDateTime.now())
.setEnabled(1)
.setLocked(0)
.setType(0);
// 7.执行新增用户对象的操作
int num=userMapper.insert(u);
if(num!=1){
throw new ServiceException("数据库忙");
}
// 8.执行新增用户角色关系表的操作
UserRole userRole=new UserRole()
.setUserId(u.getId())
.setRoleId(2);
num=userRoleMapper.insert(userRole);
if(num!=1){
throw new ServiceException("数据库忙");
}
}
}




推荐大家编写完比价复杂的业务逻辑代码时进行测试
代码如下

@Autowired
IUserService userService;
@Test
public void add(){
RegisterVo registerVo=new RegisterVo();
registerVo.setPhone("13033012345");
registerVo.setNickname("大龙");
registerVo.setInviteCode("JSD2001-706246");
registerVo.setPassword("123456");
userService.registerStudent(registerVo);
System.out.println("ok");
}
开发控制层代码

我们先来编写控制层接收表单信息的代码

创建SystemController类

编写代码如下

@RestController
// lombok提供的一个记录日志用的注解
// 一旦在类上添加@Slf4j,这个类的方法中就可以使用log对象记录日志
@Slf4j
public class SystemController {
@Autowired
private IUserService userService;
@PostMapping("/register")
public String register(RegisterVo registerVo){
//利用日志对象,将接收到的信息输出到控制台
log.debug("接收到用户信息:{}",registerVo);
try {
userService.registerStudent(registerVo);
return "ok";
}catch (ServiceException e){
log.error("注册失败",e);
return e.getMessage();
}
}
}

重启服务测试

注册成功表示代码正确,检查数据库user表和user_role表示的信息

修改为异步测试

gitee同步更新中
将一个同步的注册修改为异步注册需要如下修改

  1. 页面中需要的支持(vue,axios等)

  1. 编写并引用js代码




  1. 页面的vue绑定(v-model…)

34行开始

我们需要修改一下注册页面显示错误信息的区域
30行附近


register.js代码 if判断修改一下

.then(function(r) {
console.log("|"+r.status+"|"+OK+"|");
if(r.data=="ok"){
console.log("注册成功");
console.log(r.data);
app.hasError = false;
location.href = '/login.html?register';
}else{
console.log(r.data);
app.hasError = true;
app.message = r.data;
}
});

Spring验证框架 表单验证基本概念

我们页面中通过编写html5diamante可以实现表单验证的逻辑

一般情况下,非空正则表达式的验证都是被支持的

正常编写表单验证之后,可以降低服务器的压力,提高服务器的运行性能

表单眼中正式非常好的验证方案,但是也有缺点:它只能防止通过表单进行注册的用户提交错误信息

如果有人恶意绕开浏览器直接将请求信息发送给服务器。服务器就会处理错误信息,严重情况下服务器就会瘫痪,我们需要服务端进行验证

有了服务端验证,才能防止绕开浏览器的数据不经过验证就进入数据库

这样的验证我们自己写是比较繁琐的,我们需要框架帮助我们简化

什么是Spring验证框架

Spring验证框架:Spring Validation
它能实现简单方便的服务器端验证并且能够接收验证结果

Spring Validation的使用

要想使用先添加依赖


org.springframework.boot
spring-boot-startervalidation


添加完成依赖之后,刷新maven,到需要验证的类中边写正则表达式,也支持非空验证和正则表达式验证等其他验证方式

@Data
public class RegisterVo implements Serializable {
//message就是当本属性为空时,输出的错误信息
@NotBlank(message = "邀请码不能为空")
private String inviteCode; //邀请码
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^1\d{10}$",message = "手机号格式
不正确")
private String phone; //手机号用户名
@NotBlank(message = "昵称不能为空")
@Pattern(regexp = "^.{2,20}$",message = "昵称是2~20
位字符")
private String nickname; //昵称
@NotBlank(message = "密码不能为空")
@Pattern(regexp = "^\w{6,20}$",message = "密码是
6~20位字符")
private String password; //密码
@NotBlank(message = "确认密码不能为空")
private String /confirm/i; //确认密码
}

控制器启动验证

@PostMapping("/register")
public String register(
// RegisterVo参数前添加@Validated表示开启服务器端验
证功能
// 当控制器方法运行之前,SpringValidation框架会按
RegisterVo
// 中编写的规则进行验证
@Validated RegisterVo registerVo,
// 这个参数必须紧随RegisterVo之后
// result中包含RegisterVo的验证结果
BindingResult result){
//利用日志对象,将接收到的信息输出到控制台
log.debug("接收到用户信息:{}",registerVo);
if(result.hasErrors()){
String msg=result.getFieldError().
getDefaultMessage();
// 返回错误信息
return msg;
}
try {
userService.registerStudent(registerVo);
return "ok";
}catch (ServiceException e){
log.error("注册失败",e);
return e.getMessage();
}
}

观察效果,我们还是使用浏览器来测试
所以可以暂时删除一些html5的表单验证

随笔

QueryWrapper方法含义:

eq(): equals-等于
gt(): grate than 大于
lt(): less than 小于
ge(): grate
equals 大于等于
le(): 小于等于
ne(): not equals 不等于

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/362507.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号