文章写于2023-06-30,里面包的版本尽量都是用的当前日期下最新的,读者如果阅读的时间据此较远的话,应注意包和插件的版本.
不喜欢废话,直接放码过来.
一.引入包
需要引入的包有:reids,jedis,cache,thymeleaf,spring web,mysql,lombok
pom代码如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.1.1
com.flamelp
demo
0.0.1-SNAPSHOT
MP_Redis
MP_Redis
17
org.springframework.boot
spring-boot-starter-data-redis
redis.clients
jedis
org.springframework.boot
spring-boot-starter-cache
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
com.mysql
mysql-connector-j
runtime
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
com.baomidou
mybatis-plus-generator
3.5.3.1
com.baomidou
mybatis-plus-boot-starter
3.5.3.1
org.apache.velocity
velocity
1.7
io.springfox
springfox-swagger2
3.0.0
io.springfox
springfox-swagger-ui
3.0.0
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok
src/main/resources
mapper/*.xml
static/*.*
templates/*.html
*.yml
二.编写redis
创建一个utils包,在包下面创建一个RedisConfig来,用于管理redis缓存.代码如下.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
@Configuration
@EnableCaching//驱动缓存
public class RedisConfig extends CachingConfigurerSupport {
@Bean("redisPoolConfig")
public JedisPoolConfig poolConfig(){
JedisPoolConfig poolConfig = new JedisPoolConfig();
//最大空闲数
poolConfig.setMaxIdle(50);
//最大连接数
poolConfig.setMaxTotal(100);
//最大等待时间,毫秒
poolConfig.setMaxWaitMillis(200000);
//poolConfig.setMaxWait(Duration.ofMillis(200000));
return poolConfig;
}
@Bean("redisConnectionFactory")
public RedisConnectionFactory redisConnectionFactory(@Autowired JedisPoolConfig jedisPoolConfig){
RedisStandaloneConfiguration rsc = new RedisStandaloneConfiguration();
//设置Redis服务器
rsc.setHostName("127.0.0.1");
//设置密码
rsc.setPassword("123456");
//端口
rsc.setPort(6379);
//获得默认连接池构造器
JedisClientConfiguration.JedisClientConfigurationBuilder jpcb = JedisClientConfiguration.builder();
//设置Redis连接池
jpcb.usePooling().poolConfig(jedisPoolConfig);
//获取构建器
JedisClientConfiguration jedisClientConfiguration = jpcb.build();
//创建工厂
return new JedisConnectionFactory(rsc,jedisClientConfiguration);
}
/**
* 配置redis数据存储模板
* @param connectionFactory
* @return
*/
@Bean("redisTemplate")
public RedisTemplate redisTemplate(@Autowired RedisConnectionFactory connectionFactory){
//创建redis模板
RedisTemplate redisTemplate = new RedisTemplate<>();
//字符串和JDK序列化器
RedisSerializer strSerializer = RedisSerializer.string();
RedisSerializer
三.在spring boot项目的启动类的main方法中添加如下代码:
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
SpringApplication.run(MpRedisApplication.class, args);
}
四.修改你的application.yml文件,除了基础配置之外,主要是在执行SQL语句的时候把SQL命令打印在控制台,看看SQL语句的执行情况,或者是否有读取redis的缓存.
#server
server:
port: 8092
servlet:
context-path: /
#spring
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/XXXX
username: xxxx
password: xxxx
#mybatis-plus
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#开启缓存
cache-enabled: true
五.在你的service类的增删改查方法中加上以下标签就可以实现redis的缓存
@Cacheable,@CachePut,@CacheEvict
但是我们打算偷个懒,使用mybaits plus生成项目框架,所以还得做些其它事情.
六.mybatis plus自带的方法对redis的缓存实现不够友好,所以动手修改下几个父类,官方建议将缓存放在service层实现,所以就针对这一层下手.
mybatis plus 的service层的接口和类分别实现和继承了:IService,ServiceImpl.打算自定义父类和接口.所以有以下代码:
在utils包里创建IMyService接口,具体代码如下:
import com.baomidou.mybatisplus.extension.service.IService;
import java.io.Serializable;
public interface IMyService extends IService {
T selectById(Serializable id);
T add(T entity);
boolean delete(Serializable id);
T modify(T entity);
}
IMyService中自定义增删改查的方法,用这些方法来实现redis的缓存.请注意用上面的这几个方法实现数据的增删改查就会调用缓存,其它的不会使用缓存,如果读者需要对更多的方法实现缓存,在上面这个接口增加方法就行(当然还要最下面的这个类里面实现对应的方法.)
查询所有结果,按条件查询结果这些的结果,重复使用率不高对于缓存的意义不大,所以没有做缓存.
在utils包里在创建MyServiceImpl类,代码如下:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import java.io.Serializable;
public class MyServiceImpl, T> extends ServiceImpl {
/**
* @Cacheable:先查缓存,缓存没有对应的key值在查找数据库,找到后再进行缓存.
* value:redisCacheManager.缓存的名称,放在同一个缓存里面,通过key值进行区分方便管理.
* key:缓存在redis中时以键值对的形式存在.根据key查找缓存的值,所以不同类型的缓存不能仅仅依靠id进行区分.
* 这里用实体类名+_主键id作为key,确保key的唯一性.
* #root.target对象为调用该方法的类,获得类名后(serviceImpl类),根据命名规则去掉'ServiceImpl'后就是实体类名.
* unless = "#result==null" 当没有查询到结果时不进行缓存.
*/
@Cacheable(value="redisCacheManager"
,key ="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#id"
,unless = "#result==null")
public T selectById(Serializable id){
return this.getById(id);
}
//@CachePut会调用方法,并将方法的结果进行缓存.
@CachePut(value = "redisCacheManager"
,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#entity.id")
public T add(T entity){
this.save(entity);
return entity;
}
//@CacheEvict删除对应的缓存,再执行方法
@CacheEvict(value="redisCacheManager"
,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#id")
public boolean delete(Serializable id){
return this.removeById(id);
}
@CachePut(value = "redisCacheManager"
,key="#root.target.getClass().getSimpleName().replaceAll('ServiceImpl','_')+#entity.id")
public T modify(T entity){
this.updateById(entity);
return entity;
}
}
七.使用mybatis-plus生成项目框架
到这一步redis缓存的设置和mybatis-plus自定义父类就已经完成了.接下来编写MP的代码生成器.
还是在utils包里面创建CreateFrame类,用于生成MP代码框架.具体代码如下:
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.sql.Types;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CreateFrame {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/XXXX";
String username="root";
String password = "XXXXX";
String pkgPath = System.getProperty("user.dir")+"/src/main/java";
String pkgXml = System.getProperty("user.dir")+"/src/main/resources/mapper";
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> {//全局配置
builder.author("flamelp. 仅用于教学使用") // 设置作者
.enableSwagger() // 开启 swagger 模式
.dateType(DateType.TIME_PACK)//使用time类型转换数据库中的时间
.commentDate("yyyy-MM-dd")//注释日期
.outputDir(pkgPath); // 指定输出目录
})
.dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
int typeCode = metaInfo.getJdbcType().TYPE_CODE;
if (typeCode == Types.SMALLINT) {// 自定义类型转换
return DbColumnType.INTEGER;
}
return typeRegistry.getColumnType(metaInfo);
}))
.packageConfig(builder -> {//将包都放在启动类所在的包下面.
builder.parent("com.flamelp") // 设置父包名
.moduleName("demo") // 设置父包模块名
// .entity("entity")//entity包名
// .mapper("mapper")//dao包名
// .service("service")//service包名
// .service("service.impl")//service实体类包名
// .controller("controller")//controller包名
// .xml("mapper")//xml文件包名
.pathInfo(Collections.singletonMap(OutputFile.xml, pkgXml)); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
builder.addInclude(getTables("all")); // 设置需要生成的表名
//.addTablePrefix("t_"); // 设置过滤表前缀
//实体类配置
builder.build().entityBuilder()
.enableLombok()//设置Lombok注解
//.enableFileOverride()//覆盖已生成的文件,
.enableTableFieldAnnotation()//开启实体类字段注解
.naming(NamingStrategy.underline_to_camel)//数据库表名命名规则:下划线转驼峰
.columnNaming(NamingStrategy.no_change)//数据表字段命名规则:不处理
// .logicDeletePropertyName("deleted")//逻辑删除属性名(实体)
;//数据进行逻辑删除
//controller配置策略
builder.build().controllerBuilder();
//service配置策略
builder.build().serviceBuilder()
.superServiceClass("com.flamelp.demo.utils.IMyService")//设置服务类的父类
.superServiceImplClass("com.flamelp.demo.utils.MyServiceImpl");//设置服务实现类的父类.
//Mapper(dao)配置
builder.build().mapperBuilder()
.enableMapperAnnotation()//设置mapper注解
.enableBaseResultMap()//启用 BaseResultMap 生成resultMap
//.superClass("MPJBaseMapper")//设置mapper类的父类
//.enableFileOverride()//覆盖已生成的文件,
.enableBaseColumnList()//启用 BaseColumnList,生成列的列表
// .cache(MybatisRedisCache.class)//开启缓存.
;
})
// 使用Freemarker引擎模板,默认的是Velocity引擎模板,使用Velocity模版时,需要在pom文件中配置Velocity的引用
.templateEngine(new VelocityTemplateEngine())
.execute();
}
protected static List getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}
八.运行CreateFrame类中的main方法,
搞定,收工,写到第八点感觉自己写了个八股文似的.上面代码的注释比较全,所以没有用过多的语言描述.
另外使用mysql数据库时数据库表采用"_"下划线分隔单词是个好的方法,因为mysql的表名全部给你转小写了,但是没关系MP会给你在实体类等类的命名中给你改成驼峰命名法.但是表的列名就没有必要使用下划线了,MySQL可以识别列名大小写.