目录
前言
一、修改idea的默认配置
二、创建Springboot项目
2.1:创建基础项目结构
2.2:创建Module
2.3:修改项目通用配置
2.4:创建core的项目结构
三、集成Druid
3.1:Druid简介
3.2:项目中配置Druid
四、集成Mybatis-Plus
4.1:Mybatis-Plus简介
4.2:项目中配置Mybatis-Plus
4.2:测试用例
4.3.MybatisPlus代码生成器
五、实现基础controller、service、前端封装返回json体等
六、日志及自定义和全局异常处理
七、集成Redis缓存
八、集成SpringSecurity
九、整合vue实现前后端分离
十、使用docker打包部署
一直以来写代码都是在别人写好的框架上写代码,其实我一直想自己搭一个框架试一试,正好有机会,我就试着自己搭一下,搭的好与坏我觉得不重要,重要的是在这次搭框架的过程中,一定能学习到很多东西。在这里我借鉴了网上很多大神的博客,主要参考的还是下面链接的博主博客,第一次搭建也许在大局观以及知识和经验的储备不足,如有什么错误的地方,望即时纠正。
以后笔记会在掘金上记录了,因为csdb的页面广告太多了,笔记也会慢慢挪过去。掘金笔记地址
参考:https://www.cnblogs.com/chiangchou/p/sunny-1.html#_label8 昵称:bojiangzhou
这次搭建的项目为Springboot2.1版本,分为多模块进行。我这篇博文主要以搭建框架为主,基础学习我推荐下面链接的博主。
SpringBoot学习目录:https://www.jianshu.com/p/9a08417e4e84 昵称:恒宇少年
SpringBoot官方文档:https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/index.html
项目已发布到GitHub:项目地址,如果有帮助到你,点一点star,感谢
在开始之前 我们需要先对idea进行一些配置,这里只配置了一点,大家可以在网上搜索一下,有很多的配置,可以根据自己的习惯进行设置
1.1:在创建项目之前配置默认设置,在这里只配置了Maven,一些比较具体的配置可在网络上搜索进行相关的配置,点击下方的Settings
1.2:修改以下配置可有效的防止Could not autowire. No beans of 'xxxx' type found这个错误,或者在后面的dao接口中添加@Repository
1.3:设置默认使用本地Maven
左侧选择Spring Initializr 后选择jdk的版本,我这里用的是jdk1.8版本
根据自己的命名规范设置Group和Artifact,并选择Type类型为Maven POM
选择Springboot的版本选择2.1.0,这里我们先不用选择任何依赖,后面我们手动添加依赖,点击next
定义项目的名称,以及项目存储的地方,点击finish完成本次创建
项目的结构如下,除了一个pom文件就没有其他了。后面我们会创建Module
pom文件中
在根据链接中的博客和网上一些博客。分模块有很多种分法,大多数是根据controller、service、dao等等分模块的,这种的分法我认为分的太细了,这种的我觉得适用于大公司,人多的那种,每个人负责一个模块进行开发,出了错误也可以快速定位,并且有具体的人负责修改就可以了(也有可能是我的认知太浅薄)。我比较喜欢我参考的博文中的分法。
我暂时主要分为:
1.ywh-starter-core —— 用来放自己写的代码
2.ywh-starter-cache —— 用来放项目缓存(后面会集成Redis进去)
3.ywh-starter-security —— 用来做权限认证
4.ywh-starter-common —— 放一些工具类,以及一些基础的常量、变量、枚举类等
在项目上右键>New>Module,首先创建core子模块,这个模块在选择依赖的时候勾选上web依赖,其他子模块不需要勾选。
前面创建跟之前的一样,Type就不要选择Maven pom,默认就行了。在项目本身下创建新的文件夹来存储Module
按着以上方式创建ywh-starter-core,ywh-starter-cache,ywh-starter-common,ywh-starter-security等模块,创建所有模块以后的项目结构如下:
项目创建好以后我们对项目的所有pom.xml文件修改一下,首先是子模块pom.xml中继承父项目并且把
子模块之间也是有依赖关系的,否则在core中是无法调用其他模块中的东西的,所以我这里的依赖关系是core->common->cache->security,这里的依赖关系先暂时定下,以后有变化时可以再进行确定修改,以core为例,修改pom.xml如下:
com.ywh
common
0.0.1-SNAPSHOT
**************************************************
UTF-8
UTF-8
1.8
在父pom.xml中引入一些我们公用的依赖分别如下,关于什么依赖可以放在父pom.xml下什么可以放在其他子模块下,我是这么理解的,当一个依赖有两个以上的子模块使用的时候,就要把这个依赖提出来放到父pom下,这个依赖只有这一个子模块使用,就可以单独放在某一个子模块下。当然了 为了图方便可以把所有的依赖都放在父pom.xml中。
web依赖会替我们引入很多的东西,引入了starter、tomcat、web支持等。可以看出,Sping Boot内嵌了servlet容器,默认tomcat。
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
fastjson
1.2.53
commons-io
commons-io
2.6
commons-fileupload
commons-fileupload
1.3.3
commons-collections
commons-collections
3.2.1
commons-codec
commons-codec
1.11
org.apache.commons
commons-lang3
3.8.1
org.apache.commons
commons-pool2
2.6.0
Spring Boot使用一个全局的配置文件application.properties或application.yml,放置在src/main/resources目录下。我们可以在这个全局配置文件中对一些默认的配置值进行修改,把所有的application.properties的后缀名修改成.yml,这个不是必须的,如果习惯.properties的方式也可以不修改,是一样的。
具体有哪些配置可到官网查找,有非常多的配置,不过大部分使用默认即可。Spring Boot参考文档
我这里增加了开发环境(dev)和生产环境(prod)的配置文件,并通过在application.yml中设置spring.profiles.active=dev来指定当前环境,yml文件必须以application开头接 -*。
替换springboot项目启动时控制台显示的banner图,可以到http://patorjk.com/software/taag/这个网站生成一个自己项目的banner。创建banner.txt并放到resources根目录下,我是以core启动项目的,所以我放到了core的子模块下,启动以后就能看到修改后的banner图了。
修改启动类CoreApplication,扫描配置类为com.ywh,如果不增加,在其他的模块中添加的配置类会导致扫描不到的情况
package com.ywh.core;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.ywh")
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
我们先对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文件
规划好项目结构以后,我们要对数据库进行操作,所以我们要添加jdbc来连接数据库,这里采用阿里巴巴的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常见问题集锦
Druid的GitHub官方文档
我选择用mysql数据库,在配置Druid之前先要引入mysql的依赖以及Druid的依赖,在父pom.xml文件中引入这两个依赖,可以在Maven仓库中搜索druid-spring-boot-starter ,然后配置core下application-dev.yml文件,yml文件中大多数是默认配置并且我写了注释很好理解,如果想自定义配置可以参考 Druid的GitHub官方文档。这里添加JDBC的依赖是因为要连接数库,需要驱动来进行连接,后面添加了MyBatisPlus后就可以去掉了。
com.alibaba
druid-spring-boot-starter
1.1.10
mysql
mysql-connector-java
8.0.13
org.springframework.boot
spring-boot-starter-jdbc
2.1.1.RELEASE
#在这里我没有写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/*
...........代码省略,具体代码请前往github查看
配置好以上的文件后,我们就可以访问http://localhost:8082/core/druid/login.html 了。我的端口号是8082,因为我上面配置了context-path: /core,所以我的访问地址是上面的地址,如果没有配置的话,默认就是http://localhost:8080/druid/login.html
参考:
Mybatis-Plus官方文档
配置好Druid以后,就能连接数据库了,如果使用原生的jdbc连接数据库也可以,但是这样就太麻烦了,所以我采用了Myatis的增强版Mybatis-Plus,Mybatis-Plus对Mybatis只做增强不做修改,所以完美兼容了Mybatis,而且也支持自动生成代码给你,以及给用户支持了大量的CRUD的接口,也有很多的优秀案例采用了Mybaits-Plus。
特性:
首先在父pom.xml中引入Mybatis-Plus的相关依赖,配置core下application-dev.yml文件,在根据官网中所要求的在启动类中添加@MapperScan(basePackages = "com.ywh.core.dao")来扫描你dao包下所有接口自动注入到Spring的IOC容器中,以便我们使用;依赖分别为:mybatis-plus-boot-starter,freemarker,velocity,后两个为生成代码的时候以哪个为模板,后面会用到,这两个可自行上网搜索查看简介。
com.baomidou
mybatis-plus-boot-starter
3.0.6
org.freemarker
freemarker
2.3.28
org.apache.velocity
velocity
1.7
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
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = "com.ywh")
/**
* 全局配置,扫描指定包下的dao接口,不用每个dao接口上都写@Mapper注解了
*/
@MapperScan(basePackages = "com.ywh.core.dao")
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
配置好以后我们来测试一下是否可以对数据库进行操作了,创建一个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方法。
org.projectlombok
lombok
1.18.4
provided
在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;
}
持久层接口类
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 findAll();
}
SpringBoot测试类
import com.ywh.core.dao.ExampleDao;
import com.ywh.core.entity.ExampleEntity;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class CoreApplicationTests {
@Autowired
private ExampleDao exampleDao;
@Test
public void contextLoads() {
List all = exampleDao.findAll();
System.out.println(all);
}
}
运行此测试方法,可以看到结果已经查出来了,也是我们刚才插入数据库的数据。
上面我们集成了MybatisPlus,关于MybatisPlus的核心功能中的代码生成器可以帮我们大大提升工作效率,不用创建很多的重复工作,AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率,这个代码生成的也不过是我们提前定好的通用的方法,具体的业务代码还是要我们自己来写的,不过在很大程度上帮助了我们很多的。
参考:MybatisPlus官方代码生成器配置
这个功能我是放到了common模块下的,所以我们要对common子模块分一下结构。
base:放基础的controller、service等 config:放一些配置类
entity:放一些基础的实体类 exception:可以放我们自定义的异常类
mapper:可以放基础的mapper.xml文件 utils:放一些公用的工具类
resources目录下创建templates放我们后面用到的模板文件。
项目结构如下:
创建好目录结构以后,我们创建一个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
我们生成代码是需要根据模板来生成的,MybatisPlus官方默认使用的模板是velocity,它还提供了另外一种模板就是freemarker。
velocity:Velocity是一个基于Java的模板引擎。它允许任何人使用简单而强大的模板语言来引用Java代码中定义的对象。
freemarker:FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本的通用工具。
在com.baomidou.mybatis-plus-generator包下有一个templates文件夹下有官方提供的模板文件,我们使用的是freemarker模板引擎,后缀名为.ftl的就是了,把带.ftl的文件都复制到我们创建的templates下,关于freemarker的语法可以参考:Freemaker FTL指令常用标签及语法 作者:Duke_Cui
我对复制出来的文件略有修改,在熟悉freemarker的情况下可以按照自己的想法更改,修改如下:
controller.java.ftl:由于代码过多,这里只贴出一个示例,其他具体代码请前往我的git查看。
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;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Scanner;
/**
* 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查看
}
}
类中是一个main函数来启动,效果如下:
由于CSDN中不能把代码缩放导致篇幅过长,阅读效果不是很好,所以我把从这开始文章单独提出去作为单独一章发布了。
链接:实现基础controller、service、前端封装返回json体等
链接:日志及自定义和全局异常处理
链接:集成Redis + Redis工具类
链接:spring security学习笔记
链接:spring security进阶
链接:整合vue
链接:使用docker打包与部署