教程

使用 Spring Data Specification 构建 REST 查询语言

1、概览 上一篇文章 介绍了一个基于 JPA Criteria 的查询语言解决方案。 本文将带你了解如何使用 Spring Data JPA 和 Specification 构建一个搜索/过滤 REST API。 2、 User 实体 创建一个 User 实体类,用于检索 API: @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String firstName; private String lastName; private String email; private int age; // get、set 方法 } 3、使用 Specification 进行过滤 来看看如何使用自定义 Spring Data JPA Specification 进行查询。 创建一个实现 Specification 接口的 UserSpecification,并传入自己的约束条件来构建实际查询: public class UserSpecification implements Specification<User> { private SearchCriteria criteria; @Override public Predicate toPredicate (Root<User> root, CriteriaQuery<?

使用 Spring 和 JPA Criteria 构建 REST 查询语言

1、概览 在接下来的一系列文章中,我将带你了解一种用于 REST API 的简单查询语言。 为什么要使用查询语言(Query Language)?因为对于任何足够复杂的 API 来说,仅仅通过简单的字段来搜索/过滤资源是远远不够的。查询语言更加灵活,可以准确过滤选出所需的资源。 2、User 实体 首先,创建一个 User 实体,用于在过滤/搜索 API 中使用: @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String firstName; private String lastName; private String email; private int age; } 3、使用 CriteriaBuilder 过滤 构建查询抽象是一个平衡问题。一方面,需要足够的灵活性,另一方面,需要保持可控的复杂性。高级查询的功能很简单 - 输入一些约束条件,然后得到一些结果。 来看看如何使用: @Repository public class UserDAO implements IUserDAO { @PersistenceContext private EntityManager entityManager; @Override public List<User> searchUser(List<SearchCriteria> params) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<User> query = builder.

Spring Kafka 的 “Trusted Packages” 特性

1、概览 本文将带你了解 Spring Kafka 中的 “Trusted Packages” 功能,了解其背后的动机以及用法。 2、先决条件 一般来说,Spring Kafka 模块允许我们指定一些关于发送的 POJO 的元数据。它通常采用 Kafka Message Header 的形式。 例如,可以这样配置 ProducerFactory: @Bean public ProducerFactory<Object, SomeData> producerFactory() { JsonSerializer<SomeData> jsonSerializer = new JsonSerializer<>(); jsonSerializer.setAddTypeInfo(true); return new DefaultKafkaProducerFactory<>( producerFactoryConfig(), new StringOrBytesSerializer(), jsonSerializer ); } @Data @AllArgsConstructor static class SomeData { private String id; private String type; private String status; private Instant timestamp; } 然后,使用上面用 producerFactory 配置的 KafkaTemplate 在一个 Topic 中生产一条新消息: public void sendDataIntoKafka() { SomeData someData = new SomeData("1", "active", "sent", Instant.

使用 Spring Security OAuth2 实现 SSO 单点登录

1、概览 本文将带你了解如何使用 Spring Security OAuth 和 Spring Boot 以及 Keycloak 作为授权服务器来实现单点登录(SSO)。 我们会使用 4 个不同的应用: 授权服务器 - 中央认证机制 资源服务器 - Foo 资源的提供者 两个客户端应用 - 使用 SSO 的应用 简单地说,当用户试图通过一个客户端应用访问资源时,他们会被重定到授权服务器进行身份认证。Keycloak 会对用户进行登录,在登录第一个应用后,如果使用同一浏览器访问第二个客户端应用,用户无需再次输入凭据。 使用 OAuth2 的授权码(Authorization Code)模式。 Spring Security 将此功能称为 OAuth 2.0 登录,而 Spring Security OAuth 将其称为 SSO。 2、授权服务器 以前,通过 Spring Security OAuth 可以将授权服务器设置为 Spring 应用。 不过,Spring Security OAuth 已被 Spring 弃用,现在可以使用 Keycloak 作为授权服务器。 因此,这次我们在 Spring Boot 应用中把授权服务器设置为嵌入式 Keycloak 服务器。 在 预配置 中,我们将定义两个客户端,即 ssoClient-1 和 ssoClient-2,分别对应每个客户端应用。

使用 Spring Security OAuth2 实现 SSO 单点登录(传统技术栈)

1、概览 本文将带你了解如何使用 Spring Security OAuth 和 Spring Boot 实现单点登录(SSO)。 我们会使用三个不同的应用: 授权服务器 - 中央认证机制 两个客户端应用:使用 SSO 的应用 简单来说,当用户试图访问客户端应用中受保护的页面时,他们会被重定向到过身份认证服务器进行身份验。使用 OAuth2 的 “授权码(Authorization Code)模式”。 注:本文使用的是 Spring OAuth 传统技术。如果你想查看新版 Spring Security 的版本,请参阅《使用 Spring Security OAuth2 实现 SSO 单点登录》。 2、客户端应用 从客户端应用开始。当然,使用 Spring Boot 构建。 2.1、Maven 依赖 在 pom.xml 中加入以下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity4</artifactId> </dependency> 2.2、Security 配置 接下来是最重要的部分,即客户端应用的 Security 配置:

Java 中的 UndeclaredThrowableException 异常

1、概览 本文将带你了解 Java 抛出 UndeclaredThrowableException 异常的原因。 2、UndeclaredThrowableException 从理论上讲,当我们尝试抛出一个未声明的受检异常时,Java 会抛出一个 UndeclaredThrowableException 异常。也就是说,我们没有在 throws 子句中声明受检异常,但却在方法体中抛出了该异常。 受检异常 - 指的是必须要调用者用 try/catch 语句处理或者是再次 throws 出去的异常(即非 RuntimeException 子类)。 有人可能会说这是不可能的,因为 Java 编译器会通过编译错误来防止这种情况发生。 例如,如果我们尝试编译: public void undeclared() { throw new IOException(); } Java 编译器提示的失败信息如下: java: unreported exception java.io.IOException; must be caught or declared to be thrown 尽管在编译时可能不会抛出未声明的受检异常,但在运行时仍有可能发生。 例如,一个运行时代理拦截一个不抛出任何异常的方法: public void save(Object data) { // 省略 } 如果代理本身抛出了受检异常,从调用者的角度来看,save 方法也会抛出受检异常。调用者可能对该代理一无所知,因此会将该异常归咎于 save 方法。 在这种情况下,Java 会将实际已检查异常封装在 UndeclaredThrowableException 中,然后抛出 UndeclaredThrowableException。而 UndeclaredThrowableException 本身就是一个 非受检异常(RuntimeException)。

在 Spring Boot 中将 YAML 转换成对象列表

1、概览 本文将带你了解如何在 YAML 中定义列表,以及如何在 Spring Boot 中把 YAML 列表映射为 Java List 对象。 2、回顾一下 YAML 中的列表 简而言之,YAML 是一种人类可读的数据序列化标准,为编写配置文件提供了一种简洁明了的方法。YAML 的优点在于它支持多种数据类型,如 List、Map 和标量(Scalar)类型。 YAML 列表中的元素使用 - 字符定义,它们的缩进级别相同: yamlconfig: list: - item1 - item2 - item3 - item4 相比之下,在 properties 中定义列表则使用的是索引值: yamlconfig.list[0]=item1 yamlconfig.list[1]=item2 yamlconfig.list[2]=item3 yamlconfig.list[3]=item4 与 properties 文件相比,YAML 的分层性质大大提高了可读性。YAML 的另一个功能是可以为不同的 Spring Profile 定义不同的属性。从 Boot 2.4.0 版开始,properties 文件也可以这样做。 Spring Boot 为 YAML 配置提供了开箱即用的支持。根据设计,Spring Boot 会在启动时从 application.yml 中加载配置属性,无需任何额外工作。 3、将 YAML 列表绑定至简单的 List Spring Boot 提供了 @ConfigurationProperties 注解,以简化将外部配置数据映射到对象模型的逻辑。

在 Spring Boot 中使用 WebSocket 构建在线日志系统

本文将带你了解如何在 Spring Boot 应用中使用 WebSocket 构建一个在线的日志系统。通过该系统,不需要登录服务器,即可在 HTML 页面上通过 WebSocket 长连接预览到服务器的即时日志。 创建 Spring Boot 应用 添加 spring-boot-starter-websocket 依赖。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> WebSocket 配置 创建 WebSocketConfiguration 配置类,配置 ServerEndpointExporter Bean,用于扫描系统中的 WebSocket 端点实现。 package cn.springdoc.demo.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfiguration { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } } 创建日志端点 创建 LoggingChannel WebSocket 端点实现类,接受客户端连接,并且推送日志消息。 package cn.springdoc.demo.web.channel; import java.

Spring Security 和 Apache Shiro

1、概览 在应用开发中,尤其是在企业级 Web 和移动应用领域,安全是一个首要问题。 本文将带你了解、比较两种流行的 Java 安全框架 - Apache Shiro 和 Spring Security。 2、背景 Apache Shiro 诞生于 2004 年,原名 JSecurity,2008 年被 Apache 基金会接受。迄今为止,它已发布了多个版本,最新版本为 1.13.0。 Spring Security 起源于 2003 年的 Acegi,在 2008 年首次公开发布时被纳入 Spring 框架。自诞生以来,它经历了多次迭代,目前的 GA 版本是 6.2.0。 这两种技术都提供身份认证和授权支持,以及加密和 Session 管理解决方案。此外,Spring Security 还提供了一流的保护,防范诸如 CSRF 和会话固定等攻击。 接下来,我们将通过使用 FreeMarker 的 Spring Boot 应用来演示如何使用这两种技术进行身份认证和授权。 3、配置 Apache Shiro 首先,来看看这两种框架的配置有何不同。 3.1、Maven 依赖 添加 shiro-spring-boot-web-starter 和 shiro-core 依赖: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.5.3</version> </dependency> 依赖的最新版本可在 Maven Central 上找到。

Spring 中的 ApplicationContext

1、概览 本文将带你详细了解 Spring 中的 ApplicationContext 接口。 2、ApplicationContext 接口 Spring 框架的主要功能之一是 IoC(控制反转)容器。Spring IoC 容器负责管理应用的对象。它使用依赖注入来实现控制反转。 BeanFactory 和 ApplicationContext 接口,代表 Spring IoC 容器。其中,BeanFactory 是访问 Spring 容器的根接口。它提供了管理 Bean 的基本功能。 而 ApplicationContext 是 BeanFactory 的子接口。因此,它具备 BeanFactory 的所有功能。 此外,它还提供了更多面向企业的特定功能。ApplicationContext 的重要功能包括解析消息、支持国际化、发布事件以及应用层特定的上下文。这就是为什么我们将其作为默认的 Spring 容器使用的原因。 3、Spring Bean 是什么? 在深入了解 ApplicationContext 容器之前,有必要了解一下 Spring Bean。在 Spring 中,Bean 是 Spring 容器实例化、组装和管理的对象。 那么,是否应该将应用的所有对象都配置为 Spring Bean 呢?作为最佳实践,不应该这样做。 一般来说,根据 Spring 文档 所述,应该为服务层对象、数据访问对象 (DAO)、表现对象、基础架构对象(如 Hibernate SessionFactory、JMS Queue 等)定义 Bean。 此外,通常情况下,不应该在容器中配置细粒度的 Domain 对象。创建和加载 Domain 对象通常是 DAO 和业务逻辑的职责。