Java

使用 Bouncy Castle 签署 CSR

1、概览 签署(也叫做签发)证书签名请求(CSR)是密码学中的一项常见操作。本文将带你了解如何使用 Bouncy Castle 签署 CSR。 2、签署 CSR 签署 CSR 是证书颁发机构(CA)验证 CSR 中的信息并颁发证书的过程。CA 使用其私钥签署证书。签名后的证书可在客户端和服务器之间建立安全连接。 要使用 Bouncy Castle 签署 CSR,需要执行几个基本步骤: 生成可信实体 CA 证书和私钥。 生成证书签名请求(CSR)。 使用 CA 证书和私钥签署 CSR。 3、设置 首先,需要在 pom.xml 中添加 Bouncy Castle 依赖: <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> <version>1.76</version> </dependency> 接下来,需要创建一个 SecurityProvider 类来注册 Bouncy Castle Provider: static { Security.addProvider(new BouncyCastleProvider()); } 4、使用 Bouncy Castle 签署 CSR 使用 Bouncy Castle 签署 CSR 需要几个步骤。 4.1、生成可信实体 CA 证书和私钥 CA 是向客户签发证书的可信实体。我们必须生成 CA 证书和私钥来签署 CSR。 先生成一个密钥对:

Java 中 interface 和 @interface

1、概览 本文将带你了解 Java 中 interface(接口)和 @interface(注解接口)的区别以及它们的应用。 interface是一个类实现的规范。在最常见的形式中,它是一组相关方法,这些方法没有具体的实现。 而 @interface 则允许你在代码中添加元数据。编译器、工具或框架使用这些元数据来影响类的行为或处理过程。 2、interface interface 是一种规范。它规定了实现类必须实现的行为,但没有规定如何实现。它表明,任何实现接口的类都必须为接口的所有方法提供具体的实现。 public interface Animal { String eat(); String sleep(); } public class Dog implements Animal { @Override public String eat() { return "Dog is eating"; } @Override public String sleep() { return "Dog is sleeping"; } } 接口的所有方法都是默认 public 和 abstract 的(default 方法和 static 方法除外),所有字段都是 public、static 和 final 的。在 Java 中,我们可以使用接口实现抽象、多重继承和松散耦合。 抽象:接口只定义了调用方法所需的基本信息,而实现方法的复杂性则被隐藏起来。 多重继承:一个类可以实现多个接口,从而避免了在允许类多重继承的语言中可能出现的 “菱形继承” 问题。 松耦合:接口在功能和实现细节之间提供了明显的分离。由于我们对方法和签名进行了单独定义,它使一个类可以改变其内部流程,而不影响其用户。 3、@interface 在Java中,我们使用 @interface 来声明注解类型。注解提供了一种向 Java 代码元素(如类、方法和字段)添加元数据的方式。因此,工具和库可以利用这些元数据在编译过程或运行时收集信息,以进行代码处理。

使用 Stream API 处理 JDBC ResultSet

1、概览 通常,我们使用遍历从 JDBC ResultSet 中迭代检索到的数据,不过在某些情况下,我更喜欢用 record Stream。 本文将带你了解使用 Stream API 处理 JDBC 结果集的几种方法。 2、使用 Spliterators 首先是纯 JDK 方法,使用 Spliterators 创建流。 首先,为实体定义一个 Model: public record CityRecord(String city, String country) { } 在 CityRecord 中,我们存储了有关 city(城市)及其 country(国家)的信息。 接下来,创建一个能与数据库交互并返回 Stream<CityRecord> 的 Repository: public class JDBCStreamAPIRepository { private static final String QUERY = "SELECT name, country FROM cities"; private final Logger logger = LoggerFactory.getLogger(JDBCStreamAPIRepository.class); public Stream<CityRecord> getCitiesStreamUsingSpliterator(Connection connection) throws SQLException { PreparedStatement preparedStatement = connection.

Java JMS 读写 IBM MQ 队列

1、简介 本文将会带你了解如何使用 Java JMS(Java Message Service)从 IBM MQ 队列读写消息。 2、设置环境 我们可以在 Docker 容器中运行 IBM MQ,以避免手动安装和配置的复杂性。 使用以下命令以基本配置运行容器: docker run -d --name my-mq -e LICENSE=accept -e MQ_QMGR_NAME=QM1 MQ_QUEUE_NAME=QUEUE1 -p 1414:1414 -p 9443:9443 ibmcom/mq 接下来,需要在 pom.xml 文件中添加 IBM MQ 客户端: <dependency> <groupId>com.ibm.mq</groupId> <artifactId>com.ibm.mq.allclient</artifactId> <version>9.4.0.0</version> </dependency> 3、配置 JMS Connection 首先,我们需要用 QueueConnectionFactory 建立 JMS Connection(连接),用于创建与队列管理器(Queue Manager)的连接: public class JMSSetup { public QueueConnectionFactory createConnectionFactory() throws JMSException { MQQueueConnectionFactory factory = new MQQueueConnectionFactory(); factory.setHostName("localhost"); factory.setPort(1414); factory.setQueueManager("QM1"); factory.setChannel("SYSTEM.DEF.SVRCONN"); return factory; } } 首先创建一个 MQQueueConnectionFactory 实例,用于配置和创建与 IBM MQ 服务器的连接。我们将主机名设置为 localhost,因为 MQ 服务器是在本地 Docker 容器内运行的。暴露的映射端口为 1414。

NetBeans Profiler 的编程式用法

1、概览 对应用程序进行分析可以深入了解其运行时的行为。Java 生态系统中有多种流行的分析器(Profiler),如用于通用分析的 NetBeans Profiler、JProfiler 和 VisualVM。 本文将带你了解如何以编程方式使用 NetBeans profiler API。 2、NetBeans Profiler NetBeans IDE 提供免费的分析器来分析 Java 应用。它通过 IDE 中直观的嵌入式用户界面,提供了评估 CPU 性能和内存使用情况的功能。 然而,NetBeans Profiler 还提供了可用于编程式的分析 API。这可用于 Heap Dump 的自动化分析,而不需要依赖于 UI 界面。 Heap Dump(堆转储)是一段时间内应用的内存快照。它是深入了解内存使用情况的良好指标,因为它包括内存中的实时对象、对象的类和字段以及对象之间的引用。 3、示例项目 要使用 NetBeans Profiler API,首先在 pom.xml 中添加 依赖: <dependency> <groupId>org.netbeans.modules</groupId> <artifactId>org-netbeans-lib-profiler</artifactId> <version>RELEASE220</version> </dependency> 该依赖提供了 JavaClasses 和 Instances 等各种工具类,以帮助我们分析类、创建的实例数量和使用的内存。 接着,创建一个简单的项目并分析它的 Heap Dump: class SolarSystem { private static final Logger LOGGER = Logger.getLogger(SolarSystem.class.getName()); private int id; private String name; private List<String> planet = new ArrayList<>(); // 构造函数 public void logSolarSystem() { LOGGER.

Java 反射中的 AccessFlag(访问标志)

1、概览 Java 中的反射是一个强大的功能,它允许我们操纵不同的成员,如类、接口、字段和方法。此外,使用反射,我们可以在编译时实例化类、调用方法和访问字段,而无需知道类型。 本文将带你了解如何使用 JVM AccessFlag(访问标志),以及 Modifier 和 AccessFlag 之间的区别。 2、JVM AccessFlag Java 虚拟机规范 定义了 JVM 中已编译类的结构,它由一个 ClassFile 组成: ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } 除其他项目外,ClassFile 还包含 access_flags 项。简而言之,access_flags 是一个掩码,由定义类的访问权限和其他属性的各种标志组成。 此外,ClassFile 还包括 field_info 和 method_info 项,每个项都包含其 access_flags 项。 Javassist 和 ASM 等库使用 JVM AccessFlag 来操作 Java 字节码。

在 Java Servlet 中读取、解析 POST 请求数据

1、简介 Java Servlet 是一个服务端组件,用于处理客户端传入的 HTTP 请求,通常我们需要通过 Servlet 中的 HttpServletRequest 对象来获取到客户端提交的请求数据。 本文将带你了解在 Java Servlet 中读取 Payload(即请求体)数据的各种方法,以及最佳实践和注意事项。 2、理解 Request Payload Post 请求主要用于通过 HTTP 请求向服务器发送数据。这些数据可以是任何内容,从包含用户输入的表单数据到结构化数据如 JSON 和 XML,甚至是二进制文件。这些数据位于请求体中,与 URL 分开。这样可以实现更广泛和安全的数据传输。我们可以通过请求中的 Content-Type Header 标识不同类型的数据。 常见的 Content-Type 包括: application/x-www-form-urlencoded:用于以键值对形式编码的表单数据 application/json:用于 JSON 格式的数据 application/xml:用于 XML 格式的数据 text/plain:用于发送纯文本 multipart/form-data:用于上传二进制文件和常规表单数据(form data) 3、读取 Post 请求体的方式 接下来,让我们看看从 POST Payload 中提取数据的不同方法。 3.1、使用 getParameter() 获取 URL 编码的表单数据 我们可以使用 HttpServletRequest 接口提供的 getParameter() 方法,使用通过 POST 请求提交的参数名检索特定表单数据。该方法使用表单参数名作为参数,并以字符串(String)形式返回相应的值。 举个例子: @WebServlet(name = "FormDataServlet", urlPatterns = "/form-data") public class FormDataServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { String firstName = StringEscapeUtils.

在 JDBC PreparedStatement 中使用 IN 语句

1、简介 在数据库 SQL 查询中,我们经常使用 IN 语句来一次性检索匹配多个值的记录,本文将带你了解如何在 JDBC PreparedStatement 中使用 IN 子句。 2、设置 创建一个 CUSTOMER 表,并添加一些记录,以便使用 IN 子句进行查询: void populateDB() throws SQLException { String createTable = "CREATE TABLE CUSTOMER (id INT, first_name VARCHAR(50), last_name VARCHAR(50))"; connection.createStatement().execute(createTable); String load = "INSERT INTO CUSTOMER (id, first_name, last_name) VALUES(?,?,?)"; IntStream.rangeClosed(1, 100) .forEach(i -> { PreparedStatement preparedStatement1 = null; try { preparedStatement1 = connection.prepareStatement(load); preparedStatement1.setInt(1, i); preparedStatement1.setString(2, "firstname" + i); preparedStatement1.setString(3, "lastname" + i); preparedStatement1.execute(); } catch (SQLException e) { throw new RuntimeException(e); } }); } 3、PreparedStatement PreparedStatement 表示一个已经预编译的 SQL 语句,可以高效地多次使用,每次使用可以填充不同的参数。

包含所有 HTTP 状态码的 Java 枚举

1、简介 Enum(枚举)提供了一种在 Java 编程语言中定义一组命名常量的强大方法。这些常量可用于表示相关值的固定集合,例如 HTTP 状态码。总所周知,互联网上的所有 Web 服务器都会响应 HTTP 状态码作为标准响应码。 本文将带你了解如何创建一个包含所有 HTTP 状态码的 Java 枚举。 2、了解 HTTP 状态码 HTTP 状态码在 Wweb 通信中起着至关重要的作用,它能告知客户端其请求的结果。这些代码分为五类,每一类在 HTTP 协议中都有特定的功能。 3、HTTP 状态码使用枚举的好处 在 Java 中枚举 HTTP 状态码有几个优点,包括: 类型安全:使用 Enum 枚举可确保类型安全,使代码更具可读性和可维护性 分组常量:Enum 枚举将相关常量组合在一起,以清晰和结构化的方式处理固定值集合 避免硬编码:将 HTTP 状态码定义为枚举,有助于防止硬编码字符串或整数造成的错误 增强清晰度和可维护性:这种方法通过增强清晰度、减少错误和提高代码的可维护性,促进软件开发的最佳实践 4、基本做法 为了在 Java 应用中有效管理 HTTP 状态码,我们可以定义一个枚举来封装所有标准 HTTP 状态码及其描述。 这种方法可以让我们充分利用枚举类型安全和代码清晰的优势。 定义 HttpStatus 枚举: public enum HttpStatus { CONTINUE(100, "Continue"), SWITCHING_PROTOCOLS(101, "Switching Protocols"), OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), MULTIPLE_CHOICES(300, "Multiple Choices"), MOVED_PERMANENTLY(301, "Moved Permanently"), FOUND(302, "Found"), BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), FORBIDDEN(403, "Forbidden"), NOT_FOUND(404, "Not Found"), INTERNAL_SERVER_ERROR(500, "Internal Server Error"), NOT_IMPLEMENTED(501, "Not Implemented"), BAD_GATEWAY(502, "Bad Gateway"), UNKNOWN(-1, "Unknown Status"); private final int code; private final String description; HttpStatus(int code, String description) { this.

Java 中的 Class.cast() 方法和 Cast(转换)操作符

1、简介 Java 中的转换(“Cast”)是一个基本概念,它允许将一种数据类型转换为另一种数据类型。它是在程序中有效操作对象和变量的关键过程。在现实世界中,“Cast” 类似于将一种单位的度量值转换为另一种单位的度量值,例如将英寸转换为厘米。 在 Java 的多态(Polymorphism)中,当超类引用子类的对象时,经常会使用到转换。例如,我们需要访问子类的特定方法或属性,就需要依靠转换来实现。这一点非常重要,因为 Java 是一种强类型语言,变量具有特定的数据类型。 本文将带你了解 Java Class.cast() 方法和 Cast(强转)操作符两个选项用法和差别,以及每个选项的最佳实践。 2、定义用例 以一个视频游戏角色的层次结构为例。 创建一个包含了超类 Character(角色)和子类 Warrior(战士)、Commander(指挥官)的示例。 该用例涉及创建 Warrior 和 Commander 的实例。这些实例存储在 Character 对象类型的集合中。之后,它们会被检索并转换回各自的特定类型。这种转换允许调用特定子类的方法。 3、定义 Model 类 首先,定义第一个继承自 Character 的子类,即实现了 obeyCommand() 方法的 Warrior: public class Warrior extends Character { public void obeyCommand(String command) { logger.info("Warrior {} obeys a command {}", this.getName(), command); } } 然后,创建 Character 的第二个子类,即 Commander。这个子类实现了一个 issueCommand() 方法,可以向战士们发布命令: public class Commander extends Character { public void issueCommand(String command) { log.