• spring boot:实现图片文件上传并生成缩略图(spring boot 2.3.1)


    一,为什么要给图片生成缩略图?

    1, 用户上传的原始图片如果太大,不能直接展示在网站页面上,

       因为不但流费server的流量,而且用户打开时非常费时间,

       所以要生成缩略图。

    2,服务端管理图片要注意的几点:

       第一点:缩略图要与原图分开存储,
       然后通过符号链接方式允许前端访问,

       否则原图被直接访问仍然存在浪费流量的问题,

       有图片版权的公司也不允许外部直接访问原图

       第二点:图片名字要加上一些随机的数字,

                 避免被穷举访问

       第三点:图片要分目录存放,通常每1000张保存到一个目录,

                因为大量的图片如果存放到同一个目录下,

                打开时会非常慢或者不能打开,

                不利于我们对文件进行管理           

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,演示项目的相关信息

    1,项目的地址:

    https://github.com/liuhongdi/imagemodify

    2,项目原理:

       实现了图片的文件上传,

       并用ImageMagick给非gif图片生成缩略图,

        用ffmpeg生成gif图片的缩略图

    3,项目结构:如图:

     

    三,ImageMagick/ffmpeg工具软件的安装

    1,dnf安装ImageMagick

    [root@blog head]# dnf install ImageMagick 

    说明:注意软件包名字中I和M均为大写

    检查软件是否安装成功?

    [root@blog head]# whereis convert
    convert: /usr/bin/convert /usr/share/man/man1/convert.1.gz 

    2,安装ffmpeg

    安装rpmfusion库

    [root@blog ~]# dnf install https://download1.rpmfusion.org/free/el/rpmfusion-free-release-8.noarch.rpm 

    下载sdl库

    [root@blog ~]# wget http://mirror.centos.org/centos/8/PowerTools/x86_64/os/Packages/SDL2-2.0.8-7.el8.x86_64.rpm

    安装sdl库:

    [root@blog ~]# rpm -ivh SDL2-2.0.8-7.el8.x86_64.rpm
    Verifying...                          ################################# [100%]
    Preparing...                          ################################# [100%]
    Updating / installing...
       1:SDL2-2.0.8-7.el8                 ################################# [100%]

    安装ffmpeg

    [root@blog ~]# dnf install ffmpeg 

    四,配置文件说明:

    1,application.properties

    #upload
    spring.servlet.multipart.maxFileSize=30MB
    spring.servlet.multipart.maxRequestSize=30MB

    说明:指定上传文件的最大限制,

    默认大小是1M

    2,nginx访问文件的host配置:file.conf

    server {
        listen       81;
        server_name  file.lhdtest.com;
        root         /data/file/html;
         location ~ .(gif|jpg|jpeg|png|bmp|ico)$ {
               root /data/file/html;
               expires 24h;
           }
        index         index.html;
        access_log      /data/logs/nginxlogs/file.access_log;
        error_log       /data/logs/nginxlogs/file.error_log;
    }

    3,Constant.java

        //图片从nginx访问时的host
        public static final String IMAGES_URL_HOST = "http://127.0.0.1:81";
        //默认原始图片的路径
        public static final String IMAGES_ORIG_DIR = "/data/file/html/images";
        //缩略图的文件路径
        public static final String IMAGES_TMB_DIR = "/data/file/html/tmb";
        //缩略图的长边长度
        public static final String IMAGES_TMB_LONG = "300";
        //分页显示时每页的显示数量
        public static final int IMAGES_PAGE_SIZE = 5;
        //ImageMagick命令的安装路径
        public static final String IMAGEMAGICK_DIR = "/usr/bin";
        //ffmpeg的完整路径
        public static final String FFMPEG_CMD = "/usr/bin/ffmpeg";

    4,创建保存图片信息的数据表:

    CREATE TABLE `image_service` (
     `image_id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '图片id',
     `image_sn` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '图片编号',
     `image_type` varchar(10) NOT NULL DEFAULT '' COMMENT '图片类型',
     `title` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',
     `size` int(11) NOT NULL DEFAULT '0' COMMENT '文件大小',
     `width` int(11) NOT NULL DEFAULT '0' COMMENT '宽度',
     `height` int(11) NOT NULL DEFAULT '0' COMMENT '高度',
     `add_time` datetime NOT NULL DEFAULT '2019-11-01 01:01:01' COMMENT '添加时间 ',
     `staff_id` int(11) NOT NULL DEFAULT '0' COMMENT '添加的用户',
     PRIMARY KEY (`image_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='图片信息表'

    五,java代码说明:

    1,ImageModifyUtil.java

    public class ImageModifyUtil {
        //按指定的边长生成缩略图
        public static boolean image_resize_by_long_side(String orig_path, String dest_path, String long_size,String imageType) {
            try {
            List<String> command = new ArrayList<>();
             String command_one = "";
            if (imageType.equals("gif")) {
                //计算得到目标宽高
                File gifFile = new File(orig_path);
                int gifWidth = 0;
                int gifHeight = 0;
                try {
                    BufferedImage imageBuffer = ImageIO.read(gifFile);
                    if (imageBuffer != null) {//如果image=null 表示上传的不是图片格式
                        gifWidth = imageBuffer.getWidth();
                        gifHeight = imageBuffer.getHeight();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                int destWidth = 0;
                int destHeight = 0;
                if (gifWidth > gifHeight) {
                    destWidth = Integer.parseInt( long_size );
                    destHeight = (destWidth*gifHeight) / gifWidth;
                } else if  (gifWidth == gifHeight) {
                    destWidth = Integer.parseInt( long_size );
                    destHeight = destWidth;
                } else {
                    destHeight = Integer.parseInt( long_size );
                    destWidth = (destHeight*gifWidth) / gifHeight;
                }
                command_one = Constant.FFMPEG_CMD+" -i "+orig_path+" -s "+destWidth+"x"+destHeight+" "+dest_path+" 2>&1";
            } else {
                command_one = Constant.IMAGEMAGICK_DIR+"/convert -size "+long_size+"x"+long_size+" -resize "+long_size+"x"+long_size+" +profile '*' -quality 85 "+orig_path+" "+dest_path+" 2>&1";
            }
            //System.out.println(command_one);
            command.add("sh");
            command.add("-c");
            command.add(command_one);
            // 执行cmd命令
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(command);
            Process process = builder.start();
            return true;
            } catch (Exception e) {
                System.out.println("save ioexception");
                e.printStackTrace();
                return false;
            }
        }
    }

    这个类用来生成缩略图

    说明:gif图生成缩略图时,我们要帮助ffmpeg计算出准确的长和宽

    2,ImageDownUtil.java

    public class ImageDownUtil {
        //按指定的路径下载一张图片
        public static void downImageByLocalPath(HttpServletResponse response,String fullImagePath,String imageName) {
            File file = new File(fullImagePath);
            if (file.exists()) {
                response.setContentType("application/force-download");// 设置强制下载不打开
                response.addHeader("Content-Disposition", "attachment;fileName=" + imageName);// 设置文件名
                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                    System.out.println("success");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    
        //按指定的文件路径显示图片
        public static ResponseEntity<InputStreamResource> dispImageByLocalPath(String fullImagePath) {
            HttpHeaders header = new HttpHeaders();
            header.setContentType(MediaType.IMAGE_JPEG);
            Path path = Paths.get(fullImagePath);
            InputStream content;
            try {
                content = Files.newInputStream(path);
                return new ResponseEntity<>(new InputStreamResource(content), header, HttpStatus.OK);
            } catch (IOException e) {
                e.printStackTrace();
                return ResponseEntity.notFound().build();
            }
        }
    }

    这个类用来下载图片和用java显示一张图片

    六,效果测试

    测试前的注意事项:

    测试前要先启动服务:

    mysql

    nginx

    1,图片上传:

    访问:

    http://127.0.0.1:8080/image/imageadd

    如图:

    2,查看已上传的图片列表

    访问:

    http://127.0.0.1:8080/image/imagelist

    如图:

    七,查看spring boot的版本

      .   ____          _            __ _ _
     /\ / ___'_ __ _ _(_)_ __  __ _    
    ( ( )\___ | '_ | '_| | '_ / _` |    
     \/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.3.1.RELEASE)
  • 相关阅读:
    Python Django :HTTP生命周期
    Docker简介及Centos 7 安装[初步配置]
    python:Django 简介。
    python :Django url /views /Template 文件介绍
    python:异常处理及程序调试
    python之正则表达式【re】
    Day 21 python :面向对象 类的相关内置函数 /单例模式 /描述符
    Day 22: 软件开发目录设计规范
    Day 20: 面向对象【多态,封装,反射】字符串模块导入/内置attr /包装 /授权
    SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth)
  • 原文地址:https://www.cnblogs.com/architectforest/p/13338022.html
Copyright © 2020-2023  润新知