【Mybatis Plus】Mybatis Plus_快速上手

news2024/12/23 23:48:56

文章目录

    • 1.Mybatis Plus 简介
    • 2.与SpringBoot集成
      • 2.1在maven中引入MP依赖
      • 2.3 在application.yml中,配置好自己的数据库文件
    • 3. 快速上手 创建实体类entity/User.java
      • 3.1创建通用Mapper
      • 3.2 使用继承了BaseMapper的Mapper开始编写Crud
        • 3.2.1 Insert
        • 3.2.2 deleted
        • 3.2.3 update
        • 3.2.4 select
    • 4.创建通用Service
      • 4.1 创建通用Service
      • 4.2 使用继承了IService<User>和ServiceImpl<UserMapper, User>的UserServiceImpl开始编写Crud
        • 4.2.1 save
        • 4.2.2 saveOrUpdate
        • 4.2.3 remove
        • 4.2.3 update
        • 4.2.4 get(重)
        • 4.2.5 list
        • 4.2.6 page (重)
        • 4.2.7 count

1.Mybatis Plus 简介

Mybatis-plus简介:Mybatis增强工具,只做增强,不作改变,简化开发,提高效率。所以MP使用crud、本身是无性能损耗的。

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,提供了大量的通用的CRUD方法,因此可以省去大量手写sql的语句的工作。
  • 条件构造器:提供了强大的条件构造器,可以构造各种复杂的查询条件,以应对各种复杂查询。
  • 内置分页插件:配置好插件之后,写分页等同于普通 List 查询,无需关注分页逻辑。

2.与SpringBoot集成

2.1在maven中引入MP依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.2</version>
</dependency>

2.3 在application.yml中,配置好自己的数据库文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 1234
    url: jdbc:mysql://192.168.123.121:3306/mp_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8

3. 快速上手 创建实体类entity/User.java

@Data
@TableName("user")
public class User {

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @TableField("name")
    private String name;

    @TableField("age")
    private Integer age;

    @TableField("email")
    private String email;
}

解释一下上面几个注解的作用

实体类中的三个注解的含义如下

  • @TableName:表名注解,用于标识实体类所对应的表

    • value:用于声明表名
  • @TableId:主键注解,用于标识主键字段

    • value:用于声明主键的字段名
    • type:用于声明主键的生成策略,常用的策略有AUTOASSIGN_UUIDINPUT等等
  • @TableField:普通字段注解,用于标识属性所对应的表字段

    • value:用于声明普通字段的字段名

3.1创建通用Mapper

在这里插入图片描述

通用Mapper提供了许多自带的CRUD方法,可以省去大量编写重复简单的Sql语句工作,使用步骤在下面

1.创建Mapper接口
创建Mapper接口后需要继承MP提供的BaseMapper接口,T表示实体类

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

如果Mapper接口过多,不用每一个使用@Mapper注解,使用MapperScan注解扫描对应的maapper文件包就行

@MapperScan("com.code.mptest.mapper")

3.2 使用继承了BaseMapper的Mapper开始编写Crud

3.2.1 Insert
// 插入一条记录
int insert(T entity);

功能描述: 插入一条记录。
返回值: int,表示插入操作影响的行数,通常为 1,表示插入成功。
参数说明:
在这里插入图片描述
示例(insert):

User user = new User();
user.setName("John Doe");
user.setEmail("john.doe@example.com");
int rows = userMapper.insert(user); // 调用 insert 方法
if (rows > 0) {
    System.out.println("User inserted successfully.");
} else {
    System.out.println("Failed to insert user.");
}

生成的 SQL:

INSERT INTO user (name, email) VALUES (?, ?)
3.2.2 deleted
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

功能描述: 删除符合条件的记录。
返回值: int,表示删除操作影响的行数,通常为 1,表示删除成功。
参数说明:
在这里插入图片描述
示例

// (delete):假设有一个 QueryWrapper 对象,设置查询条件为 age > 25,删除满足条件的用户
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 25);
int rows = userMapper.delete(queryWrapper); // 调用 delete 方法
if (rows > 0) {
    System.out.println("Users deleted successfully.");
} else {
    System.out.println("No users deleted.");
}

// (deleteBatchIds):假设有一组 ID 列表,批量删除用户
List<Integer> ids = Arrays.asList(1, 2, 3);
int rows = userMapper.deleteBatchIds(ids); // 调用 deleteBatchIds 方法
if (rows > 0) {
    System.out.println("Users deleted successfully.");
} else {
    System.out.println("No users deleted.");
}

// (deleteById):根据 ID 删除单个用户
int userId = 1;
int rows = userMapper.deleteById(userId); // 调用 deleteById 方法
if (rows > 0) {
    System.out.println("User deleted successfully.");
} else {
    System.out.println("No user deleted.");
}

// (deleteByMap):假设有一个 columnMap,设置查询条件为 age = 30,删除满足条件的用户
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("age", 30);
int rows = userMapper.deleteByMap(columnMap); // 调用 deleteByMap 方法
if (rows > 0) {
    System.out.println("Users deleted successfully.");
} else {
    System.out.println("No users deleted.");
}

3.2.3 update
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

功能描述: 更新符合条件的记录。
返回值: int,表示更新操作影响的行数,通常为 1,表示更新成功。
参数说明:
在这里插入图片描述

3.2.4 select
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

功能描述: 查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
在这里插入图片描述

4.创建通用Service

通用Service进一步封装了通用Mapper的CRUD方法,并提供了例如saveOrUpdatesaveBatch等高级方法。
在这里插入图片描述

4.1 创建通用Service

  1. 创建Service接口

    创建UserService,内容如下

    public interface UserService extends IService<User> {
    }
    
  2. 创建Service实现类

    创建UserServiceImpl,内容如下

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    }
    

4.2 使用继承了IService和ServiceImpl<UserMapper, User>的UserServiceImpl开始编写Crud

4.2.1 save
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);

功能描述: 插入记录,根据实体对象的字段进行策略性插入。
返回值: boolean,表示插入操作是否成功。
参数说明:
在这里插入图片描述

4.2.2 saveOrUpdate
// TableId 注解属性值存在则更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

功能描述: 根据实体对象的主键 ID 进行判断,存在则更新记录,否则插入记录。
返回值: boolean,表示插入或更新操作是否成功。
参数说明:
在这里插入图片描述

4.2.3 remove
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

功能描述: 通过指定条件删除符合条件的记录。
返回值: boolean,表示删除操作是否成功。
参数说明:
在这里插入图片描述

4.2.3 update
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);

功能描述: 通过指定条件更新符合条件的记录。
返回值: boolean,表示更新操作是否成功。
参数说明:
在这里插入图片描述

4.2.4 get(重)
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

功能描述: 根据指定条件查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
在这里插入图片描述

4.2.5 list
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

功能描述: 查询符合条件的记录。
返回值: 查询结果,可能是实体对象、Map 对象或其他类型。
参数说明:
在这里插入图片描述

4.2.6 page (重)
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

功能描述: 分页查询符合条件的记录。
返回值: 分页查询结果,包含记录列表和总记录数。
参数说明:
在这里插入图片描述
示例(page):

// 假设要进行无条件的分页查询,每页显示10条记录,查询第1页
IPage<User> page = new Page<>(1, 10);
IPage<User> userPage = userService.page(page); // 调用 page 方法
List<User> userList = userPage.getRecords();
long total = userPage.getTotal();
System.out.println("Total users: " + total);
for (User user : userList) {
    System.out.println("User: " + user);
}

示例(page QueryWrapper 形式):

// 假设有一个 QueryWrapper 对象,设置查询条件为 age > 25,进行有条件的分页查询
IPage<User> page = new Page<>(1, 10);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 25);
IPage<User> userPage = userService.page(page, queryWrapper); // 调用 page 方法
List<User> userList = userPage.getRecords();
long total = userPage.getTotal();
System.out.println("Total users (age > 25): " + total);
for (User user : userList) {
    System.out.println("User: " + user);
}

示例

// 示例(pageMaps):
// 假设要进行无条件的分页查询,并将结果映射为 Map,每页显示10条记录,查询第1页
IPage<User> page = new Page<>(1, 10);
IPage<Map<String, Object>> userPageMaps = userService.pageMaps(page); // 调用 pageMaps 方法
List<Map<String, Object>> userMapList = userPageMaps.getRecords();
long total = userPageMaps.getTotal();
System.out.println("Total users: " + total);
for (Map<String, Object> userMap : userMapList) {
    System.out.println("User Map: " + userMap);
}

//示例(pageMaps QueryWrapper 形式):
// 假设有一个 QueryWrapper 对象,设置查询条件为 age > 25,进行有条件的分页查询,并将结果映射为 Map
IPage<User> page = new Page<>(1, 10);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 25);
IPage<Map<String, Object>> userPageMaps = userService.pageMaps(page, queryWrapper); // 调用 pageMaps 方法
List<Map<String, Object>> userMapList = userPageMaps.getRecords();
long total = userPageMaps.getTotal();
System.out.println("Total users (age > 25): " + total);
for (Map<String, Object> userMap : userMapList) {
    System.out.println("User Map: " + userMap);
}
4.2.7 count
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

//自3.4.3.2开始,返回值修改为long
// 查询总记录数
long count();
// 根据 Wrapper 条件,查询总记录数
long count(Wrapper<T> queryWrapper);

功能描述: 查询符合条件的记录总数。
返回值: 符合条件的记录总数。
参数说明:
在这里插入图片描述

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

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

相关文章

5.1树的基本概念

5.11树的定义 树是n>0的有限集.树适用于有层次结构的数据 只有根节点无前驱 只有叶子节点无后继 有后继的节点为分支节点 除根节点外,任何一个节点都有且只有一个前驱 5.12树的基本术语 祖先节点:从k-->R经过的所有节点 子孙节点:从一个节点出发后下面的所有节点 …

Oracle【plsql编写九九乘法表】

九九乘法表 DECLAREi NUMBER : 1;j NUMBER : 1; BEGINFOR i IN 1 .. 9LOOPFOR j IN 1 .. iLOOPDBMS_OUTPUT.put (i || * || j || || i * j || );END LOOP;DBMS_OUTPUT.put_line ( );END LOOP; END;输出结果

【YashanDB数据库】Ubuntu系统加载Yashan C驱动后无法使用PHP

【问题分类】驱动使用 【关键字】驱动使用、PHP、Ubuntu、C驱动 【问题描述】 客户将YashanDB的C驱动lib加载到环境变量LD_LIBRARY_PATH后&#xff0c;PHP报错&#xff1a;PHP Fatal error&#xff1a;Unable to start pcre module in Unknown on line 0 【问题原因分析】经…

集成学习:融合多个模型

集成学习 是一种机器学习范式&#xff0c;它创建一组模型&#xff0c;并将它们的预测结果结合起来&#xff0c;以期望最终模型能够优于单个模型。集成学习的关键在于如何有效地结合不同的模型。 集成学习算法分为&#xff1a;Bagging&#xff0c;Boosting和Stacking等类型。 B…

关于k8s集群的存储卷

目录 1.emptyDir存储卷 2.hostPath存储卷 3.nfs共享存储卷 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的…

大神器! 直接显示中英文期刊的等级, 及该期刊在中国顶级大学的认可度!

今天&#xff0c;推荐一款学术神器——easyScholar&#xff0c;别看这个插件小小的&#xff0c;它的功能非常强大。 它可以显示期刊的影响因子、中科院分区、JCR分区等信息&#xff01; 比如&#xff0c;它可以在知网数据库中显示期刊等级信息。 也能够在万方数据库中显示期刊等…

【Linux WEB】Linux嵌入式WEB服务器(BOA)部署

1. 下载boa源码 进入官网下载http://www.boa.org/news.html&#xff0c;版本为0.94.13 2. 交叉编译boa源码 2.1 解压boa源码压缩包   将下载好的压缩包放入到Ubuntu系统中进行解压 tar -zxvf boa-0.94.13.tar.gz 2.2 生成并配置Makefile文件 &#xff08;1&#xff09;将…

交换机常用的贴片网络变压器,滤波器H5084NL / H82409S

华强盛电子导读千兆交换机&#xff1a; 199/2643/0038 在交换机行业中&#xff0c;常用的贴片网络变压器和滤波器型号会根据具体的应用需求、性能指标、成本考量等因素而有所不同。通常&#xff0c;这些器件需要满足网络通信中的高频传输、阻抗匹配、信号隔离、电磁兼容&…

【C++】vector 的模拟实现

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

⌈ 传知代码 ⌋ CNN实现脑电信号的情感识别

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

怎么压缩ppt文件?4个常用的PPT压缩技巧分享!

在当今数字化的工作和学习环境中&#xff0c;PPT已经成为我们表达观点、展示成果的重要工具。然而&#xff0c;有时PPT文件的体积过大&#xff0c;给我们的分享和存储带来了诸多不便&#xff0c;表现在&#xff1a;无端占用宝贵的磁盘空间&#xff0c;接收下载耗费时间长等。 …

KSV1(KSU1)/KSV5(KSU5)-创建分配(分摊)规则/运行分配

将A成本中心费用分摊给B、C两个成本中心&#xff1a; 将B、C两个成本中心建一个成本中心组KSV1-创建分配规则 选择发送方的成本中心&#xff0c;选择接收方的成本中心 给不同成本中心分配比例。 点击保存 点击概览可以看到该条规则&#xff0c;可以在系统中创建多条规则。 K…

优阅达携手 HubSpot 助力出海企业营销、销售和服务自动化

2024 年 6 月 17 - 18 日&#xff0c;GTC 2024 全球流量大会在深圳福田会展中心圆满举办。作为跨境出海行业产业链最全、资源最丰富、规模最大的专业展会之一&#xff0c;本次大会聚集了近 3 万名从业者、超过 200 家海内外优质开发厂商&#xff0c;品牌方、服务商&#xff0c;…

【海贼王航海日志:前端技术探索】CSS你了解多少?(二)

目录 1 -> 字体属性 1.1 -> 设置字体 1.2 -> 字体大小 1.3 -> 字体粗细 1.4 -> 文字样式 2 -> 文本属性 2.1 -> 文本颜色 2.1.1 -> 认识RGB 2.1.2 -> 设置文本颜色 2.2 -> 文本对齐 2.3 -> 文本装饰 2.4 -> 文本缩进 2.5 -&g…

Go开发后端和Vue3开发前端的前后端分离框架中自己手戳一个OA流程审批、工作流引擎给新时代一个漂亮便捷的工作流引擎

前言 在软件项目开发中&#xff0c;我们都会接触到流程审批的需要业务&#xff0c;我们以往用的最多就是如下图这种流程编辑引擎插件&#xff1a; 以上截图中的流程工具是不是大家常见的呀&#xff01;感觉很丑拿不出手呀&#xff01;在当前行业内卷及竞争激烈情况下&#xff…

uniapp免费申请苹果证书教程每次7天可用于测试

准备一个苹果账号没有加入过任何组织的 然后下载appuploader下载链接 登录上去切记勾选上未付苹果688 然后点击苹果证书创建p12证书 创建描述文件 uniapp打包自定义基座 这就打包好了可以愉快地开发了&#xff0c;但每次生成只有7天&#xff0c;设备限制3个&#xff0c…

【C++】STL | priority_queue 堆(优先级队列)详解(使用+底层实现)、仿函数的引入、容器适配器的使用

目录 前言 总代码 堆的简介 仿函数 堆的基础框架建立size、empty、top、 向上调整法 and push 向上调整 push 向下调整法 and pop 向下调整法 pop 迭代器区间初始化&#xff08;构造&#xff09; 逻辑讲解 为何选择向下建堆&#xff1f; 建堆代码实现 结语 前言…

区块链的搭建和运维4

区块链的搭建和运维4 (1) 搭建基于MySQL分布式存储的区块链 1.构建单群组网络节点 使用开发部署工具构建单群组网络节点&#xff0c;命令如下&#xff1a; bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,85452. 启动 MySQL 并设置账户密码 输入如下命令&#xff0c;…

【mysql 第一篇章】系统和数据库的交互方法

一、宏观的查看系统怎么和数据库交互 在我们刚刚接触系统和数据库的时候不明白其中的原理&#xff0c;只知道系统和数据库是需要交互的。所以我们会理解成上图的形式。 二、MYSQL 驱动 随着我们的学习时间的加长以及对程序的了解&#xff0c;发现链接数据库是需要有别的工具辅…

免费【2024】springboot 高校毕业生信息管理系统的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…