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