当前位置: 首页 > news >正文

vue+springboot读取git的markdown文件并展示

前言

最近,在研究一个如何将我们git项目的MARKDOWN文档获取到,并且可以展示到界面通过检索查到,于是经过几天的摸索,成功的研究了出来

本次前端vue使用的是Markdown-it

Markdown-it 是一个用于解析和渲染 Markdown 标记语言的 JavaScript 库。
它采用模块化的设计,提供了灵活的配置选项和丰富的插件系统,使开发者可以根据自己的需要定制 Markdown 的解析和渲染过程。

使用 Markdown-it,你可以将 Markdown 文本解析为 HTML 输出,并且可以根据需要添加功能、扩展语法或修改解析行为

后端springboot使用JGit

JGit 是一个开源的 Java 实现的 Git 客户端库,它允许开发者在 Java 程序中直接操作 Git 仓库。

JGit 提供了一些核心的 API,使开发者可以使用 Java 代码来访问和操作 Git 仓库,例如创建仓库、提交变更、分支管理、标签管理、克隆远程仓库等。它提供了对 Git 分布式版本控制系统的完整支持,能够满足日常的代码版本管理需求。

但是我们这里单纯只是将其获取git的文件进行展示markdown,因此并用不上

准备工作

前端

在前端,
我使用了element-ui前端框架写页面
使用Markdown-it 进行解析markdown
使用axios连接了前后端
因此,需要安装如上依赖,指令如下:

npm i element-ui
npm i markdown-it
npm i axios

后端

因后端为springboot项目,需要安装springboot的依赖,这里不多赘述,主要是需要安装JGit的依赖

<dependency><groupId>org.eclipse.jgit</groupId><artifactId>org.eclipse.jgit</artifactId><version>5.9.0.202009080501-r</version>
</dependency>

效果演示

那么,在说如何做之前,先介绍一下我做出来的效果吧

首先,我建立了一个git仓库 ,专门用于获取到markdown文件

在这里插入图片描述

为了程序能够获取到文件,我在data文件夹下放了四个markdown文件,并且在程序指定只获取data下的markdown文件

  • 无数据时,前端界面显示如下
    在这里插入图片描述

当什么关键字都不输入,检索全部markdown文件

在这里插入图片描述
此时展示文件

此时随便点击列表的一个文件查看

在这里插入图片描述

切换另一个
在这里插入图片描述
在这里插入图片描述

以上,我们能够发现,它能够把我们的markdown的表格,图片以及表情正确的显示出来,并且样式排版也过得去,当然,这个是可以自己调整的

多提一句,我有做一个简单的检索关键字的逻辑,逻辑如下:

  1. 什么关键字不输入的时候,检索指定文件夹下所有markdown
  2. 当输入关键字,检索文件名,如果包含关键字,则把文件路径加入集合列表
  3. 当文件名不包含关键字,判断文件内容是否包含关键字,包含也把对应文件路径加入列表

前端代码逻辑

界面部分

<template><div><el-page-header content="MarkDown展示"/><el-input v-model="searchKey" placeholder="检索问题" 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="序号"></el-table-column><el-table-column label="列表项"><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><!-- 展示区 --><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;">请检索并查看文档</div></el-card></div></el-card></div></template>

JavaScript逻辑

<script>
// 封装的axios调用后端的方法,如需要则按照自己的项目调用修改即可import {searchProblem,findMarkDownBypath} from "../ajax/api"import MarkdownIt from 'markdown-it';export default {name: "MarkDown",data() {return {searchKey: "",searchData: [], // 检索到的问题列表markdownText: '', // 加载好图片的Markdown文本markdownRenderer: null, // 解析markdown渲染器定义htmlContent: '', // 解析为html}},mounted() {this.markdownRenderer = new MarkdownIt();},methods: {// 检索文件searchProblem() {searchProblem(this.searchKey).then(res => {console.log("检索数据:",res);this.searchData = res.data.data; // 赋值检索数据,注意这里的res.data.data请根据自己实际回参更改获取参数this.markdownText = ""; // 每次检索清空markdown显示文档内容this.htmlContent = ""; // 每次检索清空markdown显示文档内容})},// 根据文件路径查找markdown文件findMarkDown(path) {console.log("path:",path);findMarkDownBypath(path).then(res => {console.log("markdown内容:",res);this.markdownText = res.data.data;this.htmlContent = this.markdownRenderer.render(this.markdownText);console.log(this.htmlContent);})},// 处理字符串,回传的参数实际为:data/学生成绩系统前端.md,将字符串进行截取changePathName(str) {if (str) {var lastIndex = str.lastIndexOf('/');var result = str.substring(lastIndex + 1);return result.replace('.md','');}return str;}}}</script>

在以上,后端传递的路径实际为:

["data/README.en.md","data/README.md","data/学生成绩系统前端.md","data/网上购药商城.md"
]

因此为了美观和直观展示,我是有做字符处理的,详情参考如何代码

此外,我后端获取到的markdown的内容实际数据为:

# search_markdown_data#### Description
用于检索markdown的数据来源#### Software Architecture
Software architecture description#### Installation1.  xxxx
2.  xxxx
3.  xxxx#### Instructions1.  xxxx
2.  xxxx
3.  xxxx#### Contribution1.  Fork the repository
2.  Create Feat_xxx branch
3.  Commit your code
4.  Create Pull Request#### Gitee Feature1.  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创建渲染器,将如上数据转换为:

<h1>search_markdown_data</h1>
<h4>Description</h4>
<p>用于检索markdown的数据来源</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 href="https://blog.gitee.com">blog.gitee.com</a></li>
<li>Explore open source project <a href="https://gitee.com/explore">https://gitee.com/explore</a></li>
<li>The most valuable open source project <a href="https://gitee.com/gvp">GVP</a></li>
<li>The manual of Gitee <a href="https://gitee.com/help">https://gitee.com/help</a></li>
<li>The most popular members  <a href="https://gitee.com/gitee-stars/">https://gitee.com/gitee-stars/</a></li>
</ol>

实际为html的数据,因此,我们就可以在界面使用vue的v-html展示markdown的内容

css样式

以上我们知道它会将数据转为html的数据,因此,就可以使用css样式调整,以下为我的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; /* 设置表头的背景颜色 */}tr:nth-child(even) {background-color: #dddddd; /* 设置偶数行的背景颜色 */}tr:hover {background-color: #f5f5f5; /* 设置鼠标悬停时的背景颜色 */}h1,h2,h3,h4,h5{border-bottom: 1px #d8d6d6 solid;}img{width: 80%;}

后端代码逻辑

先说下我的查询的方法,JGIT我尝试了很久,都只能通过先克隆到本地,再读取的方式,于是放弃了研究如何使用JGIT在线读取文件的方式,也许后面我可能研究的出来。

同样,为了保证每次都是最新的文档,我采用了判断是否已经克隆下来了,如果克隆了则更新代码,没有克隆则克隆,来保证每次都是最新代码

在正式执行前,我们需要先定义好需要的参数

// 解析markdown图片正则private static final String MARKDOWN_IMAGE_PATTERN = "(!\\[[^\\]]*\\])\\(([^\\)]+)\\)";
// 需要克隆git到本机的路径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内指定文件夹的markdownprivate final String MARK_DOWN_PATH = "data";
// 当前后端项目的位置,该目的是为了能够找到正确的文件路径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仓库中的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) {// 如果标题包含检索关键字加入列表if (path.contains(searchKey)) {results.add(path);} else {// 判断具体内容是否包含关键字,是则加入列表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为封装的响应体,如有兴趣可参考我之前文章
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());// 这里可以根据需要进行具体的处理,比如读取文件内容等markDownFilePathList.add(treeWalk.getPathString());}}}}} catch (IOException | GitAPIException e) {e.printStackTrace();}return markDownFilePathList;}

打开本地git

    // 打开本地git项目private Repository openLocalRepository(File localPath) throws IOException {System.out.println("Opening existing repository...");Git git = Git.open(localPath);return git.getRepository();}

克隆代码

    // 克隆gitprivate 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();}

检查文件内容是否包含关键字

    /*** @param searchKey 检索关键字* @param path markdown文本路径* @desc 通过关键字和路径找到指定markdown文件是否内容包含关键字* */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;}

要判断文件内容是否包含关键字,不需要将文件图片进行解析,直接获取文件内容

    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;}

根据路径获取文件

以下为会解析图片的方式进行获取文件

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文件内容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 = "![Image](" + imageData + ")";matcher.appendReplacement(sb, transformedImageTag);} catch (IOException e) {// 图像加载出错,可以根据实际需求进行处理e.printStackTrace();}}matcher.appendTail(sb);return sb.toString();}
    public static String loadImage(String imagePath) throws IOException {File imageFile = new File(imagePath);// 读取图像文件的字节数组byte[] imageData = FileUtils.readFileToByteArray(imageFile);// 将字节数组转换为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;}

依赖

为了防止出现依赖可能缺失的情况,可参考我的项目的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><!--跳过junit--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skip>true</skip></configuration></plugin></plugins></build></project>

git

以下为我实现读取git的markdown的项目,可供参考

前端

后端

结语

以上为我实现vue+springboot读取git的markdown文件并展示的过程

相关文章:

vue+springboot读取git的markdown文件并展示

前言 最近&#xff0c;在研究一个如何将我们git项目的MARKDOWN文档获取到&#xff0c;并且可以展示到界面通过检索查到&#xff0c;于是经过几天的摸索&#xff0c;成功的研究了出来 本次前端vue使用的是Markdown-it Markdown-it 是一个用于解析和渲染 Markdown 标记语言的 …...

多功能PHP图床源码:Lsky Pro开源版v2.1 – 最新兰空图床

Lsky Pro是一款功能丰富的在线图片上传和管理工具&#xff0c;即兰空图床。它不仅可以作为个人云相册&#xff0c;还可以用作写作贴图库。 该程序的初始版本于2017年10月由ThinkPHP 5开发&#xff0c;经过多个版本的迭代&#xff0c;于2022年3月发布了全新的2.0版本。 Lsky Pro…...

Hive内置表生成函数

Hive内置UDTF 1、UDF、UDAF、UDTF简介2、Hive内置UDTF 1、UDF、UDAF、UDTF简介 在Hive中&#xff0c;所有的运算符和用户定义函数&#xff0c;包括用户定义的和内置的&#xff0c;统称为UDF&#xff08;User-Defined Functions&#xff09;。如下图所示&#xff1a; UDF官方文档…...

电源控制系统架构(PCSA)之电源控制框架概览

目录 6 电源控制框架 6.1 电源控制框架概述 6.1.1 电源控制框架低功耗接口 6.1.2 电源控制框架基础设施组件 6 电源控制框架 电源控制框架是标准基础设施组件、接口和相关方法的集合&#xff0c;可用于构建SoC电源管理所需的基础设施。 本章介绍框架的主要组件和低功耗接…...

Sentinel 监控数据持久化(mysql)

Sentinel 实时监控仅存储 5 分钟以内的数据&#xff0c;如果需要持久化&#xff0c;需要通过调用实时监控接口来定制&#xff0c;即自行扩展实现 MetricsRepository 接口&#xff08;修改 控制台源码&#xff09;。 本文通过使用Mysql持久化监控数据。 1.构建存储表&#xff08…...

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码

基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于法医调查算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于法医调查优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…...

canvas高级动画001:文字瀑布流

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…...

抽象类, 接口, Object类 ---java

目录 一. 抽象类 1.1 抽象类概念 1.2 抽象类语法 1.3 抽象类特性 1.4 抽象类的作用 二. 接口 2.1 接口的概念 2.2 语法规则 2.3 接口的使用 2.4 接口间的继承 2.5 抽象类和接口的区别 三. Object类 3.1 toString() 方法 3.2 对象比较equals()方法 3.3 hash…...

SOAP 协议和 HTTP 协议:深入解读与对比

SOAP 和 HTTP 协议 SOAP 协议 SOAP&#xff08; Simple Object Access Protocol&#xff09;是一种用于在节点之间交换结构化数据的网络协议。它使用XML格式来传输消息。它在 HTML 和 SMTP 等应用层协议的基础上进行标记和传输。SOAP 允许进程在整个平台、语言和操作系统中进…...

Unity发布IOS后,使用xcode打包报错:MapFileParser.sh:Permissiondenied

1.错误提示 使用xcode打包错误提示&#xff1a;/Users/mymac/Desktop/myproject/MapFileParser.sh: Permission denied 2.解决方案 打开控制台输入&#xff1a;chmod ax /Users/mymac/Desktop/myproject/MapFileParser.sh。按回车键执行&#xff0c;然后重新使用xcode发布程序…...

2021年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 执行下列程序,屏幕上可以看到几只小猫? A:1 B:3 C:4 D:0 答案:B 第2题 下列程序哪个可以实现:按下空格键,播放完音乐后说“你好!”2秒? A: B: C:...

mac上Homebrew的安装与使用

打开终端&#xff1a;command空格 &#xff0c;搜索‘’终端 ’&#xff0c;打开终端 在终端中输入以下命令并按下回车键&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"这个命令会自动下载并安装…...

YOLOv5 分类模型 预处理 OpenCV实现

YOLOv5 分类模型 预处理 OpenCV实现 flyfish YOLOv5 分类模型 预处理 PIL 实现 YOLOv5 分类模型 OpenCV和PIL两者实现预处理的差异 YOLOv5 分类模型 数据集加载 1 样本处理 YOLOv5 分类模型 数据集加载 2 切片处理 YOLOv5 分类模型 数据集加载 3 自定义类别 YOLOv5 分类模型…...

在arm 64 环境下使用halcon算法

背景&#xff1a; halcon&#xff0c;机器视觉领域神一样得存在&#xff0c;在windows上&#xff0c;应用得特别多&#xff0c; 但是arm环境下使用得很少。那如何在arm下使用halcon呢。按照官方说明&#xff0c;arm下只提供了运行时环境&#xff0c;并且需要使用价值一万多人民…...

H5(uniapp)中使用echarts

1,安装echarts npm install echarts 2&#xff0c;具体页面 <template><view class"container notice-list"><view><view class"aa" id"main" style"width: 500px; height: 400px;"></view></v…...

QLineEdit设置掩码Ip

目的 有时&#xff0c;用单行编辑框想限制输入&#xff0c;但QLineEdit提供的setInputMask()方法用来限制输入字符或者数字还可以&#xff0c;但要做约束&#xff0c;得和验证器结合。 setInputMash()描述 此属性包含验证输入掩码 如果没有设置掩码&#xff0c;inputMask() …...

开源语音大语言模型来了!阿里基于Qwen-Chat提出Qwen-Audio!

论文链接&#xff1a;https://arxiv.org/pdf/2311.07919.pdf 开源代码&#xff1a;https://github.com/QwenLM/Qwen-Audio 引言 大型语言模型&#xff08;LLMs&#xff09;由于其良好的知识保留能力、复杂的推理和解决问题能力&#xff0c;在通用人工智能&#xff08;AGI&am…...

缓存雪崩、击穿、穿透及解决方案_保证缓存和数据库一致性

文章目录 缓存雪崩、击穿、穿透1.缓存雪崩造成缓存雪崩解决缓存雪崩 2. 缓存击穿造成缓存击穿解决缓存击穿 3.缓存穿透造成缓存穿透解决缓存穿透 更新数据时&#xff0c;如何保证数据库和缓存的一致性&#xff1f;1. 先更新数据库&#xff1f;先更新缓存&#xff1f;解决方案 2…...

仿 美图 / 饿了么,店铺详情页功能

前言 UI有所不同&#xff0c;但功能差不多&#xff0c;商品添加购物车功能 正在写&#xff0c;写完会提交仓库。 效果图一&#xff1a;左右RecyclerView 联动 效果图二&#xff1a;通过点击 向上偏移至最大值 效果图三&#xff1a;通过点击 或 拖动 展开收缩公告 效果图四&…...

Redis Cluster主从模式详解

在软件的架构中&#xff0c;主从模式&#xff08;Master-Slave&#xff09;是使用较多的一种架构。主&#xff08;Master&#xff09;和从&#xff08;Slave&#xff09;分别部署在不同的服务器上&#xff0c;当主节点服务器写入数据时&#xff0c;同时也会将数据同步至从节点服…...

Python爬虫实战:研究MechanicalSoup库相关技术

一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

黑马Mybatis

Mybatis 表现层&#xff1a;页面展示 业务层&#xff1a;逻辑处理 持久层&#xff1a;持久数据化保存 在这里插入图片描述 Mybatis快速入门 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6501c2109c4442118ceb6014725e48e4.png //logback.xml <?xml ver…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...