java 将md文档中的本地图片上传csdn,并替换图片路径

代码仓库:BatchImgUploadCSDNAndReplaceUtil.java

配套视频:https://www.bilibili.com/video/BV1md4y1n76L


1.背景

习惯用Typora写md文档,但是导入csdn之后,图片就丢了,要浪费时间去一张一张手动上传是不可能的。

果断baidu了一下,最后虽然没有找到java版的上传csdn的现成工具,但找到了一些python写的上传其他网站的博客,也了解了一些相关知识。

主要两点:

想了想,好像自己可以写出来的样子。

先用F12找出相关图片上传接口。

然后话不多说,开干。

2.主要代码

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 将md文件中所有本地图片,上传csdn,并替换url,最终输出为新文件
 */
public class uploadAndReplaceImgUtil {
    
    

    private static String PROTOCOL = "file:" + File.separator;

    // 源.md文件
    private static String ORIGIN_FILE_PATH = "D:\\数据\\源文件.md";
    // 新文件
    private static String TARGET_FILE_PATH = "D:\\数据\\生成的新文件.md";

    // csdn图片服务器地址
    // 在csdn编辑界面,打开F12,上传一张图片,拿到的相关url和cookie
    private static String IMG_SERVICE_URL = "https://imgservice.csdn.net/direct/v1.0/image/upload?watermark=&type=blog&rtype=markdown";
    private static String IMG_OSS_URL = "https://csdn-img-blog.oss-cn-beijing.aliyuncs.com/";
    // cookie
    private static String COOKIE = "uuid_tt_dd=......";

    private static HttpClientUtil httpClientUtil = null;

    public static void main(String[] args) throws Exception {
    
    
        // http请求工具类
        httpClientUtil = new HttpClientUtil();
        // 读取一个文件,获取到内容
        String newContent = readFile(ORIGIN_FILE_PATH);
        // 写入到目标文件
        writeFile(newContent, TARGET_FILE_PATH);

        CloseableHttpClient httpClient = httpClientUtil.getHttpClient();
        if (httpClient != null) {
    
    
            httpClient.close();
        }
        System.out.println("处理完成!");
    }

    /**
     * 通过文件名读取一个markdown文件
     */
    private static String readFile(String originFile) throws Exception {
    
    
        FileInputStream fis = new FileInputStream(originFile);
        final InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
        BufferedReader bufferedReader = new BufferedReader(isr);
        String content = "";
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
    
    
            // 按行读取
            if (!line.isEmpty()) {
    
    
                // 处理图片
                line = handleImg(line);
            }
            content += line + "\r\n";
        }
        bufferedReader.close();
        return content;
    }

    /**
     * 判断该行是否有图片,有则上传并替换
     */
    private static String handleImg(String line) throws Exception {
    
    
        System.out.println(line);
        System.out.println("--------line--------");
        // 处理图片类型1: ![]()
        // copy至大佬的代码,原来不用正则也可以处理啊
        for (int i = 0; i < line.length(); i++) {
    
    
            if (i < line.length() - 4 && line.charAt(i) == '!' && line.charAt(i + 1) == '[') {
    
    
                int index1 = line.indexOf(']', i + 1);
                if (index1 != -1 && line.charAt(index1 + 1) == '(' && line.indexOf(')', index1 + 2) != -1) {
    
    
                    int index2 = line.indexOf(')', index1 + 2);
                    // [图片描述]
                    String picName = line.substring(i + 2, index1);
                    // (图片路径)
                    String picPath = line.substring(index1 + 2, index2).trim();
                    line = toUploadImg(line, picPath);
                }
            }
        }

        // 处理图片类型2: <img src="../../../图片/我是图片.png" style="zoom:25%;" />
        line = handleImgTag(line);

        return line;
    }

    /**
     * 处理html类型的img标签
     * 使用正则提取
     */
    private static String handleImgTag(String line) throws Exception {
    
    
        Matcher mImage = Pattern.compile("<img.*?src\\s*=\\s*(.*?)[^>]*?>", Pattern.CASE_INSENSITIVE).matcher(line);
        while (mImage.find()) {
    
    
            // 得到<img />数据
            String imgTagStr = mImage.group();
            // 匹配<img>中的src数据
            Matcher m = Pattern.compile("\\s{1}src=[\'\"]([^\'\"]+)[\'\"]").matcher(imgTagStr);
            while (m.find()) {
    
    
                String picPath = m.group(1);
                System.out.println("提取img标签图片:" + picPath);
                line = toUploadImg(line, picPath);
            }
        }
        return line;
    }

    /**
     * 上传图片之前拿到本地图片文件
     * 1.以http开头的不用上传
     * 2.将相对路径转为绝对路径
     * 3.拿不到图片文件的不用上传
     */
    private static String toUploadImg(String line, String picPath) throws Exception {
    
    
        // 保存原始地址,替换时使用
        String originPicPath = picPath;
        if (!picPath.isEmpty() && !picPath.startsWith("http")) {
    
    
            // 判断是相对路径,还是绝对路径
            // https://www.jb51.net/article/64518.htm
            if (picPath.startsWith("/") || picPath.indexOf(":") == 1) {
    
    
                // 绝对路径
            } else {
    
    
                // 相对路径转绝对路径
                // 使用该方法需要有协议头,比如http
                String absUrl = getAbsUrl(PROTOCOL + ORIGIN_FILE_PATH, picPath);
                // 切掉协议头
                picPath = absUrl.substring(PROTOCOL.length());
            }

            System.out.println("图片绝对路径:" + picPath);
            File file = new File(picPath);
            if (file == null || !file.exists() || file.isDirectory()) {
    
    
                // 可能url被编码过
                picPath = java.net.URLDecoder.decode(picPath, "UTF-8");
                file = new File(picPath);
                if (file == null || !file.exists() || file.isDirectory()) {
    
    
                    return line;
                }
            }
            System.out.println("图片需要上传:" + picPath);

            // 上传图片
            line = uploadImg(line, originPicPath, file);
        }
        return line;
    }

    /**
     * 上传图片到csdn,并替换图片路径
     */
    private static String uploadImg(String line, String originPicPath, File file) {
    
    
        // 获取oss凭据
        // 请求头
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("cookie", COOKIE);
        headerMap.put("origin", "https://editor.csdn.net");
        headerMap.put("referer", "https://editor.csdn.net/");
        headerMap.put("x-image-app", "direct_blog");
        headerMap.put("x-image-dir", "direct");
        headerMap.put("x-image-suffix", "jpeg");

        String result = httpClientUtil.sendHttpGet(IMG_SERVICE_URL, null, headerMap);
        // {"code":200,"msg":"success","message":null,
        // "data":{
    
    
        // "accessId":"LTAI5......",
        // "policy":"eyJle......",
        // "signature":"Zdxo......",
        // "dir":null,
        // "expire":"1650621246217", // 过期时间,时间戳,ms
        // "host":"https://csdn-img-blog.oss-cn-beijing.aliyuncs.com",
        // "callbackUrl":"eyJjYWxsYmFja0JvZHl......", // base64编码的数据
        // "filePath":"7.....12.png"}
        // }
        System.out.println(result);
        JSONObject jsonObject = JSON.parseObject(result);
        if (jsonObject != null && jsonObject.get("code") != null && "200".equals(jsonObject.get("code").toString())) {
    
    
            Object dataObject = jsonObject.get("data");
            if (dataObject != null) {
    
    
                JSONObject data = (JSONObject) JSONObject.toJSON(dataObject);
                Map<String, String> paramMap = new HashMap<>();
                paramMap.put("key", data.get("filePath").toString());
                paramMap.put("policy", data.get("policy").toString());
                paramMap.put("OSSAccessKeyId", data.get("accessId").toString());
                paramMap.put("success_action_status", "200");
                paramMap.put("signature", data.get("signature").toString());
                paramMap.put("callback", data.get("callbackUrl").toString());

                // 上传oss
                String result2 = httpClientUtil.sendHttpPostAndFile(IMG_OSS_URL, paramMap, headerMap, Arrays.asList(file));
                // {"code":200,"data":{"imageUrl":"https://img-blog.csdnimg.cn/7......589.png"},"msg":"success"}
                System.out.println(result2);
                if (result2 != null) {
    
    
                    JSONObject jsonObject2 = JSON.parseObject(result2);
                    if (jsonObject2 != null && jsonObject2.get("code") != null && "200".equals(jsonObject2.get("code").toString())) {
    
    
                        Object dataObject2 = jsonObject2.get("data");
                        if (dataObject != null) {
    
    
                            JSONObject data2 = (JSONObject) JSONObject.toJSON(dataObject2);
                            line = line.replace(originPicPath, data2.get("imageUrl").toString());
                        }
                    }
                }
            }
        }
        return line;
    }


    /**
     * 相对路径转为绝对路径
     *
     * @param absolutePath 绝对路径
     * @param relativePath 相对路径
     * @return 绝对路径
     */
    private static String getAbsUrl(String absolutePath, String relativePath) throws Exception {
    
    
        URL absoluteUrl = new URL(absolutePath);
        URL parseUrl = new URL(absoluteUrl, relativePath);
        return parseUrl.toString();
    }

    /**
     * 将内容写到目标文件
     */
    private static void writeFile(String newContent, String targetFile) throws Exception {
    
    
        File file = new File(targetFile);
        FileOutputStream fos = new FileOutputStream(file);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        osw.write(newContent);
        osw.flush();
        osw.close();
    }

}

3.pom依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.72</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
</dependency>
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>

4.http请求工具类

import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * HttpClient请求工具类
 */
public class HttpClientUtil {
    
    

    // 缓存大小
    public static final int cache = 10 * 1024;
    CloseableHttpClient httpClient = null;

    // 配置
    private static RequestConfig requestConfig = RequestConfig.custom()
            .setSocketTimeout(15000) // 返回等待时间
            .setConnectTimeout(15000) // 连接超时
            .setConnectionRequestTimeout(15000)
            .build();

    public HttpClientUtil() {
    
    
        this.httpClient = HttpClients.createDefault();
    }

    public CloseableHttpClient getHttpClient() {
    
    
        return httpClient;
    }

    /**
     * 发送get请求
     *
     * @param httpUrl   请求地址
     * @param paramMap  参数,url后面
     * @param headerMap 请求头
     */
    public String sendHttpGet(String httpUrl, Map<String, String> paramMap, Map<String, String> headerMap) {
    
    
        // 创建get请求
        HttpGet httpGet = null;
        if (paramMap != null && paramMap.size() > 0) {
    
    
            // 封装请求参数
            List<BasicNameValuePair> list = new ArrayList<>();
            for (String key : paramMap.keySet()) {
    
    
                list.add(new BasicNameValuePair(key, paramMap.get(key)));
            }
            // 转化参数
            String params = null;
            try {
    
    
                params = EntityUtils.toString(new UrlEncodedFormEntity(list, Consts.UTF_8));
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(params);
            if (params != null) {
    
    
                httpUrl = httpUrl + "?" + params;
            }
        }
        httpGet = new HttpGet(httpUrl);
        // 设置请求头
        if (headerMap != null && headerMap.size() > 0) {
    
    
            for (String key : headerMap.keySet()) {
    
    
                httpGet.addHeader(key, headerMap.get(key));
            }
        }
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        String responseContent = null;
        try {
    
    
            httpGet.setConfig(requestConfig);
            // 执行请求
            response = httpClient.execute(httpGet);
            entity = response.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                // 关闭连接,释放资源
                if (response != null) {
    
    
                    response.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        return responseContent;
    }

    /**
     * 发送form-data格式的post请求,可以上传附件
     *
     * @param httpUrl  地址
     * @param paramMap 参数,body里面
     * @param headerMap 请求头
     * @param files    附件
     */
    public String sendHttpPostAndFile(String httpUrl, Map<String, String> paramMap, Map<String, String> headerMap, List<File> files) {
    
    
        // 创建httpPost
        HttpPost httpPost = new HttpPost(httpUrl);
        httpPost.setConfig(requestConfig);
        // 设置参数 编码
        ContentType contentType = ContentType.create(HTTP.PLAIN_TEXT_TYPE, HTTP.UTF_8);
        MultipartEntityBuilder meBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
        for (String key : paramMap.keySet()) {
    
    
            meBuilder.addPart(key, new StringBody(paramMap.get(key), contentType));
        }
        // 设置请求头
        if (paramMap != null && paramMap.size() > 0) {
    
    
            for (String key : headerMap.keySet()) {
    
    
                httpPost.addHeader(key, headerMap.get(key));
            }
        }
        // 附件
        if (files != null && files.size() > 0) {
    
    
            // 单附件或多附件
            String fileKey = files.size() > 1 ? "files" : "file";
            for (File file : files) {
    
    
                FileBody fileBody = new FileBody(file);
                meBuilder.addPart(fileKey, fileBody);
            }
        }
        // 创建HttpEntity
        HttpEntity reqEntity = meBuilder.build();
        httpPost.setEntity(reqEntity);

        return sendHttpPost(httpPost);
    }

    /**
     * 发送Post请求
     */
    private String sendHttpPost(HttpPost httpPost) {
    
    
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        String responseContent = null;
        try {
    
    
            // 执行请求
            response = httpClient.execute(httpPost);
            entity = response.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");
        } catch (Exception e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                // 关闭连接,释放资源
                if (response != null) {
    
    
                    response.close();
                }
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        return responseContent;
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_44174211/article/details/124373334