點擊上方“成猿之路”,選擇“置頂公衆號”
技術文章第一時間送達!
作者:calebman
https://www.jianshu.com/p/95946d6b0c7d
本文簡介
爲什麼使用SpringBoot
搭建怎樣一個環境
開發環境
導入快速啓動項目
集成前準備
集成Mybatis
集成Swagger2
多環境配置
多環境下的日誌配置
常用配置
爲什麼使用SpringBoot
SpringBoot相對於傳統的SSM框架的優點是提供了默認的樣板化配置,簡化了Spring應用的初始搭建過程,如果你不想被衆多的xml配置文件困擾,可以考慮使用SpringBoot替代
搭建怎樣一個環境
本文將基於Spring官方提供的快速啓動項目模板集成Mybatis、Swagger2框架,並講解mybatis generator一鍵生成代碼插件、logback、一鍵生成文檔以及多環境的配置方法,最後再介紹一下自定義配置的註解獲取、全局異常處理等經常用到的東西。
開發環境
本人使用IDEA作爲開發工具,IDEA下載時默認集成了SpringBoot的快速啓動項目可以直接創建,如果使用Eclipse的同學可以考慮安裝SpringBoot插件或者直接從這裏配置並下載SpringBoot快速啓動項目,需要注意的是本次環境搭建選擇的是SpringBoot2.0的快速啓動框架,SpringBoot2.0要求jdk版本必須要在1.8及以上。
https://start.spring.io/
導入快速啓動項目
不管是由IDEA導入還是現實下載模板工程都需要初始化快速啓動工程的配置,如果使用IDEA,在新建項目時選擇Spring Initializr,主要配置如下圖
IDEA新建SpringBoot項目-填寫項目/包名
IDEA新建SpringBoot項目-選擇依賴包
點擊next之後finish之後IDEA顯示正在下載模板工程,下載完成後會根據pom.xml下載包依賴,依賴下載完畢後模板項目就算創建成功了,如果是直接從官方網站配置下載快速啓動項目可參考下圖配置
直接下載SpringBoot快速啓動項目-項目配置
從Search for dependencies 框中輸入並選擇Web、Mysql、Mybatis加入依賴,點擊Generate Project下載快速啓動項目,然後在IDE中選擇導入Maven項目,項目導入完成後可見其目錄結構如下圖
快速啓動項目-項目結構
需要關注紅色方框圈起來的部分,由上往下第一個java類是用來啓動項目的入口函數,第二個properties後綴的文件是項目的配置文件,第三個是項目的依賴包以及執行插件的配置
集成前準備
修改.properties爲.yml
yml相對於properties更加精簡而且很多官方給出的Demo都是yml的配置形式,在這裏我們採用yml的形式代替properties,相對於properties形式主要有以下兩點不同
對於鍵的描述由原有的 "." 分割變成了樹的形狀
對於所有的鍵的後面一個要跟一個空格,不然啓動項目會報配置解析錯誤
# properties式語法描述
spring.datasource.name = mysql
spring.datasource.url = jdbc:mysql://localhost:3306/db?characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = 123
# yml式語法描述
spring:
datasource:
name: mysql
url: jdbc:mysql://localhost:3306/db?characterEncoding=utf-8
username: root
password: 123
配置所需依賴
快速啓動項目創建成功後我們觀察其pom.xml文件中的依賴如下圖,包含了我們選擇的Web、Mybatis以及Mysql
<!-- spring web mvc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
但是我們使用ORM框架一般還會配合數據庫連接池以及分頁插件來使用,在這裏我選擇了阿里的druid以及pagehelper這個分頁插件,再加上我們還需要整合swagger2文檔自動化構建框架,所以增加了以下四個依賴項
<!-- 分頁插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!-- alibaba的druid數據庫連接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- alibaba的json格式化對象 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<!-- 自動生成API文檔 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.5.0</version>
</dependency>
集成Mybatis
Mybatis的配置主要包括了druid數據庫連接池、pagehelper分頁插件、mybatis-generator代碼逆向生成插件以及mapper、pojo掃描配置
配置druid數據庫連接池
添加以下配置至application.yml文件中
spring:
datasource:
# 如果存在多個數據源,監控的時候可以通過名字來區分開來
name: mysql
# 連接數據庫的url
url: jdbc:mysql://localhost:3306/db?characterEncoding=utf-8
# 連接數據庫的賬號
username: root
# 連接數據庫的密碼
password: 123
# 使用druid數據源
type: com.alibaba.druid.pool.DruidDataSource
# 擴展插件
# 監控統計用的filter:stat 日誌用的filter:log4j 防禦sql注入的filter:wall
filters: stat
# 最大連接池數量
maxActive: 20
# 初始化時建立物理連接的個數。初始化發生在顯示調用init方法,或者第一次getConnection時
initialSize: 1
# 獲取連接時最大等待時間,單位毫秒
maxWait: 60000
# 最小連接池數量
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
# 連接保持空閒而不被驅逐的最長時間
minEvictableIdleTimeMillis: 300000
# 用來檢測連接是否有效的sql,要求是一個查詢語句
# 如果validationQuery爲null,testOnBorrow、testOnReturn、testWhileIdle都不會其作用
validationQuery: select count(1) from 'table'
# 申請連接的時候檢測,如果空閒時間大於timeBetweenEvictionRunsMillis,執行validationQuery檢測連接是否有效
testWhileIdle: true
# 申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
testOnBorrow: false
# 歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能
testOnReturn: false
# 是否緩存preparedStatement,即PSCache
poolPreparedStatements: false
# 要啓用PSCache,必須配置大於0,當大於0時,poolPreparedStatements自動觸發修改爲true
maxOpenPreparedStatements: -1
配置pagehelper分頁插件
# pagehelper分頁插件
pagehelper:
# 數據庫的方言
helperDialect: mysql
# 啓用合理化,如果pageNum < 1會查詢第一頁,如果pageNum > pages會查詢最後一頁
reasonable: true
代碼逆向生成插件mybatis-generator的配置及運行
mybatis-generator插件的使用主要分爲以下三步
1.pom.xml中添加mybatis-generator插件
<build>
<plugins>
<!-- 將Spring Boot應用打包爲可執行的jar或war文件 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- mybatis generator 自動生成代碼插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<!-- 掃描resources/generator目錄下的generatorConfig.xml配置 -->
<configurationFile>
${basedir}/src/main/resources/generator/generatorConfig.xml
</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
</plugins>
</build>
2.創建逆向代碼生成配置文件generatorConfig.xml
參照pom.xml插件配置中的掃描位置,在resources目錄下創建generator文件夾,在新建的文件夾中創建generatorConfig.xml配置文件,文件的詳細配置信息如下
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 運行方式:mvaen運行命令 mybatis-generator:generate -e -->
<!-- 數據庫驅動:選擇你的本地硬盤上面的數據庫驅動包-->
<properties resource="generator/generator.properties"/>
<classPathEntry location="${classPathEntry}"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<!--數據庫鏈接URL,用戶名、密碼 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/${db}?characterEncoding=utf-8"
userId="${userId}"
password="${password}">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<javaModelGenerator targetPackage="${pojoTargetPackage}" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="${mapperTargetPackage}" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="${daoTargetPackage}" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是數據庫中的表名或視圖名 schema是數據庫名稱-->
<table tableName="%" schema="${db}"/>
</context>
</generatorConfiguration>
爲了將generatorConfig.xml配置模板化,在這裏將變動性較大的配置項單獨提取出來作爲一個generatorConfig.xml的配置文件,然後通過properties標籤讀取此文件的配置,這樣做的好處是當需要多處複用此xml時只需要關注少量的配置項。
在generatorConfig.xml同級創建generator.properties文件,現只需要配置generator.properties文件即可,配置內容如下
# 請手動配置以下選項
# 數據庫驅動:選擇你的本地硬盤上面的數據庫驅動包
classPathEntry = D:/CJH/maven-repository/mysql/mysql-connector-java/5.1.30/mysql-connector-java-5.1.30.jar
# 數據庫名稱、用戶名、密碼
db = db
userId = root
password = 123
# 生成pojo的包名位置 在src/main/java目錄下
pojoTargetPackage = com.spring.demo.springbootexample.mybatis.po
# 生成DAO的包名位置 在src/main/java目錄下
daoTargetPackage = com.spring.demo.springbootexample.mybatis.mapper
# 生成Mapper的包名位置 位於src/main/resources目錄下
mapperTargetPackage = mapper
3.運行mybatis-generator插件生成Dao、Model、Mapping
# 打開命令行cd到項目pom.xml同級目錄運行以下命令
mvn mybatis-generator:generate -e
mybatis掃描包配置
至此已經生成了指定數據庫對應的實體、映射類,但是還不能直接使用,需要配置mybatis掃描地址後才能正常調用
1.在application.yml配置mapper.xml以及pojo的包地址
mybatis:
# mapper.xml包地址
mapper-locations: classpath:mapper/*.xml
# pojo生成包地址
type-aliases-package: com.spring.demo.springbootexample.mybatis.po
2.在SpringBootExampleApplication.java中開啓Mapper掃描註解
@SpringBootApplication
@MapperScan("com.spring.demo.springbootexample.mybatis.mapper")
public class SpringBootExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootExampleApplication.class, args);
}
}
測試mapper的有效性
@Controller
public class TestController {
//替換成自己生成的mapper
@Autowired
UserMapper userMapper;
@RequestMapping("/test")
@ResponseBody
public Object test(){
//查詢該表的所有數據
return userMapper.selectByExample(null);
}
}
啓動SpringBootExampleApplication.java的main函數,如果沒有在application.yml特意配置server.port那麼springboot會採用默認的8080端口運行,運行成功將打印如下日誌
Tomcat started on port(s): 8080 (http) with context path ''
在瀏覽器輸入地址如果返回表格的中的所有數據代表mybatis集成成功
http://localhost:8080/test
集成Swagger2
Swagger2是一個文檔快速構建工具,能夠通過註解自動生成一個Restful風格json形式的接口文檔,並可以通過如swagger-ui等工具生成html網頁形式的接口文檔,swagger2的集成比較簡單,使用需要稍微熟悉一下,集成、註解與使用分如下四步
1.建立SwaggerConfig文件
@Configuration
public class SwaggerConfig {
// 接口版本號
private final String version = "1.0";
// 接口大標題
private final String title = "SpringBoot示例工程";
// 具體的描述
private final String description = "API文檔自動生成示例";
// 服務說明url
private final String termsOfServiceUrl = "http://www.kingeid.com";
// licence
private final String license = "MIT";
// licnce url
private final String licenseUrl = "https://mit-license.org/";
// 接口作者聯繫方式
private final Contact contact = new Contact("calebman", "https://github.com/calebman", "[email protected]");
@Bean
public Docket buildDocket() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(buildApiInf())
.select().build();
}
private ApiInfo buildApiInf() {
return new ApiInfoBuilder().title(title).termsOfServiceUrl(termsOfServiceUrl).description(description)
.version(version).license(license).licenseUrl(licenseUrl).contact(contact).build();
}
}
2.在SpringBootExampleApplication.java中啓用Swagger2註解
在@SpringBootApplication註解下面加上@EnableSwagger2註解
3.常用註解示例
//Contorller中的註解示例
@Controller
@RequestMapping("/v1/product")
// 表示標識這個類是swagger的資源
@Api(value = "DocController", tags = {"restful api示例"})
public class DocController extends BaseController {
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@ResponseBody
//表示一個http請求的操作
@ApiOperation(value = "修改指定產品", httpMethod = "PUT", produces = "application/json")
//@ApiImplicitParams用於方法,包含多個@ApiImplicitParam表示單獨的請求參數
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "產品ID", required = true, paramType = "path")})
public WebResult update(@PathVariable("id") Integer id, @ModelAttribute Product product) {
logger.debug("修改指定產品接收產品id與產品信息=>%d,{}", id, product);
if (id == null || "".equals(id)) {
logger.debug("產品id不能爲空");
return WebResult.error(ERRORDetail.RC_0101001);
}
return WebResult.success();
}
}
//Model中的註解示例
//表示對類進行說明,用於參數用實體類接收
@ApiModel(value = "產品信息")
public class Product {
//表示對model屬性的說明或者數據操作更改
@ApiModelProperty(required = true, name = "name", value = "產品名稱", dataType = "query")
private String name;
@ApiModelProperty(name = "type", value = "產品類型", dataType = "query")
private String type;
}
4.生成json形式的文檔
集成成功後啓動項目控制檯會打印級別爲INFO的日誌,截取部分如下,表明可通過訪問應用的v2/api-docs接口得到文檔api的json格式數據,可在瀏覽器輸入指定地址驗證集成是否成功
Mapped "{[/v2/api-docs],methods=[GET],produces=[application/json || application/hal+json]}"
http://localhost:8080/v2/api-docs
多環境配置
應用研發過程中多環境是不可避免的,假設我們現在有開發、演示、生產三個不同的環境其配置也不同,如果每次都在打包環節來進行配置難免出錯,SpringBoot支持通過命令啓動不同的環境,但是配置文件需要滿足application-{profile}.properties
的格式,profile代表對應環境的標識,加載時可通過不同命令加載不同環境。
application-dev.properties:開發環境
application-test.properties:演示環境
application-prod.properties:生產環境
# 運行演示環境命令
java -jar spring-boot-example-0.0.1-SNAPSHOT --spring.profiles.active=test
基於現在的項目實現多環境我們需要在application.yml同級目錄新建application-dev.yml、application-test.yml、application-prod.yml三個不同環境的配置文件,將不變的公有配置如druid的大部分、pagehelper分頁插件以及mybatis包掃描配置放置於application.yml中,並在application.yml中配置默認採用開發環境,那麼如果不帶--spring.profiles.active啓動應用就默認爲開發環境啓動,變動較大的配置如數據庫的賬號密碼分別寫入不同環境的配置文件中
spring:
profiles:
# 默認使用開發環境
active: dev
配置到這裏我們的項目目錄結構如下圖所示
至此我們分別完成了Mybatis、Swagger2以及多環境的集成,接下來我們配置多環境下的logger。對於logger我們總是希望在項目研發過程中越多越好,能夠給予足夠的信息定位bug,項目處於演示或者上線狀態時爲了不讓日誌打印影響程序性能我們只需要警告或者錯誤的日誌,並且需要寫入文件,那麼接下來就基於logback實現多環境下的日誌配置
多環境下的日誌配置
創建logback-spring.xml在application.yml的同級目錄,springboot推薦使用logback-spring.xml而不是logback.xml文件,logback-spring.xml的配置內容如下所示
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<!--
簡要描述
日誌格式 => %d{HH:mm:ss.SSS}(時間) [%-5level](日誌級別) %logger{36}(logger名字最長36個字符,否則按照句點分割) - %msg%n(具體日誌信息並且換行)
開發環境 => ${basepackage}包下控制檯打印DEBUG級別及以上、其他包控制檯打印INFO級別及以上
演示(測試)環境 => ${basepackage}包下控制檯打印INFO級別及以上、其他包控制檯以及文件打印WARN級別及以上
生產環境 => 控制檯以及文件打印ERROR級別及以上
日誌文件生成規則如下:
文件生成目錄 => ${logdir}
當日的log文件名稱 => ${appname}.log
其他時候的log文件名稱 => ${appname}.%d{yyyy-MM-dd}.log
日誌文件最大 => ${maxsize}
最多保留 => ${maxdays}天
-->
<!--自定義參數 -->
<!--用來指定日誌文件的上限大小,那麼到了這個值,就會刪除舊的日誌-->
<property name="maxsize" value="30MB" />
<!--只保留最近90天的日誌-->
<property name="maxdays" value="90" />
<!--application.yml 傳遞參數 -->
<!--log文件生成目錄-->
<springProperty scope="context" name="logdir" source="resources.logdir"/>
<!--應用名稱-->
<springProperty scope="context" name="appname" source="resources.appname"/>
<!--項目基礎包-->
<springProperty scope="context" name="basepackage" source="resources.basepackage"/>
<!--輸出到控制檯 ConsoleAppender-->
<appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
<!--展示格式 layout-->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>
<pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{36} - %msg%n</pattern>
</pattern>
</layout>
</appender>
<!--輸出到文件 FileAppender-->
<appender name="fileLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--
日誌名稱,如果沒有File 屬性,那麼只會使用FileNamePattern的文件路徑規則
如果同時有<File>和<FileNamePattern>,那麼當天日誌是<File>,明天會自動把今天
的日誌改名爲今天的日期。即,<File> 的日誌都是當天的。
-->
<File>${logdir}/${appname}.log</File>
<!--滾動策略,按照時間滾動 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路徑,定義了日誌的切分方式——把每一天的日誌歸檔到一個文件中,以防止日誌填滿整個磁盤空間-->
<FileNamePattern>${logdir}/${appname}.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>${maxdays}</maxHistory>
<totalSizeCap>${maxsize}</totalSizeCap>
</rollingPolicy>
<!--日誌輸出編碼格式化-->
<encoder>
<charset>UTF-8</charset>
<pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 開發環境-->
<springProfile name="dev">
<root level="INFO">
<appender-ref ref="consoleLog"/>
</root>
<!--
additivity是子Logger 是否繼承 父Logger 的 輸出源(appender) 的標誌位
在這裏additivity配置爲false代表如果${basepackage}中有INFO級別日誌則子looger打印 root不打印
-->
<logger name="${basepackage}" level="DEBUG" additivity="false">
<appender-ref ref="consoleLog"/>
</logger>
</springProfile>
<!-- 演示(測試)環境-->
<springProfile name="test">
<root level="WARN">
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileLog"/>
</root>
<logger name="${basepackage}" level="INFO" additivity="false">
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileLog"/>
</logger>
</springProfile>
<!-- 生產環境 -->
<springProfile name="prod">
<root level="ERROR">
<appender-ref ref="consoleLog"/>
<appender-ref ref="fileLog"/>
</root>
</springProfile>
</configuration>
日誌配置中引用了application.yml的配置信息,主要有logdir、appname、basepackage三項,logdir是日誌文件的寫入地址,可以傳入相對路徑,appname是應用名稱,引入這項是爲了通過日誌文件名稱區分是哪個應該輸出的,basepackage是包過濾配置。
比如開發環境中需要打印debug級別以上的日誌,但是又想使除我寫的logger之外的DEBUG不打印,可過濾到本項目的包名才用DEBUG打印,此外包名使用INFO級別打印,在application.yml中新建這三項配置,也可在不同環境配置不同屬性
#應用配置
resources:
# log文件寫入地址
logdir: logs/
# 應用名稱
appname: spring-boot-example
# 日誌打印的基礎掃描包
basepackage: com.spring.demo.springbootexample
使用不同環境啓動測試logger配置是否生效,在開發環境下將打印DEBUG級別以上的四條logger記錄,在演示環境下降打印INFO級別以上的三條記錄並寫入文件,在生產環境下只打印ERROR級別以上的一條記錄並寫入文件
@RequestMapping("/logger")
@ResponseBody
public WebResult logger() {
logger.trace("日誌輸出 {}", "trace");
logger.debug("日誌輸出 {}", "debug");
logger.info("日誌輸出 {}", "info");
logger.warn("日誌輸出 {}", "warn");
logger.error("日誌輸出 {}", "error");
return "00";
}
常用配置
加載自定義配置
@Component
@PropertySource(value = {"classpath:application.yml"}, encoding = "utf-8")
public class Config {
@Value("${resources.midpHost}")
private String midpHost;
public String getMidpHost() {
return midpHost;
}
}
全局異常處理器
@ControllerAdvice
public class GlobalExceptionResolver {
Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public WebResult exceptionHandle(HttpServletRequest req, Exception ex) {
ex.printStackTrace();
logger.error("未知異常", ex);
return WebResult.error(ERRORDetail.RC_0401001);
}
}
示例工程開源地址
https://github.com/calebman/spring-boot-example
推薦閱讀:
《
《
《
《
《