使用以下库帮助我在简单的标签搜索中实现一些逻辑过滤器:
<dependency>
<groupId>cz.jirutka.rsql</groupId>
<artifactId>rsql-parser</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>com.github.tennaito</groupId>
<artifactId>rsql-jpa</artifactId>
<version>2.0.2</version>
</dependency>
这是我的两个 DAO 对象标签和目标,中间有一个简单的映射表:
标签
@Entity
@Table(name="tags")
public class Tag implements Comparable<Tag> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tags_Seq")
@SequenceGenerator(name = "tags_Seq", sequenceName = "tags_seq", allocationSize = 1)
@Column(name = "id")
private Integer id;
@Column(name = "name", unique = true)
private String name;
@Temporal( TemporalType.TIMESTAMP)
@Column(name="creation_timestamp")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private Date created;
@ManyToMany(mappedBy="tags")
@JsonManagedReference
List<Target> targets;
目标
@Entity
@Table(name="target",
uniqueConstraints=@UniqueConstraint(columnNames={"target_id", "target_name"}))
public class Target implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
public enum TargetName {
USER
}
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tag_targets_Seq")
@SequenceGenerator(name = "tag_targets_Seq", sequenceName = "tag_targets_seq", allocationSize = 1)
private Integer id;
@Column(name = "target_id")
private Integer targetId;
@Column(name = "target_name")
@Enumerated(EnumType.STRING)
private TargetName targetName;
@Column(name = "active")
private boolean active;
@Temporal( TemporalType.TIMESTAMP)
@Column(name="creation_timestamp")
private Date created;
@Temporal( TemporalType.TIMESTAMP)
@Column(name="last_update_timestamp")
private Date updated;
@ManyToMany
@JoinTable(name="tag_target",
joinColumns = @JoinColumn(name = "Target_id", referencedColumnName = "ID"),
inverseJoinColumns = @JoinColumn(name = "Tag_id", referencedColumnName = "ID")
)
@JsonBackReference
private Set<Tag> tags= new HashSet<>();
public void setTag(Tag tag){
this.tags.add(tag);
}
public List<String> getTagsList(){
List<String> list = new ArrayList<>();
for(Tag t : this.tags){
list.add(t.getName());
}
return list;
}
我正在尝试实现一个 rsql 查询字符串搜索,这样:
public List<Target> searchByQuery(String queryString) {
RSQLVisitor<CriteriaQuery<Target>, EntityManager> visitor = new JpaCriteriaQueryVisitor<>();
CriteriaQuery<Target> query;
query = getCriteriaQuery(queryString, visitor);
List<Target> resultList = entityManager.createQuery(query).getResultList();
if (resultList == null || resultList.isEmpty()){
return Collections.emptyList();
}
return resultList;
}
private <T> CriteriaQuery<T> getCriteriaQuery(String queryString, RSQLVisitor<CriteriaQuery<T>, EntityManager> visitor) {
Node rootNode;
CriteriaQuery<T> query;
try {
rootNode = new RSQLParser().parse(queryString);
query = rootNode.accept(visitor, entityManager);
}catch (Exception e){
//log.error("An error happened while executing RSQL query", e);
throw new IllegalArgumentException(e.getMessage());
}
return query;
}
但是,当我传递的不是字符串时,它们似乎没有考虑对象之间的映射,例如,如果我传递:
search?query=(tags.name==test;tags.name!=PS4)
是的,我拿回带有标签的物品PS4
[
{
"id": 4,
"targetId": 22,
"targetName": "USER",
"active": false,
"created": "2021-05-26T04:43:32.025+00:00",
"updated": "2021-05-26T04:43:32.025+00:00",
"tagsList": [
"test",
"PS4"
]
},
{
"id": 5,
"targetId": 1,
"targetName": "USER",
"active": false,
"created": "2021-05-26T04:43:46.873+00:00",
"updated": "2021-05-26T04:43:46.873+00:00",
"tagsList": [
"test"
]
}
]
在幕后,这是 lib 正在做的事情:
2021-05-25 22:32:23,588 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.JpaCriteriaQueryVisitor: Creating CriteriaQuery for AndNode: (tags.name=='test';tags.name!='PS4')
2021-05-25 22:32:23,590 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.JpaPredicateVisitor: Creating Predicate for AndNode: (tags.name=='test';tags.name!='PS4')
2021-05-25 22:32:23,590 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicate for logical node: (tags.name=='test';tags.name!='PS4')
2021-05-25 22:32:23,591 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicates from all children nodes.
2021-05-25 22:32:23,591 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicate for: tags.name=='test'
2021-05-25 22:32:23,591 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicate for comparison node: tags.name=='test'
2021-05-25 22:32:23,591 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Property graph path : tags.name
2021-05-25 22:32:23,592 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Create a join between com.getinsured.tag.model.dao.TagTarget and com.getinsured.tag.model.dao.Tag.
2021-05-25 22:32:23,592 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Create property path for type com.getinsured.tag.model.dao.Tag property name.
2021-05-25 22:32:23,592 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Cast all arguments to type java.lang.String.
2021-05-25 22:32:23,592 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.misc.DefaultArgumentParser: Parsing argument 'test' as type String, thread http-nio-8088-exec-4
2021-05-25 22:32:23,592 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating predicate: propertyPath == [test]
2021-05-25 22:32:23,593 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicate for: tags.name!='PS4'
2021-05-25 22:32:23,593 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating Predicate for comparison node: tags.name!='PS4'
2021-05-25 22:32:23,593 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Property graph path : tags.name
2021-05-25 22:32:23,593 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Create a join between com.getinsured.tag.model.dao.TagTarget and com.getinsured.tag.model.dao.Tag.
2021-05-25 22:32:23,598 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Create property path for type com.getinsured.tag.model.dao.Tag property name.
2021-05-25 22:32:23,599 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Cast all arguments to type java.lang.String.
2021-05-25 22:32:23,599 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.misc.DefaultArgumentParser: Parsing argument 'PS4' as type String, thread http-nio-8088-exec-4
2021-05-25 22:32:23,599 INFO [http-nio-8088-exec-4] com.github.tennaito.rsql.jpa.PredicateBuilder: Creating predicate: propertyPath != [PS4]
Hibernate: select tagtarget0_.id as id1_2_, tagtarget0_.active as active2_2_, tagtarget0_.creation_timestamp as creation3_2_, tagtarget0_.target_id as target_i4_2_, tagtarget0_.target_name as target_n5_2_, tagtarget0_.last_update_timestamp as last_upd6_2_ from target tagtarget0_ inner join tag_target tags1_ on tagtarget0_.id=tags1_.target_id inner join tags tag2_ on tags1_.tag_id=tag2_.id inner join tag_target tags3_ on tagtarget0_.id=tags3_.target_id inner join tags tag4_ on tags3_.tag_id=tag4_.id where (lower(tag2_.name) like ?) and (lower(tag4_.name) not like ?)
Hibernate: select tags0_.target_id as target_i1_0_0_, tags0_.tag_id as tag_id2_0_0_, tag1_.id as id1_1_1_, tag1_.creation_timestamp as creation2_1_1_, tag1_.name as name3_1_1_ from tag_target tags0_ inner join tags tag1_ on tags0_.tag_id=tag1_.id where tags0_.target_id=?
Hibernate: select tags0_.target_id as target_i1_0_0_, tags0_.tag_id as tag_id2_0_0_, tag1_.id as id1_1_1_, tag1_.creation_timestamp as creation2_1_1_, tag1_.name as name3_1_1_ from tag_target tags0_ inner join tags tag1_ on tags0_.tag_id=tag1_.id where tags0_.target_id=?
理想情况下,如果有人能指出我如何利用带有 rsql-jpa 的映射表的正确方向,这将返回给我具有“测试标签但没有 PS4 的目标”,那就太好了!我在类似于此处描述的毒物设计,但在 rsql 中:
http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/