Steam免費送出太空策略建造遊戲《火星求生》
阿新 • • 發佈:2021-09-08
JPA
- 簡介
- JPA 是 Java Persistence API 的簡稱,是一套 Sun 公司 Java 官方制定的 ORM(Object Relational Mapping) 方案,是規範、是標準,Sun 公司自己並沒有實現;
- 市場上的主流的 JPA 框架有:Hibernate (JBoos)、EclipseTop(Eclipse社群)、OpenJPA (Apache基金會),Hibernate 是眾多實現者之中,效能最好的,我們引入的 JPA 框架,採用Hibernate實現,需要注意的是,引用是 javax.persistence 這個“標準”包,和 org.hibernate 實現包;
- JPA 想要做的就是儘量讓你少寫 Sql,甚至不寫 Sql,基於這種思想,JPA 實現了它自己的一套語法、註解規則,JPA 要用各種註解配合來實現資料實體間一對多、多對多等關聯關係,正因為這樣,個人覺得實體變得不那麼單純,摻雜了邏輯在裡面,這增加了實體的複雜度,對於比較複雜的業務來說,很容易造成實體間直接或間接的迴圈引用;
- 在此,我們引入將引入 Spring Data Jpa,在 JPA 之上新增另一層抽象(Repository 層的實現),極大地簡化持久層開發;
- Hibernate、JPA、Spring Data Jpa 之間的關係如下:
- 引入 Jar
- spring-context
- spring-orm
- mysql-connector-java
- c3p0
- hibernate-core
- spring-data-jpa
- ---------------- 已經引入的部分忽略 ----------------
- 1
<wiz_code_mirror>
1
<!-- Spring data jpa -->
2<dependency>
3<groupId>org.springframework.data</groupId>
4<artifactId>spring-data-jpa</artifactId>
5<version>2.3.4.RELEASE</version>
6</dependency>
- 2
- 配置
- 配置結構
- applicationContext.xml ---- 全域性配置,為了避免該檔案雜亂,我們按功能拆分為子配置檔案;
- 引入 jdbcParms.properties ---- Jdbc 配置資訊;
- 引入 hibernateParms.properties ---- Hibernate 配置屬性資訊;
- 引入 springJpa.xml ---- JPA 注入 Spring 配置;
- applicationContext.xml
- 1
<wiz_code_mirror>
1
<!-- 載入屬性檔案 -->
2<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
3<property name="locations">
4<list>
5<value>classpath:config/properties/jdbcParms.properties</value>
6<value>classpath:config/properties/hibernateParms.properties</value>
7</list>
8</property>
9</bean>
10 11<!-- 引入別的配置檔案 -->
12<import resource="springJpa.xml"/>
- 2
- hibernateParms.properties
- 參見 Hibernate 相關配置;
- springJpa.xml
- 配置鏈
- dataSource ---- entityManagerFactory ---- transactionManager ---- jpa:repositories;
- 1
<wiz_code_mirror>
1
<?xml version="1.0" encoding="UTF-8"?>
2<beans xmlns="http://www.springframework.org/schema/beans"
3xmlns:context="http://www.springframework.org/schema/context"
4xmlns:aop="http://www.springframework.org/schema/aop"
5xmlns:tx="http://www.springframework.org/schema/tx"
6xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
7xmlns:jpa="http://www.springframework.org/schema/data/jpa"
8xsi:schemaLocation="http://www.springframework.org/schema/beans
9http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
10http://www.springframework.org/schema/context
11http://www.springframework.org/schema/context/spring-context-3.0.xsd
12http://www.springframework.org/schema/mvc
13http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
14http://www.springframework.org/schema/aop
15http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
16http://www.springframework.org/schema/tx
17http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
18http://www.springframework.org/schema/data/jpa
19http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" >
20 21<!-- 資料來源,spring jdbc || c3p0 jdbc -->
22<!-- <bean id="dataSourceForJpa" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
23<property name="driverClassName" value="${jdbc.driverClassName}"/>
24<property name="url" value="${jdbc.url}"/>
25<property name="username" value="${jdbc.username}"/>
26<property name="password" value="${jdbc.password}"/>
27</bean> -->
28<!-- 配置 c3p0 資料來源 -->
29<bean id="dataSourceForJpa" class="com.mchange.v2.c3p0.ComboPooledDataSource">
30<property name="driverClass" value="${jdbc.driverClassName}" />
31<property name="jdbcUrl" value="${jdbc.url}" />
32<property name="user" value="${jdbc.username}" />
33<property name="password" value="${jdbc.password}" />
34 35<!-- 連線池中連線用完時,c3p0 一次性建立的連線數 -->
36<property name="acquireIncrement" value="${pool.acquireIncrement}" />
37<!-- 初始化連線數,在 minPoolSize 和 maxPoolSize 之間 -->
38<property name="initialPoolSize" value="${pool.initialPoolSize}" />
39<property name="minPoolSize" value="${pool.minPoolSize}" />
40<property name="maxPoolSize" value="${pool.maxPoolSize}" />
41<!-- 連線關閉時預設將所有未提交的操作回滾,預設為 false -->
42<property name="autoCommitOnClose" value="${pool.autoCommitOnClose}"/>
43</bean>
44 45<!-- 配置 entityManagerFactory -->
46<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
47<!-- 設定資料來源 -->
48<property name="dataSource" ref="dataSourceForJpa" />
49<!-- 掃描 Entity 包 -->
50<property name="packagesToScan" value="com.sfac.springMvc.module.*.entity" />
51<!-- 指定 JPA 實現廠商 -->
52<property name="persistenceProvider">
53<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
54</property>
55<!-- 指定 JPA 供應商介面卡 -->
56<property name="jpaVendorAdapter">
57<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
58</property>
59<!-- 配置 JPA 屬性 -->
60<property name="jpaProperties">
61<props>
62<!-- 動態生成表策略 -->
63<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
64<!-- 命名規則隱式策略 -->
65<prop key="hibernate.implicit_naming_strategy">${hibernate.implicit_naming_strategy}</prop>
66<!-- 資料庫方言 -->
67<prop key="hibernate.dialect">${hibernate.dialect}</prop>
68<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
69<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
70</props>
71</property>
72</bean>
73 74<!-- 配置事務管理器 -->
75<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
76<property name="entityManagerFactory" ref="entityManagerFactory" />
77</bean>
78 79<!-- 開啟事務註解 -->
80<tx:annotation-driven transaction-manager="jpaTransactionManager"/>
81 82<!-- 配置 repository -->
83<jpa:repositories base-package="com.sfac.springMvc.module.*.repository"
84transaction-manager-ref="jpaTransactionManager"
85entity-manager-factory-ref="entityManagerFactory" />
86</beans>
- 2
- 應用
- 主要介面和實現類
- Repository
- 屬性查詢
- 介面方法命名:
- findBy + 屬性 + 關鍵字 + 屬性(option);
- find + Top || First(option) +By +屬性 + 關鍵字 + 屬性(option);
- 查詢關鍵字列表
- 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 ---- findByAgeIsNull ---- … 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<Age> ages) ---- … where x.age in ?1;
- NotIn ---- findByAgeNotIn(Collection<Age> 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);
- @Query 註解查詢;
- 查詢語言
- SQL 語言
- 關係型資料庫查詢語言;
- select name, age, user_id from t_user;
- JPA 中使用 Sql 語句,只需註解中新增引數 nativeQuery = true 即可;
- HQL 語言
- Hibernate 造出來的物件語言,只有 Hibernate 框架能夠解析,並將其通過一系列的對映轉換,拼湊成 SQL 語言;
- 使用 “類名” 取代 “表名”,用 “類名.屬性名” 取代 “表名.列名”,類名建議不要省略;
- 沒有 * 查詢,使用 from 類名 代替;
- 查詢操作使用 @Query 註解
- 刪除修改操作使用 @Modifying + @Transactional +@Query註解,@Transactional 可加在 service 層;
- JPQL 語言
- EJB3.0 中的 JPA 造出來的物件查詢語言,其原型類似於 HQL,Sun 看到 Hibernate 做的 ORM 技術做的非常好,成為行業內領導 ORM 框架的主流產品,故 Sun 將其吸收進 EJB3 中,制定了一套 ORM 的 JAVA API 標準;
- 傳參方式
- select name,age,userId from User where userName = ?1; ---- ?加數字表示佔位符,從 1 開始;
- select name,age,userId from User where userName=:userName; ---- :加上變數名,這裡是與方法引數中有 @PARAM 的值匹配;
- CrudRepository
- 添加了對資料的增刪改查的方法;
- PagingAndSortingRepository
- 添加了對資料的分頁和排序方法;
- QueryByExampleExecutor
- Example 條件查詢;
- JpaRepository
- 對繼承父介面中方法的返回值進行了適配,在父類介面中通常都返回迭代器,需要我們自己進行強制型別轉化,而在 JpaRepository 中,直接返回了 List;
- JpaSpecificationExecutor
- 主要提供了多條件查詢的支援,並且可以在查詢中新增分頁和排序,因為這個介面單獨存在,因此需要配合以上說的介面使用;
- QueryDslPredicateExecutor
- SimpleJpaRepository ---- 實現類;
- QueryDslJpaRepository ---- 實現類;
- 新增介面
- 針對每個 Bean 書寫一個持久層介面,繼承 JpaRepository<T, ID> 介面(其中 T 是實體 bean, ID 是主鍵),新增 @Repository 註解,到此,我們一行程式碼都不用寫,即可呼叫父介面實現功能;
- StudentRepository.java
- 1
<wiz_code_mirror>
1
2
public interface StudentRepository extends JpaRepository<Student, Integer> {
3}
- 2
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
private StudentRepository studentRepository;
3 45
6
public ResultEntity<Student> insertStudentForJpa(Student student) {
7studentRepository.saveAndFlush(student);
8return new ResultEntity<Student>(ResultStatus.SUCCESS.status, "Insert success.", student);
9}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student ---- post
3* {"studentName":"HymanHu"}
4* {"studentName":"HymanHu", "studentCard":{"cardNo":"studentCard001"}}
5*/
67
public ResultEntity<Student> insertStudentForJpa(
8return studentService.insertStudentForJpa(student);
9}
- 2
- 修改介面
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
3
public ResultEntity<Student> updateStudentForJpa(Student student) {
4studentRepository.saveAndFlush(student);
5// int i = 1 / 0;
6return new ResultEntity<Student>(ResultStatus.SUCCESS.status, "Update success.", student);
7}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student ---- put
3* {"id":"2","studentName":"HymanHu1"}
4* {"id":"2","studentName":"HymanHu1","studentCard":{"id":"1","cardNo":"studentCard002"}}
5*/
67
public ResultEntity<Student> updateStudentForJpa(
8return studentService.updateStudentForJpa(student);
9}
- 2
- 刪除介面
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
public ResultEntity<Object> deleteStudentForJpa(Integer id) {
3studentRepository.deleteById(id);
4return new ResultEntity<Object>(ResultStatus.SUCCESS.status, "Delete success.");
5}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student/2 ---- delete
3*/
45
public ResultEntity<Object> deleteStudentForJpa(
6return studentService.deleteStudentForJpa(id);
7}
- 2
- 父介面查詢
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
public Student getStudentByIdForJpa(Integer id) {
3return studentRepository.findById(id).orElse(null);
4}
56
public List<Student> getStudentsForJpa() {
7return studentRepository.findAll();
8}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student/9 ---- get
3*/
45
public Student getStudentByIdForJpa(
6return studentService.getStudentByIdForJpa(id);
7}
8/**
9* 127.0.0.1/api/jpa/students ---- get
10*/
1112
public List<Student> getStudentsForJpa(
13return studentService.getStudentsForJpa();
14}
- 2
- Example && Criteria 查詢
- JpaRepository:<S extends T> Page<S> findAll(Example<S> example, Pageable pageable);
- Example:動態條件查詢樣本 ----static <T> Example<T> of(T probe, ExampleMatcher matcher);
- T:實體 bean;
- ExampleMatcher:查詢匹配器;
- ExampleMatcher.matchingAny() ---- 匹配條件是 or 的關係;
- ExampleMatcher.matching() ---- 匹配條件是 and 的關係;
- withMatcher("studentName", match -> match.contains()) ---- 模糊查詢,即 %studentName%;
- withIgnorePaths("studentId", "createDate"); ---- 忽略欄位,可以自動忽略空值的欄位,但 id 是基本資料型別,預設值為 0,必須忽略;
- Pageable:分頁元件 ---- public static PageRequest of(int page, int size, Sort sort);
- page:當前頁,從 0 開始;
- size:每頁大小;
- sort:排序物件 ---- new Sort(direction, orderBy);
- direction:排序方向,Sort.Direction.ASC;
- orderBy:排序欄位;
- Page:返回分頁物件;
- JpaSpecificationExecutor:Page findAll(@Nullable Specification<T> spec, Pageable pageable);
- Specification:Criteria 多條件查詢,支援時間比較、數字比較等;
- Pageable
- Page
- StudentRepository.java
- 1
<wiz_code_mirror>
1
2
public interface StudentRepository extends JpaRepository<Student, Integer>, JpaSpecificationExecutor<Student> {
3}
- 2
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
public Page<Student> getStudentsBySearchBeanForJpa(SearchBean searchBean) {
3searchBean.initSearchBean();
4// Page<Student> page = exampleAndPage(searchBean);
5Page<Student> page = criteriaAndPage(searchBean);
6return page;
7}
8 9/**
10* -實現方式一:Example + Page 查詢
11*/
12public Page<Student> exampleAndPage(SearchBean searchBean) {
13// 建立 Pageable 物件
14String orderBy = StringUtils.isBlank(searchBean.getOrderBy()) ? "id" : searchBean.getOrderBy();
15Sort.Direction direction = StringUtils.isBlank(searchBean.getDirection()) ||
16searchBean.getDirection().equalsIgnoreCase("asc") ? Sort.Direction.ASC : Sort.Direction.DESC;
17Sort sort = new Sort(direction, orderBy);
18// 當前頁起始為 0
19Pageable pageable = PageRequest.of(searchBean.getCurrentPage() - 1, searchBean.getPageSize(), sort);
20 21// 建立 Example 物件
22Student student = new Student();
23student.setStudentName(searchBean.getKeyWord());
24student.setCreateDate(LocalDateTime.of(2021, 1, 19, 0, 0));
25// matchingAny 相當於 or 連線查詢條件,matching 相當於 and 連線查詢條件
26ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny()
27// 模糊查詢,即 %{studentName} %
28.withMatcher("studentName", match -> match.contains())
29// 時間型別不支援模糊查詢,生成的語句為createDate=?,同時也不支援 id > startId && id < endId 這樣的操作
30.withMatcher("createDate", match -> match.contains())
31// 忽略基本資料型別欄位,如果使用包裝類則無需忽略
32.withIgnorePaths("id");
33Example<Student> example = Example.of(student, exampleMatcher);
34 35return studentRepository.findAll(example, pageable);
36}
37 38/**
39* -實現方式:Criteria + Page
40*/
41public Page<Student> criteriaAndPage(SearchBean searchBean) {
42// 建立 Pageable 物件
43String orderBy = StringUtils.isBlank(searchBean.getOrderBy()) ? "id" : searchBean.getOrderBy();
44Sort.Direction direction = StringUtils.isBlank(searchBean.getDirection()) ||
45searchBean.getDirection().equalsIgnoreCase("asc") ? Sort.Direction.ASC : Sort.Direction.DESC;
46Sort sort = new Sort(direction, orderBy);
47// 當前頁起始為 0
48Pageable pageable = PageRequest.of(searchBean.getCurrentPage() - 1, searchBean.getPageSize(), sort);
49 50// 建立 Specification 物件
51Specification<Student> specification = new Specification<Student>() {
52private static final long serialVersionUID = 1L;
53 54/**
55* -構造語句 select * from test_student where createDate>=? and
56* (studentName like ? or id between 10 and 20) order by id desc limit ?
57*/
58public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query,
60CriteriaBuilder criteriaBuilder) {
61 62return criteriaBuilder.and(
63criteriaBuilder.greaterThanOrEqualTo(
64root.get("createDate").as(LocalDateTime.class),
65LocalDateTime.of(2021, 1, 20, 0, 0)),
66criteriaBuilder.or(
67criteriaBuilder.like(root.get("studentName").as(String.class),
68String.format("%%%s%%", searchBean.getKeyWord())),
69criteriaBuilder.between(root.get("id"), 10, 20)
70)
71);
72}
73};
74 75return studentRepository.findAll(specification, pageable);
76}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/students ---- post
3* {"currentPage":1, "pageSize":5, "keyWord":"hy", "orderBy":"id", "direction":"desc"}
4* {"currentPage":1, "pageSize":5, "keyWord":"hu", "orderBy":"studentName", "direction":"asc"}
5* -注意:排序欄位不能使用下劃線
6*
7*/
89
public Page<Student> getStudentsBySearchBeanForJpa(
10return studentService.getStudentsBySearchBeanForJpa(searchBean);
11}
- 2
- 屬性查詢
- StudentRepository.java
- 1
<wiz_code_mirror>
1
List<Student> findByStudentName(String studentName);
- 2
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
public Student getStudentByNameForJpa(String studentName) {
3List<Student> students = Optional.ofNullable(studentRepository.findByStudentName(studentName))
4.orElse(Collections.emptyList());
5return students.isEmpty() ? null : students.get(0);
6}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student?studentName=HymanHu ---- get
3*/
45
public Student getStudentByNameForJpa(
6return studentService.getStudentByNameForJpa(studentName);
7}
- 2
- Sql && Hql 查詢
- StudentRepository.java
- 1
<wiz_code_mirror>
1
//@Query(nativeQuery = true, value = "select * from test_student where id = :id")
23
Student getStudentById(
4 56
//@Query(nativeQuery = true, value = "update test_student set student_name = :studentName where id = :id")
78
void updateStudentName(
9 1011
12
"set student_name = :#{#student.studentName} where id = :#{#student.id}")
13void updateStudent(
- 2
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
public Student getStudentByIdV2ForJpa(Integer id) {
3return studentRepository.getStudentById(id);
4}
5 67
8
public ResultEntity<Student> updateStudentNameForJpa(Student student) {
9studentRepository.updateStudentName(student.getStudentName(), student.getId());
10return new ResultEntity<Student>(ResultStatus.SUCCESS.status, "Update success.", student);
11}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/student/2/v2 ---- get
3*/
45
public Student getStudentByIdV2ForJpa(
6return studentService.getStudentByIdV2ForJpa(id);
7}
8 9/**
10* 127.0.0.1/api/jpa/student/v2 ---- put
11* {"id":"1","studentName":"HymanHu1"}
12*/
1314
public ResultEntity<Student> updateStudentNameForJpa(
15return studentService.updateStudentNameForJpa(student);
16}
- 2
- 批量介面
- 思路
- 方式一:父介面中有 saveAll、deleteInBatch 方法,可完成批量增刪改操作,在此不做贅述;
- 方式二:引入 @persistencecontext 註解和 EntityManager 類,屬於 Jpa 包,用途是將 Entity 在記憶體操作,處理完成之後再一次性同步到資料庫,效率要比第一種方式高;
- StudentServiceImpl.java
- 1
<wiz_code_mirror>
1
2
private EntityManager entityManager;
3 45
6
public ResultEntity<List<Student>> batchInsertStudentsForJpa(List<Student> students) {
7// 方式一,呼叫父介面完成批量操作
8// studentRepository.saveAll(students);
9// studentRepository.flush();
10 11// 方式二,引入 entityManager 進行批量操作,效率高於第一種方式
12students.stream().forEach(item -> {
13entityManager.persist(item);
14});
15entityManager.flush();
16entityManager.clear();
17return new ResultEntity<List<Student>>(ResultStatus.SUCCESS.status, "Update success.", students);
18}
- 2
- StudentController.java
- 1
<wiz_code_mirror>
1
/**
2* 127.0.0.1/api/jpa/students/v2 ---- post
3* [{"studentName":"aa1"},{"studentName":"aa2"}]
4*/
56
public ResultEntity<List<Student>> batchInsertStudentsForJpa(
7return studentService.batchInsertStudentsForJpa(students);
8}
- 2
- 練習
- 建立 User、Role、UserRole、Resource、RoleResource 五個 Bean,使用 Jpa 自動生成表(中間表不要外來鍵關係),使用 Mybatis Or Jpa 實現 User、 Role、Resource 的增刪改查介面;