## 目标
- 使用 Gradle 构建一个多模块系统,熟悉脚本
- 搭建 SpringBoot ,Spring Security ,Mybatis子模块,实现基本的 Hello World。可以独立运行。
总体步骤:新建父工程(gradle) - 配置maven - 新建多个子工程(SpringBoot ,Spring Security ,Mybatis) - 修改父子的build.gradle & 父的settings.gradle - 将无用的文件进行删除 - 写相关测试类
Pre1: 建本地数据库
Pre2: 把一个empty项目变成gradle项目: gradle init build
Pre3: git 从分支拉取:git clone -b brachname XXX
git push指定分支:git push origin brachname
1 搭建父工程:父工程没什么要求,直接new一个gradle的空工程就行。
父模块建好之后,多了下面红色框标出的东西,我们需要修改的有build.gradle(配置构建gradle项目时的一些东西,后面会细说,搭建多模块项目,主要就是在配置各个模块的这个文件) 和 settings.gradle (配置父子模块间的依赖关系)。
build.grale文件详细解释:
配置父模块的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
type选择gradle project
这里勾选web依赖(方便后面的测试),然后直接next->finish
这个时候,IDEA一直提示在importing gradle project,仿佛卡死在了这里
因为对于子项目xxx而言,IDEA为它自动生成了一个默认的build.gradle,这句mavenCentral()意思是从maven中心仓库下载相关依赖,大家都知道去国外的网站下载这些资源肯定是慢的一批
这里我们手动停止build的动作,删除其他无用配置(上面的父工程的build.gradle已经对所有的子项目做了配置,所以各个子工程里不需要再配了),只留下一句话
然后reimport all gradle projects
配置application.yaml
IDEA为我们默认生成的是application.properities文件,修改后缀为.yaml,然后添加port号
配置controller:添加@RestController 和 @RequestMapping注解,并写一个方法
启动测试
处理父子模块依赖:
修改父工程的settings.gradle,使子模块boot-demo属于父模块,多个子模块可以使用下面的逗号隔开的书写格式。写完include后,IDEA应该会自动重新import, 如果没有,则按上面的步骤执行reimport all gradle projects
如果gradle项目呈现出下图所示的所属结构,则证明子父模块依赖弄好了。
PS: 每新建一个module,都会生成一个和父工程同级的item (如下图所示),我们需要选中它,点击减号清理掉它(不然会有一些不必要的麻烦)
3 搭建子模块:mybatisplus-demo
参考:
对于Mybatisplus-demo模块的yaml文件有详细注释,方便以后学习:
和第2步搭建的boot-demo模块步骤基本一致,唯一的区别在于build.gradle文件中多引入了一些依赖(红框中的两个是必须的,其他的是我为了测试弄的)
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("121213@163.com");
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 }
项目结构
测试
查询(根据id查询,为了方便,id在代码中写死了)
DB中的数据
插入数据(为了方便,要插入的User对象直接在代码中写死了)
DB中的数据
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:
这里说一下我对springSecurity工作原理的初步认识:
shiro架构初步解读:
解释:user想和application交互之前,必须先问问security manager同不同意,security manager需要去咨询一下realm,最终做出决定。
PS: 在搭建mybatisplus-demo模块的过程中,踩了很多坑,在这里Mark一下
坑1:在build gradle项目的时候,一直提示cannot find implement(),IDEA把问题定位到了build.gradle的文件中的这些位置,做法:在gradle中直接移除子模块,再reimport (ref步骤2中的PS部分)
坑2:在所有的配置项,测试类写好之后,开始测试的时候,web页面一直提示:Whitelabel Error Page,百度了一下:一般出现这个问题的原因就是目录结构不正确,导致主应用程序类(Main application class)扫描不到controller类。默认情况下主应用程序类(Main application class)只会扫描同一包下的Class。对照了一下自己的,我是把启动类放到了config包下,所以导致扫描不到其他包,做法:把启动类拖出来,和com.example同级。
坑3:web页面访问查数据的url (getUserInfoById),在web页面死活不返回数据,只有一个大大的 {}, 里面什么都没有;同时类里面的user.setXXXX() 等方法报一系列乱码,当时我就懵逼了,反思了一下:我user的entity用的lombok,然后百度了一下lombok的gradle依赖引入,原来是我的引用方式不对。在gradle4.7版本以后甚至现在gradle5.0了里面这种方式会产生警告,在gradle5.0里面会直接报编译错误。正确使用可以采用如下方式:
1 annotationProcessor 'org.projectlombok:lombok:1.18.2'
2 compileOnly 'org.projectlombok:lombok:1.18.2'
注释掉的是我写的错的。
Lombok的使用:主要是entity中少些了一些setter 和getter等方法。
坑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相关的框架依赖,我原来是两个共存(不知道是抽什么风加进去的。。。)
PS: 其他细节,后续再补上,今天先写到这里 --- 20200408-23:03
补充(2020.4.22)
1 删除项目中的无用文件:
删除所有子模块中的gradlew文件
删除所有子模块中的gradlew.bat文件
删除所有子模块中的gradle文件夹
删除所有子模块中的.gitignore文件,在项目最外层配置.gitignore文件,做为整个项目的git提交忽略配置
github: 暂时未公开
PS: 第一次写博客,难免有不妥的地方,希望理解。