zoukankan      html  css  js  c++  java
  • 我的spring-boot-study之mybatis的应用

    我的spring-boot-study之mybatis的应用

    1. 环境:spring-boot 2.2.6.RELEASE,java 1.8

    2. 首先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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.zhoushiya</groupId>
        <artifactId>spring-boot-study</artifactId>
        <version>0.0.1</version>
        <name>spring-boot-study</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- mysql驱动配置 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
            <!-- mysql驱动配置结束 -->
    
            <!-- mybatis配置 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.2</version>
            </dependency>
            <!-- mybatis配置结束 -->
    
            <!-- lombok配置 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <!-- lombok配置结束 -->
    
            <!-- dozermapper配置-->
            <dependency>
                <groupId>com.github.dozermapper</groupId>
                <artifactId>dozer-spring-boot-starter</artifactId>
                <version>6.2.0</version>
            </dependency>
            <!-- dozermapper配置结束-->
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <!--swagger配置-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.6.1</version>
            </dependency>
    
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>2.6.1</version>
            </dependency>
    
            <dependency>
                <groupId>io.github.swagger2markup</groupId>
                <artifactId>swagger2markup</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-core</artifactId>
                <version>1.5.16</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
                <version>1.5.16</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
            <!-- swagger配置结束 -->
    
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    3. 编写代码

    3.1 先按照下图结构将目录创建好


    说明:

    • config 中有一些功能的配置类
    • testdb 就是你的数据库名称,以后有多个数据库可以加多个,例如testdb2什么的
      controller 你的api控制器包
      entity 实体类包
      mapper mybatis的mapper类包
      service 服务层
      vo 展示类包
    • utils 通用功能包
    • resource
      mapper.testdb mybatis的mapper.xml文件所在文件夹

    3.2 添加代码文件

    3.2.1 添加entity.Article.java实体

    package com.zhoushiya.springbootstudy.testdb.entity;
    
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import lombok.experimental.Accessors;
    
    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * <p>
     * Article实体类
     * </p>
     *
     * @author zhoushiya
     * @since 2020-04-30
     */
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    public class Article implements Serializable {
    
        private Long id;
    
        private String author;
    
        private String content;
    
        private Date createTime;
    
        private String title;
    
    
    }
    

    注:@Data是Lombok的注解,可以检查类的编写过程,编译后自动加上set,get等方法,你可以在target中的对应文件中找到,代码如下

    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.zhoushiya.springbootstudy.testdb.entity;
    
    import java.io.Serializable;
    import java.util.Date;
    
    public class Article implements Serializable {
        private Long id;
        private String author;
        private String content;
        private Date createTime;
        private String title;
    
        public Article() {
        }
    
        public Long getId() {
            return this.id;
        }
    
        public String getAuthor() {
            return this.author;
        }
    
        public String getContent() {
            return this.content;
        }
    
        public Date getCreateTime() {
            return this.createTime;
        }
    
        public String getTitle() {
            return this.title;
        }
    
        public Article setId(final Long id) {
            this.id = id;
            return this;
        }
    
        public Article setAuthor(final String author) {
            this.author = author;
            return this;
        }
    
        public Article setContent(final String content) {
            this.content = content;
            return this;
        }
    
        public Article setCreateTime(final Date createTime) {
            this.createTime = createTime;
            return this;
        }
    
        public Article setTitle(final String title) {
            this.title = title;
            return this;
        }
    ........后面省略
    

    3.2.2 添加mapper.ArticleMapper文件

    package com.zhoushiya.springbootstudy.testdb.mapper;
    
    import com.zhoushiya.springbootstudy.testdb.entity.Article;
    
    import java.util.List;
    
    /**
     * <p>
     *  Mapper 接口
     * </p>
     *
     * @author zhoushiya
     * @since 2020-04-30
     */
    public interface ArticleMapper {
        int insert(Article article);
    
        Article getById(long id);
    
        List<Article> getAll();
    }
    

    注:mapper类,其实是一个接口,我觉得应该叫IxxService更合适。mapper类作用是与mapper.xml形成映射关系,为mybatis提供查询接口。直接与数据库交互。不需要实现,mybatis会在程序开启后自动实现,自动注入。

    3.2.3 为mybatis指定mapper接口的路径

    刚才说到mybatis会自动实现mapper接口,但是要提前配置好mapper接口的包路径。现在一般的做法是在Application上加@MapperScan注解。

    package com.zhoushiya.springbootstudy;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.zhoushiya.springbootstudy.testdb.mapper")
    public class SpringBootStudyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringBootStudyApplication.class, args);
        }
    
    }
    

    注:@MapperScan后面是你的mapper的包路径,可以加多个,例如:

    @MapperScan({"a.mapper","b.mapper"})
    

    注:如果配置的包不对,会在调用ArticleMapper自动的地方报错,大意是找不到ArticleMapper的实现,所以这里一定要仔细
    也可以采取另一种方式,直接在mapper接口上加@Mapper注解

    @Mapper
    public interface ArticleMapper {
    }
    

    这种方式太过零散不便于维护,现在一般不用了

    3.2.4 加上mapper.xml文件

    mapper.xml文件与mapper接口对应,相当于mapper接口的实现类,后面由mybatis读取调用。resource/mapper/testdb下加入ArticleMapper.xml

    <?xml version="1.0" encoding="UTF8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--绑定一个对应的Dao/Mapper接口-->
    <mapper namespace="com.zhoushiya.springbootstudy.testdb.mapper.ArticleMapper">
        <select id="getAll" resultType="com.zhoushiya.springbootstudy.testdb.entity.Article">
            SELECT * FROM testdb.article
        </select>
        <select id="getById" parameterType="long" resultType="com.zhoushiya.springbootstudy.testdb.entity.Article">
            SELECT * FROM testdb.article where id=#{id}
        </select>
        <insert id="insert" parameterType="com.zhoushiya.springbootstudy.testdb.entity.Article">
            insert into testdb.article(id,title,author,create_time) values (#{id},#{title},#{author},#{createTime})
        </insert>
    </mapper>
    

    注:mapper的详细写法这里不重复,可以去官方文档查看。这里说几个重要的部分:

    • mapper namespace必须和你要映射的mapper接口严格一致
    • id 必须和mapper接口的方法严格一致
    • resultType 必须和mapper接口方法返回值严格一致,如果返回是集合,只需要写集合内部类型即可
    • parameterType 必须和mapper接口方法参数严格一致
    • sql语句中#{xx},即代表参数中的实体的xx属性值
      这些地方如果出现问题,都不会在编译的时候出错,运行会出错,所以一定要仔细配置。

    3.2.5 定义mybatis对mapper.xml文件的扫描路径

    上面讲了mapper.xml文件的写法,mybatis对于mapper.xml文件扫描是有自动配置的,例如mapper接口在com.zhoushiya.springbootstudy.testdb.mapper下,那么同样目录下的xml文件是会自动扫描到的。但是本教程中的xml文件并不是和mapper接口在同一文件夹下,需要手动配置。application.yml中配置:

    mybatis:
      mapper-locations: classpath:mapper/testdb/*.xml
    

    注:因为编译后resources/mapper/testdb自动到了classes/mapper/testdb下,所以这里这样配置。多个路径配置,中间加入逗号即可

    mybatis:
      mapper-locations: classpath:mapper/testdb/*.xml,classpath:mapper/testdb2/*.xml
    

    3.2.6 加上vo,展示类

    vo目录下加上ArticleVO,后面会交给controller层使用

    package com.zhoushiya.springbootstudy.testdb.vo;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.Date;
    
    /**
     * Article展示类
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @JsonPropertyOrder(value={"content","title"})
    public class ArticleVO {
    
        @JsonIgnore
        private Long id;
    
        private String author;
    
        private String title;
        private String content;
    
        private Date createTime;
    }
    

    3.2.7 加上工具类DozerUtils

    package com.zhoushiya.springbootstudy.utils;
    
    import com.google.common.collect.Lists;
    import org.dozer.DozerBeanMapperBuilder;
    import org.dozer.Mapper;
    
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.List;
    
    public class DozerUtils {
    
        static Mapper mapper = DozerBeanMapperBuilder.buildDefault();
    
        public static <T> List<T> mapList(Collection sourceList, Class<T> destinationClass){
            List destinationList = Lists.newArrayList();
            for (Iterator i$ = sourceList.iterator(); i$.hasNext();){
                Object sourceObject = i$.next();
                Object destinationObject = mapper.map(sourceObject, destinationClass);
                destinationList.add(destinationObject);
            }
            return destinationList;
        }
    }
    

    这个类的作用是,让List<A>通过DozerMapper自动转换到List<B>,后面会用到。

    3.2.8 加上service.IArticleService,接口层

    package com.zhoushiya.springbootstudy.testdb.service;
    
    import com.zhoushiya.springbootstudy.testdb.vo.ArticleVO;
    
    import java.util.List;
    
    /**
     * <p>
     *  服务类
     * </p>
     *
     * @author zhoushiya
     * @since 2020-04-30
     */
    public interface IArticleService{
        /**
         * 更新或者插入数据
         * @param articleVO
         * @return
         */
        ArticleVO insert(ArticleVO articleVO);
    
        ArticleVO getById(long id);
    
        List<ArticleVO> getAll();
    }
    

    3.2.9 加上IArticleService实现类service.impl.ArticleServiceImpl

    package com.zhoushiya.springbootstudy.testdb.service.impl;
    
    import com.zhoushiya.springbootstudy.testdb.entity.Article;
    import com.zhoushiya.springbootstudy.testdb.mapper.ArticleMapper;
    import com.zhoushiya.springbootstudy.testdb.service.IArticleService;
    import com.zhoushiya.springbootstudy.testdb.vo.ArticleVO;
    import com.zhoushiya.springbootstudy.utils.DozerUtils;
    import org.dozer.Mapper;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    /**
     * <p>
     *  服务实现类,使用@Service(value = "articleService")让其作为IArticleService注入的默认类
     * </p>
     *
     * @author zhoushiya
     * @since 2020-04-30
     */
    @Service(value = "articleService")
    public class ArticleServiceImpl implements IArticleService {
    
        @Resource
        ArticleMapper articleMapper;
    
        @Resource
        private Mapper mapper;
    
        public ArticleVO insert(ArticleVO articleVO) {
            Article article= mapper.map(articleVO,Article.class);
            articleMapper.insert(article);
            return articleVO;
        }
    
        @Override
        public ArticleVO getById(long id) {
            Article article = articleMapper.getById(id);
            ArticleVO articleVO= mapper.map(article,ArticleVO.class);
            return articleVO;
        }
    
        @Override
        public List<ArticleVO> getAll() {
            List<Article> articles = articleMapper.getAll();
            List<ArticleVO> articleVOS= DozerUtils.mapList(articles,ArticleVO.class);
            return articleVOS;
        }
    }
    

    注:此处@Service(value = "articleService")不可省略,即当使用IArticleService自动注入的时候,默认使用这个实现类。如果此处省略了,那么需要在注入使用的地方需要指定实现类的名称,如:@Resource(name="articleServiceImpl")。下面会讲到。

    3.2.10 加上config.Swagger2.java文件

    package com.zhoushiya.springbootstudy.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    @Configuration
    @EnableSwagger2
    public class Swagger2 {
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title("springboot利用swagger构建api文档")
                    .description("简单优雅的restfun风格")
                    .termsOfServiceUrl("https://www.cnblogs.com/zhoushiya")
                    .version("1.0")
                    .build();
        }
    
        @Bean
        public Docket createRestApi() {
            return new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo())
                    .select()
                    //扫描basePackage包下面的“/rest/”路径下的内容作为接口文档构建的目标
                    .apis(RequestHandlerSelectors.basePackage("com.zhoushiya.springbootstudy"))
                    .paths(PathSelectors.regex("/rest/.*"))
                    .build();
        }
    
    
    }
    

    就是配置swagger2,让后面程序启动后可以通过swagger-ui来访问。
    注:createRestApi方法中,swagger要扫描的包,paths中是要扫描的接口的路径。例如:com.zhoushiya.springbootstudy.ArticleController下有个方法getAll,其访问路径是localhost/rest/article,那么会被扫描出来并展示到swagger-ui网页中。反之,不是com.zhoushiya.springbootstudy包中,或者不符合 localhost/rest/ 路径的接口都不会出现。

    3.2.11 加上controller.ArticleController.java文件

    接口控制器,为前端提供访问

    package com.zhoushiya.springbootstudy.testdb.controller;
    
    import com.zhoushiya.springbootstudy.testdb.service.IArticleService;
    import com.zhoushiya.springbootstudy.testdb.vo.ArticleVO;
    import io.swagger.annotations.ApiOperation;
    import io.swagger.annotations.ApiResponse;
    import io.swagger.annotations.ApiResponses;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @Slf4j
    @RestController
    @RequestMapping("/rest")
    public class ArticleController {
    
        @Resource
        IArticleService articleService;
    
        /**
         * 增加一篇文章
         *
         * @param article
         * @return
         */
        @ApiOperation(value = "添加文章", notes = "添加新文章", httpMethod = "POST")
        @ApiResponses({
                @ApiResponse(code = 200, message = "成功", response = ArticleVO.class),
                @ApiResponse(code = 400, message = "用户输入错误", response = ArticleVO.class),
                @ApiResponse(code = 500, message = "系统内部错误", response = ArticleVO.class),
        })
        // @RequestMapping(value = "/article", method = RequestMethod.POST, produces = "application/json")
        @PostMapping("/article")
        public ArticleVO insertArticle(@RequestBody ArticleVO article) {
            articleService.insert(article);
            return article;
        }
    
        /**
         * 获取一篇Article,使用GET方法
         */
        // @RequestMapping(value = "/article/{id}", method = GET, produces = "application/json")
        @GetMapping("/article/{id}")
        public ArticleVO getById(@PathVariable Long id) {
            ArticleVO articleVO = articleService.getById(id);
            return articleVO;
        }
    
        @GetMapping("/article")
        public List<ArticleVO> getAll() {
            return articleService.getAll();
        }
    }
    

    注:

    • @RequestMapping注解,这里表示整个控制器接口路径都在/rest下面,方便swagger去查找
    • @Resource注解此处没有加name="",因为按照3.2.9此处默认会去找ArticleServiceImpl实现类。如果你在上面@Service省略了value="",那么这里就要加上name="articleServiceImpl"。如果两个地方都省略了,那么程序会报错,大意是注入的实现发现了两个,程序不知道用哪一个。
    • @Apixxx等注解都是Swagger提供的,目的在于前端界面展示详细的说明
    • @PostMapping,@GetMapping等都是@RequestMapping的简便写法,对应其中method=Post,Get等

    3.2.12 加上单测:test/java/com/zhoushiya/springbootstudy/ArticleTest.java

    package com.zhoushiya.springbootstudy;
    
    import com.zhoushiya.springbootstudy.testdb.service.IArticleService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class ArticleTest {
        @Resource
        IArticleService articleService;
    
        @Test
        public void getAll(){
            articleService.getAll().forEach(System.out::println);
        }
    }
    

    3.2.13 配置连接字符串

    spring:
      datasource:
        # mysql 6 以上为com.mysql.cj.jdbc.Driver
        # mysql 6 以下为com.mysql.jdbc.driver
        driver-class-name: com.mysql.cj.jdbc.Driver
        # mysql 8 要加上serverTimezone=Asia/Shanghai
        # 如果连接出现Public Key Retrieval is not allowed错误,还要加上allowPublicKeyRetrieval=true
        url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
        username: root
        password: welcome
    

    3.2.14 去数据库创建article表

    CREATE TABLE `article` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `author` varchar(32) NOT NULL,
      `content` varchar(512) DEFAULT NULL,
      `create_time` datetime DEFAULT NULL,
      `title` varchar(32) NOT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `UK_571gx7oqo5xpmgocegaidlcu9` (`title`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    

    3.2.15 随便在article表中添加一些数据

    4.测试

    • 运行ArticleTest.getAll(),如果打印除了结果就表示配置成功了
    • 另外访问/swagger-ui.html页面也可以看到当前的接口。

      然后可以执行getAll方法得到结果
  • 相关阅读:
    git的使用
    对大学学习的一些看法
    远程连接mysql失败情况总结
    缓存穿透、缓存击穿、缓存雪崩
    Hello Redis
    Celery的简单使用
    git操作
    码云、github同时配置ssh key,解决冲突问题
    阿里云短信验证码服务
    Vue中img标签的src属性绑定的坑
  • 原文地址:https://www.cnblogs.com/zhoushiya/p/12863067.html
Copyright © 2011-2022 走看看