springboot下载网络图片到本地及Linux服务器(超详细)

本文介绍了一种使用SpringBoot从远程服务器下载图片的方法,并详细解释了如何将这些图片保存到本地或Linux服务器的过程。此外,还探讨了解决图片访问延迟问题的方案。

    前言:最近做的一个项目中调用了萤石云的抓拍接口,该接口只返回了一个图片的url路径,我所需要做的是把萤石云服务器保存的图片下载下来保存到本地数据库,一开始是将图片转化为Base64格式保存到数据库,后来测试的时候发现这样效率不高,Base64是一个很庞大的字符串,仅仅存了几十张图片数据库的表都达到了20MB,另外前端页面展示的时候也有较高延迟。于是,现在要做的是将图片下载下来到本地或linux服务器,返给前端一个图片路径进行访问,提高效率,以下是博主本人在尝试该方式时遇到的一些坑,进行记录并分享给需要的猿友。

一、我先在本地做了个测试,将图片保存到项目路径下src/resources/static/images文件夹下

代码如下:

 @GetMapping("/test")
    public String test() throws Exception {
        //因为是测试,图片url可以随便搞一个,我从百度随便复制了个图片url
        String pictureUrl = "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fnimg.ws.126.net%2F%3Furl%3Dhttp%253A%252F%252Fdingyue.ws.126.net%252F2021%252F0812%252Fc8eb08e2j00qxqd8w0057c0012w00obg.jpg%26thumbnail%3D650x2147483647%26quality%3D80%26type%3Djpg&refer=http%3A%2F%2Fnimg.ws.126.net&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651129353&t=f034e15dc07748726fa861080938ec36";
        //建立图片连接
        URL url = new URL(pictureUrl);
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        //设置请求方式
        connection.setRequestMethod("GET");
        //设置超时时间
        connection.setConnectTimeout(10*1000);

        //输入流
        InputStream stream = connection.getInputStream();
        int len = 0;
        byte[] test = new byte[1024];


        //获取项目路径
        File directory = new File("src/main/resources/static/images");
        String paths = directory.getCanonicalPath();
        //如果没有文件夹则创建
        File file = new File(path);
        if (!file.exists()){
            file.mkdirs();
        }*/

        //设置图片名称,这个随意,我是用的当前时间命名
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
        String date = dateFormat.format(new Date());
        String fileName = date + ".png";

        //输出流,图片输出的目的文件
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(serverPath +"/" + fileName));

        //以流的方式上传
        while ((len =stream.read(test)) !=-1){
            fos.write(test,0,len);
        }

           
        //记得关闭流,不然消耗资源
        stream.close();
        fos.close();
        return path;
    }

调用接口后我们可以发现图片确实保存到了本地,但是此时我们直接访问是没有办法访问到图片的,因为target编译目录的images里并没有生成该图片,我们必须重启项目才可以访问到图片,这肯定是不行的。我们可以用下面这个方法来获取编译目录下的路径

String path = ResourceUtils.getURL("classpath:").getPath() + "static/images";

此时可以发先图片确实保存到了编译目录下,并且我们可以直接访问。但是,该方式仅限于本地测试写个小Demo来用,因为我们的项目终究是要打成jar包并运行在服务器上的,jar打包方式不支持将文件动态写入进去,这时需要通过映射的方式将文件上传到映射某一个文件夹,通过映射获取文件,并在页面显示。

二、springboot下载图片到linux服务器

1、此时我在配置文件中写入了一个linux服务器上的一个文件夹地址用来保存图片 serverPath

 2、在请求拦截其中配置服务器图片映射

 @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        //配置服务器图片映射
        registry.addResourceHandler("/images/**").addResourceLocations("file:"+serverPath);
        super.addResourceHandlers(registry);
    }

 3、这里跟保存到本地的代码一样,只不过路径用Linux服务器上的路径

 把红线部分的路径替换为服务器路径就可以了

@Value("${file.serverPath}")
    private String serverPath;


 //服务器上图片保存路径
        File projectFile = new File(serverPath);
        if (!projectFile.exists()){
            projectFile.mkdirs();
        }

4、到这里,我们可以运行项目并且测试一下看图片是否保存到Linux服务器并且能否访问到图片

 

 OK,测试后我已经激动的一批,看样子成功了,但是呢,当我去打开linux保存图片的文件夹,却发现下边空空如也???纳尼?我的图片没存上怎么能访问

 后来发现我们项目采用的是docker部署,图片保存到了dockers容器里的/workspace/images文件夹里, 不熟悉docker的小伙伴们可以自己去自学一下,docker容器里的文件我们必须做一个映射,把文件映射出来保存到宿主机里,不然docker容器重启的话里边存的文件就会丢失,下面是我在docker-compose-dev.yml文件中加入了一个配置,再次调用该接口,你就可以看到图片已经保存到linux服务器下的问/workspace/images里了

 # 映射图片文件
      - "/workspace/images:/workspace/images"

到这里其实可以结束了,但是呢前端要求返回的是图片全路径,这里要加上我们服务器的IP和端口号,并进行路径拼接

ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = requestAttributes.getRequest();
        //获取服务器IP
        String localAddr = request.getServerName();
        //获取服务器端口号
        int serverPort = request.getServerPort();

//此处我用的是时间命名图片
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
        String date = dateFormat.format(new Date());
        String fileName = date + ".png";

        //拼接路径,数据库中可以直接保存该路径,返回前端,前端即可访问
        String path = "http://"+localAddr +":"+ serverPort +"/api"+serverPath+ fileName;

over!感谢观看

<think>好的,我现在需要帮助用户解决如何在Spring Boot中实现从服务器下载文件到本地的功能。首先,我需要回忆一下之前的相关知识,并结合用户提供的引用内容来组织回答。 用户给出的引用内容提到了文件上传、下载和预览的实现,其中引用[1]、[2]和[3]都提到了Spring Boot Starter Web的依赖,所以这部分是基础。我需要确保在回答中包含必要的依赖配置。虽然用户现在问的是下载功能,但可能需要参考上传的部分,但这里主要是下载。 首先,实现文件下载通常涉及以下几个步骤: 1. 添加必要的依赖,比如spring-boot-starter-web,已经包含在用户的引用中,所以需要提到这一点。 2. 创建Controller层,处理HTTP请求,使用GetMapping或PostMapping映射下载路径。 3. 在Controller方法中读取服务器上的文件,并将其作为资源返回。 4. 设置HTTP响应头,指定内容类型为application/octet-stream,以及Content-Disposition,告诉浏览器这是一个附件,需要下载。 5. 处理可能的异常,比如文件不存在的情况,返回相应的错误信息。 接下来,我需要考虑代码示例的正确性。例如,使用ResourceLoader来加载文件资源,或者直接使用FileSystemResource。同时,要确保路径处理正确,可能需要使用绝对路径,或者通过配置文件指定存储位置。 另外,用户可能需要了解如何测试这个功能,比如使用Postman或浏览器直接访问URL来触发下载。还需要注意文件的大小和性能问题,比如大文件下载是否需要分块或流式传输,但可能用户暂时不需要高级部分,保持基础即可。 还要检查是否有其他相关配置,比如Spring Boot的多部分配置,但下载通常不需要,上传才需要。但确保依赖正确即可。 可能的问题点:文件路径是否正确,权限问题,跨平台路径处理(Windows和Linux的差异)。在示例中,可能需要使用绝对路径,或者在资源目录下放置文件,但资源目录通常用于静态资源,而下载可能涉及动态文件,所以最好指定一个明确的存储位置,比如系统临时目录或自定义目录。 最后,根据用户提供的引用,引用[3]提到了使用Spring MVC,所以用ResponseEntity来封装响应是合适的,可以灵活设置状态码和头部信息。 总结回答结构: 1. 添加依赖(引用已有的内容) 2. 编写Controller方法,处理下载请求 3. 示例代码,包括异常处理 4. 测试方法 5. 注意事项,如路径、异常处理等 然后生成相关问题,比如文件存储位置配置、大文件处理、安全控制等。</think>以下是使用Spring Boot实现文件下载功能的详细步骤: ### 一、添加依赖 需在pom.xml中引入基础依赖(已在引用[1][2][3]中验证): ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` ### 二、编写下载控制器 ```java @RestController public class FileDownloadController { @GetMapping("/download/{filename:.+}") public ResponseEntity<Resource> downloadFile( @PathVariable String filename, HttpServletRequest request) throws IOException { // 1.加载文件资源 Path filePath = Paths.get("/var/uploads/" + filename); Resource resource = new FileSystemResource(filePath); // 2.验证文件存在性 if (!resource.exists()) { return ResponseEntity.notFound().build(); } // 3.设置响应头 String contentType = request.getServletContext() .getMimeType(resource.getFile().getAbsolutePath()); if (contentType == null) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"") .body(resource); } } ``` ### 三、关键配置项 在application.properties中添加: ```properties # 文件存储位置(需要实际创建目录) file.upload-dir=/var/uploads/ ``` ### 四、测试验证 1. 通过浏览器访问 `http://localhost:8080/download/example.pdf` 2. 使用Postman发送GET请求: ```http GET /download/test.jpg HTTP/1.1 Host: localhost:8080 ``` ### 五、异常处理增强 建议添加全局异常处理器: ```java @ControllerAdvice public class FileExceptionHandler { @ExceptionHandler(FileNotFoundException.class) public ResponseEntity<?> handleFileNotFound() { return ResponseEntity.status(HttpStatus.NOT_FOUND) .body("File not found"); } } ```
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值