java 如何用Springboot和JPA处理同一端点的多个查询参数

xfb7svmp  于 2023-01-19  发布在  Java
关注(0)|答案(3)|浏览(283)

我目前正在学习Springboot,所以我正在开发一个个人项目。在这个项目中有一个名为Campaign的实体,我想建立一个端点来列出数据库中的所有活动过滤,排序和分页
请求的一些示例:

# Pagination 

GET domain/api/v1/campaigns (return the first page with  all campaigns, default sorting and page size 20)
GET domain/api/v1/campaigns?page=2&size=50 (return the second page with all campaigns, default sorting and page size 50)
GET domain/api/v1/campaigns?page=2&size=100 (return the second page with all campaigns, default sorting and page size 50 which is the max)

# SORTING
GET domain/api/v1/campaigns?sort=name,asc (return the first page with all campaigns, sorting by name and page size 20)
GET domain/api/v1/campaigns?sort=name,asc&sort=startDate,dsc (return the first page with all campaigns, sorting by name and startDate and page size 20) 

# Filtering

GET domain/api/v1/campaigns?status=open (return the first page with all campaigns with "open" status, default sorting and page size 20)
GET domain/api/v1/campaigns?status=open&status=new (return the first page with all campaigns with "open" and "new" status,default sorting and page size 20)
GET domain/api/v1/campaigns?status=open&startdate=2023-01-12 (return the first page with all campaigns with "open" status and startDate 2023-01-12, default sortin and page size 20)

# Combined
GET domain/api/v1/campaigns?status=open&status=new&page=2&size=10&sort=name,asc (returns page 2 with size 10 sorting by name the campaigns with statuses "open" and "new")

哪一种是最好的实现方式?一个基于参数委托给正确服务方法的控制器方法?在HashMap上收集参数并为处理参数的数据库创建一个通用查询?许多不同的控制器接收不同的参数集?
下面是mt Campign模型和空的存储库、服务和控制器
一个一个一个一个一个x一个一个二个一个x一个一个三个一个x一个一个x一个四个一个

8e2ybdfx

8e2ybdfx1#

您可以在控制器中使用注解@RequestParam,它类似于:

@GetMapping("/api/v1/campaigns")
@ResponseBody
public String CampaignController(@RequestParam(name = "page", required = false, defaultValue = "0") Integer page, @RequestParam (name = "size", required = false, defaultValue = "50") Integer size) {
return "page: " + page;
}
chy5wohz

chy5wohz2#

对于分页和排序,Spring框架提供了良好的支持:

public interface CampaignRepository extends PagingAndSortingRepository<Campaign, Long> {

}

PagingAndSortingRepository
这为您提供了将Pageable附加到方法的可能性。例如,如果您想要按状态对过滤的结果进行分页:

public interface CampaignRepository extends PagingAndSortingRepository<Campaign, Long> {

    List<Campaign> findAllByStatusIn(Collection<String> status, Pageable pageRequest);

}

然后,您的服务可以轻松地准备这样的可寻呼内容,例如:

public List<Campaign> listByStatusSorted(Collection<String> status, int page, int pageSize, String sortProperty) {

    PageRequest pageRequest = PageRequest.of(page, pageSize, Sort.by(sortProperty).ascending());
    return campaignRepository.findAllByStatusIn(status, pageRequest);

}

PageRequestSort
当然,升序或降序排序也可以从控制器提供给服务,但本质上我会有一个或两个服务方法,我认为这是一个品味问题,你宁愿有另一个服务方法,而不是添加更多的参数。
我会尽量使用一个带有默认值的控制器端点,大致如下:

public List<Campaign> listCampaigns(@RequestParam(value = "page", required = false, defaultValue = "0") int page, @RequestParam(value = "pageSize", required = false, defaultValue = "20") int pageSize, ...) {
    ...
}

从这个来看,绝对没有
收集HashMap上的参数,并为处理这些参数的数据库创建一个通用查询
通过使用命名约定,一切都为您准备好了。事实上,我上面提供的存储库应该已经可以工作了,不需要任何进一步的代码-只需将其注入到服务中。进一步阅读Spring Data 存储库的强大功能。

7uhlpewt

7uhlpewt3#

看起来您正在尝试构建一个动态查询。在这种情况下,您不仅可以使用单个控制器方法来完成此操作,而且使用Specifications也只需要一个服务方法。此外,您可以使用Page<T>接口和PageRequest类来检索某些页并限制其大小
CampaignController.java

// receive all possible arguments
public Page<Campaign> filterCampaigns(..., Pageable pageable) {
    return campaignService.getCampaignsByCriteria(..., pageable.getPageNumber());
}

您可以将所有可能的URL参数传递给控制器方法。若要执行规范,CampaignRepository需要扩展JpaSpecificationExecutor<T>接口。为活动分页需要另一个接口PagingAndSortingRepository<T, ID>
CampaignRepository.java

public interface CampaignRepository extends 
JpaRepository<Campaign, Long>, JpaSpecificationExecutor<Campaign>, 
PagingAndSortingRepository<Campaign, Long> {

}

接下来,创建一个定义这些规范的helper类。这里是一个按状态查找的示例,但是您可以根据需要创建任意多个规范
CampaignSpecification.java

public static Specification<Campaign> hasStatus(String campaignStatus) {
    return startDate == null ? null : (root, query, criteriaBuilder) -> 
        criteriaBuilder.equal(root.get("status"), campaignStatus);

}

返回规范***如果提供了状态值***或返回null使其更加灵活,因为status URL参数本质上是可选的。同样值得注意的是,这适用于方法中的每个参数。现在,您可以在服务中执行此规范。
CampaignService.java

public Page<Campaign> getCampaignsByCriteria(String status, 
                                            LocalDateTime startDate, 
                                            int pageNumber) {

    PageRequest campaignPageRequest = PageRequest
        .of(pageNumber, 2, Sort.by("startDate").ascending());

    return campaignRepository.findAll(Specification.where(
        CampaignSpecification.hasStatus(status).
        and(CampaignSpecification.hasSomethingElse(...)))
        , campaignPageRequest)
    )
}

您可以根据需要链接任意多个规范。PageRequest类允许您指定当前页面、每页的最大项目数以及执行排序
进一步阅读:
Spring数据规范:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
页面界面:https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Page.html
页面请求:https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/PageRequest.html

相关问题