引言:

目前CSDN上,大部分都是对于文本的PGP加解密博文,但实际开发中,可能会与渠道对接使用PGP加解密报文,所以这里整理了下,对文本的加解密工具,希望对你有帮助。

一、引入PGP的依赖

        <!-- PGP 加解密 依赖--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcpg-jdk15on</artifactId><optional>true</optional></dependency><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><optional>true</optional></dependency>

二、编写工具类

package com.bop.util.pgp;import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;public class BCPGPUtils {public static PGPPublicKey readPublicKey(String fileName) throws IOException, PGPException {InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));PGPPublicKey pubKey = readPublicKey(keyIn);keyIn.close();return pubKey;}public static PGPPublicKey readPublicKey(InputStream in) throws IOException, PGPException {PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(in),new JcaKeyFingerprintCalculator());Iterator<PGPPublicKeyRing> keyRings = pgpPub.getKeyRings();while (keyRings.hasNext()) {PGPPublicKeyRing keyRing = keyRings.next();Iterator<PGPPublicKey> publicKeys = keyRing.getPublicKeys();while (publicKeys.hasNext()) {PGPPublicKey key = publicKeys.next();if (key.isEncryptionKey()) {return key;}}}throw new IllegalArgumentException("Can't find encryption key in key ring.");}public static PGPSecretKey readSecretKey(String fileName) throws IOException, PGPException {InputStream keyIn = new BufferedInputStream(new FileInputStream(fileName));PGPSecretKey secKey = readSecretKey(keyIn);keyIn.close();return secKey;}public static PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException {PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in),new JcaKeyFingerprintCalculator());Iterator<PGPSecretKeyRing> keyRings = pgpSec.getKeyRings();while (keyRings.hasNext()) {PGPSecretKeyRing keyRing = keyRings.next();Iterator<PGPSecretKey> secretKeys = keyRing.getSecretKeys();while (secretKeys.hasNext()) {PGPSecretKey key = secretKeys.next();if (key.isSigningKey()) {return key;}}}throw new IllegalArgumentException("Can't find signing key in key ring.");}/*** Load a secret key ring collection from keyIn and find the private key* corresponding to keyID if it exists.*/public static PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass)throws PGPException {PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);if (pgpSecKey == null) {return null;}return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));}public static PGPPrivateKey findPrivateKey(InputStream keyIn, long keyID, char[] pass)throws IOException, PGPException {PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn),new JcaKeyFingerprintCalculator());return findPrivateKey(pgpSec.getSecretKey(keyID), pass);}public static PGPPrivateKey findPrivateKey(PGPSecretKey pgpSecKey, char[] pass)throws PGPException {if (pgpSecKey == null)return null;return pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(pass));}
}

三、编写加密类

package com.bop.util.pgp;import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPOnePassSignature;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator;import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;/*** PGP 加密类** @author neal.armstrong* @version 1.0* @since 2021.11.22*/
public class PgpMemEncryptor {private final String publicKeyPath;private final String privateKeyPath;private InputStream PUBLIC_KEY;private PGPPublicKey publicKey;private PGPPrivateKey privateKey;public PgpMemEncryptor(String publicKeyPath, String privateKeyPath) {this.publicKeyPath = publicKeyPath;this.privateKeyPath = privateKeyPath;}public PGPPublicKey getPublicKey() {if (publicKey == null) {try {publicKey = BCPGPUtils.readPublicKey(publicKeyPath);} catch (IOException | PGPException e) {e.printStackTrace();}}return publicKey;}public PGPPrivateKey getPrivateKey(String purhapse) {if (privateKey == null) {try {PGPSecretKey secretKey = BCPGPUtils.readSecretKey(privateKeyPath);privateKey = secretKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(purhapse.toCharArray()));} catch (PGPException | IOException e) {e.printStackTrace();}}return privateKey;}@SneakyThrowsprivate InputStream getPublicIs() {if (PUBLIC_KEY == null) {PUBLIC_KEY = Files.newInputStream(Paths.get(publicKeyPath));}return PUBLIC_KEY;}private static void getProvider() {Provider provider = Security.getProvider("BC");if (provider == null) {provider = new BouncyCastleProvider();Security.addProvider(provider);}}public String encryptFile(String inputFile, boolean withIntegrityCheck) throws IOException, PGPException {getProvider();byte[] rawText = inputFile.getBytes();ByteArrayOutputStream encOut = new ByteArrayOutputStream();PGPPublicKey pubKey = BCPGPUtils.readPublicKey(getPublicIs());ArmoredOutputStream outputStream = new ArmoredOutputStream(encOut);ByteArrayOutputStream bOut = new ByteArrayOutputStream();PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(CompressionAlgorithmTags.ZIP);PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();OutputStream open = lData.open(comData.open(bOut), PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, rawText.length, PGPLiteralData.NOW);open.write(rawText);lData.close();comData.close();BcPGPDataEncryptorBuilder builder = new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256);builder.setWithIntegrityPacket(withIntegrityCheck);builder.setSecureRandom(new SecureRandom());PGPEncryptedDataGenerator cpk = new PGPEncryptedDataGenerator(builder);cpk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(pubKey));byte[] bytes = bOut.toByteArray();OutputStream cOut = cpk.open(outputStream, bytes.length);cOut.write(bytes);cOut.close();outputStream.close();return new String(encOut.toByteArray(), StandardCharsets.UTF_8);}public String encryptAndSignFile(String inputFile, boolean withIntegrityCheck, String purhapse) {getProvider();InputStream input = IOUtils.toInputStream(inputFile);ByteArrayOutputStream output = new ByteArrayOutputStream();try {int DEFAULT_BUFFER_SIZE = 16 * 1024;PGPSecretKey pgpSec = BCPGPUtils.readSecretKey(privateKeyPath);PGPPrivateKey signingKey = getPrivateKey(purhapse);PGPPublicKey publicKey = pgpSec.getPublicKey();String userid = (String) publicKey.getUserIDs().next();BcPGPDataEncryptorBuilder dataEncryptor = new BcPGPDataEncryptorBuilder(PGPEncryptedData.AES_256);dataEncryptor.setWithIntegrityPacket(withIntegrityCheck);dataEncryptor.setSecureRandom(new SecureRandom());PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(dataEncryptor);encryptedDataGenerator.addMethod((new BcPublicKeyKeyEncryptionMethodGenerator(getPublicKey())));OutputStream finalOut = new BufferedOutputStream(new ArmoredOutputStream(output), DEFAULT_BUFFER_SIZE);OutputStream encOut = encryptedDataGenerator.open(finalOut, new byte[DEFAULT_BUFFER_SIZE]);PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);BufferedOutputStream compressedOut = new BufferedOutputStream(compressedDataGenerator.open(encOut));PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(new BcPGPContentSignerBuilder(publicKey.getAlgorithm(), HashAlgorithmTags.SHA256));signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, signingKey);PGPSignatureSubpacketGenerator pgpSignatureSubpacketGenerator = new PGPSignatureSubpacketGenerator();pgpSignatureSubpacketGenerator.setSignerUserID(false, userid);signatureGenerator.setHashedSubpackets(pgpSignatureSubpacketGenerator.generate());PGPOnePassSignature onePassSignature = signatureGenerator.generateOnePassVersion(false);onePassSignature.encode(compressedOut);PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator(true);OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY,PGPLiteralData.CONSOLE, PGPLiteralData.NOW, new byte[1 << 16]);byte[] buffer = new byte[1 << 16];int bytesRead;while ((bytesRead = input.read(buffer)) != -1) {literalOut.write(buffer, 0, bytesRead);signatureGenerator.update(buffer, 0, bytesRead);literalOut.flush();}// Close Literal data stream and add signatureliteralOut.close();literalDataGenerator.close();signatureGenerator.generate().encode(compressedOut);// Close all other streamscompressedOut.close();compressedDataGenerator.close();encOut.close();encryptedDataGenerator.close();finalOut.close();input.close();return new String(output.toByteArray(), StandardCharsets.UTF_8);} catch (Exception e) {e.printStackTrace();}return null;}
}

四、编写解密类

package com.bop.util.pgp;import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPCompressedData;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPLiteralData;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPOnePassSignature;
import org.bouncycastle.openpgp.PGPOnePassSignatureList;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureList;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
import org.bouncycastle.util.io.Streams;import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Provider;
import java.security.Security;
import java.util.Iterator;/*** PGP 解密类** @author neal.armstrong* @version 1.0* @since 2021.11.22*/
public class PgpMemDecryptor {private final String publicKeyPath;private final String privateKeyPath;public PgpMemDecryptor(String publicKeyPath, String privateKeyPath) {this.publicKeyPath = publicKeyPath;this.privateKeyPath = privateKeyPath;}private InputStream PUBLIC_KEY;private InputStream PRIVATE_KEY;//    int compressionAlgorithm;
//    int hashAlgorithm;
//    int symmetricKeyAlgorithm;private static void getProvider() {Provider provider = Security.getProvider("BC");if (provider == null) {provider = new BouncyCastleProvider();Security.addProvider(provider);}}@SneakyThrowsprivate InputStream getPublicIs() {if (PUBLIC_KEY == null) {PUBLIC_KEY = Files.newInputStream(Paths.get(publicKeyPath));}return PUBLIC_KEY;}@SneakyThrowsprivate InputStream getPrivateIs() {if (PRIVATE_KEY == null) {PRIVATE_KEY = Files.newInputStream(Paths.get(privateKeyPath));}return PRIVATE_KEY;}public String decryptAndVerifyFile(String content, String passPhrase) {getProvider();InputStream verifyKeyInput = getPrivateIs();InputStream decryptKeyInput = getPublicIs();char[] passwd;try {passwd = passPhrase.toCharArray();InputStream input = PGPUtil.getDecoderStream(IOUtils.toInputStream(content));PGPObjectFactory pgpF = new PGPObjectFactory(input, new BcKeyFingerprintCalculator());PGPEncryptedDataList enc;Object o = pgpF.nextObject();if (o instanceof PGPEncryptedDataList) {enc = (PGPEncryptedDataList) o;} else {enc = (PGPEncryptedDataList) pgpF.nextObject();}Iterator<?> it = enc.getEncryptedDataObjects();PGPPrivateKey sKey = null;PGPPublicKeyEncryptedData pbe = null;PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(verifyKeyInput),new BcKeyFingerprintCalculator());while (sKey == null && it.hasNext()) {pbe = (PGPPublicKeyEncryptedData) it.next();sKey = BCPGPUtils.findSecretKey(pgpSec, pbe.getKeyID(), passwd);}if (sKey == null) {throw new IllegalArgumentException("secret key for message not found.");}InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
//            pbe.getSymmetricAlgorithm(new BcPublicKeyDataDecryptorFactory(sKey));PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());Object message;PGPOnePassSignatureList onePassSignatureList = null;PGPSignatureList signatureList = null;PGPCompressedData compressedData;message = plainFact.nextObject();ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();while (message != null) {if (message instanceof PGPCompressedData) {compressedData = (PGPCompressedData) message;plainFact = new PGPObjectFactory(compressedData.getDataStream(), new BcKeyFingerprintCalculator());message = plainFact.nextObject();
//                    this.compressionAlgorithm = compressedData.getAlgorithm();}if (message instanceof PGPLiteralData) {Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput);} else if (message instanceof PGPOnePassSignatureList) {onePassSignatureList = (PGPOnePassSignatureList) message;} else if (message instanceof PGPSignatureList) {signatureList = (PGPSignatureList) message;}message = plainFact.nextObject();}actualOutput.close();PGPPublicKey publicKey;byte[] outputBytes = actualOutput.toByteArray();if (onePassSignatureList == null || signatureList == null) {throw new PGPException("Poor PGP. Signatures not found.");} else {for (int i = 0; i < onePassSignatureList.size(); i++) {PGPOnePassSignature ops = onePassSignatureList.get(0);PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(decryptKeyInput), new BcKeyFingerprintCalculator());publicKey = pgpRing.getPublicKey(ops.getKeyID());if (publicKey != null) {ops.init(new BcPGPContentVerifierBuilderProvider(), publicKey);ops.update(outputBytes);PGPSignature signature = signatureList.get(i);if (ops.verify(signature)) {
//                            this.hashAlgorithm = ops.getHashAlgorithm();}}}}return new String(outputBytes);} catch (Exception e) {e.printStackTrace();}return null;}public String decryptFile(String content, String passphrase)throws Exception {getProvider();InputStream fIn = IOUtils.toInputStream(content);InputStream in = PGPUtil.getDecoderStream(fIn);InputStream keyIn = getPrivateIs();char[] passPhrase = passphrase.toCharArray();PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());PGPEncryptedDataList enc;Object o = pgpF.nextObject();if (o instanceof PGPEncryptedDataList) {enc = (PGPEncryptedDataList) o;} else {enc = (PGPEncryptedDataList) pgpF.nextObject();}Iterator<PGPPublicKeyEncryptedData> it = enc.getEncryptedDataObjects();PGPPrivateKey sKey = null;PGPPublicKeyEncryptedData pbe = null;while (sKey == null && it.hasNext()) {pbe = it.next();sKey = BCPGPUtils.findPrivateKey(keyIn, pbe.getKeyID(), passPhrase);}InputStream clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
//        this.symmetricKeyAlgorithm = pbe.getSymmetricAlgorithm(new BcPublicKeyDataDecryptorFactory(sKey));PGPObjectFactory pgpFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());o = pgpFact.nextObject();if (o instanceof PGPCompressedData) {PGPCompressedData cData = (PGPCompressedData) o;pgpFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());o = pgpFact.nextObject();}if (o instanceof PGPLiteralData) {PGPLiteralData ld = (PGPLiteralData) o;InputStream unc = ld.getInputStream();return IOUtils.toString(unc);}return null;}
}

五、测试

请选择正确的用法,例如使用加签加密方法时,对应请使用验签解密方法。使用加密方法,则直接使用解密方法即可。

五、结尾

由于时间仓促,并未对代码进行优化,许多流文件,可能遗漏并未进行完美关闭,还请注意使用。

PGP 对于JSON的加解密相关推荐

  1. JAVA实现PGP/GPG加解密

    注:文章皆为个人纪录,可用性请以最终结果为准,若有错还请大佬们指出,谢谢! 一.加解密的准备资料 1.1  公钥 (用于加密) 1.2  私钥(用于解密) 1.3   私钥key (用于验证私钥) 导 ...

  2. 记一个在线工具网站,程序员必备,json格式化、压缩、转义,加解密 编码解码

    为你工具 ToForU-在线json格式化|在线json压缩|在线json转义|工具大全 提供 json格式化,json代码压缩,json校验解析,json数组解析,json转xml,xml转json ...

  3. php,微信视频号之微信消息加解密xml,json

    **注意!注意!注意!此文只针对json格式的解密** ![在这里插入图片描述](https://img-blog.csdnimg.cn/3041f415a4db4d58a54c9f45ec2a898 ...

  4. 【加解密篇】Passware Encryption Analyzer快速检测加密文件软件

    [加解密篇]Passware Encryption Analyzer快速检测加密文件软件 ​ 密码加密分析仪是一种免费工具,可扫描系统以检测受保护或加密的文件.存档和其他加密类型的文件-[suy] 文 ...

  5. Java 进行 RSA 加解密时不得不考虑到的那些事儿

    1. 加密的系统不要具备解密的功能,否则 RSA 可能不太合适 公钥加密,私钥解密.加密的系统和解密的系统分开部署,加密的系统不应该同时具备解密的功能,这样即使黑客攻破了加密系统,他拿到的也只是一堆无 ...

  6. python杂记-RSA加解密实现(4)-加解密消息及文件

    3.消息m分段与非负整数n之间的互相转换 #!/usr/bin/env python3 # -*- coding: utf-8 -*- #2-10-3-6.py import base64 impor ...

  7. aes js 加盐值 解密_Java已有AES加解密,现需要前端Javascript加密调接口,返回的数据需要解密,目前互..._慕课猿问...

    目前Javascript使用'crypto-js'包. 前后台可以自己跑通加解密,但是,无法互通. 针对对象{}加密--网上的方案,已经尝试了4天左右了,还没成功,请指导. 无思路,无报错. Java ...

  8. 聊一聊.NET Core结合Nacos实现配置加解密

    背景 当我们把应用的配置都放到配置中心后,很多人会想到这样一个问题,配置里面有敏感的信息要怎么处理呢? 信息既然敏感的话,那么加个密就好了嘛,相信大部分人的第一感觉都是这个,确实这个是最简单也是最合适 ...

  9. .NET Core加解密实战系列之——消息摘要与数字签名算法

    简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...

最新文章

  1. 通过 SSH 连接到 VMware NAT 模式下的 Ubuntu 虚拟机环境
  2. php 我已阅读并同意 判断,phb.php
  3. 基于Quartz.net 的开源任务管理平台
  4. SpringBoot2 Redis连接池
  5. eigrp hello报文格式
  6. iptables学习笔记:使用NAT实现简单的无线AP
  7. vue延迟渲染组件_做一个可复用的 echarts-vue 组件(延迟动画加载)
  8. C# ToString()格式笔记
  9. ROST情感分析的语法规则_NLP技术之句法分析
  10. hdu 5025 Saving Tang Monk 状态压缩dp+广搜
  11. linux 权限 c,Linux下获取root权限的c程序
  12. html 图片拼接,css sprite图像拼接技术
  13. 网络钓鱼仍然是安全行业的祸害
  14. 项目一. 家庭记账软件
  15. 计算机所选区域单元格数值,筛选Excel2007单元格区域或表中的数据
  16. OSS简单上传下载整理
  17. 一个c语言源文件可以包含两个以上main,二级C语言习题汇总及标准答案.doc
  18. PostGreSQL主从库环境下的从节点故障恢复
  19. The First :使用Anaconda+pycharm学习图像处理
  20. 质量保障(QA)和质量控制(QC)

热门文章

  1. C语言学习第五天(存储类和变量的作用域)默认熟悉数据结构
  2. 康复医疗 趋势引领新蓝海
  3. java邮件发送代码_用java代码发送邮件(优化版)
  4. ! LaTeX Error: File xxx.sty not found-统一解决办法
  5. 多方寻路RFID酝酿突围
  6. 丢手帕问题 java_丢手帕问题 (java实现)
  7. 最新公布的十中抗癌食谱,
  8. java 数据可视化
  9. 外骨骼机器人(一):Lokomat核心技术简介
  10. java中的反射机制是什么