From ab4f58bb3141184a8545305b12bc844fd75f49bb Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 14 Oct 2019 17:28:57 +0800 Subject: [PATCH] add method --- CHANGELOG.md | 2 + .../main/java/cn/hutool/core/io/FileUtil.java | 6 + .../main/java/cn/hutool/crypto/KeyUtil.java | 63 +++++ .../cn/hutool/db/nosql/mongo/MongoDS.java | 27 +- .../servlet/multipart/UploadSetting.java | 2 +- .../cn/hutool/extra/ssh/JschSessionPool.java | 67 +++-- .../java/cn/hutool/extra/ssh/JschUtil.java | 200 +++++++++----- .../java/cn/hutool/http/GlobalHeaders.java | 2 +- .../main/java/cn/hutool/http/HTMLFilter.java | 119 ++++---- .../java/cn/hutool/http/HttpConnection.java | 7 +- .../java/cn/hutool/http/HttpGlobalConfig.java | 6 +- .../java/cn/hutool/http/HttpInputStream.java | 2 +- .../main/java/cn/hutool/http/HttpUtil.java | 255 +++++++++--------- .../main/java/cn/hutool/log/StaticLog.java | 6 + 14 files changed, 472 insertions(+), 292 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4280b43cf..486aae4ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * 【all】 升级JDK最低 支持到8 * 【log】 Log接口添加get的static方法 * 【all】 部分接口添加FunctionalInterface修饰 +* 【crypto】 KeyUtil增加readKeyStore重载 +* 【extra】 JschUtil增加私钥传入支持(issue#INKDR@Gitee) ### Bug修复 * 【http】 修复Cookie中host失效导致的问题(issue#583@Github) diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java index d2fbdcb34..cd72ad167 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileUtil.java @@ -1549,6 +1549,12 @@ public class FileUtil { String pathToUse = StrUtil.removePrefixIgnoreCase(path, URLUtil.CLASSPATH_URL_PREFIX); // 去除file:前缀 pathToUse = StrUtil.removePrefixIgnoreCase(pathToUse, URLUtil.FILE_URL_PREFIX); + + // 识别home目录形式,并转换为绝对路径 + if(pathToUse.startsWith("~")){ + pathToUse = pathToUse.replace("~", getUserHomePath()); + } + // 统一使用斜杠 pathToUse = pathToUse.replaceAll("[/\\\\]+", StrUtil.SLASH).trim(); //兼容Windows下的共享目录路径(原始路径如果以\\开头,则保留这种路径) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java index ac6277842..defd400c0 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java @@ -1,5 +1,6 @@ package cn.hutool.crypto; +import java.io.File; import java.io.InputStream; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -32,6 +33,7 @@ import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.CharUtil; @@ -619,6 +621,20 @@ public class KeyUtil { return algorithm; } + /** + * 读取密钥库(Java Key Store,JKS) KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: http://snowolf.iteye.com/blog/391931 + * + * @param keyFile 证书文件 + * @param password 密码 + * @return {@link KeyStore} + * @since 5.0.0 + */ + public static KeyStore readJKSKeyStore(File keyFile, char[] password) { + return readKeyStore(KEY_TYPE_JKS, keyFile, password); + } + /** * 读取密钥库(Java Key Store,JKS) KeyStore文件
* KeyStore文件用于数字证书的密钥对保存
@@ -632,6 +648,53 @@ public class KeyUtil { return readKeyStore(KEY_TYPE_JKS, in, password); } + /** + * 读取PKCS12 KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存 + * + * @param keyFile 证书文件 + * @param password 密码 + * @return {@link KeyStore} + * @since 5.0.0 + */ + public static KeyStore readPKCS12KeyStore(File keyFile, char[] password) { + return readKeyStore(KEY_TYPE_PKCS12, keyFile, password); + } + + /** + * 读取PKCS12 KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存 + * + * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取 + * @param password 密码 + * @return {@link KeyStore} + * @since 5.0.0 + */ + public static KeyStore readPKCS12KeyStore(InputStream in, char[] password) { + return readKeyStore(KEY_TYPE_PKCS12, in, password); + } + + /** + * 读取KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: http://snowolf.iteye.com/blog/391931 + * + * @param type 类型 + * @param keyFile 证书文件 + * @param password 密码,null表示无密码 + * @return {@link KeyStore} + * @since 5.0.0 + */ + public static KeyStore readKeyStore(String type, File keyFile, char[] password) { + InputStream in = null; + try { + in = FileUtil.getInputStream(keyFile); + return readKeyStore(type, in, password); + } finally { + IoUtil.close(in); + } + } + /** * 读取KeyStore文件
* KeyStore文件用于数字证书的密钥对保存
diff --git a/hutool-db/src/main/java/cn/hutool/db/nosql/mongo/MongoDS.java b/hutool-db/src/main/java/cn/hutool/db/nosql/mongo/MongoDS.java index 5180d6570..da2f5a37c 100644 --- a/hutool-db/src/main/java/cn/hutool/db/nosql/mongo/MongoDS.java +++ b/hutool-db/src/main/java/cn/hutool/db/nosql/mongo/MongoDS.java @@ -1,11 +1,11 @@ package cn.hutool.db.nosql.mongo; -import java.io.Closeable; -import java.util.ArrayList; -import java.util.List; - -import org.bson.Document; - +import cn.hutool.core.exceptions.NotInitedException; +import cn.hutool.core.net.NetUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.db.DbRuntimeException; +import cn.hutool.log.Log; +import cn.hutool.setting.Setting; import com.mongodb.MongoClient; import com.mongodb.MongoClientOptions; import com.mongodb.MongoClientOptions.Builder; @@ -13,14 +13,11 @@ import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; +import org.bson.Document; -import cn.hutool.core.exceptions.NotInitedException; -import cn.hutool.core.net.NetUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.db.DbRuntimeException; -import cn.hutool.log.Log; -import cn.hutool.log.StaticLog; -import cn.hutool.setting.Setting; +import java.io.Closeable; +import java.util.ArrayList; +import java.util.List; /** * MongoDB工具类 @@ -29,7 +26,7 @@ import cn.hutool.setting.Setting; * */ public class MongoDS implements Closeable { - private final static Log log = StaticLog.get(); + private final static Log log = Log.get(); /** 默认配置文件 */ public final static String MONGO_CONFIG_PATH = "config/mongo.setting"; @@ -188,7 +185,7 @@ public class MongoDS implements Closeable { setting = new Setting(MONGO_CONFIG_PATH, true); } - final List addrList = new ArrayList(); + final List addrList = new ArrayList<>(); for (String group : groups) { addrList.add(createServerAddress(group)); } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java index 35e4f9041..1ad8fc9b4 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/multipart/UploadSetting.java @@ -14,7 +14,7 @@ import cn.hutool.setting.Setting; * */ public class UploadSetting { - private static Log log = StaticLog.get(); + private static final Log log = Log.get(); /** 默认的配置文件路径(相对ClassPath) */ public final static String DEFAULT_SETTING_PATH = "config/upload.setting"; diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java index 50930d2a8..b89f65fa6 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschSessionPool.java @@ -1,42 +1,44 @@ package cn.hutool.extra.ssh; +import cn.hutool.core.util.StrUtil; +import com.jcraft.jsch.Session; + import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; -import com.jcraft.jsch.Session; - -import cn.hutool.core.util.StrUtil; - /** * Jsch会话池 - * - * @author looly * + * @author looly */ public enum JschSessionPool { INSTANCE; - /** SSH会话池,key:host,value:Session对象 */ - private Map sessionPool = new ConcurrentHashMap(); - /** 锁 */ + /** + * SSH会话池,key:host,value:Session对象 + */ + private Map sessionPool = new ConcurrentHashMap<>(); + /** + * 锁 + */ private static final Object lock = new Object(); /** * 获取Session,不存在返回null - * + * * @param key 键 * @return Session */ public Session get(String key) { return sessionPool.get(key); } - + /** * 获得一个SSH跳板机会话,重用已经使用的会话 - * + * * @param sshHost 跳板机主机 * @param sshPort 跳板机端口 * @param sshUser 跳板机用户名 @@ -58,10 +60,35 @@ public enum JschSessionPool { return session; } + /** + * 获得一个SSH跳板机会话,重用已经使用的会话 + * + * @param sshHost 跳板机主机 + * @param sshPort 跳板机端口 + * @param sshUser 跳板机用户名 + * @param prvkey 跳板机私钥路径 + * @param passphrase 跳板机私钥密码 + * @return SSH会话 + */ + public Session getSession(String sshHost, int sshPort, String sshUser, String prvkey, byte[] passphrase) { + final String key = StrUtil.format("{}@{}:{}", sshUser, sshHost, sshPort); + Session session = get(key); + if (null == session || false == session.isConnected()) { + synchronized (lock) { + session = get(key); + if (null == session || false == session.isConnected()) { + session = JschUtil.openSession(sshHost, sshPort, sshUser, prvkey, passphrase); + put(key, session); + } + } + } + return session; + } + /** * 加入Session - * - * @param key 键 + * + * @param key 键 * @param session Session */ public void put(String key, Session session) { @@ -70,7 +97,7 @@ public enum JschSessionPool { /** * 关闭SSH连接会话 - * + * * @param key 主机,格式为user@host:port */ public void close(String key) { @@ -80,20 +107,20 @@ public enum JschSessionPool { } sessionPool.remove(key); } - + /** * 移除指定Session - * + * * @param session Session会话 * @since 4.1.15 */ public void remove(Session session) { - if(null != session) { + if (null != session) { final Iterator> iterator = this.sessionPool.entrySet().iterator(); Entry entry; - while(iterator.hasNext()) { + while (iterator.hasNext()) { entry = iterator.next(); - if(session.equals(entry.getValue())) { + if (session.equals(entry.getValue())) { iterator.remove(); break; } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java index 22176b609..ec10f4d6b 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ssh/JschUtil.java @@ -1,43 +1,41 @@ package cn.hutool.extra.ssh; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.net.LocalPortGenerater; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import com.jcraft.jsch.*; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; -import com.jcraft.jsch.Channel; -import com.jcraft.jsch.ChannelExec; -import com.jcraft.jsch.ChannelSftp; -import com.jcraft.jsch.ChannelShell; -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; - -import cn.hutool.core.io.IORuntimeException; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.net.LocalPortGenerater; -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.core.util.StrUtil; - /** * Jsch工具类
* Jsch是Java Secure Channel的缩写。JSch是一个SSH2的纯Java实现。
* 它允许你连接到一个SSH服务器,并且可以使用端口转发,X11转发,文件传输等。
- * + * * @author Looly * @since 4.0.0 */ public class JschUtil { - /** 不使用SSH的值 */ + /** + * 不使用SSH的值 + */ public final static String SSH_NONE = "none"; - /** 本地端口生成器 */ + /** + * 本地端口生成器 + */ private static final LocalPortGenerater portGenerater = new LocalPortGenerater(10000); /** * 生成一个本地端口,用于远程端口映射 - * + * * @return 未被使用的本地端口 */ public static int generateLocalPort() { @@ -46,7 +44,7 @@ public class JschUtil { /** * 获得一个SSH会话,重用已经使用的会话 - * + * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 @@ -57,9 +55,23 @@ public class JschUtil { return JschSessionPool.INSTANCE.getSession(sshHost, sshPort, sshUser, sshPass); } + /** + * 获得一个SSH会话,重用已经使用的会话 + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名 + * @param privateKeyPath 私钥路径 + * @param passphrase 私钥密码 + * @return SSH会话 + */ + public static Session getSession(String sshHost, int sshPort, String sshUser, String privateKeyPath, byte[] passphrase) { + return JschSessionPool.INSTANCE.getSession(sshHost, sshPort, sshUser, privateKeyPath, passphrase); + } + /** * 打开一个新的SSH会话 - * + * * @param sshHost 主机 * @param sshPort 端口 * @param sshUser 用户名 @@ -77,39 +89,103 @@ public class JschUtil { } /** - * 新建一个新的SSH会话 - * - * @param sshHost 主机 - * @param sshPort 端口 - * @param sshUser 机用户名 - * @param sshPass 密码 + * 打开一个新的SSH会话 + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名 + * @param privateKeyPath 私钥的路径 + * @param passphrase 私钥文件的密码,可以为null * @return SSH会话 - * @since 4.5.2 */ - public static Session createSession(String sshHost, int sshPort, String sshUser, String sshPass) { - if (StrUtil.isEmpty(sshHost) || sshPort < 0 || StrUtil.isEmpty(sshUser) || StrUtil.isEmpty(sshPass)) { - return null; - } - - Session session; + public static Session openSession(String sshHost, int sshPort, String sshUser, String privateKeyPath, byte[] passphrase) { + final Session session = createSession(sshHost, sshPort, sshUser, privateKeyPath, passphrase); try { - session = new JSch().getSession(sshUser, sshHost, sshPort); - session.setPassword(sshPass); - // 设置第一次登陆的时候提示,可选值:(ask | yes | no) - session.setConfig("StrictHostKeyChecking", "no"); + session.connect(); } catch (JSchException e) { throw new JschRuntimeException(e); } return session; } + /** + * 新建一个新的SSH会话,此方法并不打开会话(既不调用connect方法) + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名,如果为null,默认root + * @param sshPass 密码 + * @return SSH会话 + * @since 4.5.2 + */ + public static Session createSession(String sshHost, int sshPort, String sshUser, String sshPass) { + Assert.notEmpty(sshHost, "SSH Host must be not empty!"); + Assert.isTrue(sshPort < 0, "SSH Host must be not empty!"); + + // 默认root用户 + if (StrUtil.isEmpty(sshUser)) { + sshUser = "root"; + } + + final JSch jsch = new JSch(); + Session session; + try { + session = jsch.getSession(sshUser, sshHost, sshPort); + } catch (JSchException e) { + throw new JschRuntimeException(e); + } + + if (StrUtil.isNotEmpty(sshPass)) { + session.setPassword(sshPass); + } + + // 设置第一次登陆的时候提示,可选值:(ask | yes | no) + session.setConfig("StrictHostKeyChecking", "no"); + return session; + } + + /** + * 新建一个新的SSH会话,此方法并不打开会话(既不调用connect方法) + * + * @param sshHost 主机 + * @param sshPort 端口 + * @param sshUser 用户名,如果为null,默认root + * @param privateKeyPath 私钥的路径 + * @param passphrase 私钥文件的密码,可以为null + * @return SSH会话 + * @since 5.0.0 + */ + public static Session createSession(String sshHost, int sshPort, String sshUser, String privateKeyPath, byte[] passphrase) { + Assert.notEmpty(sshHost, "SSH Host must be not empty!"); + Assert.isTrue(sshPort < 0, "SSH Host must be not empty!"); + Assert.notEmpty(privateKeyPath, "PrivateKey Path must be not empty!"); + + // 默认root用户 + if (StrUtil.isEmpty(sshUser)) { + sshUser = "root"; + } + + final JSch jsch = new JSch(); + Session session; + try { + jsch.addIdentity(privateKeyPath, passphrase); + session = jsch.getSession(sshUser, sshHost, sshPort); + } catch (JSchException e) { + throw new JschRuntimeException(e); + } + + // 设置第一次登录的时候提示,可选值:(ask | yes | no) + session.setConfig("StrictHostKeyChecking", "no"); + return session; + } + /** * 绑定端口到本地。 一个会话可绑定多个端口 - * - * @param session 需要绑定端口的SSH会话 + * + * @param session 需要绑定端口的SSH会话 * @param remoteHost 远程主机 * @param remotePort 远程端口 - * @param localPort 本地端口 + * @param localPort 本地端口 * @return 成功与否 * @throws JschRuntimeException 端口绑定失败异常 */ @@ -127,8 +203,8 @@ public class JschUtil { /** * 解除端口映射 - * - * @param session 需要解除端口映射的SSH会话 + * + * @param session 需要解除端口映射的SSH会话 * @param localPort 需要解除的本地端口 * @return 解除成功与否 */ @@ -143,8 +219,8 @@ public class JschUtil { /** * 打开SSH会话,并绑定远程端口到本地的一个随机端口 - * - * @param sshConn SSH连接信息对象 + * + * @param sshConn SSH连接信息对象 * @param remoteHost 远程主机 * @param remotePort 远程端口 * @return 映射后的本地端口 @@ -162,7 +238,7 @@ public class JschUtil { /** * 打开SFTP连接 - * + * * @param session Session会话 * @return {@link ChannelSftp} * @since 4.0.3 @@ -173,7 +249,7 @@ public class JschUtil { /** * 创建Sftp - * + * * @param sshHost 远程主机 * @param sshPort 远程主机端口 * @param sshUser 远程主机用户名 @@ -187,7 +263,7 @@ public class JschUtil { /** * 创建Sftp - * + * * @param session SSH会话 * @return {@link Sftp} * @since 4.0.5 @@ -198,7 +274,7 @@ public class JschUtil { /** * 打开Shell连接 - * + * * @param session Session会话 * @return {@link ChannelShell} * @since 4.0.3 @@ -209,8 +285,8 @@ public class JschUtil { /** * 打开Channel连接 - * - * @param session Session会话 + * + * @param session Session会话 * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType} * @return {@link Channel} * @since 4.5.2 @@ -224,11 +300,11 @@ public class JschUtil { } return channel; } - + /** * 创建Channel连接 - * - * @param session Session会话 + * + * @param session Session会话 * @param channelType 通道类型,可以是shell或sftp等,见{@link ChannelType} * @return {@link Channel} * @since 4.5.2 @@ -248,9 +324,9 @@ public class JschUtil { /** * 执行Shell命令 - * + * * @param session Session会话 - * @param cmd 命令 + * @param cmd 命令 * @param charset 发送和读取内容的编码 * @return {@link ChannelExec} * @since 4.0.3 @@ -261,10 +337,10 @@ public class JschUtil { /** * 执行Shell命令 - * - * @param session Session会话 - * @param cmd 命令 - * @param charset 发送和读取内容的编码 + * + * @param session Session会话 + * @param cmd 命令 + * @param charset 发送和读取内容的编码 * @param errStream 错误信息输出到的位置 * @return {@link ChannelExec} * @since 4.3.1 @@ -294,7 +370,7 @@ public class JschUtil { /** * 关闭SSH连接会话 - * + * * @param session SSH会话 */ public static void close(Session session) { @@ -306,7 +382,7 @@ public class JschUtil { /** * 关闭会话通道 - * + * * @param channel 会话通道 * @since 4.0.3 */ @@ -318,7 +394,7 @@ public class JschUtil { /** * 关闭SSH连接会话 - * + * * @param key 主机,格式为user@host:port */ public static void close(String key) { diff --git a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java index 377c21871..917533b42 100644 --- a/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java +++ b/hutool-http/src/main/java/cn/hutool/http/GlobalHeaders.java @@ -21,7 +21,7 @@ public enum GlobalHeaders { INSTANCE; /** 存储头信息 */ - protected Map> headers = new HashMap>(); + protected Map> headers = new HashMap<>(); /** * 构造 diff --git a/hutool-http/src/main/java/cn/hutool/http/HTMLFilter.java b/hutool-http/src/main/java/cn/hutool/http/HTMLFilter.java index 379c241c0..ec9097448 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HTMLFilter.java +++ b/hutool-http/src/main/java/cn/hutool/http/HTMLFilter.java @@ -11,35 +11,30 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import cn.hutool.core.lang.Console; +import cn.hutool.core.util.CharUtil; /** + * HTML过滤器,用于去除XSS(Cross Site Scripting) 漏洞隐患。 * - * HTML filtering utility for protecting against XSS (Cross Site Scripting). + *

+ * 此类中的方法非线程安全 + *

* - * This code is licensed LGPLv3 + *
+ *     String clean = new HTMLFilter().filter(input);
+ * 
+ *

+ * 此类来自:http://xss-html-filter.sf.net * - * This code is a Java port of the original work in PHP by Cal Hendersen. http://code.iamcal.com/php/lib_filter/ - * - * The trickiest part of the translation was handling the differences in regex handling between PHP and Java. These resources were helpful in the process: - * - * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php http://www.regular-expressions.info/modifiers.html - * - * A note on naming conventions: instance variables are prefixed with a "v"; global constants are in all caps. - * - * Sample use: String input = ... String clean = new HTMLFilter().filter( input ); - * - * The class is not thread safe. Create a new instance if in doubt. - * - * If you find bugs or have suggestions on improvement (especially regarding performance), please contact us. The latest version of this source, and our contact details, can be found at - * http://xss-html-filter.sf.net - * * @author Joseph O'Connell * @author Cal Hendersen * @author Michael Semb Wever */ public final class HTMLFilter { - /** regex flag union representing /si modifiers in php **/ + /** + * regex flag union representing /si modifiers in php + **/ private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); @@ -66,29 +61,49 @@ public final class HTMLFilter { private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); // @xxx could grow large... maybe use sesat's ReferenceMap - private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap(); - private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap(); + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); - /** set of allowed html elements, along with allowed attributes for each element **/ + /** + * set of allowed html elements, along with allowed attributes for each element + **/ private final Map> vAllowed; - /** counts of open tags for each (allowable) html element **/ - private final Map vTagCounts = new HashMap(); + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); - /** html elements which must always be self-closing (e.g. "") **/ + /** + * html elements which must always be self-closing (e.g. "") + **/ private final String[] vSelfClosingTags; - /** html elements which must always have separate opening and closing tags (e.g. "") **/ + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ private final String[] vNeedClosingTags; - /** set of disallowed html elements **/ + /** + * set of disallowed html elements + **/ private final String[] vDisallowed; - /** attributes which should be checked for valid protocols **/ + /** + * attributes which should be checked for valid protocols + **/ private final String[] vProtocolAtts; - /** allowed protocols **/ + /** + * allowed protocols + **/ private final String[] vAllowedProtocols; - /** tags which should be removed if they contain no content (e.g. "" or "") **/ + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ private final String[] vRemoveBlanks; - /** entities allowed within html markup **/ + /** + * entities allowed within html markup + **/ private final String[] vAllowedEntities; - /** flag determining whether comments are allowed in input String. */ + /** + * flag determining whether comments are allowed in input String. + */ private final boolean stripComment; private final boolean encodeQuotes; private boolean vDebug = false; @@ -100,36 +115,35 @@ public final class HTMLFilter { /** * Default constructor. - * */ public HTMLFilter() { - vAllowed = new HashMap>(); + vAllowed = new HashMap<>(); - final ArrayList a_atts = new ArrayList(); + final ArrayList a_atts = new ArrayList<>(); a_atts.add("href"); a_atts.add("target"); vAllowed.put("a", a_atts); - final ArrayList img_atts = new ArrayList(); + final ArrayList img_atts = new ArrayList<>(); img_atts.add("src"); img_atts.add("width"); img_atts.add("height"); img_atts.add("alt"); vAllowed.put("img", img_atts); - final ArrayList no_atts = new ArrayList(); + final ArrayList no_atts = new ArrayList<>(); vAllowed.put("b", no_atts); vAllowed.put("strong", no_atts); vAllowed.put("i", no_atts); vAllowed.put("em", no_atts); - vSelfClosingTags = new String[] { "img" }; - vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" }; - vDisallowed = new String[] {}; - vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp. - vProtocolAtts = new String[] { "src", "href" }; - vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" }; - vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" }; + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; stripComment = true; encodeQuotes = true; alwaysMakeTags = true; @@ -202,6 +216,7 @@ public final class HTMLFilter { } // --------------------------------------------------------------- + /** * given a user submitted input String, filter out any invalid or restricted html. * @@ -292,15 +307,15 @@ public final class HTMLFilter { } m.appendTail(buf); - s = buf.toString(); - // these get tallied in processTag // (remember to reset before subsequent calls to filter method) + final StringBuilder sBuilder = new StringBuilder(buf.toString()); for (String key : vTagCounts.keySet()) { for (int ii = 0; ii < vTagCounts.get(key); ii++) { - s += ""; + sBuilder.append(""); } } + s = sBuilder.toString(); return s; } @@ -350,12 +365,12 @@ public final class HTMLFilter { // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); if (allowed(name)) { - String params = ""; + final StringBuilder params = new StringBuilder(); final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); - final List paramNames = new ArrayList(); - final List paramValues = new ArrayList(); + final List paramNames = new ArrayList<>(); + final List paramValues = new ArrayList<>(); while (m2.find()) { paramNames.add(m2.group(1)); // ([a-z0-9]+) paramValues.add(m2.group(3)); // (.*?) @@ -378,7 +393,7 @@ public final class HTMLFilter { if (inArray(paramName, vProtocolAtts)) { paramValue = processParamProtocol(paramValue); } - params += " " + paramName + "=\"" + paramValue + "\""; + params.append(CharUtil.SPACE).append(paramName).append("=\"").append(paramValue).append("\""); } } @@ -421,9 +436,9 @@ public final class HTMLFilter { final String protocol = m.group(1); if (!inArray(protocol, vAllowedProtocols)) { // bad protocol, turn into local anchor link instead - s = "#" + s.substring(protocol.length() + 1, s.length()); + s = "#" + s.substring(protocol.length() + 1); if (s.startsWith("#//")) { - s = "#" + s.substring(3, s.length()); + s = "#" + s.substring(3); } } } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java index a1c5a80c3..3aa47686b 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpConnection.java @@ -429,9 +429,8 @@ public class HttpConnection { * 当返回错误代码时,获得错误内容流 * * @return 错误内容 - * @throws IOException IO异常 */ - public InputStream getErrorStream() throws IOException { + public InputStream getErrorStream() { if (null != this.conn) { return this.conn.getErrorStream(); } @@ -514,8 +513,6 @@ public class HttpConnection { * 初始化http或https请求参数
* 有些时候htts请求会出现com.sun.net.ssl.internal.www.protocol.https.HttpsURLConnectionOldImpl的实现,此为sun内部api,按照普通http请求处理 * - * @param hostnameVerifier 域名验证器,非https传入null - * @param ssf SSLSocketFactory,非https传入null * @return {@link HttpURLConnection},https返回{@link HttpsURLConnection} */ private HttpURLConnection openHttp() throws IOException { @@ -532,7 +529,7 @@ public class HttpConnection { * 建立连接 * * @return {@link URLConnection} - * @throws IOException + * @throws IOException IO异常 */ private URLConnection openConnection() throws IOException { return (null == this.proxy) ? url.openConnection() : url.openConnection(this.proxy); diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java index 92d9b6065..b366701f4 100755 --- a/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpGlobalConfig.java @@ -1,5 +1,6 @@ package cn.hutool.http; +import java.io.Serializable; import java.net.CookieManager; import cn.hutool.http.cookie.GlobalCookieManager; @@ -10,10 +11,11 @@ import cn.hutool.http.cookie.GlobalCookieManager; * @author Looly * @since 4.6.2 */ -public class HttpGlobalConfig { +public class HttpGlobalConfig implements Serializable { + private static final long serialVersionUID = 1L; protected static int timeout = -1; - + /** * 获取全局默认的超时时长 * diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java b/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java index ea0f4fe49..120164471 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpInputStream.java @@ -18,7 +18,7 @@ import cn.hutool.core.util.StrUtil; public class HttpInputStream extends InputStream { /** 原始流 */ - private volatile InputStream in; + private InputStream in; /** * 构造 diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java index 42fbb5770..69086a467 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpUtil.java @@ -1,21 +1,5 @@ package cn.hutool.http; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Pattern; - import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.convert.Convert; @@ -25,27 +9,36 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.StreamProgress; import cn.hutool.core.map.MapUtil; import cn.hutool.core.text.StrBuilder; -import cn.hutool.core.util.CharsetUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.ReUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; +import cn.hutool.core.util.*; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.nio.charset.Charset; +import java.util.*; +import java.util.Map.Entry; +import java.util.regex.Pattern; /** * Http请求工具类 - * + * * @author xiaoleilu */ public class HttpUtil { - /** 正则:Content-Type中的编码信息 */ + /** + * 正则:Content-Type中的编码信息 + */ public static final Pattern CHARSET_PATTERN = Pattern.compile("charset\\s*=\\s*([a-z0-9-]*)", Pattern.CASE_INSENSITIVE); - /** 正则:匹配meta标签的编码信息 */ + /** + * 正则:匹配meta标签的编码信息 + */ public static final Pattern META_CHARSET_PATTERN = Pattern.compile("]*?charset\\s*=\\s*['\"]?([a-z0-9-]*)", Pattern.CASE_INSENSITIVE); /** * 检测是否https - * + * * @param url URL * @return 是否https */ @@ -55,9 +48,9 @@ public class HttpUtil { /** * 创建Http请求对象 - * + * * @param method 方法枚举{@link Method} - * @param url 请求的URL,可以使HTTP或者HTTPS + * @param url 请求的URL,可以使HTTP或者HTTPS * @return {@link HttpRequest} * @since 3.0.9 */ @@ -67,7 +60,7 @@ public class HttpUtil { /** * 创建Http GET请求对象 - * + * * @param url 请求的URL,可以使HTTP或者HTTPS * @return {@link HttpRequest} * @since 3.2.0 @@ -78,7 +71,7 @@ public class HttpUtil { /** * 创建Http POST请求对象 - * + * * @param url 请求的URL,可以使HTTP或者HTTPS * @return {@link HttpRequest} * @since 3.2.0 @@ -89,8 +82,8 @@ public class HttpUtil { /** * 发送get请求 - * - * @param urlString 网址 + * + * @param urlString 网址 * @param customCharset 自定义请求字符集,如果字符集获取不到,使用此字符集 * @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null */ @@ -100,7 +93,7 @@ public class HttpUtil { /** * 发送get请求 - * + * * @param urlString 网址 * @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null */ @@ -110,9 +103,9 @@ public class HttpUtil { /** * 发送get请求 - * + * * @param urlString 网址 - * @param timeout 超时时长,-1表示默认超时,单位毫秒 + * @param timeout 超时时长,-1表示默认超时,单位毫秒 * @return 返回内容,如果只检查状态码,正常只返回 "",不正常返回 null * @since 3.2.0 */ @@ -122,9 +115,9 @@ public class HttpUtil { /** * 发送get请求 - * + * * @param urlString 网址 - * @param paramMap post表单数据 + * @param paramMap post表单数据 * @return 返回数据 */ public static String get(String urlString, Map paramMap) { @@ -133,10 +126,10 @@ public class HttpUtil { /** * 发送get请求 - * + * * @param urlString 网址 - * @param paramMap post表单数据 - * @param timeout 超时时长,-1表示默认超时,单位毫秒 + * @param paramMap post表单数据 + * @param timeout 超时时长,-1表示默认超时,单位毫秒 * @return 返回数据 * @since 3.3.0 */ @@ -146,9 +139,9 @@ public class HttpUtil { /** * 发送post请求 - * + * * @param urlString 网址 - * @param paramMap post表单数据 + * @param paramMap post表单数据 * @return 返回数据 */ public static String post(String urlString, Map paramMap) { @@ -157,10 +150,10 @@ public class HttpUtil { /** * 发送post请求 - * + * * @param urlString 网址 - * @param paramMap post表单数据 - * @param timeout 超时时长,-1表示默认超时,单位毫秒 + * @param paramMap post表单数据 + * @param timeout 超时时长,-1表示默认超时,单位毫秒 * @return 返回数据 * @since 3.2.0 */ @@ -171,14 +164,14 @@ public class HttpUtil { /** * 发送post请求
* 请求体body参数支持两种类型: - * + * *

 	 * 1. 标准参数,例如 a=1&b=2 这种格式
 	 * 2. Rest模式,此时body需要传入一个JSON或者XML字符串,Hutool会自动绑定其对应的Content-Type
 	 * 
- * + * * @param urlString 网址 - * @param body post表单数据 + * @param body post表单数据 * @return 返回数据 */ public static String post(String urlString, String body) { @@ -188,15 +181,15 @@ public class HttpUtil { /** * 发送post请求
* 请求体body参数支持两种类型: - * + * *
 	 * 1. 标准参数,例如 a=1&b=2 这种格式
 	 * 2. Rest模式,此时body需要传入一个JSON或者XML字符串,Hutool会自动绑定其对应的Content-Type
 	 * 
- * + * * @param urlString 网址 - * @param body post表单数据 - * @param timeout 超时时长,-1表示默认超时,单位毫秒 + * @param body post表单数据 + * @param timeout 超时时长,-1表示默认超时,单位毫秒 * @return 返回数据 * @since 3.2.0 */ @@ -205,10 +198,11 @@ public class HttpUtil { } // ---------------------------------------------------------------------------------------- download + /** * 下载远程文本 - * - * @param url 请求的url + * + * @param url 请求的url * @param customCharsetName 自定义的字符集 * @return 文本 */ @@ -218,8 +212,8 @@ public class HttpUtil { /** * 下载远程文本 - * - * @param url 请求的url + * + * @param url 请求的url * @param customCharset 自定义的字符集,可以使用{@link CharsetUtil#charset} 方法转换 * @return 文本 */ @@ -229,10 +223,10 @@ public class HttpUtil { /** * 下载远程文本 - * - * @param url 请求的url + * + * @param url 请求的url * @param customCharset 自定义的字符集,可以使用{@link CharsetUtil#charset} 方法转换 - * @param streamPress 进度条 {@link StreamProgress} + * @param streamPress 进度条 {@link StreamProgress} * @return 文本 */ public static String downloadString(String url, Charset customCharset, StreamProgress streamPress) { @@ -247,8 +241,8 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url + * + * @param url 请求的url * @param dest 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 * @return 文件大小 */ @@ -258,8 +252,8 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url + * + * @param url 请求的url * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 * @return 文件大小 */ @@ -269,10 +263,10 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url + * + * @param url 请求的url * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 - * @param timeout 超时,单位毫秒,-1表示默认超时 + * @param timeout 超时,单位毫秒,-1表示默认超时 * @return 文件大小 * @since 4.0.4 */ @@ -282,9 +276,9 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url - * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 + * + * @param url 请求的url + * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 * @param streamProgress 进度条 * @return 文件大小 */ @@ -294,10 +288,10 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url - * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 - * @param timeout 超时,单位毫秒,-1表示默认超时 + * + * @param url 请求的url + * @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名 + * @param timeout 超时,单位毫秒,-1表示默认超时 * @param streamProgress 进度条 * @return 文件大小 * @since 4.0.4 @@ -318,9 +312,9 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url - * @param out 将下载内容写到输出流中 {@link OutputStream} + * + * @param url 请求的url + * @param out 将下载内容写到输出流中 {@link OutputStream} * @param isCloseOut 是否关闭输出流 * @return 文件大小 */ @@ -330,10 +324,10 @@ public class HttpUtil { /** * 下载远程文件 - * - * @param url 请求的url - * @param out 将下载内容写到输出流中 {@link OutputStream} - * @param isCloseOut 是否关闭输出流 + * + * @param url 请求的url + * @param out 将下载内容写到输出流中 {@link OutputStream} + * @param isCloseOut 是否关闭输出流 * @param streamProgress 进度条 * @return 文件大小 */ @@ -354,7 +348,7 @@ public class HttpUtil { /** * 将Map形式的Form表单数据转换为Url参数形式,不做编码 - * + * * @param paramMap 表单数据 * @return url参数 */ @@ -365,8 +359,8 @@ public class HttpUtil { /** * 将Map形式的Form表单数据转换为Url参数形式
* 编码键和值对 - * - * @param paramMap 表单数据 + * + * @param paramMap 表单数据 * @param charsetName 编码 * @return url参数 */ @@ -378,13 +372,13 @@ public class HttpUtil { * 将Map形式的Form表单数据转换为Url参数形式
* paramMap中如果key为空(null和"")会被忽略,如果value为null,会被做为空白符("")
* 会自动url编码键和值 - * + * *
 	 * key1=v1&key2=&key3=v3
 	 * 
- * + * * @param paramMap 表单数据 - * @param charset 编码 + * @param charset 编码 * @return url参数 */ public static String toParams(Map paramMap, Charset charset) { @@ -423,16 +417,15 @@ public class HttpUtil { } return sb.toString(); } - + /** * 对URL参数做编码,只编码键和值
* 提供的值可以是url附带参数,但是不能只是url - * + * *

注意,此方法只能标准化整个URL,并不适合于单独编码参数值

- * - * + * * @param paramsStr url参数,可以包含url本身 - * @param charset 编码 + * @param charset 编码 * @return 编码后的url和参数 * @since 4.0.1 */ @@ -458,17 +451,17 @@ public class HttpUtil { } paramPart = normalizeParams(paramPart, charset); - + return StrUtil.isBlank(urlPart) ? paramPart : urlPart + "?" + paramPart; } - + /** * 标准化参数字符串,即URL中?后的部分 - * + * *

注意,此方法只能标准化整个URL,并不适合于单独编码参数值

- * + * * @param paramPart 参数字符串 - * @param charset 编码 + * @param charset 编码 * @return 标准化的参数字符串 * @since 4.5.2 */ @@ -523,9 +516,9 @@ public class HttpUtil { /** * 将URL参数解析为Map(也可以解析Post中的键值对参数) - * + * * @param paramsStr 参数字符串(或者带参数的Path) - * @param charset 字符集 + * @param charset 字符集 * @return 参数Map * @since 4.0.2 */ @@ -542,9 +535,9 @@ public class HttpUtil { /** * 将URL参数解析为Map(也可以解析Post中的键值对参数) - * + * * @param paramsStr 参数字符串(或者带参数的Path) - * @param charset 字符集 + * @param charset 字符集 * @return 参数Map */ public static Map> decodeParams(String paramsStr, String charset) { @@ -558,7 +551,7 @@ public class HttpUtil { paramsStr = StrUtil.subSuf(paramsStr, pathEndPos + 1); } - final Map> params = new LinkedHashMap>(); + final Map> params = new LinkedHashMap<>(); final int len = paramsStr.length(); String name = null; int pos = 0; // 未处理字符开始位置 @@ -601,10 +594,10 @@ public class HttpUtil { /** * 将表单数据加到URL中(用于GET表单提交)
* 表单的键值对会被url编码,但是url中原参数不会被编码 - * - * @param url URL - * @param form 表单数据 - * @param charset 编码 + * + * @param url URL + * @param form 表单数据 + * @param charset 编码 * @param isEncodeParams 是否对键和值做转义处理 * @return 合成后的URL */ @@ -620,11 +613,11 @@ public class HttpUtil { /** * 将表单数据字符串加到URL中(用于GET表单提交) - * - * @param url URL + * + * @param url URL * @param queryString 表单数据字符串 - * @param charset 编码 - * @param isEncode 是否对键和值做转义处理 + * @param charset 编码 + * @param isEncode 是否对键和值做转义处理 * @return 拼接后的字符串 */ public static String urlWithForm(String url, String queryString, Charset charset, boolean isEncode) { @@ -662,7 +655,7 @@ public class HttpUtil { /** * 从Http连接的头信息中获得字符集
* 从ContentType中获取 - * + * * @param conn HTTP连接对象 * @return 字符集 */ @@ -676,14 +669,13 @@ public class HttpUtil { /** * 从流中读取内容
* 首先尝试使用charset编码读取内容(如果为空默认UTF-8),如果isGetCharsetFromContent为true,则通过正则在正文中获取编码信息,转换为指定编码; - * - * @param in 输入流 - * @param charset 字符集 + * + * @param in 输入流 + * @param charset 字符集 * @param isGetCharsetFromContent 是否从返回内容中获得编码信息 * @return 内容 - * @throws IOException IO异常 */ - public static String getString(InputStream in, Charset charset, boolean isGetCharsetFromContent) throws IOException { + public static String getString(InputStream in, Charset charset, boolean isGetCharsetFromContent) { final byte[] contentBytes = IoUtil.readBytes(in); return getString(contentBytes, charset, isGetCharsetFromContent); } @@ -691,9 +683,9 @@ public class HttpUtil { /** * 从流中读取内容
* 首先尝试使用charset编码读取内容(如果为空默认UTF-8),如果isGetCharsetFromContent为true,则通过正则在正文中获取编码信息,转换为指定编码; - * - * @param contentBytes 内容byte数组 - * @param charset 字符集 + * + * @param contentBytes 内容byte数组 + * @param charset 字符集 * @param isGetCharsetFromContent 是否从返回内容中获得编码信息 * @return 内容 */ @@ -727,11 +719,11 @@ public class HttpUtil { } return content; } - + /** * 根据文件扩展名获得MimeType - * - * @param filePath 文件路径或文件名 + * + * @param filePath 文件路径或文件名 * @param defaultValue 当获取MimeType为null时的默认值 * @return MimeType * @see FileUtil#getMimeType(String) @@ -743,7 +735,7 @@ public class HttpUtil { /** * 根据文件扩展名获得MimeType - * + * * @param filePath 文件路径或文件名 * @return MimeType * @see FileUtil#getMimeType(String) @@ -754,16 +746,16 @@ public class HttpUtil { /** * 从请求参数的body中判断请求的Content-Type类型,支持的类型有: - * + * *
 	 * 1. application/json
 	 * 1. application/xml
 	 * 
- * + * * @param body 请求参数体 * @return Content-Type类型,如果无法判断返回null - * @since 3.2.0 * @see ContentType#get(String) + * @since 3.2.0 */ public static String getContentTypeByRequestBody(String body) { final ContentType contentType = ContentType.get(body); @@ -773,20 +765,17 @@ public class HttpUtil { /** * 将键值对加入到值为List类型的Map中 - * - * @param params 参数 - * @param name key - * @param value value + * + * @param params 参数 + * @param name key + * @param value value * @param charset 编码 */ private static void addParam(Map> params, String name, String value, String charset) { name = URLUtil.decode(name, charset); value = URLUtil.decode(value, charset); - List values = params.get(name); - if (values == null) { - values = new ArrayList(1); // 一般是一个参数 - params.put(name, values); - } + final List values = params.computeIfAbsent(name, k -> new ArrayList<>(1)); + // 一般是一个参数 values.add(value); } diff --git a/hutool-log/src/main/java/cn/hutool/log/StaticLog.java b/hutool-log/src/main/java/cn/hutool/log/StaticLog.java index 49f7d07d3..02ddad43b 100644 --- a/hutool-log/src/main/java/cn/hutool/log/StaticLog.java +++ b/hutool-log/src/main/java/cn/hutool/log/StaticLog.java @@ -220,7 +220,9 @@ public final class StaticLog { * * @param clazz 日志发出的类 * @return Log + * @deprecated 请使用 {@link Log#get(Class)} */ + @Deprecated public static Log get(Class clazz) { return LogFactory.get(clazz); } @@ -230,14 +232,18 @@ public final class StaticLog { * * @param name 自定义的日志发出者名称 * @return Log + * @deprecated 请使用 {@link Log#get(String)} */ + @Deprecated public static Log get(String name) { return LogFactory.get(name); } /** * @return 获得日志,自动判定日志发出者 + * @deprecated 请使用 {@link Log#get()} */ + @Deprecated public static Log get() { return LogFactory.get(CallerUtil.getCallerCaller()); }