最近笔者在搭一个自己的小框架,基于SpringBoot全家桶整合了SpringSecurity、Redis、MyBatis-Plus、RSA加密等,所以我打算将搭建过程记录下来以做学习只用,好了废话不多说,下面开始。
针对Redis在项目中的使用场景,最基础的便是存取用户登录凭证----token,所以必须使用数据库去查询登录用户信息,那么文章就先从整合MyBatis-Plus开始。
写在前面:
MyBatis-Plus是一个非常强大且轻量的ORM框架,它在MyBatis的基础上只做了增强而不做改变,一方面降低了学习成本,另一方面你可以像使用MyBatis一样使用MyBatis-Plus。关于SpringBoot怎么整合MyBatis-plus,个人建议您还是去其官网去阅读官方文档去使用,首先官方文档写的更加权威,而且阅读官方文档也是一种能力。
maven工程:
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
<version>8.0.22version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jdbcartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plusartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
Gradle:
compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.4.1'
在pom中引入苞米豆依赖后,您就可以使用MP实现一行代码进行单表增删改查,多表查询按MyBatis的方式写xml即可,关于多表查询自动分页相关的内容,请阅读我的这篇文章:MyBatis_Plus联表分页查询
本文使用的是MySQL 8.0+版本、配置文件使用的是yml
yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&zeroDateTimeBehavior=round&characterEncoding=UTF-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
global-config:
# 关闭MP3.0自带的banner
banner: true
db-config:
#主键类型 0:"数据库ID自增",1:"该类型为未设置主键类型", 2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID",5:"字符串全局唯一ID (idWorker 的字符串表示)";
id-type: ASSIGN_ID
# 默认数据库表下划线命名
table-underline: true
configuration:
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 返回类型为Map,显示null对应的字段
call-setters-on-nulls: true
请按需更改您的数据库配置,整合完成
本文只是讲MP的引入,具体使用方法请参考这位大佬的文章:
MyBatis-Plus之基础CURD
写在后面
由于Mapper的特殊实现类xml文件在SpringBoot项目中属于resource文件,所以会涉及到一个资源文件加载问题,如果您想简单来的话,您可以直接在resource包下建立mapper包用于存放mapper.xml文件,pom中resource配置如下,如果您出现无法启动、如果是出现找不到Mapper报错的问题,请先查看target目录下xml有无加载为class文件。
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.xmlinclude>
includes>
resource>
<resource>
<directory>src/main/resourcesdirectory>
resource>
resources>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
pom.xml
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
application.yml
redis的配置请放在spring的配置,服务器配置请按需配置
spring:
redis:
database: 1
host: localhost
lettuce:
pool:
max-active: 8 #最大连接数据库连接数,设 0 为没有限制
max-idle: 8 #最大等待连接中的数量,设 0 为没有限制
max-wait: -1ms #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
min-idle: 0 #最小等待连接中的数量,设 0 为没有限制
shutdown-timeout: 100ms
password: ''
port: 6379
在SpringBoot中遵循约定大于配置,所以多数使用注解的方式来配置
RedisConfig.class
/**
* @author Liutx
* @date 2020/12/14 21:39
* @Description redisTemplate相关配置
* @EnableCaching 开启缓存
*/
@Configuration
@EnableCaching//开启注解
public class RedisConfig extends CachingConfigurerSupport {
@Resource
private LettuceConnectionFactory lettuceConnectionFactory;
/**
* @description 自定义的缓存key的生成策略 若想使用这个key
* 只需要讲注解上keyGenerator的值设置为keyGenerator即可
* @return 自定义策略生成的key
*/
@Override
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getDeclaringClass().getName());
Arrays.stream(params).map(Object::toString).forEach(sb::append);
return sb.toString();
}
};
}
/**
* RedisTemplate配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
RedisSerializer<?> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);// key序列化
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);// value序列化
redisTemplate.setHashKeySerializer(stringSerializer);// Hash key序列化
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);// Hash value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 缓存配置管理器
*/
@Bean
public CacheManager cacheManager(LettuceConnectionFactory factory) {
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
// 以锁写入的方式创建RedisCacheWriter对象
//RedisCacheWriter writer = RedisCacheWriter.lockingRedisCacheWriter(factory);
// 创建默认缓存配置对象
/* 默认配置,设置缓存有效期 1小时*/
//RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));
/* 配置test的超时时间为120s*/
RedisCacheManager cacheManager = RedisCacheManager.builder(RedisCacheWriter.lockingRedisCacheWriter(factory)).cacheDefaults(redisCacheConfiguration)
.withInitialCacheConfigurations(singletonMap("test", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(120)).disableCachingNullValues()))
.transactionAware().build();
return cacheManager;
}
}
在项目中我们可以直接使用 redisTemplate 来进行对Redis的操作,一般情况下我们可以封装一个工具类去实现功能。
由于篇幅愿意,本文只列举基础的get、set方法,redis支持多种数据类型,其Key是String类型,Value最常用的是String类型,当然也可以存入Object等其他类型,如果您需要存入一个引用类型,请在存入前转为Json字符串,或者调用redisTemplate存入Object(请配置好序列化,否则在get时会报无法转义)。
/**
* redis 工具类
* @Author Ltx
*
*/
@Component
public class RedisUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
// ============================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;
}
}
}
在使用SpringSecurity登录时,可将登录信息或token存入redis
//引入工具类
@Autowired
private RedisUtil redisUtil;
//设置缓存时间
public static final long CACHE_TIME = 60 * 60 * 24 * 3;
//登录成功的回调
.loginProcessingUrl("/doLogin")
.usernameParameter("userName")
.passwordParameter("passWord")
.successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
//登陆成功处理句柄,前后分离项目,给前端返回Json即可
resp.setContentType("application/json;charset=utf-8");
Map<String, Object> map = new HashMap<>();
map.put("status", HttpServletResponse.SC_OK);
User principal = (User) authentication.getPrincipal();
String token = JwtUtil.sign(principal.getUsername(), principal.getPassword());
map.put("msg", authentication.getPrincipal());
map.put("token", token);
redisUtil.set("USER_UID:" + principal.getId(), map, CACHE_TIME);
ResponseUtil.responseJson(resp, HttpStatus.OK.value(), map);
}
})
根据key去查看value即可
over~~~