Spring MVC结合Spring Data JPA实现按条件查询和分页

下面是“Spring MVC结合Spring Data JPA实现按条件查询和分页”的完整攻略。

简介

Spring MVC结合Spring Data JPA可以实现按条件查询和分页,这对于实现Web应用程序中的高级搜索和结果分页非常有用。Spring MVC提供了有效的Web层,而Spring Data JPA则提供了持久层,两者结合可以快速搭建一个Web应用程序。本文将介绍如何使用Spring MVC和Spring Data JPA实现按条件查询和分页功能。

环境配置

首先确保你的电脑上已经安装好了JDK和Maven。然后,需要添加以下依赖项到Maven的pom.xml文件中。

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.9.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.data</groupId>
  <artifactId>spring-data-jpa</artifactId>
  <version>2.3.5.RELEASE</version>
</dependency>

实现步骤

1. 指定实体类和仓库接口

首先定义一个实体类和对应的JpaRepository接口。本文以一个简单的用户实体类为例。

@Entity
@Table(name = "users")
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "username")
  private String username;

  @Column(name = "email")
  private String email;

  @Column(name = "password")
  private String password;

  // getters and setters
}
public interface UserRepository extends JpaRepository<User, Long> {

  List<User> findByUsernameContaining(String username, Pageable pageable);

  Long countByUsernameContaining(String username);
}

上面的仓库接口中定义了两个方法。第一个方法findByUsernameContaining用于可以按照用户名查询用户列表,并且可以传入Pageable参数实现结果分页。第二个方法countByUsernameContaining用于统计按条件查询用户列表的总数。

2. 配置JPA和数据源

在Spring Boot项目中,只需要在application.properties文件中配置相关信息即可使用JPA和数据源。下面是一个示例:

spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=password

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

根据实际情况修改以上配置信息。

3. 实现Controller

下面是一个基于Spring MVC的控制器,用于处理用户搜索请求。

@Controller
public class UserController {

  @Autowired
  private UserRepository userRepository;

  @GetMapping("/users")
  public String searchUsers(@RequestParam(value = "username", required = false, defaultValue = "") String username,
                                 @RequestParam(value = "page", required = false, defaultValue = "0") int page,
                                 Model model) {

    Page<User> result = userRepository.findByUsernameContaining(username,
            PageRequest.of(page, 10, Sort.by(Sort.Direction.ASC, "username")));
    model.addAttribute("users", result.getContent());
    model.addAttribute("currentPage", result.getNumber());
    model.addAttribute("totalPages", result.getTotalPages());
    model.addAttribute("totalItems", result.getTotalElements());
    model.addAttribute("keyword", username);

    return "userSearchResult";
  }
}

上述Controller的searchUsers方法会接收两个请求参数,一个是搜索用户的关键字,另一个是页码。然后调用UserRepository的findByUsernameContaining方法按照用户名查询用户,并返回分页结果。

4. 配置视图模板

最后,还需要配置一个视图模板,用于显示用户搜索结果。下面给出一个Thymeleaf的示例模板:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>User Search Result</title>
  <meta charset="UTF-8"/>
</head>
<body>
  <h2>User Search Result</h2>
  <form method="get" th:action="@{/users}">
    <input type="text" th:name="username" th:value="${keyword}"/>
    <button type="submit">Search</button>
  </form>

  <table>
    <thead>
      <tr>
        <th>ID</th>
        <th>Username</th>
        <th>Email</th>
      </tr>
    </thead>
    <tbody>
      <tr th:each="user : ${users}">
        <td th:text="${user.id}"></td>
        <td th:text="${user.username}"></td>
        <td th:text="${user.email}"></td>
      </tr>
    </tbody>
  </table>

  <div>
    <span>Showing ${totalItems} users</span>
    <nav>
      <ul class="pagination">
        <li th:if="${currentPage > 0}">
          <a th:href="@{/users(page=0,keyword=${keyword})}" aria-label="First">
            <span aria-hidden="true">«</span>
          </a>
        </li>
        <li th:if="${currentPage > 0}">
          <a th:href="@{/users(page=${currentPage-1},keyword=${keyword})}" aria-label="Previous">
            <span aria-hidde n="true">‹</span>
          </a>
        </li>
        <li th:each="i : ${#numbers.sequence(0,totalPages-1)}" th:class="${currentPage == i} ? 'active' : '' ">
          <a th:href="@{/users(page=${i},keyword=${keyword})}" th:text="${i+1}">
          </a>
        </li>
        <li th:if="${currentPage < totalPages-1}">
          <a th:href="@{/users(page=${currentPage+1},keyword=${keyword})}" aria-label="Next">
            <span aria-hidde n="true">›</span>
          </a>
        </li>
        <li th:if="${currentPage < totalPages-1}">
          <a th:href="@{/users(page=${totalPages-1},keyword=${keyword})}" aria-label="Last">
            <span aria-hidden="true">»</span>
          </a>
        </li>
      </ul>
    </nav>
  </div>
</body>
</html>

上述Thymeleaf模板中显示了用户搜索结果以及分页导航。需要注意的是,其中涉及到的参数(如关键字、页码等)需要使用th:value,th:href等Thymeleaf属性进行动态渲染。

示例

下面给出两个简单的示例,一个是使用单元测试进行测试,另一个是使用Postman进行测试。

单元测试

下面是一个基于JUnit和Mockito的单元测试,用于测试UserController中的searchUsers方法。

@RunWith(MockitoJUnitRunner.class)
public class UserControllerUnitTest {

  @InjectMocks
  private UserController userController;

  @Mock
  private UserRepository userRepository;

  @Test
  public void should_returnUsers_when_searchUsers_givenKeyword() {
    // given
    List<User> userList = Arrays.asList(
            new User(1L, "Leo", "leo@example.com", "password1"),
            new User(2L, "Tom", "tom@example.com", "password2"));
    Page<User> result = new PageImpl<>(userList);
    when(userRepository.findByUsernameContaining(anyString(), any(Pageable.class)))
            .thenReturn(result);

    // when
    Model model = new ExtendedModelMap();
    String viewName = userController.searchUsers("leo", 0, model);

    // then
    assertEquals("userSearchResult", viewName);
    assertEquals(userList, model.getAttribute("users"));
    assertEquals(0, model.getAttribute("currentPage"));
    assertEquals(1, model.getAttribute("totalPages"));
    assertTrue((Boolean) model.getAttribute("totalPages") > 0);
    assertEquals(userList.size(), model.getAttribute("totalItems"));
    assertEquals("leo", model.getAttribute("keyword"));
  }
}

上述单元测试使用Mockito框架模拟了UserRepository中的findByUsernameContaining方法,并通过JUnit框架对UserController中的searchUsers方法进行代码覆盖率测试。测试结果应该返回包含用户数据的List对象。

Postman测试

另一个更为直观的测试方法是使用Postman进行接口测试。首先需要启动应用程序,然后在Postman中创建一个GET请求,请求地址为http://localhost:8080/users。下面是一个查询Leo用户的示例请求:

GET http://localhost:8080/users?username=Leo

应用程序将会返回包含Leo用户信息的JSON对象,以及分页信息(当前页码、总页数、总记录数):

{
  "users": [
    {
      "id": 1,
      "username": "Leo",
      "email": "leo@example.com",
      "password": "password1"
    }
  ],
  "currentPage": 0,
  "totalPages": 1,
  "totalItems": 1,
  "keyword": "Leo"
}

结论

本文介绍了如何使用Spring MVC和Spring Data JPA实现按条件查询和分页功能。结合Spring Boot的自动配置机制,开发Web应用程序变得更加简单、高效。希望这篇文章能够帮助到你。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring MVC结合Spring Data JPA实现按条件查询和分页 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • ActiveMQ结合Spring收发消息的示例代码

    ActiveMQ是目前非常流行的一种消息中间件,而Spring框架则是目前最为流行的Java企业应用开发框架之一。它们可以结合使用,为我们带来高效可靠的消息传递。 下面,我将详细讲解如何在Spring中使用ActiveMQ进行消息的发送与接收。 环境准备 在开始使用之前,需要先准备好以下环境。 安装ActiveMQ。 创建一个Maven项目,添加Active…

    Java 2023年5月30日
    00
  • 解决因jdk版本引起的TypeNotPresentExceptionProxy异常

    如何解决因jdk版本引起的TypeNotPresentExceptionProxy异常 在Java开发中,有时使用特定的JDK版本可能会导致TypeNotPresentExceptionProxy异常,这是因为类路径上不存在必需的类而引起的。本文将提供解决此问题的完整攻略。 1. 确认异常的具体信息 首先需要确认异常的具体信息,包括异常堆栈和异常提示信息。可…

    Java 2023年5月27日
    00
  • 如何进行Java并发编程?

    下面是关于如何进行Java并发编程的完整使用攻略。 1. 理解Java的并发问题 在开始了解如何进行Java并发编程之前,首先我们需要对Java的并发问题进行了解。Java并发问题主要体现在多线程协同执行的过程中,比如线程间的互斥、同步、等待-通知机制等。 2. Java中的并发编程工具 在Java中处理并发问题常用的工具包括线程、锁、Semaphore等。…

    Java 2023年5月11日
    00
  • jstorm源码解析之bolt异常处理方法

    JStorm 源码解析之 Bolt 异常处理方法 1. 异常处理方法概述 在jstorm运行过程中,可能会出现各种异常情况,对于Bolt组件来说,我们通常采用以下方式进行异常处理: 对于常见的异常,例如空指针等,在代码中直接进行判断和处理; 对于未知异常,可以在Bolt的prepare方法中进行初始化,比如创建日志对象,在execute方法中进行异常处理; …

    Java 2023年5月25日
    00
  • 在IDEA中创建跑得起来的Springboot项目

    让我来详细讲解如何在IntelliJ IDEA中创建跑得起来的Spring Boot项目。 1. 准备工作 在开始创建Spring Boot项目之前,我们需要确保电脑上已经安装好以下两个软件:- JDK 1.8或更高版本- IntelliJ IDEA 2. 创建Spring Boot项目 现在我们来开始创建Spring Boot项目。 2.1 打开Intel…

    Java 2023年5月19日
    00
  • Servlet注解之@WebInitParam多个InitParam的使用

    Servlet注解之@WebInitParam多个InitParam的使用 在Java Web开发中,Servlet是一个非常重要的组件,而注解是Servlet中的一种方便的写法。@WebInitParam是Servlet的注解之一,用于指定初始化参数。在Servlet中,我们可以使用多个@WebInitParam注解,在一次Servlet初始化中指定多个初…

    Java 2023年6月15日
    00
  • 浅谈Java中实现深拷贝的两种方式—clone() & Serialized

    Java中实现对象拷贝通常有两种方式:浅拷贝和深拷贝。浅拷贝只复制原对象中所有基本数据类型的值和引用类型变量的地址,而深拷贝则是在堆中重新开辟空间,将原对象的所有属性都复制到新的对象中去,新的对象与原始对象没有任何关联。本文将讲解Java中实现深拷贝的两种方式:clone()和Serialized。 使用clone()方法实现深拷贝 Java中Object类…

    Java 2023年5月19日
    00
  • Java下载文件时文件名乱码问题解决办法

    关于Java下载文件时出现文件名乱码问题的解决办法,我将提供以下完整攻略: 问题描述 当我们使用Java程序进行文件下载时,有时会出现文件名乱码的问题。这是因为在Http响应头中,如果文件名中含有中文等非英文字符,服务器会使用UTF-8对文件名进行编码,而Java程序默认使用ISO-8859-1来解码文件名,因此就会出现乱码问题。 解决办法 1.获取文件名编…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部