SpringBoot(41) —— Shiro整合MyBatis

    科技2022-07-15  105

    1.Shiro整合MyBatis

    在上一篇博客中,我们为了通过账号+密码认证,直接就在realm中的AuthenticationInfo()中伪造了一个账户+密码,但是真正情况下我们应该从数据库中将数据查询出来,所以这一篇博客我们来整合Shiro+MyBatis,实现一个真正项目中的用户认证功能首先导入依赖<!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--Druid数据源依赖--> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.24</version> </dependency> <!--log4j的依赖--> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!--mybatis和spring boot整合依赖--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> 配置数据库连接4大参数+spring boot整合Druid数据源spring: datasource: username: root password: 123 url: jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource #Spring Boot 默认是不注入这些属性值的,需要自己绑定 #druid 数据源专有配置 initialSize: 5 minIdle: 5 maxActive: 20 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT 1 FROM DUAL testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入 #如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j filters: stat,wall,log4j #stat:监控统计、log4j:日志记录、wall:防御sql注入 maxPoolPreparedStatementPerConnectionSize: 20 useGlobalDataSourceStat: true connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

    spring boot整合mybatis,将mybatis配置写在application中即可#整合mybatis的配置 mybatis: type-aliases-package: com.thhh.pojo #给类取别名 mapper-locations: classpath:mybatis/mapper/*.xml #mapper注册 创建pojo,创建resource文件夹下的mybatis/mapper/*.xml文件package com.thhh.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String name; private String pwd; } 有一个pojo就创建一个mapper/daopackage com.thhh.mapper; import com.thhh.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; @Mapper @Repository public interface UserMapper { //根据用户名查询密码 public User queryUserByName(@Param("username") String name); } 有一个mapper就去编写一个mapper.xml,注意:在spring boot中我们统一将mapper.xml放在resource文件夹下<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.thhh.mapper.UserMapper"> <select id="queryUserByName" resultType="user"> SELECT * FROM mybatis.user WHERE name = #{username} </select> </mapper> 创建service层(完善这个项目的架构)package com.thhh.service; import com.thhh.pojo.User; public interface UserService { //通过用户名称查询用户对象 public User queryUserByName(String name); } service层的实现package com.thhh.service; import com.thhh.mapper.UserMapper; import com.thhh.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service //注意:一定把这个注解加上 public class UserServiceImpl implements UserService{ @Autowired private UserMapper mapper; @Override public User queryUserByName(String name) { return mapper.queryUserByName(name); } } 在业务足够简单的情况下,我们可以直接在controller层调用mapper/dao层,而省略service层,但是为了项目结构的合理性和可扩展性,我们最好写上service层测试service是否能够成功获取数据package com.thhh; import com.thhh.pojo.User; import com.thhh.service.UserService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class ShiroSpringbootApplicationTests { @Autowired private UserService userService; @Test void contextLoads() { User user = userService.queryUserByName("张三"); System.err.println(user); } }

    改造上一篇博客中编写的realm获取数据的过程//认证 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证========>doGetAuthenticationInfo"); //使用token获取用户传入需要认证的用户名+密码 UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; User user = userService.queryUserByName(usernamePasswordToken.getUsername()); if (user==null){ //判断用户名是否正确 return null; //如果用户名和我们数据库中的用户名不一致,即没有查询到用户,就return null, //只要return null,就会抛出异常,这里对比的是用户名,抛出的异常就是UnknownAccountException } //密码认证shiro不允许我们自己进行,我们只能将我们设置好的密码传进去,具体的操作,大概就是shiro会拿着我们在这里设置的密码和token中传入的密码进行对比,并返回结果 return new SimpleAuthenticationInfo("",user.getPwd(),""); //传入密码,shiro判断密码是否正确 } 测试 测试成功!注意:此时我们并没有在realm中伪造数据,我们的数据都是从数据库中查询出来的但是我们在使用spring security的时候,在认证阶段给我们报了一个错误,即强制要求我们将密码进行加密,否则不能正常使用 shiro中也可以对密码进行加密,这里先不展开讲,后面补上
    Processed: 0.013, SQL: 8