新闻详情

新闻详情

首页 / 资讯中心 / 详情

Spring注解开发与Mybatis整合:从原理到实践,彻底搞懂IoC与事务管理

发布时间:2026/9/21 7:10:45来源:尧图网络
Spring注解开发与Mybatis整合:从原理到实践,彻底搞懂IoC与事务管理
简介这是一份面向Java开发学习者的SSM框架入门课件聚焦Spring注解开发与Spring整合MyBatis两大主题适合正在学习Spring核心容器、依赖注入及持久层框架整合的读者。讲解脉络清晰从IoC/DI基本思想、BeanFactory与ApplicationContext容器层次到注解定义bean、纯注解开发、第三方bean管理和依赖注入再延伸到Spring整合MyBatis与JUnit层层递进便于系统建立SSM整合知识框架。压缩包内共1个pptx文件约2.99MB彩色排版通过结构图、示例代码和XML配置对照展示知识点既可用作课堂同步讲义也可作为考前复习提纲。目前已有181人学习使用内容覆盖Spring概述、核心容器总结、注解开发、整合MyBatis与JUnit等章节适合希望快速掌握Spring注解风格开发和SSM整合配置的初学者进阶参考。 看到这个标题我就知道这应该是不少Java开发入行时都会遇到的一份PPT——讲注解开发也讲SSM里最核心的Spring和Mybatis整合。老实说这类材料网上多得是但绝大多数要么只贴代码不讲为什么要么上来就甩配置把人看懵。这篇我就以做过的项目经验为底把注解开发和两者整合这条线从头捋一遍不光是能用还得让你知道它是怎么跑起来的。1. Spring注解开发的核心思路从XML到注解到底省了什么1.1 为什么注解能取代一堆XML配置早些年做Spring项目光一个applicationContext.xml就能写上好几百行里面全是bean标签定义一个对象就得写一段对象多了以后维护成本直接爆炸。后来Spring从2.5开始引入注解到了Spring Boot时代基本全面转向注解和自动配置这背后其实是三层逻辑。第一注解把“定义”和“使用”放在了一起。你在类上写一个Service这个类就是业务层组件不用再跑到配置文件里找对应的bean定义。类本身即文档别人看代码就知道这个类在容器里扮演什么角色而不是把代码和配置来回切换。第二注解开发能大幅减少样板代码。比如依赖注入你只要用Autowired声明一下Spring容器启动时就会把对应的bean塞进来不需要写setter注入或构造器注入的XML。第三注解让项目的启动和构建流程更轻尤其在微服务拆分的场景下一个服务一个模块各自用注解完成装配互不干扰。但有一点我得提醒你注解不是银弹。它把配置从XML搬到了代码里虽然直观但如果你想全局查一下某个bean被哪些地方引用还是会比搜XML麻烦一点。这也是为什么Spring Boot后来引入了ConfigurationProperties这类配置绑定方式把外部配置和Java对象做映射尽量把容易变的东西留在配置文件里把稳定的装配逻辑留在代码里。我的理解是注解解决的是“怎么装配的问题”配置文件解决的是“参数是什么的问题”两者要搭配用别走极端。1.2 实操里最高频的注解组合逐个说透Component系列最基础Service、Repository、Controller其实都是它的衍生本质都是把类注册成Spring容器中的bean只是语义层面区分了层次。Autowired是按类型注入Resource是按名称注入这俩面试经常会问实际开发里如果你的容器里只有一个实现类两者用起来没区别一旦有多个实现Autowired需要配合Qualifier指定名字Resource自己就能指定name属性。我个人的习惯是能用一个实现类就直接Autowired有多实现时优先Resource(name xxx)写起来短也不容易出错。Configuration和Bean是用来定义配置类的简单说就是让你用Java代码代替XML里的bean定义。比如你要注入一个第三方库的对象没法在类上直接加Component那就在配置类里写一个方法方法上标注Bean方法的返回值就是容器里注册的对象。这个方法名字默认就是bean名称也可以显式指定Bean(name)。ComponentScan负责扫描包路径Spring Boot里默认扫描启动类所在包及其子包。这里有个坑有时候你把新写的Service放在启动类包外面的目录里结果启动报了NoSuchBeanDefinitionException多半就是扫描路径没覆盖到。处理方式要么调整包结构要么在启动类上显式加上ComponentScan(basePackages com.xxx)。还有一个容易被忽略的是Scope默认单例这个对于绝大多数场景没问题但你在多线程环境下往类成员变量里塞状态就要小心了。单例bean在多线程下是共享的成员变量容易出并发问题。需要原型作用域时在Bean或Component上标注Scope(prototype)即可。说实话我工作这些年用到prototype的次数很少大多数情况都是把无状态的服务类设计成单例有状态的数据往方法参数和数据库里放。Value用来注入配置文件里的值PropertySource指定外部配置文件位置比如PropertySource(classpath:jdbc.properties)。Value(${jdbc.url})这样就能读出来但这个方案在字段多的时候很啰嗦Spring Boot时代基本被ConfigurationProperties取代了。1.3 注解开发的底层逻辑Bean生命周期是怎么回事很多人面试被问到Spring三级缓存其实这玩意儿跟注解开发也有关系。Spring IoC容器启动的时候会先扫描所有加了注解的类生成BeanDefinition然后按照依赖关系实例化bean。实例化并不等于初始化完成Spring把对象创建分成了好几步。三级缓存解决的是循环依赖问题比如A依赖B、B依赖A没有三级缓存的话两个对象互相引用就会死锁。一级缓存是成品对象二级缓存是早期暴露的半成品三级缓存放的是对象工厂。注解注入基本都是在对象创建完成后通过后置处理器来完成的。我在实际工作中直接遇到循环依赖的次数不多但确实有一次加了Transactional后发现启动报错定位下来是A依赖B、B又依赖A当时就把其中一个依赖改成Lazy延迟加载解决了。后来我换了个思路直接从设计上把循环依赖干掉该拆的方法拆出去该抽的类抽出来反而代码结构更清爽。所以我的建议是三级缓存这东西面试要知道但工程项目里碰到循环依赖优先想怎么重构而不是依赖缓存机制硬扛。2. Spring与Mybatis整合为什么要整合以及整合时发生了什么2.1 原生Mybatis的痛点与整合思路Mybatis本身是个半自动ORM框架SQL由你控制执行结果自动映射成Java对象灵活性很高。但如果你不用Spring就得自己手动创建SqlSessionFactory自己管理SqlSession每个Mapper接口还得手动写实现类去调用SqlSession的方法或者用Mybatis官方提供的Mapper动态代理。这在简单项目里还能接受项目一复杂就是灾难。真正接手一个项目后你会发现纯Mybatis的使用方式有四个致命伤第一SqlSession线程不安全你不能把它定义为单例每个线程都要独立的SqlSession第二事务控制全靠自己写commit/rollback稍不留神就出现数据不一致第三Mapper的获取和生命周期管理非常繁琐每个业务代码里都得写“获取session、调用mapper、关闭session”的样板代码第四跟Spring的声明式事务Transactional没法直接集成事务边界只能靠人肉维护。所以Spring与Mybatis整合本质就是让Spring容器接管Mybatis的核心对象。SqlSessionFactory被定义成单例SqlSession的生命周期交给Spring的SqlSessionTemplate统一管理事务交给Spring的TransactionManager统一处理Mapper接口的代理生成也交给Spring扫描注册。你这边的开发就只需要定义一个接口加几个注解或者写个XML映射文件方法调用时自动拿到代理对象去执行SQL。2.2 SqlSessionFactoryBean和MapperScan是怎么回事你用Spring Boot的时候一般只需要在启动类上加MapperScan(com.xxx.mapper)然后Mybatis的配置类就自动干了一堆活。但如果你理解了底层无非就是几件事。首先SqlSessionFactoryBean实现了Spring的FactoryBean接口它的作用是把Mybatis的SqlSessionFactory创建过程封装起来交给Spring容器管理。这里面会读取Mybatis全局配置注册typeAliases、typeHandlers、Mapper XML映射文件的位置等。只有这个factory创建好了后续的Mapper代理才有基础。其次MapperScan这个注解的作用是扫描指定包下的所有接口把它们注册成MapperFactoryBean。注意这里不是直接注册接口本身而是注册了一个工厂bean每次获取的时候工厂bean会调用SqlSession.getMapper(Class)来创建接口的动态代理。所以你在业务代码里能直接Autowired注入Mapper接口注入的实际对象就是代理对象。还有一点整合后的事务。Mybatis本身只提供对数据库的操作能力但它没有事务管理器。Spring通过DataSourceTransactionManager管理事务整合的时候SqlSessionFactoryBean用的是Spring事务管理下的数据源这样Transactional才能生效。当方法调用MybatisTemplate执行SQL时Spring的事务管理器会保证同一个方法里的SQL都在同一个事务里。这里有个常见问题如果你在Spring配置里自己new了一个DataSource没有交给Spring管理那事务注解就会失效操作一条数据提交一条根本不走事务。排查的时候先看DataSource是不是容器里的单例bean。3. 手把手搭建一个注解开发Spring与Mybatis整合的项目3.1 基础依赖和项目结构理解原理之外还得能跑起来。这里我给一个完整的精简版项目示例不依赖Spring Boot用传统的Spring Mybatis整合方式把底层链路看得明明白白。项目用Maven管理先看pom.xml里最核心的依赖dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.3.23/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version5.3.23/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.13/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version3.0.3/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency这里一定要加上spring-jdbc因为事务管理器要用它。mybatis-spring是两者的桥接包专门负责把Mybatis的对象接入Spring容器。项目结构就按标准的Java工程来src/main/java ├── com/demo/config │ └── SpringConfig.java ├── com/demo/entity │ └── User.java ├── com/demo/mapper │ └── UserMapper.java ├── com/demo/service │ ├── UserService.java │ └── UserServiceImpl.java ├── com/demo/App.java src/main/resources └── mapper └── UserMapper.xml3.2 核心配置类和数据源既然用的是注解开发整个Spring配置就交给Java配置类。先看数据源这块我们这里手动配置一个简单的HikariCP或者直接用DriverManagerDataSource都行生产环境建议用HikariCP测试就怎么简单怎么来Configuration ComponentScan(com.demo) EnableTransactionManagement MapperScan(com.demo.mapper) PropertySource(classpath:db.properties) public class SpringConfig { Value(${jdbc.driver}) private String driver; Value(${jdbc.url}) private String url; Value(${jdbc.username}) private String username; Value(${jdbc.password}) private String password; Bean public DataSource dataSource() { HikariConfig config new HikariConfig(); config.setDriverClassName(driver); config.setJdbcUrl(url); config.setUsername(username); config.setPassword(password); config.setMaximumPoolSize(10); return new HikariDataSource(config); } Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); org.apache.ibatis.session.Configuration configuration new org.apache.ibatis.session.Configuration(); configuration.setMapUnderscoreToCamelCase(true); configuration.setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class); factoryBean.setConfiguration(configuration); factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources(classpath:mapper/*.xml)); return factoryBean.getObject(); } Bean public DataSourceTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }几个细节说一下。setMapUnderscoreToCamelCase(true)这个非常关键数据库字段是create_timeJava属性是createTime不开启驼峰映射的话这个字段就注入不进去查出来全是null。setMapperLocations是告诉Spring去哪里加载Mapper的XML文件如果你用的是纯注解SQL也就是Select、Insert这些那这行可以不写但XML和注解混合的项目必须配置。EnableTransactionManagement开启注解事务没有这行Transactional不生效。3.3 Mapper接口与XML映射的写法Mapper接口本身很简单public interface UserMapper { User selectById(Param(id) Long id); ListUser selectList(); int insert(User user); int update(User user); int deleteById(Param(id) Long id); }对应的XML文件放在src/main/resources/mapper/UserMapper.xml里?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.demo.mapper.UserMapper select idselectById resultTypecom.demo.entity.User SELECT id, name, age, create_time FROM t_user WHERE id #{id} /select select idselectList resultTypecom.demo.entity.User SELECT id, name, age, create_time FROM t_user /select insert idinsert parameterTypecom.demo.entity.User useGeneratedKeystrue keyPropertyid INSERT INTO t_user(name, age) VALUES (#{name}, #{age}) /insert update idupdate parameterTypecom.demo.entity.User UPDATE t_user SET name #{name}, age #{age} WHERE id #{id} /update delete iddeleteById DELETE FROM t_user WHERE id #{id} /delete /mapper有两点值得注意。namespace必须写接口的全限定名不能写错写错的话运行时报错还不好查。resultType如果你开了typeAliases可以写别名但我建议起手阶段就写全限定名清晰不背锅。useGeneratedKeystrue keyPropertyid是插入后回填自增主键到实体对象这个在新增后马上要用到主键的场景比如插入订单后要关联订单明细特别方便省得再查一次数据库。3.4 Service层的使用和事务Service层直接注入Mapper接口加Transactional来控制事务Service public class UserServiceImpl implements UserService { Resource private UserMapper userMapper; Override Transactional(rollbackFor Exception.class) public int createUser(User user) { userMapper.insert(user); if (user.getAge() ! null user.getAge() 0) { throw new RuntimeException(年龄不能为负数); } return user.getId(); } }Transactional的rollbackFor Exception.class这个一定要写因为Spring默认只在遇到RuntimeException时才回滚如果你代码里抛的是一个自定义CheckedException不加这个属性的话事务照样提交数据就脏了。这个坑我印象很深有一次导入接口处理Excel解析里面抛了业务异常但事务没回滚排查了半天发现就是没加rollbackFor。启动类就一行public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService context.getBean(UserService.class); // 业务调用... context.close(); } }用AnnotationConfigApplicationContext加载配置类容器启动时会自动扫描com.demo包创建所有bean生成Mapper代理注册事务管理器。跑起来你会在控制台看到Mybatis打印的SQL日志 Preparing: ...就是真正执行的语句排查SQL问题全靠它。4. 整合过程中的常见问题与排查技巧4.1 启动报错NoSuchBeanDefinitionException、Invalid bound statement这是两个出现频率最高的错误。NoSuchBeanDefinitionException一般是扫描路径没覆盖到接口或者MapperScan没生效检查启动类和配置类上的ComponentScan路径。Invalid bound statement (not found)说明Mapper接口找到了但接口方法和XML里的id对不上要么XML文件没被加载要么namespace写错要么方法名和XML id不一致。排查这两类问题我建议先看启动日志。Spring启动时会打印bean初始化情况你看有没有类似userMapper这样的bean名称如果没有说明根本没扫描到。有的话再看Mybatis加载了多少个Mapper XML这些日志都会明确打印。把问题定位到具体层级比瞎猜强太多。4.2 事务不生效的排查思路事务不生效的常见原因除了前面说的DataSource不是同一个、没写rollbackFor还有一个容易被忽略的点同一个类的内部调用。Transactional是基于Spring AOP动态代理实现的如果你在UserServiceImpl里直接写一个方法内部调用另一个带有Transactional的方法事务是不生效的因为内部调用没有走代理对象。这个冷知识导致的现象就是外部调用方法AA内部调用BB有事务B抛异常了但A的事务没回滚。解决办法一是把B挪到另一个Service里二是自己注入自身代理三是用AopContext.currentProxy()获取当前代理再调用。我遇到过一个奇葩case一开始以为是事务没生效后来发现是DataSource被C3P0和Druid两个连接池配置了双份Spring容器里有两个DataSource事务管理器管的那个和Mybatis用的那个根本不是同一个。你说这种问题怎么排查看日志基本没用得把所有关于数据源的配置全部搜一遍把多余的那份注释掉世界就清净了。4.3 Mybatis属性映射和SQL日志打印的实用技巧数据库字段是下划线风格、Java属性是驼峰风格这个前面说了开启mapUnderscoreToCamelCase就行。但如果你用的是Select注解直接在接口里写SQL不想建XML文件那么SQL可以这样写Select(SELECT * FROM t_user WHERE id #{id}) Results(id userMap, value { Result(column create_time, property createTime) }) User selectById(Long id);SQL日志这块开发阶段我喜欢在Mybatis配置里加上StdOutImpl就是上面配置类里那行configuration.setLogImpl(...)SQL会自动打印到控制台。但生产环境别这么干日志量太大而且会打印完整参数有数据泄露风险。线上的做法是用p6spy这类监控组件或者把Mybatis日志级别调到DEBUG交给日志框架统一管理。用idea mybatis log free插件也可以把参数替换进SQL里直接显示可执行的完整语句排错更快。4.4 关于逻辑删除和Mybatis Plus的一些补充提到Mybatis绕不开Mybatis Plus现在新项目用Mybatis Plus的很多。它有一个内置的逻辑删除功能用起来很爽但有个坑你写了自定义SQL时如果没注意它自动拼接的deleted0条件查出来的数据可能不符合预期。比如你写一个自定义JOIN查询没有显式加逻辑删除过滤条件Mybatis Plus的插件可能在某些场景下不生效。我的经验是不管是Mybatis还是Mybatis Plus自定义SQL务必自己把控过滤条件别把逻辑依赖在框架的自动行为上。另外Mybatis Plus的saveOrUpdateBatch在多数据源环境下有兼容问题如果项目里配了多数据源、分库分表组件使用这类批量方法之前一定提前测试特别是主键策略和分布式ID生成器冲突的场景。5. 从学习角度给读者的进阶建议5.1 面试常考的点要连成知识网结合这份PPT的主题Spring注解开发和Spring与Mybatis整合面试官大概率会这么问Autowired和Resource的区别是什么Component和Bean有什么区别Spring容器启动流程是怎样的Mybatis的#{}和${}有什么区别Mapper接口没有实现类Spring怎么代理的这些问题看似零散但核心都指向一个东西你有没有真正理解IoC和DI。我建议学习的时候把知识串起来先理解容器做了什么再理解注解如何驱动容器干活最后理解Mybatis如何把自己扮演的角色塞进容器里。这样面试答起来才不是背答案而是层层递进地讲设计思路。5.2 读一点点源码胜过看十篇博客说真的做Java开发绕不开Spring系源码。你不用全读抓住一条主线就行Spring容器的刷新过程refresh方法、Bean的实例化和初始化流程、BeanPostProcessor的扩展点、Mybatis的MapperScan如何通过ImportBeanDefinitionRegistrar把Mapper注入容器的。这几个点走一遍你立刻能解释很多实际开发中的灵异现象。我当年就是被一次Invalid bound statement折磨了两天才开始硬着头皮去看MapperRegistry和MapperAnnotationBuilder的源码看完才发现Mybatis的XML和注解最终都会被解析成MapperAnnotationBuilder里的方法定义怪不得id对不上就找不到。从那以后遇到问题我第一反应不是搜报错信息而是想这个报错是在哪个环节抛出来的链路走一遍基本能定位个八九不离十。5.3 建议动手把项目从零写一遍看再多文档不如自己敲一遍。建议你用Maven从零搭一个这种传统Spring Mybatis的项目把下面这些事一样一样做完做完基本就通透了用Configuration定义配置类替代原来的XML。手动配DataSource和SqlSessionFactoryBean不依赖Spring Boot自动配置。写一个带Transactional的Service验证事务是否真的回滚。分别用XML和注解两种方式写Mapper查询体会两者的风格差异。故意把XML里的id写错观察报错信息提高定位问题的速度。尝试开启驼峰映射和不开启对比实体类字段为null的原因。尤其是第一项很多人在Spring Boot里用得顺手但根本不知道Spring容器是怎么初始化Bean的。回到原生环境写一遍boot里那层自动配置的神秘面纱就彻底没了。这一步走了你对Spring的理解会比绝大部分同龄人深一个档次。最后说个自己的体会吧。从最开始照着文档抄XML配置到后来能用注解一行搞定再到后面读懂容器源码这个过程中最爽的不是学会某个API而是踩坑后明白每个设计背后的约束条件。Spring和Mybatis能统治Java后端这么多年靠的就是它们把复杂留给自己把简单留给开发者的妥帖设计。希望这篇整理能帮你少走点弯路以后写代码时遇到奇怪问题能想起链路背后的那一步。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」 2026/9/21 7:43:50

Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」

AI 应用前端 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、Claude 与 ChatGPT 的增强套件;其中的提示词管理器可用…

阅读更多 →
gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层 2026/9/21 7:43:50

gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层

前端静态站点Web框架 【免费下载链接】gatsby React-based framework with performance, scalability, and security built in. 项目地址: https://gitcode.com/gh_mirrors/ga/gatsby 点击查看 免费下载 本篇技术指南以 gatsby-source-graphql 插件的 CHANGELOG 版…

阅读更多 →
Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案 2026/9/21 7:43:50

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案 【免费下载链接】lightweight-charts Performant financial charts built with HTML5 canvas 项目地址: https://gitcode.com/gh_mirrors/li/lightweight-charts 本指南以 Lightweig…

阅读更多 →
FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南 2026/9/21 7:43:50

FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南

分布式数据库KV存储数据库后端 【免费下载链接】foundationdb FoundationDB - the open source, distributed, transactional key-value store 项目地址: https://gitcode.com/gh_mirrors/fo/foundationdb 点击查看 免费下载 mako_storage_bench.sh 是 FoundationD…

阅读更多 →
Trigger.dev SDK 公共包修改规范:Changesets 发布流程、版本策略与 @trigger.dev/core 子路径导入指南 2026/9/21 7:43:50

Trigger.dev SDK 公共包修改规范:Changesets 发布流程、版本策略与 @trigger.dev/core 子路径导入指南

AI Agent后端任务调度开发工具可观测性AI 应用 【免费下载链接】trigger.dev Trigger.dev – build and deploy durable AI agents and workflows 项目地址: https://gitcode.com/gh_mirrors/tr/trigger.dev 点击查看 免费下载 本篇指南围绕仓库内的 .claude/rules…

阅读更多 →
VUX 的 vux2 模板与 Vue 官方 webpack 模板有什么区别:模板选型、预置配置与 vux-loader 原理 2026/9/21 7:40:49

VUX 的 vux2 模板与 Vue 官方 webpack 模板有什么区别:模板选型、预置配置与 vux-loader 原理

UI组件前端 【免费下载链接】vux Mobile UI Components based on Vue & WeUI 项目地址: https://gitcode.com/gh_mirrors/vu/vux 点击查看 免费下载 vux2 是 VUX 官方维护的 Vue 2.x 工程模板,它 fork 自 Vue 官方 webpack 模板并针对 VUX 组件库做…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞