分享一个可以可以下载文件和发起请求的https工具

自写https请求工具

import com.alibaba.druid.support.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Random;


/**
 * https工具
 *
 * @author [email protected]
 * @version 1.0
 * @since 2020/3/2 6:36 PM
 */
@Slf4j
public class HttpsUtils {

    private HttpsUtils() {
    }

    /**
     * 将url中的协议改为https
     */
    public static String convertUrl2Https(String url) {
        if (StringUtils.isEmpty(url)) {
            return "";
        }

        return url.replaceFirst("^(?:http:)?//", "https://");
    }

    /**
     * 发起https请求
     *
     * @param url     带参数的url, 比如https://www.xxx.com?a=1
     * @param params  需要放在body中的参数,最终会转化为json格式传递
     * @param timeout 超时时间,单位是毫秒。
     * @return 请求返回的结果,json格式
     */
    public static String doHttps(String url, Map params, int timeout) {
        // 返回的结果
        StringBuilder result = new StringBuilder();


        String sendString =JSONUtils.toJSONString(params);
        log.info("do https request. url:{}, params:{}, timeout:{}", url, params, timeout);
        HttpsURLConnection urlCon = getHttpsUrlConn(url, true, timeout);
        if (urlCon == null) {
            return null;
        }
        BufferedReader in = null;
        OutputStream os = null;
        try {
            // 获取URLConnection对象对应的输出流
            os = urlCon.getOutputStream();

            //参数是键值队,放在请求的body当中
            os.write(sendString.getBytes());
            os.flush();
            // 发送请求参数
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(urlCon.getInputStream(), "UTF-8"));
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            log.error("do https fail . url:{}, params:{}, timeout:{}, e:{}", url, params, timeout, e);
            return null;
        } finally {// 使用finally块来关闭输出流、输入流
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(os);
            urlCon.disconnect();
        }
        log.info("do https request. url:{}, params:{}, timeout:{}, result:{}", url, params, timeout, result);
        return result.toString();
    }

    /**
     * 获取https连接实例
     *
     * @param url     请求的url,以https开头
     * @param isPost  为true代表使用post请求,为false代表使用get请求
     * @param timeout 超时时间
     * @return
     */
    public static HttpsURLConnection getHttpsUrlConn(String url, boolean isPost, Integer timeout) {
        HttpsURLConnection urlCon;
        try {
            // 返回指定协议的 SSLContext 对象
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            // 初始化上下文
            sslContext.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new SecureRandom());

            URL url2 = new URL(url);
            urlCon = (HttpsURLConnection) url2.openConnection();

            /*
             * 设置信任凭据,这里方法体为空,所以任何https的链接都不需要验证证书
             * 这一步的原因: 当访问HTTPS的网址。您可能已经安装了服务器证书到您的JRE的keystore
             * 但是服务器的名称与证书实际域名不相等。这通常发生在你使用的是非标准网上签发的证书。
             *
             * 解决方法:让JRE相信所有的证书和对系统的域名和证书域名。
             *
             * 如果少了这一步会报错:java.io.IOException: HTTPS hostname wrong: should be 
             */
            urlCon.setHostnameVerifier(new TrustAnyHostnameVerifier());
            //默认是get请求
            if (isPost) {
                urlCon.setRequestMethod("POST");
            }
            urlCon.setRequestProperty("Content-type", "application/json;charset=UTF-8");
            if (timeout != null) {
                //设置超时时间
                urlCon.setConnectTimeout(timeout);
                urlCon.setReadTimeout(timeout);
            }
            // 发送POST请求必须设置如下两行, get请求可以设置
            urlCon.setDoOutput(true);
            urlCon.setDoInput(true);
            urlCon.setUseCaches(false);
            // 设置当前实例使用的SSLSoctetFactory
            urlCon.setSSLSocketFactory(sslContext.getSocketFactory());
        } catch (Exception e) {
            log.error("getHttpsUrlConn fail. url:{}, timeout:{}, e:{}", url, timeout, e);
            return null;
        }
        return urlCon;
    }

    /**
     * 获取url中的文件名
     *
     * @param url https格式的url
     * @return 文件名
     */
    public static String getFileName(String url) {
        String[] arr1 = url.split("/");
        String fileName = "";
        if (arr1.length > 0) {
            fileName = arr1[arr1.length - 1];
        }
        return fileName;
    }

    /**
     * 根据https链接下载文件
     *
     * @param urlStr   https开头的链接
     * @param fileName 下载之后的文件名
     * @param savePath 文件保存的路径
     * @return 返回下载好的文件的全路径
     */
    public static String downLoadFromUrlHttps(String urlStr, String fileName,
                                              String savePath) {
        // 文件保存位置
        File saveDir = new File(savePath);
        if (!saveDir.exists()) {
            saveDir.mkdirs();
        }
        File file = new File(saveDir + File.separator + getRandomStr() + fileName);

        HttpsURLConnection conn = HttpsUtils.getHttpsUrlConn(urlStr, false, null);
        if (conn == null) {
            log.error("downLoadFromUrlHttps get HttpsURLConnection fail. url:{}, fileName:{}, savePath:{}",
                urlStr, fileName, savePath);
            return null;
        }
        try (InputStream inputStream = conn.getInputStream();
             FileOutputStream fileOutputStream = new FileOutputStream(file)) {

            IOUtils.copyLarge(inputStream, fileOutputStream);
            return file.getAbsolutePath();
        } catch (Exception e) {
            log.error("downLoadFromUrlHttps fail. url:{}, fileName:{}, savePath:{}, e:{}",
                urlStr, fileName, savePath, e);
            return null;
        } finally {
            conn.disconnect();
        }
    }

    /**
     * 生成长度为6的随机字符串
     *
     * @return 生成的字符串
     */
    private static String getRandomStr() {
        return "LAN" + getRandomInt(100, 999);
    }

    private static int getRandomInt(int min, int max) {
        return new Random().nextInt(max) % (max - min + 1) + min;
    }

    /**
     * 删除文件
     *
     * @param absolutePath 文件的绝对路径
     */
    public static void deleteFile(String absolutePath) {
        try {
            Files.delete(Paths.get(new File(absolutePath).getPath()));
        } catch (IOException e) {
            log.error("delete file fail. absolutePath:{}", absolutePath);
        }
    }


    /**
     * 里面的方法都是空的,当方法为空是默认为所有的链接都为安全,也就是所有的链接都能够访问到 当然这样有一定的安全风险,可以根据实际需要写入内容
     */
    public static class TrustAnyTrustManager implements X509TrustManager {

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            //https信任验证
            log.info("this method never throws exception, it means trust any client");
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            //https信任验证
            log.info("this method never throws exception, it means trust any client");
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    /**
     * 校验https网址是否安全
     */
    public static class TrustAnyHostnameVerifier implements HostnameVerifier {

        @Override
        public boolean verify(String hostname, SSLSession session) {
            //直接返回true,默认所有https请求都是安全的,也就是说不校验证书的正确性
            return StringUtils.isNotEmpty(hostname);
        }
    }
}

你可能感兴趣的:(java学习)