1. 程式人生 > >Spring Data JPA 動態拼接條件的通用設計模式

Spring Data JPA 動態拼接條件的通用設計模式

記住官方文件永遠是首選

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;
}