使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

## 目标

- 使用 Gradle 构建一个多模块系统,熟悉脚本
- 搭建 SpringBoot ,Spring Security ,Mybatis子模块,实现基本的 Hello World。可以独立运行。

总体步骤:新建父工程(gradle) - 配置maven - 新建多个子工程(SpringBoot ,Spring Security ,Mybatis) - 修改父子的build.gradle & 父的settings.gradle  - 将无用的文件进行删除 - 写相关测试类 - 测试

Pre1: 建本地数据库

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

Pre2: 把一个empty项目变成gradle项目:  gradle init build

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

Pre3: git 从分支拉取:git clone -b brachname XXX

git push指定分支:git push origin brachname

 

1 搭建父工程:父工程没什么要求,直接new一个gradle的空工程就行。

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

父模块建好之后,多了下面红色框标出的东西,我们需要修改的有build.gradle(配置构建gradle项目时的一些东西,后面会细说,搭建多模块项目,主要就是在配置各个模块的这个文件) settings.gradle (配置父子模块间的依赖关系)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

配置父模块的build.gradle文件

  1 /*
  2  * This file was generated by the Gradle 'init' task.
  3  *
  4  * This is a general purpose Gradle build.
  5  * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds
  6  */
  7 buildscript {
  8     repositories {
  9         maven {
 10             url 'https://maven.aliyun.com/repository/gradle-plugin'
 11         }
 12     }
 13 }
 14 plugins {
 15     id 'org.springframework.boot' version '2.2.5.RELEASE' apply false
 16     id 'io.spring.dependency-management' version '1.0.9.RELEASE'
 17 }
 18 description="flight-sample"
 19 
 20 ext {
 21 
 22 
 23     //================= datasource ================
 24     mysqlConnectorJavaVersion = "8.0.19"
 25     druidStarterVersion = "1.1.18"
 26     druidVersion = "1.0.31"
 27 
 28     mybatisPlusStarterVersion = "3.3.1"
 29 
 30     //=================json=======================
 31     fastjsonVersion = "1.2.62"
 32     gsonVersion = "2.8.6"
 33     jjwtVersion = "0.9.1"
 34 
 35     //=================cache=======================
 36     ehcacheVersion = "2.10.6"
 37 
 38     //=================httpclient=================
 39     httpclientVersion = "4.5.10"
 40     OkHttpVersion = "3.14.4"
 41 
 42     //================= tools====================
 43     GuavaVersion = "26.0-jre"
 44     validationApiVersion = "2.0.1.Final"
 45     protostuffVersion = "1.6.0"
 46     curatorVersion = "4.0.1"
 47     jacksonDataformatYamlVersion="2.9.8"
 48 
 49     //================= test ====================
 50     h2Version = "1.4.197"
 51 
 52 }
 53 
 54 configure(allprojects ) { abjects ->
 55     apply plugin: 'java'
 56     apply plugin: 'maven-publish'
 57     repositories {
 58 
 59         maven {
 60             url 'https://maven.aliyun.com/nexus/content/groups/public/'
 61         }
 62 
 63         maven {
 64             url = 'https://repo.spring.io/libs-milestone'
 65         }
 66 
 67         maven {
 68             url 'https://repo.spring.io/snapshot/'
 69         }
 70 
 71         maven {
 72             url = 'https://oss.sonatype.org/content/repositories/snapshots/'
 73         }
 74 
 75         mavenLocal()
 76 
 77     }
 78 }
 79 
 80 configure(subprojects){subjects ->
 81     apply plugin: 'java'
 82     apply plugin: 'maven'
 83     apply plugin: 'maven-publish'
 84     apply plugin: 'io.spring.dependency-management'
 85 
 86     group = 'com.td.flight'
 87     version = '0.0.1'
 88 
 89     repositories {
 90 
 91         maven {
 92             url 'https://maven.aliyun.com/nexus/content/groups/public/'
 93         }
 94 
 95         maven {
 96             url = 'https://repo.spring.io/libs-milestone'
 97         }
 98 
 99         maven {
100             url 'https://repo.spring.io/snapshot/'
101         }
102 
103         maven {
104             url = 'https://oss.sonatype.org/content/repositories/snapshots/'
105         }
106 
107         mavenLocal()
108     }
109 
110     dependencyManagement {
111         imports {
112             mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
113         }
114     }
115 
116     dependencies{
117         compile "org.springframework.boot:spring-boot-starter-aop"
118         compile "org.springframework.boot:spring-boot-autoconfigure"
119         compile "org.springframework.boot:spring-boot-configuration-processor"
120         compile "org.springframework.retry:spring-retry"
121         testImplementation 'org.junit.platform:junit-platform-commons:1.5.2'
122         testCompile "org.springframework.boot:spring-boot-starter-test"
123         testCompile "org.assertj:assertj-core:3.15.0"
124     }
125     test {
126         useJUnitPlatform()
127     }
128 
129 
130     compileJava {
131         sourceCompatibility = 1.8
132         targetCompatibility = 1.8
133         options.encoding = "UTF-8"
134     }
135 
136     task sourcesJar(type: Jar) {
137         from sourceSets.main.allJava
138         archiveClassifier = 'sources'
139     }
140 
141     task javadocJar(type: Jar) {
142         from javadoc
143         archiveClassifier = 'javadoc'
144     }
145 
146 }

2 搭建子模块:boot-demo

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

type选择gradle project

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

这里勾选web依赖(方便后面的测试),然后直接next->finish

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

这个时候,IDEA一直提示在importing gradle project,仿佛卡死在了这里

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

因为对于子项目xxx而言,IDEA为它自动生成了一个默认的build.gradle,这句mavenCentral()意思是从maven中心仓库下载相关依赖,大家都知道去国外的网站下载这些资源肯定是慢的一批

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

这里我们手动停止build的动作,删除其他无用配置(上面的父工程的build.gradle已经对所有的子项目做了配置,所以各个子工程里不需要再配了),只留下一句话

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

然后reimport all gradle projects

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

配置application.yaml

IDEA为我们默认生成的是application.properities文件,修改后缀为.yaml,然后添加port

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

配置controller:添加@RestController @RequestMapping注解,并写一个方法

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

启动测试

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

处理父子模块依赖:

修改父工程的settings.gradle,使子模块boot-demo属于父模块,多个子模块可以使用下面的逗号隔开的书写格式。写完include后,IDEA应该会自动重新import, 如果没有,则按上面的步骤执行reimport all gradle projects

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

如果gradle项目呈现出下图所示的所属结构,则证明子父模块依赖弄好了。

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

PS: 每新建一个module,都会生成一个和父工程同级的item (如下图所示),我们需要选中它,点击减号清理掉它(不然会有一些不必要的麻烦)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

3 搭建子模块:mybatisplus-demo

参考:https://www.cnblogs.com/happy4java/p/11206801.html

对于Mybatisplus-demo模块的yaml文件有详细注释,方便以后学习:https://www.cnblogs.com/lgg20/archive/2019/10/28/11752946.html

和第2步搭建的boot-demo模块步骤基本一致,唯一的区别在于build.gradle文件中多引入了一些依赖(红框中的两个是必须的,其他的是我为了测试弄的)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

build.gradle的脚本

 1 configurations {
 2     mybatisGenerator
 3 }
 4 dependencies {
 5     implementation 'org.springframework.boot:spring-boot-starter-web'
 6     compile "com.baomidou:mybatis-plus-boot-starter:${mybatisPlusStarterVersion}"
 7     implementation "mysql:mysql-connector-java:${mysqlConnectorJavaVersion}"
 8     //implementation 'org.projectlombok:lombok:1.18.2'
 9     implementation 'org.mybatis.generator:mybatis-generator-core:1.3.5'
10     //mybatisGenerator 'mysql:mysql-connector-java:${mysqlConnectorJavaVersion}'
11     //implementation 'tk.mybatis:mapper:3.3.9'
12     //implementation 'tk.mybatis:mapper-spring-boot-starter:2.0.0'
13     annotationProcessor 'org.projectlombok:lombok:1.18.2'
14     compileOnly 'org.projectlombok:lombok:1.18.2'
15 }

配置application.yaml

 1 spring:
 2   datasource:
 3     driver-class-name: com.mysql.cj.jdbc.Driver
 4     url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
 5     username: root
 6     password: root
 7 mybatis-plus:
 8   mapper-locations: classpath:/mybatis/*Dao.xml
 9   #实体扫描,多个package用逗号或者分号分隔
10   type-aliases-package: com.example.entity
11   global-config:
12   #主键类型  0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
13     id-type: 3
14     #字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断"
15     field-strategy: 2
16     #驼峰下划线转换
17     db-column-underline: true
18     logic-delete-value: 1
19     logic-not-delete-value: 0
20   configuration:
21     map-underscore-to-camel-case: true
22     cache-enabled: false
23 server:
24   port: 8097

新建controller/mapper/entity/config

controller

 1 @RestController
 2 public class UserController {
 3 
 4     @Autowired
 5     private UserDao UserDao;
 6 
 7     @RequestMapping("/getUserInfoById")
 8     public User getUserInfoById(){
 9         //List<User> users = UserDao.selectAll();
10         User user = UserDao.selectById("1");
11         return user;
12     }
13     @RequestMapping("/getUserList")
14     public List<User> getUserList(){
15         List<User> users = UserDao.selectList(new QueryWrapper<>());
16         return users;
17     }
18     @RequestMapping("/hello")
19     public String hello(){
20         return "hello";
21     }
22     @RequestMapping("/insertUserInfo")
23     public String insertUserInfo(){
24         String result = "";
25         User user = new User();
26         user.setName("飞飞飞");
27         user.setEmail("[email protected]");
28         user.setAge(21);
29         int count = UserDao.insert(user);
30         if(count > 0){
31             result = "插入成功!";
32         } else {
33             result = "失败!";
34         }
35         return result;
36     }
37 }

mapper

1 @Mapper
2 public interface UserDao extends BaseMapper<User> {
3     //User findById(String id);
4 }

entity

1 @Data
2 @TableName("user")
3 public class User{
4     @TableId
5     private String id;
6     private String name;
7     private int age;
8     private String email;
9 }

config

 1 @Configuration
 2 @MapperScan("com.example.dao")//扫描文件
 3 public class MybatisPlusConfig {
 4 
 5     /*
 6      * 分页插件,自动识别数据库类型
 7      * 多租户,请参考官网【插件扩展】
 8      */
 9     @Bean
10     public PaginationInterceptor paginationInterceptor() {
11         return new PaginationInterceptor();
12     }
13 }

项目结构

使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

测试

查询(根据id查询,为了方便,id在代码中写死了)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

DB中的数据

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

插入数据(为了方便,要插入的User对象直接在代码中写死了)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

DB中的数据

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 4 搭建子模块:security-demo

build.gradle文件

1 dependencies {
2     compile project(":mybatisplus-demo")
3     implementation 'org.springframework.boot:spring-boot-starter-security'
4     implementation 'org.springframework.boot:spring-boot-starter-web'
5     annotationProcessor 'org.projectlombok:lombok:1.18.2'
6     compileOnly 'org.projectlombok:lombok:1.18.2'
7 }

测试用的类ref: https://www.cnblogs.com/telwanggs/p/10802851.html

这里说一下我对springSecurity工作原理的初步认识:

使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

PS: 在搭建mybatisplus-demo模块的过程中,踩了很多坑,在这里Mark一下

1:在build gradle项目的时候,一直提示cannot find implement()IDEA把问题定位到了build.gradle的文件中的这些位置,做法:在gradle中直接移除子模块,再reimport (ref步骤2中的PS部分)

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

2:在所有的配置项,测试类写好之后,开始测试的时候,web页面一直提示:Whitelabel Error Page,百度了一下:一般出现这个问题的原因就是目录结构不正确,导致主应用程序类(Main application class)扫描不到controller类。默认情况下主应用程序类(Main application class)只会扫描同一包下的Class。对照了一下自己的,我是把启动类放到了config包下,所以导致扫描不到其他包,做法:把启动类拖出来,和com.example同级。

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

3web页面访问查数据的url (getUserInfoById),在web页面死活不返回数据,只有一个大大的 {}, 里面什么都没有;同时类里面的user.setXXXX() 等方法报一系列乱码,当时我就懵逼了,反思了一下:我userentity用的lombok,然后百度了一下lombokgradle依赖引入,原来是我的引用方式不对。在gradle4.7版本以后甚至现在gradle5.0了里面这种方式会产生警告,在gradle5.0里面会直接报编译错误。正确使用可以采用如下方式:

1 annotationProcessor 'org.projectlombok:lombok:1.18.2'
2 compileOnly 'org.projectlombok:lombok:1.18.2'

注释掉的是我写的错的。

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

Lombok的使用:主要是entity中少些了一些setter getter等方法。

 使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

4:本来用的是mybatisplus框架,因为在搭模块的时候参考了网上的一些资料,竟然阴差阳错的又引入了另外一个mybatis框架:tk.mybatis,然后就遇到了下面的问题:java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseSelectProvider.<init>(),使用selectByPrimaryKey无法根据主键查找获取结果,解决方法:在写实体类时,引入@Id注解时,导入正确的包:import javax.persistence.Id

而我导成了:org.springframework.data.annotation.Id (当然最后注释掉了tk.mybatis相关的依赖,不然会冲突,这里只是mark一下遇到这个问题的解决方法)

同时应该只保留一种Mybatis相关的框架依赖,我原来是两个共存(不知道是抽什么风加进去的。。。)

使用Gradle 构建一个SpringBoot + Spring Security + Mybatisplus的多模块系统

 

 

 

PS: 其他细节,后续再补上,今天先写到这里 --- 20200408-23:03

 github: 暂时未公开

PS: 第一次写博客,难免有不妥的地方,希望理解。