1.Query DSL介绍
Querydsl定义了一个通用的静态类型语法,用于查询持久化域模型数据。 JDO和JPA是Querydsl的主要集成技术。 本指南介绍如何结合使用Querydsl和JPA。
针对JPA的Querydsl是JPQL和Criteria查询的替代方案。 它将Criteria查询的动态特性与JPQL的表现力以及完全类型安全的方式相结合。
2.maven集成
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<project>
<build>
<plugins>
...
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
</project>
3.Query DSL的部分常规使用
使用QueryDSL进行一些常规的查询.例如:根据属性查询,order by,group by,left join等请看该官方文档,上面很详细.足够使用.文档地址
4.Query DSL 部分场景使用
场景1: 在查询一个聊天记录表中时,想要提供根据id,openid,或者聊天记录发送的时间和手机号中的一个或者多个条件来查询聊天的数据.这个时候,想要在一个接口中使用QueryDSL实现的话 可以使用在仓库类中继承QueryDslPredicateExecutor接口来实现.如下:
实体类
package com.newtank.scorpio.jpa.entity;
import com.newtank.scorpio.framework.entity.PkUUID;
import com.newtank.scorpio.framework.entity.enums.ValuedEnum;
import com.newtank.scorpio.jpa.entity.converter.MsgChannelConverter;
import com.newtank.scorpio.jpa.entity.converter.MsgDirectionConverter;
import com.newtank.scorpio.jpa.entity.converter.MsgStatusConverter;
import com.newtank.scorpio.jpa.entity.converter.ScheduleFlagConverter;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
/**
* Created by looper on 2017/9/21.
*
* @author looper
* @author trueorfalse.yuan
*/
@Entity
@Table(name = "t_msg_log")
@Getter
@Setter
public class MsgLog extends PkUUID implements Serializable {
private static final long serialVersionUID = -1479947068453421077L;
@Column(name = "mobile", length = 16)
private String mobile;
@Column(name = "openid", length = 64)
private String openid;
@Column(name = "tsrname", length = 64)
private String tsrname;
@Column(name = "msg_direction", length = 2)
@Convert(converter = MsgDirectionConverter.class)
private MsgDirection msgDirection;
@Column(name = "msg_type", length = 16)
@Enumerated(EnumType.STRING)
private MsgType msgType;
@Column(name = "msg_channel", length = 2)
@Convert(converter = MsgChannelConverter.class)
private MsgChannel msgChannel;
@Lob
@Column(name = "msg_content")
private String msgContent;
@Column(name = "is_passive")
private Boolean isPassive;
@Column(name = "status", length = 2)
@Convert(converter = MsgStatusConverter.class)
private MsgStatus status;
@Column(name = "send_time")
private Date sendTime;
@Column(name = "schedule_flag", length = 2)
@Convert(converter = ScheduleFlagConverter.class)
private ScheduleFlag scheduleFlag;
@Column(name = "src_msg_id")
private String srcMsgId;
/**
* enum
*/
public enum MsgType {
text, image, video, voice, news, link, template, location
}
@RequiredArgsConstructor
public enum MsgDirection implements ValuedEnum<String> {
User2Agent("0"), Agent2User("1");
@Getter
private final String value;
}
@RequiredArgsConstructor
public enum MsgChannel implements ValuedEnum<String> {
SMS("0"), WECHAT("1");
@Getter
private final String value;
}
@RequiredArgsConstructor
public enum MsgStatus implements ValuedEnum<String> {
Success("1"), Failure("-1");
@Getter
private final String value;
}
@RequiredArgsConstructor
public enum ScheduleFlag implements ValuedEnum<String> {
ScheduledMsg("0"), InstantMsg("1");
@Getter
private final String value;
}
}
仓库类:
package com.newtank.scorpio.jpa.repository;
import com.newtank.scorpio.jpa.entity.MsgLog;
import com.newtank.scorpio.jpa.entity.QMsgLog;
import com.querydsl.core.types.dsl.StringExpression;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.stereotype.Repository;
import java.util.Date;
/**
* Created by looper on 2017/9/21.
*/
@Repository
public interface MsgLogRepository extends JpaRepository<MsgLog,String>,QueryDslPredicateExecutor<MsgLog>{
}
controller类
package com.newtank.scorpio.web.controller;
import com.google.common.base.Function;
import com.newtank.scorpio.jpa.entity.MsgLog;
import com.newtank.scorpio.jpa.repository.MsgLogRepository;
import com.newtank.scorpio.web.controller.response.MsgLogPageResp;
import com.newtank.scorpio.web.controller.response.MsgLogResp;
import com.newtank.scorpio.web.until.JsonUtil;
import com.querydsl.core.types.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Created by looper on 2017/10/30.
*/
@RestController
@RequestMapping("/msgLog/")
public class MsgLogController {
private static final Logger LOGGER = LoggerFactory.getLogger(MsgLogController.class);
@Autowired
private MsgLogRepository msgLogRepository;
/**
* 根据条件查询回话内容
* @param predicate
* @return
*/
@RequestMapping(value = "list")
public List<MsgLogResp> list(@QuerydslPredicate(root = MsgLog.class) Predicate predicate){
Iterable<MsgLog> msgLogs = msgLogRepository.findAll(predicate);
LOGGER.info("msgLogs = "+ JsonUtil.toJson(msgLogs));
List<MsgLog> msgLogList = new ArrayList<>();
msgLogs.forEach((MsgLog msgLog)-> msgLogList.add(msgLog));
return msgLogList.stream().map(new Function<MsgLog, MsgLogResp>() {
@Nullable
@Override
public MsgLogResp apply(@Nullable MsgLog msgLog) {
return new MsgLogResp(msgLog);
}
}).collect(Collectors.toList());
}
}
postman上的url如下 {{scorpio}} /msgLog/list?openid=XXX@id=XXX
Ps: openid 和id 等参数 要和后台的entity属性一致.
场景2: 如果不止要求按照id,openid,手机号等条件,还要求这些条件支持模糊查询,例如按照聊天内容的部分内容来查找,或者按照聊天的时间段来查找.这个时候使用QueryDSL 应该怎么做呢.现在需要在仓库类中继承QuerydslBinderCustomizer接口.这个接口的泛型参数是Query DSL生成的QEntity类.需要注意.例子如下:
实体类:
同上 MsgLog
仓库类
package com.newtank.scorpio.jpa.repository;
import com.newtank.scorpio.jpa.entity.MsgLog;
import com.newtank.scorpio.jpa.entity.QMsgLog;
import com.querydsl.core.types.dsl.StringExpression;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
import org.springframework.data.querydsl.binding.QuerydslBindings;
import org.springframework.stereotype.Repository;
import java.util.Date;
/**
* Created by looper on 2017/9/21.
*/
@Repository
public interface MsgLogRepository extends JpaRepository<MsgLog,String>,QueryDslPredicateExecutor<MsgLog>, QuerydslBinderCustomizer<QMsgLog> {
@Override
default public void customize(QuerydslBindings bindings, QMsgLog qMsgLog){
bindings.bind(qMsgLog.mobile).first(StringExpression::contains); //模糊查询
// bindings.bind(qMsgLog.tsrname).first(StringExpression::contains);
bindings.bind(qMsgLog.msgContent).first(StringExpression::contains);
bindings.bind(qMsgLog.sendTime).first((path,sendTime) -> path.between(sendTime,new Date())); //时间段查询
}
}
继承 QuerydslBinderCustomizer接口,必须要实现 customize方法,里面就是设置你想要查询的条件是否是模糊查询的代码.例子中有字符串的模糊查询和时间段查询,有需要的童鞋可以看一下.
Ccontroller
同上 MsgLogController