Spring Data JPA 过滤器搜索示例

在本教程中,您将学习使用 Spring Data JPA、Hibernate、MySQL 和 Thymeleaf 为现有 Spring Boot 应用程序实现过滤/搜索功能。假设我们有一个现有的 Spring Boot 应用程序,它显示如下产品列表:

数据库中可以有很多产品,所以我们想添加搜索功能,帮助用户根据特定关键字轻松找到产品。

本教程中的代码示例基于项目管理器项目,该项目可以从这个Spring Boot CRUD 教程下载。

1.构建搜索查询

我不使用 Criteria API,因为搜索查询是静态的——一个简单的 JPQL 就足够了。更新ProductRepository 接口以声明搜索查询,如下所示:

1
2
3
4
5
6
7
8
public interface ProductRepository extends JpaRepository<Product, Long> {
     
    @Query("SELECT p FROM Product p WHERE p.name LIKE %?1%"
            " OR p.brand LIKE %?1%"
            " OR p.madein LIKE %?1%"
            " OR CONCAT(p.price, '') LIKE %?1%")
    public List<Product> search(String keyword);
}

如您所见,此查询搜索具有与指定关键字匹配的字段之一的产品。包含关键字的任何字段(名称、品牌、制造商或价格)将包含在结果中的产品。

请注意,对于数字字段,我们必须将其与空字符串连接,以便可以使用 LIKE 运算符比较其值:

1
CONCAT(p.price, '')

您可以通过连接所有相关字段来简化搜索查询,如下所示:

1
2
@Query("SELECT p FROM Product p WHERE CONCAT(p.name, p.brand, p.madein, p.price) LIKE %?1%")
public List<Product> search(String keyword);

 

更准确地说,我们应该用空格连接每个字段,以避免字符串连接产生不希望的结果。所以最终的搜索查询将是:

1
@Query("SELECT p FROM Product p WHERE CONCAT(p.name, ' ', p.brand, ' ', p.madein, ' ', p.price) LIKE %?1%")

如您所见,使用这样的搜索查询比使用更适合动态查询的 Criteria API 更易于理解且简单得多。

 

2. 更新 Spring Service 和 Controller 类

接下来,更新ProductService类的listAll()方法以将关键字作为参数,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
public class ProductService {
    @Autowired
    private ProductRepository repo;
     
    public List<Product> listAll(String keyword) {
        if (keyword != null) {
            return repo.search(keyword);
        }
        return repo.findAll();
    }
     
    ...
}

如果关键字为空,则调用存储库接口(由 Spring Data JPA 提供)的默认findAll()方法。

并更新控制器类中的处理程序方法以从 URL 中的参数中读取关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Controller
public class AppController {
    @Autowired
    private ProductService service;
     
    @RequestMapping("/")
    public String viewHomePage(Model model, @Param("keyword") String keyword) {
        List<Product> listProducts = service.listAll(keyword);
        model.addAttribute("listProducts", listProducts);
        model.addAttribute("keyword", keyword);
         
        return "index";
    }
     
    ...
}

如您所见,除了存储在listProducts对象中的搜索结果添加到模型之外,关键字也添加到模型中,因此我们可以在搜索表单中再次显示关键字。

 

3. 带有 Thymeleaf 的代码搜索表单

要在视图页面中添加带有搜索按钮的过滤器文本框,请在index.html文件的顶部添加以下代码:

1
2
3
4
5
6
7
<form th:action="@{/}">
    Filter: <input type="text" name="keyword" id="keyword" size="50" th:value="${keyword}" required />
    &nbsp;
    <input type="submit" value="Search" />
    &nbsp;
    <input type="button" value="Clear" id="btnClear" onclick="clearSearch()" />
</form>

如您所见,我们使用 Thymeleaf 来呈现表单操作和关键字的值。清除按钮允许用户重置搜索表单。还要编写以下 Javascript 代码:

1
2
3
4
5
<script type="text/javascript">
    function clearSearch() {
        window.location = "[[@{/}]]";
    }
</script>

清除搜索将显示所有产品。请注意,我们使用 Thymeleaf 表达式[[@{/}]]来正确呈现主页 URL。

 

4.测试搜索/过滤功能

现在,启动我们的 Spring Boot 应用程序。转到主页并输入电话作为关键字,然后单击搜索按钮。结果将显示如下:

 

因为我们搜索包含关键字的任何字段,所以输入usa将显示所有美国制造的产品:

到目前为止,我已经与您分享了使用 Spring Data JPA、Hibernate、MySQL 和 Thymeleaf 实现过滤/搜索功能或现有 Spring Boot 项目的解决方案。您也可以在下面观看本教程的视频版本,并在附件部分下载示例项目。

附件:
ProductManagerFilterSearch.zip[示例 Spring Boot 项目]73 KB

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot Security是一个非常流行的安全框架,可以帮助开发人员实现各种安全功能。其中,OAuth2和JWT是两个非常重要的安全技术,可以用于实现授权和认证。下面是一个基于Spring Boot Security的完整示例,演示如何使用OAuth2和JWT实现安全功能。 1. 创建一个Spring Boot项目 使用Spring Initializr创建一个新的Spring Boot项目,添加以下依赖: - Spring Web - Spring Security - Spring Data JPA - H2 Database - Spring Security OAuth2 - jjwt 2. 添加配置文件 在application.properties文件中添加以下配置: ``` spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.security.oauth2.client.registration.myapp.client-id=myapp spring.security.oauth2.client.registration.myapp.client-secret=myappsecret spring.security.oauth2.client.registration.myapp.scope=read,write spring.security.oauth2.client.provider.myapp.authorization-uri=http://localhost:8080/oauth/authorize spring.security.oauth2.client.provider.myapp.token-uri=http://localhost:8080/oauth/token spring.security.oauth2.client.provider.myapp.user-info-uri=http://localhost:8080/userinfo spring.security.oauth2.client.provider.myapp.user-name-attribute=name ``` 这些配置将用于配置数据源、Hibernate、H2控制台和OAuth2。 3. 创建实体类和仓库 创建一个User实体类,用于表示用户信息: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; @Column(nullable = false) private String email; // getters and setters } ``` 创建一个UserRepository接口,用于操作User实体类: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } ``` 4. 创建用户服务 创建一个UserService接口,用于定义获取用户和创建用户的方法: ```java public interface UserService { User createUser(String username, String password, String email); Optional<User> getUserByUsername(String username); } ``` 创建一个UserServiceImpl实现UserService接口,用于实现上述方法: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Override public User createUser(String username, String password, String email) { User user = new User(); user.setUsername(username); user.setPassword(passwordEncoder.encode(password)); user.setEmail(email); return userRepository.save(user); } @Override public Optional<User> getUserByUsername(String username) { return userRepository.findByUsername(username); } } ``` 5. 配置Spring Security 创建一个WebSecurityConfig类,用于配置Spring Security: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/oauth/**").permitAll() .anyRequest().authenticated() .and() .csrf().disable() .formLogin().disable() .httpBasic().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 这个配置类将所有请求都需要进行认证,但是允许OAuth2请求。同时,禁用了CSRF、表单登录、HTTP基本认证和会话管理。 6. 配置OAuth2 创建一个OAuth2Config类,用于配置OAuth2: ```java @Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("myapp") .secret(passwordEncoder.encode("myappsecret")) .authorizedGrantTypes("authorization_code", "refresh_token") .scopes("read", "write") .redirectUris("http://localhost:8081/login/oauth2/code/myapp"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .accessTokenConverter(accessTokenConverter()) .pathMapping("/oauth/token", "/signin"); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("secret"); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } } ``` 这个配置类定义了一个OAuth2客户端,将授权码和刷新令牌作为授权类型,并允许读取和写入作用域。同时,定义了一个端点配置,将认证管理器、用户详情服务、访问令牌转换器和令牌存储配置到端点上。 7. 创建控制器 创建一个UserController类,用于处理用户相关的请求: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @PostMapping public User createUser(@RequestBody UserDto userDto) { return userService.createUser(userDto.getUsername(), userDto.getPassword(), userDto.getEmail()); } @GetMapping("/{username}") public User getUser(@PathVariable String username) { return userService.getUserByUsername(username) .orElseThrow(() -> new NotFoundException("User not found: " + username)); } } ``` 这个控制器中定义了创建用户和获取用户的方法。 8. 创建JWT过滤器 创建一个JwtFilter类,用于在请求中验证JWT令牌: ```java public class JwtFilter extends OncePerRequestFilter { private static final String AUTHORIZATION_HEADER = "Authorization"; @Autowired private JwtAccessTokenConverter accessTokenConverter; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); Authentication authentication = accessTokenConverter.extractAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } } ``` 这个过滤器会从请求头中获取JWT令牌,并使用令牌转换器验证令牌。如果验证通过,则将用户认证信息存储到Spring Security上下文中。 9. 注册JWT过滤器 在WebSecurityConfig类中,添加以下配置: ```java @Bean public JwtFilter jwtFilter() { return new JwtFilter(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); // ... } ``` 这个配置将JwtFilter注册到Spring Security过滤器链中。 10. 创建JWT工具类 创建一个JwtUtils类,用于生成和解析JWT令牌: ```java public class JwtUtils { public static final String SUBJECT = "myapp"; public static String generateToken(User user) { Map<String, Object> claims = new HashMap<>(); claims.put("sub", SUBJECT); claims.put("id", user.getId()); claims.put("username", user.getUsername()); claims.put("email", user.getEmail()); Date now = new Date(); Date expiration = new Date(now.getTime() + 60 * 60 * 1000); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS256, "secret") .compact(); } public static Long getUserIdFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey("secret") .parseClaimsJws(token) .getBody(); return claims.get("id", Long.class); } } ``` 这个工具类将用户信息存储到JWT令牌中,并使用HS256算法进行签名。 11. 创建DTO类 创建一个UserDto类,用于接收创建用户的请求: ```java public class UserDto { private String username; private String password; private String email; // getters and setters } ``` 12. 测试 启动应用程序,并使用以下命令创建一个用户: ``` curl -X POST -H 'Content-Type: application/json' -d '{"username":"test","password":"test123","email":"test@example.com"}' http://localhost:8080/users ``` 使用以下命令获取访问令牌: ``` curl -X POST -vu myapp:myappsecret http://localhost:8080/oauth/token -H 'Accept: application/json' -d 'grant_type=authorization_code&code={CODE}&redirect_uri=http://localhost:8081/login/oauth2/code/myapp' ``` 将{CODE}替换为授权码,并将返回的访问令牌用于获取用户信息: ``` curl -H 'Authorization: Bearer {ACCESS_TOKEN}' http://localhost:8080/users/test ``` 将{ACCESS_TOKEN}替换为访问令牌,在请求头中发送即可。 以上就是一个完整的Spring Boot Security OAuth2 JWT示例,演示了如何实现授权和认证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值