SpringBoot整合Mybatis和Shiro(代码记录)
本文为个人学习demo记录随笔,主要代码记录
*Redis部分忽略,因为仅仅是整合,未测试
*内容中包含很多个人学习性代码
一、项目目录
展开
二、详细代码
pom.xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.1.RELEASE</version> <relativePath/> </parent> <groupId>com.classic</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <mybatis.version>2.1.3</mybatis.version> <shiro.version>1.5.3</shiro.version> <hikaricp.version>3.4.5</hikaricp.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <!-- JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <exclusions> <exclusion> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> </exclusion> </exclusions> </dependency> <!-- HikariCP --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.version}</version> </dependency> <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>${shiro.version}</version> </dependency> <!-- Redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.properties
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
### 基本配置 ### server.port=8080 server.servlet.context-path=/demo ### DataSource ### spring.datasource.url=jdbc:mysql://localhost:3306/sourceplan?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false spring.datasource.username=root spring.datasource.password=pw123456 # 驱动 spring.datasource.driver-class-name=com.mysql.jdbc.Driver # 数据源类型 spring.datasource.type=com.zaxxer.hikari.HikariDataSource # 连接池名称 spring.datasource.hikari.pool-name=DateSourceHikariCP # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒 spring.datasource.hikari.connection-timeout=30000 # 最小连接数 spring.datasource.hikari.minimum-idle=10 # 最大连接数 spring.datasource.hikari.maximum-pool-size=2000 # 自动提交 spring.datasource.hikari.auto-commit=true # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟 spring.datasource.hikari.idle-timeout=600000 # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms spring.datasource.hikari.max-lifetime=1800000 # 连接测试 spring.datasource.hikari.connection-test-query=SELECT 1 ### MyBatis 配置 ### # 所有POJO类所在包路径 #mybatis.type-aliases-package=com.test.pojo # mapper映射文件 mybatis.mapper-locations=classpath:mapper/*.xml ### Redis pool 配置 ### # Redis数据库索引(默认为0,最大15) #spring.redis.database=0 # Redis服务器地址 #spring.redis.host=192.168.0.24 # Redis服务器连接端口 #spring.redis.port=6379 # Redis服务器连接密码(默认为空) #spring.redis.password= # 连接池最大连接数(使用负值表示没有限制) #spring.redis.pool.max-active=200 # 连接池最大阻塞等待时间(使用负值表示没有限制) #spring.redis.pool.max-wait=-1 # 连接池中的最大空闲连接 #spring.redis.pool.max-idle=10 # 连接池中的最小空闲连接 #spring.redis.pool.min-idle=0 # 连接超时时间(毫秒) #spring.redis.timeout=1000
启动类:DemoApplication.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.app; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication @ComponentScan(basePackages = {"com.classic"}) @MapperScan("com.classic.dao") @EnableTransactionManagement // 启注解事务管理,等同于xml配置方式的 <tx:annotation-driven /> public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
建表语句(表中均为模拟数据)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for permission -- ---------------------------- DROP TABLE IF EXISTS `permission`; CREATE TABLE `permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `permission_code` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of permission -- ---------------------------- INSERT INTO `permission` VALUES ('1', 'query'); INSERT INTO `permission` VALUES ('2', 'update'); INSERT INTO `permission` VALUES ('3', 'insert'); INSERT INTO `permission` VALUES ('4', 'delete'); -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `role_code` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES ('1', 'ADMIN'); INSERT INTO `role` VALUES ('2', 'USER'); -- ---------------------------- -- Table structure for role_to_permission -- ---------------------------- DROP TABLE IF EXISTS `role_to_permission`; CREATE TABLE `role_to_permission` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_id` int(11) DEFAULT NULL, `permission_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of role_to_permission -- ---------------------------- INSERT INTO `role_to_permission` VALUES ('1', '1', '1'); INSERT INTO `role_to_permission` VALUES ('2', '1', '2'); INSERT INTO `role_to_permission` VALUES ('3', '1', '3'); INSERT INTO `role_to_permission` VALUES ('4', '1', '4'); INSERT INTO `role_to_permission` VALUES ('5', '2', '1'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(30) DEFAULT NULL, `password` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'zhousjcn', 'pw123456'); INSERT INTO `user` VALUES ('2', 'zhousj', 'pw123456'); -- ---------------------------- -- Table structure for user_role -- ---------------------------- DROP TABLE IF EXISTS `user_role`; CREATE TABLE `user_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `user_id` bigint(20) DEFAULT NULL, `role_id` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of user_role -- ---------------------------- INSERT INTO `user_role` VALUES ('1', '1', '1'); INSERT INTO `user_role` VALUES ('2', '2', '2');
entity
User.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.entity; import java.util.Set; public class User { private Long id; private String username; private String password; /* * 用户对应角色集合 */ private Set<Role> roleSet; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Set<Role> getRoleSet() { return roleSet; } public void setRoleSet(Set<Role> roleSet) { this.roleSet = roleSet; } }
Role.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.entity; import java.util.Set; public class Role { private Long id; private String roleCode; /** * 角色对应权限集合 */ private Set<Permission> permissionSet; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getRoleCode() { return roleCode; } public void setRoleCode(String roleCode) { this.roleCode = roleCode; } public Set<Permission> getPermissionSet() { return permissionSet; } public void setPermissionSet(Set<Permission> permissionSet) { this.permissionSet = permissionSet; } }
Permission.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.entity; public class Permission { private Long id; private String permissionCode; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getPermissionCode() { return permissionCode; } public void setPermissionCode(String permissionCode) { this.permissionCode = permissionCode; } }
AbstractDao.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.commons; /** * 一些规定的dao层接口 * @author ... * */ public abstract class AbstractDao { }
configure包
DemoExceptionHandler.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.configure; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.UnauthorizedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; /** * 异常捕捉类 */ @ControllerAdvice public class DemoExceptionHandler { private static Logger logger = LoggerFactory.getLogger(DemoExceptionHandler.class); @ExceptionHandler @ResponseBody public String unauthenticatedExceptionHandler(UnauthenticatedException e) { logger.warn(e.getMessage(), e); return "用户名或密码错误"; } @ExceptionHandler @ResponseBody public String unauthorizedExceptionHandler(UnauthorizedException e) { logger.warn(e.getMessage(), e); return "权限不足"; } @ExceptionHandler @ResponseBody public String exceptionHandler(Exception e) { logger.error(e.getMessage(), e); return "未知异常"; } }
ExceptionMessageType.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.configure; public enum ExceptionMessageType { AUTHENTICATION_EXCEPTION, AUTHORIZATION_EXCEPTION, UNAUTHENTICATED_EXCEPTION, // 账号密码错误 UNAUTHORIZED_EXCEPTION // 权限不足 }
RedisConfig.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.configure; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; @Configuration public class RedisConfig { @Bean // @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, DefaultTyping.NON_FINAL, As.PROPERTY); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也采用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式采用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式采用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
ShiroConfig.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.configure; import java.util.HashMap; import java.util.Map; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.classic.realm.UserRealm; @Configuration public class ShiroConfig { @Autowired private UserRealm userRealm; /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions) * 配置以下两个bean(DefaultAdvisorAutoProxyCreator和AuthorizationAttributeSourceAdvisor)即可实现此功能 * @return */ @Bean @ConditionalOnMissingBean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator daapc = new DefaultAdvisorAutoProxyCreator(); daapc.setProxyTargetClass(true); return daapc; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } //权限管理,配置主要是Realm的管理认证 @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm); return securityManager; } //Filter工厂,设置对应的过滤条件和跳转条件 @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); Map<String, String> map = new HashMap<>(); //登出 map.put("/logout", "logout"); //对所有用户认证 map.put("/**", "authc"); // 如果未登录这跳转登录 shiroFilterFactoryBean.setLoginUrl("/user/login"); //首页 shiroFilterFactoryBean.setSuccessUrl("/index"); //错误页面,认证不通过跳转 shiroFilterFactoryBean.setUnauthorizedUrl("/error"); shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } }
realm包
UserRealm.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.realm; import java.util.Set; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.classic.entity.Permission; import com.classic.entity.Role; import com.classic.entity.User; import com.classic.service.UserService; @Component public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { Object primaryPrincipal = principals.getPrimaryPrincipal(); if (primaryPrincipal == null) { return null; } String principal = primaryPrincipal.toString(); User user = userService.queryUserByUsername(principal); if (user == null) { return null; } SimpleAuthorizationInfo sai = new SimpleAuthorizationInfo(); Set<Role> roleSet = user.getRoleSet(); if (roleSet != null && roleSet.size() > 0) { for (Role role : roleSet) { // 添加角色 sai.addRole(role.getRoleCode()); // 添加权限 Set<Permission> permissionSet = role.getPermissionSet(); if (permissionSet != null && permissionSet.size() > 0) { for (Permission permission : permissionSet) { sai.addStringPermission(permission.getPermissionCode()); } } } } return sai; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //加这一步的目的是在Post请求的时候会先进认证,然后在到请求 Object principalObj = token.getPrincipal(); if (principalObj == null) { return null; } //获取用户信息 String principal = principalObj.toString(); User user = userService.queryUserByUsername(principal); if (user == null) { //这里返回后会报出对应异常 return null; } else { //这里验证authenticationToken和simpleAuthenticationInfo的信息 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, user.getPassword().toString(), getName()); return simpleAuthenticationInfo; } } }
util包
RedisUtil.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.util; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; /** * Redis工具类 */ @Component public final class RedisUtil { @Autowired private RedisTemplate<String, Object> redisTemplate; // =============================common============================ /** * 指定缓存失效时间 * @param key 键 * @param time 时间(秒) * @return */ public boolean expire(String key, long time) { try { if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据key 获取过期时间 * @param key 键 不能为null * @return 时间(秒) 返回0代表为永久有效 */ public long getExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } /** * 判断key是否存在 * @param key 键 * @return true 存在 false不存在 */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除缓存 * @param key 可以传一个值 或多个 */ @SuppressWarnings("unchecked") public void del(String... key) { if (key != null && key.length > 0) { if (key.length == 1) { redisTemplate.delete(key[0]); } else { redisTemplate.delete(CollectionUtils.arrayToList(key)); } } } // ============================String============================= /** * 普通缓存获取 * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入 * @param key 键 * @param value 值 * @return true成功 false失败 */ public boolean set(String key, Object value) { try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 普通缓存放入并设置时间 * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } else { set(key, value); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 递增 * @param key 键 * @param delta 要增加几(大于0) * @return */ public long incr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递增因子必须大于0"); } return redisTemplate.opsForValue().increment(key, delta); } /** * 递减 * @param key 键 * @param delta 要减少几(小于0) * @return */ public long decr(String key, long delta) { if (delta < 0) { throw new RuntimeException("递减因子必须大于0"); } return redisTemplate.opsForValue().increment(key, -delta); } // ================================Map================================= /** * HashGet * @param key 键 不能为null * @param item 项 不能为null * @return 值 */ public Object hget(String key, String item) { return redisTemplate.opsForHash().get(key, item); } /** * 获取hashKey对应的所有键值 * @param key 键 * @return 对应的多个键值 */ public Map<Object, Object> hmget(String key) { return redisTemplate.opsForHash().entries(key); } /** * HashSet * @param key 键 * @param map 对应多个键值 * @return true 成功 false 失败 */ public boolean hmset(String key, Map<String, Object> map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * HashSet 并设置时间 * @param key 键 * @param map 对应多个键值 * @param time 时间(秒) * @return true成功 false失败 */ public boolean hmset(String key, Map<String, Object> map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value) { try { redisTemplate.opsForHash().put(key, item, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 向一张hash表中放入数据,如果不存在将创建 * @param key 键 * @param item 项 * @param value 值 * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 * @return true 成功 false失败 */ public boolean hset(String key, String item, Object value, long time) { try { redisTemplate.opsForHash().put(key, item, value); if (time > 0) { expire(key, time); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除hash表中的值 * @param key 键 不能为null * @param item 项 可以使多个 不能为null */ public void hdel(String key, Object... item) { redisTemplate.opsForHash().delete(key, item); } /** * 判断hash表中是否有该项的值 * @param key 键 不能为null * @param item 项 不能为null * @return true 存在 false不存在 */ public boolean hHasKey(String key, String item) { return redisTemplate.opsForHash().hasKey(key, item); } /** * hash递增 如果不存在,就会创建一个 并把新增后的值返回 * @param key 键 * @param item 项 * @param by 要增加几(大于0) * @return */ public double hincr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, by); } /** * hash递减 * @param key 键 * @param item 项 * @param by 要减少记(小于0) * @return */ public double hdecr(String key, String item, double by) { return redisTemplate.opsForHash().increment(key, item, -by); } // ============================set============================= /** * 根据key获取Set中的所有值 * @param key 键 * @return */ public Set<Object> sGet(String key) { try { return redisTemplate.opsForSet().members(key); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 根据value从一个set中查询,是否存在 * @param key 键 * @param value 值 * @return true 存在 false不存在 */ public boolean sHasKey(String key, Object value) { try { return redisTemplate.opsForSet().isMember(key, value); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将数据放入set缓存 * @param key 键 * @param values 值 可以是多个 * @return 成功个数 */ public long sSet(String key, Object... values) { try { return redisTemplate.opsForSet().add(key, values); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 将set数据放入缓存 * @param key 键 * @param time 时间(秒) * @param values 值 可以是多个 * @return 成功个数 */ public long sSetAndTime(String key, long time, Object... values) { try { Long count = redisTemplate.opsForSet().add(key, values); if (time > 0) expire(key, time); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 获取set缓存的长度 * @param key 键 * @return */ public long sGetSetSize(String key) { try { return redisTemplate.opsForSet().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 移除值为value的 * @param key 键 * @param values 值 可以是多个 * @return 移除的个数 */ public long setRemove(String key, Object... values) { try { Long count = redisTemplate.opsForSet().remove(key, values); return count; } catch (Exception e) { e.printStackTrace(); return 0; } } // ===============================list================================= /** * 获取list缓存的内容 * @param key 键 * @param start 开始 * @param end 结束 0 到 -1代表所有值 * @return */ public List<Object> lGet(String key, long start, long end) { try { return redisTemplate.opsForList().range(key, start, end); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 获取list缓存的长度 * @param key 键 * @return */ public long lGetListSize(String key) { try { return redisTemplate.opsForList().size(key); } catch (Exception e) { e.printStackTrace(); return 0; } } /** * 通过索引 获取list中的值 * @param key 键 * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 * @return */ public Object lGetIndex(String key, long index) { try { return redisTemplate.opsForList().index(key, index); } catch (Exception e) { e.printStackTrace(); return null; } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, Object value) { try { redisTemplate.opsForList().rightPush(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, Object value, long time) { try { redisTemplate.opsForList().rightPush(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, List<Object> value) { try { redisTemplate.opsForList().rightPushAll(key, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 将list放入缓存 * * @param key 键 * @param value 值 * @param time 时间(秒) * @return */ public boolean lSet(String key, List<Object> value, long time) { try { redisTemplate.opsForList().rightPushAll(key, value); if (time > 0) expire(key, time); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 根据索引修改list中的某条数据 * @param key 键 * @param index 索引 * @param value 值 * @return */ public boolean lUpdateIndex(String key, long index, Object value) { try { redisTemplate.opsForList().set(key, index, value); return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * 移除N个值为value * @param key 键 * @param count 移除多少个 * @param value 值 * @return 移除的个数 */ public long lRemove(String key, long count, Object value) { try { Long remove = redisTemplate.opsForList().remove(key, count, value); return remove; } catch (Exception e) { e.printStackTrace(); return 0; } } }
dao层
UserMapper.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.dao; import java.util.List; import org.apache.ibatis.annotations.Select; import com.classic.entity.User; public interface UserMapper { @Select("select * from user") List<User> queryAll(); @Select( "select id,username,password from user " + "where username = #{username}" ) User queryUserByUsername(String username); }
UserMapper.xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.classic.dao.UserMapper"> <!-- <select id="queryAll" resultType="com.classic.entity.User"> select * from user </select> --> </mapper>
RoleMapper.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.dao; import java.util.Set; import org.apache.ibatis.annotations.Select; import com.classic.entity.Role; public interface RoleMapper { Set<Role> queryRolesByIds(Set<Long> ids); @Select("select role_id from user_role where user_id=#{userId}") Set<Long> queryRoleIdsByUserId(Long userId); }
RoleMapper.xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.classic.dao.RoleMapper"> <sql id="selectAllColumnSql"> select id,role_code roleCode from role </sql> <select id="queryRolesByIds" resultType="com.classic.entity.Role"> <include refid="selectAllColumnSql" /> where id in <foreach collection="ids" item="id" index="index" open="(" close=")" separator=","> #{id} </foreach> </select> </mapper>
PermissionMapper.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.dao; import java.util.Set; import org.apache.ibatis.annotations.Select; import com.classic.entity.Permission; public interface PermissionMapper { Set<Permission> queryPermissionsByIds(Set<Integer> ids); @Select("select permission_id from role_to_permission where role_id=#{roleId}") Set<Integer> queryPermissionIdsByRoleId(Long roleId); }
PermissionMapper.xml
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.classic.dao.PermissionMapper"> <sql id="selectAllColumnSql"> select id,permission_code permissionCode from permission </sql> <select id="queryPermissionsByIds" resultType="com.classic.entity.Permission"> <include refid="selectAllColumnSql"/> where id in <foreach collection="ids" item="id" index="index" open="(" close=")" separator=","> #{id} </foreach> </select> </mapper>
service层
UserService.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.List; import com.classic.entity.User; public interface UserService { List<User> queryAll(); User queryUserByUsername(String username); }
UserServiceImp.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.List; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.classic.dao.UserMapper; import com.classic.entity.Role; import com.classic.entity.User; @Service public class UserServiceImp implements UserService { @Autowired private UserMapper userMapper; @Autowired private RoleService roleService; @Override public List<User> queryAll() { return userMapper.queryAll(); } @Override public User queryUserByUsername(String username) { User user = userMapper.queryUserByUsername(username); if (user != null) { Long userId = user.getId(); Set<Role> roleSet = roleService.queryRolesByUserId(userId); user.setRoleSet(roleSet); } return user; } }
RoleService.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.Set; import com.classic.entity.Role; public interface RoleService { Set<Role> queryRolesByUserId(Long userId); }
RoleServiceImpl.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.classic.dao.RoleMapper; import com.classic.entity.Role; @Service public class RoleServiceImpl implements RoleService { @Autowired private RoleMapper roleMapper; @Autowired private PermissionService permissionService; @Override public Set<Role> queryRolesByUserId(Long userId) { Set<Long> ids = roleMapper.queryRoleIdsByUserId(userId); if (ids != null && ids.size() > 0) { Set<Role> roleSet = roleMapper.queryRolesByIds(ids); if (roleSet != null && roleSet.size() > 0) { for (Role role : roleSet) { Long roleId = role.getId(); role.setPermissionSet(permissionService.queryPermissionsByRoleId(roleId)); } } return roleSet; } return null; } }
PermissionService.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.Set; import com.classic.entity.Permission; public interface PermissionService { Set<Permission> queryPermissionsByRoleId(Long roleId); }
PermissionServiceImpl.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.service; import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.classic.dao.PermissionMapper; import com.classic.entity.Permission; @Service public class PermissionServiceImpl implements PermissionService { @Autowired private PermissionMapper permissionMapper; @Override public Set<Permission> queryPermissionsByRoleId(Long roleId) { Set<Integer> ids = permissionMapper.queryPermissionIdsByRoleId(roleId); if (ids != null && ids.size() > 0) { return permissionMapper.queryPermissionsByIds(ids); } return null; } }
Controller层(仅提供测试接口)
UserController.java
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.classic.controller; import java.util.List; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationException; import org.apache.shiro.authz.annotation.Logical; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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 com.classic.entity.User; import com.classic.service.UserService; @RestController @RequestMapping("/user") public class UserController { private static final Logger logger = LoggerFactory.getLogger(UserController.class); @Autowired private UserService userService; @GetMapping("/queryAll") public List<User> queryAll() { return userService.queryAll(); } @GetMapping("/queryByUsername") public User queryByUsername(String username) { return userService.queryUserByUsername(username); } @RequestMapping("/login") public String userLogin(User user) { //添加用户认证信息 Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try { //进行验证,这里可以捕获异常,然后返回对应信息 subject.login(usernamePasswordToken); // subject.checkRole("ADMIN"); // subject.checkPermissions("query", "add"); } catch (AuthenticationException e) { logger.error(e.getMessage(), e); return "账号或密码错误!"; } catch (AuthorizationException e) { logger.error(e.getMessage(), e); return "没有权限"; } return "登录成功"; } @RequestMapping("/index") @RequiresRoles(value={"ADMIN","USER"},logical = Logical.OR) @RequiresPermissions(value={"query"},logical = Logical.OR) public String indexTest() { return "Index"; } @RequestMapping("/logout") public String userLogout() { Subject subject = SecurityUtils.getSubject(); subject.logout(); return "登出成功"; } }
参考链接:
https://www.jianshu.com/p/7f724bec3dc3