引言:在前段时间写有一篇”Spring and JPA的框架集成和编码测试.“的文章,其中主要介绍Spring与JPA的集成配置,并以常见的三层结构代码进行了测试。今天这篇是基于这篇文章扩展的,主要作用是,在有很多条件查询时,能够使用需要的条件进行查询,减少开发量。
如果您没有看过”Spring and JPA的框架集成和编码测试.“这篇文章,最好能去看一下,因为本篇文章是在其基础上做的扩展,示例代码也是如此。代码方面需要自己动手来操作,这样才能有更深的印象。代码定有不规范之处,也请留下您宝贵的意见,将受益匪浅。
准备(实体扩展和数据)
本文重在创建相关查询,所以先给User实体添加两个属性,用于多条件查询;同时添加几条数据,用于查询。
1. 扩展User实体
package com.stark.demo.entitys;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;@Entity
@Table(name=”USER”)
public class User implements Serializable {private static final long serialVersionUID = -6395834411937686352L;
@Id
@Column(name = “ID”, length = 32)
@GeneratedValue(generator = “system-uuid”)
@GenericGenerator(name = “system-uuid”, strategy = “uuid”)
private String id;//唯一id,使用uuid生成策略@Column(name = “NAME”, length = 50)
private String name;//用户名@Column(name = “PWD”, length = 50)
private String pwd;//用户密码@Column(name = “STATE”, length = 2)
private String state;//0表示禁用,1表示启用@Column(name = “DESCRIPTION”, length = 200)
private String description;//描述信息/** 省略get和set **/
}
2. 添加数据
添加Criteria查询支持(实现JpaSpecificationExecutor接口)
Criteria 查询:是一种类型安全和更面向对象的查询。
在Jpa中使用Criteria查询,需要在Dao层实现相应的接口JpaSpecificationExecutor。这个接口是围绕Specification接口来定义的。
Specification接口中只定义了如下一个方法:
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);该方法用于创建相关的条件。
官方该接口的API地址为:http://docs.spring.io/spring-data/data-jpa/docs/current/api/org/springframework/data/jpa/repository/JpaSpecificationExecutor.html,基本的用法都已提供,还有其他的类似的接口,多看看,多学学。其他的资料可自行查找,也可以参考本文下方的参考资料。
1. 扩展UserDao
如下:
package com.stark.demo.dao;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository;
import com.stark.demo.entitys.User;public interface UserDao extends CrudRepository<User, String>,JpaSpecificationExecutor<User> {
}
2. 添加IUserService接口方法和其实现类UserServiceImpl
(1)IUserService
此次的示例中,将原文章中的UserService接口改为IUserService接口,只是重新命名了一下,这样更加规范。
如下:
package com.stark.demo.service;
import java.util.List;
import org.springframework.data.jpa.domain.Specification;
import com.stark.demo.entitys.User;public interface IUserService {
/**
* 保存User对象
* @param vo
* @return
* @throws Exception
*/
public User saveVo(User vo) throws Exception;/**
* 根据id获取User对象
* @param id
* @return
* @throws Exception
*/
public User loadVo(String id) throws Exception;/**
* 查询所有的User
* @return
* @throws Exception
*/
public List<User> findAllList() throws Exception;/**
* 使用Specification查询
* @param spec
* @return
* @throws Exception
*/
public List<User> findList(Specification<User> spec) throws Exception;}
(2)UserServiceImpl
在此次的示例中,添加了新的查询方式,同时也修正了之前findAllList方法中返回为空的问题,具体的修改请对比一下。
package com.stark.demo.service;
import java.util.ArrayList;
import java.util.List;
import org.apache.openjpa.persistence.ReadOnly;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.stark.demo.dao.UserDao;
import com.stark.demo.entitys.User;@Service(“userService”)
@Transactional
public class UserServiceImpl implements IUserService {@Autowired
private UserDao userDao;@Transactional(rollbackFor = { Exception.class })
public User saveVo(User vo) throws Exception {
User user = null;
try {
user = this.userDao.save(vo);
} catch (Exception e) {
System.out.println(“出错信息:” + e.getMessage());
}
return user;
}@ReadOnly
public User loadVo(String id) throws Exception {
User user = null;
try {
user = this.userDao.findOne(id);
} catch (Exception e) {
System.out.println(“出错信息:” + e.getMessage());
}
return user;
}@ReadOnly
public List<User> findAllList() throws Exception {
List<User> userList = new ArrayList<User>();
try {
userList = (List<User>) this.userDao.findAll();
} catch (Exception e) {
System.out.println(“出错信息:” + e.getMessage());
}
return userList;
}@ReadOnly
public List<User> findList(Specification<User> spec) throws Exception {
List<User> userList = new ArrayList<User>();
try {
userList = this.userDao.findAll(spec);
} catch (Exception e) {
System.out.println(“出错信息:” + e.getMessage());
}
return userList;
}}
实现Specification的查询
上面已经继承了相关的接口,下面主要就是创建Specification了,还有Controller中的的调用实现。
1. 创建UserSpecs类,用于生成相关的Specification
如下:
package com.stark.demo.specifications;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification;
import com.stark.demo.entitys.User;public class UserSpecs {
/**
* 设置查询条件
* @param paramMap
* @return
*/
public static Specification<User> setQuery(final Map<String, Object> paramMap) {
return new Specification<User>() {
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query,
CriteriaBuilder builder) {
Predicate p = null;
//判断参数Map是否为空
if (paramMap != null && !paramMap.isEmpty()) {
if(paramMap.containsKey(“key”) && paramMap.get(“key”) != null){
String key = “%” + paramMap.get(“key”) + “%”;
Path<String> _p1 = root.get(“name”);
Path<String> _p2 = root.get(“description”);
//生成对应的条件,语句为:(name LIKE key OR description LIKE key)
p = builder.or(builder.like(_p1, key), builder.like(_p2, key));
}
}
if(p == null){//如果以上没有相关的条件,就直接生成条件,为:(state = ‘1’)
p = builder.equal(root.get(“state”), “1”);
}else{//如果已有相关的条件,就以上的条件为基础生成,为:(state = ‘1’) AND (name LIKE key OR description LIKE key)
p = builder.and(builder.equal(root.get(“state”), “1”), p);
}
if(p == null){
query.where();
}else{
query.where(p);
}
return p;
}
};
}}
上面的setQuery方法,用于生成相关的条件,具体的生成请看代码上的注释。
2. Controller调用实现
添加如下方法:
/**
* 获取指定条件的用户列表
* @param request
* @return
* @throws Exception
*/
@ResponseBody
@RequestMapping(“/userlist.do”)
public Object userList(HttpServletRequest request) throws Exception{
//获取参数
String _key = request.getParameter(“key”);
//创建存放参数的Map
Map<String, Object> paramMap = new HashMap<String, Object>();
//存放参数
if(_key != null && _key.trim() != “”){
paramMap.put(“key”, _key);
}
//查询数据
List<User> userList = this.userService.findList(UserSpecs.setQuery(paramMap));
return userList;
}
测试
(1)不添加条件查询
在浏览器端输入:localhost:8082/stark-spring-jpa-demo/user/userlist.do
返回如下:
(2)添加key值查询
在浏览器端输入:localhost:8082/stark-spring-jpa-demo/user/userlist.do?key=1
返回如下:
注意:这里key值没有使用中文,因为是直接在浏览器(google)上输入的,中文会被转码,会导致查不到数据,请留意。
根据上方的两个查询即可看出条件已经生效了,最好能在控制端看看Hibernate的语句输出。
如有问题,欢迎指出;如需转载,请标明出处,谢谢!
参考资料