前言

  jpa是ORM映射框架,更多详情,请戳:apring-data-jpa官网:
http://spring.io/projects/spring-data-jpa
<http://spring.io/projects/spring-data-jpa>,以及一篇优秀的博客:
https://www.cnblogs.com/cmfwm/p/8109433.html
<https://www.cnblogs.com/cmfwm/p/8109433.html>,这里只是记录项目实现。

 

  工程结构



 

  代码编写

  maven引包
<!--添加springdata-jpa依赖 --> <dependency> <groupId>org.springframework.boot</
groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
<!--添加MySQL驱动依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>
mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--
lombok插件--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok
</artifactId> </dependency>
 

  applicaction.yml
#注意:在yml文件中添加value值时,value前面需要加一个空格 #2.0.0的配置切换为servlet.path而不是"-" server: port
:10086 #端口号 servlet: context-path: /springboot #访问根路径 spring: thymeleaf: cache
: false#关闭页面缓存 prefix: classpath:/view/ #thymeleaf访问根路径 mode: LEGACYHTML5
datasource: #数据库相关 url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver jpa:
show-sql: true mvc: date-format: yyyy-MM-dd HH:mm:ss #mvc接收参数时对日期进行格式化 jackson:
date-format: yyyy-MM-dd HH:mm:ss #jackson对响应回去的日期参数进行格式化 time-zone: GMT+8
 

  实体类与表数据



  tb_user



  tb_description



 
/** * 用户类 */ @Entity @Table(name = "tb_user") @Data public class User
implements Serializable { @Id @GeneratedValue(strategy= GenerationType.IDENTITY)
//IDENTITY 自增 private Integer id; @Column(name = "username")//
命名相同或驼峰标识(与数据库下划线映射)可以不用写 private String username; private String password;
private Date created; private String descriptionId; @OneToOne @JoinColumn(name
= "descriptionId",referencedColumnName = "id", insertable =false, updatable =
false) @NotFound(action= NotFoundAction.IGNORE) //用户描述信息 private Description
description; } /** * 用户描述类 */ @Entity @Table(name = "tb_description") @Data
public class Description implements Serializable { @Id @GeneratedValue(strategy
= GenerationType.IDENTITY)//IDENTITY 自增 private Integer id; private String
userId;private String description; }
 

  通讯对象
/** * 统一返回对象 */ @Data public class Result<T> implements Serializable { /** *
通信数据*/ private T data; /** * 通信状态 */ private boolean flag = true; /** * 通信描述 */
private String msg = ""; /** * 通过静态方法获取实例 */ public static <T> Result<T> of(T
data) {return new Result<>(data); } public static <T> Result<T> of(T data,
boolean flag) { return new Result<>(data, flag); } public static <T> Result<T>
of(T data,boolean flag, String msg) { return new Result<>(data, flag, msg); }
@Deprecatedpublic Result() { } private Result(T data) { this.data = data; }
private Result(T data, boolean flag) { this.data = data; this.flag = flag; }
private Result(T data, boolean flag, String msg) { this.data = data; this.flag =
flag;this.msg = msg; } }
 

 

  分页对象
/** * 分页对象(参考JqGrid插件) */ @Data public class PageInfo<M> { private int page;//
当前页码 private int pageSize;//页面大小 private String sidx;//排序字段 private String sord;
//排序方式 private List<M> rows;//分页结果 private int records;//总记录数 private int total;
//总页数 /** * 获取统一分页对象 */ public static <M> PageInfo<M> of(Page page, Class<M>
entityModelClass) {int records = (int) page.getTotalElements(); int pageSize =
page.getSize();int total = records % pageSize == 0 ? records / pageSize :
records / pageSize + 1; PageInfo<M> pageInfo = new PageInfo<>();
pageInfo.setPage(page.getNumber()+ 1);//页码 pageInfo.setPageSize(pageSize);//页面大小
pageInfo.setRows(CopyUtil.copyList(page.getContent(), entityModelClass));//分页结果
pageInfo.setRecords(records);//总记录数 pageInfo.setTotal(total);//总页数 return
pageInfo; }/** * 获取JPA的分页对象 */ public static Page readPage(Query query,
Pageable pageable, Query countQuery) {if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
query.setMaxResults(pageable.getPageSize()); }return
PageableExecutionUtils.getPage(query.getResultList(), pageable, () ->
executeCountQuery(countQuery)); }private static Long executeCountQuery(Query
countQuery) { Assert.notNull(countQuery,"TypedQuery must not be null!"); List
<Number> totals = countQuery.getResultList(); Long total = 0L; for (Number
number : totals) {if (number != null) { total += number.longValue(); } } return
total; } } /** * 分页条件(参考JqGrid插件) */ @Data public class PageCondition { private
int page = 1;//当前页码 private int rows = 10;//页面大小 private String sidx;//排序字段
private String sord;//排序方式 /** * 获取JPA的分页查询对象 */ public Pageable getPageable() {
//处理非法页码 if (page < 0) { page = 1; } //处理非法页面大小 if (rows < 0) { rows = 10; }
return PageRequest.of(page - 1, rows); } }
 

 

 

   UserController
@RestController @RequestMapping("/user") public class UserController {
@Autowiredprivate UserService userService; @RequestMapping("/getAllUser") public
ModelAndView getAllUser(){ Result result=userService.getAllUser();
ModelAndView mv=new ModelAndView(); mv.addObject("userList",result.getData());
mv.setViewName("index.html"); return mv; } @RequestMapping("page") public
Result<PageInfo<User>> page(User entity, PageCondition pageCondition) { return
userService.page(entity,pageCondition); } @RequestMapping("list") public
Result<List<User>> list(User entity) { return userService.list(entity); }
@RequestMapping("get/{id}") public Result<User> get(@PathVariable("id") Integer
id) {return userService.get(id); } @RequestMapping("save") public Result<User>
save(User entity) {return userService.save(entity); } @RequestMapping(
"delete/{id}") public Result<Integer> delete(@PathVariable("id") Integer id){
return userService.delete(id); } }
 

  UserService
public interface UserService{ Result<PageInfo<User>> page(User entity,
PageCondition pageCondition); Result<List<User>> list(User entity); Result<User>
get(Integer id); Result<User> save(User entity); Result<Integer>
delete(Integer id); Result getAllUser(); } @Service
@Transactional public class UserServiceImpl implements UserService { @Autowired
private UserRepository userRepository; @Override public Result<PageInfo<User>>
page(User entity ,PageCondition pageCondition) { Page<User> page =
userRepository.findAll(Example.of(CopyUtil.copy(entity, User.class)),
pageCondition.getPageable());int records = (int) page.getTotalElements(); int
pageSize = page.getSize(); int total = records % pageSize == 0 ? records /
pageSize : records / pageSize + 1; PageInfo<User> pageInfo = new PageInfo<>();
pageInfo.setPage(page.getNumber()+ 1);//页码 pageInfo.setPageSize(pageSize);//页面大小
pageInfo.setRows(page.getContent());//分页结果 pageInfo.setRecords(records);//总记录数
pageInfo.setTotal(total);//总页数 return Result.of(pageInfo); } @Override public
Result<List<User>> list(User entity) { List<User> entityList =
userRepository.findAll(Example.of(entity));return Result.of(entityList); }
@Overridepublic Result<User> get(Integer id) { Optional<User> optionalE =
userRepository.findById(id);if (!optionalE.isPresent()) { throw new
RuntimeException("ID不存在!"); } return Result.of(optionalE.get()); } @Override
public Result<User> save(User entity) { User user = userRepository.save(entity);
return Result.of(user); } @Override public Result<Integer> delete(Integer id) {
userRepository.deleteById(id);return Result.of(id); } @Override public Result
getAllUser() { List<User> userList = userRepository.getAllUser(); if(userList !=
null && userList.size()>0){ return Result.of(userList); }else { return
Result.of(userList,false,"获取失败!"); } } }
 

  UserRepository
public interface UserRepository extends JpaRepository<User, Integer>,
JpaSpecificationExecutor<User> { @Query(value = "from User") //HQL //
@Query(value = "select * from tb_user",nativeQuery = true)//原生SQL List<User>
getAllUser(); }
 

  效果

  get接口

  http://localhost:10086/springboot/user/get/1



 

  list接口

  http://localhost:10086/springboot/user/list



   http://localhost:10086/springboot/user/list?username=张三



   

  page接口

  http://localhost:10086/springboot/user/page?page=1&rows=10



   http://localhost:10086/springboot/user/page?page=1&rows=10&username=张三



 

  save接口(插入跟更新)


  没有id或id不存在,为插入,http://localhost:10086/springboot/user/save?username=张麻子&password=123



  id已存在,则为更新,注意:这里的更新是你的字段是什么jpa就帮你存什么
,如果想要实现只更新接参对象有值的字段,应该先用id去同步数据,再更新,http://localhost:10086/springboot/user/save?id=1&username=张三1&password=666



  delete接口

  http://localhost:10086/springboot/user/delete/6



 

  自定义Dao层方法

  http://localhost:10086/springboot/user/getAllUser



  后记

   JPA牛逼!

  注意:
<!--继承信息--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>
spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <
relativePath/> </parent> <!--继承信息--> <parent> <groupId>org.springframework.boot
</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>
1.5.9.RELEASE</version> <relativePath/> </parent>

  2.0之后是大版本升级,使用了1.8JDK,许多方法API都发生了改变,其中就碰到了一个坑,之前写得不规范,Service中已经@Transactional了一次,Repository的自定义SQL又@Transactional一次,当我们service直接调公用JPA方法,后面又调我们自定义的Dao层方法时,由于事务传播,后面的事务不进行提交,而且也不报错

 

  补充

  有园友发现我们少贴了部分代码,在这里补充一下,CopyUtil类是我们自定义的一个实体类型转换的工具类,用于将实体模型与实体的转换,在 
SpringBoot系列——Spring-Data-JPA(升级版)
<https://www.cnblogs.com/huanzi-qch/p/9984261.html>
中,我们已经对该工具类进行了升级,升级之后支持复杂对象的转换
/** * 实体类型转换的工具类 */ public class CopyUtil { /** * 类型转换:实体模型<->实体 * <p> *
例如:List<DataModel> <--> List<Data>*/ public static <T> List<T> copyList(List
list, Class<T> target) { List<T> newList = new ArrayList<>(); for (Object
entity : list) { newList.add(copy(entity, target)); }return newList; } /** *
类型转换:实体模型 <->实体 * <p> * 例如:DataModel <--> Data*/ public static <T> T
copy(Object origin, Class<T> target) { T t = null; try { t =
target.newInstance(); }catch (InstantiationException | IllegalAccessException
e) { e.printStackTrace(); } BeanUtils.copyProperties(origin, t);return t; } }