這裏使用 IDEA 來進行工程的建立,使用了 Gradle 對整個項目進行管理,具體的過程以下:java
點擊 Create New Project -> Spring Initializr , 以後選擇默認的 Initalizr Service URL,而後填寫項目的信息,以下所示:mysql
這裏採用了 Gradle 來進行項目的管理,而後就是對 SpringBoot 進行選擇,以下:web
依賴組件 | 含義 |
---|---|
Spring Boot DevTools | 熱部署插件,能夠在項目運行時自動替換 class,生產環境禁用 |
Lombok | 簡化 Java 代碼 |
Spring Web Starter | Spring Web 開發的起步依賴 |
Spring Data JPA | 持久層 ORM 框架 |
MySQL Driver | MySQL 驅動 |
作完這一步以後就是選擇項目的存儲位置。所有完成以後項目的結構以下所示:spring
../blog/
├── blog.iml
├── build.gradle
├── .gradle
└── src
├── main
│ ├── java
│ └── resources
└── test
└── java
複製代碼
這裏主要是對 Gradle 的配置作出小小的改動,在 repositories
節點下增長新的倉庫配置,具體以下:sql
plugins {
id 'org.springframework.boot' version '2.1.6.RELEASE'
id 'java'
}
apply plugin: 'io.spring.dependency-management'
group = 'hk.mars'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
maven { url "https://maven.aliyun.com/repository/spring-plugin" }
maven { url "https://maven.aliyun.com/repository/spring" }
maven { url "https://repo.spring.io/libs-release" }
maven { url "https://repo.spring.io/milestone" }
mavenLocal()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
複製代碼
這裏須要注意的地方是 Gradle 在初始化的時候速度略慢,甚至可能會失敗,主要是 Gradle 在初始化時會下載一個 .zip 文件,受到國內網絡大環境的影響,該網站響應較慢,不過對此網絡上有不少解決的辦法。shell
同時國內訪問 Maven 中央倉庫也受到網絡大環境的影響比較慢,這裏設置了阿里雲提供的 Maven 倉庫,能夠提升訪問速度(位置靠上的倉庫優先訪問)。數據庫
SpringData JPA 能夠在項目啓動的時候會自動的數據庫中的表,所以沒必要提早初始化數據庫,只需在配置文件中配置數據源便可,固然這種自動生成表的方法是不容許在生產環境中使用的,具體的配置以下:json
application.propertiesapi
spring.datasource.url=jdbc:mysql://x.x.x.x:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=xxxxxx
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
複製代碼
這裏須要進一步說明的是 spring.jpa.properties.hibernate.hbm2ddl.auto
的含義:網絡
前文提到過 SpringBoot JPA 在項目啓動的時候會自動的在數據庫中生成相應的表,該項配置就是設置自動生成的策略,一個有四個選項,分別以下:
生成策略 含義 create 每次加載 hibernate 時都會從新生成表 create-drop 每次加載 hibernate 時都會從新生成表,在 sessionFactory 關閉時刪除表結構 update 第一次加載 hibernate 時都會從新生成表,以後每次加載 hibernate 會更新表結構 validate 驗證模型與數據庫表結構是否匹配 none 若是不配置該項,默認不對數據庫作任何改動
在設計數據庫的時候,不一樣的表可能具備相同的字段,用來存儲一些通用的信息,例如每一張表中都會有 id
字段做爲主鍵,同時存在 create_time
、 update_time
用來存儲表中每一行數據的通用信息,這時候就須要定義一個超類來表示這些信息。 這一功能可使用 @MappedSuperclass
註解實現,具體實現以下的 BaseEntity.java :
package hk.mars.user;
import lombok.Data;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.sql.Timestamp;
/** * @author qingke.hk@gmmail.com */
@MappedSuperclass
@Data
public abstract class BaseEntity {
@Id
@GeneratedValue(generator = "id-uuid")
@GenericGenerator(name = "id-uuid", strategy = "uuid")
private String id;
@Column(name = "create_time")
private Timestamp createTime;
@Column(name = "update_time")
private Timestamp updateTime;
}
複製代碼
@Data
註解是 Lombok 提供的註解,能夠簡化 Java 代碼。
@Id
註解通常是用在屬性上,表示該屬性對應的數據庫表字段爲主鍵類型,同時可使用 @GeneratedValue
和 @GenericGenerator
指定主鍵生成策略,在上文使用了內置的 uuid
的生成策略,但 hibernate 還提供了替他的策略,同時還支持自定義的主鍵生成策略。
@MappedSuperclass
註解是 SpringData JPA 提供的註解,主要是用於用於類上,表示該類是全部的 Entity 的父類,固然你要在你的 Entity 中顯示的繼承,具體的用法能夠繼續向下看。
- todo: 寫一篇 hibernate 的主鍵生成策略相關的博客
- todo: 寫一篇 Lombok 的博客
首先定義用戶角色的枚舉:
package hk.mars.user;
import lombok.Getter;
/** * @author qingke.hk@gmmail.com */
public enum UserRole {
/** 管理員角色 */
ADMIN("admin"),
/** 用戶角色 */
USER("user");
@Getter
private String role;
UserRole(String role) {
this.role = role;
}
}
複製代碼
@Getter
是有 Lombok 提供的,能夠在編譯的時候自動生成 Getter 方法。
接下來咱們將在繼承 BaseEntity
的基礎之上定義用戶模型,以下 UserEntity.java 所示:
package hk.mars.commons;
import hk.mars.commons.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import java.util.Date;
/** * @author qingke.hk@gmmail.com */
@Data
@Entity
@Table(name = "user")
@EqualsAndHashCode(callSuper = false)
@SuppressWarnings("WeakerAccess")
public class UserEntity extends BaseEntity {
private String name;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@DateTimeFormat(pattern = "yyyy-mm-dd")
private Date birthday;
private String email;
private String password;
@Enumerated(EnumType.STRING)
private UserRole role;
}
複製代碼
@Data
與 @EqualsAndHashCode
註解是有 Lombok 提供,用來簡化 Java 代碼。
@Entity
註解是最主要的一個註解,表示這個類表示數據庫中的一個表。
@Table
註解主要是聲明表的配置,例如上文能夠設置表名,固然還能夠設置 數據庫的名稱、設置索引等等。
@Column
註解主要是對數據庫表字段與 Java 類屬性之間的關係進行配置,上文僅僅是設置了字段名稱,同時還能夠設施是否惟1、長度限制、是否可控等等。
@Enumerated
表示屬性是一個註解類型,可是在存儲的時候字符串形式進行存儲。
@DateTimeFormat
註解是有 Spring 提供的,在這裏由於 birthday
是時間類型,而調用 RESTful 接口的時候是以 JSON 形式,若是不走任何處理是沒法將 JSON 字符串轉化爲時間類型的,所以咱們在這裏使用了 @DataTimeFormat
註解。
- todo: 後面寫一些關於 SpringData JPA 的更多的用法。
SpringBoot JPA 能夠將接口中的方法名解析爲相應的 SQL 語句,但同時針對一些常見的 CRUD 操做提供了一個 CrudRepository
的接口,經過繼承能夠實現一些常見的 CRUD 操做,固然若是 CrudRepository
提供的操做不能知足業務的需求能夠編寫新的接口,以下,定義了一個新的分頁查詢的接口:
UserRepository.java
package hk.mars.user;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
/** * @author qingke.hk@gmmail.com */
public interface UserRepository extends CrudRepository<UserEntity, String> {
/** * 查詢全部的用戶信息 - 分頁 * * @param pageConf 分頁參數 * @return 用戶信息 */
Page<UserEntity> findAll(Pageable pageConf);
}
複製代碼
當你已經完成上述的操做後,此時的項目的結構以下所示:
../blog/
├── blog.iml
├── build.gradle
└── src
├── main
│ ├── java
│ │ └── hk.mars
│ │ ├── Application.java
│ │ ├── commons
│ │ │ ├── BaseEntity.java
│ │ │ └── response
│ │ │ ├── ResultResponse.java
│ │ │ └── ResultResponseBuilder.java
│ │ ├── config
│ │ └── user
│ │ ├── UserController.java
│ │ ├── UserEntity.java
│ │ ├── UserRepository.java
│ │ ├── UserRole.java
│ │ └── UserService.java
│ └── resources
│ └── application.properties
└── test
└── java
└── hk
└── mars
複製代碼
固然此時的項目代碼多了一些別的東西,不過都與 SpringData JPA 無關,在下載源碼以後你們能夠自行查看便可。
接下來就能夠編寫 Service 和 Controller 來對以前的代碼進行測試:
UserService.java:
package hk.mars.user;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import java.util.List;
/** * @author qingke.hk@gmmail.com */
@SuppressWarnings("WeakerAccess")
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<UserEntity> getUserList(Pageable pageConf) {
Page<UserEntity> userInPage = userRepository.findAll(pageConf);
return userInPage.getContent();
}
public void saveUser(UserEntity userEntity) {
String password = userEntity.getPassword();
userEntity.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
this.userRepository.save(userEntity);
}
}
複製代碼
UserController.java:
package hk.mars.user;
import hk.mars.commons.response.ResultResponse;
import hk.mars.commons.response.ResultResponseBuilder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/** * @author qingke.hk@gmmail.com */
@RestController
public class UserController {
private static final int DEFAULT_PAGE_NUMS = 10;
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/user")
public ResultResponse<List<UserEntity>> getUsers(
@RequestParam(value = "page-num", defaultValue = "0") Integer pageNum,
@RequestParam(value = "page-size", defaultValue = "10") Integer pageSize) {
Pageable pageRequest = PageRequest.of(pageNum, pageSize == null ? DEFAULT_PAGE_NUMS : pageSize);
List<UserEntity> userList = this.userService.getUserList(pageRequest);
return ResultResponseBuilder.buildSuccess(userList);
}
@PostMapping("/user")
public ResultResponse saveUser(UserEntity user) {
if (user == null) {
return ResultResponseBuilder.buildError("use information is null");
}
this.userService.saveUser(user);
return ResultResponseBuilder.buildSuccess();
}
}
複製代碼
而後就是啓動項目,開始測試:
同時在啓動的過程當中經過觀察日誌輸出能夠看到 SpringData JPA 會在項目啓動的過程當中刪除掉數據庫的舊錶,而後從新建表:
對於 RESTful 風格的接口能夠經過 IDEA 自帶的功能進行測試,能夠新建一個 rest-api.http 文件,經過該文件就能夠直接在 IDEA 中進行測試,文件內容以下:
POST http://localhost:8080/user?name=Tom&password=123456&birthday=2019-07-11&email=test@test.test
Accept: */*
Cache-Control: no-cache
###
GET http://localhost:8080/user?page-num=0&page-size=10
Accept: */*
Cache-Control: no-cache
複製代碼
經過點擊左側邊欄上的三角標誌就能夠啓動一次測試,同時 IDEA 會將測試結果保存爲一個 JSON 文件,這樣就能夠查看測試的歷史,查看的方法是在下圖的 2019-07-14T125418.200.json
使用快捷鍵 Command + B 就能夠直接轉跳到文件中去。
點擊測試以後會顯示以下,能夠看到測試的返回結果是成功了,而後咱們去查看數據庫中的信息,能夠看到數據庫中已經插入了一條數據:
而後運行第二個測試,看分頁查詢是否成功:
至此本片博客就基本上完成了,咱們已經能夠簡單的使用 SpringData JPA 進行操做。
- 上傳項目至 Github