SpringBoot+mybatis+redis的简单使用
1.SpringBoot是什么
Spring Boot是由Pivotal团队提供的一套开源框架,可以简化spring应用的创建及部署。它提供了丰富的Spring模块化支持,可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能,降低了复杂性,同时支持基于JVM的多种开源框架,可以缩短开发时间,使开发更加简单和高效。(摘自SpringBoot官方文档)
个人理解,SpringBoot就是Spring的各种技术的整合,是一个简化了配置的Spring应用框架,可以简单完整的解决java的J2EE开发流程。有如下特点:
1.创建独立的Spring应用程序
2.直接内置了Tomcat,Jetty等,无需部署war包
3.尽可能自动配置Spring
4.无代码生成,也不需要XML配置
2.SpringBoot项目的简单创建
在idea中,建立springBoot项目
选择springBoot的版本,勾选需要导入的依赖
(springBoot3的版本,不支持jdk1.8)
点击create创建项目
可以看到在pom.xml下需要的依赖已经全部自动导入,当然后续需要添加也可以手动添加依赖。
比如这里我手动引入了redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
目录结构如上图。
3springBoot + Mybatis + Redis的简单使用
SpringBoot虽然简化了Spring、SpringMVC等复杂的配置文件,但是其本身也还是需要一个简单的配置的,在resources目录下的application.properties就是springBoot的核心配置文件。springBoot的配置支持2种,properties和yml,两者没有本质上的区别,只是书写风格的不同。这里我使用yml。
先将application.properties重命名为application.yml,然后就可以编写配置了。
# 配置启用的配置文件
spring:
profiles:
active: dev
个人习惯使用分使用情况来配置文件,也可以不需要这步,直接配置
application-dev.yml的配置
server:
# 修改端口
port: 80
servlet:
# 应用上下文路径
context-path: /
# 日志配置
logging:
level:
com.springtest: debug
# springMVC静态资源的配置
spring:
mvc:
static-path-pattern: /static/**
# 数据源配置,这里连接的是mysql
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&&userSSL=false
username: root
password: 123456
# mapper映射
mybatis:
mapper-locations: classpath:/mappers/*.xml
type-aliases-package: com.springtest.entity
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
配置完发现配置了一些不存在的包?下面就来建立这些包
在resources下建立mappers包,将来存放mapper映射的xml文件,用来处理sql
(Mybatis)
在主启动类TestSpringBootDemoApplication的包内,建立如下几个包:
entity 将来存放实体类
service 将来存放service层,及业务操作
controller 将来存放控制器,请求主要访问他
config 将来存放一些自定义的配置,比如dao扫描
utils 将来存放一些自己需要使用的工具类或者常量接口
mapper 将来存放sql的dao的接口
建立完成后,目录如下(这里好像漏了一个mapper包,加上即可)
到这里,基础的配置就完成了
接下来在主启动类TestSpringBootDemoApplication中这样编写(自行导包)
public class TestSpringBootDemoApplication {
public static void main(String[] args)
{
ConfigurableApplicationContext run = SpringApplication.run(TestSpringBootDemoApplication.class, args);
//启动springboot的时候拿到返回值
String[] beanDefinitionNames = run.getBeanDefinitionNames();
//获取所有的组件,返回一个数组
for (String beanDefinitionName : beanDefinitionNames)
{
//遍历他,并打印到控制台
System.out.println(beanDefinitionName);
}
}
}
然后运行这个类
就可以在控制台看到springboot的IOC中的所有注册的组件
接下来,编写entity层,这一层需要存放实体类,打开需要连接的数据,将字段转变成属性,或者直接使用我上一篇博客的utils工具转换实体类。在和时间有关的字段上,按照需求加上注解
完成后如下
接下来,编写mapper,处理sql语句
对应的,需要在mappers里加入xml映射文件编写sql
<?xml version="1.0" encoding="UTF-8" ?>
<!--映射map文件,实现接口方法-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--全路径 包名类名-->
<mapper namespace="com.springtest.mapper.TbBookMapper">
<!--简单的映射-->
<resultMap id="BookMap" type="com.springtest.entity.TbBook">
<id property="id" column="id"/>
<result property="bookName" column="bookname"/>
<result property="author" column="author"/>
<result property="price" column="price"/>
<result property="address" column="address"/>
<result property="publishDate" column="publishdate"/>
</resultMap>
<insert id="addOneBook" useGeneratedKeys="true" keyProperty="id">
insert into test.tb_book (bookname, author, price, address, publishdate)
values (#{bookName},#{author},#{price},#{address},#{publishDate})
</insert>
<update id="updateOneBook" parameterType="com.springtest.entity.TbBook">
update test.tb_book
<set>
<if test="bookName!=null">
bookname = #{bookName},
</if>
<if test="author!=null">
author = #{author},
</if>
<if test="price!=null">
price = #{price},
</if>
<if test="address!=null">
address = #{address},
</if>
<if test="publishDate!=null">
publishdate = #{publishDate},
</if>
</set>
where id = #{id}
</update>
<delete id="deleteOneBookById">
delete from test.tb_book where id = #{id}
</delete>
<select id="findAll" resultMap="BookMap">
select * from test.tb_book
</select>
<select id="findOneBookById" resultType="com.springtest.entity.TbBook">
select * from test.tb_book where id = #{id};
</select>
</mapper>
完成后运行一下,这时发现,刚刚编写的mapper的dao接口并没有被注册
只有这个xml被MapperScannerConfigurer扫描到了
这样当然不能映射到sql,因此,需要自己配置一个扫描dao的类
在config下,创建一个MyMapperConfig类,然后加入如下注解
package com.springtest.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan(value = "com.springtest.mapper")
public class MyMapperConfig
{
}
再次运行,就会发现可以扫描到了
这样dao层就配置完成了
接下来,编写service层接口
package com.springtest.service;
import com.springtest.entity.TbBook;
import java.util.List;
import java.util.Map;
public interface TbBookService
{
List<TbBook> findAll();
//查询一个
TbBook findOneBookById(Integer id);
//增加
TbBook addOneBook(TbBook book);
//修改
TbBook updateOneBook(TbBook book);
//删除(这样编写便于向前端传递信息,在上面的增加和修改如果不需要缓存也可以这样返回)
Map<String ,Object> deleteOneBookById(Integer id);
}
在service包下创建一个impl包存放实现类,编写一个实现类实现上面的接口
package com.springtest.service.impl;
import com.springtest.entity.TbBook;
import com.springtest.mapper.TbBookMapper;
import com.springtest.service.TbBookService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author: Otomi
* @Contact: xxx@xxx.com
* @Date: 2023/6/6 23:02
* @Version: 1.0
* @Description:
*/
@Service//注入service
@Transactional//添加事务
public class TbBookServiceImpl implements TbBookService
{
@Resource//自动注入
private TbBookMapper tbBookMapper;
@Cacheable(value = "books")//将结果缓存到redis
@Override
public List<TbBook> findAll() {
return tbBookMapper.findAll();
}
@Cacheable(value = "book",key = "#id",unless = "#result eq null")//unless:结果为空不保存
@Override
public TbBook findOneBookById(Integer id) {
return tbBookMapper.findOneBookById(id);
}
@CachePut(value = "book",key = "#result.id",unless = "#result eq null")
//注意在添加的时候,没有传入id,所以需要在mapperXml中自动映射,具体见xml中的增加语句
@Override
public TbBook addOneBook(TbBook book) {
tbBookMapper.addOneBook(book);
return book;
}
@CachePut(value = "book",key = "#result.id",unless = "#result eq null")
@Override
public TbBook updateOneBook(TbBook book) {
tbBookMapper.updateOneBook(book);
//注意,更新语句使用的是动态sql,所以可能会传入null,但是存入redis的时候不能存入这个数据(指null),因此我们需要再执行一次查询
return findOneBookById(book.getId());
}
@CacheEvict(value = "book",key = "#id")
@Override
public Map<String, Object> deleteOneBookById(Integer id)
{
Map<String,Object> map = new HashMap<>();
//执行完sql后,需要根据返回值来判断是否执行成功(这个方法可以封装)
Integer result = tbBookMapper.deleteOneBookById(id);
if(result > 0)
{
map.put("status",200);
map.put("msg","删除成功");
}
else
{
map.put("status",400);
map.put("msg","删除失败");
}
return map;
}
}
此时,存入redis的值的编码是不能阅读的,需要自定义一个config来设置redis
在config下新建一个类
package com.springtest.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
// key序列化方式
template.setKeySerializer(redisSerializer);
// value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
// value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config =
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
这个类不需要修改,直接使用即可,或者自行修改,这里不多做介绍
接下来,编写controller层
package com.springtest.controller;
import com.springtest.entity.TbBook;
import com.springtest.service.TbBookService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @Author: Otomi
* @Contact: xxx@xxx.com
* @Date: 2023/6/6 23:29
* @Version: 1.0
* @Description:
*/
@RestController
@RequestMapping(value = "/test")
public class TbBookController
{
@Resource
private TbBookService tbBookService;
@GetMapping
public List<TbBook> findAll()
{
return tbBookService.findAll();
}
@GetMapping("/{id}")//restful风格
public TbBook findOneBookById(@PathVariable("id") Integer id)
{
return tbBookService.findOneBookById(id);
}
@PutMapping
public TbBook addOneBook(@RequestBody TbBook book)//传入json
{
return tbBookService.addOneBook(book);
}
@PostMapping
public TbBook updateOneBook(@RequestBody TbBook book)
{
return tbBookService.updateOneBook(book);
}
@DeleteMapping("/{id}")
public Map<String ,Object> deleteBookById(@PathVariable("id") Integer id)
{
return tbBookService.deleteOneBookById(id);
}
}
至此,SpringBoot+mybatis+redis已经基本编写完成
下面可以使用接口测试工具测试或者直接使用浏览器测试(浏览器测试请求不能发送post等,需要修改这个controller)
4测试
如果测试报错,可以试试将entity序列化
查全
查一
增一
更新
删除
完。