一,為什么要給圖片生成縮略圖?
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)