前言:最近做的一个项目中调用了萤石云的抓拍接口,该接口只返回了一个图片的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!感谢观看

Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐