个人博客项目笔记_05

news2024/11/25 4:26:08

1. ThreadLocal内存泄漏

在这里插入图片描述

ThreadLocal 内存泄漏是指由于没有及时清理 ThreadLocal 实例所存储的数据,导致这些数据在线程池或长时间运行的应用中累积过多,最终导致内存占用过高的情况。

内存泄漏通常发生在以下情况下:

  1. 线程池场景下的 ThreadLocal 使用不当: 在使用线程池时,如果线程被重用而没有正确清理 ThreadLocal 中的数据,那么下次使用这个线程时,它可能会携带上一次执行任务所遗留的数据,从而导致数据累积并消耗内存。
  2. 长时间运行的应用中未清理 ThreadLocal 数据: 在一些长时间运行的应用中,比如 Web 应用,可能会创建很多 ThreadLocal 实例并存储大量数据。如果这些数据在使用完后没有及时清理,就会导致内存泄漏问题。
  3. 没有使用 remove() 方法清理 ThreadLocal 数据: 在使用完 ThreadLocal 存储的数据后,如果没有调用 remove() 方法清理数据,就会导致数据长时间存在于 ThreadLocal 中,从而可能引发内存泄漏。

实线代表强引用,虚线代表弱引用

每一个Thread维护一个ThreadLocalMap, key为使用弱引用的ThreadLocal实例,value为线程变量的副本。

强引用,使用最普遍的引用,一个对象具有强引用,不会被垃圾回收器回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不回收这种对象。

如果想取消强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样可以使JVM在合适的时间就会回收该对象。

弱引用,JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。

2. 文章详情

2.1 接口说明

接口url:/articles/view/{id}

请求方式:POST

请求参数:

参数名称参数类型说明
idlong文章id(路径参数)

返回数据:

{
    "success": true,
    "code": 200,
    "msg": "success",
    "data": "token"
}

2.2 涉及到的表

CREATE TABLE `blog`.`ms_article_body`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `content` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
  `content_html` longtext CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
  `article_id` bigint(0) NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `article_id`(`article_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
package com.cherriesovo.blog.dao.pojo;

import lombok.Data;

@Data
public class ArticleBody {	//文章详情表

    private Long id;
    private String content;
    private String contentHtml;
    private Long articleId;
}
#文章分类
CREATE TABLE `blog`.`ms_category`  (
  `id` bigint(0) NOT NULL AUTO_INCREMENT,
  `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `category_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
package com.cherriesovo.blog.dao.pojo;

import lombok.Data;

@Data
public class Category {

    private Long id;

    private String avatar;

    private String categoryName;

    private String description;
}

2.3 Controller

//json数据进行交互
@RestController
@RequestMapping("articles")
public class ArticleController {
    /*
    * 通过id获取文章
    * */
    @PostMapping("view/{id}")
    	//@PathVariable("id") 注解用于将 URL 中的 {id} 赋值给 articleId 参数。
    public Result findArticleById(@PathVariable("id") Long articleId) {	

        return articleService.findArticleById(articleId);
    }
}

2.4 Service

 ArticleVo findArticleById(Long id);
public interface ArticleService {
    
    //查看文章详情
    Result findArticleById(Long articleId);
}

package com.cherriesovo.blog.vo;


import lombok.Data;

import java.util.List;

@Data
public class ArticleVo {

    private Long id;

    private String title;

    private String summary;

    private int commentCounts;

    private int viewCounts;

    private int weight;
    /**
     * 创建时间
     */
    private String createDate;

    private String author;

    private ArticleBodyVo body;

    private List<TagVo> tags;

    private CategoryVo category;

}
@Service
public class ArticleServiceImpl implements ArticleService {
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private TagService tagService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private CategoryService categoryService;

    public ArticleVo copy(Article article,boolean isAuthor,boolean isBody,boolean isTags,boolean isCategory){
        ArticleVo articleVo = new ArticleVo();
        BeanUtils.copyProperties(article, articleVo);

        articleVo.setCreateDate(new DateTime(article.getCreateDate()).toString("yyyy-MM-dd HH:mm"));
        //并不是所有的接口都需要标签,作者信息
        if(isTags){
            Long articleId = article.getId();
            articleVo.setTags(tagService.findTagsByArticleId(articleId));
        }
        if(isAuthor){
            Long authorId = article.getAuthorId();
            //getNickname()用于获取某个对象或实体的昵称或别名
            articleVo.setAuthor(sysUserService.findUserById(authorId).getNickname());
        }
        if (isBody){
            Long bodyId = article.getBodyId();
            articleVo.setBody(findArticleBodyById(bodyId));
        }
        if (isCategory){
            Long categoryId = article.getCategoryId();
            articleVo.setCategory(categoryService.findCategoryById(categoryId));
        }
        return articleVo;
    }

    private List<ArticleVo> copyList(List<Article> records,boolean isAuthor,boolean isBody,boolean isTags) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article article : records) {
            ArticleVo articleVo = copy(article,isAuthor,false,isTags,false);
            articleVoList.add(articleVo);
        }
        return articleVoList;
    }

    private List<ArticleVo> copyList(List<Article> records,boolean isAuthor,boolean isBody,boolean isTags,boolean isCategory) {
        List<ArticleVo> articleVoList = new ArrayList<>();
        for (Article article : records) {
            ArticleVo articleVo = copy(article,isAuthor,isBody,isTags,isCategory);
            articleVoList.add(articleVo);
        }
        return articleVoList;
    }

    @Autowired
    private ArticleBodyMapper articleBodyMapper;
    
    private ArticleBodyVo findArticleBodyById(Long bodyId) {
        ArticleBody articleBody = articleBodyMapper.selectById(bodyId);
        ArticleBodyVo articleBodyVo = new ArticleBodyVo();
        articleBodyVo.setContent(articleBody.getContent());//setContent()是articleBodyVo的set方法
        return articleBodyVo;
    }

    @Override
    public List<ArticleVo> listArticlesPage(PageParams pageParams) {
    //  分页查询article数据库表
        QueryWrapper<Article> queryWrapper = new QueryWrapper<>();
        Page<Article> page = new Page<>(pageParams.getPage(),pageParams.getPageSize());
        Page<Article> articlePage = articleMapper.selectPage(page, queryWrapper);
        List<ArticleVo> articleVoList = copyList(articlePage.getRecords(),true,false,true);
        return articleVoList;
    }

    @Override
    public Result hotArticle(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getViewCounts);   //根据浏览量倒序
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.last("limit " + limit);
        //select id,title from article order by view_counts desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);
        return Result.success(copyList(articles,false,false,false));
    }

    @Override
    public Result newArticles(int limit) {
        LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(Article::getCreateDate);
        queryWrapper.select(Article::getId,Article::getTitle);
        queryWrapper.last("limit "+limit);
        //select id,title from article order by create_date desc limit 5
        List<Article> articles = articleMapper.selectList(queryWrapper);

        return Result.success(copyList(articles,false,false,false));
    }

    @Override
    public Result listArchives() {
        List<Archives> archivesList = articleMapper.listArchives();
        return Result.success(archivesList);
    }

    @Override
    public Result findArticleById(Long articleId) {
        /*
        * 1、根据id查询文章信息
        * 2、根据bodyId和categoryId去做关联查询
        * */
        Article article = this.articleMapper.selectById(articleId);
        ArticleVo articleVo = copy(article, true, true, true,true);
        return Result.success(articleVo);
    }
}
package com.cherriesovo.blog.vo;

import lombok.Data;

@Data
public class CategoryVo {

    private Long id;

    private String avatar;

    private String categoryName;
}
package com.cherriesovo.blog.vo;

import lombok.Data;

@Data
public class ArticleBodyVo {

    private String content;
}

package com.cherriesovo.blog.service;

import com.cherriesovo.blog.vo.CategoryVo;

import java.util.List;

public interface CategoryService {
    CategoryVo findCategoryById(Long categoryId);
}

@Service
public class CategoryServiceImpl implements CategoryService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Override
    public CategoryVo findCategoryById(Long categoryId) {
        Category category = categoryMapper.selectById(categoryId);
        CategoryVo categoryVo = new CategoryVo();
        BeanUtils.copyProperties(category,categoryVo);
        return categoryVo;
    }
}
package com.cherriesovo.blog.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.pojo.ArticleBody;

public interface ArticleBodyMapper extends BaseMapper<ArticleBody> {
}

package com.cherriesovo.blog.dao.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cherriesovo.blog.dao.pojo.Category;

public interface CategoryMapper extends BaseMapper<Category> {
}

2.5 测试

3. 使用线程池 更新阅读次数

3.1 线程池配置

  1. taskExecutor 是一个线程池对象,在这段代码中通过 @Bean("taskExecutor") 注解定义并配置了一个线程池,并将其命名为 “taskExecutor”。
  2. asyncServiceExecutor() 方法是一个 Bean 方法,用于创建并配置一个线程池,并以 taskExecutor 作为 Bean 的名称。
  3. ThreadPoolTaskExecutor 是 Spring 框架提供的一个实现了 Executor 接口的线程池
  4. 在方法中创建了一个 ThreadPoolTaskExecutor 实例 executor,并对其进行了一系列配置:
    • setCorePoolSize(5): 设置核心线程数为 5,即线程池在空闲时会保持 5 个核心线程。
    • setMaxPoolSize(20): 设置最大线程数为 20,即线程池中允许的最大线程数量。
    • setQueueCapacity(Integer.MAX_VALUE): 配置队列大小为整数的最大值,即任务队列的最大容量。
    • setKeepAliveSeconds(60): 设置线程活跃时间为 60 秒,即线程在空闲超过该时间后会被销毁。
    • setThreadNamePrefix("CherriesOvO博客项目"): 设置线程名称的前缀为 “CherriesOvO博客项目”。
    • setWaitForTasksToCompleteOnShutdown(true): 设置在关闭线程池时等待所有任务结束。
    • initialize(): 执行线程池的初始化。
  5. 最后,将配置好的线程池返回为一个 Executor Bean,供其他组件使用。
package com.cherriesovo.blog.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync    //开启多线程
public class ThreadPoolConfig {

    @Bean("taskExecutor")
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心线程数
        executor.setCorePoolSize(5);
        // 设置最大线程数
        executor.setMaxPoolSize(20);
        //配置队列大小
        executor.setQueueCapacity(Integer.MAX_VALUE);
        // 设置线程活跃时间(秒)
        executor.setKeepAliveSeconds(60);
        // 设置默认线程名称
        executor.setThreadNamePrefix("CherriesOvO博客项目");
        // 设置等待所有任务结束后再关闭线程池
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //执行初始化
        executor.initialize();
        return executor;
    }
}

3.1 使用

  1. 通过 @Async("taskExecutor") 注解,该方法标记为异步执行,并指定了使用名为 “taskExecutor” 的线程池。

  2. articleMapper.update(articleUpdate, updateWrapper) 是一个 MyBatis-Plus 中的更新操作,用于更新数据库中的文章记录。

    update 方法接受两个参数:

    1. articleUpdate:表示需要更新的文章对象,其中包含了新的阅读量。
    2. updateWrapper:表示更新条件,即确定哪些文章需要被更新的条件。
  3. 这段代码通过 Thread.sleep(5000) 方法在当前线程中休眠了5秒钟。这样做的目的是为了模拟一个耗时操作,以展示在异步线程中执行的任务不会影响到主线程的执行。

package com.cherriesovo.blog.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cherriesovo.blog.dao.mapper.ArticleMapper;
import com.cherriesovo.blog.dao.pojo.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class ThreadService {

    //期望此操作在线程池中执行,不会影响原有的主线程
    @Async("taskExecutor")
    public void updateArticleViewCount(ArticleMapper articleMapper, Article article){

        int viewCounts = article.getViewCounts();
        Article articleUpdate = new Article();
        articleUpdate.setViewCounts(viewCounts + 1);
        LambdaQueryWrapper<Article> updateWrapper = new LambdaQueryWrapper<>();
        updateWrapper.eq(Article::getId,article.getId());
        //设置一个 为了在多线程环境下 线程安全
        updateWrapper.eq(Article::getViewCounts,article.getViewCounts());
		//update article set view_count=? where view_count=? and id=?
        articleMapper.update(articleUpdate,updateWrapper);
        try {
            //睡眠5秒 证明不会影响主线程的使用,5秒后数据才会出现
            Thread.sleep(5000);
//            System.out.println("更新完成了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ThreadService threadService;
    @Override
    public Result findArticleById(Long articleId) {
        /*
        * 1、根据id查询文章信息
        * 2、根据bodyId和categoryId去做关联查询
        * */
        Article article = this.articleMapper.selectById(articleId);
        ArticleVo articleVo = copy(article, true, true, true,true);
        //查看完文章了,新增阅读数,有没有问题?
        //查看完文章之后,本应该直接返回数据了,这时候做了一个更新操作,更新时加写锁,阻塞其他读操作,性能比较低
        //更新增加此时接口的耗时,如果一旦更新出问题,不能影响查看文章的操作
        //线程池  可以把更新操作扔到线程池中去执行,和主线程就不相关了
        threadService.updateArticleViewCount(articleMapper,article);
        return Result.success(articleVo);
    }
}

3.3 测试

  • 2、根据bodyId和categoryId去做关联查询
    * */
    Article article = this.articleMapper.selectById(articleId);
    ArticleVo articleVo = copy(article, true, true, true,true);
    //查看完文章了,新增阅读数,有没有问题?
    //查看完文章之后,本应该直接返回数据了,这时候做了一个更新操作,更新时加写锁,阻塞其他读操作,性能比较低
    //更新增加此时接口的耗时,如果一旦更新出问题,不能影响查看文章的操作
    //线程池 可以把更新操作扔到线程池中去执行,和主线程就不相关了
    threadService.updateArticleViewCount(articleMapper,article);
    return Result.success(articleVo);
    }
    }

## 3.3 测试

睡眠 ThredService中的方法 5秒,不会影响主线程的使用,即文章详情会很快的显示出来,不受影响

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1588159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mysql内存表及使用场景(12/16)

内存表&#xff08;Memory引擎&#xff09; InnoDB引擎使用B树作为主键索引&#xff0c;数据按照索引顺序存储&#xff0c;称为索引组织表&#xff08;Index Organized Table&#xff09;。 Memory引擎的数据和索引分开存储&#xff0c;数据以数组形式存放&#xff0c;主键索…

个人博客项目笔记_07

写文章 写文章需要 三个接口&#xff1a; 获取所有文章类别 获取所有标签 发布文章 1. 所有文章分类 1.1 接口说明 接口url&#xff1a;/categorys 请求方式&#xff1a;GET 请求参数&#xff1a; 参数名称参数类型说明 返回数据&#xff1a; {"success":…

PyTorch-Lightning:trining_step的自动优化

文章目录 PyTorch-Lightning&#xff1a;trining_step的自动优化总结&#xff1a; class _ AutomaticOptimization()def rundef _make_closuredef _training_stepclass ClosureResult():def from_training_step_output class Closure PyTorch-Lightning&#xff1a;trining_ste…

算法 分割字符串为实体类

题目 String userData "10000:张三:男:1998-01-01#10001:张三:男:1998-01-01#10002:李四:女:1999-02-02#10003:王五:男:2000-03-03#10004:赵六:女:2001-04-04"; String[] usersArray userData.split("#"); // 使用Stream API将字符串数组转换为SysUser对…

ALV合并单元格

1、文章说明 在开发一些报表时&#xff0c;需要显示双层的标题&#xff0c;或者合并单元格的数据&#xff0c;归根结底就是要实现类似EXCEL合并单元格的需求。如图所示 网上的资料&#xff0c;很多根据国外某大神的方法实现&#xff1a;https://tricktresor.de/blog/zellen-ver…

JavaScript(四)-Web APIS

文章目录 日期对象实例化时间对象方法时间戳 节点操作DOM节点查找节点增加节点删除节点 M端事件JS插件Window对象BOM&#xff08;浏览器对象模型&#xff09;定时器-延时函数JS执行机制location对象navigator对象history对象 本地存储本地存储介绍本地存储分类localStoragesess…

Play Module Factory:Codigger系统上的高效Module开发工具

Play Module Factory&#xff0c;这款在Codigger系统上独树一帜的Play-Module开发工具&#xff0c;为广大的开发者们提供了一个全新的、高效的插件开发平台。它汇集了丰富的模板资源、基础库、API接口以及语言支持&#xff0c;这些功能强大的工具组合在一起&#xff0c;使得开发…

14亿美元!德国默克与AI生物科技公司合作;马斯克Neuralink首位脑机接口植入者用意念打游戏;黄仁勋在俄勒冈州立大学开讲

AI for Science 的新成果、新动态、新视角—— 日本第一 IT 公司富士通&#xff1a;生成式 AI 加速药物研发 马斯克&#xff1a;Neuralink 首位脑机接口植入者用「意念」打游戏 默克与 AI 生物科技公司 Caris 达成合作 AI 蛋白质设计服务提供商「天鹜科技」完成数千万元 Pre…

VE、希喂、PR猫咪主食冻干怎么样?测评品控最强、配方最好主食冻干!

我发现还是有不少铲屎官局限于“进口最高贵”&#xff0c;盲目的迷信进口产品。看到进口粮就盲买&#xff0c;甚至过分的贬低国产品牌&#xff0c;将国产粮贴上“不靠谱”“不合格”等标签。 最近&#xff0c;我针对主食冻干的国内、国际标准&#xff0c;相关规范文件&#xf…

C++资源重复释放问题

这不是自己释放了2次&#xff1b; 可能是类互相引用&#xff0c;有类似现象释放资源时引起&#xff1b;还不太了解&#xff1b; 类对象作为函数参数也会引起&#xff1b; 下面是一个简单示例&#xff1b; #include <iostream> #include <string.h> #include &l…

如何快速写一份简历

文章目录 如何快速写一份简历一些写简历的技巧 最近一段时间一直在忙简历相关的事情&#xff0c;起初是有一个其他行业的朋友问我&#xff0c;说这些简历我写了好久真难写&#xff0c;我说你可以借助AI&#xff0c;现在这种工具多了去了&#xff0c;为什么不借助呢&#xff1f;…

2024年 Mathorcup高校数学建模竞赛(B题)| 甲骨文识别 | 特征提取,图像分割解析,小鹿学长带队指引全代码文章与思路

我是鹿鹿学长&#xff0c;就读于上海交通大学&#xff0c;截至目前已经帮200人完成了建模与思路的构建的处理了&#xff5e; 本篇文章是鹿鹿学长经过深度思考&#xff0c;独辟蹊径&#xff0c;通过神经网络解决甲骨文识别问题。结合特征提取&#xff0c;图像分割等多元算法&…

Apabi Reader软件:打开ceb文件

Apabi Reader软件&#xff1a;打开ceb文件 软件下载软件安装 打开ceb文件参考 软件下载 下载官网-Apabi Reader软件 软件安装 打开ceb文件 ceb文件目录如下&#xff1a; 打开文件如下&#xff1a; 参考

从“黑箱”到“透明”:云里物里电子标签助力汽车总装数字化转型

“汽车总装”指“汽车产品&#xff08;包括整车及总成等&#xff09;的装配”&#xff0c;是把经检验合格的数以百计、或数以千计的各种零部件按照一定的技术要求组装成整车及发动机、变速器等总成的工艺过程&#xff0c;是汽车产品制造过程中最重要的工艺环节之一。 其中&…

社交网络与Web3:数字社交的下一阶段

随着信息技术的飞速发展&#xff0c;人们的社交方式也发生了巨大的变化。从最初的互联网聊天室到如今的社交网络平台&#xff0c;我们已经见证了数字社交的不断演变和发展。而随着区块链技术的兴起&#xff0c;Web3时代的到来将为数字社交带来全新的可能性和挑战。本文将探讨社…

.NET MAUI使用Visual Studio Android Emulator(安卓模拟器)运行

Android Emulator&#xff08;安卓模拟器&#xff09;运行&#xff1a; 安卓模拟器一直卡在不动&#xff1a; 在某些情况下&#xff0c;在“打开或关闭 Windows 功能”对话框中启用 Hyper-V 和 Windows 虚拟机监控程序平台后可能无法正确启用Hyper-V。 我就是开启Hyper-V才把安…

Python网络爬虫中JSON格式数据存储详解

目录 一、引言 二、JSON格式数据简介 三、Python中处理JSON数据 四、网络爬虫中获取JSON数据 五、存储JSON数据到文件 六、从文件中读取JSON数据 七、注意事项和常见问题 八、总结 一、引言 在网络爬虫的应用中&#xff0c;JSON格式数据以其轻量级、易读易写的…

Redis性能管理和集群的三种模式(二)

一、Redis集群模式 1.1 redis的定义 redis 集群 是一个提供高性能、高可用、数据分片、故障转移特性的分布式数据解决方案 1.2 redis的功能 数据分片&#xff1a;redis cluster 实现了数据自动分片&#xff0c;每个节点都会保存一份数据故障转移&#xff1a;若个某个节点发生故…

2024年第十四届 Mathorcup (B题)| 甲骨文智能识别 | 深度学习 计算机视觉 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 让我们来看看Mathorcup (B题&#xff09;&#xff01; CS团队…

基于springboot+vue的汽车租赁管理系统

背景介绍: 网络发展的越来越迅速&#xff0c;它深刻的影响着每一个人生活的各个方面。每一种新型事务的兴起都是为了使人们的生活更加方便。汽车租赁管理系统是一种低成本、更加高效的电子商务方式&#xff0c;它已慢慢的成为一种全新的管理模式。人们不再满足于在互联网上浏览…