利用水墨映客圖床作為COS伺服器

愚生浅末發表於2024-04-28

目錄
  • 利用水墨映客作為COS伺服器
    • 利用picGo配合typora上傳圖片
      • 安裝PicGo(以Windows為例)
      • 安裝lankong外掛
    • 在SpringBoot中開發圖片上傳工具類
      • 設定圖片上傳請求的引數
      • 設定圖片的引數
      • 讀取圖片內容並寫入請求
      • 獲取響應

利用水墨映客作為COS伺服器

文章類網站專案的圖片儲存都是一個很重要的問題,一般都是使用雲服務廠商的COS物件儲存服務(參考前文:使用騰訊雲物件儲存搭建圖床) ,雖然小網站的需求不大,購買也不貴,但是還是想能不能找個免費的,畢竟能省就省嘛。

平常有些部落格或者筆記的都是用markdown編輯,圖片一般都是上傳圖床,但是很多圖床都沒有開放介面。最近用路過圖床的時候網站沒開啟,諮詢管理說有DNS汙染,便又搜尋有沒有好用一些的圖床,就發現了水墨映客圖床,雖然容量有限,但是他每天簽到都可以擴充容量,並且最最重要的我發現水墨映客開放上傳介面,於是就開始鼓搗想著利用水墨映客作為COS伺服器。

水墨圖床地址:圖片映客--水墨圖床,免費專業的高速外鏈圖床

image-20240428131922417

image-20240428130441660

分為兩種,一種還是利用picGo配合typora,另一種是在SpringBoot中開發為工具類專門用作圖片上傳。

利用picGo配合typora上傳圖片

安裝PicGo(以Windows為例)

先下載PicGo的客戶端安裝包,找到對應的平臺安裝包然後下載。

下載連結:

  • GitHub:https://github.com/Molunerfinn/PicGo/releases (訪問較慢)
  • 山東大學映象網站:https://mirrors.sdu.edu.cn/github-release/Molunerfinn_PicGo/ (速度較快)

(我的電腦:Windows11,64位,故下載PicGo-Setup-2.3.1-x64.exe)

image-20240428131055904

下載之後正常安裝就可以了。

640

安裝lankong外掛

這是一個為 蘭空圖床適配開發的 PicGo 圖片上傳外掛。同樣適用於水墨映客圖床

在picGo的外掛設定中搜尋lankong,然後安裝。

image-20240428131511419

安裝後配置

image-20240428131607818

image-20240428131701803

  • Lsky Pro Version 在下拉選單中選擇 Lsky Pro 版本,V1 還是 V2,預設 V1

  • 填寫圖床的 server url,注意不要以 / 結束

    • https://image.example.com ✅️
    • https://image.example.com/ ❌️
  • 填寫 Auth Token 使用 Bearer 拼接,token在水墨映客的設定中獲取,注意在配置時候需要前面拼接Bearer

    image-20240428132004523

  • Strategy ID,儲存策略 ID,如果是 V1 或 V2 使用預設儲存策略的使用者,請留空;除非你知道具體 ID,否則請留空

  • Album ID,相簿 ID,只針對 V2 有效

  • Permission,圖片許可權,公開還是私有,預設是私有

  • Sync Delete 同步刪除選項,只支援 V2,開啟後在 PicGo 相簿中刪除圖片可同步刪除圖床上的檔案,預設關閉

  • Ignore certificate error 開關,預設關閉,請保持關閉,除非你遇到 certificate has expired 等證書報錯才需要考慮將其開啟。由於有些站點使用 Let's Encrypt 頒發的免費證書,有效期只有 90 天,在測試上傳中遇到了 certificate has expired 錯誤,開啟開關 Ignore certificate error 即可成功上傳

配置完畢儲存即可,然後再typora裡配置圖片上傳服務即可。

image-20240428132124664

在SpringBoot中開發圖片上傳工具類

該工具類的方法有兩個引數一個是檔名(fileName),另一個是檔案的輸入流。

在Spring Boot中一般使用MultipartFile類來處理檔案相關,在此處可以透過getInputStream()方法獲取檔案的輸入流

主要的步驟分為:

  • 設定圖片上傳請求的引數
  • 設定圖片的引數
  • 讀取圖片內容並寫入請求
  • 獲取響應

水墨映客圖床的上傳介面為https://img.ink/api/upload,如果上傳成功狀態碼返回200,失敗返回500

上傳成功的返回格式:

{
    "code":200,
    "msg":"success",
    "data":		  
        {
            "id":"281381",
            "name":".jpg",
            "url":"https:\/\/pic2.ziyuan.wang\/user\/userNickName\/2024\/04\/fileName_d75b474147589.jpg",               "size":101168,
            "mime":"image\/jpeg",
            "sha1":"9adb76331eb1254567547afea3e516ac1901eac1",
            "md5":"aef7bc728fd44e77d5688529c8122882",
            "quota":"6485442560.00",
            "use_quota":"6666141.00"
        },
    "time":1714282312
}

設定圖片上傳請求的引數

 // 設定上傳地址
URL url = new URL("https://img.ink/api/upload");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 // 設定請求方法為POST
connection.setRequestMethod("POST");
connection.setDoOutput(true);
// 設定請求頭
connection.setRequestProperty("token", "你的請求頭"); // 替換為你的token,在設定中獲取
// 構建請求引數
String boundary = Long.toHexString(System.currentTimeMillis());//用來標識multipart/form-data內容型別的邊界字串,使用時間戳,確保每次請求的邊界字串都是唯一的,以避免衝突
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);//設定上傳檔案的格式
OutputStream output = connection.getOutputStream();//獲取與HTTP連線關聯的輸出流
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true);//向輸出流寫入文字形式的資料

設定圖片的引數

writer.append("--" + boundary).append("\r\n");//新增了一個分隔邊界標記
writer.append("Content-Disposition: form-data; name=\"image\"; filename=\"" + fileName + "\"").append("\r\n");//設定Content-Disposition頭部資訊,
writer.append("Content-Type: image/jpeg").append("\r\n");//宣告上傳檔案的MIME型別為image/jpeg
writer.append("\r\n");//回車換行符作為分隔
writer.flush();

讀取圖片內容並寫入請求

//接受傳入的輸入流
InputStream input = inputStream;
byte[] buffer = new byte[4096];//臨時儲存從輸入流中讀取的資料
int bytesRead;
//持續讀取輸入流中的資料直到沒有資料
while ((bytesRead = input.read(buffer)) != -1) {
    output.write(buffer, 0, bytesRead);
}
output.flush();
input.close();
// 結束整個multipart/form-data請求體
writer.append("\r\n").append("--" + boundary + "--").append("\r\n");
writer.close();

獲取響應

//獲取伺服器對上傳請求的響應狀態碼,200代表上傳成功
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
    BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
    String line;
    StringBuffer response = new StringBuffer();
    //逐行讀取伺服器返回的文字資料
    while ((line = reader.readLine()) != null) {
        response.append(line);
    }
    reader.close();
    ObjectMapper mapper = new ObjectMapper();
    //使用Jackson庫的ObjectMapper來解析response中的JSON字串為JsonNode物件
    JsonNode rootNode = mapper.readTree(String.valueOf(response));
    //從解析出的JSON物件中,透過路徑rootNode.path("data")定位到"data"節點,再從該節點下獲取"url"欄位的值,即圖片上傳後的URL
    JsonNode userNode = rootNode.path("data");
    String imgUrl = userNode.path("url").asText();
    return imgUrl;
} else {
    return "error";
}

呼叫該方法時的使用(file為MultipartFile物件):

String originalFilename = file.getOriginalFilename();//獲取完整檔名
String fileName = originalFilename.substring(originalFilename.lastIndexOf("."));//獲取檔名字尾
String url = InkImageUtil.uploadImg(fileName,file.getInputStream());//呼叫方法上傳圖片

測試:

image-20240428143227459

image-20240428143258379

原始碼:

public class InkImageUtil {
    public static String uploadImg(String fileName,InputStream inputStream) throws IOException {
            // 設定上傳地址
            URL url = new URL("https://img.ink/api/upload");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 設定請求方法為POST
            connection.setRequestMethod("POST");
            connection.setDoOutput(true);
            // 設定請求頭
            connection.setRequestProperty("token", "f3ee57bcc8d796ea9b72bd776f243d98"); // 替換為你的token
            // 構建請求引數
            String boundary = Long.toHexString(System.currentTimeMillis());
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            OutputStream output = connection.getOutputStream();
            PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true);
            // 新增圖片引數
            writer.append("--" + boundary).append("\r\n");
            writer.append("Content-Disposition: form-data; name=\"image\"; filename=\"" + fileName + "\"").append("\r\n");
            writer.append("Content-Type: image/jpeg").append("\r\n");
            writer.append("\r\n");
            writer.flush();
            // 讀取圖片內容並寫入請求
            InputStream input = inputStream;
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                output.write(buffer, 0, bytesRead);
            }
            output.flush();
            input.close();
            // 結束請求
            writer.append("\r\n").append("--" + boundary + "--").append("\r\n");
            writer.close();
            // 獲取響應
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String line;
                StringBuffer response = new StringBuffer();
                while ((line = reader.readLine()) != null) {
                    response.append(line);
                }
                reader.close();
                System.out.println(response.toString());
                ObjectMapper mapper = new ObjectMapper();
                JsonNode rootNode = mapper.readTree(String.valueOf(response));
                JsonNode userNode = rootNode.path("data");
                String imgUrl = userNode.path("url").asText();
                return imgUrl;
            } else {
                return "error";
            }
    }
}
@PostMapping("/upload")
    public Result<String> fileUpload(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        String fileName = originalFilename.substring(originalFilename.lastIndexOf("."));
        String url = InkImageUtil.uploadImg(fileName,file.getInputStream());
        return Result.success(url);
    }

歡迎關注公眾號:愚生淺末

相關文章