圖床小世界(基於Java Servlet搭建的圖片伺服器)
文章目錄
一、前言
1)背景需求
-
在我們的日常生活或者工作過程中,有時候我們需要在寫部落格或者寫文件的時候需要插入圖片,這個時候我們就需要給定一個連結就把圖片的內容獲取出來。
-
這個伺服器可以進行把我們的圖片進行上傳,下載,檢視等等操作,可以適當的作為一個雲儲存圖片的地方。
2)重要知識點
- 簡單的Web伺服器設計的能力
- 通過JDBC來操作MySQL資料庫
- 進行資料庫的設計
- Gson庫的使用,更好的去理解JSON
- 強化對HTTP協議的理解
- 對Servlet的理解及使用
- 基於Md5對圖片進行校驗
- 加深對Postman,Filddler,Tomcat工具的使用
- 軟體測試的基本理解和方法
二、專案設計
1)整體架構及設計
- 核心就是一個HTTP伺服器,提供對圖片的增刪改查操作,同時搭配簡單的前端頁面輔助完成圖片的操作展示。
2)資料庫設計
資料庫的屬性:
圖片編號:imageId --> int型非空且自增
圖片的名字:imageName --> varchar(50)
圖片的大小:size --> int型
圖片的上傳時間:uploadTime varchar(50)
圖片正文型別:contentType varchar(50)
圖片路徑:path varchar(1024)
校驗和:md5演算法:圖片的md5校驗和 --> varchar(1024)
-
資料庫儲存的是圖片的屬性(元資訊),而圖片正文是以檔案的形式直接存在磁碟上的,當有一個圖片上傳到伺服器上時,資料庫就記錄一個path對應到磁碟上的這個檔案
校驗和:通過一個更短的字串,來驗證整體資料是否正確。短的字串是根據原串內容通過一定的規則來計算出來的 這是一種常見字串 hash 演算法, 具有三個特性: 1.不管源字串多長, 得到的最終 md5 值都是固定長度 2.源字串稍微變化一點點內容, md5 值會變化很大(降低衝突概率) 3.通過原字串很容易計算得到 md5 值, 但是根據 md5 推匯出原字串很難(幾乎不可能).
3)伺服器 API 設計(前後端互動介面設計)
3.1 Gson的使用
- 這裡我們使用JSON來組織資料。Json 是一種常見是資料格式組織方式. 源於 JavaScript, 是一種鍵值對風格的資料格式.
- Java 中可以使用 Gson 庫來完成 Json 的解析和構造.
在Maven 中新增 Gson 的依賴
一般的時候它會是這個樣子:
3.2 新增圖片
我們先寫一個簡單的 html 來實現上傳圖片
3.3 檢視所有圖片元資訊
3.4 檢視指定圖片元資訊
3.5 刪除圖片
3.6 檢視圖片內容
4)進行原始碼的開發
4.1 封裝資料庫操作
4.1.1 建立dao包
(1)先建立DBUtil類實現了封裝獲取資料庫連線的操作
- 建立一個單例類DBUtail輔助建立連線,其中URL為我的雲伺服器的MySQL連結
-
這個類主要包含3個方法:
建立DateSource的例項:DataSource getDataSource() 獲取連線:Connection getConnection() 關閉連線:void close(Connection connection, PreparedStatement statement, ResultSet resultSet) 這裡關閉的時候要注意:先建立的物件後關閉,後建立的物件先關閉 close也不是真的銷燬連線,只是回收到池子裡了,後邊還可以用,因為DataSource內建了連線池
(2)建立Image類,每一個image物件對應到一個圖片物件(包含圖片的相關屬性)
(3)建立imageDao類:作為image物件的管理器,藉助這個類完成image物件的增刪改查操作
(4)使用JDBC的時候是用DataSourse訪問資料庫的,稍微要比JDBCDriver方式高效一些
(5)當寫完一組功能後用單元測試的思想進行測試,也就是將一個類或者方法作為一個單元,然後分開測試,一旦出現了問題,就能及時發現BUG。
4.1.2 瞭解加回顧
-
回顧:受查異常與非受查異常
出現異常之後,處理的具體措施: 1)當前接觸的大部分都是列印呼叫棧 2)讓程式直接直接終止:及時止損 3)監控報警通知程式猿
-
瞭解jar與war包:類似於zip這樣的壓縮包,也就是將一大堆.class檔案放到一起打包成一個檔案
-
使用maven打包成war包放在伺服器上的Tomcat的安裝目錄裡的webapps目錄下
4.2 基於Servlet來搭建伺服器
Servlet負責處理客戶端發來的請求,生成伺服器所需要生成的響應
4.2.1 建立api包
(1)在包下建立ImageServlet類繼承HttpServlet父類並且重寫這個父類中的一些方法,完成圖片的增刪改查
- 這個類的 doPost 對應插入圖片, doGet 對應檢視圖片資訊, doDelete 對應刪除圖片.
- 這裡的doGet要分成兩種情況, 一個是獲取所有圖片資訊, 一個是獲取單個圖片資訊,根據請求中是否帶有 image_id 引數來決定
- 記得將這個類加到web.xml中,其中的類名要寫完整的帶包的名字
(2)在包下建立ImageShowServlet類繼承HttpServlet父類並且重寫這個父類中的doGet方法實現展示圖片詳細內容
4.2.2 瞭解加回顧
-
對Servlet的理解:
Servlet相關的程式碼執行方式和平時寫的不太一樣,平時的程式碼是從main方法執行的,而Servlet裡面沒有main方法,而是靠Tomcat來自動呼叫到Servlet的程式碼,Tomcat的工作原理和曾經寫的Http伺服器是很相似的 -
Tomcat的工作步驟:
(1)啟動的時候要繫結埠號(一般是8080)
(2)進入一個迴圈
(3)在主迴圈裡面,呼叫accept獲取到當前的請求的連結
(4)讀取客戶端發生的資料(字串)
(5)把這個字串按照Http協議來進行解析
(6)解析出的Http請求的方法和URL之後,找到對應的Servlet,並執行對應的doXXX方法
(7)生成響應,回覆客戶端 -
理解Tomcat中URL與Servlet的對映關係,步驟如下:
(1)Tomcat根據URL查詢對映關係表(在那個web.xml檔案中),找到api.ImageServlet類
(2)Tomcat根據get方法,決定給你api.ImageServlet類建立一個物件,並且呼叫其中的doGet方法(這個方法我們一般要進行重寫)
(3)執行doGet方法,往resp物件中寫入一些內容
(4)Tomcat構造resp物件,根據這個物件生成Http響應報文,再通過socket寫回給客戶端(瀏覽器或者其他)
5)前端頁面設計
5.1使用HTML模板
-
因為當前的知識對前端不是很瞭解,所以我們採用對別人的HTML模板就行刪減,下載好一個比較好看的模板之後下載到專案的webapp目錄中。
前置知識
-
HTML:網頁的骨架 --骨架
-
CSS:描述網頁上元件的樣式(位置,顏色,大小,字型,背景等等) --皮囊
-
JavaScript:描述前端頁面上的一些動作(和使用者具體互動的行為) --靈魂
-
HTML,CSS,JavaScript都可以寫到同一個HTML檔案中,也可以分開寫,瀏覽器載入這個HTML的時候,就會執行到這些程式碼
5.2基於模板進行刪減
(1)導航欄實現上傳
-
檔案上傳和提交按鈕:在原來的input標籤下載增加一個input標籤,將type改為file,增加name=“filename”,新的input標籤type=“submit”
-
修改form標籤屬性,新增method(請求方式)=“POST” enctype(上傳到伺服器上資料的組織型別)=“multipart/form-data” action(訪問的路徑)="/java_image_server/image"
-
小問題:發現“上傳按鈕”和前面不一樣高,用style="height:41px"修飾它
(2)頁面主題展示圖片預覽
5.3使用Vue.js
前置知識
-
把網頁上顯示的預覽圖片替換成我們伺服器上儲存的圖片:將img標籤中src改成伺服器存的圖片的url就可以了,需要獲取伺服器上所有的圖片的url(ImageServlet),需要通過JS先獲取到所有圖片的屬性,在分別載入每一個圖片,使用JS來完成。
-
此處引入Vue JS的框架來幫助我們更方便的編寫程式碼:JS中變數型別都是在初始化的時候自動推導的。
-
var宣告這是一個“變數”,const宣告這是一個“常量”。
-
Vue所做的最核心的工作,就是把頁面顯示的內容和JS中的程式碼相互關聯在一起,修改JS的變數就能很方便的影響到頁面的顯示情況
-
{{author}}稱為“差值表示式”:
如果是在標籤內部使用Vue物件中的資料,就需要使用插值表示式; 如果是在標籤屬性中使用Vue物件中的資料就不需要用插值表示式,但是需要搭配Vue的命令 Vue的命令:v-for:迴圈訪問一個資料 v-bind:把資料繫結到html標籤上的 v-on:繫結某種事件的處理函式,比如點選滑鼠,雙擊,右鍵,按下某個鍵盤,調整視窗大小...
Vue建立物件
示例圖片:
5.4 實現展示圖片
修改 html 程式碼, 和資料關聯
-
使用v-bind:src 把圖片的src通過imageShow介面獲取到
-
使用 {{image.imageName}} 表示圖片標題
從伺服器獲取資料
-
在methods中新增獲取所有圖片的方法
-
ajax: JS中構造HTTP請求傳送給伺服器的一種實現方式.
解決小bug
-
為了解決瀏覽器能自動適配圖片位置的問題,我們用 $("#app").resize(); 主動觸發瀏覽器 resize 事件即可.
5.5實現展示圖片
當前的上傳請求會返回一個 JSON 格式的資料. 而我們更需要的是直接能看到上傳的效果,解決如下:
- 修改上傳介面的響應, 直接返回一個 302 響應, 重定向回主頁.
- 修改 ImageServlet.doPost 在上傳成功程式碼最後, 加上一個重定向resp.sendRedirect(“index.html”);
5.6 完善功能
圖片下方新增刪除按鈕
實現事件處理函式
- 瀏覽器給伺服器傳送一個DELETE /image?imageld= xxx這樣的請求就可以了. (ajax完成)
解決小bug
- 點選刪除按鈕之後, 會觸發預覽圖片效果:
這是因為 JavaScript 的事件冒泡機制導致的. 一個標籤接受到的事件會依次傳給父級標籤.
此處需要阻止 click 事件冒泡. Vue 中使用 v-on:click.stop 即可.
三、後期加入
1)實現基於白名單方式的防盜鏈
-
當我們不想讓別人在別的網站直接使用我們的圖片連結時,可以採用如下方法:
-
通過 HTTP 中的 refer 欄位判定是否是指定網站請求圖片.修改 ImageShowServlet.doGet 方法
-
refer記錄了它的上一個請求頁面是哪
2)基於 MD5 實現相同內容圖片只存一份:類似於百度網盤的 “秒傳” 功能
(1)前置知識
Md5的特點:
1.不管原串多長,得到的MD5值是固定長度.
2.原串哪怕變動一點點(一個位元組), MD5值就會變動很大.
3.計算MD5值的過程很簡單,但是通過MD5值無法推測出原字串的. (應用在密碼學)
在我們的專案裡Md5的應用:
1.如果兩個圖片內容完全一樣, 就在磁碟上只存-份檔案就可以了. 通過MD5就能判定兩個圖片內容是否是一樣的.
2.圖片檔案雖然是二進位制資料,但是本質上也是字串,針對圖片內容計算MD5. 如果兩個圖片內容相同,得到的MD5 一定是相同的.
3.反之,近似的認為MD5相同,原圖片內容一定相同. 理論上是有可能兩個圖片內容不同,
MD5相同,但是實際,上出現概率極低(MD5自身演算法設計.上弓|起的特性)
4.通過Md5計算出的字串是無法在推算出原檔案的,即這是一個不可逆的過程
(2)整體思路
1.修改dao層的程式碼,在imageDao類裡邊增加selectByMd5方法,再根據Md5來查詢資料庫中的圖片資訊
2.修改上傳圖片的程式碼,上傳檔案時先進行判定,如果這個md5對應的檔案存在就不會上傳並提示使用者該圖片已經存在
(3)計算md5
1.在pom.xml中引入依賴
2.修改ImageServlet.doPost方法,計算md5
3.修改ImageDao類,新增selectByMd5方法
public static Image selectByMd5(String md5) {
// 1. 獲取資料庫連線
Connection connection = DBUtil.getConnection();
// 2. 構造 SQL 語句
String sql = "select * from image_table where md5 = ?";
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
// 3. 執行 SQL 語句
statement = connection.prepareStatement(sql);
statement.setString(1, md5);
resultSet = statement.executeQuery();
// 4. 處理結果集
if (resultSet.next()) {
Image image = new Image();
image.setImageId(resultSet.getInt("imageId"));
image.setImageName(resultSet.getString("imageName"));
image.setSize(resultSet.getInt("size"));
image.setUploadTime(resultSet.getString("uploadTime"));
image.setContentType(resultSet.getString("contentType"));
image.setPath(resultSet.getString("path"));
image.setMd5(resultSet.getString("md5"));
return image;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 5. 關閉連結
DBUtil.close(connection, statement, resultSet);
}
return null;
}
4.根據md5決定是否寫入檔案
- 修改ImageServlet.doPost方法,如果該md5值的檔案存在,則不會存入資料庫和磁碟
相關文章
- 圖床搭建圖床
- 搭建圖床-切換本站圖片至自建服務圖床
- Blog的圖床搭建圖床
- PicGo:搭建圖床PicGo圖床
- 伺服器搭建圖床:Chevereto安裝教程伺服器圖床
- 七牛圖床圖片轉移圖床
- 搭建微博圖床圖床
- 最快速搭建個人伺服器圖床siuuuuu伺服器圖床
- 教你如何搭建自己的圖床圖床
- 囊個搭建自己的圖床圖床
- PicGo+jsDelivr+GitHub搭建免費圖床,Typora使用圖床PicGoJSVRGithub圖床
- Github+picGo搭建圖床GithubPicGo圖床
- 如何使用 Gitee 搭建圖床Gitee圖床
- github搭建圖床配合typoraGithub圖床
- 部落格搭建-圖床篇圖床
- 【寧泊雲】搭建一個自己的免費圖床-基於gitee+PicGo圖床GiteePicGo
- 基於Minio和Thumbor搭建獨立圖片服務
- 基於canvas生成圖片Canvas
- 搭建基於OSS的圖片分享網站-反饋有禮網站
- 基於SpringMVC的上傳圖片SpringMVC
- 基於 NSData 的圖片壓縮
- 基於WebUploader的圖片上傳Web
- Java基於百度API的圖片文字識別JavaAPI
- 部落格搭建-自建Lychee圖床圖床
- 利用Github搭建免費圖床Github圖床
- 【教程】使用gitee搭建免費的圖床Gitee圖床
- Java和PHP兩種方式實現上傳圖片到新浪微博的圖床JavaPHP圖床
- 基於python的文字轉圖片工具Python
- 寫了一個基於 API 的簡單圖床 AUXPIAPI圖床UX
- PicGo + GitHub 搭建個人圖床工具PicGoGithub圖床
- 搭建一個自己圖床網站圖床網站
- Picgo+Gitee搭建免費圖床PicGoGitee圖床
- PicGo+CloudFire搭建免費圖床PicGoCloud圖床
- 前端圖床搭建實踐(前端篇)前端圖床
- 攻防世界-簡單的圖片
- 搭建自己的圖床:七牛雲+Mpic【棄】圖床
- 基於React Hook實現圖片的裁剪ReactHook
- 基於ThinkPHP的圖片下載網站PHP網站