以下http工具来自jboot源码
共五个类:

HttpUtil.java

HttpRequest.java

HttpResponse.java

StringUtils.java

ArrayUtils.java

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;import javax.net.ssl.*;public class HttpUtil {/*** http get操作** @param url* @return*/public static String httpGet(String url) {return httpGet(url, null);}/*** http get操作** @param url* @param params* @return*/public static String httpGet(String url, Map<String, Object> params) {HttpRequest request = HttpRequest.create(url, params, HttpRequest.METHOD_GET);HttpResponse response = new HttpUtil().handle(request);return response.isError() ? null : response.getContent();}/*** http post 操作** @param url* @return*/public static String httpPost(String url) {return httpPost(url, null);}/*** Http post 操作** @param url* @param params post的参数,可以是文件* @return*/public static String httpPost(String url, Map<String, Object> params) {HttpRequest request = HttpRequest.create(url, params, HttpRequest.METHOD_POST);HttpResponse response = new HttpUtil().handle(request);return response.isError() ? null : response.getContent();}public HttpResponse handle(HttpRequest request) {HttpResponse response = request.getDownloadFile() == null? new HttpResponse(): new HttpResponse(request.getDownloadFile());doProcess(request, response);return response;}private void doProcess(HttpRequest request, HttpResponse response) {HttpURLConnection connection = null;InputStream stream = null;try {connection = getConnection(request);configConnection(connection, request);if (request.isGetRquest()) {connection.setInstanceFollowRedirects(true);connection.connect();}/*** 处理 post请求*/else if (request.isPostRquest()) {connection.setRequestMethod("POST");connection.setDoOutput(true);/*** 处理 非文件上传的 post 请求*/if (!request.isMultipartFormData()) {String postContent = buildParams(request);if (StringUtils.isNotEmpty(postContent)) {DataOutputStream dos = new DataOutputStream(connection.getOutputStream());dos.write(postContent.getBytes(request.getCharset()));dos.flush();dos.close();}}/*** 处理文件上传的post请求*/else {if (ArrayUtils.isNotEmpty(request.getParams())) {uploadData(request, connection);}}}stream = getInutStream(connection);response.setContentType(connection.getContentType());response.setResponseCode(connection.getResponseCode());response.setHeaders(connection.getHeaderFields());response.pipe(stream);response.finish();} catch (Throwable ex) {response.setError(ex);} finally {if (connection != null) {connection.disconnect();}if (stream != null) {try {stream.close();} catch (IOException e) {e.printStackTrace();}}}}private InputStream getInutStream(HttpURLConnection connection) throws IOException {return connection.getResponseCode() >= 400 ? connection.getErrorStream() : connection.getInputStream();}@SuppressWarnings({ "rawtypes", "resource" })private void uploadData(HttpRequest request, HttpURLConnection connection) throws IOException {String endFlag = "\r\n";String boundary = "---------" + StringUtils.uuid();connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);DataOutputStream dos = new DataOutputStream(connection.getOutputStream());for (Map.Entry entry : request.getParams().entrySet()) {if (entry.getValue() instanceof File) {File file = (File) entry.getValue();checkFileNormal(file);dos.writeBytes(boundary + endFlag);dos.writeBytes(String.format("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"", entry.getKey(), file.getName()) + endFlag);dos.writeBytes(endFlag);FileInputStream fStream = new FileInputStream(file);byte[] buffer = new byte[2028];for (int len = 0; (len = fStream.read(buffer)) > 0; ) {dos.write(buffer, 0, len);}dos.writeBytes(endFlag);} else {dos.writeBytes("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"");dos.writeBytes(endFlag);dos.writeBytes(endFlag);dos.writeBytes(String.valueOf(entry.getValue()));dos.writeBytes(endFlag);}}dos.writeBytes("--" + boundary + "--" + endFlag);}private static void checkFileNormal(File file) throws IOException {if (!file.exists()) {throw new IOException("file not exists!!!!" + file);}if (file.isDirectory()) {throw new IOException("cannot upload directory!!!!" + file);}if (!file.canRead()) {throw new IOException("cannnot read file!!!" + file);}}private static void configConnection(HttpURLConnection connection, HttpRequest request) throws ProtocolException {if (connection == null)return;connection.setReadTimeout(request.getReadTimeOut());connection.setConnectTimeout(request.getConnectTimeOut());connection.setRequestMethod(request.getMethod());connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");if (request.getHeaders() != null && request.getHeaders().size() > 0) {for (Map.Entry<String, String> entry : request.getHeaders().entrySet()) {connection.setRequestProperty(entry.getKey(), entry.getValue());}}}private static HttpURLConnection getConnection(HttpRequest request) throws IOException {try {if (request.isGetRquest()) {buildGetUrlWithParams(request);}if (request.getRequestUrl().toLowerCase().startsWith("https")) {return getHttpsConnection(request);} else {return getHttpConnection(request.getRequestUrl());}} catch (Throwable ex) {throw new IOException(ex);}}private static HttpURLConnection getHttpConnection(String urlStr) throws Exception {URL url = new URL(urlStr);HttpURLConnection conn = (HttpURLConnection) url.openConnection();return conn;}private static HttpsURLConnection getHttpsConnection(HttpRequest request) throws Exception {URL url = new URL(request.getRequestUrl());HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();if (request.getCertPath() != null && request.getCertPass() != null) {KeyStore clientStore = KeyStore.getInstance("PKCS12");clientStore.load(new FileInputStream(request.getCertPath()), request.getCertPass().toCharArray());KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());keyManagerFactory.init(clientStore, request.getCertPass().toCharArray());KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(clientStore);SSLContext sslContext = SSLContext.getInstance("TLSv1");sslContext.init(keyManagers, trustManagerFactory.getTrustManagers(), new SecureRandom());conn.setSSLSocketFactory(sslContext.getSocketFactory());} else {conn.setHostnameVerifier(hnv);SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");if (sslContext != null) {TrustManager[] tm = {trustAnyTrustManager};sslContext.init(null, tm, null);SSLSocketFactory ssf = sslContext.getSocketFactory();conn.setSSLSocketFactory(ssf);}}return conn;}private static X509TrustManager trustAnyTrustManager = new X509TrustManager() {public void checkClientTrusted(X509Certificate[] chain, String authType) {}public void checkServerTrusted(X509Certificate[] chain, String authType) {}public X509Certificate[] getAcceptedIssuers() {return null;}};private static HostnameVerifier hnv = new HostnameVerifier() {public boolean verify(String hostname, SSLSession session) {return true;}};public static String buildParams(HttpRequest request) throws UnsupportedEncodingException {Map<String, Object> params = request.getParams();if (params == null || params.isEmpty()) {return null;}StringBuilder builder = new StringBuilder();for (Map.Entry<String, Object> entry : params.entrySet()) {if (entry.getKey() != null && StringUtils.isNotBlank(entry.getValue()))builder.append(entry.getKey().trim()).append("=").append(URLEncoder.encode(entry.getValue().toString(), request.getCharset())).append("&");}if (builder.charAt(builder.length() - 1) == '&') {builder.deleteCharAt(builder.length() - 1);}return builder.toString();}public static void buildGetUrlWithParams(HttpRequest request) throws UnsupportedEncodingException {String params = buildParams(request);if (StringUtils.isBlank(params)) {return;}String originUrl = request.getRequestUrl();if (originUrl.contains("?")) {originUrl = originUrl + "&" + params;} else {originUrl = originUrl + "?" + params;}request.setRequestUrl(originUrl);}
}
import java.io.File;
import java.util.HashMap;
import java.util.Map;public class HttpRequest {public static final String METHOD_POST = "POST";public static final String METHOD_GET = "GET";public static final int READ_TIME_OUT = 1000 * 10; // 10秒public static final int CONNECT_TIME_OUT = 1000 * 5; // 5秒public static final String CHAR_SET = "UTF-8";public static final String CONTENT_TYPE_JSON = "application/json; charset=utf-8";public static final String CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded;charset=utf-8";Map<String, String> headers;Map<String, Object> params;private String requestUrl;private String certPath;private String certPass;private String method = METHOD_GET;private int readTimeOut = READ_TIME_OUT;private int connectTimeOut = CONNECT_TIME_OUT;private String charset = CHAR_SET;private boolean multipartFormData = false;private File downloadFile;private String contentType = CONTENT_TYPE_URL_ENCODED;public static HttpRequest create(String url) {return new HttpRequest(url);}public static HttpRequest create(String url, String method) {HttpRequest request = new HttpRequest(url);request.setMethod(method);return request;}public static HttpRequest create(String url, Map<String, Object> params) {HttpRequest request = new HttpRequest(url);request.setParams(params);return request;}public static HttpRequest create(String url, Map<String, Object> params, String method) {HttpRequest request = new HttpRequest(url);request.setMethod(method);request.setParams(params);return request;}public HttpRequest() {}public HttpRequest(String url) {this.requestUrl = url;}public void addParam(String key, Object value) {if (params == null) {params = new HashMap<>();}if (value instanceof File) {setMultipartFormData(true);}params.put(key, value);}public void addParams(Map<String, Object> map) {if (params == null) {params = new HashMap<>();}for (Map.Entry<String, Object> entry : map.entrySet()) {if (entry.getValue() == null) {continue;}if (entry.getValue() instanceof File) {setMultipartFormData(true);}params.put(entry.getKey(), entry.getValue());}}public void setRequestUrl(String requestUrl) {this.requestUrl = requestUrl;}public String getCertPath() {return certPath;}public void setCertPath(String certPath) {this.certPath = certPath;}public String getCertPass() {return certPass;}public void setCertPass(String certPass) {this.certPass = certPass;}public String getMethod() {return method;}public void setMethod(String method) {this.method = method;}public int getReadTimeOut() {return readTimeOut;}public void setReadTimeOut(int readTimeOut) {this.readTimeOut = readTimeOut;}public int getConnectTimeOut() {return connectTimeOut;}public void setConnectTimeOut(int connectTimeOut) {this.connectTimeOut = connectTimeOut;}public String getRequestUrl() {return requestUrl;}public Map<String, String> getHeaders() {return headers;}public void setHeaders(Map<String, String> headers) {this.headers = headers;}public void addHeader(String key, String value) {if (headers == null) {headers = new HashMap<>();}headers.put(key, value);}public Map<String, Object> getParams() {return params;}public void setParams(Map<String, Object> params) {if (params == null) {return;}for (Map.Entry<String, Object> entry : params.entrySet()) {if (entry.getValue() == null) {continue;}if (entry.getValue() instanceof File) {setMultipartFormData(true);}}this.params = params;}public boolean isGetRquest() {return METHOD_GET.equalsIgnoreCase(method);}public boolean isPostRquest() {return METHOD_POST.equalsIgnoreCase(method);}public String getCharset() {return charset;}public void setCharset(String charset) {this.charset = charset;}public boolean isMultipartFormData() {return multipartFormData;}public void setMultipartFormData(boolean multipartFormData) {this.multipartFormData = multipartFormData;}public File getDownloadFile() {return downloadFile;}public void setDownloadFile(File downloadFile) {this.downloadFile = downloadFile;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}
}
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;public class HttpResponse {private String content;private OutputStream outputStream;private File file;private Throwable error;private Map<String, List<String>> headers;private int responseCode;private String contentType;public HttpResponse() {this.outputStream = new ByteArrayOutputStream();}public HttpResponse(File file) {if (!file.getParentFile().exists()) {file.getParentFile().mkdir();}if (file.exists()) {file.delete();}try {file.createNewFile();this.file = file;this.outputStream = new FileOutputStream(file);} catch (Exception e) {setError(e);}}/*** 获取数据内容** @return*/public String getContent() {if (content != null) {return content;}if (outputStream != null && outputStream instanceof ByteArrayOutputStream) {return new String(((ByteArrayOutputStream) outputStream).toByteArray());}return null;}public void setContent(String content) {this.content = content;}/*** 把 inputStream 写入response** @param inputStream*/public void pipe(InputStream inputStream) {try {byte[] buffer = new byte[1024];for (int len = 0; (len = inputStream.read(buffer)) > 0; ) {outputStream.write(buffer, 0, len);}} catch (Throwable throwable) {setError(throwable);}}/*** 结束response和释放资源*/public void finish() {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}}public boolean isNotError() {return !isError();}public boolean isError() {return error != null;}public Throwable getError() {return error;}public void setError(Throwable error) {this.error = error;}public File getFile() {return file;}public void setFile(File file) {this.file = file;}public Map<String, List<String>> getHeaders() {return headers;}public void setHeaders(Map<String, List<String>> headers) {this.headers = headers;}public int getResponseCode() {return responseCode;}public void setResponseCode(int responseCode) {this.responseCode = responseCode;}public String getContentType() {return contentType;}public void setContentType(String contentType) {this.contentType = contentType;}
}
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class StringUtils {public static String urlDecode(String string) {try {return URLDecoder.decode(string, "UTF-8");} catch (UnsupportedEncodingException e) {}return string;}public static String urlEncode(String string) {try {return URLEncoder.encode(string, "UTF-8");} catch (UnsupportedEncodingException e) {}return string;}public static String urlRedirect(String redirect) {try {redirect = new String(redirect.getBytes("UTF-8"), "ISO8859_1");} catch (UnsupportedEncodingException e) {}return redirect;}public static boolean areNotEmpty(String... strings) {if (strings == null || strings.length == 0)return false;for (String string : strings) {if (string == null || "".equals(string)) {return false;}}return true;}public static boolean isNotEmpty(String string) {return string != null && !string.equals("");}public static boolean areNotBlank(String... strings) {if (strings == null || strings.length == 0)return false;for (String string : strings) {if (string == null || "".equals(string.trim())) {return false;}}return true;}public static boolean isNotBlank(Object o) {return o == null ? false : isNotBlank(o.toString());}public static boolean isNotBlank(String string) {return string != null && !string.trim().equals("");}public static boolean isBlank(String string) {return string == null || string.trim().equals("");}public static long toLong(String value, Long defaultValue) {try {if (value == null || "".equals(value.trim()))return defaultValue;value = value.trim();if (value.startsWith("N") || value.startsWith("n"))return -Long.parseLong(value.substring(1));return Long.parseLong(value);} catch (Exception e) {}return defaultValue;}public static int toInt(String value, int defaultValue) {try {if (value == null || "".equals(value.trim()))return defaultValue;value = value.trim();if (value.startsWith("N") || value.startsWith("n"))return -Integer.parseInt(value.substring(1));return Integer.parseInt(value);} catch (Exception e) {}return defaultValue;}public static BigInteger toBigInteger(String value, BigInteger defaultValue) {try {if (value == null || "".equals(value.trim()))return defaultValue;value = value.trim();if (value.startsWith("N") || value.startsWith("n"))return new BigInteger(value).negate();return new BigInteger(value);} catch (Exception e) {}return defaultValue;}public static boolean match(String string, String regex) {Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(string);return matcher.matches();}public static boolean isNumeric(String str) {if (str == null)return false;for (int i = str.length(); --i >= 0; ) {int chr = str.charAt(i);if (chr < 48 || chr > 57)return false;}return true;}public static boolean isEmail(String email) {return Pattern.matches("\\w+@(\\w+.)+[a-z]{2,3}", email);}public static boolean isMobileNumber(String phoneNumber) {return Pattern.matches("^(1[3,4,5,7,8])\\d{9}$", phoneNumber);}public static String escapeHtml(String text) {if (isBlank(text))return text;return text.replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;").replace("'", "'").replace("/", "/");}public static String uuid() {return UUID.randomUUID().toString().replace("-", "");}/*** 生成流水号** @param uuid 谋订单的主键ID* @return*/public static String generateSerialNumber(String uuid) {return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + Math.abs(uuid.hashCode());}public static String clearSpecialCharacter(String string) {if (isBlank(string)) {return string;}/**P:标点字符;L:字母;M:标记符号(一般不会单独出现);Z:分隔符(比如空格、换行等);S:符号(比如数学符号、货币符号等);N:数字(比如阿拉伯数字、罗马数字等);C:其他字符*/
//        return string.replaceAll("[\\pP\\pZ\\pM\\pC]", "");return string.replaceAll("[\\\\\'\"\\/\f\n\r\t]", "");}/*** 生成验证码*/public static String getValidateCode() {Random random = new Random();return String.valueOf(random.nextInt(9999 - 1000 + 1) + 1000);//为变量赋随机值1000-9999}public static Set<String> splitToSet(String src, String regex) {if (src == null) {return null;}String[] strings = src.split(regex);Set<String> set = new HashSet<>();for (String table : strings) {if (StringUtils.isBlank(table)) {continue;}set.add(table.trim());}return set;}public static void main(String[] args) {String url = "http://www.baidu.com?username=aaa";System.out.println(StringUtils.urlEncode(url));}
}
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;public class ArrayUtils {@SuppressWarnings("rawtypes")public static boolean isNotEmpty(Collection list) {return list != null && list.size() > 0;}@SuppressWarnings("rawtypes")public static boolean isNotEmpty(Map map) {return map != null && map.size() > 0;}public static boolean isNotEmpty(Object[] objects) {return objects != null && objects.length > 0;}@SuppressWarnings("rawtypes")public static boolean isNullOrEmpty(Collection list) {return list == null || list.size() == 0;}@SuppressWarnings("rawtypes")public static boolean isNullOrEmpty(Map map) {return map == null || map.size() == 0;}public static boolean isNullOrEmpty(Object[] objects) {return objects == null || objects.length == 0;}@SuppressWarnings("unchecked")public static <T> T[] concat(T[] first, T[]... rest) {int totalLength = first.length;for (T[] array : rest) {totalLength += array.length;}T[] result = Arrays.copyOf(first, totalLength);int offset = first.length;for (T[] array : rest) {System.arraycopy(array, 0, result, offset, array.length);offset += array.length;}return result;}}

Jboot学习笔记--Http工具包相关推荐

  1. Hadoop学习笔记一 简要介绍

    Hadoop学习笔记一 简要介绍 这里先大致介绍一下Hadoop.     本文大部分内容都是从官网Hadoop上来的.其中有一篇介绍HDFS的pdf文档,里面对Hadoop介绍的比较全面了.我的这一 ...

  2. MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  3. 机器学习入门学习笔记:(4.2)SVM的核函数和软间隔

    前言 之前讲了有关基本的SVM的数学模型(机器学习入门学习笔记:(4.1)SVM算法).这次主要介绍介绍svm的核函数.软间隔等概念,并进行详细的数学推导.这里仅将自己的笔记记录下来,以便以后复习查看 ...

  4. 台湾大学林轩田机器学习技法课程学习笔记4 -- Soft-Margin Support Vector Machine

    红色石头的个人网站:redstonewill.com 上节课我们主要介绍了Kernel SVM.先将特征转换和计算内积这两个步骤合并起来,简化计算.提高计算速度,再用Dual SVM的求解方法来解决. ...

  5. Spring Boot学习笔记-进阶(3)

    文章目录 Spring Boot学习笔记-进阶(3) 一.Spring Boot与缓存 二.Spring Boot与消息 三.Spring Boot与检索 四.Spring Boot与任务 异步任务 ...

  6. 【Jetson Nano学习笔记】2. ORB-SLAM3及ZED 2i驱动安装

    目录 ZED 2i驱动安装 安装驱动 自测 ROS测试 zed2i.launch rostopic list rosnode list display_zed2i.launch zed_rtabmap ...

  7. 【RK3399Pro学习笔记】十七、Debian安装ORB-SLAM3和单目demo的运行

    目录 安装OpenCV 3 注意事项 安装Glew 安装Pangolin 安装boost 安装Eigen 3 安装ORB_SLAM3 试用 平台:华硕 Thinker Edge R 瑞芯微 RK339 ...

  8. 【OS学习笔记】五 VirtualBox的下载、安装和配置

    上一篇文章学习了:计算机的启动过程(点击链接查看上一篇文章) 今天来接着上一篇文章,解决我们学习中的实验环境问题. 参考:X86汇编语言-从实模式到保护模式.作者李忠.纯学习笔记.如有侵权请联系我删除 ...

  9. Dollar toolbox 学习笔记(一)

     Dollar toolbox 学习笔记(一) Dollar toolbox工具包是dollar写的关于行人检测的MATLAB工具包,工具包是对他经典论文的实现. 可在https://pdolla ...

最新文章

  1. 带你一起学kivy第一天
  2. hive底层原理 sql执行过程_Hive mapreduce SQL实现原理——SQL最终分解为MR任务,而group by在MR里和单词统计MR没有区别了-阿里云开发者社区...
  3. 老鸟程序员才知道的40个小技巧
  4. JavaScript HTML DOM元素节点常用操作接口
  5. 学linux做笔记本,linux学习之笔记本安装CentOS7
  6. PAT甲级1016 (map,排序)
  7. 网易云信浏览器WebRTC视频聊天集成
  8. 基于`IRIS`,动态解析`HL7`消息
  9. Excel中提取单元格(括号)内的信息
  10. 记一次云服务器挖矿病毒处理过程
  11. Gradle sync failed: No variants found for ‘:app‘. Check build files to ensure at least one varian
  12. 阿里云centos7安装图形界面
  13. 网络流(最大流和最小费用流)
  14. 电力 Web SCADA 工控组态编辑器
  15. 高手帮忙啊!关于插入数据库的问题!急急!菜鸟提问!
  16. python爬虫学习_junior
  17. 军棋计算机博弈规则,军棋机器人UCT算法及计算机博弈行为研究
  18. DDD如何设计落地?(库存,产品账示例)
  19. 2022“杭电杯”中国大学生算法设计超级联赛 (1) 杭电多校第一场 2 3 4 5 8 12
  20. 嵌入式入门实践——编写简单STM32程序

热门文章

  1. linux 重建ext4分区表,修改分区和EXT4文件系统大小
  2. Magento 2 bitnami 刷新/添加/更新 模块 模板 加修复 Magento 目录 文件 权限 命令
  3. Python实现抖音关键词热度搜索小程序(附源码)
  4. 正确解决驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接
  5. CSS学习之字体属性系列
  6. 大数据24小时:美图发布区块链技术白皮书,百度副总裁邬学斌宣布离职或将加入宝能汽车
  7. 每日三题 10.13
  8. GBase8s 汉字转拼音函数
  9. Android原生TabLayout使用全解析,看这篇就够了
  10. MoeCTF2022 部分Crypto 复现