java實現安全證書相關操作

来源:https://www.cnblogs.com/kungfupanda/archive/2018/07/11/9292567.html
-Advertisement-
Play Games

https://blog.csdn.net/zhushanzhi/article/details/77864516 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 [java] view plain copy package test; i ...


https://blog.csdn.net/zhushanzhi/article/details/77864516

[java] view plain copy    
  1. package test;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileNotFoundException;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.InputStream;  
  10. import java.io.OutputStream;  
  11. import java.io.PrintStream;  
  12. import java.security.Key;  
  13. import java.security.KeyPair;  
  14. import java.security.KeyPairGenerator;  
  15. import java.security.KeyStore;  
  16. import java.security.Principal;  
  17. import java.security.PrivateKey;  
  18. import java.security.PublicKey;  
  19. import java.security.SecureRandom;  
  20. import java.security.Signature;  
  21. import java.security.cert.Certificate;  
  22. import java.security.cert.CertificateException;  
  23. import java.security.cert.CertificateFactory;  
  24. import java.security.cert.CertificateFactorySpi;  
  25. import java.security.cert.X509Certificate;  
  26. import java.util.ArrayList;  
  27. import java.util.Calendar;  
  28. import java.util.Collection;  
  29. import java.util.Date;  
  30. import java.util.Enumeration;  
  31. import java.util.HashMap;  
  32. import java.util.List;  
  33. import java.util.Map;  
  34. import java.util.regex.Matcher;  
  35. import java.util.regex.Pattern;  
  36.   
  37. import javax.crypto.KeyGenerator;  
  38. import javax.crypto.SecretKey;  
  39. import javax.crypto.spec.SecretKeySpec;  
  40.   
  41. import org.junit.Test;  
  42.   
  43. import sun.misc.BASE64Decoder;  
  44. import sun.misc.BASE64Encoder;  
  45. import sun.security.pkcs.ContentInfo;  
  46. import sun.security.pkcs.PKCS10;  
  47. import sun.security.pkcs.PKCS7;  
  48. import sun.security.tools.KeyStoreUtil;  
  49. import sun.security.x509.AlgorithmId;  
  50. import sun.security.x509.CertificateAlgorithmId;  
  51. import sun.security.x509.CertificateIssuerName;  
  52. import sun.security.x509.CertificateSerialNumber;  
  53. import sun.security.x509.CertificateSubjectName;  
  54. import sun.security.x509.CertificateValidity;  
  55. import sun.security.x509.CertificateVersion;  
  56. import sun.security.x509.CertificateX509Key;  
  57. import sun.security.x509.X500Name;  
  58. import sun.security.x509.X500Signer;  
  59. import sun.security.x509.X509CertImpl;  
  60. import sun.security.x509.X509CertInfo;  
  61.   
  62. public class ReadKeyStoreTest {  
  63.     /** 
  64.      * 列出store中所有的私鑰和公鑰 以及簽名信息 
  65.      *  
  66.      * @param ks 
  67.      * @param storePass 
  68.      * @param priKeyPass 
  69.      * @throws Exception 
  70.      */  
  71.     private void listKeyAndCertificate(KeyStore ks, String storePass,  
  72.             String priKeyPass) throws Exception {  
  73.         System.out.println("size=" + ks.size());  
  74.         Enumeration<string> enum1 = ks.aliases();  
  75.         int i = 0;  
  76.         while (enum1.hasMoreElements()) {  
  77.             String alias = enum1.nextElement();  
  78.             System.out.println("第" + (++i) + "個");  
  79.             System.out.println("alias=" + alias);  
  80.             java.security.cert.Certificate c = ks.getCertificate(alias);// alias為條目的別名  
  81.             readX509Certificate((X509Certificate) c);  
  82.             readPriKey(ks, alias, priKeyPass);  
  83.         }  
  84.     }  
  85.   
  86.     /** 
  87.      * 列出store中私鑰和cert chain信息 
  88.      *  
  89.      * @param ks 
  90.      * @param alias 
  91.      * @param pass 
  92.      * @throws Exception 
  93.      */  
  94.     private void readPriKey(KeyStore ks, String alias, String pass)  
  95.             throws Exception {  
  96.         Key key = ks.getKey(alias, pass.toCharArray());  
  97.         if (null == key) {  
  98.             System.out.println("no priviate key of " + alias);  
  99.             return;  
  100.         }  
  101.         System.out.println();  
  102.         System.out.println("algorithm=" + key.getAlgorithm());  
  103.         System.out.println("format=" + key.getFormat());  
  104.         System.out.println("toString=" + key);  
  105.         readCertChain(ks, alias);  
  106.     }  
  107.   
  108.     /** 
  109.      * 列出store中 cert chain信息 
  110.      *  
  111.      * @param ks 
  112.      * @param alias 
  113.      * @throws Exception 
  114.      */  
  115.     private void readCertChain(KeyStore ks, String alias) throws Exception {  
  116.         Certificate[] certChain = ks.getCertificateChain(alias);  
  117.         System.out.println("chain of " + alias);  
  118.         if (null == certChain) {  
  119.             System.out.println("no chain");  
  120.             return;  
  121.         }  
  122.         int i = 0;  
  123.         for (Certificate c : certChain) {  
  124.             System.out.println("index " + (i++) + " in chain of " + alias);  
  125.             readX509Certificate((X509Certificate) c);  
  126.         }  
  127.     }  
  128.   
  129.     /** 
  130.      * 列出x509Certificate的基本信息 
  131.      *  
  132.      * @param t 
  133.      */  
  134.     private void readX509Certificate(X509Certificate t) {  
  135.         System.out.println(t);  
  136.         System.out.println("輸出證書信息:\n" + t.toString());  
  137.         System.out.println("版本號:" + t.getVersion());  
  138.         System.out.println("序列號:" + t.getSerialNumber().toString(16));  
  139.         System.out.println("主體名:" + t.getSubjectDN());  
  140.         System.out.println("簽發者:" + t.getIssuerDN());  
  141.         System.out.println("有效期:" + t.getNotBefore());  
  142.         System.out.println("簽名演算法:" + t.getSigAlgName());  
  143.         byte[] sig = t.getSignature();// 簽名值  
  144.         PublicKey pk = t.getPublicKey();  
  145.         byte[] pkenc = pk.getEncoded();  
  146.         System.out.println("簽名 :");  
  147.         for (int i = 0; i < sig.length; i++)  
  148.             System.out.print(sig[i] + ",");  
  149.         System.out.println();  
  150.         System.out.println("公鑰: ");  
  151.         for (int i = 0; i < pkenc.length; i++)  
  152.             System.out.print(pkenc[i] + ",");  
  153.         System.out.println();  
  154.     }  
  155.   
  156.     /** 
  157.      * 創建一個新的keystore 
  158.      *  
  159.      * @param storePass 
  160.      * @param storeType 
  161.      *            PKCS12/JKS 
  162.      * @return 
  163.      * @throws Exception 
  164.      */  
  165.     private KeyStore createKeyStore(String storePass, String storeType)  
  166.             throws Exception {  
  167.         KeyStore ks = KeyStore.getInstance(storeType);  
  168.         ks.load(null, storePass.toCharArray());  
  169.         return ks;  
  170.     }  
  171.   
  172.     /** 
  173.      * 載入一個已有的keyStore 
  174.      *  
  175.      * @param path 
  176.      * @param storePass 
  177.      * @param storeType 
  178.      *            PKCS12/JKS 
  179.      * @return 
  180.      * @throws Exception 
  181.      */  
  182.     private KeyStore loadKeyStore(String path, String storePass,  
  183.             String storeType) throws Exception {  
  184.         FileInputStream in = new FileInputStream(path);  
  185.         KeyStore ks = KeyStore.getInstance(storeType);  
  186.         ks.load(in, storePass.toCharArray());  
  187.         in.close();  
  188.         return ks;  
  189.     }  
  190.   
  191.     /** 
  192.      * 從文件載入一個證書 
  193.      *  
  194.      * @param path 
  195.      * @param certType 
  196.      * @return 
  197.      * @throws Exception 
  198.      */  
  199.     private Certificate loadCert(String path, String certType) throws Exception {  
  200.         CertificateFactory cf = CertificateFactory.getInstance(certType);  
  201.         FileInputStream in = new FileInputStream(path);  
  202.         Certificate c = cf.generateCertificate(in);  
  203.         in.close();  
  204.         return c;  
  205.     }  
  206.   
  207.     /** 
  208.      * 生成一個由根證書簽名的store 
  209.      *  
  210.      * @param rootStore 
  211.      * @param rootAlias 
  212.      * @param rootKeyPass 
  213.      * @param subjectStr 
  214.      * @param storeType 
  215.      * @param storePass 
  216.      * @param alg 
  217.      * @param keySize 
  218.      * @param keyPass 
  219.      * @return 
  220.      * @throws Exception 
  221.      */  
  222.     public KeyStore generateSignedKeyStore(KeyStore rootStore,  
  223.             String rootAlias, String rootKeyPass, String subjectStr,  
  224.             String storeType, String storePass, String alias, String alg,  
  225.             int keySize, String keyPass) throws Exception {  
  226.   
  227.         PrivateKey rootKey = null;  
  228.         X509CertImpl rootCert = null;  
  229.         X509CertInfo rootInfo = null;  
  230.         CertificateSubjectName rootsubject = null;  
  231.         // 簽發者  
  232.         X500Name issueX500Name = new X500Name(subjectStr);  
  233.   
  234.         if (null != rootStore) {  
  235.             rootKey = (PrivateKey) rootStore.getKey(rootAlias,  
  236.                     rootKeyPass.toCharArray());  
  237.             rootCert = (X509CertImpl) rootStore.getCertificate(rootAlias);  
  238.             rootInfo = (X509CertInfo) rootCert.get(X509CertImpl.NAME + "."  
  239.                     + X509CertImpl.INFO);  
  240.             rootsubject = (CertificateSubjectName) rootInfo  
  241.                     .get(X509CertInfo.SUBJECT);  
  242.             issueX500Name = (X500Name) rootsubject  
  243.                     .get(CertificateIssuerName.DN_NAME);  
  244.         }  
  245.   
  246.         // 簽發者  
  247.         CertificateIssuerName issuerName = new CertificateIssuerName(  
  248.                 issueX500Name);  
  249.         // 被簽發者  
  250.         X500Name subjectX500Name = new X500Name(subjectStr);  
  251.         CertificateSubjectName subjectName = new CertificateSubjectName(  
  252.                 subjectX500Name);  
  253.   
  254.         // 有效期設置  
  255.         Calendar calendar = Calendar.getInstance();  
  256.         Date startDate = calendar.getTime();  
  257.         calendar.add(Calendar.DATE, 85);  
  258.         Date endDate = calendar.getTime();  
  259.         CertificateValidity certificateValidity = new CertificateValidity(  
  260.                 startDate, endDate);  
  261.   
  262.         // 序列號  
  263.         CertificateSerialNumber sn = new CertificateSerialNumber(  
  264.                 (int) (startDate.getTime() / 1000L));  
  265.   
  266.         // 版本  
  267.         CertificateVersion certVersion = new CertificateVersion(  
  268.                 CertificateVersion.V3);  
  269.   
  270.         // 演算法  
  271.         // TODO 獲取演算法的代碼有問題  
  272.         AlgorithmId algorithmId = new AlgorithmId(  
  273.                 "RSA".equals(alg) ? AlgorithmId.sha1WithRSAEncryption_oid  
  274.                         : AlgorithmId.sha1WithDSA_oid);  
  275.   
  276.         // 密鑰對  
  277.         KeyPairGenerator keygen = KeyPairGenerator.getInstance(alg);  
  278.         keygen.initialize(keySize, new SecureRandom());  
  279.         KeyPair kp = keygen.genKeyPair();  
  280.   
  281.         X509CertInfo certInfo = new X509CertInfo();  
  282.         certInfo.set("version", certVersion);  
  283.         certInfo.set("serialNumber", sn);  
  284.   
  285.         // localX500Signer.getAlgorithmId();  
  286.         certInfo.set("algorithmID", new CertificateAlgorithmId(algorithmId));  
  287.         certInfo.set("key", new CertificateX509Key(kp.getPublic()));  
  288.         certInfo.set("validity", certificateValidity);  
  289.         certInfo.set("subject", subjectName);  
  290.         certInfo.set("issuer", issuerName);  
  291.         // 擴展信息  
  292.         // if (System.getProperty("sun.security.internal.keytool.skid") !=  
  293.         // null)  
  294.         // {  
  295.         // CertificateExtensions localCertificateExtensions = new  
  296.         // CertificateExtensions();  
  297.         // localCertificateExtensions.set("SubjectKeyIdentifier", new  
  298.         // SubjectKeyIdentifierExtension(new  
  299.         // KeyIdentifier(this.publicKey).getIdentifier()));  
  300.         // certInfo.set("extensions", localCertificateExtensions);  
  301.         // }  
  302.   
  303.         X509CertImpl newcert = new X509CertImpl(certInfo);  
  304.         // TODO 這裡的簽名演算法可能有問題 貌似應該用rootcert的簽名演算法 待測試  
  305.         KeyStore ks = this.createKeyStore(storePass, storeType);  
  306.         Certificate[] certChain = null;  
  307.         // 如果rootStore為空 則生成自簽名證書  
  308.         if (null == rootStore) {  
  309.             newcert.sign(kp.getPrivate(), "SHA1WithRSA");  
  310.             certChain = new Certificate[] { newcert };  
  311.         } else {  
  312.             newcert.sign(rootKey, "SHA1WithRSA");  
  313.             certChain = new Certificate[] { newcert, rootCert };  
  314.         }  
  315.   
  316.         // ks.setCertificateEntry("zrbin", newcert);  
  317.         ks.setKeyEntry(alias, kp.getPrivate(), keyPass.toCharArray(), certChain);  
  318.         return ks;  
  319.   
  320.     }  
  321.   
  322.     @Test  
  323.     public void testReadCer() throws Exception {  
  324.         String path = "d:\\test.cer";  
  325.         String certType = "X.509";  
  326.         CertificateFactory cf = CertificateFactory.getInstance(certType);  
  327.         FileInputStream in = new FileInputStream(path);  
  328.         Collection<certificate> cs = (Collection<certificate>) cf  
  329.                 .generateCertificates(in);  
  330.         in.close();  
  331.         System.out.println("size=" + cs.size());  
  332.         for (Certificate c : cs) {  
  333.             readX509Certificate((X509Certificate) c);  
  334.         }  
  335.     }  
  336.   
  337.     @Test  
  338.     public void testReadP12() throws Exception {  
  339.         String storePass = "123456";  
  340.         String keyPass = "123456";  
  341.         String path = "d:\\zrbin.p12";  
  342.         KeyStore ks = loadKeyStore(path, storePass, "PKCS12");  
  343.         listKeyAndCertificate(ks, storePass, keyPass);  
  344.     }  
  345.   
  346.     @Test  
  347.     public void testReadKeyStore() throws Exception {  
  348.         String storePass = "123456";  
  349.         String keyPass = "123456";  
  350.         String path = "d:\\test.keystore";  
  351.         KeyStore ks = loadKeyStore(path, storePass, "JCEKS");  
  352.         listKeyAndCertificate(ks, storePass, keyPass);  
  353.     }  
  354.   
  355.     @Test  
  356.     public void testExportCert() throws FileNotFoundException, Exception {  
  357.         String pass = "123456";  
  358.         FileInputStream in = new FileInputStream("d:\\zrbin.p12");  
  359.         boolean rfc = true;  
  360.         KeyStore ks = KeyStore.getInstance("PKCS12");  
  361.         ks.load(in, pass.toCharArray());  
  362.         Certificate cert = ks.getCertificate("zrbin");  
  363.         PrintStream out = new PrintStream("D:\\zrbin.cer");  
  364.         if (rfc) {  
  365.             BASE64Encoder encoder = new BASE64Encoder();  
  366.             out.println("-----BEGIN CERTIFICATE-----");  
  367.             encoder.encodeBuffer(cert.getEncoded(),  
  368.                     out);  
  369.             out.println("-----END CERTIFICATE-----");  
  370.         } else {  
  371.             out.write(cert.getEncoded());  
  372.         }  
  373.         out.write(cert.getEncoded());  
  374.     }  
  375.   
  376.     @Test  
  377.     public void testImportCert() throws Exception {  
  378.         CertificateFactory cf = CertificateFactory.getInstance("X.509");  
  379.         FileInputStream storeIn = new FileInputStream("d:\\server.keystore");  
  380.         FileInputStream in = new FileInputStream("d:\\zrbin.cer");  
  381.         FileInputStream rootin = new FileInputStream("d:\\root.cer");  
  382.   
  383.         X509CertImpl cert = (X509CertImpl) cf.generateCertificate(in);  
  384.         X509CertImpl rootcert = (X509CertImpl) cf.generateCertificate(rootin);  
  385.   
  386.         KeyStore ks = KeyStore.getInstance("JKS");  
  387.         ks.load(null, "123456".toCharArray());  
  388.         ks.deleteEntry("zrbin");  
  389.         // ks.setCertificateEntry("zrbin", cert);  
  390.         ks.setCertificateEntry("root", rootcert);  
  391.         in.close();  
  392.         FileOutputStream out = new FileOutputStream("d:\\server.keystore");  
  393.         ks.store(out, "123456".toCharArray());  
  394.     }  
  395.   
  396.     @Test  
  397.     public void testImportSigenedCert() throws Exception {  
  398.         String alias = "test";  
  399.         CertificateFactory cf = CertificateFactory.getInstance("X.509");  
  400.         FileInputStream storeIn = new FileInputStream("d:\\test.keystore");  
  401.         KeyStore ks = KeyStore.getInstance("JKS");  
  402.         ks.load(storeIn, "123456".toCharArray());  
  403.         PrivateKey priKey = (PrivateKey) ks.getKey(alias,  
  404.                 "123456".toCharArray());  
  405.         FileInputStream in = new FileInputStream("d:\\test.cer");  
  406.         Collection<certificate> certCollection = (Collection<certificate>) cf  
  407.                 .generateCertificates(in);  
  408.         System.out.println(certCollection.size());  
  409.         if (certCollection.size() == 0) {  
  410.             System.out.println("沒有要導入的證書");  
  411.             return;  
  412.         }  
  413.         // 如果沒有對應的私鑰,直接導入certficateEntry  
  414.         if (null == priKey) {  
  415.             for (Certificate _cert : certCollection) {  
  416.                 ks.setCertificateEntry(alias, _cert);  
  417.                 break;  
  418.             }  
  419.         } else {  
  420.             Certificate importCert = null;  
  421.             for (Certificate cert : certCollection) {  
  422.                 if (ks.getCertificate(alias).getPublicKey()  
  423.                         .equals(cert.getPublicKey())) {  
  424.                     importCert = cert;  
  425.                     break;  
  426.                 }  
  427.             }  
  428.             if (null == importCert) {  
  429.                 System.out.println("錯誤:no replay cert");  
  430.             }  
  431.             certCollection.remove(importCert);  
  432.             if (X509CertImpl.isSelfSigned((X509Certificate) importCert, null)) {  
  433.                 System.out.println("證書未被ca簽名,無需導入");  
  434.             } else {  
  435.                 // 構建認證鏈  
  436.                 List<certificate> certList = new ArrayList<certificate>(  
  437.                         ks.size());  
  438.                 Map<principal certificate=""> cerMap = new HashMap<principal certificate="">();  
  439.                 Enumeration<string> aliasEnum = ks.aliases();  
  440.                 // 把不包括當前回覆的都加到map里  
  441.                 while (aliasEnum.hasMoreElements()) {  
  442.                     String _alias = aliasEnum.nextElement();  
  443.                     if (!_alias.equals(alias)) {  
  444.                         X509CertImpl _cert = (X509CertImpl) ks  
  445.                                 .getCertificate(_alias);  
  446.                         cerMap.put(_cert.getSubjectDN(), _cert);  
  447.                     }  
  448.                 }  
  449.                 for (Certificate cert : certCollection) {  
  450.                     cerMap.put(((X509Certificate) cert).getSubjectDN(), cert);  
  451.                 }  
  452.                 certList.add(importCert);  
  453.                 Principal issuerName = ((X509Certificate) importCert)  
  454.                         .getIssuerDN();  
  455.                 while (cerMap.keySet().contains(issuerName)) {  
  456.                     X509Certificate _rootCert = (X509Certificate) cerMap  
  457.                             .remove(issuerName);  
  458.                     if (null == _rootCert) {  
  459.                         System.out.println(issuerName + "的根證書為空");  
  460.                         return;  
  461.                     }  
  462.                     certList.add(_rootCert);  
  463.                     issuerName = _rootCert.getIssuerDN();  
  464.                 }  
  465.   
  466.                 X509CertImpl rootCert = (X509CertImpl) certList.get(certList  
  467.                         .size() - 1);  
  468.                 if (!X509CertImpl.isSelfSigned(rootCert, null)) {  
  469.                     System.out.println("構建證書鏈錯誤,請先導入頒發者(" + issuerName  
  470.                             + ")的CA證書");  
  471.                     return;  
  472.                 }  
  473.                 Certificate[] certChain = certList  
  474.                         .toArray(new Certificate[certList.size()]);  
  475.                 ks.setKeyEntry(alias, priKey, "123456".toCharArray(), certChain);  
  476.   
  477.             }  
  478.         }  
  479.         in.close();  
  480.         FileOutputStream out = new FileOutputStream("d:\\test.keystore");  
  481.         ks.store(out, "123456".toCharArray());  
  482.   &n
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 微服務 將整體功能按著模塊劃分成多個獨立的單元,這些單元可以獨立部署,它們之前通過輕量級的web api方式進行通訊,對於微服務框架來說,最流行的就是springcloud和Service Fabric,前者是java開發,後者是.net的產品,今天主要介紹一下springcloud! 參考文章:h ...
  • 系統介紹: 1.系統採用主流的 SSM 框架 jsp JSTL bootstrap html5 (PC瀏覽器使用) 2.springmvc +spring4.3.7+ mybaits3.3 SSM 普通java web(非maven, 附贈pom.xml文件) 資料庫:mysql 3.開發工具:my ...
  • 基於.net core 的微服務,網上很多介紹都是千篇一律基於類似webapi,通過http請求形式進行訪問,但這並不符合大家使用習慣.如何像形如[ GetService<IOrderService>().SaveOrder(orderInfo)]的方式, 調用遠程的服務,如果你正在為此苦惱, 本文 ...
  • 大型網站架構從來都不是一個預先定義的架構,而是一個演進式的架構。很少有一個網站從建站開始,就能夠因具備大型網站的所有屬性而一成不變的,從最簡單的LAMP架構,再到基於IOE的大型集中式應用架構,再演變成時下的分散式應用架構,隨著網站用戶規模的擴大,架構也在不斷演進。從實體機到虛擬機再到當前流行的Do... ...
  • 最近開始學習SpringCloud,在此把我學習的過程記錄起來,跟大家分享一下,一起學習。想學習SpringCloud的同學趕快上車吧。 本次學習使用得SpringBoot版本為2.0.3.RELEASE,SpringCloud版本為Finchley.RELEASE 創建父Maven工程 首先我們創 ...
  • 在我的理解中,面向對象就是一種萬物皆對象的編程思想,就是把現實世界中所有的事物都當做對象來看待,而每一個對象可以看成是一個事物的實例,面向對象是以對象為中心,以消息為驅動,所以程式=對象+消息; 面向對象有三大特征:封裝 繼承 多態 封裝:將屬性和行為抽象成一個類,將其屬性私有化,行為公開化,提高了 ...
  • 搭建WEB項目過程中,哪些點需要註意: 1、技術選型: 前端:freemarker、vue 後端:spring boot、spring mvc 2、如何包裝返回統一結構結果數據? 首先要弄清楚為什麼要包裝統一結構結果數據,這是因為當任意的ajax請求超時或者越權操作時,系統能返回統一的錯誤信息給到前 ...
  • Object類和常用的API 學習過程中的筆記,涉及到Objetc中的equals方法和toString方法,日期類Date,日曆類Calendar,日期格式化類SimpleDateFormat以及基本數據類型和封裝類的拆箱和裝箱,還有String與基本數據類型的轉換.有錯誤還望諒解 Object類 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...