日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

jooq 分页排序_将jOOQ与Spring结合使用:排序和分页

發布時間:2023/12/3 javascript 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jooq 分页排序_将jOOQ与Spring结合使用:排序和分页 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

jooq 分頁排序

JOOQ是一個庫,可以幫助我們控制SQL。 它可以從我們的數據庫生成代碼,并允許我們使用其流暢的API來構建類型安全的數據庫查詢。

本教程前面的部分向我們介紹了如何配置應用程序的應用程序上下文,如何從數據庫生成代碼以及將CRUD操作添加到jOOQ存儲庫。

這次,我們將學習如何實現支持排序和分頁的簡單搜索功能。

讓我們開始吧。

補充閱讀:

  • 將jOOQ與Spring結合使用:配置是本教程的第一部分,它描述了您可以配置使用jOOQ的Spring應用程序的應用程序上下文。 您可以在不閱讀本教程第一部分的情況下了解此博客文章,但是,如果您想在Spring支持的應用程序中真正使用jOOQ,建議您也閱讀本教程的第一部分。
  • 將jOOQ與Spring結合使用:代碼生成是本教程的第二部分,它描述了如何對數據庫進行反向工程并創建代表不同數據庫表,記錄等的jOOQ查詢類。 因為這些類是類型安全SQL查詢的構建塊, 所以建議您在閱讀本博客文章之前閱讀本教程的第二部分
  • 在Spring中使用jOOQ:CRUD描述了如何為管理待辦事項的簡單應用程序添加CRUD操作。 因為它涵蓋了使用Spring創建jOOQ存儲庫所需的信息, 所以建議您在閱讀此博客文章之前先閱讀它

向Web層添加分頁和排序支持

當我們實現必須同時支持分頁和排序的搜索功能時,我們必須找出一種方法來向后端提供頁碼,頁面大小,排序字段的名稱和排序順序。

我們當然可以實現一個支持此功能的組件,但它并不像聽起來那么簡單。 創建一個HandlerMethodArgumentResolver很容易,它可以從HTTP請求中找到此信息并將其轉換為對象,然后將該對象作為方法參數傳遞給我們的控制器方法。 問題在于,存在許多“例外”情況,這使該任務非常棘手。 例如,

  • 如果從HTTP請求中找不到此信息,則必須回退到默認值。
  • 如果缺少所需的信息(例如,沒有指定頁面大小就給出了頁碼),我們必須退回到默認值或向REST API用戶返回錯誤。

幸運的是,我們不必實現此組件。 Spring Data Commons項目具有一個組件 , 該組件從HTTP請求中提取分頁和排序信息,并允許我們將該信息注入到控制器方法中。

讓我們發現我們可以使用Maven獲得Spring Data Commons二進制文件。

使用Maven獲取所需的依賴關系

通過將以下依賴項聲明添加到POM文件的依賴項部分,我們可以使用Maven獲得所需的二進制文件:

<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-commons</artifactId><version>1.7.1.RELEASE</version> </dependency>

下一步是對示例應用程序的應用程序上下文配置進行一些更改。 讓我們繼續前進,找出我們必須進行的更改。

配置應用程序上下文

我們可以通過對應用程序上下文配置類進行簡單的更改來啟用Spring Data的Web分頁支持,該類配置了示例應用程序的Web層。 我們必須使用@EnableSpringDataWebSupport批注來批注配置類。 這樣可以確保所需的bean自動注冊。

@EnableSpringDataWebSupport批注的API文檔提供了有關使用此批注時注冊的bean的更多信息。

WebAppContext類的相關部分如下所示:

import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.data.web.config.EnableSpringDataWebSupport; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration @ComponentScan({"net.petrikainulainen.spring.jooq.common.controller","net.petrikainulainen.spring.jooq.todo.controller" }) @EnableWebMvc @EnableSpringDataWebSupport public class WebAppContext extends WebMvcConfigurerAdapter {//Other methods are omitted for the sake of clarity }

這就對了。 現在,我們對示例應用程序的應用程序上下文配置進行了必要的更改。 讓我們找出如何在應用程序中使用Web分頁支持。

使用網頁分頁

當我們想對查詢結果進行排序和分頁時,我們必須遵循以下步驟:

  • 將分頁和排序配置添加到HTTP請求。
  • 將Pageable方法參數添加到控制器方法。
  • 首先 ,我們可以使用以下請求參數將分頁和排序配置添加到HTTP請求:

    • 頁面請求參數指定請求的頁碼。
    • size request參數指定所請求頁面的大小。
    • 排序請求參數指定用于對查詢結果進行排序的屬性。 此請求參數的此值必須遵循以下語法: property,property(,ASC | DESC) 。 如果未給出排序方向,則結果將按升序排序。 如果要切換排序順序,則必須使用多個排序參數(例如?sort = title&sort = id,desc )。

    其次 ,我們必須在我們的控制器方法中添加一個Pageable方法參數。 TodoController類的相關部分如下所示:

    import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController;import javax.validation.Valid; import java.util.List;@RestController @RequestMapping("/api/todo") public class TodoController {private final TodoCrudService crudService;private final TodoSearchService searchService;@Autowiredpublic TodoController(TodoCrudService crudService, TodoSearchService searchService) {this.crudService = crudService;this.searchService = searchService;}@RequestMapping(value = "/search", method = RequestMethod.GET)public List<TodoDTO> findBySearchTerm(@RequestParam("searchTerm") String searchTerm, Pageable pageable) {return searchService.findBySearchTerm(searchTerm, pageable);} }

    現在,我們可以將搜索功能添加到我們的jOOQ存儲庫中。 讓我們找出這是如何完成的。

    實施存儲庫層

    我們要做的第一件事是向TodoService接口添加一個新的公共方法。 findBySearchTerm(String searchTerm,Pageable pageable)方法查找其標題或描述包含給定搜索詞的待辦事項,并按照作為方法參數給出的分頁和排序配置返回查詢結果。

    TodoRepository接口的相關部分如下所示:

    import org.springframework.data.domain.Pageable;import java.util.List;public interface TodoRepository {public List<Todo> findBySearchTerm(String searchTerm, Pageable pageable);//Other methods are omitted for the sake of clarity }

    此方法的實現有兩個職責:

  • 它必須找到標題或描述包含給定搜索詞的待辦事項。
  • 它必須處理從Pageable對象中找到的排序和分頁選項,并將它們轉換為jOOQ可以理解的形式。
  • 讓我們繼續前進,找出如何找到標題或描述包含給定搜索詞的待辦事項。

    實施搜索查詢

    我們可以按照以下步驟實施搜索查詢:

  • 將findBySearchTerm(String searchTerm,Pageable pageable )方法添加到JOOQTodoRepository類。
  • 使用@Transactional注釋對方法進行注釋,并將其readOnly屬性的值設置為true。
  • 通過執行以下步驟來實現findBySearchTerm()方法:
  • 創建在我們的數據庫查詢中使用的like表達式。
  • 通過調用DSLContext接口的selectFrom(Table table)方法來創建新的SELECT語句,并指定要從todos表中選擇信息。
  • 通過調用SelectWhereStep接口的where(Collection condition)方法來指定SELECT語句的WHERE子句。 通過執行以下步驟創建此方法的方法參數:
  • 通過調用Field接口的likeIgnoreCase(String value)方法,為 todos表的description和title列創建相似的條件。 將like表達式作為方法參數傳遞。
  • 通過使用Condition接口的or(Condition other)方法組合創建的類似條件。
  • 通過調用ResultQuery接口的fetchInto(Class type)方法獲取TodosRecord對象的列表。 傳遞TodosRecord.class對象作為方法參數。
  • 通過調用私有的convertQueryResultsToModelObjects()方法,將TodosRecord對象的列表轉換為Todo對象的列表。 此方法迭代TodosRecord對象的列表,并通過調用convertQueryResultToModelObject()方法將每個TodosRecord對象轉換為Todo對象。 每個Todo對象都添加到一個列表中,當所有TodosRecord對象都處理完畢后 ,將返回該列表。
  • 返回Todo對象的列表。
  • 我們實現的源代碼如下:

    import org.jooq.DSLContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList; import java.util.List;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional(readOnly = true)@Overridepublic List<Todo> findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression = "%" + searchTerm + "%";List<TodosRecord> queryResults = jooq.selectFrom(TODOS).where(TODOS.DESCRIPTION.likeIgnoreCase(likeExpression).or(TODOS.TITLE.likeIgnoreCase(likeExpression))).fetchInto(TodosRecord.class);return convertQueryResultsToModelObjects(queryResults);}private List<Todo> convertQueryResultsToModelObjects(List<TodosRecord> queryResults) {List<Todo> todoEntries = new ArrayList<>();for (TodosRecord queryResult : queryResults) {Todo todoEntry = convertQueryResultToModelObject(queryResult);todoEntries.add(todoEntry);}return todoEntries;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}//Other methods are omitted for the sake of clarity }

    此示例的數據庫查詢非常簡單。 如果需要創建更復雜的數據庫查詢,則應閱讀4.6節。 jOOQ參考手冊的條件表達式 。 它描述了如何在數據庫查詢中使用條件表達式。

    現在,我們已經創建了一個存儲庫方法,該方法從數據庫中搜索待辦事項。 下一步是對該數據庫查詢的查詢結果進行排序。

    查詢結果排序

    在對搜索查詢的查詢結果進行排序之前,我們必須了解如何從Pageable對象中獲取數據庫查詢的排序選項。

    • 我們可以通過調用Pageable接口的getSort()方法來獲得對Sort對象的引用。 該對象包含從HTTP請求中找到的排序選項。
    • 排序對象可以包含零個或多個排序選項。 Sort類的iterator()方法返回一個Iterator <Sort.Order>對象,當我們要處理數據庫查詢的每個排序選項時可以使用該對象。
    • Sort.Order類包含屬性名稱和排序方向 。

    換句話說,我們必須滿足以下要求:

    • 我們必須支持未指定排序選項的情況。
    • 我們必須支持一種情況,其中我們的查詢結果通過使用多列進行排序。
    • 我們必須假設每個列都有自己的排序順序。

    我們可以通過對JOOQTodoRepository類進行以下更改來滿足這些要求:

  • 將私有的getTableField(String sortFieldName)方法添加到存儲庫類,并按照以下步驟實現此方法:
  • 使用反射獲得一個Field對象,該對象提供有關Todos對象的請求字段的信息。
  • 如果找不到該字段或我們無法訪問它,則拋出一個新的InvalidDataAccessApiUsageException 。
  • 如果找到該字段,則將返回的Field對象轉換為TableField對象,然后將其返回。
  • 將私有的convertTableFieldToSortField(TableField tableField,Sort.Direction sortDirection)方法添加到存儲庫類,并通過以下步驟實現該方法:
  • 如果此字段的排序順序是升序,請調用Field接口的asc()方法并返回返回的對象。
  • 否則,調用Field接口的desc()方法并返回返回的對象。
  • 將私有的getSortFields(Sort sortSpecification)方法添加到存儲庫類,并通過以下步驟實現它:
  • 創建一個包含SortField <?>對象的新Collection 。
  • 如果找不到排序選項,則返回一個空的Collection對象。
  • 迭代從作為方法參數給出的Sort對象中找到的Sort.Order對象,并按照以下步驟處理每個Sort.Order對象:
  • 使用getTableField()和convertTableFieldToSortField()方法將每個Sort.Order對象轉換為SortField <?>對象。
  • 將每個SortField <?>對象添加到在第一步中創建的Collection中。
  • <?>的對象返回的的SortField 集合 。
  • 請按照以下步驟對查詢結果進行排序:
  • 通過調用Pageable接口的getSort()方法來獲取Sort對象。
  • 通過調用getSortFields()方法獲取Collection <SortField <?>>對象。 將Sort對象作為方法參數傳遞。
  • 通過調用SelectSeekStepN接口的orderBy(Collection <?擴展SortField <?>>字段)方法來創建ORDER BY子句,并將Collection <SortField <?>>對象作為方法參數傳遞。
  • 我們的實現的源代碼如下所示(相關部分已突出顯示):

    import org.jooq.DSLContext; import org.jooq.SortField; import org.jooq.TableField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional(readOnly = true)@Overridepublic List<Todo> findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression = "%" + searchTerm + "%";List<TodosRecord> queryResults = jooq.selectFrom(TODOS).where(TODOS.DESCRIPTION.likeIgnoreCase(likeExpression).or(TODOS.TITLE.likeIgnoreCase(likeExpression))).orderBy(getSortFields(pageable.getSort())).fetchInto(TodosRecord.class);return convertQueryResultsToModelObjects(queryResults);}private Collection<SortField<?>> getSortFields(Sort sortSpecification) {Collection<SortField<?>> querySortFields = new ArrayList<>();if (sortSpecification == null) {return querySortFields;}Iterator<Sort.Order> specifiedFields = sortSpecification.iterator();while (specifiedFields.hasNext()) {Sort.Order specifiedField = specifiedFields.next();String sortFieldName = specifiedField.getProperty();Sort.Direction sortDirection = specifiedField.getDirection();TableField tableField = getTableField(sortFieldName);SortField<?> querySortField = convertTableFieldToSortField(tableField, sortDirection);querySortFields.add(querySortField);}return querySortFields;}private TableField getTableField(String sortFieldName) {TableField sortField = null;try {Field tableField = TODOS.getClass().getField(sortFieldName);sortField = (TableField) tableField.get(TODOS);} catch (NoSuchFieldException | IllegalAccessException ex) {String errorMessage = String.format("Could not find table field: {}", sortFieldName);throw new InvalidDataAccessApiUsageException(errorMessage, ex);}return sortField;}private SortField<?> convertTableFieldToSortField(TableField tableField, Sort.Direction sortDirection) {if (sortDirection == Sort.Direction.ASC) {return tableField.asc();}else {return tableField.desc();}}private List<Todo> convertQueryResultsToModelObjects(List<TodosRecord> queryResults) {List<Todo> todoEntries = new ArrayList<>();for (TodosRecord queryResult : queryResults) {Todo todoEntry = convertQueryResultToModelObject(queryResult);todoEntries.add(todoEntry);}return todoEntries;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}//The other methods are omitted for the sake of clarity }

    此解決方案有效,但會將我們的存儲庫層(和數據庫)的實現細節泄漏給REST API的客戶端。 我們可以通過為列名稱指定一組允許的別名來避免這種情況,并實現一個轉換組件,將這些別名轉換為Todos類的字段名稱。

    但是,因為這會增加我們的存儲庫類的復雜性,所以我們不會這樣做。

    這實際上是泄漏抽象的一個很好的例子。 這個詞最初是由Joel Spolsky推廣的。 他“發明” 了泄漏抽象定律,該定律指出:

    在某種程度上,所有非平凡的抽象都是泄漏的。

    通過閱讀jOOQ參考手冊的4.3.2.9節 ORDER BY子句,可以獲得有關ORDER BY子句的更多信息。

    現在,我們在搜索查詢中添加了排序支持。 讓我們繼續并通過向findBySearchTerm()方法添加分頁支持來完成我們的搜索功能。

    分頁查詢結果

    通過將LIMIT .. OFFSET子句添加到數據庫查詢中,我們可以對搜索查詢的查詢結果進行分頁。 我們可以通過對數據庫查詢的實現進行以下更改來做到這一點:

  • 通過調用SelectLimitStep接口的limit(int NumberOfRows)方法指定返回的行數,并將頁面大小傳遞給方法參數(您可以通過調用Pageable接口的getPageSize()方法來獲取頁面大小)。
  • 通過調用SelectOffsetStep接口的offset(int offset)方法指定偏移量, 并將偏移量作為方法參數傳遞(您可以通過調用Pageable接口的getOffset()方法來獲取偏移量)。
  • 在對存儲庫方法進行了這些更改之后,存儲庫方法的源代碼如下所示(突出顯示了更改):

    import org.jooq.DSLContext; import org.jooq.SortField; import org.jooq.TableField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional;import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional(readOnly = true)@Overridepublic List<Todo> findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression = "%" + searchTerm + "%";List<TodosRecord> queryResults = jooq.selectFrom(TODOS).where(TODOS.DESCRIPTION.likeIgnoreCase(likeExpression).or(TODOS.TITLE.likeIgnoreCase(likeExpression))).orderBy(getSortFields(pageable.getSort())).limit(pageable.getPageSize()).offset(pageable.getOffset()).fetchInto(TodosRecord.class);return convertQueryResultsToModelObjects(queryResults);}private Collection<SortField<?>> getSortFields(Sort sortSpecification) {Collection<SortField<?>> querySortFields = new ArrayList<>();if (sortSpecification == null) {return querySortFields;}Iterator<Sort.Order> specifiedFields = sortSpecification.iterator();while (specifiedFields.hasNext()) {Sort.Order specifiedField = specifiedFields.next();String sortFieldName = specifiedField.getProperty();Sort.Direction sortDirection = specifiedField.getDirection();TableField tableField = getTableField(sortFieldName);SortField<?> querySortField = convertTableFieldToSortField(tableField, sortDirection);querySortFields.add(querySortField);}return querySortFields;}private TableField getTableField(String sortFieldName) {TableField sortField = null;try {Field tableField = TODOS.getClass().getField(sortFieldName);sortField = (TableField) tableField.get(TODOS);} catch (NoSuchFieldException | IllegalAccessException ex) {String errorMessage = String.format("Could not find table field: {}", sortFieldName);throw new InvalidDataAccessApiUsageException(errorMessage, ex);}return sortField;}private SortField<?> convertTableFieldToSortField(TableField tableField, Sort.Direction sortDirection) {if (sortDirection == Sort.Direction.ASC) {return tableField.asc();}else {return tableField.desc();}}private List<Todo> convertQueryResultsToModelObjects(List<TodosRecord> queryResults) {List<Todo> todoEntries = new ArrayList<>();for (TodosRecord queryResult : queryResults) {Todo todoEntry = convertQueryResultToModelObject(queryResult);todoEntries.add(todoEntry);}return todoEntries;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}//Other methods are omitted for the sake of clarity }

    您可以對限制更多信息..閱讀OFFSET條款部分4.3.2.10極限.. OFFSET的jOOQ參考手冊的條款 。

    如果您需要實現“永恒滾動”(如時間軸上的Facebook),則應考慮使用seek方法。 您可以從jOOQ網站獲取有關此信息的更多信息:

    • 使用Seek方法使用jOOQ進行更快SQL分頁
    • 使用鍵集進行更快SQL分頁,續
    • SEEK子句@ jOOQ參考手冊

    就這些了。 讓我們繼續并總結從這篇博客文章中學到的知識。

    摘要

    現在,我們已經實現了支持排序和分頁的搜索功能。 本教程教會了我們三件事:

    • 我們了解了如何使用Spring Data Commons項目的Web分頁支持。
    • 我們學習了如何將ORDER BY子句添加到數據庫查詢中。
    • 我們學習了如何在數據庫查詢中添加LIMIT .. OFFSET子句。

    本教程的下一部分描述了如何集成Spring Data JPA和jOOQ,更重要的是,為什么要這樣做。

    • Github上提供了此博客文章的示例應用程序。

    翻譯自: https://www.javacodegeeks.com/2014/05/using-jooq-with-spring-sorting-and-pagination.html

    jooq 分頁排序

    總結

    以上是生活随笔為你收集整理的jooq 分页排序_将jOOQ与Spring结合使用:排序和分页的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。