javabean赋值转换,整合SpringDataJPA
当我们处于实际的开发过程中,业务会具有一定的复杂性,一个model实体贯穿持久层、服务层、控制层是很难的。所以需要进行实体对象javabean的赋值转换。(如果业务很简单用一个实体类对象可以解决,那么就直接贯穿持久层到展现层,没有必要做映射赋值转换,没必要去分VO、BO、PO。)
javabean赋值转换
首先来解释几个概念:
PO:持久对象,在进行数据库数据存取操作时使用,对应数据库中的一个表,po的每个属性与数据库表里面字段一一对应。是一个符合JavaBean规范的纯Java对象。PO对象里只有基本数据类型和String类型的属性。
BO:业务对象,它主要的作用是把业务逻辑封装为一个对象,是对数据进行检索和处理的组件。通常一个BO是由多个PO的组成的。
VO:视图对象,用于展示层,它的作用是与web页面的展示结构相对应,也是前端与后端的数据交换定义。
PO是我们在数据库中查出来的数据,VO要比PO中的数据更丰富。
PO:用来对数据库表中的数据进行存取。
public class Pets { private long id; private String name; private String varieties; private Date createTime; } 123456复制代码类型:[java]
VO:返回给前端的数据内容。(还包含了customer的内容)
public class PetsVo { private long id; private String name; private String varieties; private Date createTime; private List<Customer> customer; } 1234567复制代码类型:[java]
当我们向数据库中添加数据,就要将Pets,Customer(PO)分别作为PO记录插入数据库。如果需要Pets,Customer信息返回给前端做页面渲染时,只要在数据库中查询出二者的信息然后组合起来,映射转换成PetsVo返回给前端。
对象间的转换赋值:
PetsVO.setId(pets.getId()); PetsVO.setName(pets.getName()); PetsVO.setVarieties(pets.getVarieties()); PetsVO.setCreateTime(pets.getCreateTime());1234复制代码类型:[java]
如果碰到大量的字段,那这种写法将会非常的麻烦,所以我们可以考虑使用BeanUtils和Dozer。
BeanUtils:
是SpringBoot默认提供的javabean赋值转换的工具,使用方法很简单。
PetsVO petsVO = new PetsVO(); BeanUtils.copyProperties(pets,petsVO);12复制代码类型:[java]
使用BeanUtils的前提是成员变量的数据类型是相同的
Dozer:
使用方法跟BeanUtils差不多,是一个能把实体和实体之间进行转换的工具。
Mapper mapper = DozerBeanMapperBuilder.buildDefault(); PetsVO petsVO = mapper .map(pets, PetsVO.class);12复制代码类型:[java]
Dozer的功能更强大可以实现Integer、Long等基础类型与String数据类型的属性之间的转换。还可以通过xml配置的方式实现复杂的数据转换。BeanUtils的性能更好。
SpringDataJPA
SpringDataJPA是SpringData家族的一部分,基于JPA规范的基础上封装的一套JPA应用框架,底层使用了Hibernate的JPA技术实现。除了常用接口(增,删,改,查)以外,还非常的易于扩展。
首先在pom.xml文件中引入依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>1234复制代码类型:[java]
之后修改application.yml文件:
spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/Family?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: 123456 jpa: # Hibernate 创建数据库表的时候,默认使用的数据库存储引擎是 MyISAM # database-platform在建表的时候将存储引擎切换为 InnoDB database-platform: org.hibernate.dialect.MySQL5InnoDBDialect hibernate: # 在Hibernate每次加载的时候,都会验证数据库中的表结构是否跟model类中字段的定义是一致的,如果不一致就抛出异常 ddl-auto: validate naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl database: mysql # 在日志打印出执行的sql语句 show-sql: true1234567891011121314151617181920212223复制代码类型:[java]
在完成以上配置工作以后,我们来实现一个JPA操作数据库的例子。
我们重新配置一下model文件下的Pets.java使他的字段跟数据库中的表结构一一对应。将原来的Pets.java改名成PetsVO.java。
package com.javafamily.familydemo.model;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.NoArgsConstructor;import javax.persistence.*;import java.util.Date;@Data@AllArgsConstructor@NoArgsConstructor@Builder// 表示当前的类是实体类,并且接受Spring Data JPA的控制管理。对应数据库中的一张表。@Entity@Table(name = "pets")public class Pets { // id 自动递增 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; // name 不能为空,并且是唯一的,长度不能超过50 @Column(nullable = false, unique = true, length = 50) private String name; // varieties 不能为空,长度不能超过50 @Column(nullable = false, length = 50) private String varieties; @Column(name = "create_time") private Date createTime; }1234567891011121314151617181920212223242526272829303132复制代码类型:[java]
之后在Dao文件夹下创建PetsRepository.java编写数据库操作端口:
package com.javafamily.familydemo.dao;import com.javafamily.familydemo.model.Pets;import org.springframework.data.jpa.repository.JpaRepository;// 尖括号里表示的是要操作的数据库表对应的实体PO和实体主键的类型public interface PetsRepository extends JpaRepository<Pets, Long> { }123456789复制代码类型:[java]
JpaRepository<Pets,Long>为我们提供了增删改查功能。
之后来改写Service文件下的petsService.java和PetsServiceImpl.java:
package com.javafamily.familydemo.service;import com.javafamily.familydemo.model.PetsVO;import java.util.List;public interface PetsService { PetsVO savePets(PetsVO pets); void deletePets(long id); void updatePets(PetsVO pets); PetsVO getPets(Long id); List<PetsVO> getAll(); }1234567891011121314151617复制代码类型:[java]
package com.javafamily.familydemo.service;import com.javafamily.familydemo.dao.PetsRepository;import com.javafamily.familydemo.model.Pets;import com.javafamily.familydemo.model.PetsVO;import com.javafamily.familydemo.utils.DozerUtils;import org.dozer.Mapper;import org.springframework.stereotype.Service;import javax.annotation.Resource;import java.util.List;import java.util.Optional;@Servicepublic class PetsServiceImpl implements PetsService { @Resource private PetsRepository petsRepository; @Resource private Mapper dozerMapper; public PetsVO savePets(PetsVO pets) { Pets petsPO = dozerMapper.map(pets, Pets.class); // 通过insert,保存一个对象 petsRepository.save(petsPO); return pets; } @Override public void deletePets(long id) { // 通过id删除数据库内容 petsRepository.deleteById(id); } @Override public void updatePets(PetsVO pets) { Pets petsPO = dozerMapper.map(pets,Pets.class); // 更新一个对象,使用save方法 petsRepository.save(petsPO); } @Override public PetsVO getPets(Long id) { // Optional<> 表示可能查到记录,也可能查不到 Optional<Pets> pets = petsRepository.findById(id); // 通过id查找一条数据 return dozerMapper.map(pets.get(),PetsVO.class); } @Override public List<PetsVO> getAll() { List<Pets> petsList = petsRepository.findAll(); //查询表的所有数据 return DozerUtils.mapList(petsList,PetsVO.class); } }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859复制代码类型:[java]
在com.javafamily.familydemo文件下创建utils文件夹,并且在其中创建DozerUtils.java
package com.javafamily.familydemo.utils;import com.google.common.collect.Lists;import org.dozer.DozerBeanMapperBuilder;import org.dozer.Mapper;import java.util.Collection;import java.util.Iterator;import java.util.List;public class DozerUtils { static Mapper mapper = DozerBeanMapperBuilder.buildDefault(); public static <T> List<T> mapList(Collection sourceList, Class<T> destinationClass) { List destinationList = Lists.newArrayList(); for (Iterator i$ = sourceList.iterator(); i$.hasNext(); ) { Object sourceObject = i$.next(); Object destinationObject = mapper.map(sourceObject, destinationClass); destinationList.add(destinationObject); } return destinationList; } }12345678910111213141516171819202122232425复制代码类型:[java]
最后我们把数据库中的数据全部删除,并使用postman进行测试:
添加的数据成功出现在数据库中。
数据库中的数据被查询出来。
之后我们将varieties修改为red:
数据被修改成功:
最后删除这条数据:
数据被成功删除:
通过关键字查询接口
如果我们想要通过name来进行数据查询,那么就要编写关键字查询接口。
在PetsRepository中添加代码:
package com.javafamily.familydemo.dao;import com.javafamily.familydemo.model.Pets;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.stereotype.Repository;// 尖括号里表示的是要操作的数据库表对应的实体PO和实体主键的类型public interface PetsRepository extends JpaRepository<Pets, Long> { // jpa会根据这条代码自动生成SQL语句 Pets findPetsBy(String name); }1234567891011复制代码类型:[java]
其他具体的关键字,使用方法和生产成SQL:
之后我们编写一个测试类用来对关键字搜索功能进行测试:
package com.javafamily.familydemo;import com.javafamily.familydemo.dao.PetsRepository;import com.javafamily.familydemo.model.Pets;import org.junit.jupiter.api.Test;import org.junit.jupiter.api.extension.ExtendWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit.jupiter.SpringExtension;import javax.annotation.Resource;@ExtendWith(SpringExtension.class)@SpringBootTestpublic class KeyWordsTest { @Resource private PetsRepository petsRepository; @Test public void Test() { Pets pets = petsRepository.findPetsByName("fish"); System.out.println(pets); } }1234567891011121314151617181920212223复制代码类型:[java]
向数据库中添加两条数据:
执行代码打印结果:
这时我们就通过关键字完成了查询。