使用RSQL实现端到端的动态查询

本文主要研究一下如何使用RSQL实现从前端到后端的动态数据查询。

RSQL

RSQL(RESTful Service Query Language)是Feed Item Query Language (FIQL) 的超集,是一种RESTful服务的查询语言。这里我们使用rsql-jpa来实践,它依赖rsql-parser来解析RSQL语法,然后将解析后的RSQL转义到JPA的Specification。

maven

<dependency>
    <groupId>com.github.tennaito</groupId>
    <artifactId>rsql-jpa</artifactId>
    <version>2.0.2</version>
</dependency>

它依赖了rsql-parser

实例

domain

@Entity
public class TodoTask {

    @javax.persistence.Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private Long totalNum = 0L;

    private String title;

    @Version
    private Long version;

    //...
}    

controller

@RestController
@RequestMapping("/rsql")
public class RsqlController {

    @Autowired
    TodoTaskService todoTaskService;

    /**
     * @param condition
     * @param page
     * @param size
     * @return
     */
    @GetMapping("")
    public Page<TodoTask> query(@RequestParam String condition,
                                @RequestParam(required = false,defaultValue = "0") int page,
                                @RequestParam(required = false,defaultValue = "20") int size){
        return todoTaskService.query(condition,new PageRequest(page,size));
    }
}

service

@Component
public class TodoTaskService {

    @Autowired
    private EntityManager entityManager;

    public Page<TodoTask> query(String condition, Pageable pageable){
        // 1.Create the JPA Visitor
        RSQLVisitor<CriteriaQuery<TodoTask>, EntityManager> visitor = new JpaCriteriaQueryVisitor<TodoTask>();
        // 2.Parse a RSQL into a Node
        Node rootNode = new RSQLParser().parse(condition);
        // 3.Create CriteriaQuery
        CriteriaQuery<TodoTask> criteriaQuery = rootNode.accept(visitor, entityManager);
        List<TodoTask> total = entityManager.createQuery(criteriaQuery).getResultList();
        List<TodoTask> resultList = entityManager.createQuery(criteriaQuery)
                .setFirstResult(pageable.getOffset()).setMaxResults(pageable.getPageSize()).getResultList();

        return new PageImpl<>(resultList,pageable, total.size());
    }
}

这里直接使用EntityManager来查询,总共分三步,1是创建RSQLVisitor,2是解析condition到Node,3是根据node创建CriteriaQuery,然后就可以根据CriteriaQuery来查询了。

运行

curl -i http://localhost:8080/rsql?condition=title==hello
curl -i http://localhost:8080/rsql?condition=totalNum%3E50
curl -i http://localhost:8080/rsql?condition=totalNum%3E50;title==hello

其中%3E是>的url转义,如果有多个and条件,用;分隔

小结

RSQL是一种强大抽象的语言,可以用来做REST服务的通用查询语言,spring-data-rest也提供了类似的功能,功能更为强大。不过这种貌似不支持or查询,另外数据量大的时候,直接走db查询可能造成慢查询,因为并不是所有字段都有索引,不过对于走elasticsearch来说,还是比较合适的。

doc

猜你喜欢

转载自my.oschina.net/go4it/blog/1633108