我对这些技术还是比较陌生的,我需要一个能够理解做事的好方法。 我有一个Employee实体,我想通过对端点进行GET查询来列出它们。在对字段应用过滤器之后,我必须返回一个Employees页面。目前,GET查询中的Pageable有效,但不适用于我的过滤器。
这是我的REST端点:
@RequestMapping(value = "/employees",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional(readOnly = true)
public ResponseEntity<List<EmployeeDTO>> getAllEmployees(Pageable pageable, String filters) throws URISyntaxException, JSONException {
JSONObject sfilters = null;
try {
sfilters = new JSONObject(filters.trim());
} catch (JSONException e) {
e.printStackTrace();
}
// I wish this on could works, but still have to update it if we add fields to our Employee entity
Page<Employee> page = employeeRepository.findAllByCompanyIdAndFirstnameLikeAndLastnameLike(
userService.getUserWithAuthorities().getCompany().getId(),
sfilters.get("firstname").toString(),
sfilters.get("lastname").toString(),
pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/employees");
ResponseEntity<List<EmployeeDTO>> result = new ResponseEntity<>(page.getContent().stream()
.map(employeeMapper::employeeToEmployeeDTO)
.collect(Collectors.toCollection(LinkedList::new)), headers, HttpStatus.OK);
return result;
}
注意:我必须过滤掉比这更多的字段,但我希望尽可能清楚地保持示例。
我的存储库方法:
Page<Employee> findAllByCompanyIdAndFirstnameLikeAndLastnameLike(Long idCompany, String firstname, String lastname, Pageable pageable);
客户端,它运行良好,我发送可用于分页的好的参数,并将我的过滤器转换为JSONObject。但现在我需要有关如何在查询中正确生成动态过滤器的建议。我的JPA存储库方法不起作用。
我尝试使用谓词,但是当我给它一个Predicate arg时,它没有帮助,因为这些方法失败了。这个方法似乎很好检查项目,如果一个或多个匹配你的pred但不确定它们是用于检索动态查询的项目集。
编辑:我创建了一个实现规范的EmployeeSpecification类,但我想要返回一个Predicates的列表/数组,而不仅仅是一个。因此,覆盖的默认方法返回单个谓词。如何设法从该实体获取多个谓词?
感谢您提供任何暗示,帮助和过去的经验。
答案 0 :(得分:3)
我发现了如何使用Predicates做到这一点。首先,我必须在我的存储库中使用JPA方法findAll:
Page<Employee> findAll(Specification<Employee> spec, Pageable pageable);
然后,我创建了一个实现规范Spring Boot对象的自定义类:
public class EmployeeSpecification implements Specification<Employee> {
private final JSONObject criteria;
private List<Predicate> filters;
public EmployeeSpecification(JSONObject criteria) {
this.criteria = criteria;
}
@Override
public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
Iterator<?> keys = criteria.keys();
List<Predicate> filters = new ArrayList<>();
if (criteria.length() != 0) {
while (keys.hasNext()) {
String key = (String) keys.next();
String filterValue = null;
try {
filterValue = criteria.get(key).toString();
} catch (JSONException e) {
e.printStackTrace();
}
if (filterValue != null) {
filters.add(criteriaBuilder.like(criteriaBuilder.upper(root.<String>get(key)), "%" + filterValue.toUpperCase() + "%"));
}
}
}
//this is the point : didn't know we could concatenate multiple predicates into one.
return criteriaBuilder.and(filters.toArray(new Predicate[filters.size()]));
}
}
在此之后,在我的WS端点方法中,我只需实现EmployeeSpecification 并调用JPA findAll方法,传递我的过滤器JSON对象和我的Pageable对象:
@RequestMapping(value = "/employees",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional(readOnly = true)
public ResponseEntity<List<EmployeeDTO>> getAllEmployees(Pageable pageable, String filters) throws URISyntaxException, JSONException {
JSONObject sfilters = null;
try {
sfilters = new JSONObject(filters.trim());
} catch (JSONException e) {
e.printStackTrace();
}
EmployeeSpecification spec = new EmployeeSpecification(sfilters);
Page<Employee> page = employeeRepository.findAll(
spec,
pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/employees");
ResponseEntity<List<EmployeeDTO>> result = new ResponseEntity<>(page.getContent().stream()
.map(employeeMapper::employeeToEmployeeDTO)
.collect(Collectors.toCollection(LinkedList::new)), headers, HttpStatus.OK);
return result;
}
现在我可以发送Pageable项目和多个字段过滤器,我可以根据排序,每页数量,当前页面和字段过滤器正确检索结果。 非常感谢你的帮助;)(笑)
答案 1 :(得分:0)
也可以使用规格来完成。看起来更加干净和正确。请检查这篇文章: https://blog.tratif.com/2017/11/23/effective-restful-search-api-in-spring/
它还显示了如何解决“加入”问题和其他问题。 通常,您可以像这样添加过滤器来查询(摘自上面的链接):
install.packages(c("cowplot","googleway", "ggplot2", "ggrepel",
"ggspatial", "libwgeom", "sf", "rnaturalearth", "rnaturalearthdata",
"rgeos"))
library("ggplot2")
theme_set(theme_bw())
library("sf")
library("rnaturalearth")
library("rnaturalearthdata")
library(rgeos)
world <- ne_countries(scale = "medium", returnclass = "sf")
class(world)