1.創建子模塊
右鍵點擊工程名[mapcloudservice] --> New --> Module --> 選擇Maven -->設置子模塊的名稱[datamanager] --> Finish
創建成功後如下圖所示:
2.配置pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
<scope>runtime</scope>
</dependency>
</dependencies>
查看該項目的依賴關係圖:
方法一:右鍵點擊pom.xml文件中的任意處 --> Diagrams --> Show Dependencies
方法二:打開Maven工具欄,選擇 Show Dependencies
3.配置數據源
3.1 配置application.yml
首先在目錄/src/main/resources下創建application.yml,配置內容示例如下:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_example?serverTimezone=UTC&useSSL=true&autoReconnect=true&failOverReadOnly=false
username: chaoshui
password: 123456
jpa:
database: mysql
show-sql: true
hibernate:
ddl-auto: update
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
open-in-view: false
3.2 注意事項
命名策略physical-strategy使用:org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl,Hibernate 會默認以實體名和屬性名分別作爲表名及字段名進行映射,但是如果添加了註解@Table和@Column,則以註解屬性值進行映射命名。
4.創建Entity類
entity用於關聯映射數據庫中的一張表,entity類需要完成以下幾項工作:
(1)註解
@Entity:表明這是一個實體類,與指定的數據庫表進行映射
@Id:該屬性映射爲數據庫的主鍵
@GeneratedValue:默認使用主鍵生成方式爲自增,hibernate會自動生成一個名爲HIBERNATE_SEQUENCE的序列
@Table:指定映射的表名,若沒有則根據類的名稱進行映射
@Column:指定映射的字段名
@OneToOne/@OneToMany/ManyToOne:一對一、一對多、多對一的關聯
(2)定義屬性,類型爲私有
(3)創建所有屬性所對應的setter和getter方法
(4)創建帶參數的構造器和無參數的構造函數
(5)重寫父類中的eauals()方法和hashcode()方法
(6)實現序列化並賦予其一個版本號。
示例代碼:
package com.emapgo.datamanager.entity;
import net.bytebuddy.implementation.HashCodeMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.core.HashCodeCustomizer;
import sun.security.util.AuthResources_pt_BR;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "UserManage")
public class UserManage implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "clientID")
private String clientID;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@Column(name = "credentials")
private String credentials;
@Column(name = "grantType")
private String grantType;
@Column(name = "accessToken")
private String accessToken;
@Column(name = "tokenType")
private String tokenType;
@Column(name = "expireIN")
private String expireIN;
@Column(name = "scope")
private String scope;
public UserManage(){}
public UserManage(String _clientID,
String _username,
String _password,
String _credentials,
String _grantType,
String _accessToken,
String _tokenType,
String _expireIN,
String _scope){
this.clientID = _clientID;
this.username = _username;
this.password = _password;
this.credentials = _credentials;
this.grantType = _grantType;
this.accessToken = _accessToken;
this.tokenType = _tokenType;
this.expireIN = _expireIN;
this.scope = _scope;
}
// getter and setter methods
public String getClientID() {
return clientID;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getCredentials() {
return credentials;
}
public String getGrantType() {
return grantType;
}
public String getAccessToken() {
return accessToken;
}
public String getTokenType() {
return tokenType;
}
public String getExpireIN() {
return expireIN;
}
public String getScope() {
return scope;
}
public void setClientID(String clientID) {
this.clientID = clientID;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setCredentials(String credentials) {
this.credentials = credentials;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public void setExpireIN(String expireIN) {
this.expireIN = expireIN;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString(){
return "Table-UserManage: " + "(" + this.clientID + "," + this.username + "," +
this.password + "," + this.credentials + "," +
this.grantType + "," + this.accessToken + "," +
this.expireIN + "," + this.scope + ")\n";
}
// @Override
// public int hashCode(){}
// @Override
// public boolean equals(Object obj){
// if(this == obj){
// return true;
// }
// if(obj == null || (getClass() != obj.getClass())){
// return false;
// }
// UserManage other = (UserManage) obj;
// if(!this.clientID.equals(other.clientID)){
// return false;
// }
// return true;
// }
}
5.創建Repository接口
5.1創建repository接口
目的是通過repository訪問MySQL數據庫。
(1) 需要添加entity的類型和ID的類型用於表示關聯哪個entity。
(2) 增刪改查等操作方法只需按照書寫規範進行聲明,不需要實現,spring data jpa會在運行程序時根據方法名稱自動創建相關的實現,如下圖所示是CrudRepository接口中的全部方法
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
// 保存指定的entity
<S extends T> S save(S var1);
// 保存所有的entity
<S extends T> Iterable<S> saveAll(Iterable<S> var1);
// 根據指定屬性返回entity
Optional<T> findById(ID var1);
// 判斷具有指定屬性的entity是否存在
boolean existsById(ID var1);
// 返回全部entity
Iterable<T> findAll();
// 根據指定屬性返回全部entity
Iterable<T> findAllById(Iterable<ID> var1);
// 返回entity的數量
long count();
// 根據指定的屬性刪除entity
void deleteById(ID var1);
// 刪除指定的entity
void delete(T var1);
// 刪除全部entity
void deleteAll();
void deleteAll(Iterable<? extends T> var1);
}
(3) 方法名支持的Query關鍵字:
Keyword | Sample | JPQL snippet |
---|---|---|
And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
Between | findByStartDateBetween | … where x.startDate between ?1 and ?2 |
LessThan | findByAgeLessThan | … where x.age < ?1 |
LessThanEqual | findByAgeLessThanEqual | … where x.age <= ?1 |
GreaterThan | findByAgeGreaterThan | … where x.age > ?1 |
GreaterThanEqual | findByAgeGreaterThanEqual | … where x.age >= ?1 |
After | findByStartDateAfter | … where x.startDate > ?1 |
Before | findByStartDateBefore | … where x.startDate < ?1 |
IsNull, Null | findByAge(Is)Null | … where x.age is null |
IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
Like | findByFirstnameLike | … where x.firstname like ?1 |
NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection ages) | … where x.age not in ?1 |
True | findByActiveTrue() | … where x.active = true |
False | findByActiveFalse() | … where x.active = false |
IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstame) = UPPER(?1) |
(4) 可以繼承的接口有四個:
Repository
CrudRepository
PagingAndSortingRepository
QueryByExampleExecutor
接口間繼承關係如下:
5.2基於Query註解的CRUD
在繼承JpaRepository接口的方法中,可以在自定義的查詢方法上使用@Query,來指定該方法要執行的自定義的查詢語句。其中的value值可以是任意的查詢語句,同樣只需要進行方法的定義,無需進行實現。
5.3示例代碼
package com.emapgo.datamanager.repository;
import com.emapgo.datamanager.entity.UserManage;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface UserManageRepository extends CrudRepository<UserManage, String>
{
// find
List<UserManage> findAllByClientID(String clientID);
List<UserManage> findAllByUsername(String username);
List<UserManage> findAllByPassword(String password);
List<UserManage> findAllByCredentials(String credentials);
List<UserManage> findAllByGrantType(String grantType);
List<UserManage> findAllByAccessToken(String accessToken);
List<UserManage> findAllByTokenType(String tokenType);
List<UserManage> findAllByExpireIN(String expireIN);
List<UserManage> findAllByScope(String scope);
UserManage findByClientID(String clientID);
UserManage findByUsername(String username);
UserManage findByPassword(String password);
UserManage findByCredentials(String credentials);
UserManage findByGrantType(String grantType);
UserManage findByAccessToken(String accessToken);
UserManage findByTokenType(String tokenType);
UserManage findByExpireIN(String expireIN);
UserManage findByScope(String scope);
UserManage findByClientIDAndAccessToken(String cleintID, String accessToken);
// ...等等
// save
// 略
// update
@Modifying
@Transactional
@Query(value = "update UserManage um set um.username = ?1 where um.clientID = ?2", nativeQuery = true)
public void UpdateUsernameByClientID(String username, String clientID);
// ...等等
// delete
@Modifying
@Transactional
int deleteByClientID(String clientID);
// ...等等
}
5.3選擇性暴露部分CRUD方法
示例如下
@NoRepositoryBean
interface BaseRepository<T, ID> extends Repository<T, ID> {
Optional<T> findById(ID id);
<S extends T> S save(S entity);
}
interface UserManageRepository extends BaseRepository<User, Long> {
// 略
}
6.創建Controller
略
7.添加主程序,測試
@SpringBootApplication
public class datamanageapplication {
@Autowired
UserManageRepository umr;
public static void main(String[] args) {
SpringApplication.run(datamanageapplication.class, args);
}
@Bean
public CommandLineRunner userManageDemo(){
System.out.println("-----------------------> **hello world** <-------------------------");
return (args) -> {
// insert
umr.save(new UserManage("client_00", "lingwen_00", "123456_00", "creden_00", "grant_00","access_00", "token_00", "expire_00", "scope_00"));
umr.save(new UserManage("client_01", "lingwen_01", "123456_01", "creden_01", "grant_01","access_01", "token_01", "expire_01", "scope_01"));
// update
umr.UpdateUsernameByClientID("lingwen_01", "client_00");
System.out.println("Updated OK!");
// fetch all records
System.out.println("usermanager found with findAll(): ");
System.out.println("----------------------------------");
for(UserManage um : umr.findAll()){
System.out.println(um.toString());
}
System.out.println();
// fetch all records by clientID
List<UserManage> um1 = umr.findAllByClientID("client_00");
System.out.println("user manage found with findById(1L):");
System.out.println("-----------------------------");
System.out.println(um1.toString());
// fetch all records by grant_type
UserManage um2 = umr.findByScope("scope_00");
System.out.println("user manage found with findById(2L):");
System.out.println("-----------------------------");
if(um2 != null){
System.out.println(um2.toString());
}else {
System.out.println("cannot find any record that have attribute 'scope_00' in table UserManage!");
}
System.out.println();
// fetch all user manage by ******
// 略
// delete
umr.deleteByClientID("client_08");
System.out.println("deleted OK!");
};
}
}
8.可能遇到的問題
寫entity類的時候,相關注解會出現紅色波浪線,並且在最終運行程序的時候會失敗(但是底層Hibernate顯示可以連接上數據庫),如下圖所示
解決方法:
- 點擊View --> ToolWindows -> Persistence,在左下區域出現Persistence
- 右鍵點擊Entity --> Generate Persistence Mapping --> By Database Schema,在彈出的對話框中選擇Choose Data Source
- 配置好數據庫相關的選項,可以點擊Test Connection測試能否連接成功
- 完了之後點擊OK, 回到上一個對話框,點擊Database Schema mapping下的刷新,選中UserManage表 --> OK (必須點刷新,不點刷新不會自動出現這些內容)
- 右鍵單擊Entity --> Assign Datasource 配置數據源
配置完以後,紅色波浪線消失,程序能夠正常運行,增刪改查等操作執行也沒有問題
- 原因分析:暫時不清楚
參考資料
1.Spring Data JPA - Reference Documentation
2.Accessing Data with Spring Data JPA and MySQL
3.Getting Started with Spring Data JPA
4.spring data jpa 實戰之增刪改查(乾貨!你想要的查詢!)
5.Spring Data JPARepository Example
其他相關參考資料:
Create your first Java application
Spring MVC框架入門教程
MySQL Java tutorial