利用水墨映客图床作为COS服务器
利用水墨映客作为COS服务器
文章类网站项目的图片存储都是一个很重要的问题,一般都是使用云服务厂商的COS对象存储服务(参考前文:使用腾讯云对象存储搭建图床) ,虽然小网站的需求不大,购买也不贵,但是还是想能不能找个免费的,毕竟能省就省嘛。
平常有些博客或者笔记的都是用markdown编辑,图片一般都是上传图床,但是很多图床都没有开放接口。最近用路过图床的时候网站没打开,咨询管理说有DNS污染,便又搜索有没有好用一些的图床,就发现了水墨映客图床,虽然容量有限,但是他每天签到都可以扩充容量,并且最最重要的我发现水墨映客开放上传接口,于是就开始鼓捣想着利用水墨映客作为COS服务器。
水墨图床地址:图片映客--水墨图床,免费专业的高速外链图床


分为两种,一种还是利用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)

下载之后正常安装就可以了。

安装lankong插件
这是一个为 兰空图床适配开发的 PicGo 图片上传插件。同样适用于水墨映客图床
在picGo的插件设置中搜索lankong,然后安装。

安装后配置


Lsky Pro Version在下拉菜单中选择 Lsky Pro 版本,V1还是V2,默认V1填写图床的
server url,注意不要以/结束https://image.example.com️https://image.example.com/️
填写
Auth Token使用Bearer拼接,token在水墨映客的设置中获取,注意在配置时候需要前面拼接Bearer
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里配置图片上传服务即可。

在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());//调用方法上传图片
测试:


源码:
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);
}
欢迎关注公众号:愚生浅末

利用水墨映客图床作为COS服务器的更多相关文章
- gitee+picgo搭建个人博客图床
gitee+picgo搭建个人博客图床 准备 首先需要去码云注册一个账号,并新建一个仓库.接着下载PicGO并安装好. 过程 点击左下方的插件设置. image 在搜索框中输入gitee搜索插件,安装 ...
- 解决“用PicGo-2.3.0-beta5 + GitHub做博客图床,github仓库图片文件不显示”的问题记录(备忘)
解决"用PicGo-2.3.0-beta5 + GitHub做博客图床,github仓库图片文件不显示"的问题记录(备忘) 历时几个小时百度,终于靠自己理解解决了GitHub仓库图 ...
- gitee+typro+picgo搭建博客图床
gitee+typro+picgo搭建博客图床 前提环境 typro.picgo.nodejs 直接在官网下载即可 下载完成后,打开picgo 安装插件gitee-uploader 1.1-2即可显示 ...
- 零成本搭建个人博客之图床和cdn加速
本文属于零成本搭建个人博客指南系列 为什么要使用图床 博客文章中的图片资源文件一般采用本地相对/绝对路径引用,或者使用图床通过外链进行引用展示.本地引用的弊端我认为在于: 图片和博客放在同一个代码托管 ...
- 七牛云图床和Markdown使用
七牛云图床和Markdown使用 1.图床是什么? 图床一般是指储存图片的服务器,有国内和国外之分.国外的图床由于有空间距离等因素决定访问速度很慢影响图片显示速度.国内也分为单线空间.多线空间和cdn ...
- 图床搭建|chrome插件|操作简单不要钱
为什么需要一个图床 为了写博客 图床:专门用来存放图片,同时允许你把图片对外连接的网上空间. 用markdown格式写作,插入图片需要图片的url地址,然后博客的背景图也是要用url地址. 有段时间, ...
- GitHub+PicGo构建免费图床及其高效使用
搭建免费图床全过程! 一.搭建缘由 一开始搭建博客,避免不了要用许多图片,最初使用七牛云来做博客图床,但是后来发现,七牛云只有30天的临时域名,hhhhhhh,果然啊,天下就没有免费的好事啊~后来就发 ...
- 写了个适用于vscode的minio图床客户端插件
缘起 自己搭建minio做我的个人博客图床好一段时间了, 一直用minio自带的web管理后台来上传图片, 它的界面长下面这个样子 上传完后, 需要点下文件列表里刚刚传上去的文件的分享按钮 然后会出来 ...
- 搭建markdown图床-腾讯云COS
背景介绍 书写markdown笔记时,如何处理图片,实在是有些棘手的问题.每一张图都保存在当前文件夹? 每张图都自己重命名?每次上传到cnblogs博客都需要一张一张拖动?markdown已经非常成功 ...
- Typora+PicGo+cos图床打造开发者文档神器
一.Typora简介 markdown简单.高效的语法,被每一个开发者所喜爱.Typora又是一款简约.强悍的实时渲染markdown编辑器.本文将介绍Typora搭配PicGo与腾讯cos对象存储( ...
随机推荐
- win10 VMware 关闭虚拟机失败导致再打开时显示连接不上虚拟机的一种解决方法
VMware关闭虚拟机失败,强行关闭后,再次打开VMware,打开虚拟机时提示连接不上虚拟机,没有访问权限. 先试了退出后,用管理员权限打开,无果. 然后从网上查资料,cmd->services ...
- 如何合理开发Java接口(安全性,可重复调用,稳定性,追溯性)
一.接口开发规范 签名:对外提供的接口要做签名认证,认证不通过的请求不允许访问接口.提供服务. 加密:敏感数据在网络传输过程中应该加密. IP白名单:限制请求的IP,增加IP白名单,一般在网关层处理. ...
- 怎样理解 Vue 的单向数据流?
数据从父级组件传递给子组件,只能单向绑定. 子组件内部不能直接修改从父级传递过来的数据. 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件 ...
- 什么是JS执行上下文?
我们都知道,JS代码的执行顺序总是与代码先后顺序有所差异,当先抛开异步问题你会发现就算是同步代码,它的执行也与你的预期不一致,比如: function f1() { console.log('听风是风 ...
- 3. set 的使用
3. set 的使用 因为在实际工程中,我们不会将具体文件全部写出来,这是一件费力不讨好的事情. 3.1 set 定义变量 在 CMake 文件中,默认的变量数据类型是字符串,如果要用别的类型,需要进 ...
- AI时代你一定要知道的Agent概念
这两年,随着人工智能(AI)和计算能力的发展,AI应用的落地速度大大加快.以ChatGPT为代表的AI应用迅速火遍全球,成为打工人的常用工具.紧接着,多模态.AI Agent等各种高大尚的名词也逐渐进 ...
- 前端说你的API接口太慢了,怎么办?
当有千万条海量数据时,前端调取接口发现接口响应的太慢,前端这时让你优化一下接口,你说有几千万条数据,觉得自己尽力了,前端觉得你好菜,别急,读完这篇文章,让前端喊你一声:大佬,厉害!!! 常用的方法总结 ...
- JavaScript高级~数组偏平化
方式一: let arr=[11,[22,[33,[44]]],[55,66,77],88,99,['00']] let arr2=arr.toString().split("," ...
- 打开电脑属性 设置 windows
组合键:win+R,输入sysdm.cpl,然后运行. 右键"此电脑",选择属性,然后点击高级系统设置. 组合键:win+Pause/Break. 在命令提示符中输入SystemP ...
- EdgeOne安全专项实践:上传文件漏洞攻击详解与防范措施
前言 今天,我们将深入探讨上传文件漏洞攻击,这部分内容是EdgeOne专项实践篇的一部分.在本章中,我们不会涉及文件漏洞的含义.原理或站点配置等基础教程,如果你对这些内容感兴趣,可以参考这篇文章:探索 ...