下面是“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技术站