Java通过HttpClient从外部url下载文件到本地

简介: 该Java程序旨在通过URL将外部网络文件(如图片)下载至本地,并解决防盗链问题。首先,它通过`HttpGet`请求获取远程文件,并通过设置`Referer`头防止防盗链。然后,根据响应内容类型确定文件后缀并保存至指定路径。测试表明,程序能够成功下载文件。

目标

1.将外网文件通过url转化成本地文件

如百度logo图片,右键复制图片链接https://www.baidu.com/img/flexible/logo/pc/result.png

通过代码将图片下载到本地

2.解决图片防盗链问题

防盗链如上图展示,那什么是盗链,什么是防盗链?

盗链

盗链是指在自己的网站页面上展示一些并不在自己服务器上的内容。

大白话就是自己的网站上的资源,如图片,视频等链接在别人的网址中出现,则流量和服务器压力都是走的我们自己的电脑,造成服务器压力和流量流失。

防盗链

防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让从非本站资源展示页面的资源链接失效,保证流量没必要流失。

大白话就是通过Referer或者签名来保证访问的资源都是统一站点,保证来源一致。

上代码

package com.haier.healthroom.kefu.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 一个低端小气没档次的程序狗 JavaDog
 * blog.javadog.net
 *
 * @BelongsProject: healthroom
 * @BelongsPackage: com.haier.healthroom.kefu.utils
 * @Author: hdx
 * @CreateTime: 2021-06-04 10:10
 * @Description: HttpDownload
 */
public class HttpDownloadUtil {
   
   

    public static final int cache = 10 * 1024;

    public static void main(String[] args) {
   
   
        String url = "https://www.baidu.com/img/flexible/logo/pc/result.png";
        String targetUrl = "E:\\demo\\";
        HttpDownloadUtil.download(url,targetUrl);
    }

    /**
     * 根据url下载文件,保存到filepath中
     *
     * @param url
     * @param diskUrl
     * @return
     */
    public static String download(String url, String diskUrl) {
   
   
        String filepath = "";
        String filename = "";
        try {
   
   
            HttpClient client = HttpClients.createDefault();
            HttpGet httpget = new HttpGet(url);
            // 加入Referer,防止防盗链
            httpget.setHeader("Referer", url);
            HttpResponse response = client.execute(httpget);
            HttpEntity entity = response.getEntity();
            InputStream is = entity.getContent();
            if (StringUtils.isBlank(filepath)){
   
   
                Map<String,String> map = getFilePath(response,url,diskUrl);
                filepath = map.get("filepath");
                filename = map.get("filename");
            }
            File file = new File(filepath);
            file.getParentFile().mkdirs();
            FileOutputStream fileout = new FileOutputStream(file);
            byte[] buffer = new byte[cache];
            int ch = 0;
            while ((ch = is.read(buffer)) != -1) {
   
   
                fileout.write(buffer, 0, ch);
            }
            is.close();
            fileout.flush();
            fileout.close();

        } catch (Exception e) {
   
   
            e.printStackTrace();
        }
        return filename;
    }

    /**
     * 根据contentType 获取对应的后缀 (列出常用的ContentType对应的后缀)
     *
     * @param contentType
     * @return
     */
    static String getContentType(String contentType){
   
   
        HashMap<String, String> map = new HashMap<String, String>() {
   
   
            {
   
   
                put("application/msword", ".doc");
                put("image/jpeg", ".jpeg");
                put("application/x-jpg", ".jpg");
                put("video/mpeg4", ".mp4");
                put("application/pdf", ".pdf");
                put("application/x-png", ".png");
                put("application/x-ppt", ".ppt");
                put("application/postscript", ".ps");
                put("application/vnd.android.package-archive", ".apk");
                put("video/avi", ".avi");
                put("text/html", ".htm");
                put("image/png", ".png");
                put("application/x-png", ".png");
                put("image/gif", ".gif");
            }
        };
        return map.get(contentType);

    }

    /**
     * 获取response要下载的文件的默认路径
     *
     * @param response
     * @return
     */
    public static Map<String,String> getFilePath(HttpResponse response, String url, String diskUrl) {
   
   
        Map<String,String> map = new HashMap<>();
        String filepath = diskUrl;
        String filename = getFileName(response, url);
        String contentType = response.getEntity().getContentType().getValue();
        if(StringUtils.isNotEmpty(contentType)){
   
   
            // 获取后缀
            String suffix = getContentType(contentType);
            String regEx = ".+(.+)$";
            Pattern p = Pattern.compile(regEx);
            Matcher m = p.matcher(filename);
            if (!m.find()) {
   
   
                // 如果正则匹配后没有后缀,则需要通过response中的ContentType的值进行匹配
                if(StringUtils.isNoneBlank(suffix)){
   
   
                    filename = filename + suffix;
                }
            }else{
   
   
                if(filename.length()>20){
   
   
                    filename = getRandomFileName() + suffix;
                }
            }
        }
        if (filename != null) {
   
   
            filepath += filename;
        } else {
   
   
            filepath += getRandomFileName();
        }
        map.put("filename", filename);
        map.put("filepath", filepath);
        return map;
    }

    /**
     * 获取response header中Content-Disposition中的filename值
     * @param response
     * @param url
     * @return
     */
    public static String getFileName(HttpResponse response,String url) {
   
   
        Header contentHeader = response.getFirstHeader("Content-Disposition");
        String filename = null;
        if (contentHeader != null) {
   
   
            // 如果contentHeader存在
            HeaderElement[] values = contentHeader.getElements();
            if (values.length == 1) {
   
   
                NameValuePair param = values[0].getParameterByName("filename");
                if (param != null) {
   
   
                    try {
   
   
                        filename = param.getValue();
                    } catch (Exception e) {
   
   
                        e.printStackTrace();
                    }
                }
            }
        }else{
   
   
            // 正则匹配后缀
            filename = getSuffix(url);
        }

        return filename;
    }

    /**
     * 获取随机文件名
     *
     * @return
     */
    public static String getRandomFileName() {
   
   
        return String.valueOf(System.currentTimeMillis());
    }

    /**
     * 获取文件名后缀
     * @param url
     * @return
     */
    public static String getSuffix(String url) {
   
   
        // 正则表达式“.+/(.+)$”的含义就是:被匹配的字符串以任意字符序列开始,后边紧跟着字符“/”,
        // 最后以任意字符序列结尾,“()”代表分组操作,这里就是把文件名做为分组,匹配完毕我们就可以通过Matcher
        // 类的group方法取到我们所定义的分组了。需要注意的这里的分组的索引值是从1开始的,所以取第一个分组的方法是m.group(1)而不是m.group(0)。
        String regEx = ".+/(.+)$";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(url);
        if (!m.find()) {
   
   
            // 格式错误,则随机生成个文件名
            return String.valueOf(System.currentTimeMillis());
        }
        return m.group(1);

    }
}

测试

运行main方法

目录
相关文章
|
2月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
92 4
|
1月前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
63 9
|
1月前
|
人工智能 Java 物联网
JAVA网络编程的未来:URL与URLConnection的无限可能,你准备好了吗?
随着技术的发展和互联网的普及,JAVA网络编程迎来新的机遇。本文通过案例分析,探讨URL与URLConnection在智能API调用和实时数据流处理中的关键作用,展望其未来趋势和潜力。
46 7
|
10天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
72 34
|
1月前
|
Java 开发者
JAVA高手必备:URL与URLConnection,解锁网络资源的终极秘籍!
在Java网络编程中,URL和URLConnection是两大关键技术,能够帮助开发者轻松处理网络资源。本文通过两个案例,深入解析了如何使用URL和URLConnection从网站抓取数据和发送POST请求上传数据,助力你成为真正的JAVA高手。
64 11
|
1月前
|
JSON 安全 算法
JAVA网络编程中的URL与URLConnection:那些你不知道的秘密!
在Java网络编程中,URL与URLConnection是连接网络资源的两大基石。本文通过问题解答形式,揭示了它们的深层秘密,包括特殊字符处理、请求头设置、响应体读取、支持的HTTP方法及性能优化技巧,帮助你掌握高效、安全的网络编程技能。
66 9
|
1月前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
46 4
|
1月前
|
JSON Java API
JAVA网络编程新纪元:URL与URLConnection的神级运用,你真的会了吗?
本文深入探讨了Java网络编程中URL和URLConnection的高级应用,通过示例代码展示了如何解析URL、发送GET请求并读取响应内容。文章挑战了传统认知,帮助读者更好地理解和运用这两个基础组件,提升网络编程能力。
55 5
|
2月前
|
Web App开发 Java
使用java操作浏览器的工具selenium-java和webdriver下载地址
【10月更文挑战第12天】Selenium-java依赖包用于自动化Web测试,版本为3.141.59。ChromeDriver和EdgeDriver分别用于控制Chrome和Edge浏览器,需确保版本与浏览器匹配。示例代码展示了如何使用Selenium-java模拟登录CSDN,包括设置驱动路径、添加Cookies和获取页面源码。
131 6
|
2月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
66 2
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下