一、Spring起步
- Spring早已經成為企業級開發的業界標準,尤其是Spring Boot 2.0、Spring 5釋出後,Spring的生態系統引領了技術架構發展的潮流,對於Java開發人員,深入掌握Spring全家桶的各種框架應用及必要的底層原理知識,是一件非常重要的事情。
學習路線圖
Spring的基礎知識
什麼是Spring
Spring的核心是提供了一個容器(container),通常稱為Spring應用上下文(Spring application context),它們會建立和管理應用元件。這些元件也可以稱為bean,會在Spring應用上下文中裝配在一起,從而形成一個完整的應用程式。
將bean裝配在一起的行為是通過一種基於依賴注入(dependency injection,DI)的模式實現的。此時,元件不會再去建立它所依賴的元件並管理它們的生命週期,使用依賴注入的應用依賴於單獨的實體(容器)來建立和維護所有的元件,並將其注入到需要它們的bean中。通常,這是通過構造器引數和屬性訪問方法來實現的。
Spring框架核心模組
SpringBoot
在歷史上,一般通過兩種配置方式為Spring應用上下文提供Bean
- 使用一個或多個XML檔案描述bean
- 使用@Configuration註解會告知Spring這是一個配置類
隨著Spring Boot 2.x的引入,Spring自動配置的能力已經大大加強,Spring Boot能夠基於類路徑中的條目、環境變數和其他因素合理猜測需要配置的元件並將它們裝配在一起。Java程式設計師儘可能多地使用Spring Boot,只有在必要的時候才使用顯式配置。
第一個Spring應用DEMO
- 在IntelliJ IDEA中建立新專案
- 通過地址為https://start.spring.io/初始化專案;
- 指定專案通用資訊:
- 選擇專案Starter:
- 生成的專案結構:
- maven規範
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
可參見本人部落格《Maven POM( Project Object Model,專案物件模型 )》及《一圖說清maven常見要素》這兩篇文章。
- 入口類
/**
* SpringBoot應用
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
// 執行應用
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication是一個組合註解,它組合了3個其他的註解。
- @SpringBootConfiguration:將該類宣告為配置類。儘管這個類目前還沒有太多的配置,但是後續我們可以按需新增基於Java的Spring框架配置。這個註解實際上是@Configuration註解的特殊形式。
- @EnableAutoConfiguration:啟用Spring Boot的自動配置。我們隨後會介紹自動配置的更多功能。就現在來說,我們只需要知道這個註解會告訴SpringBoot自動配置它認為我們會用到的元件。
- @ComponentScan:啟用元件掃描。這樣我們能夠通過@Component@Controller、@Service這樣的註解宣告其他類,Spring會自動發現它們並將它們註冊為Spring應用上下文中的元件。
8. 測試類
// SpringBoot測試
@SpringBootTest
class DemoApplicationTests {
// 測試方法
@Test
void contextLoads() {
}
}
- 程式啟動
編寫自己的第一個SpringMVC例子
- 第一個Controller
index()是一個簡單的控制器方法。它帶有@GetMapping註解,表明如果針對“/”傳送HTTP GET請求,那麼這個方法將會處理請求。該方法所做的只是返回String型別的index值,該控制器方法中還通過Spring自動注入IndexService服務元件,及呼叫服務元件方法。
/**
* 第一個SpringMVC程式--Controller層
*
* @author zhuhuix
* @date 2020-07-02
*/
@Controller
public class IndexController {
// Spring注入服務元件
@Autowired
private IndexService indexService;
@GetMapping("/")
public String index(Model model) {
String index = indexService.getIndex();
model.addAttribute("index", index);
// 返回檢視 即index.html
return "index";
}
}
- 第一個Service
getIndex()是一個簡單的服務方法。該方法所做的只是返回String型別的index值,該服務元件供控制層呼叫。
/**
* 第一個SpringMVC程式--Service層
* * @author zhuhuix
* @date 2020-07-02
*/
@Service
public class IndexService {
public String getIndex() {
return "hello world!!!";
}
}
- 第一個View
-- 使用Thymeleaf模板引擎
### application.properties
###ThymeLeaf配置
spring:
thymeleaf:
#模板的模式,支援 HTML, XML TEXT JAVASCRIPT
mode: HTML5
#編碼 可不用配置
encoding: UTF-8
#內容類別,可不用配置
content-type: text/html
#開發配置為false,避免修改模板還要重啟伺服器
cache: false
#配置模板路徑,預設是templates,可以不用配置
prefix: classpath:/templates
-- 定義index.html檢視層
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<p th:text="${index}" />
</body>
</html>
- 執行測試
嘗試使用Spring Boot DevTools
•程式碼變更後應用會自動重啟;
•當面向瀏覽器的資源(如模板、JavaScript、樣式表)等發生變化時,會自動重新整理瀏覽器
- pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
<scope>runtime</scope>
</dependency>
...
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!--fork : devtools生效必須設定成true -->
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
- idea設定
-- 需勾選Build project automaticallty
-- ctrl+alt+shift+/ :Registry 中第一項必須打勾
Spring起步小結
- Spring核心框架:Spring核心框架是Spring領域中一切的基礎。它提供了核心容器和依賴注入框架。
- Spring Boot:Spring Boot構建在Spring之上,通過簡化依賴管理、自動配置和執行時洞察,使Spring更加易用;
- Spring MVC:我們通過SpringBoot初始化生成的框架上加入Controller,Service,View的分層,編寫了第一個Spring MVC程式,併成功執行。
- 使用Idea開發環境,安裝Spring Boot DevTools並進行配置,提高了開發效率。
二、基於SpringMVC開發web應用
. 在上一小節中建立了第一個DEMO,本章將繼續基於SpringMVC框架構建我們的web應用,該應用需要實現使用者登記,具體實現步驟如下:
- 建立使用者的資料模型;
- 在服務層編寫使用者登記的業務邏輯;
- 生成為Web瀏覽器提供使用者登記內容的控制器
- 在檢視層運用模板引擎展示資料及校驗表單輸入
建立資料模型
- 建立一個使用者類,定義使用者id,使用者名稱稱,郵箱三個屬性;
- 新增預設構造方法與全屬性構造方法;
- 對使用者屬性新增對應getter,setter方法;
/**
* 基於SpringMVC框架開發web應用--使用者類
*
* @author zhuhuix
* @date 2020-07-03
*/
public class User implements Serializable {
// 使用者id
private Long id;
// 使用者名稱
private String name;
// 郵箱
private String email;
User(){ }
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
建立業務邏輯
- 實現返回所有使用者資料的列表
- 實現增加使用者的功能
/**
* 基於SpringMVC框架開發web應用--使用者服務類
*
* @author zhuhuix
* @date 2020-07-03
*/
@Service
public class UserService {
public static ArrayList<User> users = new ArrayList<>();
// mock資料
public UserService() {
users.add(new User(1L, "Mike", "mike@gmail.com"));
users.add(new User(2L, "Jack", "jack@gmail.com"));
users.add(new User(3L, "Kate", "kate@gmail.com"));
users.add(new User(4L, "Mary", "mary@gmail.com"));
users.add(new User(5L, "Rose", "rose@gmail.com"));
}
// 返回所有的使用者
public List<User> listUsers() {
return users;
}
// 增加使用者
public User saveUser(User user) {
user.setId(users.size() + 1L);
users.add(user);
return user;
}
}
建立控制器
在Spring MVC框架中,控制器是重要的參與者。它們的主要職責是處理HTTP請求傳遞給檢視以便於渲染HTML(瀏覽器展現)。
- SpirngMVC的請求註解
註解 | 描述 |
---|---|
@RequestMapping | 通用的請求 |
@GetMapping | 處理HTTP GET請示 |
@PostMapping | 處理HTTP POST請示 |
@PutMapping | 處理HTTP PUT請示 |
@DeleteMapping | 處理HTTP DELETE請示 |
- 使用者控制器的處理內容
-- 處理路徑為“/user”的HTTP GET請求,向服務層呼叫返回所有使用者資料列表的介面,獲取資料後傳遞給對應的檢視模板,併傳送給發起請求的Web瀏覽器。
-- 處理路徑為“/user”的HTTP POST請求,向服務層呼叫增加使用者的介面,處理成功後呼叫路徑為“/user”的HTTP GET請求,併傳送給發起請求的Web瀏覽器。
-- 處理路徑為“/user/form”的HTTP GET請求,產生一個新使用者資料模型,並呼叫對應的檢視模板,傳送給發起請求的Web瀏覽器。
/**
* 基於SpringMVC框架開發web應用--使用者控制器
*
* @author zhuhuix
* @date 2020-07-03
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 儲存使用者並返回到使用者列表頁面
@PostMapping
public ModelAndView saveUser(User user) {
userService.saveUser(user);
return new ModelAndView("redirect:/user");//重定向到list頁面
}
// 獲取建立使用者表單頁面
@GetMapping("/form")
public ModelAndView createForm(Model model) {
model.addAttribute("user",new User());
return new ModelAndView("register","userModel",model);
}
// 獲取使用者列表頁面
@GetMapping
public ModelAndView list(Model model) {
model.addAttribute("userList", userService.listUsers());
return new ModelAndView("userlist", "userModel", model);
}
}
設計檢視模板
- 設計一個使用者列表的檢視模板
-- Thymeleaf提供了一個屬性“th:each”,它會迭代一個元素集合,為集合中的每個條目渲染HTML,我們可以利用這個屬性,設計出使用者的列表檢視
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultrag.net.nz/thymeleaf/layout"
>
<head>
<meta charset="UTF-8">
</head>
<body>
<h3>使用者列表</h3>
<div>
<a th:href="@{/user/form}">建立使用者</a>
</div>
<table border="1">
<thead>
<tr>
<td>ID</td>
<td>Email</td>
<td>Name</td>
</tr>
</thead>
<tbody>
<tr th:if="${userModel.userList.size()} eq 0">
<td colspan="3">沒有使用者資訊!</td>
</tr>
<tr th:each="user:${userModel.userList}">
<td th:text="${user.id}"></td>
<td th:text="${user.email}"></td>
<td th:text="${user.name}"></td>
</tr>
</tbody>
</table>
</body>
</html>
- 設計一個提交新使用者的檢視模板
-- 使用者通過這個檢視,錄用名稱與郵箱地址,提交新使用者的資訊。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultrag.net.nz/thymeleaf/layout"
>
<head>
<meta charset="UTF-8">
</head>
<body>
<h3>登記使用者</h3>
<form action="/users" th:action="@{/user}" method="POST" th:object="${userModel.user}">
<input type="hidden" name="id" th:value="*{id}">
名稱:<br>
<input type="text" name="name" th:value="*{name}">
<br>
郵箱:<br>
<input type="text" name="email" th:value="*{email}">
<input type="submit" value="提交" >
</form>
</body>
</html>
執行Web應用
- 到目前為止,我們已經開發了User使用者模型、UserService使用者服務類、UserController控制器、userlist使用者列表檢視模板、register使用者登記檢視模板,接下來我們可以嘗試執行一下。開啟瀏覽器並訪問http://localhost:8080/user。
- 點選頁面上的建立使用者,登記新使用者,並提交
該web應用一切執行正常。
表單校驗
雖然我們已經實現了使用者列表與登記新使用者,但檢視層還存在漏洞,比如使用者名稱稱為空的時候不能儲存,郵箱輸入格式要符合規則,所以程式要對錶單輸入的內容進行校驗。
- 引入Validation API與Hibernate的Validation API 依賴
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
- 在要被校驗的類上宣告校驗規則:即在User類上宣告校驗規則。
public class User implements Serializable {
// 使用者id
@NotNull
private Long id;
// 使用者名稱
@NotBlank(message = "使用者名稱稱不能為空")
private String name;
// 郵箱
@Pattern(message ="郵箱格式不符", regexp = "^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
private String email;
...
}
- 在控制器方法中宣告要進行校驗:即在UserController類的saveUser上增加使用者資料的校驗規則。
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 儲存使用者並返回到使用者列表頁面
@PostMapping
public ModelAndView saveUser(@Valid User user, Errors errors,Model model) {
if (errors.hasErrors()){
model.addAttribute("user",user);
if (errors.getFieldError("name")!=null) {
model.addAttribute("nameError", errors.getFieldError("name").getDefaultMessage());
}
if (errors.getFieldError("email")!=null) {
model.addAttribute("emailError", errors.getFieldError("email").getDefaultMessage());
}
return new ModelAndView("register","userModel",model);
}
userService.saveUser(user);
//重定向到list頁面
return new ModelAndView("redirect:/user");
}
...
}
- 修改register表單檢視以展現校驗錯誤。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<h3>登記使用者</h3>
<form action="/users" th:action="@{/user}" method="POST" th:object="${userModel.user}">
<input type="hidden" name="id" th:value="*{id}">
名稱:<br>
<input type="text" name="name" th:value="*{name}" >
<br>
郵箱:<br>
<input type="text" name="email" th:value="*{email}">
<br>
<input type="submit" value="提交" >
<div style="color:red" th:text="${nameError}"></div>
<div style="color:red" th:text="${emailError}"></div>
</form>
</body>
</html>
展現校驗錯誤
基於SpringMVC開發web應用小結
- Spring提供了一個強大Spring MVC的Web框架。
- Spring MVC是基於註解的,通過像@RequestMapping、@GetMapping和@PostMapping這樣的註解來啟用請求處理方法的宣告。
- 請求處理方法返回一個Thymeleaf模板,同時會帶有模型資料。
- Spring MVC支援表單校驗。
三、實現資料持久化
. 在上一小節中基於SpringMVC框架構建了我們的web應用,並在檢視層運用模板引擎展示資料及校驗表單輸入,本章將使用JdbcTemplate及Spring Data實現資料持久化的操作。
資料庫
- 一說到資料的持久化,首選方案就是關係型資料庫,本文將使用網際網路領域最常用mysql資料庫。
MySQL 最流行的關係型資料庫管理系統,MySQL所使用的 SQL 語言是用於訪問資料庫的最常用標準化語言,MySQL由於效能高、成本低、可靠性好,已經成為最流行的開源資料庫,因此被廣泛地應用在網際網路領域中。
建立使用者資訊登記表
- 根據使用者資訊模型類,設計使用者資訊登入表
DROP DATABASE IF EXISTS user_info;
CREATE DATABASE user_info
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
use user_info;
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
Web應用專案整合mysql
- 增加依賴
<!--Mysql依賴包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
<!-- 資料庫連線池:druid資料來源驅動 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
- Spring配置
#配置資料來源
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://user_info?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
使用JdbcTemplate實現資料持久化
Spring對JDBC的支援要歸功於JdbcTemplate類。JdbcTemplate提供了一種特殊的方式,通過這種方式,開發人員在對關係型資料庫執行SQL操作的時候能夠避免使用JDBC時常見的繁文縟節和樣板式程式碼。
- 增加依賴
<!-- JDBC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
- 修改UserService業務邏輯
/**
* 基於SpringMVC框架開發web應用--使用者服務類
*
* @author zhuhuix
* @date 2020-07-03
* @date 2020-07-04 增加通過jdbcTemplate處理資料
*/
@Service
public class UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
// 返回所有的使用者
public List<User> listUsers() {
return jdbcTemplate.query("select id,name,email from user;",
new Object[]{}, new BeanPropertyRowMapper<>(User.class));
}
// 增加使用者
public int saveUser(User user) {
return jdbcTemplate.update("insert into user(name,email) values(?,?);"
, user.getName(), user.getEmail());
}
}
再次執行Web應用
-
我們只修改了UserService使用者服務類;控制器、檢視模板都未做任何改變,接下來我們可以再次嘗試執行一下。開啟瀏覽器並訪問http://localhost:8080/user。
-
輸入使用者資訊並提交
-
檢視資料庫使用者資訊表
實現資料持久化小結
相對於普通的JDBC,Spring的JdbcTemplate能夠極大地簡化關係型資料庫的使用。但是,你會發現使用JPA會更加簡單。接下來我們會繼續通過Spring Data框架讓資料持久化變得更簡單。
四、使用Spring Data實現資料持久化
在上篇文章中,我們使用mysql資料庫與JdbcTemplate簡單實現了資料持久化操作,並對web程式進行了測試,本篇文章將繼續通過Spring Data框架讓資料持久化變得更簡單。
Spring Data
- Spring Data是一個用於簡化資料庫訪問,並支援雲服務的開源框架。其主要目標是使得資料庫的訪問變得方便快捷,常用的子專案有:
Spring Data JDBC -資料訪問元件對JDBC的支援。
Spring Data JPA:-基於關係型資料庫進行JPA持久化。
Spring Data MongoDB - 持久化到Mongo文件資料庫。
Spring Data Redis-持久化到Redis key-value記憶體資料庫。
Spring Data REST:通過Spring Data資料訪問元件匯出為RESTful資源。
Spring Data Cassandra:持久化到Cassandra資料庫。
四、使用Spring Data JPA持久化資料
- 本文會基於原JDBC的實現替換為使用SpringData JPA的repository
新增JPA starter依賴
<!--pom.xml-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
修改實體類,新增JPA對映註解
- 首先我們給原來的user表增加兩個時間欄位
ALTER TABLE user ADD COLUMN create_time DATETIME;
ALTER TABLE user ADD COLUMN update_time DATETIME;
- 修改user.class
-- 給user類新增@Entity註解,宣告為JPA實體
-- 給id欄位新增@Id註解將其指定為資料庫中唯一標識該實體的屬性
-- 給id欄位新增@GeneratedValue註解,依賴資料庫自動生成ID值
-- 給其它欄位新增@Column註解,並宣告對應user表中的欄位名稱
-- 增加createTime成員,新增@CreationTimestamp註解,使用該註解可以讓Hibernate在插入資料時對註解的屬性對應的日期型別建立預設值
-- 增加updateTime成員,新增@UpdateTimestamp註解,使用該註解可以讓Hibernate在更新資料時對註解的屬性對應的日期型別進行更新
/**
* 基於SpringMVC框架開發web應用--使用者類
*
* @author zhuhuix
* @date 2020-07-03
* @date 2020-07-07 新增JPA對映註解
*/
@Entity
public class User implements Serializable {
// 使用者id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 使用者名稱
@NotBlank(message = "使用者名稱稱不能為空")
@Column(name="name")
private String name;
// 郵箱
@Column(name="email")
@Pattern(message ="郵箱格式不符", regexp = "^[A-Za-z0-9\\u4e00-\\u9fa5]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")
private String email;
// 建立時間
@Column(name = "create_time")
@CreationTimestamp
private Timestamp createTime;
// 更新時間
@Column(name = "update_time")
@UpdateTimestamp
private Timestamp updateTime;
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
宣告JPA repository介面
- 藉助Spring Data JPA,我們可以通過繼承CrudRepository介面,快速定義應用的資料層。CrudRepository定義並實現了很多用於CRUD(建立、讀取、更新、刪除)操作的方法,我們根本就不用編寫實現類!當應用啟動的時候,Spring DataJPA會在執行期自動生成實現類。這意味著,我們現在就可以在服務層直接設用repository的增刪改查操作了。
/**
* 基於SpringMVC框架開發web應用--資料操作層
*
* @author zhuhuix
* @date 2020-07-07
*/
public interface UserRepository extends CrudRepository<User,Long> {
}
服務層repository
- 接下來我們在UserService層直接呼叫UserRepository中由Spring Data JPA提供的各種方法,實現查詢及增加使用者資訊。
/**
* 基於SpringMVC框架開發web應用--使用者服務類
*
* @author zhuhuix
* @date 2020-07-03
* @date 2020-07-04 增加通過jdbcTemplate處理資料
* @date 2020-07-07 將jdbcTemplate處理資料程式改為Spring Data JPA的處理方式
*/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 返回所有的使用者
public List<User> listUsers() {
return (List<User>) userRepository.findAll();
}
// 增加使用者
public User saveUser(User user) {
return userRepository.save(user);
}
}
再次執行Web應用
-
我們增加了資料層並修改了UserService服務層;控制器、檢視模板都未做任何改變,接下來我們可以再次嘗試執行一下。開啟瀏覽器並訪問http://localhost:8080/user。
-
輸入使用者資訊並提交
-
檢視資料庫使用者資訊表
-
測試結論:通過將JdbcTemplate替換成Spring Data JPA,同樣實現了使用者資訊的查詢與增加,而且通過JPA CrudRepository介面,我們沒有書寫一行SQL語句,也實現了資料的增加與查詢。
自定義JPA repository
- 除了CrudRepository提供的基本CRUD操作之外,還需要通過使用者名稱稱或郵箱地址查詢使用者資訊,那我們需要新增如下的方法宣告到UserRepository中:
public interface UserRepository extends CrudRepository<User,Long> {
// 自定義新增通過使用者名稱稱查詢使用者資訊
List<User> findByName(String name);
}
按照Spring Data的規範的規定,查詢方法以find | read | get開頭(比如 find、findBy、read、readBy、get、getBy),涉及查詢條件時,條件的屬性用條件關鍵字連線,要注意的是:條件屬性以首字母大寫。框架在進行方法名解析時,會先把方法名多餘的字首擷取掉,然後對剩下部分進行解析。
直接在介面中定義查詢方法,如果是符合規範的,可以不用寫實現,即不用寫SQL。
服務層增加查詢介面
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
...
// 根據名稱查詢使用者
public List<User> searchUser(String name){
return userRepository.findByName(name);
}
}
控制器增加使用者查詢功能
/**
* 基於SpringMVC框架開發web應用--使用者控制器
*
* @author zhuhuix
* @date 2020-07-03
* @date 2020-07-07 增加使用者查詢
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
...
// 查詢輸入頁面
@GetMapping("/index")
public ModelAndView index(Model model) {
model.addAttribute("user", new User());
return new ModelAndView("index", "userModel", model);
}
// 查詢提交併跳轉使用者列表
@PostMapping("/search")
public ModelAndView search(@ModelAttribute User user, Model model) {
model.addAttribute("userList", userService.searchUser(user.getName()));
return new ModelAndView("userlist", "userModel", model);
}
}
檢視層增加使用者查詢頁面
<!-- index.html-->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<h3>查詢使用者</h3>
<form action="/users" th:action="@{/user/search}" method="POST" th:object="${userModel.user}">
名稱:<br>
<input type="text" name="name" th:value="*{name}" >
<br>
<input type="submit" value="查詢" >
</form>
</body>
</html>
查詢功能測試
使用Spring Data實現資料持久化小結
- Spring Data JPA能夠極大地簡化JPA持久化,我們只需編寫repository介面即可;
- Spirng Data 對於實體類可以通過各種註解進行資料的管理:比如@Id ,@Column,@CreationTimestamp等等
- 只需要符合JPA的介面命名規則,我們可以自定義JPA repository各種對於資料的操作方法:比如findBy... ,findAllBy...,findBy..And..等。
五、使用Spring Security安全框架保護web應用
- 在前四篇文章中已經實現了一個非常簡單的使用者郵箱登記的web應用,並將資料儲存到mysql資料庫中。但這個web應用涉及的資料展示、查詢及操作都是開放的,如果部署在網際網路上,可以訪問應用的人員都可隨意增加及查詢資料,這顯然是不符合安全要求的。
作為軟體開發人員,我們必須採取措施來保護應用程式中的資訊。
啟用Spring Security
Spring Security是一個功能強大且高度可定製的身份驗證和訪問控制框架。它是用於保護基於Spring的應用程式的標準。
本文將通過Spring Security配置實現web應用的如下功能:
- 實現頁面的WEB安全保護
- 實現管理員的帳戶註冊
- 實現登入驗證的完整流程
Spring Security的基本登入認證
- 在pom.xml檔案中新增依賴
<!-- Spring Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security </artifactId>
</dependency>
通過將security starter新增到專案的構建檔案中,我們得到了如下的安全特性:
- 所有的HTTP請求路徑都需要認證;
- 不需要特定的角色和許可權;
- 沒有登入頁面;
- 認證過程是通過HTTP basic認證對話方塊實現的;
- 系統只有一個使用者,使用者名稱為user。
我們試著啟動一下應用,並訪問使用者列表頁面,發現程式竟然跳轉到了一個login登入頁面,並要求輸入使用者和密碼。
這是一個HTTP basic認證對話方塊,提示進行認證。要想通過這個認證,需要一個使用者名稱和密碼。使用者名稱為user,而密碼則是隨機生成的,可以在日誌監控介面上查到:
我們試著在登入介面上輸入使用者名稱user與圖中的密碼,進行認證登入:
程式順利通過了密碼認證,並進入到使用者列表介面。但顯然以上的方式是不符合需求的,我們需要的是:
- 通過自定義的登入頁面來提示管理員使用者進行認證;
- 提供一個註冊頁面,新管理員使用者能夠註冊;
- 對不同的請求路徑,執行不同的安全規則。比如註冊頁面不需要進行認證,其他頁面需要進行認證。
使用Spring Security實現自定義使用者認證
增加管理員實體類
-- ----------------------------
-- Table structure for admin
-- ----------------------------
DROP TABLE IF EXISTS `admin`;
CREATE TABLE `admin` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`user_password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
/**
* 基於SpringMVC框架開發web應用--管理員使用者類,用於登入認證
*
* @author zhuhuix
* @date 2020-07-08
*/
@Entity
public class Admin implements UserDetails {
// 管理員id
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="user_name")
private String userName;
@Column(name="user_password")
private String userPassword;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
}
@Override
public String getPassword() {
return userPassword;
}
@Override
public String getUsername() {
return userName;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
}
- 管理員類實現了Spring Security的UserDetails介面。通過實現UserDetails介面,我們能夠提供更多資訊給框架,比如使用者都被授予了哪些許可權以及使用者的賬號是否可用。
- getAuthorities()方法返回使用者被授予許可權的一個集合。各種is…Expired()方法要返回一個boolean值,表明使用者的賬號是否可用或過期。
使用Spring Data JPA定義管理員的持久化介面
/**
* 基於SpringMVC框架開發web應用--管理員資料操作層
*
* @author zhuhuix
* @date 2020-07-08
*/
public interface AdminRepository extends CrudRepository<Admin,Long> {
// 根據使用者名稱查詢管理員
Admin findByUserName(String username);
}
建立獲取管理員詳情資訊的服務層
/**
* 基於SpringMVC框架開發web應用--管理員服務層
*
* @author zhuhuix
* @date 2020-07-08
*/
@Service
public class AdminService implements UserDetailsService {
private final Logger logger = LoggerFactory.getLogger(Logger.class);
@Autowired
private AdminRepository adminRepository;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
Admin admin = adminRepository.findByUserName(s);
if (admin == null) {
logger.error("管理員" + s + "未找到");
throw new UsernameNotFoundException("User " + s + "not found");
}
return admin;
}
// 儲存管理員
public Admin save(Admin admin){
return adminRepository.save(admin);
}
}
配置Spring Security
/**
* Spring Security配置類
*
* @author zhuhuix
* @date 2020-07-08
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AdminService adminService;
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(adminService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
測試自定義的登入驗證方法
以上通過建立管理員資訊表,及通過JPA定義資料處理層,編寫獲取管理員資訊的服務實現,最後配置Spring Security Web安全類,實現了自定義的登入驗證方法,下面具體來測試一下:
web應用程式已經實現了自定義的使用者登入驗證。
實現管理員的註冊
- 以上雖然完成了管理員的登入驗證,但沒有涉及管理員的新增,以下需要完成管理員註冊流程。
管理員註冊控制器
/**
* 基於SpringMVC框架開發web應用--管理員註冊控制器
*
* @author zhuhuix
* @date 2020-07-08
*/
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private AdminService adminService;
// 管理註冊頁
@GetMapping
public ModelAndView registerForm(Model model) {
model.addAttribute("admin", new Admin());
return new ModelAndView("registration", "adminModel", model);
}
// 提交註冊資訊
@PostMapping("/register")
public ModelAndView save(Admin admin) {
BCryptPasswordEncoder bCryptPasswordEncoder =new BCryptPasswordEncoder();
admin.setUserPassword(bCryptPasswordEncoder.encode(admin.getPassword()));
if (adminService.save(admin) != null) {
return new ModelAndView("redirect:/login ");
} else {
return null;
}
}
}
管理員註冊頁面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<h3>管理員註冊</h3>
<form action="/admin" th:action="@{/admin/register}" method="POST" th:object="${adminModel.admin}">
名稱:<br>
<input type="text" name="userName" th:value="*{userName}" >
<br>
輸入密碼:<br>
<input type="password" name="userPassword" th:value="*{userPassword}">
<br>
<input type="submit" value="註冊" >
</form>
</body>
</html>
配置保護Web請求的安全性規則
- 以上完成了管理員註冊的業務邏輯、控制層、與頁面檢視,但如果我們直接訪問管理員註冊頁面的時候,web應用程式仍然會跳轉到login頁面,要求輸入使用者名稱和密碼,這顯然不符合需求,我們只需要對需要認證的頁面進行登入驗證保護,對於註冊頁面是開放的,所以我們需要配置保護web請求的安全性規則:
/**
* Spring Security配置類
*
* @author zhuhuix
* @date 2020-07-08
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AdminService adminService;
// 自定義使用者驗證
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(adminService)
.passwordEncoder(new BCryptPasswordEncoder());
}
// 保護web請求的安全性規則
@Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/user/**").access("hasRole('ROLE_USER')")
.antMatchers("/admin/**").permitAll()
.and().formLogin().defaultSuccessUrl("/user")
.and().httpBasic();
}
}
完整測試
- 訪問管理員註冊頁面進行註冊
- 使用註冊的管理員帳戶進行登入驗證
使用Spring Security安全框架保護web應用小結
- Spring Security的自動配置是實現基本安全性功能的好辦法,但是大多數的應用都需要自定義安全規則,這樣才能滿足特定的安全需求。
- 認證使用者詳情資訊可以通過自定義使用者儲存機制進行管理,它的後端可以是關係型資料庫。
- 注意:以上實現功能有不完全處:如管理員註冊時,需在頁面進行密碼的兩次確認,服務層需判斷帳戶名是否存在等,請大家借鑑使用。
六、Spring的配置屬性
- 本小節將瞭解Spring的配置屬性及完成自定義的配置
Spring的環境抽象(Environment)
Spring的環境抽象是各種配置屬性的一站式服務。它抽取了原始的屬性,這樣需要這些屬性的bean就可以從Spring本身中獲取了。Spring環境會拉取多個屬性源,包括:
- JVM系統屬性;
- 作業系統環境變數;
- 命令列引數;
- 應用屬性配置檔案。
通過應用屬性配置檔案完成Spring的環境配置
- 我們回顧下原web應用中的application.properties檔案:
###資料來源配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:mysql://localhost:3306/user_info?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
#thymelea模板配置
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.mode=HTML5
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.content-type=text/html
spring.thymeleaf.cache=false
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
- Spring Boot引入了具有層次關係的yml格式的配置檔案:
spring:
port:8080
顯然具有層次關係的配置檔案更易於理解與書寫,接下來我們將使用application.yml取代application.properties完成各種屬性配置。
配置資料來源
###資料來源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: root
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
url: jdbc:log4jdbc:mysql://localhost:3306/user_info?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
配置模板引擎
#thymelea模板配置
thymeleaf:
prefix: classpath:/templates/
suffix: .html
mode: HTML5
encoding: UTF-8
content-type: text/html
cache: false
配置日誌
- 預設情況下,Spring Boot通過Logback配置日誌,日誌會以INFO級別寫入到控制檯中,我們希望重新配置顯示日誌的格式;
- 同時我們希望通過監控sql日誌輸出到控制檯,並將輸出的資訊進行篩選列印;
- 首先需引入log4jdbc依賴
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
<version>1.16</version>
</dependency>
- 其次生成配置檔案log4jdbc.log4j2.properties:
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.auto.load.popular.drivers=false
log4jdbc.drivers=com.mysql.cj.jdbc.Driver
- 最後建立一個logback.xml檔案完成配置:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds" debug="false">
<contextName>web demo</contextName>
<property name="log.charset" value="utf-8" />
<property name="log.pattern" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)" />
<!--輸出到控制檯-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${log.pattern}</pattern>
<charset>${log.charset}</charset>
</encoder>
</appender>
<!--普通日誌輸出到控制檯-->
<root level="info">
<appender-ref ref="console" />
</root>
<!--監控sql日誌輸出 -->
<logger name="jdbc.sqlonly" level="INFO" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="jdbc.resultset" level="ERROR" additivity="false">
<appender-ref ref="console" />
</logger>
<!-- 如想看到表格資料,將OFF改為INFO -->
<logger name="jdbc.resultsettable" level="OFF" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="jdbc.connection" level="OFF" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="jdbc.sqltiming" level="OFF" additivity="false">
<appender-ref ref="console" />
</logger>
<logger name="jdbc.audit" level="OFF" additivity="false">
<appender-ref ref="console" />
</logger>
</configuration>
- 輸出格式如下:
建立自定義的配置屬性
為了支援配置屬性的注入,Spring Boot提供了@ConfigurationProperties註解。將它放到Spring 應用上下文的 bean之後,它就會為該bean中那些能夠根據Spring環境注入值的屬性賦值。
- 我們希望給管理員註冊時,新增一個應用的預設密碼,假設使用者註冊時,不輸入密碼,web應用就以這個預設密碼進行註冊,並寫入資料庫。
在application.yml中加入配置
#管理員預設密碼
admin:
password: 123456
編寫配置類
- 使用 @ConfigurationProperties 配置模組
- 過新增 @Component 註解讓 Component Scan 掃描到
/**
* 基於SpringMVC框架開發web應用--管理員使用者預設金鑰
*
* @author zhuhuix
* @date 2020-07-09
*/
@Component
@ConfigurationProperties(prefix = "admin")
public class DefaultPasswordProperties {
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
使用自定義的配置屬性
/**
* 基於SpringMVC框架開發web應用--管理員註冊控制器
* * @author zhuhuix
* @date 2020-07-08
* @date 2020-07-09 註冊密碼為空時使用自定義的預設密碼屬性
*/
@RestController
@RequestMapping("/admin")
public class AdminController {
@Autowired
private AdminService adminService;
@Autowired
private DefaultPasswordProperties defaultPasswordProperties;
// 管理註冊頁
@GetMapping
public ModelAndView registerForm(Model model) {
model.addAttribute("admin", new Admin());
return new ModelAndView("registration", "adminModel", model);
}
// 提交註冊資訊
@PostMapping("/register")
public ModelAndView save(Admin admin) {
// 如果註冊密碼為空,則賦值預設密碼
if (StringUtils.isEmpty(admin.getPassword())) {
admin.setUserPassword(defaultPasswordProperties.getPassword());
}
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
admin.setUserPassword(bCryptPasswordEncoder.encode(admin.getPassword()));
if (adminService.save(admin) != null) {
return new ModelAndView("redirect:/login ");
} else {
return null;
}
}
}
屬性配置測試
- 註冊admin2管理員,密碼保持為空,並提交
- 用admin2管理員,密碼為123456進行登入
- 登入成功
Spring的配置屬性小結
- Spring的配置屬性可以通過命令列引數、環境變數、JVM系統屬性、屬性檔案或YAML檔案等方式進行設定。
- Spring的配置屬性可以用來覆蓋自動配置相關的設定,包括指定資料來源URL和日誌級別。
- Spring的配置屬性可以新增@ConfigurationProperties註解,這樣就能夠從多個屬性源中選取一個來注入它的值。
七、Spring整合REST API服務
本節將進入到新的單元:Spring與應用的整合,今天先實現整合REST API服務。
REST API服務
微服務架構,前後端分離目前已成為網際網路專案開發的業界標準,其核心思想就是前端(APP、小程式、H5頁面等)通過呼叫後端的API介面,提交及返回JSON資料進行互動。
- 移動裝置、平板電腦、智慧裝置已經非常常見,許多應用程式採用了一種通用的設計,那就是將使用者介面推到更接近客戶端的地方,而讓伺服器公開API,通過這種API,各種客戶端都能與後端功能進行互動。
- REST API(REpresentation State Transfer Application Programming Interface):通過URL定位資源,用HTTP動詞(GET,POST,DELETE,PUSH等)描述操作,與後端服務進行互動。
Spring整合REST API服務
-
在前幾篇文章中我們用了模板引擎開發了多頁應用(MultiPage Application,MPA),我們將在原有基礎上按以下步驟實現整合API服務:
-
建立使用者管理的Restful Api(UserRestfulApi.java)的介面,實現增加、刪除、修改、查詢使用者資訊的API互動服務;
-
整合Swagger2,對上述API介面進行測試。
用Spring MVC實現使用者管理Restful Api
- Controller
/**
* 基於SpringMVC框架開發web應用--使用者restful api
* 增加、刪除、修改、查詢使用者資訊的API互動服務
*
* @author zhuhuix
* @date 2020-07-10
*/
@RestController
@RequestMapping("/user/api")
public class UserRestfulApi {
@Autowired
private UserService userService;
// 增加使用者資訊
@PostMapping
public ResponseEntity<User> addUser(User user) {
return ResponseEntity.ok(userService.saveUser(user));
}
// 根據id刪除使用者
@DeleteMapping("/{id}")
public ResponseEntity deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.ok(HttpStatus.OK);
}
// 根據id修改使用者
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@RequestBody User user) {
return ResponseEntity.ok(userService.saveUser(user));
}
// 根據id查詢使用者
@GetMapping("/{id}")
public ResponseEntity<User> findUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.findUser(id));
}
}
- Service
/**
* 基於SpringMVC框架開發web應用--使用者服務類
*
* @author zhuhuix
* @date 2020-07-03
* @date 2020-07-04 增加通過jdbcTemplate處理資料
* @date 2020-07-07 將jdbcTemplate處理資料程式改為Spring Data JPA的處理方式
* @date 2020-07-10 增加
*/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
// 返回所有的使用者
public List<User> listUsers() {
return (List<User>) userRepository.findAll();
}
// 儲存使用者
public User saveUser(User user) {
return userRepository.save(user);
}
// 刪除使用者
public void deleteUser(Long id){
userRepository.deleteById(id);
}
// 查詢使用者
public User findUser(Long id){
return userRepository.findById(id).get();
}
// 根據名稱查詢使用者
public List<User> searchUser(String name){
return userRepository.findByName(name);
}
}
- Repository
/**
* 基於SpringMVC框架開發web應用--資料操作層
*
* @author zhuhuix
* @date 2020-07-07
*/
public interface UserRepository extends CrudRepository<User,Long> {
// 自定義新增通過使用者名稱稱查詢使用者資訊
List<User> findByName(String name);
}
Spring 整合Swagger2
Swagger2 作為一個規範和完整的框架,可以用於生成、描述、呼叫和視覺化 RESTful 風格的 Web 服務:
1、 介面文件線上自動生成,文件隨介面變動實時更新,節省維護成本
2、 支援線上介面測試,不依賴第三方工具
- 新增maven依賴
<!-- RESTful APIs swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
</dependency>
- 建立 Swagger2配置類
/**
* Swagger2配置類
*
* @author zhuhuix
* @date 2020-07-10
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
@SuppressWarnings("all")
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(true)
.apiInfo(apiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Restful Api介面測試")
.version("1.0")
.build();
}
}
API介面進行測試
- 在測試之前,為防止post、put、delete請求出現 403 Forbidden ,需要禁用跨域請求的安全驗證
/**
* Spring Security配置類
*
* @author zhuhuix
* @date 2020-07-08
* @date 2020-07-10 禁用跨域請求的安全驗證
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AdminService adminService;
// 自定義使用者驗證
@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(adminService)
.passwordEncoder(new BCryptPasswordEncoder());
}
// 保護web請求的安全性規則
@Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/user/**").access("hasRole('ROLE_USER')")
.antMatchers("/admin/**").permitAll()
.and().formLogin().defaultSuccessUrl("/user")
.and().httpBasic()
// 禁用 CSRF
.and().csrf().disable();
}
}
增加使用者(HTTP POST請求)
查詢使用者(HTTP GET請求)
修改使用者(HTTP PUT請求)
刪除使用者(HTTP DELETE請求)
Spring整合REST API服務小結
至此我們完成了Spring整合restful api服務,並通過整合Swagger2,簡單直觀地對http的各種請求進行了完整地測試,下面做個總結:
- Rest端點可以通過Spring MVC來建立,這裡的控制器與面向瀏覽器的控制器遵循相同的程式設計模型。
- @RestController註解簡化了REST控制器,使用它的話,處理器方法中就不需要新增@ResponseBody註解了。
- Restful Api一般會新增JWT認證機制進行安全驗證,具體可參見《SpringBoot整合SpringSecurity實現JWT認證》。