我们相信加密! 教程

许多人认为加密是一个复杂的主题,这很难理解。 虽然可以实现它的某些方面,但是每个人都可以理解它在更高层次上的工作方式。

这就是我要处理的这篇文章。 用简单的术语解释它是如何工作的,然后使用一些代码。

是的,我们信任加密。 信任是什么意思? 我们相信,我们的消息仅由授权方读取(机密性),在传输过程中不会更改(完整性),并且确实由我们认为已发送(验证)的人发送。

维基百科为加密提供了一个很好的定义:“是以一种仅授权方可以访问的方式对消息或信息进行编码的过程”。

因此,加密通过使用密钥(密码)将我们的信息转换为难以理解的密钥(密文),该密钥只​​能从授权方转回原始信息。

加密方案有两种类型, 对称非对称密钥加密。

在对称加密中,相同的密钥用于加密和解密消息。 我们希望访问该消息的用户必须具有密钥,但没有其他密钥,否则我们的消息将受到威胁。

我对非对称密钥加密很感兴趣。 非对称密钥方案使用两个密钥:私有密钥和公共密钥。 这些键对很特殊。 它们之所以特别是因为它们是使用称为非对称算法的一类算法生成的。 实际的算法不在此讨论范围之内,但是在本教程的后面,我们将使用RSA。

您现在需要知道的是,这些键具有以下属性。 使用以下内容加密的消息:

  1. 只能使用私钥解密公钥
  2. 私钥只能使用公钥解密


看起来足够简单吧? 那么它在实践中如何使用? 让我们考虑两个朋友,爱丽丝和鲍勃。 他们有自己的一对公钥和私钥,并且希望在聊天中保持私密性。 他们每个人都公开提供他们的公钥,但是要小心地隐藏他们的私钥。

当爱丽丝(Alice)要发送仅从鲍勃(Bob)读取的消息时,她使用鲍勃(Bob)的公共密钥对消息进行加密。 然后Bob和只有他才能使用他的私钥解密消息。 而已。

这就解释了第一个属性的使用,但是第二个呢? 似乎没有理由使用我们的私钥进行加密。 好吧,有。 我们怎么知道爱丽丝是那个发信息的人? 如果我们可以使用Alice的公钥解密消息,则可以确保使用Alice的私钥进行加密,因此确实是从Alice发送的。 简单的说:

使用公钥,以便人们只能将内容发送给您,而私钥则用于证明您的身份。

因此,我们可以使用公钥来确保机密性 ,并使用私钥来保证真实性 。 那么诚信呢? 为了实现这一点,我们使用加密哈希。 良好的加密散列可接收输入消息并生成具有以下属性的消息摘要:

  1. 消息摘要易于生成
  2. 计算哪个输入提供了哈希值非常困难
  3. 两个不同的输入/消息生成相同的哈希值的可能性极小

如果我们想确保接收到的消息在过渡期间没有受到破坏,则将哈希值与加密消息一起发送。 在接收端,我们使用相同的算法对解密后的消息进行哈希处理,然后进行比较以确保哈希值完全匹配。 如果它们是,那么我们可以确信消息没有被更改。

这些散列或消息摘要也具有其他用途。 您会看到,有时Bob做出承诺,然后否认自己曾经做过。 我们想让他检查。 用奇特的术语来说,这是不可否认的 ,它可以防止各方拒绝发送消息。 数字签名是众所周知的应用。

在继续学习并享受代码乐趣之前,让我再说几件事。

  1. 非对称密钥算法实际上具有两种用于不同功能的算法。 一个当然是用于密钥生成,另一个功能是用于功能评估。 功能评估意味着获取输入(即消息)和密钥,并根据获得的输入结果得到加密或解密的消息。 因此功能评估就是使用公钥/私钥对消息进行加密和解密的方式。
  2. 也许您已经想过,我们怎么知道公钥实际上与Bob或Alice相关? 如果有人假装自己怎么办? 有一个标准可以帮助我们。 X.509定义了公钥证书的格式。 这些证书由证书颁发机构提供,通常包含:
    1. 主题,聚会的详细说明(例如Alice)
    2. 有效期,证书有效期
    3. 公钥,可帮助我们向聚会发送加密的消息
    4. 证书颁发机构,证书的颁发者
  3. 哈希和加密是不同的东西。 加密的消息最终将被转换回原始消息。 散列的消息应该不可能转回原始消息。

现在,让我们使用一个教程来帮助所有这些问题。我们将允许三个人爱丽丝,鲍勃和保罗与机密性,完整性和身份验证进行通信(进一步将它们称为CIA)。 完整的代码可在github上找到 。
该项目有几个依赖项,如下所示:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.tasosmartidis.tutorial.encryption</groupId><artifactId>encryption-tutorial</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>encryption-tutorial</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><lombok.version>1.16.18</lombok.version><commons-codec.version>1.11</commons-codec.version><junit.version>4.12</junit.version><bouncycastle.version>1.58</bouncycastle.version></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>${commons-codec.version}</version></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>${bouncycastle.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version><scope>test</scope></dependency></dependencies><build><finalName>encryption-tutorial</finalName><pluginManagement><plugins><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.0</version><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></pluginManagement></build>
</project>

我们将从EncryptedMessage类开始,该类将提供我们确保CIA所需的所有信息。 该消息将包含用于机密性的实际加密消息,该消息的哈希值将用于确保发送者的完整性和身份验证,原始消息和加密消息则用于身份验证。 我们还提供了一种破坏消息有效负载的方法,因此我们可以针对摘要测试验证(稍后会进行介绍)。

package com.tasosmartidis.tutorial.encryption.domain;import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;@AllArgsConstructor
@Getter
@EqualsAndHashCode
public class EncryptedMessage {private String encryptedMessagePayload;private String senderId;private String encryptedSenderId;private String messageDigest;// FOR DEMO PURPOSES ONLY!public void compromiseEncryptedMessagePayload(String message) {this.encryptedMessagePayload = message;}@Overridepublic String toString() {return encryptedMessagePayload;}
}

现在让我们进入加密部分。 我们将创建一个独立于实际非对称算法和密钥长度的基本加密器类。 它将创建密钥和密码,具有用于加密和解密文本以及提供对密钥的访问的方法。 看起来像这样:

package com.tasosmartidis.tutorial.encryption.encryptor;import com.tasosmartidis.tutorial.encryption.domain.EncryptorProperties;
import com.tasosmartidis.tutorial.encryption.exception.DecryptionException;
import com.tasosmartidis.tutorial.encryption.exception.EncryptionException;
import com.tasosmartidis.tutorial.encryption.exception.EncryptorInitializationException;
import com.tasosmartidis.tutorial.encryption.exception.UnauthorizedForDecryptionException;
import org.apache.commons.codec.binary.Base64;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;public class BaseAsymmetricEncryptor {private final KeyPairGenerator keyPairGenerator;private final KeyPair keyPair;private final Cipher cipher;private final EncryptorProperties encryptorProperties;protected BaseAsymmetricEncryptor(EncryptorProperties encryptorProperties) {this.encryptorProperties = encryptorProperties;this.keyPairGenerator = generateKeyPair();this.keyPairGenerator.initialize(this.encryptorProperties.getKeyLength());this.keyPair = this.keyPairGenerator.generateKeyPair();this.cipher = createCipher(encryptorProperties);}protected PrivateKey getPrivateKey() {return this.keyPair.getPrivate();}public PublicKey getPublicKey() {return this.keyPair.getPublic();}protected String encryptText(String textToEncrypt, Key key) {try {this.cipher.init(Cipher.ENCRYPT_MODE, key);return Base64.encodeBase64String(cipher.doFinal(textToEncrypt.getBytes(StandardCharsets.UTF_8)));} catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException ex) {throw new EncryptionException("Encryption of message failed", ex);}}protected String decryptText(String textToDecrypt, Key key) {try {this.cipher.init(Cipher.DECRYPT_MODE, key);return new String(cipher.doFinal(Base64.decodeBase64(textToDecrypt)), StandardCharsets.UTF_8);}catch (InvalidKeyException | BadPaddingException ex){throw new UnauthorizedForDecryptionException("Not authorized to decrypt message", ex);} catch (IllegalBlockSizeException ex) {throw new DecryptionException("Decryption of message failed", ex);}}private Cipher createCipher(EncryptorProperties encryptorProperties) {try {return Cipher.getInstance(encryptorProperties.getAsymmetricAlgorithm());} catch (NoSuchAlgorithmException | NoSuchPaddingException ex) {throw new EncryptorInitializationException("Creation of cipher failed", ex);}}private KeyPairGenerator generateKeyPair() {try {return KeyPairGenerator.getInstance(this.encryptorProperties.getAsymmetricAlgorithm());} catch (NoSuchAlgorithmException ex) {throw new EncryptorInitializationException("Creation of encryption keypair failed", ex);}}}

为了实现我们的功能,我们需要处理许多异常,但是由于万一发生它们,我们将不对其进行任何处理,因此我们将它们包装在语义上有意义的运行时异常中。 我不会在这里展示异常类,因为它们只有一个构造函数。 但是您可以在github.com.tasosmartidis.tutorial.encryption.exception包下的项目中检出它们。

您将在代码的不同部分看到它们的实际用法。 BaseAsymmetricEncryptor的构造BaseAsymmetricEncryptorEncryptorProperites实例作为参数。

package com.tasosmartidis.tutorial.encryption.domain;import lombok.AllArgsConstructor;@AllArgsConstructor
public class EncryptorProperties {private final AsymmetricAlgorithm asymmetricAlgorithm;private final int keyLength;public String getAsymmetricAlgorithm() {return asymmetricAlgorithm.toString();}public int getKeyLength() {return keyLength;}
}

我们将创建一个基于RSA的加密器实现。 该代码应该说明一切:

package com.tasosmartidis.tutorial.encryption.encryptor;import com.tasosmartidis.tutorial.encryption.domain.AsymmetricAlgorithm;
import com.tasosmartidis.tutorial.encryption.domain.EncryptedMessage;
import com.tasosmartidis.tutorial.encryption.domain.EncryptorProperties;
import org.bouncycastle.jcajce.provider.digest.SHA3;
import org.bouncycastle.util.encoders.Hex;import java.security.PublicKey;public class RsaEncryptor extends BaseAsymmetricEncryptor {private static final int KEY_LENGTH = 2048;public RsaEncryptor() {super(new EncryptorProperties(AsymmetricAlgorithm.RSA, KEY_LENGTH));}public String encryptMessageForPublicKeyOwner(String message, PublicKey key) {return super.encryptText(message, key);}public String encryptMessageWithPrivateKey(String message) {return super.encryptText(message, super.getPrivateKey());}public String decryptReceivedMessage(EncryptedMessage message) {return super.decryptText(message.getEncryptedMessagePayload(), super.getPrivateKey());}public String decryptMessageFromOwnerOfPublicKey(String message, PublicKey publicKey) {return super.decryptText(message, publicKey);}public String hashMessage(String message) {SHA3.DigestSHA3 digestSHA3 = new SHA3.Digest512();byte[] messageDigest = digestSHA3.digest(message.getBytes());return Hex.toHexString(messageDigest);}
}

对于我们的演示,我们将需要演员,彼此交流信息的人。 每个人都将具有唯一的身份,姓名以及与之通信的受信任联系人的列表。

package com.tasosmartidis.tutorial.encryption.demo;import com.tasosmartidis.tutorial.encryption.domain.EncryptedMessage;
import com.tasosmartidis.tutorial.encryption.message.RsaMessenger;
import lombok.EqualsAndHashCode;import java.security.PublicKey;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;@EqualsAndHashCode
public class Person {private final String id;private final String name;private final Set<Person> trustedContacts;private final RsaMessenger rsaMessenger;public Person(String name) {this.id = UUID.randomUUID().toString();this.name = name;this.trustedContacts = new HashSet<>();this.rsaMessenger = new RsaMessenger(this.trustedContacts, this.id);}public PublicKey getPublicKey() {return this.rsaMessenger.getPublicKey();}public String getName() {return name;}public String getId() {return id;}public void addTrustedContact(Person newContact) {if(trustedContacts.contains(newContact)) {return;}trustedContacts.add(newContact);}public EncryptedMessage sendEncryptedMessageToPerson(String message, Person person) {return this.rsaMessenger.encryptMessageForPerson(message, person);}public void readEncryptedMessage(EncryptedMessage encryptedMessage) {this.rsaMessenger.readEncryptedMessage(encryptedMessage);}}

接下来,让我们创建一个RsaMessanger类,该类将允许人们使用RsaEncryptor发送加密的消息。 发送加密的消息时,我们将提供所有必要的信息,以确保机密性,完整性和身份验证。 阅读时,我们将解密消息,我们将尝试验证消息是由受信任的联系人发送的,并确保消息没有受到破坏或更改。

package com.tasosmartidis.tutorial.encryption.message;import com.tasosmartidis.tutorial.encryption.demo.Person;
import com.tasosmartidis.tutorial.encryption.domain.EncryptedMessage;
import com.tasosmartidis.tutorial.encryption.encryptor.RsaEncryptor;
import com.tasosmartidis.tutorial.encryption.exception.PayloadAndDigestMismatchException;import java.security.PublicKey;
import java.util.Optional;
import java.util.Set;public class RsaMessenger {private final RsaEncryptor encryptionHandler;private final Set<Person> trustedContacts;private final String personId;public RsaMessenger(Set<Person> trustedContacts, String personId) {this.encryptionHandler = new RsaEncryptor();this.trustedContacts = trustedContacts;this.personId = personId;}public PublicKey getPublicKey() {return this.encryptionHandler.getPublicKey();}public EncryptedMessage encryptMessageForPerson(String message, Person person) {String encryptedMessage = this.encryptionHandler.encryptMessageForPublicKeyOwner(message, person.getPublicKey());String myEncryptedId = this.encryptionHandler.encryptMessageWithPrivateKey(this.personId);String hashedMessage = this.encryptionHandler.hashMessage(message);return new EncryptedMessage(encryptedMessage, this.personId, myEncryptedId, hashedMessage);}public void readEncryptedMessage(EncryptedMessage message) {String decryptedMessage = this.encryptionHandler.decryptReceivedMessage(message);Optional<Person> sender = tryIdentifyMessageSender(message.getSenderId());if(!decryptedMessageHashIsValid(decryptedMessage, message.getMessageDigest())) {throw new PayloadAndDigestMismatchException("Message digest sent does not match the one generated from the received message");}if(sender.isPresent() && senderSignatureIsValid(sender.get(), message.getEncryptedSenderId())) {System.out.println(sender.get().getName() +" send message: " + decryptedMessage);}else {System.out.println("Unknown source send message: " + decryptedMessage);}}private boolean senderSignatureIsValid(Person sender, String encryptedSenderId) {if(rawSenderIdMatchesDecryptedSenderId(sender, encryptedSenderId)) {return true;}return false;}private boolean rawSenderIdMatchesDecryptedSenderId(Person sender, String encryptedSenderId) {return sender.getId().equals(this.encryptionHandler.decryptMessageFromOwnerOfPublicKey(encryptedSenderId, sender.getPublicKey()));}private Optional<Person> tryIdentifyMessageSender(String id) {return this.trustedContacts.stream().filter(contact -> contact.getId().equals(id)).findFirst();}private boolean decryptedMessageHashIsValid(String decryptedMessage, String hashedMessage) {String decryptedMessageHashed = this.encryptionHandler.hashMessage(decryptedMessage);if(decryptedMessageHashed.equals(hashedMessage)) {return true;}return false;}
}

好的! 现在是演示时间!

我们将创建一些测试以确保一切正常。 我们要测试的方案是:
当爱丽丝(鲍勃的受信任联系人)向他发送加密的消息时,鲍勃可以解密该消息,并且知道来自鲍勃。 还要确保有效载荷没有被更改。
从Alice到Bob的相同消息不可用于Paul解密,并且将引发UnauthorizedForDecryptionException 。 当保罗(鲍勃不知道)发送加密消息时,鲍勃将能够读取该消息,但不知道是谁发送了该消息。 最后,当我们危及加密消息的有效负载时,带有消息摘要的验证将识别出该消息并引发异常。

package com.tasosmartidis.tutorial.encryption;import com.tasosmartidis.tutorial.encryption.demo.Person;
import com.tasosmartidis.tutorial.encryption.domain.EncryptedMessage;
import com.tasosmartidis.tutorial.encryption.exception.PayloadAndDigestMismatchException;
import com.tasosmartidis.tutorial.encryption.exception.UnauthorizedForDecryptionException;
import org.junit.Before;
import org.junit.Test;public class DemoTest {private static final String ALICE_MESSAGE_TO_BOB = "Hello Bob";private static final String PAULS_MESSAGE_TO_BOB = "Hey there Bob";private final Person bob = new Person("Bob");private final Person alice = new Person("Alice");private final Person paul = new Person("Paul");private EncryptedMessage alicesEncryptedMessageToBob;private EncryptedMessage paulsEncryptedMessageToBob;@Beforepublic void setup() {bob.addTrustedContact(alice);alicesEncryptedMessageToBob = alice.sendEncryptedMessageToPerson(ALICE_MESSAGE_TO_BOB, bob);paulsEncryptedMessageToBob = paul.sendEncryptedMessageToPerson(PAULS_MESSAGE_TO_BOB, bob);}@Testpublic void testBobCanReadAlicesMessage() {bob.readEncryptedMessage(alicesEncryptedMessageToBob);}@Test(expected = UnauthorizedForDecryptionException.class)public void testPaulCannotReadAlicesMessageToBob() {paul.readEncryptedMessage(alicesEncryptedMessageToBob);}@Testpublic void testBobCanReadPaulsMessage() {bob.readEncryptedMessage(paulsEncryptedMessageToBob);}@Test(expected = PayloadAndDigestMismatchException.class)public void testChangedMessageIdentifiedAndRejected() {EncryptedMessage slightlyDifferentMessage = alice.sendEncryptedMessageToPerson(ALICE_MESSAGE_TO_BOB + " ", bob);alicesEncryptedMessageToBob.compromiseEncryptedMessagePayload(slightlyDifferentMessage.getEncryptedMessagePayload());bob.readEncryptedMessage(alicesEncryptedMessageToBob);}
}

运行测试将产生以下结果:

就是这样! 再次感谢您的阅读,您可以在github上找到代码。

翻译自: https://www.javacodegeeks.com/2017/11/encryption-trust-tutorial.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348737.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Http协议访问网络--HttpURLConnection

public abstract classHttpURLConnection extends URLConnectionjava.lang.Object ↳java.net.URLConnection ↳java.net.HttpURLConnection 1、获取HttpURLConnection实例Protected ConstructorsHttpURLConnection(URL url)Constructs a new HttpURLConnection instance …

Spring Cloud –基本设置

Spring Cloud解决了分布式系统的常见问题。 但是&#xff0c;对于只使用广为人知的整体应用程序工作的人来说&#xff0c;从一开始就跳入一长串为分布式服务设计的模式可能会让人不知所措。 本文将通过实用的方法为您介绍Spring Cloud的基础知识。 完成后&#xff0c;您不仅应该…

Eclipse中的Tomcat:6个流行的“如何做”问题

学习新技术总是一个艰难的过程。 当您尝试学习将要相互交互的两种技术时&#xff0c;此过程变得更加困难。 Tomcat和Eclipse是Java EE开发中最流行的先决条件之一。 因此&#xff0c;要成为一名专业的开发人员&#xff0c;您需要知道如何使用此对执行最需要的操作以及如何进行一…

Spring Boot中带有CKEditor的AJAX

1.概述 在本文中&#xff0c;我们将介绍如何在Spring Boot中使用CKEditor 。 在本教程中&#xff0c;我们将导入一个包含大量数据的XML文档&#xff0c;对使用GET请求将一组数据加载到CKEditor实例的能力进行编程&#xff0c;并执行POST请求以保存CKEditor的数据。 我们将使用…

使用Http协议访问网络--HttpClient

public interface HttpClient org.apache.http.client.HttpClient HttpClient是Apache提供的Http网络访问接口。1、创建HttpClient实例HttpClient是一个接口&#xff0c;无法直接创建实例&#xff0c;通常创建一个DefaultHttpClient&#xff08;HttpClient 的SubClass&#xff…

编写测试用例

1、创建测试用例 为ComeOnBroadcastReceiverDo创建一个测试用例&#xff1a; 在导航栏File-->New-->Other 选择AndroidTestProject 2、点击next输入测试工程的name&#xff0c;选择测试工程路径 点击next,选择要测试的工程&#xff1a; 点击Finish完成测试工程的新建 被…

欢迎界面动画

实现一个欢迎界面的动画&#xff0c;即打开app显示的页面&#xff0c;动画结束后跳到Activity。 1、欢迎界面的背景是一个绿色矩形 <?xml version"1.0" encoding"utf-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/andr…

IP地址分类及ISO-OSI、三次握手

1. A类地址A类地址的表示范围为&#xff1a;0.0.0.0~126.255.255.255(00000000~01111110)&#xff0c;最前面一位是“0”&#xff0c;用7位&#xff08;bit&#xff09;来标识网络号&#xff0c;24位标识主机号&#xff1b;默认网络掩码为&#xff1a;255.0.0.0&#xff0c;111…

drools 决策表_骆驼和春天的Drools决策表

drools 决策表正如我在之前的文章中所展示的那样&#xff0c; JBoss Drools是一个非常有用的规则引擎 。 唯一的问题是&#xff0c;对于非技术人员而言&#xff0c;以Rule语言创建规则可能会非常复杂。 这就是为什么人们可以提供一种简便的方法来创建业务规则-在电子表格中创建…

在Java中处理异常

每个程序员都希望编写一个完美的程序。 也就是说&#xff0c;程序运行时没有任何障碍。 好吧&#xff0c;如果希望是马&#xff0c;乞g就会骑。 除了程序员的所有愿望之外&#xff0c;有时还会发生无法预料的情况。 这些不可预见的情况在Java中通常被归类为“例外”。 异常会…

通信系统的组成

数字通信模型&#xff1a; http://blog.csdn.net/yaosiming2011/article/details/44280797 进程和线程

存储卡显示0字节怎么办?恢复0字节的存储小技巧

存储卡显示0字节是一个常见的故障现象&#xff0c;可能由多种原因引起。本文将详细分析存储卡出现此类问题的各种原因&#xff0c;并提供针对性的解决方法。通过深入了解这些原因和解决方案&#xff0c;读者可以有效地应对存储卡显示0字节的故障&#xff0c;从而恢复存储卡的正…

OSI模型和TCP/IP协议族

1、协议分层 两个实体之间要进行通信就需要有一个协议。而当通信比较复杂时就有必要将这个复杂的任务划分为多层&#xff0c;就需要有多个协议&#xff0c;每一层都有自己的协议。 2、ISO 国际标准化组织&#xff08;International Standard Organization &#xff0c; ISO&…

在PhotoShop中改像素m*n

快捷键&#xff1a;CtrlAlti&#xff0c;如图&#xff0c;改为28*28

Spring Boot Redis简介

1.概述 在本文中&#xff0c;我们将通过Spring Data Redis库回顾如何将Redis与Spring Boot结合使用的基础知识。 我们将构建一个应用程序&#xff0c;演示如何通过Web界面执行CRUD操作Redis 。 Github上提供了该项目的完整源代码。 2.什么是Redis&#xff1f; Redis是一个开源…

Dijkstra-解决最短路径问题

1、从A开始&#xff08;也可以从其他点&#xff0c;此处选择从A&#xff09; 将A 加入树&#xff0c;A被圈红 列出最短路径数组&#xff1a; 2、 确定从A到其他顶点的最短距离为50&#xff0c;A-->B 将B加入树&#xff1a; 更新最短路径数组&#xff1a; 比较到C的距离&a…

简单排序--冒泡排序

冒泡排序&#xff1a; public void sort(){int out,in;//out指向已经排好序的前一个for( outnElements-1;out>1;out--){for(in0;in<out;in){if(arr[in]>arr[in1]){swap(in,in1);//相邻的两个元素比较&#xff0c;交换}}}}//实现冒泡排序相邻的元素两两比较&#xff0c…

简单排序--选择排序

选择排序&#xff1a; public void sort(){int out,in,min;for(out0;out<nElements-1;out){min out;for(inout1;in<nElements;in)if(arr[in]<arr[min])min in;swap(out,min);//将min放在out位置&#xff0c;out始终指向最小值的下一个位置&#xff0c;即下一个min要…

Java 9模块服务

接线与查找 Java长期以来都有一个ServiceLoader类。 它是在1.6中引入的&#xff0c;但是自Java 1.2以来就使用了类似的技术。 一些软件组件使用了它&#xff0c;但是使用并不广泛。 它可以用于模块化应用程序&#xff08;甚至更多&#xff09;&#xff0c;并提供一种使用应用程…