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项目

mybatis 可以 redis mybatis+redis_mybatis


选择springBoot的版本,勾选需要导入的依赖

(springBoot3的版本,不支持jdk1.8)

mybatis 可以 redis mybatis+redis_redis_02


点击create创建项目

mybatis 可以 redis mybatis+redis_mybatis_03


可以看到在pom.xml下需要的依赖已经全部自动导入,当然后续需要添加也可以手动添加依赖。

比如这里我手动引入了redis

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

mybatis 可以 redis mybatis+redis_mybatis_04


目录结构如上图。

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包,加上即可)

mybatis 可以 redis mybatis+redis_spring_05


到这里,基础的配置就完成了

接下来在主启动类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);
        }
    }
}

然后运行这个类

mybatis 可以 redis mybatis+redis_mybatis_06


就可以在控制台看到springboot的IOC中的所有注册的组件

接下来,编写entity层,这一层需要存放实体类,打开需要连接的数据,将字段转变成属性,或者直接使用我上一篇博客的utils工具转换实体类。在和时间有关的字段上,按照需求加上注解

完成后如下

mybatis 可以 redis mybatis+redis_mybatis_07


接下来,编写mapper,处理sql语句

mybatis 可以 redis mybatis+redis_spring_08


对应的,需要在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扫描到了

mybatis 可以 redis mybatis+redis_mybatis 可以 redis_09


这样当然不能映射到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
{
    
}

再次运行,就会发现可以扫描到了

mybatis 可以 redis mybatis+redis_mybatis 可以 redis_10


这样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序列化

查全

mybatis 可以 redis mybatis+redis_spring boot_11


查一

mybatis 可以 redis mybatis+redis_spring_12


增一

mybatis 可以 redis mybatis+redis_spring boot_13


mybatis 可以 redis mybatis+redis_redis_14


更新

mybatis 可以 redis mybatis+redis_mybatis_15


mybatis 可以 redis mybatis+redis_mybatis_16


删除

mybatis 可以 redis mybatis+redis_mybatis 可以 redis_17


mybatis 可以 redis mybatis+redis_redis_18


完。