Java 中文官方教程 2022 版(四十二)(2)

简介: Java 中文官方教程 2022 版(四十二)

Java 中文官方教程 2022 版(四十二)(1)https://developer.aliyun.com/article/1488227

将签名和公钥保存在文件中

原文:docs.oracle.com/javase/tutorial/security/apisign/step4.html

现在您已经为某些数据生成了签名,您需要将签名字节保存在一个文件中,将公钥字节保存在另一个文件中,这样您就可以通过调制解调器、软盘、邮件等方式将其发送给其他人。

  • 生成签名的数据,
  • 签名,
  • 公钥

接收方可以通过运行您将在接下来的验证数字签名步骤中生成的VerSig程序来验证数据是否来自您,并且在传输过程中没有被修改。该程序使用公钥来验证接收到的签名是否是接收到的数据的真实签名。

回想一下,签名是放在一个名为realSig的字节数组中的。您可以通过以下方式将签名字节保存在名为sig的文件中。

/* save the signature in a file */
FileOutputStream sigfos = new FileOutputStream("sig");
sigfos.write(realSig);
sigfos.close();

从生成公钥和私钥步骤中回想一下,公钥是放在一个名为pub的 PublicKey 对象中的。您可以通过调用getEncoded方法获取编码后的密钥字节,然后将编码后的字节存储在一个文件中。您可以随意命名文件。例如,如果您的名字是 Susan,您可以将其命名为suepk(代表"Sue 的公钥"),如下所示:

/* save the public key in a file */
byte[] key = pub.getEncoded();
FileOutputStream keyfos = new FileOutputStream("suepk");
keyfos.write(key);
keyfos.close();

编译并运行程序

原文:docs.oracle.com/javase/tutorial/security/apisign/step5.html

这里GenSig.java程序的完整源代码,添加了一些注释。编译并运行它。请记住,您需要指定要签名的文件名,如

java GenSig data

您可以下载并使用名为data的示例文件或您喜欢的任何其他文件。该文件不会被修改。它将被读取,以便为其生成签名。

执行程序后,您应该看到保存的suepk(公钥)和sig(签名)文件。

验证数字签名

原文:docs.oracle.com/javase/tutorial/security/apisign/versig.html

如果您有生成数字签名的数据,您可以验证签名的真实性。为此,您需要

  • 数据
  • 签名
  • 用于签署数据的私钥对应的公钥

在这个例子中,您编写一个VerSig程序来验证由GenSig程序生成的签名。这演示了验证据称签名真实性所需的步骤。

VerSig导入一个公钥和一个据称是指定数据文件签名的签名,然后验证签名的真实性。公钥、签名和数据文件名在命令行中指定。

创建VerSig示例程序以导入文件并验证签名的步骤如下。

  1. 准备初始程序结构
    创建一个名为VerSig.java的文本文件。输入初始程序结构(导入语句、类名、main方法等)。
  2. 输入并转换编码的公钥字节
    从指定为第一个命令行参数的文件中导入编码的公钥字节,并将其转换为PublicKey
  3. 输入签名字节
    从指定为第二个命令行参数的文件中输入签名字节。
  4. 验证签名
    获取一个Signature对象并用于验证签名的公钥进行初始化。提供要验证签名的数据(来自指定为第三个命令行参数的文件),并验证签名。
  5. 编译和运行程序

准备初始程序结构

原文:docs.oracle.com/javase/tutorial/security/apisign/vstep1.html

这是在本课程后续部分创建的VerSig程序的基本结构。将此程序结构放在名为VerSig.java的文件中。

import java.io.*;
import java.security.*;
import java.security.spec.*;
class VerSig {
    public static void main(String[] args) {
        /* Verify a DSA signature */
        if (args.length != 3) {
            System.out.println("Usage: VerSig " +
                "publickeyfile signaturefile " + "datafile");
        }
        else try {
        // the rest of the code goes here
        } catch (Exception e) {
            System.err.println("Caught exception " + e.toString());
        }
    }
}

注意:

  • 用于验证数据的方法位于java.security包中,因此程序从该包中导入所有内容。程序还从java.io包中导入所需的用于输入要签名的文件数据的方法,以及从java.security.spec包中导入包含X509EncodedKeySpec类的内容。
  • 期望有三个参数,分别指定公钥、签名和数据文件。
  • 在本课程后续步骤中编写的代码将放在trycatch块之间。

输入并转换编码的公钥字节

原文:docs.oracle.com/javase/tutorial/security/apisign/vstep2.html

接下来,VerSig需要从指定为第一个命令行参数的文件中导入编码的公钥字节,并将其转换为PublicKey。需要一个PublicKey,因为SignatureinitVerify方法需要它来初始化用于验证的Signature对象。

首先,读取编码的公钥字节。

FileInputStream keyfis = new FileInputStream(args[0]);
byte[] encKey = new byte[keyfis.available()];  
keyfis.read(encKey);
keyfis.close();

现在字节数组encKey包含了编码的公钥字节。

你可以使用KeyFactory类来实例化一个 DSA 公钥,从其编码中。KeyFactory类提供了不透明密钥(类型为Key)和密钥规范之间的转换,密钥规范是底层密钥材料的透明表示。通过不透明密钥,你可以获取算法名称、格式名称和编码的密钥字节,但不能获取密钥材料,例如,可能包括密钥本身和用于计算密钥的算法参数。 (请注意,PublicKey,因为它扩展了Key,本身也是一个Key。)

所以,首先你需要一个密钥规范。假设密钥是根据 X.509 标准编码的,你可以通过以下方式获取一个,例如,如果密钥是使用 SUN 提供的内置 DSA 密钥对生成器生成的:

X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);

现在你需要一个KeyFactory对象来进行转换。该对象必须是一个可以处理 DSA 密钥的对象。

KeyFactory keyFactory = KeyFactory.getInstance("DSA", "SUN");

最后,你可以使用KeyFactory对象从密钥规范生成一个PublicKey

PublicKey pubKey =
    keyFactory.generatePublic(pubKeySpec);

输入签名字节

原文:docs.oracle.com/javase/tutorial/security/apisign/vstep3.html

下一步,输入作为第二个命令行参数指定的文件中的签名字节。

FileInputStream sigfis = new FileInputStream(args[1]);
byte[] sigToVerify = new byte[sigfis.available()]; 
sigfis.read(sigToVerify);
sigfis.close();

现在字节数组sigToVerify包含了签名字节。

验证签名

原文:docs.oracle.com/javase/tutorial/security/apisign/vstep4.html

您已经向VerSig程序添加了代码

  • 输入编码的密钥字节并将其转换为名为pubKeyPublicKey
  • 将签名字节输入到名为sigToVerify的字节数组中

您现在可以继续进行验证。

初始化用于验证的 Signature 对象

与生成签名一样,签名是通过使用Signature类的实例来验证的。您需要创建一个使用与生成签名相同的签名算法的Signature对象。GenSig程序使用的算法是来自 SUN 提供程序的 SHA1withDSA 算法。

Signature sig = Signature.getInstance("SHA1withDSA", "SUN");

接下来,您需要初始化Signature对象。验证的初始化方法需要公钥。

sig.initVerify(pubKey);

向签名对象提供要验证的数据 现在,您需要向Signature对象提供生成签名的数据。这些数据位于以第三个命令行参数指定的文件中。与签名时一样,逐个缓冲区读取数据,并通过调用update方法将其提供给Signature对象。

FileInputStream datafis = new FileInputStream(args[2]);
BufferedInputStream bufin = new BufferedInputStream(datafis);
byte[] buffer = new byte[1024];
int len;
while (bufin.available() != 0) {
    len = bufin.read(buffer);
    sig.update(buffer, 0, len);
};
bufin.close();

验证签名

一旦您向Signature对象提供了所有数据,您可以验证该数据的数字签名并报告结果。请记住,所谓的签名已读入名为sigToVerify的字节数组。

boolean verifies = sig.verify(sigToVerify);
System.out.println("signature verifies: " + verifies);

如果所谓的签名(sigToVerify)是由与公钥pubKey对应的私钥生成的指定数据文件的实际签名,则verifies值将为true

编译并运行程序

原文:docs.oracle.com/javase/tutorial/security/apisign/vstep5.html

这里VerSig.java程序的完整源代码,附加了一些注释。

编译并运行程序。请记住,您需要在命令行上指定三个参数:

  • 包含编码的公钥字节的文件的名称
  • 包含签名字节的文件的名称
  • 数据文件的名称(生成签名的文件)

由于您将测试GenSig程序的输出,您应该使用的文件名是

  • suepk
  • sig
  • data

这是一个示例运行;粗体表示您需要键入的内容。

%java VerSig suepk sig data
signature verifies: true

弱点和替代方案

原文:docs.oracle.com/javase/tutorial/security/apisign/enhancements.html

本课程中的GenSigVerSig程序演示了使用 JDK 安全 API 生成数据的数字签名以及验证签名的用法。然而,这些程序描绘的实际场景,即发送方使用 JDK 安全 API 生成新的公钥/私钥对,发送方将编码的公钥字节存储在文件中,接收方读取密钥字节,这并不一定是现实的,并且存在一个潜在的重大缺陷。

在许多情况下,密钥不需要生成;它们已经存在,要么作为文件中的编码密钥,要么作为密钥库中的条目。

潜在的重大缺陷在于没有任何保证接收方收到的公钥的真实性,而VerSig程序只有在提供的公钥本身是真实的情况下才能正确验证签名的真实性!

使用编码的密钥字节

有时,编码的密钥字节已经存在于用于签名和验证的密钥对的文件中。如果是这种情况,GenSig程序可以导入编码的私钥字节,并将其转换为签名所需的PrivateKey,通过以下方式,假设包含私钥字节的文件名在privkeyfile字符串中,并且字节代表已使用 PKCS #8 标准编码的 DSA 密钥。

FileInputStream keyfis = new FileInputStream(privkeyfile);
byte[] encKey = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);

GenSig不再需要将公钥字节保存在文件中,因为它们已经在一个文件中。

在这种情况下,发送方发送接收方

  • 包含编码的公钥字节的已存在文件(除非接收方已经拥有此文件)和
  • GenSig导出的数据文件和签名文件。

VerSig程序保持不变,因为它已经期望文件中存在编码的公钥字节。

但是,如果有恶意用户拦截文件并以一种无法检测到其更换的方式替换它们,会出现什么潜在问题呢?在某些情况下,这不是问题,因为人们已经通过面对面或通过信任的第三方进行了公钥交换。之后,可以远程进行多次文件和签名交换(即在不同位置的两个人之间),并且可以使用公钥来验证其真实性。如果有恶意用户尝试更改数据或签名,这将被VerSig检测到。

如果无法进行面对面的密钥交换,您可以尝试其他方法来增加正确接收的可能性。例如,您可以在随后的数据和签名文件交换之前,通过尽可能安全的方法发送您的公钥,也许使用不太安全的媒介。

一般来说,将数据和签名与你的公钥分开发送大大降低了攻击的可能性。除非所有三个文件都被更改,并且以下一段讨论的特定方式,否则VerSig将检测到任何篡改。

如果所有三个文件(数据文档、公钥和签名)被恶意用户拦截,那个人可以用私钥替换文档并签名,然后将替换后的文档、新签名和用于生成新签名的私钥对应的公钥转发给你。然后VerSig会报告验证成功,你会认为文档来自原始发送者。因此,你应该采取措施确保至少公钥完整接收(VerSig检测到其他文件的任何篡改),或者可以使用证书来促进公钥的认证,如下一节所述。

使用证书

在密码学中,更常见的是交换包含公钥的证书,而不是公钥本身。

一个好处是,证书由一个实体(颁发者)签名,以验证所包含的公钥是另一个实体(主体所有者)的实际公钥。通常,一个受信任的第三方认证机构(CA)验证主体的身份,然后通过签署证书来担保其为公钥所有者。

使用证书的另一个好处是,你可以通过使用颁发者(签名者)的公钥验证其数字签名来检查你收到的证书的有效性,该公钥本身可能存储在一个证书中,其签名可以通过使用该证书颁发者的公钥验证;该公钥本身可能存储在一个证书中,依此类推,直到达到你已经信任的公钥。

如果你无法建立信任链(也许因为所需的颁发者证书对你不可用),可以计算证书的指纹。每个指纹是一个相对较短的数字,可以唯一可靠地识别证书。(从技术上讲,它是证书信息的哈希值,使用消息摘要,也称为单向哈希函数。)你可以联系证书所有者,比较你收到的证书的指纹与发送的指纹。如果它们相同,证书也相同。

对于GenSig来说,更安全的做法是创建包含公钥的证书,然后让VerSig导入证书并提取公钥。然而,JDK 没有公共证书 API,允许你从公钥创建证书,因此GenSig程序无法从生成的公钥创建证书。(尽管有从证书中提取公钥的公共 API。)

如果您愿意,您可以使用各种安全工具,而不是 API,对您的重要文档进行签名,并与密钥库中的证书一起使用,就像在文件交换课程中所做的那样。

或者,您可以使用 API 修改您的程序以使用来自密钥库的已存在私钥和相应的公钥(在证书中)。首先,修改GenSig程序以从密钥库中提取私钥而不是生成新密钥。首先,让我们假设以下内容:

  • 密钥库名称在String``ksName
  • 密钥库类型为"JKS",这是来自 Oracle 的专有类型。
  • 密钥库密码在字符数组spass
  • 包含私钥和公钥证书的密钥库条目的别名在String``alias
  • 私钥密码在字符数组kpass

然后,您可以通过以下方式从密钥库中提取私钥。

KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream ksfis = new FileInputStream(ksName); 
BufferedInputStream ksbufin = new BufferedInputStream(ksfis);
ks.load(ksbufin, spass);
PrivateKey priv = (PrivateKey) ks.getKey(alias, kpass);

您可以从密钥库中提取公钥证书,并将其编码字节保存到名为suecert的文件中,通过以下方式。

java.security.cert.Certificate cert = ks.getCertificate(alias);
byte[] encodedCert = cert.getEncoded();
// Save the certificate in a file named "suecert" 
FileOutputStream certfos = new FileOutputStream("suecert");
certfos.write(encodedCert);
certfos.close();

然后,您将数据文件、签名和证书发送给接收者。接收者通过首先使用keytool -printcert命令获取证书的指纹来验证证书的真实性。

keytool -printcert -file suecert
Owner: CN=Susan Jones, OU=Purchasing, O=ABC, L=Cupertino, ST=CA, C=US
Issuer: CN=Susan Jones, OU=Purchasing, O=ABC, L=Cupertino, ST=CA, C=US
Serial number: 35aaed17
Valid from: Mon Jul 13 22:31:03 PDT 1998 until:
Sun Oct 11 22:31:03 PDT 1998
Certificate fingerprints:
MD5:  1E:B8:04:59:86:7A:78:6B:40:AC:64:89:2C:0F:DD:13
SHA1: 1C:79:BD:26:A1:34:C0:0A:30:63:11:6A:F2:B9:67:DF:E5:8D:7B:5E

然后接收者验证指纹,可能通过给发送者打电话并将其与发送者的证书进行比较,或者通过在公共存储库中查找它们来进行验证。

接收者的验证程序(修改后的VerSig)然后可以通过以下方式导入证书并从中提取公钥,假设证书文件名(例如,suecert)在String``certName中。

FileInputStream certfis = new FileInputStream(certName);
java.security.cert.CertificateFactory cf =
    java.security.cert.CertificateFactory.getInstance("X.509");
java.security.cert.Certificate cert =  cf.generateCertificate(certfis);
PublicKey pub = cert.getPublicKey();

确保数据机密性

假设您希望保持数据的内容机密性,以便在传输过程中(或在您自己的计算机或磁盘上)无意或恶意尝试查看数据的人无法这样做。为了保持数据的机密性,您应该对其进行加密,仅存储和发送加密结果(称为ciphertext)。接收者可以解密密文以获得原始数据的副本。

课程:实现您自己的权限

原文:docs.oracle.com/javase/tutorial/security/userperm/index.html

本课程演示了如何编写一个定义自己特殊权限的类。本课程的基本组件包括:

  1. 一个名为ExampleGame的示例游戏。
  2. 一个名为HighScore的类,被ExampleGame用来存储用户最新的高分。
  3. 一个名为HighScorePermission的类,用于保护对用户存储的高分值的访问。
  4. 用户的安全策略文件,授予ExampleGame更新他/她的高分的权限。

基本场景如下:

  1. 用户玩ExampleGame
  2. 如果用户达到新的高分,ExampleGame使用HighScore类来保存这个新值。
  3. HighScore类查看用户的安全策略,以检查ExampleGame是否有权限更新用户的高分值。
  4. 如果ExampleGame有权限更新高分,则 HighScore 类更新该值。

我们描述每个基本组件的关键点,然后展示一个示例运行:

  • ExampleGame
  • 高分类
  • 高分权限类
  • 一个示例策略文件
  • 将所有内容整合在一起

ExampleGame

原文:docs.oracle.com/javase/tutorial/security/userperm/game.html

下面是ExampleGame的源代码。为简单起见,ExampleGame实际上并不包含玩游戏的代码。它只是检索或更新用户的最高分。

要查看用户当前的最高分值,您可以运行:

java ExampleGame get

要为用户设置新的最高分值,您可以运行:

java ExampleGame set *score* 

要检索用户当前的最高分,ExampleGame只需实例化一个HighScore对象并调用其getHighScore方法。要为用户设置新的最高分,ExampleGame实例化一个HighScore对象并调用setHighScore,将用户的新最高分传递给它。

这里是ExampleGame的源代码,ExampleGame.java:

package com.gamedev.games;
import java.io.*;
import java.security.*;
import java.util.Hashtable;
import com.scoredev.scores.*;
public class ExampleGame
{
    public static void main(String args[])
  throws Exception 
    {
  HighScore hs = new HighScore("ExampleGame");
  if (args.length == 0)
      usage();
  if (args[0].equals("set")) {
      hs.setHighScore(Integer.parseInt(args[1]));
  } else if (args[0].equals("get")) {
      System.out.println("score = "+ hs.getHighScore());
  } else {
      usage();
  }
    }
    public static void usage()
    {
  System.out.println("ExampleGame get");
  System.out.println("ExampleGame set <score>");
  System.exit(1);
    }
}

高分类

原文:docs.oracle.com/javase/tutorial/security/userperm/highscore.html

HighScore类存储并保护用户在ExampleGame(以及调用它的任何其他游戏)中的高分值的访问。为简单起见,该类将高分值保存到名为.highscore的文件中,该文件位于用户的主目录中。但是,在允许ExampleGame检索或更新用户的高分值之前,该类会检查用户是否已在其安全策略文件中授予ExampleGame访问高分的权限。

检查ExampleGame是否具有HighScorePermission

要检查ExampleGame是否具有访问用户高分值的权限,HighScore类必须:

  1. 调用System.getSecurityManager()以获取当前安装的安全管理器。
  2. 如果结果不为空(也就是说,存在一个安全管理器,而不是调用者是一个无限制的应用程序),那么
  1. 构造一个HighScorePermission对象,并
  2. 调用安全管理器的checkPermission方法,并传递新构造的HighScorePermission对象。

这是代码:

SecurityManager sm = System.getSecurityManager();
if (sm != null) {
    sm.checkPermission(
        new HighScorePermission(gameName));
}

checkPermission方法本质上是询问安全管理器是否ExampleGame具有指定的HighScorePermission。换句话说,它询问安全管理器是否ExampleGame有权限更新指定游戏(ExampleGame)的用户高分值。底层安全框架将查阅用户的安全策略,以查看ExampleGame是否确实具有此权限。

高分代码

这里HighScore类的完整源代码。

注意:doPrivileged方法调用用于使HighScore能够临时访问对其可用但对调用它的代码(ExampleGame)不可用的资源。例如,预期策略文件将授予HighScore访问用户主目录中的.highscore文件的权限,但不会授予这些权限给游戏,如ExampleGame

HighScorePermission 类

原文:docs.oracle.com/javase/tutorial/security/userperm/perm.html

HighScorePermission 类定义了 ExampleGame 需要更新用户高分的权限。

所有权限类都应该从 java.security.Permissionjava.security.BasicPermission 中的一个子类化。两者之间的基本区别在于,java.security.Permission 定义了需要名称和操作的更复杂的权限。例如,java.io.FilePermission 扩展自 java.security.Permission,并需要一个名称(文件名)以及该文件允许的操作(读/写/删除)。

相比之下,java.security.BasicPermission 定义了只需要名称的更简单的权限。例如,java.lang.RuntimePermission 扩展自 java.security.BasicPermission,只需要一个名称(如 “exitVM”),允许程序退出 Java 虚拟机。

我们的 HighScorePermission 是一个简单的权限,因此可以从 java.security.BasicPermission 扩展。

通常,BasicPermission 类中的方法实现本身不需要被其子类重写。这就是我们的 HighScorePermission 的情况,所以我们只需要实现构造函数,它们只是调用超类的构造函数,如以下所示:

package com.scoredev.scores;
import java.security.*;
public final class HighScorePermission extends BasicPermission {
    public HighScorePermission(String name)
    {
  super(name);
    }
    // note that actions is ignored and not used,
    // but this constructor is still needed
    public HighScorePermission(String name, String actions) 
    {
  super(name, actions);
    }
}

一个示例策略文件

原文:docs.oracle.com/javase/tutorial/security/userperm/policy.html

以下是一个完整的策略文件,供用户运行ExampleGame使用。

这里不描述策略文件的语法;如果您感兴趣,请参阅默认策略实现和策略文件语法页面。

你不需要了解语法;你可以随时使用策略工具创建策略文件,如创建策略文件,控制应用程序的快速导览,以及签署代码并授予权限课程中所示。

以下是示例策略文件,后面是各个条目的描述。假设

  • 策略文件位于 Kim 的计算机上,Kim 的密钥库命名为kim.keystore
  • ExampleGame已由游戏创建者 Terry 的私钥签名,相应的公钥在别名为"terry"的密钥库条目中。
  • HighScoreHighScorePermissions类是由实现它们的人(Chris)的私钥签名的,相应的公钥在别名为"chris"的密钥库条目中。

这是策略文件:kim.policy

keystore "kim.keystore";
// Here is the permission ExampleGame needs.
// It grants code signed by "terry" the
// HighScorePermission, if the
// HighScorePermission was signed by "chris"
grant SignedBy "terry" {
  permission
    com.scoredev.scores.HighScorePermission
      "ExampleGame", signedBy "chris";
};
// Here is the set of permissions the HighScore
// class needs:
grant SignedBy "chris" {
  // The HighScore class needs permission to read
  // "user.home" to find the location of the
  // highscore file
  permission java.util.PropertyPermission
    "user.home", "read";
  // It needs permission to read and write the
  // high score file itself
  permission java.io.FilePermission
      "${user.home}${/}.highscore", "read,write";
  // It needs to get granted its own permission,
  // so it can call checkPermission
  // to see if its caller has permission.
  // Only grant it the permission
  // if the permission itself was signed by
  // "chris"
  permission
    com.scoredev.scores.HighScorePermission 
      "*", signedBy "chris";
};

密钥库条目

密钥库是密钥和证书的存储库,用于查找策略文件中指定的签名者的公钥(在本例中为"terry""chris")。

keytool实用程序用于创建和管理密钥库。

对于本课程,假设 Kim 想玩ExampleGame。如果 Kim 的密钥库命名为kim.keystore,那么 Kim 的策略文件需要在开头加上以下行:

keystore "kim.keystore";

ExampleGame 条目

策略文件条目指定了特定代码源的一个或多个权限 - 来自特定位置(URL)的代码,或者由特定实体签名的代码,或两者兼有。

我们的策略文件需要为每个游戏添加一个条目,为该游戏的创建者签名的代码授予一个名为HighScorePermission的权限,其名称为游戏名称。该权限允许游戏调用HighScore方法来获取或更新该特定游戏用户的最高分值。

ExampleGame所需的条目是:

grant SignedBy "terry" {
    permission
        com.scoredev.scores.HighScorePermission 
            "ExampleGame", signedBy "chris";
};

要求ExampleGame"terry"签名使 Kim 知道该游戏是 Terry 开发的实际游戏。为了使其工作,Kim 必须已经将 Terry 的公钥证书存储到kim.keystore中,别名为"terry"

注意,HighScorePermission需要由实际实现该权限的"chris"签名,以确保ExampleGame被授予由"chris"实现的实际权限,而不是其他人。与之前一样,为了使其工作,Kim 必须已经将 Chris 的公钥证书存储到kim.keystore中,别名为"chris"

Java 中文官方教程 2022 版(四十二)(3)https://developer.aliyun.com/article/1488232

相关文章
|
7月前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
360 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
3月前
|
Oracle Java 关系型数据库
java 编程基础入门级超级完整版教程详解
这份文档是针对Java编程入门学习者的超级完整版教程,涵盖了从环境搭建到实际项目应用的全方位内容。首先介绍了Java的基本概念与开发环境配置方法,随后深入讲解了基础语法、控制流程、面向对象编程的核心思想,并配以具体代码示例。接着探讨了常用类库与API的应用,如字符串操作、集合框架及文件处理等。最后通过一个学生成绩管理系统的实例,帮助读者将理论知识应用于实践。此外,还提供了进阶学习建议,引导学员逐步掌握更复杂的Java技术。适合初学者系统性学习Java编程。资源地址:[点击访问](https://pan.quark.cn/s/14fcf913bae6)。
305 2
|
8月前
|
消息中间件 Java 数据库
自研Java框架 Sunrays-Framework使用教程「博客之星」
### Sunrays-Framework:助力高效开发的Java微服务框架 **Sunrays-Framework** 是一款基于 Spring Boot 构建的高效微服务开发框架,深度融合了 Spring Cloud 生态中的核心技术组件。它旨在简化数据访问、缓存管理、消息队列、文件存储等常见开发任务,帮助开发者快速构建高质量的企业级应用。 #### 核心功能 - **MyBatis-Plus**:简化数据访问层开发,提供强大的 CRUD 操作和分页功能。 - **Redis**:实现高性能缓存和分布式锁,提升系统响应速度。 - **RabbitMQ**:可靠的消息队列支持,适用于异步
自研Java框架 Sunrays-Framework使用教程「博客之星」
|
9月前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
8405 5
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
8月前
|
Java 数据库连接 数据处理
探究Java异常处理【保姆级教程】
Java 异常处理是确保程序稳健运行的关键机制。它通过捕获和处理运行时错误,避免程序崩溃。Java 的异常体系以 `Throwable` 为基础,分为 `Error` 和 `Exception`。前者表示严重错误,后者可细分为受检和非受检异常。常见的异常处理方式包括 `try-catch-finally`、`throws` 和 `throw` 关键字。此外,还可以自定义异常类以满足特定需求。最佳实践包括捕获具体异常、合理使用 `finally` 块和谨慎抛出异常。掌握这些技巧能显著提升程序的健壮性和可靠性。
133 4
|
8月前
|
存储 移动开发 算法
【潜意识Java】Java基础教程:从零开始的学习之旅
本文介绍了 Java 编程语言的基础知识,涵盖从简介、程序结构到面向对象编程的核心概念。首先,Java 是一种高级、跨平台的面向对象语言,支持“一次编写,到处运行”。接着,文章详细讲解了 Java 程序的基本结构,包括包声明、导入语句、类声明和 main 方法。随后,深入探讨了基础语法,如数据类型、变量、控制结构、方法和数组。此外,还介绍了面向对象编程的关键概念,例如类与对象、继承和多态。最后,针对常见的编程错误提供了调试技巧,并总结了学习 Java 的重要性和方法。适合初学者逐步掌握 Java 编程。
145 1
|
9月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
556 26
|
8月前
|
前端开发 Java 开发工具
Git使用教程-将idea本地Java等文件配置到gitte上【保姆级教程】
本内容详细介绍了使用Git进行版本控制的全过程,涵盖从本地仓库创建到远程仓库配置,以及最终推送代码至远程仓库的步骤。
415 0
|
9月前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
9月前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)

热门文章

最新文章