SpringBoot2.1版本的个人应用开发框架 - 集成Druid + MybatisPlus

6,151 阅读10分钟

本篇作为SpringBoot2.1版本的个人开发框架 子章节,请先阅读SpringBoot2.1版本的个人开发框架再次阅读本篇文章

后端项目地址:SpringBoot2.1版本的个人应用开发框架

前端项目地址:ywh-vue-admin

创建core子模块的项目结构

我们先对core模块进行规划,core模块主要用来编写业务代码,能把一些公用的方法或者类最好都提出去放到common模块下,修改以上文件后,我们对core模块中创建我们写代码以及配置的一些package在core模块下com,ywh.core右键点击 New->package创建包名,这里以我自己的习惯来创建的,可以按照自己的习惯来命名。

core是项目的核心模块,结构初步规划如下:

  • config —— 放一些配置文件
  • controller —— controller层的控制器放在这个包下
  • dao —— 对数据库的一些操作接口放到这里
  • entity —— 业务对象的实体类
  • service —— service层的接口与实现类,Impl里放service的实现类
  • system —— 可以放一些core单独使用的系统类
  • mybatis-mappers —— 放Mybatis的xml文件,这个文件在resource下创建

core模块结构

Druid介绍

创建数据库连接是一个很耗时的操作,也很容易对数据库造成安全隐患。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响程序的性能指标。

Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQLParser。Druid支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQLServer、H2等等。 Druid针对Oracle和MySql做了特别优化,比如Oracle的PSCache内存占用优化,MySql的ping检测优化。Druid在监控、可扩展性、稳定性和性能方面都有明显的优势。Druid提供了Filter-Chain模式的扩展API,可以自己编写Filter拦截JDBC中的任何方法,可以在上面做任何事情,比如说性能监控、SQL审计、用户名密码加密、日志等等。

参考:

项目中配置Druid

我选择用mysql数据库,在配置Druid之前先要引入mysql的依赖以及Druid的依赖,在父pom.xml文件中引入依赖 ,然后配置coreapplication-dev.yml文件,yml文件中大多数是默认配置并且我写了注释很好理解,如果想自定义配置可以参考Druid的GitHub官方文档。这里添加JDBC的依赖是因为要连接数库,需要驱动来进行连接,后面添加了MyBatisPlus后就可以去掉了。

<!-- druid连接池的依赖 -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.10</version>
</dependency>
 
<!-- mysql驱动依赖  不加版本号会获取最新的 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.13</version>
</dependency>
 
<!-- jdbc驱动依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

application-dev.yml文件内容,以下内容有省略,具体内容可查看 application-dev.yml

#在这里我没有写driver-class-name: com.mysql.jdbc.Driver这个驱动被弃用了  使用新版com.mysql.cj.jdbc.Driver  
#控制台提示说自动帮我们找相应的驱动,一般无需手动加载,所以我注释掉了
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    # 初始化Druid
    druid:
      # mysql数据库接地址
      url: jdbc:mysql://127.0.0.1:3306/ywh_code?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
      #driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: 123456
      # 监控页面的用户名和密码 以及页面地址
      stat-view-servlet:
        login-username: admin
        login-password: admin
        enabled: true
        url-pattern: /druid/*

配置好Durid后,我们就可以访问 http://localhost:8082/core/druid/login.html 了。我的端口号是8082,因为我在application.yml配置了context-path: /core,所以我的访问地址是上面的地址,如果没有配置的话,默认就是 http://localhost:8080/druid/login.html ,登录账户和密码都是admin,监控界面我就不贴了。

集成Mybatis-Plus

配置好Druid以后,就能连接数据库了,如果使用原生的jdbc连接数据库也可以,但是这样就太麻烦了,所以我采用了Myatis的增强版Mybatis-Plus,Mybatis-Plus对Mybatis只做增强不做修改,所以完美兼容了Mybatis,而且也支持自动生成代码给你,以及给用户支持了大量的CRUD的接口,也有很多的优秀案例采用了Mybaits-Plus。

项目中配置Mybatis-Plus

首先在父pom.xml中引入Mybatis-Plus的相关依赖,配置core下application-dev.yml文件,在根据官网中所要求的在启动类中添加@MapperScan(basePackages = "com.ywh.**.dao")来扫描你dao包下所有接口自动注入到Spring的IOC容器中,以便我们使用;依赖分别为:mybatis-plus-boot-starter,freemarker,velocity,后两个为生成代码的时候以哪个为模板,后面会用到,这两个可自行上网搜索查看简介。

<!-- mybatisPlus的依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.6</version>
</dependency>
<!-- freemarke引擎依赖引入 -->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.28</version>
</dependency>
 
<!-- velocity引擎依赖引入 -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.7</version>
</dependency>

application-dev.yml

mybatis-plus:
  mapper-locations: classpath*:/mybatis-mappers/*
  # MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名
  type-aliases-package: com.ywh.core.entity
  # 数据库表与实体类的驼峰命名自动转换
  configuration:
    map-underscore-to-camel-case: true
@SpringBootApplication(scanBasePackages = "com.ywh")
/**
 * 全局配置,扫描指定包下的dao接口,不用每个dao接口上都写@Mapper注解了
 */
@MapperScan(basePackages = "com.ywh.**.dao")
public class CoreApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(CoreApplication.class, args);
	}
}

测试用例

配置好以后我们来测试一下是否可以对数据库进行操作了,数据库ywh_code中创建一个user表并且插入几条数据供我们查询。

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
  `age` tinyint(3) unsigned NOT NULL COMMENT '用户年龄',
  `gender` tinyint(3) unsigned NOT NULL COMMENT '用户性别',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
 
INSERT INTO `user` VALUES ('1', 'ywh', '22', '1');
INSERT INTO `user` VALUES ('2', 'lry', '22', '1');
INSERT INTO `user` VALUES ('3', 'whp', '26', '0');

在我们之前创建的Entity实体包中的ExampleEntity实体类中编写对应数据库的属性,dao层的ExampleDao接口类中写个查询方法,并在springboot的测试类中测试一下我们的配置是否好使,实体类中的属性要有自己的get,set方法,我使用Lombok的注解方式帮我们自动生产get,set方法。首先在父pom.xml引入lombok的依赖包,并在idea中安装lombok的插件,如果认为这种方式太麻烦,可以直接自己生成get,set方法。

<!-- lombok的依赖 -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.4</version>
  <scope>provided</scope>
</dependency>

在idea中选择File->Settings->Plugins中搜索lombok Plugin插件并安装,如果有连接超时的错误,下载不了的话,可以点击IDEA中lombok插件下载下载到本地后,本地安装此插件。

实体类

import lombok.Data;
 
/**
 * CreateTime: 2018-12-09 18:24
 * ClassName: ExampleEntity
 * Package: com.ywh.core.entity
 * Describe:
 * 测试实体类
 *
 * @author YWH
 */
@Data
public class ExampleEntity {
 
    private Integer id;
 
    private String name;
 
    private String age;
 
    private String gender;
 
}

dao接口

import com.ywh.core.entity.ExampleEntity;
import org.apache.ibatis.annotations.Select;
 
import java.util.List;
 
/**
 * CreateTime: 2018-12-09 18:25
 * ClassName: ExampleDao
 * Package: com.ywh.core.dao
 * Describe:
 * 测试例子的Dao层  持久层
 *
 * @author YWH
 */
public interface ExampleDao {
 
    @Select("select * from user")
    List<ExampleEntity> findAll();
 
}

SpringBoot测试类

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class CoreApplicationTests {
 
    @Autowired
    private ExampleDao exampleDao;
 
    @Test
    public void contextLoads() {
        List<ExampleEntity> all = exampleDao.findAll();
        System.out.println(all);
    }
 
}

运行测试方法后,输出结果为:

[ExampleEntity(id=1, name=ywh, age=22, gender=1), ExampleEntity(id=2, name=lry, age=22, gender=1), ExampleEntity(id=3, name=whp, age=26, gender=0)]

MybatisPlus代码生成器

集成了MybatisPlus,关于MybatisPlus的核心功能中的代码生成器可以帮我们大大提升工作效率,不用创建很多的重复工作,AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率,这个代码生成的也不过是我们提前定好的通用的方法,具体的业务代码还是要我们自己来写的,不过在很大程度上帮助了我们很多。

这个功能我是放到了common模块下的,所以我们要对common子模块分一下结构。

  • base:放基础的controller、service等
  • config:放一些配置类
  • entity:放一些基础的实体类
  • mapper:可以放基础的mapper.xml文件
  • exception:可以放我们自定义的异常类
  • utils:放一些公用的工具类
  • resources目录下创建templates放我们后面用到的模板文件。

20190411144717

创建好目录结构以后,我们创建一个myBatisPlus.properties文件来存放我们常常要改变的变量,这样就不用去代码中去更改了,内容如下:

#此处为本项目src所在路径(代码生成器输出路径)
outputDir=/ywh-starter-core/src/main/java
#父的包名
setParent=com.ywh.core
#是否覆盖文件   默认是false    如果生成的代码有改动的话  在没有确认之前不要改成true  否则会把文件覆盖  丢失代码
fileOverride=false
#数据库地址
url=jdbc:mysql://127.0.0.1:3306/ywh_code?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8
#数据库驱动
driverClass=com.mysql.cj.jdbc.Driver
#数据库用户名
userName=root
#数据库密码
passWord=123456
# mapper.xml文件生成路径
mapperPath=/ywh-starter-core/src/main/resources/mybatis-mappers/

配置模板内容

我们生成代码是需要根据模板来生成的,MybatisPlus官方默认使用的模板是velocity,它还提供了另外一种模板就是freemarker。

  • velocity:Velocity是一个基于Java的模板引擎。它允许任何人使用简单而强大的模板语言来引用Java代码中定义的对象。
  • freemarker:FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本的通用工具。
  • freemarker的语法可以参考:Freemaker FTL指令常用标签及语法

com.baomidou.mybatis-plus-generator包下有一个templates文件夹下有官方提供的模板文件,我们使用的是freemarker模板引擎,后缀名为.ftl的就是了,把带.ftl的文件都复制到我们创建的templates下,当然如果不想自己修改内容,可以不用复制出来,直接使用默认的就可以了,跳过这步就可以。

模板所在地方

controller.java.ftl:由于代码过多,这里只贴出一个示例,其他具体代码请前往我的git查看。freemarker模板

package ${package.Controller};
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.beans.factory.annotation.Autowired;
import ${package.Service}.${table.serviceName};
import ${package.Entity}.${table.entityName};
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
 
/**
 * CreateTime: ${date}
 * ClassName: ${table.controllerName}
 * Package: ${package.Controller}
 * Describe:
 * ${table.comment!} 前端控制器
 * @author YWH
 */
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if controllerMappingHyphenStyle??>${table.controllerName}<#else>${controllerMappingHyphen}</#if>")
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass}<${table.serviceName},${table.entityName}> {
<#else>
public class ${table.controllerName} {
</#if>
    private static final Logger log = LoggerFactory.getLogger(${table.controllerName}.class);
    @Autowired
    private ${table.serviceName} service;
}

编写自动生成代码

接下来我们就可以按着官方的提供的示例来编写我们自己用来生成代码的工具类了,在utils下创建CodeGenerator类,代码详解我就不介绍了,可以根据官方文档来阅读(在上面有贴出地址),生成的代码中虽然是空的,但是因为继承了MybatisPlus提供的类,所以我们已经有了大量的CRUD的接口来供我们使用了,具体的CRUD接口可以参考MybatisPlus官方CRUD接口

package com.ywh.common.utils;

/**
 * CreateTime: 2018-12-16 13:52
 * ClassName: CodeGenerator
 * Package: com.ywh.common.utils
 * Describe:
 * MybatisPlus的代码生成器
 *
 * @author YWH
 */
public class CodeGenerator {
 
    /**
     * 获取控制台上的内容
     * @param tip 控制台输入的内容
     * @return
     */
    public static String scanner(String tip){
        Scanner scanner = new Scanner(System.in);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("请输入" + tip + ":");
        System.out.println(stringBuilder.toString());
        if(scanner.hasNext()){
            String ipt = scanner.next();
            if(StringUtils.isNotEmpty(ipt)){
                //输入的不是空就返回
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip +"! ");
    }
 
    public static void main(String[] args) {
 
        ResourceBundle resource = ResourceBundle.getBundle("myBatisPlus");
        String outPutDir = resource.getString("outputDir");
        Boolean fileOverride = false;
        if("true".equals(resource.getString("fileOverride"))){
            fileOverride = true;
        }
        String url = resource.getString("url");
        String driverClass = resource.getString("driverClass");
        String userName = resource.getString("userName");
        String passWord = resource.getString("passWord");
        String setParent = resource.getString("setParent");
 
        //代码生成器
        。。。。。。。由于代码过长,具体代码请前往github查看
    }
}

效果如下:

自动生成代码