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

时间:2024-02-22 22:30:39

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

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)