
简介面向Java毕业设计与课程设计场景这份基于SSM框架的广告管理系统完整项目包适合需要完成企业级广告业务后台开发的在校学生与初级开发者。系统采用SpringSpringMVCMyBatis与Vue前后端分离架构内置管理员、广告客户、广告商、广告制作商四类角色细化出广告投放渠道管理、广告需求与提案、广告设计预览、调整信息、签署及结算等完整业务闭环功能划分清晰便于按模块阅读和改造。压缩包共540个文件约83.42MB以Java源码、Vue组件、XML映射、JavaScript脚本为主同时包含数据库SQL建表脚本、Maven/IDE工程配置、Windows启动批处理与演示视频覆盖从环境搭建、数据初始化到系统运行、二次开发的全过程。已有150人学习下载资料目录结构清晰尤其适合具备Java基础、希望参考完整SSMVue前后端分离项目完成毕业设计或课程设计并快速形成可演示、可答辩作品的学生。1. 为什么要聊 SSM 广告管理系统「Java毕业设计-基于SSM框架的广告管理系统.rar」这类资源几乎是高校 Java 方向毕业设计里出现频率最高的题目之一。它看起来是一个业务系统实际考核的是三件事Spring、Spring MVC、MyBatis 三个框架能不能在一个 Web 工程里顺畅协作业务表设计能不能覆盖一个完整的管理流程以及权限、分页、统计这些通用能力有没有真的落地。广告管理系统本身业务不复杂广告主、广告位、素材、投放计划、投放统计正好把 SSM 的整合链路完整走一遍。这个项目适合两类人。一类是把这套代码当作业参考的在校学生需要从运行、改表、改页面到答辩讲解都能说清楚另一类是准备 Java 面试的工程师SSM 虽然已经算老技术但 Spring 的 Bean 生命周期、MyBatis 的动态代理、事务传播行为这些东西依然是面试八股文的钉子户用一个完整的业务工程去复盘它们比死记硬背效果好得多。这篇文章不假设你已经拿到了某个具体的压缩包而是按一个可运行、可扩展的 SSM 广告管理系统该有的样子把从搭建、设计、编码到优化的完整路径讲清楚。2. SSM 框架整合原理与项目骨架搭建2.1 三个框架在广告系统里的角色边界SSM 是 Spring Spring MVC MyBatis 三个框架的组合它们解决的是三层架构里不同层面的问题。理解边界是看懂一切 SSM 项目的第一步。Spring 是整个项目的大管家负责对象的创建和管理。广告系统里的 AdService、AdPlanService、AdvertiserMapper 这些对象都由 Spring 的 IoC 容器创建并注入到需要它们的地方。比如 Controller 里要调用 Service不用自己 new标注 Autowired 就能把容器里的 Bean 拿过来。这是依赖注入的基本操作。Spring MVC 管的是 HTTP 请求的分发。浏览器发来一个「/adPlan/list」的请求DispatcherServlet 这个前端控制器会去找哪个 Controller 方法能处理它处理完再返回一个视图名或者 JSON 数据。它把 URL、参数、Java 方法三者绑定在一起是 Web 层和业务层之间的桥梁。MyBatis 管的是数据库访问。它把 Mapper 接口和 SQL 语句绑定起来框架底层通过 JDBC 执行 SQL把结果集映射成 Java 对象。和 Hibernate 这类全自动 ORM 框架不同MyBatis 的半自动特性在广告系统这种查询条件多变、统计 SQL 多的场景下更灵活。广告计划的状态筛选、投放数据的多表聚合写 SQL 比让框架自动生成更可控。2.1.1 Spring 容器与 MyBatis 的整合关键整合的难点在于MyBatis 的 SqlSessionFactory 和 Mapper 代理对象需要交给 Spring 管理。常见做法是引入 mybatis-spring 这个桥接包通过 SqlSessionFactoryBean 在 Spring 容器里创建工厂再用 MapperScannerConfigurer 扫描 Mapper 接口并生成代理 Bean。配置完成后Mapper 接口就能像普通 Spring Bean 一样被注入到 Service 里。整合后需要注意一个面试常考的点Spring 默认管理的 Bean 是单例的但 MyBatis 的 SqlSession 生命周期应该跟随每个数据库操作。mybatis-spring 里 SqlSessionTemplate 已经帮你处理了 SqlSession 的创建和关闭Service 层拿到的 Mapper 代理每次调用都会从连接池申请连接执行完归还不会出现连接泄漏。2.2 搭建 SSM 广告系统的 Maven 工程骨架创建工程用 Maven 是当前 Java 项目的主流选择。它负责依赖管理和构建打包比手动拷 jar 包方便得多。一个典型的 SSM 广告管理系统会用到以下核心依赖spring-webmvc、spring-jdbc、mybatis、mybatis-spring、mysql-connector-java、druid 连接池、jstl以及 servlet-api 和 jackson 用于 JSON 处理。依赖版本选择有个原则Spring 5.x 对应 javax.servlet 规范Spring 6.x 对应 jakarta.servlet如果你用的是 Tomcat 9 及以下老老实实用 Spring 5.x 系列避免 servlet 包名对不上导致启动报 NoClassDefFoundError。MyBatis 3.5.x 和 mybatis-spring 2.x 是稳定搭配。pom.xml 的核心依赖片段大致长这样properties spring.version5.3.39/spring.version mybatis.version3.5.16/mybatis.version /properties dependencies dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version${spring.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version${mybatis.version}/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.23/version /dependency /dependenciesspring-webmvc 依赖里已经传递引入了 spring-context所以不用重复声明 Spring 核心包。mybatis-spring 是整合的桥接包漏掉它会出现 ClassNotFoundException: org.mybatis.spring.SqlSessionFactoryBean。MySQL 8 的驱动类名是 com.mysql.cj.jdbc.Driver和 MySQL 5 的 com.mysql.jdbc.Driver 不一样连不上数据库时优先检查这里。2.2.1 包结构设计包名一般按 com.xxx.adm 来组织adm 是 advertisement management 的缩写。下面分 domain实体类、mapperMyBatis 接口、service业务接口和实现、controller请求处理、interceptor拦截器、config配置类这几层。domain 里放 Advertiser、AdSlot、AdMaterial、AdPlan、DeliveryStat 这些广告业务实体和数据库表一一对应里面的字段名保持和表字段一致或开启驼峰自动映射。2.3 配置文件的关键项解析SSM 项目至少有四个配置文件web.xml、spring-mvc.xml、applicationContext.xml、jdbc.properties。它们各管一段理解它们的职责比死记代码重要。web.xml 是整个 Web 应用的入口。它需要配置两个关键内容ContextLoaderListener 用于加载 Spring 根容器DispatcherServlet 用于加载 Spring MVC 的控制器层容器。根容器和 Web 容器有父子关系子容器可以访问父容器的 BeanController 能注入 Service 就是靠这个机制。spring-mvc.xml 要开启注解驱动、配置 JSP 视图解析器、扫描 controller 包还要放行静态资源。注解驱动mvc:annotation-driven/这一行很重要它注册了 JSON 转换器、参数解析器等一系列处理器没有它ResponseBody 返回对象时根本无法序列化成 JSON。applicationContext.xml 配置数据源、SqlSessionFactory、Mapper 扫描、事务管理器。Druid 数据源配置里注意 initialSize、maxActive、minIdle 三个参数分别代表初始连接数、最大活跃连接数、最小空闲连接数。开发环境设成 5、20、5 就够了不要照抄生产环境的动辄上百的配置本地跑不起来还白白占用数据库连接。jdbc.properties 里放数据库连接信息。推荐把时区参数 serverTimezoneAsia/Shanghai 显式写出来MySQL 8 对时区敏感漏了会报 SQLException: The server time zone value is unrecognized。另外建议加 characterEncodingutf8否则中文数据写入后查询会出现乱码。2.4 在本地跑通一个最小可运行工程配置到这里应该先做一次完整启动验证确认环境和框架没问题再开始写广告业务代码。启动验证的步骤很简单用 Maven 的 tomcat7-maven-plugin 插件启动或者把工程打成 war 包扔进本地 Tomcat 的 webapps 目录。推荐用插件方式开发调试在 pom.xml 里配置 tomcat7 插件后命令行执行 mvn tomcat7:run浏览器访问 http://localhost:8080/ 看到页面就算通了。启动时控制台如果报 Error creating bean with name sqlSessionFactory去检查 MySQL 是否启动、URL 里的数据库名是否存在、账号密码是否正确这三点占了八成以上的启动失败原因。启动成功后再写一个简单的 AdvertiserController 返回「hello」测试 JSON 接口输出确认 MVC 链路正常。3. 广告管理系统的数据模型设计与持久层实现3.1 广告业务的核心实体与 E-R 关系做毕业设计有个普遍问题拿到题目直接开始建表建到一半发现关联关系理不清。广告管理系统的实体关系其实很直观核心是「广告主发布广告计划计划关联广告位和素材每次曝光产生投放记录」。广告主 Advertiser 是一方一个广告主可以创建多条投放计划 AdPlan这是 1:N 关系。广告位 AdSlot 是一方一个广告位可以被多个计划选中投放广告位和计划是多对多但实际设计时通常把广告位字段直接挂在计划表上或者用中间表关联。素材 AdMaterial 和计划也是 N:1一个素材可以被多个计划复用到不同广告位。为什么用多对多要拆中间表因为后续要记录「某个计划在某个广告位的出价」这个属性既不属于计划也不属于广告位只能属于关联关系本身。3.1.1 建表 SQL 设计要点广告系统涉及金额和状态流转表设计上有几个关键点。金额字段用 DECIMAL(10,2) 而不是 DOUBLE避免浮点精度误差导致对账不平。状态字段推荐 TINYINT 加注释比字符串省空间且语义明确。所有业务表都要有 create_time 和 update_time一方面做数据审计另一方面为后面写日统计 SQL 留出时间字段。下面给出核心表的简化 DDLCREATE TABLE ad_plan ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 主键, plan_name VARCHAR(64) NOT NULL COMMENT 计划名称, advertiser_id BIGINT NOT NULL COMMENT 广告主ID, slot_id BIGINT NOT NULL COMMENT 广告位ID, material_id BIGINT NOT NULL COMMENT 素材ID, budget DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT 总预算, start_date DATE NOT NULL COMMENT 开始日期, end_date DATE NOT NULL COMMENT 结束日期, status TINYINT NOT NULL DEFAULT 0 COMMENT 状态:0待审核,1运行,2暂停,3结束, create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_advertiser_id (advertiser_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT广告投放计划表;这个建表语句里有几个信息量较大的设计id 用 BIGINT 是因为广告系统将来数据量大INT 只有 20 亿上限budget 用 DECIMAL 精确到分start_date 和 end_date 用 DATE 类型而不是 DATETIME因为日期比较只精确到天加了时间反而麻烦KEY 索引给了 advertiser_id 和 status查询计划列表时「按广告主查」和「按状态查」是最频繁的两个过滤条件。3.2 MyBatis 动态 SQL 处理条件查询广告系统的核心查询场景是「投放计划筛选」按广告主、按状态、按时间范围组合筛选。用 MyBatis 的动态 SQL可以只写一条语句覆盖多种组合条件不用在 Java 代码里拼 SQL 字符串。在 Mapper 接口里定义方法ListAdPlanVO selectPlanList(Param(query) PlanQuery query)对应的 XML 里这样写select idselectPlanList resultTypecom.example.adm.domain.vo.AdPlanVO SELECT p.*, a.name AS advertiser_name, s.slot_name FROM ad_plan p LEFT JOIN advertiser a ON p.advertiser_id a.id LEFT JOIN ad_slot s ON p.slot_id s.id where if testquery.advertiserId ! null AND p.advertiser_id #{query.advertiserId} /if if testquery.status ! null AND p.status #{query.status} /if if testquery.startDate ! null AND p.start_date gt; #{query.startDate} /if if testquery.endDate ! null AND p.end_date lt; #{query.endDate} /if /where ORDER BY p.create_time DESC /select动态 SQL 里的where标签会自动处理 AND 前缀问题多个条件拼接时永远不用在 Java 层判断是不是第一个条件。注意gt;和lt;是 XML 里对 和 的转义写法直接写 会导致 XML 解析失败。用 LEFT JOIN 把广告主名称和广告位名称查出来返回给页面展示比在 Java 层循环查二次数据库要快得多。3.2.1 数据库文档自动生成数据表设计完成后写数据库设计文档是个体力活。常见做法是用工具自动生成。比如在 IDEA 的 Database 面板连接 MySQL选中需要的表右键「Generate POJOs」可以快速生成实体类文档部分可以用开源的 SchemaSpy 或者 MyBatis Generator 插件的注释生成能力减少手工编写的工作量。Java 的环境变量配置好之后这些工具基本都可以通过命令行直接运行。3.3 投放统计报表的多表聚合广告管理系统的另一个刚需是统计报表每天各广告位的曝光量、点击量、消耗金额。统计的前提是有一张按天汇总的明细表 ad_delivery_daily字段包括 plan_id、slot_id、show_count、click_count、cost、stat_date。统计报表的 SQL 写法要注意先按日维度过滤出某一天的所有投放记录再按广告主分组聚合。这个 SQL 值得在面试时讲清楚因为它考察的正是 MyBatis 多表关联加聚合函数的使用能力。SELECT date(d.created_at) AS stat_date, a.name AS advertiser_name, sum(d.show_count) AS total_shows, sum(d.click_count) AS total_clicks, sum(d.cost) AS total_cost FROM ad_delivery_daily d LEFT JOIN ad_plan p ON d.plan_id p.id LEFT JOIN advertiser a ON p.advertiser_id a.id WHERE d.created_at gt; #{startDate} AND d.created_at lt; DATE_ADD(#{endDate}, INTERVAL 1 DAY) GROUP BY date(d.created_at), a.id ORDER BY stat_date DESCd.created_at startDate和 DATE_ADD(endDate, INTERVAL 1 DAY)的组合确保了结束日期当天能完整包含在统计范围内。GROUP BY date(d.created_at), a.id表示数据按天和广告主组合分组。LEFT JOIN 保证了如果某天没有投放记录广告主仍然会出现在结果集中只是统计值为 NULL。3.4 持久层最容易踩的两个坑3.4.1 下划线字段与驼峰属性的映射数据库字段通常是 advertiser_id、create_time 这种下划线风格Java 实体类里则是 advertiserId、createTime。全局开启驼峰映射可以在 MyBatis 配置里加一行setting namemapUnderscoreToCamelCase valuetrue/这样 resultType 自动映射时不用写繁琐的 resultMap。如果你看到的项目没有加这行配置SQL 里查出来列名带下划线实体类里全是 null很可能就是这里的问题。3.4.2 N1 查询问题查询计划列表然后循环每个计划去查广告主名称这是典型的 N1。广告系统列表页如果这么写管理后台打开一次计划列表就要执行几十条 SQL。解决办法就是前面给的 join 查询一次查出关联字段。4. Service 层事务设计与权限控制实现4.1 让广告计划审核流程与事务绑定广告投放计划有一个状态流转提交后待审核审核通过后运行运行中可以暂停到期自动结束。这些状态变更都对应着数据库的 update 操作每一步都不能出现「改了状态但没记录日志」的情况。Service 层是事务控制的核心位置。Spring 声明式事务管理用 Transactional 注解实现一般加在实现类的方法上而不是接口上这样 CGLIB 动态代理能正确处理。一个典型的场景是「创建计划同时扣减广告主余额」这两个操作必须在同一个事务里——创建成功但余额没扣减会造成广告主欠费还能继续投放。Service public class AdPlanServiceImpl implements AdPlanService { Autowired private AdPlanMapper adPlanMapper; Autowired private AdvertiserMapper advertiserMapper; Override Transactional(rollbackFor Exception.class) public void createPlanWithBudget(AdPlan plan, BigDecimal budget) { // 1. 插入投放计划 adPlanMapper.insertPlan(plan); // 2. 扣减广告主余额 int rows advertiserMapper.deductBalance(plan.getAdvertiserId(), budget); if (rows 0) { // 余额不足主动抛出运行时异常触发回滚 throw new BizException(广告主余额不足); } } }这个方法里 Transactional 的 rollbackFor 属性值得单独解释默认情况下 Spring 只对 RuntimeException 回滚如果 BizException 是自定义的受检异常不加 rollbackFor 会导致事务不生效出现「计划创建成功但余额没扣」这种脏数据。另一个细节是 deductBalance 的 SQL 一定要写成UPDATE advertiser SET balance balance - #{budget} WHERE id #{advertiserId} AND balance #{budget}利用数据库行锁保证并发扣减的安全性而不是先查余额再在 Java 里比较。4.2 Controller 层如何接收和校验请求参数Controller 层是页面的入口负责把 HTTP 参数翻译成 Java 对象再调用 Service。广告管理系统的接口一般分为两类一类是返回 JSP 页面的传统 MVC 接口另一类是返回 JSON 数据的 REST 接口。REST 接口的核心是请求参数绑定和校验。用 RequestBody 接收 JSON 对象时框架默认通过 Jackson 反序列化如果前端传的字段类型和实体类不一致会抛 HttpMessageNotReadableException。分页查询的参数用 RequestParam 接收并设置默认值避免前端不传参数时报 400 错误。RestController RequestMapping(/api/ad/plan) public class AdPlanController { Autowired private AdPlanService adPlanService; GetMapping(/list) public PageResultAdPlanVO list( RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) Integer status) { PlanQuery query new PlanQuery(); query.setPageNum(pageNum); query.setPageSize(pageSize); query.setStatus(status); return adPlanService.pageQuery(query); } PostMapping(/audit) public ResultVoid audit(RequestBody AuditRequest request) { adPlanService.auditPlan(request.getPlanId(), request.getPassed()); return Result.success(); } }这个例子展示了 Controller 的两种常用写法GET 请求带 RequestParam 逐个接参数POST 请求用 RequestBody 整体接对象。RequestParam(required false) 表示该参数可传可不传对应状态筛选为空时查询全部。分页查询返回 PageResult 对象而不是直接返回 List是因为页面需要知道总条数来渲染分页按钮。4.3 基于拦截器实现管理员与广告主双角色权限广告管理系统通常有两类用户平台管理员和广告主。管理员审核计划、管理广告位广告主只能管理自己的计划。如果不去做权限控制任何登录用户都能调审核接口整个系统的业务逻辑就崩了。Spring MVC 的拦截器是实现权限控制的常见手法。继承 HandlerInterceptor 接口重写 preHandle 方法在请求进入 Controller 前检查 Session 里的登录用户信息。Component public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 从 Session 获取登录用户 SysUser user (SysUser) request.getSession().getAttribute(loginUser); if (user null) { // 未登录重定向到登录页 response.sendRedirect(request.getContextPath() /login); return false; } // 管理员放行所有路径广告主只能访问自己的资源 if (ADMIN.equals(user.getRole())) { return true; } String uri request.getRequestURI(); if (uri.startsWith(/api/ad/plan) POST.equals(request.getMethod())) { // 非管理员禁止审核和修改操作 response.setStatus(HttpServletResponse.SC_FORBIDDEN); return false; } return true; } }这个拦截器里有两个细节值得注意。第一Session 里存的是登录用户对象而不是只存一个 username这样后续取用户角色、用户 ID 都方便。第二判断权限时同时校验了 URI 前缀和 HTTP 方法GET 查询放行、POST 审核拦截比粗暴地整段路径拦截更精细。注册拦截器需要在 spring-mvc.xml 里配置mvc:interceptors指定拦截路径为 /api/** 并排除登录接口。4.4 页面渲染方式的选择SSM 项目里页面层常用的技术是 JSP JSTL 或者返回 JSON 让前端用 JS 渲染。如果你的毕业设计以「演示功能」为导向JSP JSTL 是最省事的后端查好数据放进 ModelJSP 页面直接用${list}遍历展示一副完整的列表页几分钟就能出来。如果演示时希望页面交互更流畅比如广告计划列表不刷新页面就更新状态那就把接口写成返回 JSON 的 REST 风格前端用简单的 jQuery 请求 API。两种方式可以共存后台管理页面用 JSP前台 API 用 JSON。5. 让广告管理系统的代码更值钱验证清单与优化方向5.1 从「能跑」到「能展示」的自测清单答辩或演示前最少要完整走一遍的核心流程按以下顺序自测。第一用管理员账号登录能看到菜单导航和各模块入口。第二创建一条广告计划选择广告位和素材填写预算和投放日期提交后状态变为「待审核」。第三切换到管理员账号审核该计划通过后状态变为「运行」。第四模拟一条投放记录写入 ad_delivery_daily 表去统计报表页检查数据是否正确汇总。第五用广告主账号登录确认看不到审核按钮修改和删除操作被拦截。这五步覆盖了登录、CRUD、状态流转、权限拦截、统计报表五个核心模块任何一步卡住都说明对应模块没有真正打通。5.2 加分项一用 Redis 做针对热点广告位的缓存如果希望项目在面试或答辩时能聊出一些亮点引入 Redis 做缓存是个性价比很高的选择。广告位信息的访问频率高但数据变动少非常适合放到缓存里。用 Spring Data Redis 时有个常见的面试考点更新缓存中数值类型的字段不要用「先读出来再写回去」的方式而应该直接用 increment 或 decrement 方法保证原子性。Autowired private StringRedisTemplate redisTemplate; public void increaseShowCount(Long slotId) { String key ad:slot:show: slotId; // 直接对 Redis 中的数值做原子自增 Long count redisTemplate.opsForValue().increment(key); if (count ! null count 1L) { // 第一次写入设置过期时间防止 key 永不失效 redisTemplate.expire(key, Duration.ofDays(1)); } }这段代码解决了 increment 方法使用中的经典问题如果 key 不存在第一次 increment 会创建 key 并赋值为 1但此时 key 没有过期时间后续如果不手动删除就会一直占着内存。所以判断返回值等于 1 时补一个 expire 设置。类似的逻辑反过来做预算扣减时不要用get拿出来减完再set回去直接用decrement才是线程安全的。5.3 加分项二给 MyBatis 查询接上分页插件广告计划列表的数据量上来后用 LIMIT 手动分页还要单独写 count 查询实在太啰嗦。常见的做法是集成 PageHelper 分页插件它会在执行查询前自动拦截 SQL生成带 count 的查询和分页物理 SQL。dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.7/version /dependencySSM 项目里不需要 starter 包用 pagehelper 5.x 并在 MyBatis 配置里指定插件类即可。注意一个使用陷阱PageHelper 和线程池有隔离性问题必须在调用分页查询的方法内部紧挨着写PageHelper.startPage(pageNum, pageSize)确保线程中的 ThreadLocal 参数会被下一次查询消费掉否则分页条件会污染其他请求。5.4 把 SSM 项目改造成 Spring Boot 的迁移思路如果你拿到手的项目还是 SSM 的 XML 版本但现在面试时几乎所有岗位都要求 Spring Boot花两天做一次迁移是非常值得的投入。迁移的核心思路不是重写业务代码而是把配置方式从 XML 改为约定优于配置web.xml 里的 DispatchServlet 由内嵌 Tomcat 自动完成xml 里mvc:annotation-driven/用 EnableWebMvc 替代数据源和 MyBatis 的配置简化成 application.yml 里几行参数。Service、Mapper、Controller 的核心代码几乎不用动把事务注解、接口入参出参原样保留替换掉配置文件即可。这种迁移在面试时讲到「为什么 Spring Boot 简化了 SSM 的整合」会比单纯背框架知识点更有说服力。技术栈终会迭代但今天你从广告管理系统搭好的这套三层架构、事务边界、权限控制、统计聚合的思路到了 Spring Boot 时代依然全部适用只是换了一套装配方式而已。本文还有配套的精品资源点击获取