mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
add HttpDownloader
This commit is contained in:
parent
2cedffa492
commit
b14bbffa32
@ -3,7 +3,7 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.6.4 (2021-04-23)
|
||||
# 5.6.4 (2021-04-25)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 DatePattern补充DateTimeFormatter(pr#308@Gitee)
|
||||
@ -13,6 +13,7 @@
|
||||
* 【core 】 BeanUtil增加copyToList方法(issue#1526@Github)
|
||||
* 【extra 】 MailAccount增加customProperty可以用户自定义属性(pr#317@Gitee)
|
||||
* 【system 】 SystemUtil.getUserInfo()中所有平台路径统一末尾加/(issue#I3NM39@Gitee)
|
||||
* 【http 】 新增HttpDownloader,默认开启自动跳转(issue#I3NM39@Gitee)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【db 】 修复SQL分页时未使用别名导致的错误,同时count时取消order by子句(issue#I3IJ8X@Gitee)
|
||||
|
@ -130,8 +130,7 @@ public class DesensitizedUtil {
|
||||
if (StrUtil.isBlank(fullName)) {
|
||||
return StrUtil.EMPTY;
|
||||
}
|
||||
final String name = StrUtil.subPre(fullName, 1);
|
||||
return StrUtil.padAfter(name, StrUtil.length(fullName), "*");
|
||||
return StrUtil.hide(fullName, 1, fullName.length());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,8 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
/**
|
||||
* 进制转换工具类,可以转换为任意进制
|
||||
* <p>
|
||||
* 把一个十进制整数根据自己定义的进制规则进行转换<br>
|
||||
* from:https://gitee.com/loolly/hutool/pulls/260
|
||||
* <p>
|
||||
@ -107,7 +109,7 @@ public class RadixUtil {
|
||||
/**
|
||||
* 把转换后进制的字符还原成long 值
|
||||
*
|
||||
* @param radixs 自定进制,需要和encode的保持一致
|
||||
* @param radixs 自定进制,需要和encode的保持一致
|
||||
* @param encodeStr 需要转换成十进制的字符串
|
||||
* @return long
|
||||
*/
|
||||
|
@ -23,7 +23,7 @@ import java.util.ServiceLoader;
|
||||
public class ServiceLoaderUtil {
|
||||
|
||||
/**
|
||||
* 加载第一个可用服务,如果用户定义了多个接口实现类,只获取第一个不报错的服务。
|
||||
* 。加载第一个可用服务,如果用户定义了多个接口实现类,只获取第一个不报错的服务
|
||||
*
|
||||
* @param <T> 接口类型
|
||||
* @param clazz 服务接口
|
||||
|
105
hutool-http/src/main/java/cn/hutool/http/HttpDownloader.java
Normal file
105
hutool-http/src/main/java/cn/hutool/http/HttpDownloader.java
Normal file
@ -0,0 +1,105 @@
|
||||
package cn.hutool.http;
|
||||
|
||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import cn.hutool.core.io.StreamProgress;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 下载封装,下载统一使用{@code GET}请求,默认支持30x跳转
|
||||
*
|
||||
* @since 5.6.4
|
||||
* @author looly
|
||||
*/
|
||||
public class HttpDownloader {
|
||||
|
||||
/**
|
||||
* 下载远程文本
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param customCharset 自定义的字符集,可以使用{@code CharsetUtil#charset} 方法转换
|
||||
* @param streamPress 进度条 {@link StreamProgress}
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, Charset customCharset, StreamProgress streamPress) {
|
||||
final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
download(url, out, true, streamPress);
|
||||
return null == customCharset ? out.toString() : out.toString(customCharset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件数据,支持30x跳转
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @return 文件数据
|
||||
*/
|
||||
public static byte[] downloadBytes(String url) {
|
||||
return requestDownload(url, -1).bodyBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownload(url, timeout).writeBody(destFile, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件,返回文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件
|
||||
*/
|
||||
public static File downloadForFile(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownload(url, timeout).writeBodyForFile(destFile, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param out 将下载内容写到输出流中 {@link OutputStream}
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
* @param streamProgress 进度条
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut, StreamProgress streamProgress) {
|
||||
Assert.notNull(out, "[out] is null !");
|
||||
|
||||
return requestDownload(url, -1).writeBody(out, isCloseOut, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求下载文件
|
||||
*
|
||||
* @param url 请求下载文件地址
|
||||
* @param timeout 超时时间
|
||||
* @return HttpResponse
|
||||
* @since 5.4.1
|
||||
*/
|
||||
private static HttpResponse requestDownload(String url, int timeout) {
|
||||
Assert.notBlank(url, "[url] is blank !");
|
||||
|
||||
final HttpResponse response = HttpUtil.createGet(url, true)
|
||||
.timeout(timeout)
|
||||
.executeAsync();
|
||||
|
||||
if (response.isOk()) {
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new HttpException("Server response error with status code: [{}]", response.getStatus());
|
||||
}
|
||||
}
|
@ -278,10 +278,27 @@ public class HttpResponse extends HttpBase<HttpResponse> implements Closeable {
|
||||
Assert.notNull(destFile, "[destFile] is null!");
|
||||
|
||||
final File outFile = completeFileNameFromHeader(destFile);
|
||||
final OutputStream outputStream = FileUtil.getOutputStream(outFile);
|
||||
return writeBody(outputStream, true, streamProgress);
|
||||
return writeBody(FileUtil.getOutputStream(outFile), true, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
* 异步模式下直接读取Http流写出,同步模式下将存储在内存中的响应内容写出<br>
|
||||
* 写出后会关闭Http流(异步模式)
|
||||
*
|
||||
* @param destFile 写出到的文件
|
||||
* @param streamProgress 进度显示接口,通过实现此接口显示下载进度
|
||||
* @return 写出的文件
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public File writeBodyForFile(File destFile, StreamProgress streamProgress) {
|
||||
Assert.notNull(destFile, "[destFile] is null!");
|
||||
|
||||
final File outFile = completeFileNameFromHeader(destFile);
|
||||
writeBody(FileUtil.getOutputStream(outFile), true, streamProgress);
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将响应内容写出到文件<br>
|
||||
|
@ -2,11 +2,9 @@ package cn.hutool.http;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.StreamProgress;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.net.url.UrlQuery;
|
||||
import cn.hutool.core.text.StrBuilder;
|
||||
@ -85,7 +83,19 @@ public class HttpUtil {
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static HttpRequest createGet(String url) {
|
||||
return HttpRequest.get(url);
|
||||
return createGet(url, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建Http GET请求对象
|
||||
*
|
||||
* @param url 请求的URL,可以使HTTP或者HTTPS
|
||||
* @param isFollowRedirects 是否打开重定向
|
||||
* @return {@link HttpRequest}
|
||||
* @since 5.6.4
|
||||
*/
|
||||
public static HttpRequest createGet(String url, boolean isFollowRedirects) {
|
||||
return HttpRequest.get(url).setFollowRedirects(isFollowRedirects);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,13 +259,7 @@ public class HttpUtil {
|
||||
* @return 文本
|
||||
*/
|
||||
public static String downloadString(String url, Charset customCharset, StreamProgress streamPress) {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
throw new NullPointerException("[url] is null!");
|
||||
}
|
||||
|
||||
FastByteArrayOutputStream out = new FastByteArrayOutputStream();
|
||||
download(url, out, true, streamPress);
|
||||
return null == customCharset ? out.toString() : out.toString(customCharset);
|
||||
return HttpDownloader.downloadString(url, customCharset, streamPress);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -316,63 +320,59 @@ public class HttpUtil {
|
||||
* @since 4.0.4
|
||||
*/
|
||||
public static long downloadFile(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
return requestDownloadFile(url, destFile, timeout).writeBody(destFile, streamProgress);
|
||||
return HttpDownloader.downloadFile(url, destFile, timeout, streamProgress);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param dest 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
*
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, String dest) {
|
||||
return downloadFileFromUrl(url, FileUtil.file(dest));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
*
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile) {
|
||||
return downloadFileFromUrl(url, destFile, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
*
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, int timeout) {
|
||||
return downloadFileFromUrl(url, destFile, timeout, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param streamProgress 进度条
|
||||
*
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, StreamProgress streamProgress) {
|
||||
return downloadFileFromUrl(url, destFile, -1, streamProgress);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
@ -380,47 +380,19 @@ public class HttpUtil {
|
||||
* @param destFile 目标文件或目录,当为目录时,取URL中的文件名,取不到使用编码后的URL做为文件名
|
||||
* @param timeout 超时,单位毫秒,-1表示默认超时
|
||||
* @param streamProgress 进度条
|
||||
*
|
||||
* @return 下载的文件对象
|
||||
* @since 5.4.1
|
||||
*/
|
||||
public static File downloadFileFromUrl(String url, File destFile, int timeout, StreamProgress streamProgress) {
|
||||
HttpResponse response = requestDownloadFile(url, destFile, timeout);
|
||||
|
||||
final File outFile = response.completeFileNameFromHeader(destFile);
|
||||
long writeBytes = response.writeBody(outFile, streamProgress);
|
||||
return outFile;
|
||||
return HttpDownloader.downloadForFile(url, destFile, timeout, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求下载文件
|
||||
*
|
||||
* @param url 请求下载文件地址
|
||||
* @param destFile 目标目录或者目标文件
|
||||
* @param timeout 超时时间
|
||||
*
|
||||
* @return HttpResponse
|
||||
* @since 5.4.1
|
||||
*/
|
||||
private static HttpResponse requestDownloadFile(String url, File destFile, int timeout) {
|
||||
Assert.notBlank(url, "[url] is blank !");
|
||||
Assert.notNull(destFile, "[destFile] is null !");
|
||||
|
||||
final HttpResponse response = HttpRequest.get(url).timeout(timeout).executeAsync();
|
||||
if (response.isOk()) {
|
||||
return response;
|
||||
}
|
||||
|
||||
throw new HttpException("Server response error with status code: [{}]", response.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载远程文件
|
||||
*
|
||||
* @param url 请求的url
|
||||
* @param out 将下载内容写到输出流中 {@link OutputStream}
|
||||
* @param isCloseOut 是否关闭输出流
|
||||
*
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut) {
|
||||
@ -437,40 +409,18 @@ public class HttpUtil {
|
||||
* @return 文件大小
|
||||
*/
|
||||
public static long download(String url, OutputStream out, boolean isCloseOut, StreamProgress streamProgress) {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
throw new NullPointerException("[url] is null!");
|
||||
}
|
||||
if (null == out) {
|
||||
throw new NullPointerException("[out] is null!");
|
||||
}
|
||||
|
||||
final HttpResponse response = HttpRequest.get(url).executeAsync();
|
||||
if (!response.isOk()) {
|
||||
throw new HttpException("Server response error with status code: [{}]", response.getStatus());
|
||||
}
|
||||
return response.writeBody(out, isCloseOut, streamProgress);
|
||||
return HttpDownloader.download(url, out, isCloseOut, streamProgress);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载远程文件数据,支持30x跳转
|
||||
*
|
||||
* @param url 请求的url
|
||||
*
|
||||
* @return 文件数据
|
||||
*
|
||||
* @since 5.3.6
|
||||
*/
|
||||
public static byte[] downloadBytes(String url) {
|
||||
if (StrUtil.isBlank(url)) {
|
||||
throw new NullPointerException("[url] is null!");
|
||||
}
|
||||
|
||||
final HttpResponse response = HttpRequest.get(url)
|
||||
.setFollowRedirects(true).executeAsync();
|
||||
if (!response.isOk()) {
|
||||
throw new HttpException("Server response error with status code: [{}]", response.getStatus());
|
||||
}
|
||||
return response.bodyBytes();
|
||||
return HttpDownloader.downloadBytes(url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -880,11 +830,11 @@ public class HttpUtil {
|
||||
*
|
||||
* @param username 账号
|
||||
* @param password 密码
|
||||
* @param charset 编码(如果账号或密码中有非ASCII字符适用)
|
||||
* @param charset 编码(如果账号或密码中有非ASCII字符适用)
|
||||
* @return 密码验证信息
|
||||
* @since 5.4.6
|
||||
*/
|
||||
public static String buildBasicAuth(String username, String password, Charset charset){
|
||||
public static String buildBasicAuth(String username, String password, Charset charset) {
|
||||
final String data = username.concat(":").concat(password);
|
||||
return "Basic " + Base64.encode(data, charset);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user