Spring Data JPA 動態拼接條件的通用設計模式
阿新 • • 發佈:2019-02-01
記住官方文件永遠是首選
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework .data.jpa.domain.Specification;
import com.xxx.controller.logManage.LogSearchParamDTO;
import com.xxx.controller.trade.TradeParams;
/**
* 改進方向 1:能不能 通過反射 ,只要---
* 相關知識請自行查閱JPA Criteria查詢
// 過濾條件
// 1:過濾條件會被應用到SQL語句的FROM子句中。在criteria
// 查詢中,查詢條件通過Predicate或Expression例項應用到CriteriaQuery物件上。
// 2:這些條件使用 CriteriaQuery .where 方法應用到CriteriaQuery 物件上
// 3:CriteriaBuilder也作為Predicate例項的工廠,通過呼叫CriteriaBuilder 的條件方法(
// equal,notEqual, gt, ge,lt, le,between,like等)建立Predicate物件。
// 4:複合的Predicate 語句可以使用CriteriaBuilder的and, or andnot 方法構建。
* @author 小言
* @date 2017年11月27日
* @time 上午10:44:53
* @version ╮(╯▽╰)╭
*/
public class SpecificationBuilderForOperateLog {
public static <T> Specification buildSpecification(Class<T> clazz,
final LogSearchParamDTO logSearchParamDTO) {
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicate = new ArrayList<Predicate>();
Timestamp startTime = logSearchParamDTO.getStartTime();
Timestamp endTime = logSearchParamDTO.getEndTime();
// 時間段
if (startTime != null && endTime != null) {
predicate.add(cb.between(root.<Timestamp> get("logTime"), startTime, endTime));
}
// 操作日誌查詢欄
String searchCondition = logSearchParamDTO.getSearchCondition();
if (searchCondition != null && !searchCondition.equals("")) {
predicate.add(cb.or(cb.equal(root.<String> get("operatorName"), searchCondition),
cb.equal(root.<String> get("operatorId"), searchCondition)));
}
// 操作日誌使用者型別
String operatorType = logSearchParamDTO.getOperatorType();
System.out.println("operatorType=="+operatorType);
if (operatorType != null ){
predicate.add(cb.equal(root.<String> get("operatorType"), operatorType));
}
Predicate[] pre = new Predicate[predicate.size()];
// System.out.println("pre=="+predicate.toArray(pre));
query.where(predicate.toArray(pre));
return query.getRestriction();
}
};
}
}
下面是實際開發例子
controller層
@Controller
@RequestMapping(value = "/operateLog")
public class BgOperateLogController {
@Autowired
private BgOperateLogService bgOperateLogService;
@ResponseBody
@PostMapping("/findOperateLogByCondition")
public Result findOperateLogByCondition(@RequestBody LogSearchParamDTO logSearchParamDTO) {
System.out.println("logSearchParamDTO="+logSearchParamDTO);
Map<String, Object> result = new HashMap<>();
String start = logSearchParamDTO.getStart();
String end = logSearchParamDTO.getEnd();
if (start != null && end == null) {
return new Result(1001, "操作日誌查詢錯誤,時間引數缺少結束時間", result);
}
if (end != null && start == null) {
return new Result(1001, "操作日誌查詢錯誤,時間引數缺少開始時間", result);
}
//時間
long startTimeTimestamp = 0L;
long endTimeTimestamp = System.currentTimeMillis();
if(start != null && end != null){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date startTime;
Date endTime;
try {
startTime = sdf.parse(start);
endTime = sdf.parse(end);
startTimeTimestamp = startTime.getTime();
endTimeTimestamp = endTime.getTime();
} catch (ParseException e) {
e.printStackTrace();
return new Result(1001, "操作日誌查詢錯誤,轉換日期出錯", result);
}
}
String condition = logSearchParamDTO.getSearchCondition();
Integer pageNumber = logSearchParamDTO.getPageNumber()-1;
Integer pageSize = logSearchParamDTO.getPageSize() ;
String operatorType =logSearchParamDTO.getOperatorType();
Page<BgOperateLog> findByCondition = bgOperateLogService.findByCondition(new Timestamp(startTimeTimestamp),
new Timestamp(endTimeTimestamp),
condition,operatorType, pageNumber, pageSize);
// 這些欄位必須有,暫時沒有做校驗
List<BgOperateLog> list = findByCondition.getContent();
result.put("totalPages", findByCondition.getTotalPages());
result.put("pageNumber", pageNumber+1);
result.put("list", list);
return new Result(1002, "操作日誌查詢成功", result);
}
}
DTO
@Data
public class LogSearchParamDTO {
//前端傳來的時間引數
private String start;
private String end;
private Timestamp startTime;
private Timestamp endTime;
private String searchCondition;
//操作日誌查詢引數
//操作使用者型別(0,消費者,1商家,2後臺人員)
private String operatorType;
private Integer pageNumber;
private Integer pageSize;
//登陸日誌查詢條件
public LogSearchParamDTO(Timestamp startTime, Timestamp endTime, String searchCondition) {
this.startTime = startTime;
this.endTime = endTime;
this.searchCondition = searchCondition;
}
public LogSearchParamDTO() {}
//操作日誌查詢條件
public LogSearchParamDTO(Timestamp startTime, Timestamp endTime, String searchCondition, String operatorType) {
this.startTime = startTime;
this.endTime = endTime;
this.searchCondition = searchCondition;
this.operatorType = operatorType;
}
}
service 層
@Override
public Page<BgOperateLog> findByCondition(Timestamp start,
Timestamp end, String condition ,String operatorType,
int pageNumber, int pageSize) {
Sort sort = new Sort(Sort.Direction.DESC, "logTime");
Pageable pageable = new PageRequest(pageNumber, pageSize, sort);
LogSearchParamDTO operateLog = new LogSearchParamDTO(start, end, condition,operatorType);
Page<BgOperateLog> page = bgOperateLogDao
.findAll(SpecificationBuilderForOperateLog.buildSpecification(BgOperateLog.class,operateLog), pageable);
return page;
}
dao層
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.stereotype.Repository;
import com.xxx.entity.BgOperateLog;
@Repository
public interface BgOperateLogDao extends JpaRepository<BgOperateLog, Serializable>,JpaSpecificationExecutor<BgOperateLog>{}
entity層
@Data
@Entity
public class BgOperateLog implements java.io.Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String logText;
private String operatorId;
private String operatorName;
private String operatorType;
private String ip;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
private Timestamp logTime;
}