vue+springboot讀取git的markdown文件并展示功能
前言
最近,在研究一個(gè)如何將我們git項(xiàng)目的MARKDOWN文檔獲取到,并且可以展示到界面通過(guò)檢索查到,于是經(jīng)過(guò)幾天的摸索,成功的研究了出來(lái)
本次前端vue使用的是Markdown-it
Markdown-it 是一個(gè)用于解析和渲染 Markdown 標(biāo)記語(yǔ)言的 JavaScript 庫(kù)。
它采用模塊化的設(shè)計(jì),提供了靈活的配置選項(xiàng)和豐富的插件系統(tǒng),使開(kāi)發(fā)者可以根據(jù)自己的需要定制 Markdown 的解析和渲染過(guò)程。
使用 Markdown-it,你可以將 Markdown 文本解析為 HTML 輸出,并且可以根據(jù)需要添加功能、擴(kuò)展語(yǔ)法或修改解析行為
后端springboot使用JGit
JGit 是一個(gè)開(kāi)源的 Java 實(shí)現(xiàn)的 Git 客戶端庫(kù),它允許開(kāi)發(fā)者在 Java 程序中直接操作 Git 倉(cāng)庫(kù)。
JGit 提供了一些核心的 API,使開(kāi)發(fā)者可以使用 Java 代碼來(lái)訪問(wèn)和操作 Git 倉(cāng)庫(kù),例如創(chuàng)建倉(cāng)庫(kù)、提交變更、分支管理、標(biāo)簽管理、克隆遠(yuǎn)程倉(cāng)庫(kù)等。它提供了對(duì) Git 分布式版本控制系統(tǒng)的完整支持,能夠滿足日常的代碼版本管理需求。
但是我們這里單純只是將其獲取git的文件進(jìn)行展示markdown,因此并用不上
準(zhǔn)備工作
前端
在前端,
我使用了element-ui
前端框架寫(xiě)頁(yè)面
使用Markdown-it
進(jìn)行解析markdown
使用axios
連接了前后端
因此,需要安裝如上依賴,指令如下:
npm i element-ui npm i markdown-it npm i axios
后端
因后端為springboot項(xiàng)目,需要安裝springboot的依賴,這里不多贅述,主要是需要安裝JGit
的依賴
<dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> <version>5.9.0.202009080501-r</version> </dependency>
效果演示
那么,在說(shuō)如何做之前,先介紹一下我做出來(lái)的效果吧
首先,我建立了一個(gè)
git倉(cāng)庫(kù)
,專門(mén)用于獲取到markdown文件
為了程序能夠獲取到文件,我在data文件夾下放了四個(gè)markdown文件,并且在程序指定只獲取data下的markdown文件
無(wú)數(shù)據(jù)時(shí),前端界面顯示如下
當(dāng)什么關(guān)鍵字都不輸入,檢索全部markdown文件
此時(shí)展示文件
此時(shí)隨便點(diǎn)擊列表的一個(gè)文件查看
切換另一個(gè)
以上,我們能夠發(fā)現(xiàn),它能夠把我們的markdown的
表格
,圖片
以及表情
正確的顯示出來(lái),并且樣式排版也過(guò)得去,當(dāng)然,這個(gè)是可以自己調(diào)整的
多提一句,我有做一個(gè)簡(jiǎn)單的
檢索關(guān)鍵字的邏輯
,邏輯如下:
- 什么關(guān)鍵字不輸入的時(shí)候,檢索指定文件夾下所有markdown
- 當(dāng)輸入關(guān)鍵字,檢索文件名,如果包含關(guān)鍵字,則把文件路徑加入集合列表
- 當(dāng)文件名不包含關(guān)鍵字,判斷文件內(nèi)容是否包含關(guān)鍵字,包含也把對(duì)應(yīng)文件路徑加入列表
前端代碼邏輯 界面部分
<template> <div> <el-page-header content="MarkDown展示"/> <el-input v-model="searchKey" placeholder="檢索問(wèn)題" style="position: relative;;width: 70%;left: 0%"></el-input> <el-button @click="searchProblem" type="primary" plain style="margin: 10px;">檢索</el-button> <el-card> <el-table :data="searchData" style="width: 100%;font-size: 20px; max-height: 500px; overflow-y: auto;background-color: white;"> <el-table-column type="index" label="序號(hào)"> </el-table-column> <el-table-column label="列表項(xiàng)"> <template slot-scope="scope"> <span>{{ changePathName(scope.row )}}</span> </template> </el-table-column> <el-table-column label="操作"> <template slot-scope="scope"> <div> <el-button type="primary" size="medium" @click="findMarkDown(scope.row)" style="font-size: 24px;">查看</el-button> </div> </template> </el-table-column> </el-table> </el-card> <!-- 展示區(qū) --> <el-card style="position: relative;width: 100%;overflow-x: auto;" header="MarkDown處理文檔"> <div style="position: relative;"> <el-card style="background-color:rgb(255, 253, 245);padding: 32px;" v-if="htmlContent"> <div v-html="htmlContent" class="v-md-header"></div> </el-card> <el-card style="background-color:rgb(255, 253, 245);padding: 32px;" v-else> <div style="position: absolute;left:46.5%;text-align: center;line-height: 0px;font-weight: bold;">請(qǐng)檢索并查看文檔</div> </el-card> </div> </el-card> </div> </template>
JavaScript邏輯
<script> // 封裝的axios調(diào)用后端的方法,如需要?jiǎng)t按照自己的項(xiàng)目調(diào)用修改即可 import {searchProblem,findMarkDownBypath} from "../ajax/api" import MarkdownIt from 'markdown-it'; export default { name: "MarkDown", data() { return { searchKey: "", searchData: [], // 檢索到的問(wèn)題列表 markdownText: '', // 加載好圖片的Markdown文本 markdownRenderer: null, // 解析markdown渲染器定義 htmlContent: '', // 解析為html } }, mounted() { this.markdownRenderer = new MarkdownIt(); }, methods: { // 檢索文件 searchProblem() { searchProblem(this.searchKey).then(res => { console.log("檢索數(shù)據(jù):",res); this.searchData = res.data.data; // 賦值檢索數(shù)據(jù),注意這里的res.data.data請(qǐng)根據(jù)自己實(shí)際回參更改獲取參數(shù) this.markdownText = ""; // 每次檢索清空markdown顯示文檔內(nèi)容 this.htmlContent = ""; // 每次檢索清空markdown顯示文檔內(nèi)容 }) }, // 根據(jù)文件路徑查找markdown文件 findMarkDown(path) { console.log("path:",path); findMarkDownBypath(path).then(res => { console.log("markdown內(nèi)容:",res); this.markdownText = res.data.data; this.htmlContent = this.markdownRenderer.render(this.markdownText); console.log(this.htmlContent); }) }, // 處理字符串,回傳的參數(shù)實(shí)際為:data/學(xué)生成績(jī)系統(tǒng)前端.md,將字符串進(jìn)行截取 changePathName(str) { if (str) { var lastIndex = str.lastIndexOf('/'); var result = str.substring(lastIndex + 1); return result.replace('.md',''); } return str; } } } </script>
在以上,后端傳遞的路徑實(shí)際為:
[ "data/README.en.md", "data/README.md", "data/學(xué)生成績(jī)系統(tǒng)前端.md", "data/網(wǎng)上購(gòu)藥商城.md" ]
因此為了美觀和直觀展示,我是有做字符處理的,詳情參考如何代碼
此外,我后端獲取到的markdown的內(nèi)容實(shí)際數(shù)據(jù)為:
# search_markdown_data #### Description 用于檢索markdown的數(shù)據(jù)來(lái)源 #### Software Architecture Software architecture description #### Installation 1. xxxx 2. xxxx 3. xxxx #### Instructions 1. xxxx 2. xxxx 3. xxxx #### Contribution 1. Fork the repository 2. Create Feat_xxx branch 3. Commit your code 4. Create Pull Request #### Gitee Feature 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md 2. Gitee blog [blog.gitee.com](https://blog.gitee.com) 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) 4. The most valuable open source project [GVP](https://gitee.com/gvp) 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
我的代碼中,使用
markdown-it
創(chuàng)建渲染器,將如上數(shù)據(jù)轉(zhuǎn)換為:
<h1>search_markdown_data</h1> <h4>Description</h4> <p>用于檢索markdown的數(shù)據(jù)來(lái)源</p> <h4>Software Architecture</h4> <p>Software architecture description</p> <h4>Installation</h4> <ol> <li>xxxx</li> <li>xxxx</li> <li>xxxx</li> </ol> <h4>Instructions</h4> <ol> <li>xxxx</li> <li>xxxx</li> <li>xxxx</li> </ol> <h4>Contribution</h4> <ol> <li>Fork the repository</li> <li>Create Feat_xxx branch</li> <li>Commit your code</li> <li>Create Pull Request</li> </ol> <h4>Gitee Feature</h4> <ol> <li>You can use Readme_XXX.md to support different languages, such as Readme_en.md, Readme_zh.md</li> <li>Gitee blog <a rel="external nofollow" >blog.gitee.com</a></li> <li>Explore open source project <a rel="external nofollow" >https://gitee.com/explore</a></li> <li>The most valuable open source project <a rel="external nofollow" >GVP</a></li> <li>The manual of Gitee <a rel="external nofollow" >https://gitee.com/help</a></li> <li>The most popular members <a rel="external nofollow" >https://gitee.com/gitee-stars/</a></li> </ol>
實(shí)際為html的數(shù)據(jù),因此,我們就可以在界面使用vue的
v-html
展示markdown的內(nèi)容
css樣式
以上我們知道它會(huì)將數(shù)據(jù)轉(zhuǎn)為html的數(shù)據(jù),因此,就可以使用css樣式調(diào)整,以下為我的css樣式,供參考:
h1 { color: #ff0000; } p { font-size: 16px; line-height: 1.5; } .v-md-header { text-align: left !important; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid black; padding: 8px; } th { background-color: #f2f2f2; /* 設(shè)置表頭的背景顏色 */ } tr:nth-child(even) { background-color: #dddddd; /* 設(shè)置偶數(shù)行的背景顏色 */ } tr:hover { background-color: #f5f5f5; /* 設(shè)置鼠標(biāo)懸停時(shí)的背景顏色 */ } h1,h2,h3,h4,h5{ border-bottom: 1px #d8d6d6 solid; } img{ width: 80%; }
后端代碼邏輯
先說(shuō)下我的查詢的方法,JGIT
我嘗試了很久,都只能通過(guò)先克隆到本地
,再讀取的方式,于是放棄了研究如何使用JGIT在線讀取文件的方式,也許后面我可能研究的出來(lái)。
同樣,為了保證每次都是最新的文檔,我采用了判斷是否已經(jīng)克隆下來(lái)了,如果克隆了則更新代碼,沒(méi)有克隆則克隆,來(lái)保證每次都是最新代碼
在正式執(zhí)行前,我們需要先定義好需要的參數(shù)
// 解析markdown圖片正則 private static final String MARKDOWN_IMAGE_PATTERN = "(!\\[[^\\]]*\\])\\(([^\\)]+)\\)"; // 需要克隆git到本機(jī)的路徑 private final String LOCAL_PATH = "E:\\git\\markdown"; // 需要獲取markdown的git鏈接 private final String GIT_PATH = "https://gitee.com/spring-in-huangxian-county/search_markdown_data.git"; // 需要獲取的git分支 private final String GIT_BRANCH = "master"; // 需要抓取的Git內(nèi)指定文件夾的markdown private final String MARK_DOWN_PATH = "data"; // 當(dāng)前后端項(xiàng)目的位置,該目的是為了能夠找到正確的文件路徑 private final String PROJECT_PATH = "F:\\gitee\\search_markdown_end";
查詢
controller層
@GetMapping("/searchProblem") public ResultVO<List<String>> searchMarkdown(@RequestParam("searchKey") String searchKey) throws Exception { // 獲取Git倉(cāng)庫(kù)中的Markdown文檔列表 try { List<String> markdownFiles = new MarkDownService().getGitDataFilePath(); List<String> results = new ArrayList<>(); if (StringUtils.isEmpty(searchKey)) { results.addAll(markdownFiles); } else { for (String path:markdownFiles) { // 如果標(biāo)題包含檢索關(guān)鍵字加入列表 if (path.contains(searchKey)) { results.add(path); } else { // 判斷具體內(nèi)容是否包含關(guān)鍵字,是則加入列表 if (new MarkDownService().isContainSearchKeyForContent(searchKey,path)) { results.add(path); } } } } return new ResultVO<>(0,"OK",results); }catch (Exception e) { return new ResultVO<>(1,e.getMessage()); } }
ResultVO為封裝的響應(yīng)體,如有興趣可參考我之前文章
MarkDownService為service層文件名
service層
克隆和拉取git的方式讀取文件,獲取文件路徑
// 克隆和拉取git的方式讀取文件 public List<String> getGitDataFilePath() throws Exception { File localPath = new File(LOCAL_PATH); String remoteUrl = GIT_PATH; String branchName =GIT_BRANCH; // 或者其他分支名稱 String folderPath = MARK_DOWN_PATH; // data文件夾的路徑 List<String> markDownFilePathList = new ArrayList<>(); Repository repository; if (localPath.exists()) { repository = openLocalRepository(localPath); pullLatestChanges(repository); } else { repository = cloneRepository(localPath, remoteUrl); } try (Git git = new Git(repository)) { Iterable<RevCommit> commits = git.log().add(repository.resolve(branchName)).call(); RevCommit commit = commits.iterator().next(); try (RevWalk revWalk = new RevWalk(repository)) { RevTree tree = revWalk.parseTree(commit.getTree()); try (TreeWalk treeWalk = new TreeWalk(repository)) { treeWalk.addTree(tree); treeWalk.setRecursive(true); while (treeWalk.next()) { if (treeWalk.getPathString().startsWith(folderPath) && treeWalk.getPathString().endsWith(".md")) { System.out.println("Found markdown file: " + treeWalk.getPathString()); // 這里可以根據(jù)需要進(jìn)行具體的處理,比如讀取文件內(nèi)容等 markDownFilePathList.add(treeWalk.getPathString()); } } } } } catch (IOException | GitAPIException e) { e.printStackTrace(); } return markDownFilePathList; }
打開(kāi)本地git
// 打開(kāi)本地git項(xiàng)目 private Repository openLocalRepository(File localPath) throws IOException { System.out.println("Opening existing repository..."); Git git = Git.open(localPath); return git.getRepository(); }
克隆代碼
// 克隆git private Repository cloneRepository(File localPath, String remoteUrl) throws GitAPIException { System.out.println("Cloning repository..."); Git git = Git.cloneRepository() .setURI(remoteUrl) .setDirectory(localPath) .call(); return git.getRepository(); }
拉取最新代碼
//拉取git最新代碼 private void pullLatestChanges(Repository repository) throws GitAPIException { System.out.println("Pulling latest changes..."); Git git = new Git(repository); PullCommand pull = git.pull().setTimeout(30); pull.call(); }
檢查文件內(nèi)容是否包含關(guān)鍵字
/** * @param searchKey 檢索關(guān)鍵字 * @param path markdown文本路徑 * @desc 通過(guò)關(guān)鍵字和路徑找到指定markdown文件是否內(nèi)容包含關(guān)鍵字 * */ public Boolean isContainSearchKeyForContent(String searchKey,String path) { Boolean containFlag = false; String content =""; try { content = findMarkDownBypathNoWithImage(path); }catch (Exception e) { System.out.println("獲取markdown文本失敗:"+e.getMessage()); } if (content.contains(searchKey)) { containFlag = true; } return containFlag; }
要判斷文件內(nèi)容是否包含關(guān)鍵字,不需要將文件圖片進(jìn)行解析,直接獲取文件內(nèi)容
public String findMarkDownBypathNoWithImage(String filePath) throws Exception{ String localPath = LOCAL_PATH; String markDownContent = ""; if (filePath.endsWith(".md")) { File markdownFile = new File(localPath, filePath); try (Scanner scanner = new Scanner(markdownFile)) { StringBuilder contentBuilder = new StringBuilder(); while (scanner.hasNextLine()) { contentBuilder.append(scanner.nextLine()).append("\n"); } markDownContent = contentBuilder.toString(); System.out.println("Markdown file content:\n" + markDownContent); } catch (IOException e) { throw new Exception(e.getMessage()); } } return markDownContent; }
根據(jù)路徑獲取文件
以下為會(huì)解析圖片的方式進(jìn)行獲取文件
controller層
@GetMapping("findMarkDownBypath") public ResultVO<String> findMarkDownBypath(@RequestParam("path")String path) throws Exception { try { return new ResultVO<>(new MarkDownService().findMarkDownBypathWithImage(path)); }catch (Exception e) { return new ResultVO<>(1,e.getMessage()); } }
service層
public String findMarkDownBypathWithImage(String filePath) throws Exception{ String localPath = LOCAL_PATH; String markDownContent = ""; if (filePath.endsWith(".md")) { File markdownFile = new File(localPath, filePath); try (Scanner scanner = new Scanner(markdownFile)) { StringBuilder contentBuilder = new StringBuilder(); while (scanner.hasNextLine()) { contentBuilder.append(scanner.nextLine()).append("\n"); } String markdownContent = contentBuilder.toString(); markDownContent = loadImages(markdownContent,filePath); // 在這里得到了具體的markdown文件內(nèi)容 System.out.println("Markdown file content:\n" + markdownContent); } catch (IOException e) { throw new Exception(e.getMessage()); } } return markDownContent; }
解析圖片
public String loadImages(String markdownContent, String markdownFilePath) { Pattern pattern = Pattern.compile(MARKDOWN_IMAGE_PATTERN); Matcher matcher = pattern.matcher(markdownContent); String localPath = LOCAL_PATH; StringBuffer sb = new StringBuffer(); while (matcher.find()) { String originalImageTag = matcher.group(0); String altText = matcher.group(1); String imagePath = matcher.group(2); try { String absoluteImagePath = getAbsoluteImagePath(imagePath, markdownFilePath); absoluteImagePath = absoluteImagePath.replace(PROJECT_PATH,localPath); String imageData = loadImage(absoluteImagePath); String transformedImageTag = ""; matcher.appendReplacement(sb, transformedImageTag); } catch (IOException e) { // 圖像加載出錯(cuò),可以根據(jù)實(shí)際需求進(jìn)行處理 e.printStackTrace(); } } matcher.appendTail(sb); return sb.toString(); }
public static String loadImage(String imagePath) throws IOException { File imageFile = new File(imagePath); // 讀取圖像文件的字節(jié)數(shù)組 byte[] imageData = FileUtils.readFileToByteArray(imageFile); // 將字節(jié)數(shù)組轉(zhuǎn)換為Base64編碼字符串 String base64ImageData = java.util.Base64.getEncoder().encodeToString(imageData); return "data:image/png;base64," + base64ImageData; }
public static String getAbsoluteImagePath(String imagePath, String markdownFilePath) { File markdownFile = new File(markdownFilePath); String markdownDirectory = markdownFile.getParent(); String absoluteImagePath = new File(markdownDirectory, imagePath).getAbsolutePath(); return absoluteImagePath; }
依賴
為了防止出現(xiàn)依賴可能缺失的情況,可參考我的項(xiàng)目的maven
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <groupId>org.hxc.common</groupId> <artifactId>CommonBack</artifactId> <version>1.0</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <mysql.version>5.1.47</mysql.version> <druid.version>1.1.16</druid.version> <log4j2.version>2.17.0</log4j2.version> <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.2.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <optional>true</optional> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.8</version> </dependency> <!-- swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> <exclusions> <exclusion> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> </exclusion> <exclusion> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> <version>1.5.21</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.21</version> </dependency> <!-- swagger的ui--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.5</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.5</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>${mybatis.spring.boot.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.15.0</version> </dependency> <!-- 文件處理--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <!-- POI excel處理依賴 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.9</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency> <!-- 工具類 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.8</version> </dependency> <!-- <dependency>--> <!-- <groupId>org.eclipse.jgit</groupId>--> <!-- <artifactId>org.eclipse.jgit</artifactId>--> <!-- <version>4.4.1.201607150455-r</version>--> <!-- </dependency>--> <dependency> <groupId>org.eclipse.jgit</groupId> <artifactId>org.eclipse.jgit</artifactId> <version>5.9.0.202009080501-r</version> </dependency> </dependencies> <build> <finalName>common_end</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.1.0</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.hxc.common.MarkDownApplication</mainClass> <classpathPrefix>libs/</classpathPrefix> </manifest> </archive> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>copy-dependencies</id> <phase>package</phase> <goals> <goal>copy-dependencies</goal> </goals> <configuration> <outputDirectory>${project.build.directory}/libs</outputDirectory> </configuration> </execution> </executions> </plugin> <!--跳過(guò)junit--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <skip>true</skip> </configuration> </plugin> </plugins> </build> </project>
git
以下為我實(shí)現(xiàn)讀取git的markdown的項(xiàng)目,可供參考
結(jié)語(yǔ)
以上為我實(shí)現(xiàn)vue+springboot讀取git的markdown文件并展示的過(guò)程
到此這篇關(guān)于vue+springboot讀取git的markdown文件并展示的文章就介紹到這了,更多相關(guān)vue讀取git的markdown文件并展示內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java利用java.net.URLConnection發(fā)送HTTP請(qǐng)求的方法詳解
如何通過(guò)Java(模擬瀏覽器)發(fā)送HTTP請(qǐng)求是我們?cè)谌粘=?jīng)常會(huì)遇到的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于java利用java.net.URLConnection發(fā)送HTTP請(qǐng)求的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-05-05Spring BeanPostProcessor源碼示例解析
這篇文章主要為大家介紹了Spring BeanPostProcessor源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01java.lang.NoClassDefFoundError錯(cuò)誤的原因及解決方法
這篇文章主要給大家介紹了關(guān)于java.lang.NoClassDefFoundError錯(cuò)誤的原因及解決的相關(guān)資料,java.lang.NoClassDefFoundError是Java虛擬機(jī)在運(yùn)行時(shí)無(wú)法找到特定類的錯(cuò)誤,需要的朋友可以參考下2023-10-10Java中使用@CrossOrigin和Proxy解決跨域問(wèn)題詳解
這篇文章主要介紹了Java中使用@CrossOrigin和Proxy解決跨域問(wèn)題詳解,在Web開(kāi)發(fā)中,如果前端頁(yè)面和后端接口不在同一個(gè)域名下,就會(huì)發(fā)生跨域請(qǐng)求的問(wèn)題,同源策略是瀏覽器的一種安全策略,它限制了來(lái)自不同源的客戶端腳本在瀏覽器中運(yùn)行時(shí)的交互,需要的朋友可以參考下2023-12-12使用socket實(shí)現(xiàn)網(wǎng)絡(luò)聊天室和私聊功能
這篇文章主要介紹了使用socket實(shí)現(xiàn)網(wǎng)絡(luò)聊天室和私聊功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12詳解MyBatis直接執(zhí)行SQL查詢及數(shù)據(jù)批量插入
這篇文章主要介紹了MyBatis直接執(zhí)行SQL查詢及數(shù)據(jù)批量插入的相關(guān)知識(shí),需要的朋友一起學(xué)習(xí)吧2016-01-01使用Maven打包時(shí)包含資源文件和源碼到j(luò)ar的方法
這篇文章主要介紹了使用Maven打包時(shí)包含資源文件和源碼到j(luò)ar的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn)
本文主要介紹了Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12