前言
这一章我主要是想要稳固下之前所学到的redis、与mybatis,但是我这里并没有使用mybatis,而是使用了Mybatis Plus。
redis如果还有不了解的朋友可以参考:redis简单入门、springboot整合redis
对于mybatis plus不熟悉不了解的朋友,可以去官网看看:传送门
对于swagger不知道是什么的朋友,可以参考:springboot整合swagger
以后有可能的话,我也会简单开一篇文章来简单的说下mybatis plus。不过我个人认为,只要认真看过我这章博客,以及再去官文了解下,应该对于plus也不会有太大的问题了。不过最主要的还是对mybatis要有所了解才行。
创建项目:
新建一个项目,整体pom文件如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wujie</groupId>
<artifactId>springboot-cache-redis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-cache-redis</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<!--<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>-->
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.boot</groupId>-->
<!--<artifactId>spring-boot-starter-data-mongodb</artifactId>-->
<!--</dependency>-->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<!-- <resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>-->
<resources>
<resource>
<directory>${basedir}/src/main/java</directory>
<filtering>false</filtering>
<includes>
<include>**/mapper/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
配置application.yml
server:
port: 80
#数据库访问配置
#主数据源,默认的
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
#下面为连接池补充设置,应用到上面所有的数据源中
#初始化大小
tomcat:
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000 #设置超时时间
time-between-eviction-runs-millis: 60000 #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
min-evictable-idle-time-millis: 30000 #配置一个链接在池中的最小生存时间
validation-query: select 'X'
test-while-idle: true
test-on-borrow: false
test-on-return: false
redis:
host: localhost
port: 6379
database: 1
timeout: 5000ms
jedis:
pool:
max-active: 8
max-idle: 500
max-wait: 1ms
#mybatis:
# mapper-locations: classpath:com/wujie/springbootcacheredis/mapper/*.xml
mybatis-plus:
# 如果是放在src/main/java目录下 classpath:/com/yourpackage/*/mapper/*Mapper.xml
# 如果是放在resource目录 classpath:/mapper/*Mapper.xml
mapper-locations: classpath*:/com/wujie/*/mapper/xml/*Mapper.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.wujie.springbootcacheredis.pojo
global-config:
#主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
id-type: 3
#字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
field-strategy: 2
#驼峰下划线转换
db-column-underline: true
#mp2.3+ 全局表前缀 mp_
#table-prefix: mp_
#刷新mapper 调试神器
#refresh-mapper: true
#数据库大写下划线转换
#capital-mode: true
# Sequence序列接口实现类配置
key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
#逻辑删除配置(下面3个配置)
logic-delete-value: 1
logic-not-delete-value: 0
sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector
#自定义填充策略接口实现
# meta-object-handler: com.baomidou.springboot.MyMetaObjectHandler
configuration:
#配置返回数据库(column下划线命名&&返回java实体是驼峰命名),自动匹配无需as(没开启这个,SQL需要写as: select user_id as userId)
map-underscore-to-camel-case: true
cache-enabled: true
#配置JdbcTypeForNull, oracle数据库必须配置
jdbc-type-for-null: 'null'
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
构建一些配置类:
第一个redis的配置类,在介绍springboot整合redis的时候似乎好像给忽略了,在这里给补上
这个配置类主要是针对存入redis的时候的二进制数据利用可视化工具看不懂的问题,所以重新配置一下,换成我们自己的序列化方法,以方便我们进行查看。
package com.wujie.springbootcacheredis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.text.SimpleDateFormat;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean(name = "springSessionDefaultRedisSerializer")
public GenericJackson2JsonRedisSerializer getGenericJackson2JsonRedisSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
// 以下两种redisTemplate自由根据场景选择
/* @Bean
public RedisTemplate<Object, Object> template(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}*/
@Bean
public RedisTemplate<Object, Object> template(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule());
// objectMapper.set
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setDefaultSerializer(jackson2JsonRedisSerializer);
redisTemplate.setEnableDefaultSerializer(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/* @Bean
public RedisTemplate<String, Object> template(
RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
return redisTemplate;
}*/
@Bean
public StringRedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
stringRedisTemplate.setConnectionFactory(factory);
return stringRedisTemplate;
}
}
在这里需要特别注意的是:
objectMapper.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule());
这段代码有助于对时间的处理,不然很有可能有出现以下的异常情况,这个问题也是给我带来了不少的麻烦,在百度很久也没有找到,最后还是通过Google才得以解决。
Could not read JSON: Cannot construct instance of `java.time.LocalDateTime`
第二个配置类就是mybatis-plus
@EnableTransactionManagement
@Configuration
@MapperScan("com.wujie.*.mapper")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
没有什么特别之处,就是简单跟着官网的步骤来就可以了。
第三个配置类就是swagger了
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.wujie.springbootcacheredis.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("springboot 整合swaager2 构建api文档")
.description("springboot 学习 ,https://blog.csdn.net/u013783065")
.termsOfServiceUrl("https://blog.csdn.net/u013783065")
.version("1.0")
.build();
}
}
这里也没有任何特别之处,根据我们之前整合的步骤来就可以了。
到这里基本的配置都已经算是结束了,就到了我们书写dao,pojo,service,及时service实现类和controller的地方了,不过我使用mybatis plus最大程度就是想要使用它强大的代码生成功能了,自动帮我们生成了以上的方法,controller以及页面也可以根据我们个人需要来编写模板进行生成。
懒人配置代码如下:
public class GeneratorServiceEntity {
@Test
public void generateCode() {
String packageName = "com.wujie.springbootcacheredis";
boolean serviceNameStartWithI = false;//user -> UserService, 设置成true: user -> IUserService
generateByTables(serviceNameStartWithI, packageName, "user");
}
private void generateByTables(boolean serviceNameStartWithI, String packageName, String... tableNames) {
GlobalConfig config = new GlobalConfig();
String dbUrl = "jdbc:mysql://localhost:3306/mydb";
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL)
.setUrl(dbUrl)
.setUsername("root")
.setPassword("root")
.setDriverName("com.mysql.jdbc.Driver");
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig
.setCapitalMode(true)
.setEntityLombokModel(false)
.setDbColumnUnderline(true)
.setNaming(NamingStrategy.underline_to_camel)
.setInclude(tableNames);//修改替换成你需要的表名,多个表名传数组
config.setActiveRecord(false)
.setAuthor("wujie")
.setOutputDir("e:\\codeGen")
.setFileOverride(true);
if (!serviceNameStartWithI) {
config.setServiceName("%sService");
}
new AutoGenerator().setGlobalConfig(config)
.setDataSource(dataSourceConfig)
.setStrategy(strategyConfig)
.setPackageInfo(
new PackageConfig()
.setParent(packageName)
.setController("controller")
.setEntity("pojo")
).execute();
}
private void generateByTables(String packageName, String... tableNames) {
generateByTables(true, packageName, tableNames);
}
}
但是为了测试我们的redis我这里对于它自动给我们提供CRUD方法,我做了一点小小重写,因为我只用到了增加的方法,所以就就是仅仅对insert的方法加了redis。
dao层代码如下:
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
mapper.xml文件如下:
<?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.wujie.springbootcacheredis.mapper.UserMapper">
</mapper>
pojo代码如下:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
public User() {
}
private String id;
/**
* 姓名
*/
private String realName;
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 创建时间
*/
private LocalDateTime createTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
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;
}
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
@Override
public String toString() {
return "User{" +
", id=" + id +
", realName=" + realName +
", username=" + username +
", password=" + password +
", createTime=" + createTime +
"}";
}
}
service层代码如下:
public interface UserService extends IService<User> {
public List<?> selectUserPage(String name, Integer pageSize, Integer startPage);
List<?> selectUserAll(Integer pageSize, Integer startPage);
public boolean insertOrUpdate(User entity);
}
service实现类代码如下:
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private UserMapper userMapper;
@Resource
private RedisTemplate<String,User> template;
@Resource
private StringRedisTemplate redisTemplate;
@Override
public List<?> selectUserPage(String name, Integer pageSize, Integer startPage) {
User user1 = (User) template.opsForHash().get("user", "user:" + name);
List<User> userList = new ArrayList<User>();
// List<Object> values = template.opsForHash().values("user:" + name);
if(user1 != null){
userList.add(user1);
System.out.println("未走数据库");
return userList;
}
List<User> users = userMapper.selectPage(new Page<User>(startPage,pageSize),new EntityWrapper<User>().like("username", name));
for (User user:users
) {
template.opsForHash().put("user","user:"+name,user);
// redisTemplate.opsForHash().put("user","user:"+name,JSONObject.toJSON(user).toString());
System.out.println("存入缓存");
}
return users;
}
@Override
public List<?> selectUserAll(Integer pageSize, Integer startPage) {
List<Object> list = template.opsForHash().values("user");
if(list != null && list.size()>0){
System.out.println("未走数据库");
return list;
}
List<User> users = userMapper.selectPage(new Page<User>(startPage, pageSize), new EntityWrapper<User>());
for (User user: users
) {
template.opsForValue().set("user:"+user.getUsername(),user);
System.out.println("走数据库");
}
return users;
}
/**
* <p>
* TableId 注解存在更新记录,否插入一条记录
* </p>
*
* @param entity 实体对象
* @return boolean
*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean insertOrUpdate(User entity) {
if (null != entity) {
Class<?> cls = entity.getClass();
TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
if (StringUtils.checkValNull(idVal)) {
return insert(entity);
} else {
/*
* 更新成功直接返回,失败执行插入逻辑
*/
template.opsForHash().put("user","user:"+entity.getUsername(),entity);
// template.opsForList().leftPush("user:"+user.getUsername(),user);
return updateById(entity) || insert(entity);
}
} else {
throw new MybatisPlusException("Error: Can not execute. Could not find @TableId.");
}
}
return false;
}
}
controller层代码如下:
@RestController
@RequestMapping("/user")
@Api(value = "/user",description = "用户管理器")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation(value = "addOrUpdateUser",notes = "新增或者更新用户",httpMethod = "POST")
@RequestMapping(value = "addOrUpdateUser",method = RequestMethod.POST)
public JSONObject addOrUpdateUser(@RequestBody User user, @RequestParam String type){
JSONObject jsonObject = new JSONObject();
user.setId(UUID.randomUUID().toString());
boolean saveOrUpdate = userService.insertOrUpdate(user);
if(saveOrUpdate){
jsonObject.put("status","true");
jsonObject.put("msg","update".equals(type)?"更新成功":"新增成功");
}else{
jsonObject.put("status","false");
jsonObject.put("msg","update".equals(type)?"更新失败":"新增失败");
}
return jsonObject;
}
@ApiOperation(value = "findAll",httpMethod = "POST",notes = "查找所有数据")
@RequestMapping(value = "findAll",method = RequestMethod.POST)
public JSONObject findAll(@RequestParam Integer pageSize,@RequestParam Integer startPage){
JSONObject jsonObject = new JSONObject();
List<?> users = userService.selectUserAll(pageSize, startPage);
if(users != null && users.size() != 0){
jsonObject.put("status","true");
jsonObject.put("data",users);
}else{
jsonObject.put("status","false");
jsonObject.put("msg","暂无数据");
}
return jsonObject;
}
@ApiOperation(value = "findByName",notes = "根据名字进行查找分页",httpMethod = "POST")
@RequestMapping(value = "findByName",method = RequestMethod.POST)
public JSONObject findByName(@RequestParam String name,@RequestParam Integer pageSize,@RequestParam Integer startPage){
JSONObject jsonObject = new JSONObject();
List<?> users = userService.selectUserPage(name, pageSize, startPage);
if(users != null && users.size() != 0){
jsonObject.put("status","true");
jsonObject.put("data",users);
}else{
jsonObject.put("status","false");
jsonObject.put("msg","暂无数据");
}
return jsonObject;
}
}
总结:
到此所有的代码基本上也就算是书写完成了,对于redis的分页以及模糊查询,条件查询等等,我目前还是比较头疼,一直没有思路,思考了两天也没有结果,所以就暂时没有在继续考虑了,等有时间了在来去深入学习redis的使用,可是我个人又想了想,其实redis是一个挡在数据库前的一个缓存层,这个里面放的是一些经常查询的东西,而不是什么东西都会往redis里去缓存。也米有必要这么纠结,所以在今天也才将这篇文章写完。
欢迎关注我的公众号一起学习: