1、自定义DTO返回结果
一般情况下,返回的字段和DB查询结果的字段是一一对应的。但有的时候需要返回一些指定的字段,或者返回一些复合型字段,而不需要全部返回。
Spring Data 允许对专用返回类型进行建模,有选择地返回同一个实体的不同试图对象。
1.1 举例
User类
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "user")
public class User {
/**
* 主键id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@Column(name = "address")
private String address;
}
如果我们只想返回User对象里面的name和address,应该怎么做呢?
1.1 第一种方式:直接定义一个DTO
新建一个DTO类来返回我们想要的字段,如下所示:
@Data
@AllArgsConstructor
public class UserDTO {
private String name;
private String address;
}
在UserRepository中构造查询方法,注意不要写findById这种语句,否则会报转化错误的异常
public interface UserRepo JpaRepository<User, Integer> {
UserDTO findByIdAndName(int id,String name);
}
还需要注意的是,再看源码PreferredConstructorDiscoverer类时会发现,UserDTO里面只能有一个全参数构造方法。buildPreferredConstructor 会帮我们做构造参数的选择,如果UserDTO里面有多个构造方法,就会报转化错误的异常。
这种方式的优点就是返回的结果不需要一个实体对象。缺点就是构造方法不能更改,必须全参数。
1.2 第二种方式:返回结果是一个POJO的接口
定义一个UserNameAndAddress接口
public interface UserNameAndAddress {
String getName();
String getAddress();
}
UserNameAndAddress findByIdAndNameLike( int id,String name);
测试方法
@Test
public void findByUserInterface() {
UserNameAndAddress e = userRepo.findByIdAndNameLike(1,"老王");
System.out.println(e.getAddress());
System.out.println(e.getName());
}
这种方式非常灵活,不需要添加构造方法。在运行过程中,UserNameAndAddress接口成了一个代理对象,里面通过Map的格式包含了我们要返回的字段的值(如name,address),用的时候直接调用接口里面的方法即可。
1.3 不同DTO类型生成的JPQL语句也不同
返回DTO接口形式的Query生成的JPQL语句如下
返回DTO类的时候QueryStructure生成的JPQL语句如下,两者最大的区别是DTO类需要用到构造方法新建一个对象出来