SpringBoot_第二天
學習目標
Mybatis整合&數據訪問
使用SpringBoot開發企業項目時,持久層數據訪問是前端頁面數據展示的基礎,SpringBoot支持市面上常見的關系庫產品(Oracle,Mysql,SqlServer,DB2等)對應的相關持久層框架,當然除了對于關系庫訪問的支持,也支持當下眾多的非關系庫(Redis,Solr,MongoDB等)數據訪問操作,這里主要介紹SpringBoot集成Mybatis并實現持久層數據基本增刪改查操作。
SpringBoot 整合Mybatis
環境整合配置
Idea 下創建Maven 普通工程 springboot_mybatis
pom.xml 添加核心依賴
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
?
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<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>2.1.1</version>
</dependency>
<!-- springboot分頁插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.13</version>
</dependency>
?
<!--mysql 驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
</dependencies>
?
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
application.yml 整合配置
## 端口號
server:
? port: 9999
?
## 數據源配置
spring:
? datasource:
?? type: com.mchange.v2.c3p0.ComboPooledDataSource
?? driver-class-name: com.mysql.cj.jdbc.Driver
?? url: jdbc:mysql://127.0.0.1:3306/springboot_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
?? username: root
?? password: root
?
## mybatis 配置
mybatis:
? mapper-locations: classpath:/mappers/*.xml
? type-aliases-package: com.xxxx.springboot.vo
? configuration:
## 下劃線轉駝峰配置
?? map-underscore-to-camel-case: true
?
## pageHelper
pagehelper:
? helper-dialect: mysql
#顯示dao 執行sql語句
logging:
? level:
?? com:
? ?? xxxx:
? ? ?? springboot:
? ? ? ?? dao: debug
源代碼添加
Dao層接口方法定義
com.xxxx.springboot.dao 包下創建UserDao.java 接口聲明查詢方法
packagecom.xxxx.springboot.dao;
?
importcom.xxxx.springboot.vo.User;
?
publicinterfaceUserMapper{
? ? // 根據用戶名查詢用戶記錄
UserqueryUserByUserName(StringuserName);
}
SQL映射文件添加
resources/mappers 目錄下添加UserMapper.xml 配置查詢statetment
<?xmlversion="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mappernamespace="com.xxxx.springboot.dao.UserMapper">
<selectid="queryUserByUserName"parameterType="string"resultType="com.xxxx.springboot.vo.User">
? ? ?? select
? ? ?? id,user_name,user_pwd
? ? ?? from t_user
? ? ?? where user_name=#{userName}
</select>
</mapper>
添加service 、controller 對應代碼
UserService.java
@Service
publicclassUserService{
@Autowired
privateUserMapperuserMapper;
?
publicUserqueryUserByUserName(StringuserName){
returnuserMapper.queryUserByUserName(userName);
?? }
}
UserController.java
@RestController
publicclassUserController{
?
@Resource
privateUserServiceuserService;
?
?
@GetMapping("user/{userName}")
publicUserqueryUserByUserName(@PathVariableStringuserName){
returnuserService.queryUserByUserName(userName);
?? }
}
添加應用啟動入口
@SpringBootApplication
@MapperScan("com.xxxx.springboot.dao")
publicclassStarter{
?
publicstaticvoidmain(String[]args) {
SpringApplication.run(Starter.class);
?? }
}
啟動測試
運行Starter? main方法,啟動應用瀏覽器測試查詢
后端日志打印效果:
SpringBoot數據訪問操作
完成SpringBoot 與Mybatis 集成后,接下來以用戶表為例實現一套用戶模塊基本數據維護。
接口方法 & Sql映射文件
UserDao 接口方法定義
UserDao 接口添加數據訪問基本方法
publicinterfaceUserMapper{
?
publicUserqueryById(Integerid);
?
UserqueryUserByUserName(StringuserName);
?
publicintsave(Useruser);
?
publicintupdate(Useruser);
?
publicList<User>selectByParams(UserQueryuserQuery);
?
}
UserMapper.xml 映射文件配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xxxx.springboot.dao.UserMapper">
? ? <select id="queryById" parameterType="int" resultType="com.xxxx.springboot.vo.User">
? ? ? ? select *
? ? ? ? from t_user
? ? ? ? where id = #{id,jdbcType=INTEGER}
? ? </select>
? ? <select id="queryUserByUserName" parameterType="string" resultType="com.xxxx.springboot.vo.User">
? ? ? ? select *
? ? ? ? from t_user
? ? ? ? where user_name=#{userName}
? ? </select>
? ? <insert id="save" parameterType="com.xxxx.springboot.vo.User" useGeneratedKeys="true" keyProperty="id">
? ? ? ? insert into t_user(id,user_name,user_pwd) values(#{id},#{userName},#{userPwd})
? ? </insert>
? ? <update id="update" parameterType="com.xxxx.springboot.vo.User">
? ? ? ? update t_user set user_name =#{userName},user_pwd=#{userPwd}
? ? ? ? where id = #{id}
? ? </update>
? ? <select id="selectByParams" parameterType="com.xxxx.springboot.query.UserQuery" resultType="com.xxxx.springboot.vo.User">
? ? ? ? select *
? ? ? ? from t_user
? ? ? ? <where>
? ? ? ? ? ? <if test="null !=userName and userName !=''">
? ? ? ? ? ? ? ? and user_name like concat('%',#{userName},'%')
? ? ? ? ? ? </if>
? ? ? ? </where>
? ? </select>
</mapper>
UserService.java方法實現
public User queryUserByUserName(String userName){
? ? return userMapper.queryUserByUserName(userName);
}
public User queryUserByUserId(Integer userId){
? ? return userMapper.queryById(userId);
}
public void saveUser(User user) {
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "用戶名不能為空!");
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"用戶密碼不能為空!");
? ? User temp = userMapper.queryUserByUserName(user.getUserName());
? ? AssertUtil.isTrue(null != temp, "該用戶已存在!");
? ? AssertUtil.isTrue(userMapper.save(user)<1,"用戶記錄添加失敗!");
}
public void updateUser(User user) {
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "用戶名不能為空!");
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"用戶密碼不能為空!");
? ? User temp = userMapper.queryUserByUserName(user.getUserName());
? ? AssertUtil.isTrue(null != temp && !(temp.getId().equals(user.getId())), "該用戶已存在!");
? ? AssertUtil.isTrue(userMapper.update(user)<1,"用戶記錄添加失敗!");
}
public? void deleteUser(Integer id){
? ? AssertUtil.isTrue(null == id || null ==userMapper.queryById(id),"待刪除記錄不存在!");
? ? AssertUtil.isTrue(userMapper.delete(id)<1,"用戶刪除失敗!");
}
public PageInfo<User> queryUserByParams(UserQuery userQuery){
? ? PageHelper.startPage(userQuery.getPageNum(),userQuery.getPageSize());
? ? return new PageInfo<User>(userMapper.selectByParams(userQuery));
}
UserController.java 接口方法
@GetMapping("user/{userId}")
public User queryUserByUserId(@PathVariable? Integer userId){
? ? return userService.queryUserByUserId(userId);
}
@GetMapping("user/list")
public PageInfo<User> list(UserQuery userQuery){
? ? return userService.queryUserByParams(userQuery);
}
@PutMapping("user")
public ResultInfo saveUser(User user){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.saveUser(user);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄添加失敗!");
? ? }
? ? return resultInfo;
}
@PostMapping("user")
public ResultInfo updateUser(User user){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.updateUser(user);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄更新失敗!");
? ? }
? ? return resultInfo;
}
@DeleteMapping("user/{userId}")
public ResultInfo deleteUser(@PathVariable? Integer? userId){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.deleteUser(userId);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄刪除失敗!");
? ? }
? ? return resultInfo;
}
PostMan 接口測試工具下載與使用
在企業web 應用開發中,對服務器端接口進行測試,通常借助接口測試工具,這里使用Postman 接口測試工具來對后臺restful接口進行測試,Postman 工具下載地址: https://www.getpostman.com/apps 選中對應平臺下載即可。
下載安裝后,啟動Postman 根據后臺接口地址發送響應請求即可對接口進行測試。
API 文檔構建工具-Swagger2
由于Spring Boot能夠快速開發、便捷部署等特性,通常在使用Spring Boot構建Restful 接口應用時考慮到多終端的原因,這些終端會共用很多底層業務邏輯,因此我們會抽象出這樣一層來同時服務于多個移動端或者Web前端。對于不同的終端公用一套接口API時對于聯調測試時就需要知道后端提供的接口Api 列表文檔,對于服務端開發人員來說就需要編寫接口文檔,描述接口調用地址參數結果等,這里借助第三方構建工具Swagger2來實現Api文檔生成功能。
環境整合配置
pom.xml 依賴添加
<dependency>
? <groupId>io.springfox</groupId>
? <artifactId>springfox-swagger2</artifactId>
? <version>2.9.2</version>
</dependency>
<dependency>
? <groupId>io.springfox</groupId>
? <artifactId>springfox-swagger-ui</artifactId>
? <version>2.9.2</version>
</dependency>
配置類添加
@Configuration
@EnableSwagger2
public class Swagger2 {
? ? @Bean
? ? public Docket createRestApi() {
? ? ? ? return new Docket(DocumentationType.SWAGGER_2)
? ? ? ? ? ? ? ? .apiInfo(apiInfo())
? ? ? ? ? ? ? ? .select()
? ? ? ? ? ? ? ? .apis(RequestHandlerSelectors.basePackage("com.xxxx.springboot.controller"))
? ? ? ? ? ? ? ? .paths(PathSelectors.any())
? ? ? ? ? ? ? ? .build();
? ? }
? ? private ApiInfo apiInfo() {
? ? ? ? return new ApiInfoBuilder()
? ? ? ? ? ? ? ? .title("用戶管理接口API文檔參考")
? ? ? ? ? ? ? ? .version("1.0")
? ? ? ? ? ? ? ? .build();
? ? }
}
Swagger2 常用注解說明
@Api
@Api:用在請求的類上,說明該類的作用
? ? tags="說明該類的作用"
@Api(tags="APP用戶注冊Controller")
@ApiOperation
@ApiOperation:"用在請求的方法上,說明方法的作用"
? ? value="說明方法的作用"
? ? notes="方法的備注說明"
@ApiOperation(value="用戶注冊",notes="手機號、密碼都是必輸項,年齡隨邊填,但必須是數字")
@ApiImplicitParams
@ApiImplicitParams:用在請求的方法上,包含一組參數說明
? ? @ApiImplicitParam:用在 @ApiImplicitParams 注解中,指定一個請求參數的配置信息? ? ?
? ? ? ? name:參數名
? ? ? ? value:參數的漢字說明、解釋
? ? ? ? required:參數是否必須傳
? ? ? ? paramType:參數放在哪個地方
? ? ? ? ? ? · header --> 請求參數的獲取:@RequestHeader
? ? ? ? ? ? · query --> 請求參數的獲取:@RequestParam
? ? ? ? ? ? · path(用于restful接口)--> 請求參數的獲取:@PathVariable
? ? ? ? ? ? · body(不常用)
? ? ? ? ? ? · form(不常用)? ?
? ? ? ? dataType:參數類型,默認String,其它值dataType="Integer"? ? ?
? ? ? ? defaultValue:參數的默認值
@ApiImplicitParams({
? ? @ApiImplicitParam(name="mobile",value="手機號",required=true,paramType="form"),
? ? @ApiImplicitParam(name="password",value="密碼",required=true,paramType="form"),
? ? @ApiImplicitParam(name="age",value="年齡",required=true,paramType="form",dataType="Integer")
})
@ApiResponses
@ApiResponses:用于請求的方法上,表示一組響應
? ? @ApiResponse:用在@ApiResponses中,一般用于表達一個錯誤的響應信息
? ? ? ? code:數字,例如400
? ? ? ? message:信息,例如"請求參數沒填好"
? ? ? ? response:拋出異常的類
@ApiOperation(value = "select請求",notes = "多個參數,多種的查詢參數類型")
@ApiResponses({
? ? @ApiResponse(code=400,message="請求參數沒填好"),
? ? @ApiResponse(code=404,message="請求路徑沒有或頁面跳轉路徑不對")
})
@ApiModel
@ApiModel:用于響應類上,表示一個返回響應數據的信息
? ? ? ? ? ? (這種一般用在post創建的時候,使用@RequestBody這樣的場景,
? ? ? ? ? ? 請求參數無法使用@ApiImplicitParam注解進行描述的時候)
? ? @ApiModelProperty:用在屬性上,描述響應類的屬性
@ApiModel(description= "返回響應數據")
public class RestMessage implements Serializable{
? ? @ApiModelProperty(value = "是否成功")
? ? private boolean success=true;
? ? @ApiModelProperty(value = "返回對象")
? ? private Object data;
? ? @ApiModelProperty(value = "錯誤編號")
? ? private Integer errCode;
? ? @ApiModelProperty(value = "錯誤信息")
? ? private String message;
? ? /* getter/setter */
}
用戶模塊注解配置
UserController.java 接口方法注解使用
@GetMapping("user/uname/{userName}")
@ApiOperation(value = "根據用戶名查詢用戶記錄")
@ApiImplicitParam(name = "userName",value = "查詢參數",required = true,paramType = "path")
public User queryUserByUserName(@PathVariable String userName){
? ? return userService.queryUserByUserName(userName);
}
@ApiOperation(value = "根據用戶id查詢用戶記錄")
@ApiImplicitParam(name = "userId",value = "查詢參數",required = true,paramType = "path")
@GetMapping("user/{userId}")
public User queryUserByUserId(@PathVariable? Integer userId, HttpServletRequest request){
? ? return userService.queryUserByUserId(userId);
}
@GetMapping("user/list")
@ApiOperation(value = "多條件查詢用戶列表記錄")
public PageInfo<User> list(UserQuery userQuery){
? ? return userService.queryUserByParams(userQuery);
}
@PutMapping("user")
@ApiOperation(value = "用戶添加")
@ApiImplicitParam(name = "user",value = "用戶實體類",dataType = "User")
public ResultInfo saveUser(@RequestBody? User user){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.saveUser(user);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄添加失敗!");
? ? }
? ? return resultInfo;
}
@PostMapping("user")
@ApiOperation(value = "用戶更新")
@ApiImplicitParam(name = "user",value = "用戶實體類",dataType = "User")
public ResultInfo updateUser(@RequestBody? User user){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.updateUser(user);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄更新失敗!");
? ? }
? ? return resultInfo;
}
@PutMapping("user/{userId}")
@ApiOperation(value = "根據用戶id刪除用戶記錄")
@ApiImplicitParam(name = "userId",value = "查詢參數",required = true,paramType = "path")
public ResultInfo deleteUser(@PathVariable? Integer? userId){
? ? ResultInfo resultInfo=new ResultInfo();
? ? try {
? ? ? ? userService.deleteUser(userId);
? ? } catch (ParamsException e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(e.getCode());
? ? ? ? resultInfo.setMsg(e.getMsg());
? ? }catch (Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("記錄刪除失敗!");
? ? }
? ? return resultInfo;
}
JavaBean 使用
User.java
@ApiModel(description = "響應結果-用戶信息")
public class User {
? ? @ApiModelProperty(value = "用戶id",example = "0")
? ? private Integer id;
? ? @ApiModelProperty(value = "用戶名")
? ? private String userName;
? ? @ApiModelProperty(value = "用戶密碼")
? ? private String userPwd;
? ? /*
? ? ? 省略get|set
? ? */
}
UserQuery.java
@ApiModel(description = "用戶模塊條件查詢類")
public class UserQuery {
? ? @ApiModelProperty(value = "分頁頁碼",example = "1")
? ? private Integer pageNum=1;
? ? @ApiModelProperty(value = "每頁大小",example = "10")
? ? private Integer pageSize=10;
? ? @ApiModelProperty(value = "用戶名")
? ? private String userName;
? ? /*
? ? ? 省略get|set
? ? */
}
ResultInfo.java
@ApiModel(description = "響應結果-Model信息")
public class ResultInfo {
? ? @ApiModelProperty(value = "響應狀態碼",example = "200")
? ? private Integer code=200;
? ? @ApiModelProperty(value = "響應消息結果")
? ? private String msg="success";
? ? @ApiModelProperty(value = "響應具體結果信息")
? ? private Object result;
? ? /*
? ? ? 省略get|set
? ? */
}
Swagger2 接口文檔訪問
啟動工程,瀏覽器訪問:http://localhost:9999/swagger-ui.html
SpringBoot應用熱部署
什么是熱部署?
熱部署,就是在應用正在運行的時候升級軟件(增加業務/修改bug),卻不需要重新啟動應用
大家都知道在項目開發過程中,常常會改動頁面數據或者修改數據結構,為了顯示改動效果,往往需要重啟應用查看改變效果,其實就是重新編譯生成了新的 Class 文件,這個文件里記錄著和代碼等對應的各種信息,然后 Class 文件將被虛擬機的 ClassLoader 加載。
而熱部署正是利用了這個特點,它監聽到如果有 Class 文件改動了,就會創建一個新的 ClaassLoader 進行加載該文件,經過一系列的過程,最終將結果呈現在我們眼前,Spring Boot通過配置DevTools? 工具來達到熱部署效果。
在原理上是使用了兩個ClassLoader,一個Classloader加載那些不會改變的類(第三方Jar包),另一個ClassLoader加載會更改的類,稱為restart ClassLoader,這樣在有代碼更改的時候,原來的restart ClassLoader 被丟棄,重新創建一個restart ClassLoader,由于需要加載的類相比較少,所以實現了較快的重啟時間。
熱部署環境配置與測試
配置 DevTools 環境
修改 Pom 文件,添加 DevTools 依賴
<!-- DevTools 的坐標 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
? ? <!--當前這個項目被繼承之后,這個不向下傳遞-->
<optional>true</optional>
</dependency>
同時在plugin中添加devtools生效標志
<plugin>
? <groupId>org.springframework.boot</groupId>
? <artifactId>spring-boot-maven-plugin</artifactId>
? <configuration>
? ? ? <fork>true</fork><!-- 如果沒有該配置,熱部署的devtools不生效 -->
? </configuration>
</plugin>
devtools可以實現頁面熱部署(即頁面修改后會立即生效,這個可以直接在application.properties文件中配置spring.thymeleaf.cache=false來實現),實現類文件熱部署(類文件修改后不會立即生效),實現對屬性文件的熱部署。即devtools會監聽classpath下的文件變動,并且會立即重啟應用(發生在保存時機),注意:因為其采用的虛擬機機制,該項重啟是很快的。?配置了后在修改java文件后也就支持了熱啟動,不過這種方式是屬于項目重啟(速度比較快的項目重啟),會清空session中的值,也就是如果有用戶登陸的話,項目重啟后需要重新登陸。
默認情況下,/META-INF/maven,/META-INF/resources,/resources,/static,/templates,/public這些文件夾下的文件修改不會使應用重啟,但是會重新加載(devtools內嵌了一個LiveReload server,當資源發生改變時,瀏覽器刷新)
全局配置文件配置
在application.yml中配置spring.devtools.restart.enabled=false,此時restart類加載器還會初始化,但不會監視文件更新。
spring:
? ## 熱部署配置
? devtools:
? ? restart:
? ? ? enabled: true
? ? ? # 設置重啟的目錄,添加目錄的文件需要restart
? ? ? additional-paths: src/main/java
? ? ? # 解決項目自動重新編譯后接口報404的問題
? ? ? poll-interval: 3000
? ? ? quiet-period: 1000
Idea 配置
當我們修改了Java類后,IDEA默認是不自動編譯的,而spring-boot-devtools又是監測classpath下的文件發生變化才會重啟應用,所以需要設置IDEA的自動編譯
自動編譯配置
File-Settings-Compiler-Build Project automatically
Registry 屬性修改
ctrl + shift + alt + /,選擇Registry,勾上 Compiler autoMake allow when app running
熱部署效果測試
第一次訪問 user/uname/{uname} 接口
@GetMapping("user/uname/{userName}")
@ApiOperation(value = "根據用戶名查詢用戶記錄")
@ApiImplicitParam(name = "userName",value = "查詢參數",required = true,paramType = "path")
public User queryUserByUserName(@PathVariable String userName){
? ? return userService.queryUserByUserName(userName);
}
修改接口代碼 控制臺打印接收的uname參數 ctrl+f9 鍵重新編譯 瀏覽器訪問
@GetMapping("user/uname/{userName}")
@ApiOperation(value = "根據用戶名查詢用戶記錄")
@ApiImplicitParam(name = "userName",value = "查詢參數",required = true,paramType = "path")
public User queryUserByUserName(@PathVariable String userName){
? ? System.out.println("查詢參數-->userName:"+userName);
? ? return userService.queryUserByUserName(userName);
}
SpringBoot單元測試
做過web項目開發的對于單元測試都并不陌生了,通過它能夠快速檢測業務代碼功能的正確與否,SpringBoot框架對單元測試也提供了良好的支持,來看SpringBoot應用中單元測試的使用。
pom.xml 測試依賴添加
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-test</artifactId>
</dependency>
Service業務方法測試
這里以UserService為例,src/tets/java 目錄下添加測試包 com.xxxx.sprinboot.service 定義測試類代碼如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
public class TestUserService {
? ? private Logger log = LoggerFactory.getLogger(TestUserService.class);
? ? @Resource
? ? private UserService userService;
? ? @Before
? ? public void before(){
? ? ? ? log.info("單元測試開始...");
? ? }
? ? @Test
? ? public? void test01(){
? ? ? ? log.info(userService.queryUserByUserId(10).toString());
? ? }
? ? @Test
? ? public? void test02(){
? ? ? ? log.info(userService.queryUserByParams(new UserQuery()).toString());
? ? }
? ? @After
? ? public void after(){
? ? ? ? log.info("單元測試結束...");
? ? }
}
控制層接口方法測試
視圖層代碼使用MockMvc 進行測試,這里以UserCntroller 為例,src/tets/java 目錄下添加測試包 com.xxxx.sprinboot.controller 定義測試類代碼如下:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Starter.class})
@AutoConfigureMockMvc
public class TestUserController {
? ? private Logger log = LoggerFactory.getLogger(TestUserController.class);
? ? @Autowired
? ? private MockMvc mockMvc;
? ? //用戶列表查詢
? ? @Test
? ? public void apiTest01()throws Exception{
? ? ? ? MvcResult mvcResult=mockMvc.perform(MockMvcRequestBuilders.get("/user/list")).
? ? ? ? ? ? ? ? andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
? ? ? ? log.info("響應狀態:{}",mvcResult.getResponse().getStatus());
? ? ? ? log.info("響應內容:{}",mvcResult.getResponse().getContentAsString());;
? ? }
? ? // 用戶名記錄查詢
? ? @Test
? ? public void apiTest02()throws Exception{
? ? ? ? MvcResult mvcResult=mockMvc.perform(MockMvcRequestBuilders.get("/user/uname/admin")).
? ? ? ? ? ? ? ? andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
? ? ? ? log.info("響應狀態:{}",mvcResult.getResponse().getStatus());
? ? ? ? log.info("響應內容:{}",mvcResult.getResponse().getContentAsString());;
? ? }
}
分布式緩存Ehcache整合
EhCache是一個比較成熟的Java緩存框架,最早從hibernate發展而來, 是進程中的緩存系統,它提供了用內存,磁盤文件存儲,以及分布式存儲方式等多種靈活的cache管理方案,快速簡單。
Spring Boot對Ehcache的使用提供支持,所以在Spring Boot中只需簡單配置即可使用Ehcache實現數據緩存處理。
Spring Cache 相關注解說明
SpringBoot 內部使用SpringCache 來實現緩存控制,這里集成Ehcache實際上是對SpringCache 抽象的其中一種實現,這里在使用Ehcache實現緩存控制時相關注解說明如下
@CacheConfig
用于標注在類上,可以存放該類中所有緩存的公有屬性,比如設置緩存的名字。
@CacheConfig(cacheNames = "users")
public class UserService {。。。}
這里也可以不使用該注解,直接使用@Cacheable配置緩存集的名字。
@Cacheable
應用到讀取數據的方法上,即可緩存的方法,如查找方法,先從緩存中讀取,如果沒有再調用相應方法獲取數據,然后把數據添加到緩存中。
該注解主要有下面幾個參數:
value、cacheNames:兩個等同的參數(cacheNames為Spring 4新增,作為value的別名),用于指定緩存存儲的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必須有的value屬性,也成為非必需項了
key:緩存對象存儲在Map集合中的key值,非必需,缺省按照函數的所有參數組合作為key值,若自己配置需使用SpEL表達式,比如:@Cacheable(key = "#p0"):使用函數第一個參數作為緩存的key值,更多關于SpEL表達式的詳細內容可參考官方文檔
condition:緩存對象的條件,非必需,也需使用SpEL表達式,只有滿足表達式條件的內容才會被緩存,比如:@Cacheable(key = "#p0", condition = "#p0.length() < 3"),表示只有當第一個參數的長度小于3的時候才會被緩存。
unless:另外一個緩存條件參數,非必需,需使用SpEL表達式。它不同于condition參數的地方在于它的判斷時機,該條件是在函數被調用之后才做判斷的,所以它可以通過對result進行判斷。
keyGenerator:用于指定key生成器,非必需。若需要指定一個自定義的key生成器,我們需要去實現org.springframework.cache.interceptor.KeyGenerator接口,并使用該參數來指定。需要注意的是:該參數與key是互斥的
cacheManager:用于指定使用哪個緩存管理器,非必需。只有當有多個時才需要使用
cacheResolver:用于指定使用那個緩存解析器,非必需。需通過org.springframework.cache.interceptor.CacheResolver接口來實現自己的緩存解析器,并用該參數指定。
@Cacheable(value = "user", key = "#id")
User selectUserById(final Integer id);
@CachePut
應用到寫數據的方法上,如新增/修改方法,調用方法時會自動把相應的數據放入緩存,@CachePut的參數與@Cacheable類似,示例如下:
@CachePut(value = "user", key = "#user.id")?
public User save(User user) {?
? ? users.add(user);?
? ? return user;?
}?
@CacheEvict
應用到移除數據的方法上,如刪除方法,調用方法時會從緩存中移除相應的數據,示例如下:
@CacheEvict(value = "user", key = "#id")
void delete(final Integer id);
除了同@Cacheable一樣的參數之外,@CacheEvict還有下面兩個參數:
allEntries:非必需,默認為false。當為true時,會移除所有數據
beforeInvocation:非必需,默認為false,會在調用方法之后移除數據。當為true時,會在調用方法之前移除數據。
@Caching
組合多個Cache注解使用。示例:
@Caching(
? ? put = {
? ? ? ? @CachePut(value = "user", key = "#user.id"),
? ? ? ? @CachePut(value = "user", key = "#user.username"),
? ? ? ? @CachePut(value = "user", key = "#user.age")
? }
}
將id-->user;username--->user;age--->user進行緩存。
用戶管理模塊緩存引入
環境配置
pom.xml 依賴添加
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Ehcache 坐標 -->
<dependency>
? ? <groupId>net.sf.ehcache</groupId>
? ? <artifactId>ehcache</artifactId>
</dependency>
ehcahe.xml 文件添加
src/main/resources 目錄下添加ehcache.xml 文件,內容如下:
<ehcache name="mycache">
? ? <diskStore path="C:\java\cache"/>
? ? <!--
? ? ? ? name:緩存名稱。
? ? ? ? maxElementsInMemory:緩存最大數目
? ? ? ? maxElementsOnDisk:硬盤最大緩存個數。
? ? ? ? eternal:對象是否永久有效,一但設置了,timeout將不起作用。
? ? ? ? overflowToDisk:是否保存到磁盤,當系統宕機時
? ? ? ? timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。
? ? ? ? ? ? ? 僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。
? ? ? ? timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。
? ? ? ? ? ? 最大時間介于創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
? ? ? ? diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
? ? ? ? diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩沖區。
? ? ? ? diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
? ? ? ? memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。
? ? ? ? ? ? 默認策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。
? ? ? ? clearOnFlush:內存數量最大時是否清除。
? ? ? ? memoryStoreEvictionPolicy:可選策略有:LRU(最近最少使用,默認策略)、FIFO(先進先出)、LFU(最少訪問次數)。
? ? ? ? ? ? FIFO,first in first out,這個是大家最熟的,先進先出。
? ? ? ? ? ? LFU, Less Frequently Used,最近最少被訪問的。
? ? ? ? ? ? LRU,Least Recently Used,最近最少使用的,緩存的元素有一個時間戳,
? ? ? ? ? ? ? 當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那么現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存。
? ? ? ? -->
? ? <defaultCache
? ? ? ? ? ? maxElementsInMemory="10000"
? ? ? ? ? ? eternal="false"
? ? ? ? ? ? timeToIdleSeconds="120"
? ? ? ? ? ? timeToLiveSeconds="120"
? ? ? ? ? ? maxElementsOnDisk="10000000"
? ? ? ? ? ? diskExpiryThreadIntervalSeconds="120"
? ? ? ? ? ? memoryStoreEvictionPolicy="LRU">
? ? </defaultCache>
? ? <cache
? ? ? ? ? ? name="users"
? ? ? ? ? ? eternal="false"
? ? ? ? ? ? maxElementsInMemory="100"
? ? ? ? ? ? overflowToDisk="false"
? ? ? ? ? ? diskPersistent="false"
? ? ? ? ? ? timeToIdleSeconds="0"
? ? ? ? ? ? timeToLiveSeconds="300"
? ? ? ? ? ? memoryStoreEvictionPolicy="LRU"/>
</ehcache>
application.yml 添加緩存配置
spring:
? datasource:
? ? type: com.mchange.v2.c3p0.ComboPooledDataSource
? ? driver-class-name: com.mysql.cj.jdbc.Driver
? ? url: jdbc:mysql://127.0.0.1:3306/springboot_mybatis?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
? ? username: root
? ? password: root
? devtools:
? ? restart:
? ? ? enabled: true
? ? ? # 設置重啟的目錄,添加目錄的文件需要restart
? ? ? additional-paths: src/main/java
? ? ? # 解決項目自動重新編譯后接口報404的問題
? ? ? poll-interval: 3000
? ? ? quiet-period: 1000
? cache:
? ? ehcache:
? ? ? config: classpath:ehcahe.xml
Starter 啟動入口類啟動緩存
@MapperScan("com.xxxx.springboot.dao")
@EnableCaching
@SpringBootApplication
public class Starter {
? ? public static void main(String[] args) {
? ? ? ? SpringApplication.run(Starter.class);
? ? }
}
緩存User 對象實現序列化接口
@ApiModel(description = "用戶實體對象")
public class User implements Serializable {
? ? @ApiModelProperty(value = "用戶id主鍵")
? ? private Integer id;
? ? @ApiModelProperty(value = "用戶名")
? ? private String userName;
? ? @ApiModelProperty(value = "用戶密碼")
? ? private String userPwd;
? ? /*
? ? ? 省略 get|set方法
? ? */
}
緩存代碼添加
這里以UserService 方法為例
用戶詳情查詢緩存添加
@Cacheable(value = "users",key = "#userId")
public User queryUserByUserId(Integer userId){
? ? return userMapper.queryById(userId);
}
用戶列表查詢緩存
@Cacheable(value = "users",key="#userQuery.userName+'-'+#userQuery.pageNum+'-'+#userQuery.pageSize")
public PageInfo<User> queryUserByParams(UserQuery userQuery){
? ? PageHelper.startPage(userQuery.getPageNum(),userQuery.getPageSize());
? ? return new PageInfo<User>(userMapper.selectByParams(userQuery));
}
用戶更新&刪除緩存清除
@Transactional(propagation = Propagation.REQUIRED)
@CacheEvict(value = "users",key="#user.id")
public void updateUser(User user) {
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "用戶名不能為空!");
? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"用戶密碼不能為空!");
? ? User temp = userMapper.queryUserByUserName(user.getUserName());
? ? AssertUtil.isTrue(null != temp && !(temp.getId().equals(user.getId())), "該用戶已存在!");
? ? AssertUtil.isTrue(userMapper.update(user)<1,"用戶記錄添加失敗!");
}
@Transactional(propagation = Propagation.REQUIRED)
@CacheEvict(value = "users",allEntries=true)
public? void deleteUser(Integer userId){
? ? AssertUtil.isTrue(null == userId || null ==userMapper.queryById(userId),"待刪除記錄不存在!");
? ? AssertUtil.isTrue(userMapper.delete(userId)<1,"用戶刪除失敗!");
}
定時調度集成-Quartz
在日常項目運行中,我們總會有需求在某一時間段周期性的執行某個動作。比如每天在某個時間段導出報表,或者每隔多久統計一次現在在線的用戶量等。
在Spring Boot中有Java自帶的java.util.Timer類,SpringBoot自帶的Scheduled來實現,也有強大的調度器Quartz。Scheduled 在Spring3.X 引入,默認SpringBoot自帶該功能,使用起來也很簡單,在啟動類級別添加@EnableScheduling注解即可引入定時任務環境。但遺憾的是Scheduled? 默認不支持分布式環境,這里主要講解Quartz 時鐘調度框架與Spring Boot 集成。
環境整合配置
<dependency>
? ? <groupId>org.springframework.boot</groupId>
? ? <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
源代碼添加
定義job
com.xxxx.springboot下添加jobs包,定義待執行job任務
public class MyFirstJob implements Job {
? ? private Logger log = LoggerFactory.getLogger(MyFirstJob.class);
? ? @Override
? ? public void execute(JobExecutionContext context) throws JobExecutionException {
? ? ? ? SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
? ? ? ? TriggerKey triggerKey =? context.getTrigger().getKey();
? ? ? ? log.info("觸發器:"+triggerKey.getName()+"-->所屬組:"+triggerKey.getGroup()+"-->"+sdf.format(new Date())+"-->"+"hello Spring Boot Quartz...");
? ? }
}
構建調度配置類
@Configuration
public class QuartzConfig {
? ? @Bean
? ? public JobDetail jobDetail1(){
? ? ? ? return JobBuilder.newJob(MyFirstJob.class).storeDurably().build();
? ? }
? ? @Bean
? ? public Trigger trigger1(){
? ? ? ? SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
? ? ? ? ? ? ? ? //每一秒執行一次
? ? ? ? ? ? ? ? .withIntervalInSeconds(1)
? ? ? ? ? ? ? ? //永久重復,一直執行下去
? ? ? ? ? ? ? ? .repeatForever();
? ? ? ? return TriggerBuilder.newTrigger()
? ? ? ? ? ? ? ? .withIdentity("trigger1","group1")
? ? ? ? ? ? ? ? .withSchedule(scheduleBuilder)
? ? ? ? ? ? ? ? .forJob(jobDetail1())
? ? ? ? ? ? ? ? .build();
? ? }
? ? // 每兩秒觸發一次任務
? ? @Bean
? ? public Trigger trigger2(){
? ? ? ? return TriggerBuilder.newTrigger()
? ? ? ? ? ? ? ? .withIdentity("trigger2", "group1")
? ? ? ? ? ? ? ? .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"))
? ? ? ? ? ? ? ? .forJob(jobDetail1())
? ? ? ? ? ? ? ? .build();
? ? }
}
啟動StarterApplication 查看控制臺打印效果
全局異常與事物控制
Spring Boot事物支持
在使用Jdbc 作為數據庫訪問技術時,Spring Boot框架定義了基于jdbc 的PlatformTransactionManager 接口的實現DataSourceTransactionManager,并在Spring Boot 應用啟動時自動進行配置。如果使用jpa 的話 Spring Boot 同樣提供了對應實現。
這里Spring Boot 集成了Mybatis框架,Mybatis底層數據訪問層實現基于jdbc 來實現,所以在Spring Boot 環境下對事物進行控制,事物實現由Spring Boot實現并自動配置,在使用時通過注解方式標注相關方法加入事物控制即可
聲明式事物配置
@Transactional(propagation = Propagation.REQUIRED)
? ? public void saveUser(User user) {
? ? ? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "用戶名不能為空!");
? ? ? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"用戶密碼不能為空!");
? ? ? ? User temp = userMapper.queryUserByUserName(user.getUserName());
? ? ? ? AssertUtil.isTrue(null != temp, "該用戶已存在!");
? ? ? ? AssertUtil.isTrue(userMapper.save(user)<1,"用戶記錄添加失敗!");
? ? }
? ? @Transactional(propagation = Propagation.REQUIRED)
? ? public void updateUser(User user) {
? ? ? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserName()), "用戶名不能為空!");
? ? ? ? AssertUtil.isTrue(StringUtils.isBlank(user.getUserPwd()),"用戶密碼不能為空!");
? ? ? ? User temp = userMapper.queryUserByUserName(user.getUserName());
? ? ? ? AssertUtil.isTrue(null != temp && !(temp.getId().equals(user.getId())), "該用戶已存在!");
? ? ? ? AssertUtil.isTrue(userMapper.update(user)<1,"用戶記錄添加失敗!");
? ? }
? ? @Transactional(propagation = Propagation.REQUIRED)
? ? public? void deleteUser(Integer id){
? ? ? ? AssertUtil.isTrue(null == id || null ==userMapper.queryById(id),"待刪除記錄不存在!");
? ? ? ? AssertUtil.isTrue(userMapper.delete(id)<1,"用戶刪除失敗!");
? ? }
Spring Boot 全局異常處理
SpringMvc 中對異常統一處理提供了相應處理方式,推薦大家使用的是實現接口HandlerExceptionResolver的方式,對代碼侵入性較小。
在Spring Boot 應用中同樣提供了對異常的全局性處理,相關注解如下:
@ControllerAdvice
該注解組合了@Component注解功能,最常用的就是作為全局異常處理的切面類,同時通過該注解可以指定包掃描的范圍。@ControllerAdvice約定了幾種可行的返回值,如果是直接返回model類的話,需要使用@ResponseBody進行json轉換
@ExceptionHandler
? 該注解在Spring 3.X 版本引入,在處理異常時標注在方法級別,代表當前方法處理的異常類型有哪些 具體應用以Restful 接口為例,測試保存用戶接口
全局異常應用
異常拋出與全局捕捉
UserController 查詢接口
@ApiOperation(value = "根據用戶id查詢用戶記錄")
@ApiImplicitParam(name = "userId",value = "查詢參數",required = true,paramType = "path")
@GetMapping("user/{userId}")
public User queryUserByUserId(@PathVariable? Integer userId){
? ? return userService.queryUserByUserId(userId);
}
UserService 查詢業務方法,拋出ParamExceptions 異常
public User queryUserByUserId(Integer userId){
? ? AssertUtil.isTrue(true,"異常測試...");
? ? return userMapper.queryById(userId);
}
全局異常處理類GlobalExceptionHandler定義
@ControllerAdvice
public class GlobalExceptionHandler{
? ? /**
? ? * 全局異常處理 返回json
? ? * @param e
? ? * @return
? ? */
? ? @ExceptionHandler(value = Exception.class)
? ? @ResponseBody
? ? public ResultInfo exceptionHandler(Exception e){
? ? ? ? ResultInfo resultInfo=new ResultInfo();
? ? ? ? resultInfo.setCode(300);
? ? ? ? resultInfo.setMsg("操作失敗!");
? ? ? ? if(e instanceof ParamsException){
? ? ? ? ? ? ParamsException pe= (ParamsException) e;
? ? ? ? ? ? resultInfo.setMsg(pe.getMsg());
? ? ? ? ? ? resultInfo.setCode(pe.getCode());
? ? ? ? }
? ? ? ? return resultInfo;
? ? }
}
Postman 執行測試效果
特定異常處理
通過@ExceptionHandler 標注方法可以處理特定異常,這里以用戶未登錄異常為例,通過全局異常進行統一處理
/**
* 用戶未登錄異常特殊處理 返回json
* @param authExceptions
* @return
*/
@ExceptionHandler(value = NoLoginException.class)
@ResponseBody
public? ResultInfo userNotLoginHandler(NoLoginException authExceptions){
? ? System.out.println("用戶未登錄異常處理。。。");
? ? return new ResultInfo(authExceptions.getCode(),authExceptions.getMsg());
}
在用戶添加接口中拋出未登錄異常為例進行測試
@PutMapping("user")
@ApiOperation(value = "用戶添加")
@ApiImplicitParam(name = "user",value = "用戶實體類",dataType = "User")
public ResultInfo saveUser(@RequestBody? User user){
? ? if(1==1){
? ? ? ? throw? new NoLoginException();
? ? }
? ? ResultInfo resultInfo=new ResultInfo();
? ? ? ? userService.saveUser(user);
? ? return resultInfo;
}
SpringBoot 數據校驗-Validation
日常項目開發中,對于前端提交的表單,后臺接口接收到表單數據后,為了程序的嚴謹性,通常后端會加入業務參數的合法校驗操作來避免程序的非技術性bug,這里對于客戶端提交的數據校驗,SpringBoot通過spring-boot-starter-validation 模塊包含了數據校驗的工作。
這里主要介紹Spring Boot中對請求數據進行校驗,相關概念如下
JSR303/JSR-349: JSR303是一項標準,只提供規范不提供實現,規定一些校驗規范即校驗注解,如@Null,@NotNull,@Pattern,位于javax.validation.constraints包下。JSR-349是其升級版本,添加了一些新特性。
Hibernate Validation:Hibernate Validation是對這個規范的實現,并增加了一些其他校驗注解,如@Email,@Length,@Range等等
Spring Validation:Spring Validation對Hibernate Validation進行了二次封裝,在Spring Mvc模塊中添加了自動校驗,并將校驗信息封裝進了特定的類中
環境配置
實現參數校驗,程序必須引入spring-boot-starter-validation 依賴,只是在引入spring-boot-starter-web依賴時,該模塊會自動依賴spring-boot-starter-validation,所以程序中引入spring-boot-starter-web 會一并依賴spring-boot-starter-validation到項目中。
校驗相關注解
注解功能
@AssertFalse可以為null,如果不為null的話必須為false
@AssertTrue可以為null,如果不為null的話必須為true
@DecimalMax設置不能超過最大值
@DecimalMin設置不能超過最小值
@Digits設置必須是數字且數字整數的位數和小數的位數必須在指定范圍內
@Future日期必須在當前日期的未來
@Past日期必須在當前日期的過去
@Max最大不得超過此最大值
@Min最大不得小于此最小值
@NotNull不能為null,可以是空
@Pattern必須滿足指定的正則表達式
@Size集合、數組、map等的size()值必須在指定范圍內
@Email必須是email格式
@Length長度必須在指定范圍內
@NotBlank字符串不能為null,字符串trin()后也不能等于“”
@NotEmpty不能為null,集合、數組、map等size()不能為0;字符串trin()后可以等于“”
@Range值必須在指定范圍內
@URL必須是一個URL
參數校驗注解使用
User實體類參數校驗注解
public class User? implements Serializable {
? ? private Integer id;
? ? @NotBlank(message = "用戶名不能為空!")
? ? private String userName;
? ? @NotBlank(message = "用戶密碼不能為空!")
? ? @Length(min = 6, max = 10,message = "密碼長度至少6位但不超過10位!")
? ? private String userPwd;
? ? private String email;
? ? /*
? ? ? 省略get set 方法?
? ? */
}
接口方法形參@Valid注解添加
@PostMapping("user02")
@ApiOperation(value = "用戶添加")
@ApiImplicitParam(name = "user02",value = "用戶實體類",dataType = "User")
public ResultInfo saveUser02(@Valid? User user){
? ? ResultInfo resultInfo=new ResultInfo();
? ? //userService.saveUser(user);
? ? return resultInfo;
}
全局異常錯誤信息捕捉
/**
* 全局異常處理 返回json
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResultInfo exceptionHandler(Exception e){
? ? ResultInfo resultInfo=new ResultInfo();
? ? resultInfo.setCode(300);
? ? resultInfo.setMsg("操作失敗!");
? ? if(e instanceof ParamsException){
? ? ? ? ParamsException pe= (ParamsException) e;
? ? ? ? resultInfo.setMsg(pe.getMsg());
? ? ? ? resultInfo.setCode(pe.getCode());
? ? }else if(e instanceof BindException){
? ? ? ? BindException be = (BindException) e;
? ? ? ? resultInfo.setResult(be.getBindingResult().getFieldError().getDefaultMessage());
? ? }
? ? return resultInfo;
}
PostMan 接口測試
總結
今天課程主要介紹了SpringBoot中各種環境的整合與測試工作,持久層框架Mybatis集成與數據訪問基本操作,借助SpringBoot單元測試實現業務方法與控制器接口測試,同時集成了Swagger2 接口文件生成工具來快速生成接口文檔的功能。在web項目開發中常見的項目熱部署配置,這里集成DevTools工具來幫助web開發者在項目開發中不斷手動啟動服務器部署項目的繁瑣流程,通過引入EhCache 緩存技術來加快應用程序數據的訪問效率,然后對于項目中常見的定時任務的執行,這里集成了Quartz 任務調度框架來實現任務定時執行處理,最后提到了SpringBoot 應用中對象項目事物控制與異常統一處理,從而提高項目代碼的健壯性與數據的一致性,借助SpringBoot 的Validation 實現后端數據參數的校驗機制,結合全局異常來對校驗結果進行輸出操作,提高后端應參數處理的嚴謹性。