java 通过指定url地址下载文件到本地工具类(包含https的数字签名请求)
java 通过指定url地址下载文件到本地工具类(包含https的数字签名请求)
XFileUtils
public class XFileUtils {
/**
* 从网络Url中下载文件
* @param urlStr url的路径
* @throws IOException
*/
public static String downLoadByUrl(String urlStr,String savePath, String fileName) {
if (StrUtil.isBlank(fileName)) {
fileName = getFileName(urlStr);
}
InputStream inputStream = null;
FileOutputStream fos = null;
try {
URL url = new URL(urlStr);
// 防止https被证书校验报错,信任所有证书
if(urlStr.contains("https")){
SslUtils.ignoreSsl();
}
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置超时间为10秒
conn.setConnectTimeout(10 * 1000);
//得到输入流
inputStream = conn.getInputStream();
//获取自己数组
byte[] getData = readInputStream(inputStream);
//文件保存位置
File saveDir = new File(savePath);
if (!saveDir.exists()) { // 没有就创建该文件
saveDir.mkdir();
}
File file = new File(saveDir + File.separator + fileName);
fos = new FileOutputStream(file);
fos.write(getData);
} catch (Exception e) {
e.printStackTrace();
} finally {
IoUtil.close(fos);
IoUtil.close(inputStream);
}
return fileName;
}
/**
* 从输入流中获取字节数组
* @param inputStream
* @return
* @throws IOException
*/
private static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[4*1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
/**
* 从src文件路径获取文件名
* @param srcRealPath src文件路径
* @return 文件名
*/
private static String getFileName(String srcRealPath){
return StringUtils.substringAfterLast(srcRealPath,"/");
}
}
测试类:
public static void main(String[] args) {
String url = "https://xxxxxxxxxxxx/kpfw/fpjfzz/v1/exportDzfpwjEwm?Wjgs=PDF&Jym=7D1E&Fphm=23512000000118158368&Czsj=1699335192593&Kprq=20231107111703";
// String url = "https://www.w3school.com.cn/example/xmle/note.xml";
String filePath = "D:\\workFile";
String fileName = XFileUtils.downLoadByUrl(url, filePath, null);
}
javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:371)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:314)
at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:309)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:654)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:396)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:480)
at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:458)
at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:201)
at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172)
at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1505)
at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1420)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:455)
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:426)
at java.base/sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:578)
at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:183)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1665)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)
at example.common.utils.XFileUtils.downLoadByUrl(XFileUtils.java:36)
at example.common.utils.XFileUtils.main(XFileUtils.java:89)
由上面的测试类,可以发现,http请求是可以正常下载文件到本地,但是如果是https,就会报错。这是因为java对SSL证书不信任造成,需要证书鉴权。这种报错有两种比较常用的解决方式。
解决java对SSL证书不信任造成报错(https)
一、运行或者打包去掉SSL证书检验(不推荐)
-Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true
二、导入证书(不推荐)
三、信任所有SSL证书(推荐)
public class SslUtils {
private static final Logger logger = LoggerFactory.getLogger(SslUtils.class);
private static void trustAllHttpsCertificates() throws Exception {
TrustManager[] trustAllCerts = new TrustManager[1];
TrustManager tm = new miTM();
trustAllCerts[0] = tm;
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
}
static class miTM implements TrustManager, X509TrustManager {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public boolean isServerTrusted(X509Certificate[] certs) {
return true;
}
public boolean isClientTrusted(X509Certificate[] certs) {
return true;
}
public void checkServerTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
public void checkClientTrusted(X509Certificate[] certs, String authType)
throws CertificateException {
return;
}
}
/**
* 忽略HTTPS请求的SSL证书,必须在openConnection之前调用
* @throws Exception
*/
public static void ignoreSsl() throws Exception{
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String urlHostName, SSLSession session) {
logger.info("Warning: URL Host: " + urlHostName + " vs. " + session.getPeerHost());
return true;
}
};
trustAllHttpsCertificates();
HttpsURLConnection.setDefaultHostnameVerifier(hv);
}
}
PS:必须在openConnection之前调用,SslUtils.ignoreSsl();
至此,通过上面的工具类就解决证书不信任,可以通过url地址下载正常下载文件