怀化网站优化哪里有,移动建站平台,福州网seo,陕西省咸阳市建设银行网站jooq 分页排序JOOQ是一个库#xff0c;可以帮助我们控制SQL。 它可以从我们的数据库生成代码#xff0c;并允许我们使用其流畅的API来构建类型安全的数据库查询。 本教程前面的部分向我们介绍了如何配置应用程序的应用程序上下文#xff0c;如何从数据库生成代码以及将CRUD… jooq 分页排序 JOOQ是一个库可以帮助我们控制SQL。 它可以从我们的数据库生成代码并允许我们使用其流畅的API来构建类型安全的数据库查询。 本教程前面的部分向我们介绍了如何配置应用程序的应用程序上下文如何从数据库生成代码以及将CRUD操作添加到jOOQ存储库。 这次我们将学习如何实现支持排序和分页的简单搜索功能。 让我们开始吧。 补充阅读 将jOOQ与Spring结合使用配置是本教程的第一部分它描述了您可以配置使用jOOQ的Spring应用程序的应用程序上下文。 您可以在不阅读本教程第一部分的情况下了解此博客文章但是如果您想在Spring支持的应用程序中真正使用jOOQ建议您也阅读本教程的第一部分。 将jOOQ与Spring结合使用代码生成是本教程的第二部分它描述了如何对数据库进行反向工程并创建代表不同数据库表记录等的jOOQ查询类。 因为这些类是类型安全SQL查询的构建块 所以建议您在阅读本博客文章之前阅读本教程的第二部分 。 在Spring中使用jOOQCRUD描述了如何为管理待办事项的简单应用程序添加CRUD操作。 因为它涵盖了使用Spring创建jOOQ存储库所需的信息 所以建议您在阅读此博客文章之前先阅读它 。 向Web层添加分页和排序支持 当我们实现必须同时支持分页和排序的搜索功能时我们必须找出一种方法来向后端提供页码页面大小排序字段的名称和排序顺序。 我们当然可以实现一个支持此功能的组件但它并不像听起来那么简单。 创建一个HandlerMethodArgumentResolver很容易它可以从HTTP请求中找到此信息并将其转换为对象然后将该对象作为方法参数传递给我们的控制器方法。 问题在于存在许多“例外”情况这使该任务非常棘手。 例如 如果从HTTP请求中找不到此信息则必须回退到默认值。 如果缺少所需的信息例如没有指定页面大小就给出了页码我们必须退回到默认值或向REST API用户返回错误。 幸运的是我们不必实现此组件。 Spring Data Commons项目具有一个组件 该组件从HTTP请求中提取分页和排序信息并允许我们将该信息注入到控制器方法中。 让我们发现我们可以使用Maven获得Spring Data Commons二进制文件。 使用Maven获取所需的依赖关系 通过将以下依赖项声明添加到POM文件的依赖项部分我们可以使用Maven获得所需的二进制文件 dependencygroupIdorg.springframework.data/groupIdartifactIdspring-data-commons/artifactIdversion1.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参数指定所请求页面的大小。 排序请求参数指定用于对查询结果进行排序的属性。 此请求参数的此值必须遵循以下语法 propertypropertyASC | DESC 。 如果未给出排序方向则结果将按升序排序。 如果要切换排序顺序则必须使用多个排序参数例如sort titlesort iddesc 。 其次 我们必须在我们的控制器方法中添加一个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 ListTodoDTO findBySearchTerm(RequestParam(searchTerm) String searchTerm, Pageable pageable) {return searchService.findBySearchTerm(searchTerm, pageable);}
} 现在我们可以将搜索功能添加到我们的jOOQ存储库中。 让我们找出这是如何完成的。 实施存储库层 我们要做的第一件事是向TodoService接口添加一个新的公共方法。 findBySearchTermString searchTermPageable pageable方法查找其标题或描述包含给定搜索词的待办事项并按照作为方法参数给出的分页和排序配置返回查询结果。 TodoRepository接口的相关部分如下所示 import org.springframework.data.domain.Pageable;import java.util.List;public interface TodoRepository {public ListTodo findBySearchTerm(String searchTerm, Pageable pageable);//Other methods are omitted for the sake of clarity
} 此方法的实现有两个职责 它必须找到标题或描述包含给定搜索词的待办事项。 它必须处理从Pageable对象中找到的排序和分页选项并将它们转换为jOOQ可以理解的形式。 让我们继续前进找出如何找到标题或描述包含给定搜索词的待办事项。 实施搜索查询 我们可以按照以下步骤实施搜索查询 将findBySearchTermString searchTermPageable pageable 方法添加到JOOQTodoRepository类。 使用Transactional注释对方法进行注释并将其readOnly属性的值设置为true。 通过执行以下步骤来实现findBySearchTerm方法 创建在我们的数据库查询中使用的like表达式。 通过调用DSLContext接口的selectFromTable table方法来创建新的SELECT语句并指定要从todos表中选择信息。 通过调用SelectWhereStep接口的whereCollection condition方法来指定SELECT语句的WHERE子句。 通过执行以下步骤创建此方法的方法参数 通过调用Field接口的likeIgnoreCaseString value方法为 todos表的description和title列创建相似的条件。 将like表达式作为方法参数传递。 通过使用Condition接口的orCondition other方法组合创建的类似条件。 通过调用ResultQuery接口的fetchIntoClass 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 clarityTransactional(readOnly true)Overridepublic ListTodo findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression % searchTerm %;ListTodosRecord queryResults jooq.selectFrom(TODOS).where(TODOS.DESCRIPTION.likeIgnoreCase(likeExpression).or(TODOS.TITLE.likeIgnoreCase(likeExpression))).fetchInto(TodosRecord.class);return convertQueryResultsToModelObjects(queryResults);}private ListTodo convertQueryResultsToModelObjects(ListTodosRecord queryResults) {ListTodo 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类进行以下更改来满足这些要求 将私有的getTableFieldString sortFieldName方法添加到存储库类并按照以下步骤实现此方法 使用反射获得一个Field对象该对象提供有关Todos对象的请求字段的信息。 如果找不到该字段或我们无法访问它则抛出一个新的InvalidDataAccessApiUsageException 。 如果找到该字段则将返回的Field对象转换为TableField对象然后将其返回。 将私有的convertTableFieldToSortFieldTableField tableFieldSort.Direction sortDirection方法添加到存储库类并通过以下步骤实现该方法 如果此字段的排序顺序是升序请调用Field接口的asc方法并返回返回的对象。 否则调用Field接口的desc方法并返回返回的对象。 将私有的getSortFieldsSort 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接口的orderByCollection 扩展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 clarityTransactional(readOnly true)Overridepublic ListTodo findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression % searchTerm %;ListTodosRecord 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 CollectionSortField? getSortFields(Sort sortSpecification) {CollectionSortField? querySortFields new ArrayList();if (sortSpecification null) {return querySortFields;}IteratorSort.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 ListTodo convertQueryResultsToModelObjects(ListTodosRecord queryResults) {ListTodo 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接口的limitint NumberOfRows方法指定返回的行数并将页面大小传递给方法参数您可以通过调用Pageable接口的getPageSize方法来获取页面大小。 通过调用SelectOffsetStep接口的offsetint 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 clarityTransactional(readOnly true)Overridepublic ListTodo findBySearchTerm(String searchTerm, Pageable pageable) {String likeExpression % searchTerm %;ListTodosRecord 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 CollectionSortField? getSortFields(Sort sortSpecification) {CollectionSortField? querySortFields new ArrayList();if (sortSpecification null) {return querySortFields;}IteratorSort.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 ListTodo convertQueryResultsToModelObjects(ListTodosRecord queryResults) {ListTodo 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.htmljooq 分页排序