spring-data-jpa是一款基于JPA规范开发的持久层框架,与hibernate类似,spring-data-jpa也基于JPA的规范提供了自己的面相对象的查询方法。
在org.springframework.data.jpa.repository.JpaSpecificationExecutor接口中提供了一个List<T> findAll(Specification<T> spec)的方法,我们在使用面相对象的查询方法时候需要实现Specification接口,Specification接口的定义如下:
public interface Specification<T> {
/**
* Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
* {@link Root} and {@link CriteriaQuery}.
*
* @param root
* @param query
* @return a {@link Predicate}, must not be {@literal null}.
*/
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}
可以看出Specification接口需要实现toPredicate方法,熟悉JPA的朋友应该都清楚,这三个参数都属于JPA的规范,如果我们需要对单个表进行相对复杂的查询操作,就可以使用List<T> findAll(Specification<T> spec)的查询方法,我在这里举例使用数据库表格脚本是:
CREATE TABLE `NewTable` (
`call_prefix_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '前缀字冠' ,
`call_prefix_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字冠名称' ,
`call_prefix_code` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '字冠前缀' ,
`call_type_id` int(5) NOT NULL COMMENT '呼叫类型字冠ID' ,
PRIMARY KEY (`call_prefix_id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=5
ROW_FORMAT=COMPACT
;
entity类:
@Entity
@Table(name = "call_prefix_info_table")
public class CallPrefixInfoTable implements java.io.Serializable {
/**
* @Fields serialVersionUID : TODO
*/
private static final long serialVersionUID = 1L;
// Fields
private Integer callPrefixId;
private String callPrefixName;
private String callPrefixCode;
private Integer callTypeId;
// Constructors
/** default constructor */
public CallPrefixInfoTable() {
}
/** minimal constructor */
public CallPrefixInfoTable(String callPrefixCode, Integer callTypeId) {
this.callPrefixCode = callPrefixCode;
this.callTypeId = callTypeId;
}
/** full constructor */
public CallPrefixInfoTable(String callPrefixName, String callPrefixCode,
Integer callTypeId) {
this.callPrefixName = callPrefixName;
this.callPrefixCode = callPrefixCode;
this.callTypeId = callTypeId;
}
// Property accessors
@Id
@GeneratedValue
@Column(name = "call_prefix_id", unique = true, nullable = false)
public Integer getCallPrefixId() {
return this.callPrefixId;
}
public void setCallPrefixId(Integer callPrefixId) {
this.callPrefixId = callPrefixId;
}
@Column(name = "call_prefix_name", length = 50)
public String getCallPrefixName() {
return this.callPrefixName;
}
public void setCallPrefixName(String callPrefixName) {
this.callPrefixName = callPrefixName;
}
@Column(name = "call_prefix_code", nullable = false, length = 30)
public String getCallPrefixCode() {
return this.callPrefixCode;
}
public void setCallPrefixCode(String callPrefixCode) {
this.callPrefixCode = callPrefixCode;
}
@Column(name = "call_type_id", nullable = false)
public Integer getCallTypeId() {
return this.callTypeId;
}
public void setCallTypeId(Integer callTypeId) {
this.callTypeId = callTypeId;
}
}
mvc使用的查询model:
public class CallPrefixModel {
private String prefixName;
private String prefixCode;
private String callTypeId;
public CallPrefixModel() {
super();
}
public CallPrefixModel(String prefixName, String prefixCode,
String callTypeId) {
super();
this.prefixName = prefixName;
this.prefixCode = prefixCode;
this.callTypeId = callTypeId;
}
public String getPrefixName() {
return prefixName;
}
public void setPrefixName(String prefixName) {
this.prefixName = prefixName;
}
public String getPrefixCode() {
return prefixCode;
}
public void setPrefixCode(String prefixCode) {
this.prefixCode = prefixCode;
}
public String getCallTypeId() {
return callTypeId;
}
public void setCallTypeId(String callTypeId) {
this.callTypeId = callTypeId;
}
}
spring-data-jpa的dao层不需要我们自己写实现类,只需要提供接口,想要使用面向对象的查询方法,dao接口需要继承org.springframework.data.jpa.repository.JpaSpecificationExecutor接口,本文实例的dao接口:
@Repository("callPrefixInfoTableDao")
public interface CallPrefixInfoTableRepository extends
JpaRepository<CallPrefixInfoTable, Integer>,JpaSpecificationExecutor<CallPrefixInfoTable> {
}
其中在service层中,我们需要实现查询方法的定义,service层的代码:
@Service
public class CallPrefixService {
@Resource
private CallPrefixInfoTableRepository callPrefixInfoTableDao;
/**
*
* 根据查询条件查询字冠信息
* @param @param model
* @return List<CallPrefixInfoTable>
* @author QianLei
* @date 2015年9月25日
*/
public List<CallPrefixInfoTable> findCallPrefixs(final CallPrefixModel model) {
List<CallPrefixInfoTable> infos = callPrefixInfoTableDao.findAll(new Specification<CallPrefixInfoTable>(){
@Override
public Predicate toPredicate(Root<CallPrefixInfoTable> root,
CriteriaQuery<?> query, CriteriaBuilder cb) {
Path<String> namePath = root.get("callPrefixName");
Path<String> codePath = root.get("callPrefixCode");
Path<Integer> callTypePath = root.get("callTypeId");
List<Predicate> predicatesList = new ArrayList<Predicate>();
predicatesList.add(cb.like(namePath, "%" + model.getPrefixName() + "%"));
predicatesList.add(cb.like(codePath, "%" + model.getPrefixCode() + "%"));
String[] typeIdsStr = model.getCallTypeId().split(",");
List<Integer> typeIds = new ArrayList<Integer>();
for(String typeId : typeIdsStr){
typeIds.add(Integer.valueOf(typeId));
}
predicatesList.add(callTypePath.in(typeIds));
query.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
return query.getRestriction();
}
});
return infos;
}
}
只需要在controller中调用service的findCallPrefixs()方法,传入查询对象,就可以以面相对象的方式进行查询操作。例子中的查询操作转换成sql语句为:
select * from CallPrefixInfoTable where callPrefixName like `%参数%` and callPrefixCode like `%参数%` and callTypeId in (int,int,int);
同时还可以调用query的排序方法对查询结果进行排序。