JavaEE学习路线:从Servlet到SSM整合的完整指南
很多人学完 JavaSE 之后会突然陷入一段迷茫期面向对象、集合、IO、多线程好像都学了但打开招聘网站一看岗位要求上写的全是 Spring、SpringMVC、MyBatis 这些名词根目录里一堆 Maven 依赖和 web.xml 配置完全对不上号。我当年就是从这个阶段过来的。当时我手头能找到的、体系比较完整的就是“狂神说Java系列”里那套 JavaEE 相关的教程。说真的这套系列帮我把“JavaSE 之后到底学什么”这个问题彻底捋清楚了。它不是单纯给你念 PPT而是从 JavaWeb 基础一路讲到 SSM 整合把 Servlet、过滤器和 Spring 容器这些抽象的概念用能跑起来的代码一步步带出来。如果你现在也在自学 JavaEE或者上完了学校的 Java 课但还不会做项目这篇文章就是把我基于这套学习框架整理的路线、核心原理和踩过的坑一次性写出来分享给你。先放个整体认知JavaEE 学习不是去背一堆框架的 API而是要理解一套 Web 应用的底层运行逻辑。你在浏览器里输入一个网址回车数据到底经过了哪些过程才显示在页面上请求怎么被服务器接收、怎么被处理、怎么返回数据存在哪里、怎么保证安全还有代码如何组织、依赖如何管理、怎么和数据库交互、事务怎么控制把这些问题的答案串起来你再去学 Spring、SpringBoot会发现它们只是把底层过程封装得更好看、更好用而已。1. 为什么需要一套系统化的 JavaEE 学习路线网上 Java 学习的零散资料太多了今天看一个 Servlet 教程明天看一段 Spring 视频后天翻一翻 MyBatis 的官方文档结果就是每个技术名词都见过但脑子里是一盘散沙。这套系列最大的价值是给了你一条主线让你知道每个知识点在这个链路里属于哪一环。1.1 JavaSE 到 JavaEE 之间那道坎很多人卡住不是因为 JavaSE 没学好而是因为不知道 JavaEE 阶段的学习目标和之前完全不同。JavaSE 阶段你写的代码运行入口是 main 方法你自己控制程序的流程。JavaEE 阶段写的是 Web 应用运行在容器里面由容器来管理组件的生命周期。你不再主动 new 一个 Servlet 出来调用而是把 Servlet 配置好让 Tomcat 在收到 HTTP 请求时帮你创建实例、调 init、调 service、再调 destroy。这个思维的转换是入门 Web 开发的第一道门槛。当时我花了很多时间想明白一件事你写的类什么时候被实例化谁调用了它数据是怎么传进来的。这些问题的答案不在代码本身而在容器规范里。所以学习 JavaEE一定要带着“容器思维”去看问题而不是像写单机程序一样只关注自己的类怎么实现。1.2 主线内容到底覆盖了什么这套学习体系基本覆盖了 JavaEE 开发的核心链路JavaWeb 基础HTTP 协议、Servlet、请求响应、Session 与 Cookie、过滤器、监听器数据库访问JDBC、数据库连接池、MyBatis项目管理Maven企业级框架Spring 的 IOC 和 AOP、SpringMVC整合实战SSM 整合做一个完整的增删改查项目R如果你把这几个点串起来看其实就是一条完整的请求链路浏览器发送 HTTP 请求 → Tomcat 容器接收 → Servlet 或 SpringMVC 的 DispatcherServlet 分发 → Controller 处理业务 → Service 层调用 Mapper → MyBatis 操作数据库 → 返回结果渲染到页面。每一个环节都在这个链路里有明确的位置。1.3 这套路线适合哪些人如果你是零基础转行自学或者科班刚上完 JavaSE 课程但对框架一脸懵又或者准备面试但发现自己的项目只是“照着视频敲了一遍”这条路线都值得完整走一遍。不过要说明白的是它适合的是“建立整体认知”的阶段而不是“追新”的阶段。它讲的主要是传统 JavaEE 技术栈SpringBoot 和微服务只是顺带提一下。但反过来讲如果你连 Servlet 的生命周期、Maven 的依赖机制、Spring 容器的运行原理都没想过直接去啃 SpringBoot 的自动装配很容易变成只会写注解的“配置搬运工”。2. JavaWeb 阶段的理解与实操要点从 HTTP 到 Servlet如果让我只选一个阶段来夯实基础我会把时间优先砸在 JavaWeb 这里。因为这个阶段学的东西决定了你后面理解框架时是“顿悟”还是“硬背”。2.1 先彻底搞懂 B/S 结构和 HTTP 协议很多教程一上来就写 Servlet 代码结果初学者连浏览器和服务器之间发生了什么都不知道。我建议你在写任何代码之前先用抓包工具或者浏览器开发者工具里的 Network 面板观察一次完整的 HTTP 请求。看什么看请求行、请求头、请求体请求方式是 GET 还是 POST路径是什么带了多少参数Cookie 在哪个字段里Content-Type 是什么。再看响应状态码 200、302、404、500 分别代表什么响应头里 Set-Cookie 做了什么响应体结构如何。我之前学习的时候专门用开发者工具访问了一个最简单的登录页面把请求和响应的每个字段抄下来挨个对照着看。这一步比单纯看视频有用得多。理解了这些你后面再看 Session 怎么维系状态、过滤器怎么拦截请求、SpringMVC 怎么绑定参数全都是水到渠成的事。HTTP 协议本身不复杂但它是 Web 开发的“普通话”。你不需要背下所有状态码但常用的那几十个尤其是 301/302、304、400、401、403、404、500、502要能说出来什么场景下会出现。2.2 Servlet 到底是什么为什么框架里还在用有时候你会听人说“现在谁还写 Servlet”这话其实是有误导性的。SpringMVC 的 DispatcherServlet 本身就是一个 Servlet只不过框架帮你把“分发到哪个 Controller、调用哪个方法”这层逻辑封装掉了。所以Servlet 是 JavaEE 的地基。你至少要手写过一次 Servlet并且搞清楚生命周期里那四个方法的调用顺序和调用者initServlet 实例创建后容器调用一次完成初始化service每次请求都会进入这个方法根据 HTTP 方法类型转给 doGet 或 doPostdestroy容器关闭或应用卸载时调用一次释放资源我在第一次学的时候有个体会不要只停留在“知道”层面要打开 Tomcat 的源码看一眼 HttpServlet 里的 service 方法是怎么把请求转发给 doGet、doPost 的。看完你就明白为什么继承 HttpServlet 之后只需要重写 doGet/doPost也明白为什么 doGet 里写逻辑的话发 POST 请求会得到 405。另外学 Servlet 一定要配合 web.xml 或者注解配置去理解映射关系。一个 URL 到了服务器容器怎么知道交给哪个 Servlet这就是 web.xml 里的 servlet-mapping 在做的事。哪怕后来你用 SpringMVC 的 RequestMapping本质上也还是在一个东西请求路径和处理器之间的映射。2.3 过滤器、监听器、Cookie/Session 的底层作用这三个概念如果只看定义很容易相互混淆。我用自己的话给你梳理一遍Cookie服务器放在浏览器本地的小数据每次请求都会自动携带。作用是用来标识客户端比如记住登录状态、记录偏好设置。Session服务器端为每个“会话”保存的数据结构。你第一次访问时服务器创建 Session给浏览器返回一个 JSESSIONID 的 Cookie之后浏览器每次请求带上这个 ID服务器就能找到对应的 Session。过滤器在请求进入 Servlet 之前做的拦截处理。登录校验、编码设置、请求日志都是典型场景。监听器监听 application、session、request 这几个作用域对象的创建和销毁或者属性的变化。比如在应用启动时初始化数据、在会话销毁时清理资源。这里有一个很经典的理解方法把一次请求想象成快递寄送。过滤器是快递分拣站检查包装、贴标签Servlet 是收件人真正处理包裹内容Session 是你在快递公司的会员档案Cookie 是你的会员卡。这么一对比谁在什么阶段干什么事就清楚多了。2.4 实操建议手动配置、源码追踪、调试走一遍JavaWeb 阶段我给的实操建议是三个第一不要一开始就全部用注解。手动在 web.xml 里配置一次 Servlet 和 Filter路径、初始化参数、加载顺序分别是什么配置一遍就懂。第二在 Servlet 的 init、service、destroy 方法里打日志启动 Tomcat发几个请求看日志打印顺序体会容器调用的顺序和时机。第三在过滤器中打印请求路径然后把 Chain 放行与不放行的结果都试一遍感受一下请求怎么被拦截、怎么回到页面。这套动作做完你对 Web 容器如何工作的理解会比背十遍概念都深刻得多。3. Maven 与项目环境管理别把时间浪费在“找 jar 包”上很多人学 JavaEE 新框架的时候最烦躁的其实不是代码而是环境。jar 包去哪里下载版本冲突了怎么办项目为什么在这台电脑上能跑、换一台就报错这些问题遇过一次之后你就明白Maven 不是可学可不学的工具而是 JavaEE 开发的基础设施。3.1 Maven 解决的核心问题依赖、构建、约定Maven 最核心的作用有三个依赖管理你只需要在 pom.xml 里声明依赖的坐标也就是 groupId、artifactId、versionMaven 就会自动从仓库下载相应的 jar 包以及它依赖的其他 jar 包也就是传递依赖。构建流程统一编译、测试、打包、部署这些步骤Maven 用生命周期给你统一管理起来。你不需要手动敲 javac、jar直接执行 mvn clean package 就行。目录约定源代码放在哪里、配置文件放在哪里、打包输出到哪里Maven 有约定好的结构。你只需要照着它的约定去创建目录团队协作时就不会出现“项目结构只有我自己懂”的情况。3.2 坐标、仓库与依赖冲突排查Maven 仓库分三级本地仓库、中央仓库以及配置的镜像、远程私服。依赖查找顺序也是先本地再镜像再远程。你在 pom.xml 里引入一个新依赖如果本地仓库没有它会去镜像下载。实际开发中依赖冲突是最常见的坑。比如直接用 JUnit 4 还是 JUnit 5Spring 和某个第三方库传递下来的 Spring 版本不一致就会导致运行时报 NoSuchMethodError 或者 ClassNotFoundException。最常见的排查方式是在 idea 的 Maven 面板里看依赖树找到冲突然后用排除依赖的方式解决。我以前解决过一个印象深刻的问题项目里有两个库都传递依赖了旧版的 commons-logging结果启动时报日志相关的异常。查了半天发现是依赖树里出现了两个版本。解决方式就是在 pom.xml 里用 exclusion 排除掉较旧的那个传递依赖显式声明需要的版本。这个排查过程本身就是对 Maven 机制的实战检验。3.3 新手必踩的几个坑与解决方案本地仓库默认在 C 盘一旦下载的依赖多了C 盘空间不够或者权限问题导致部分 jar 包损坏。建议改到自定义目录在 settings.xml 里配置 localRepository。依赖下载慢大概率是镜像没配好。在 settings.xml 里配置国内镜像仓库下载速度会有明显提升。idea 里改了 pom.xml 但项目没生效多半是没刷新 Maven 项目。IDEA 有 Maven 面板点 reload 按钮或者命令行 mvn clean compile。有时候明明在仓库里能看到 jar 包但项目就是报红。最笨但有效的办法是删除本地仓库里对应的目录重新 mvn -U 强制刷新下载。提示Maven 不是 JavaEE 的某个框架它更像你的“项目管家”。任何新加入的依赖、任何打包部署动作都优先经过 Maven 来做长期来看能避免很多环境问题。4. Spring 与 SpringMVC从“对象管理”到“请求处理”到了 Spring 这个阶段很多人会感觉前面学的东西突然“沉”下去了。因为 Spring 不是一个单一功能而是一整套容器和生态。你只有理解了容器怎么管理对象、AOP 怎么解决横切逻辑、SpringMVC 怎么接收请求才算是真正迈进了企业级开发的层次。4.1 IOC 与 DI 如何改变对象管理方式IOC控制反转听起来很玄其实核心就是一个概念对象的创建和管理不再由自己代码 new 来负责而是交给容器。你在配置文件里或者用注解定义好 Bean容器启动时帮你创建对象、维护它们之间的依赖关系。你需要用的时候直接告诉容器我要哪个 Bean容器就把装配好的对象给你。DI依赖注入就是 IOC 的具体实现方式容器在创建对象的时候把依赖的属性主动塞进对象里而不是让对象自己去找。我第一次理解这个思想的时候用了这么个类比自己造房子是传统的做法你要自己联系水泥、砖头、工人还要管施工进度。IOC 的模型是什么呢你只跟装修公司说出你的需求装修公司帮你把材料准备好、把工人安排好你只管住进去或者只管使用这个空间。对象之间的关系不由代码决定而是由容器统一装配。这个思想带来最直接的好处是代码解耦。你换一个实现类只需要改配置或者改注解标注的类而不用改业务逻辑里的 new。4.2 AOP 到底在解决什么问题AOP面向切面编程解决的是横切逻辑问题。业务代码要关心的事务、日志、权限校验本质上和“计算订单金额”这种核心逻辑关系不大。如果你在每个业务方法里都手动写一遍事务开启和提交代码会重复得没法看。AOP 的做法是把这些横切逻辑抽取成切面在方法调用前、后、异常抛出时插入指定逻辑。你只需要在配置里声明“哪些方法需要被拦截、拦截时要执行什么逻辑”Spring 就用动态代理或 CGLIB 帮你在运行时把增强逻辑织入目标方法。我当时是在实现一个转账功能时才真正理解 AOP 的价值的。两个账户之间转钱必须保证同一个事务中途任何一个 SQL 出错都要全部回滚。如果不用声明式事务你得手动在 Service 层 try-catch 来回写 commit 和 rollback。用 Spring 的 Transactional 注解容器会自动在方法执行前开启事务、执行后提交、异常时回滚。这背后就是 AOP 在起作用。4.3 SpringMVC 请求流转与 DispatcherServletSpringMVC 的学习核心只有一个请求从进入到返回经过了哪些组件。一条典型链路是这样的浏览器发送请求Tomcat 收到后转发给 DispatcherServlet。DispatcherServlet 根据请求 URL 匹配 HandlerMapping找到对应的 Controller 方法。然后通过 HandlerAdapter 调用 Controller 方法方法返回 ModelAndView 或者直接返回 JSON。如果是视图解析ViewResolver 会解析出具体的 JSP 或 HTML 页面。最后 DispatcherServlet 把结果写回浏览器。我把这个流程背了大概五遍才真正画得出流程图。画出来的那一瞬间就明白为什么 Controller 方法可以只写业务逻辑不用关心 Servlet API。因为从请求进入到返回所有 Servlet 层级的处理细节都被 DispatcherServlet 和它的组件封装好了。4.4 SSM 整合的思路与配置细节SSM 整合是很多 JavaEE 学习路线最后一个实战大项目。整合的意义是让你把所有组件放在同一个项目里跑通。核心就三件事Spring 管好 Service 层对象SpringMVC 管好 Controller 层MyBatis 管好数据库映射层。配置方式分两种1用 XML 配置手写 applicationContext.xml、springmvc.xml、mybatis-config.xml2用全注解和配置类。我建议第一遍老老实实用 XML 配置一次因为整个过程中你会把扫描包、数据源、事务管理器、Mapper 扫描、视图解析器这些配置逐个弄明白而不是复制粘贴一个自动配置类。举一个常见的整合细节Spring 容器和 SpringMVC 容器是两个容器Spring 管 Service、MapperSpringMVC 管 Controller。如果包扫描配置错了要么注入不到 Service要么报重复 Bean 的错。很多整合失败的案例问题都出在扫描范围上spring 的扫描配置该写 service、dao 包而不该把 controller 包也扫进去SpringMVC 的扫描配置则只负责 controller 和相关 Web 组件。注意不要把所有包一股脑让两个容器都扫描不然很容易出现事务不生效或者 Bean 覆盖的问题。这个坑几乎每个做过 SSM 整合的人都会遇到一次。5. 数据库访问JDBC、连接池与 MyBatis如果你不想只能做“展示数据的网页”数据库这块必须学扎实。JavaEE 里操作数据库的方式是一步步演进的从 JDBC 原生操作到用连接池到 MyBatis 半自动化框架再到 Spring 封装好的 MyBatis。理解这条演进路径你就知道框架到底帮你省了什么。5.1 JDBC 原生操作与连接池的意义JDBC 是 Java 操作数据库的标准接口。你自己手写的时候步骤大概是加载驱动 → 获取连接 → 创建 Statement/PreparedStatement → 执行 SQL → 处理 ResultSet → 关闭连接。这里最明显的问题是连接每次使用时都要创建用完要关闭频繁创建销毁开销很大。所以连接池就出现了比如 HikariCP、Druid、C3P0。连接池的本质是预先创建一批数据库连接用完放回池里复用需要的时候从池里取不关闭连接而是归还连接。你用代码看获取和关闭连接的写法好像没变但底层管理方式完全不同。我建议你至少在初学阶段手动写一遍完整的 JDBC 增删改查再封装一次 JDBCUtils 工具类。在封装的过程中你对“为什么需要连接池”这个问题的理解会非常深。5.2 MyBatis 的 Mapper、参数映射与动态 SQLMyBatis 做的事情是把 JDBC 的重复样板代码封装掉让你只关注 SQL 和参数映射。它有两个关键概念Mapper 接口定义数据库操作方法方法名对应 XML 里的 SQL id。Mapper XML写 SQL 的地方参数用 #{} 方式占位。第一个要注意的点是 #{} 和 ${} 的区别。#{} 是预编译传进去的值会作为参数值设置到 PreparedStatement 中防 SQL 注入${} 是字符串拼接很多东西不能用它比如表名、排序字段但输入不可信时不要直接用 ${} 拼接 SQL。第二个要掌握的是动态 SQL。MyBatis 的 if、choose、foreach 等标签是为了解决“查询条件不确定”的常见场景。我在实际项目里体会最深的是这种场景列表页筛选条件可能有也可能没有你会写 according to 条件拼 SQL。用动态 SQL 之后就不用在代码里手动拼接一堆 if else 字符串。5.3 事务控制与数据库隔离级别写数据库应用事务肯定绕不开。事务的 ACID 特性以及隔离级别算是面试常考的重点也是实际开发中会踩坑的地方。隔离级别有四个读未提交、读已提交、可重复读、串行化。MySQL 默认是可重复读这意味着在一次事务里多次读取同一数据的结果应该是一样的。但这也会带来潜在问题比如幻读MySQL 用多版本并发控制MVCC和行锁/间隙锁配合解决。实际工作中事务的配置粒度也很关键。Spring 的事务默认在 RuntimeException 上回滚如果业务方法里把异常 catch 掉了事务不会回滚数据可能就写错了。我当时为了排查一个“数据明明报错但还是保存了”的 bug看了好久代码最后发现是 catch 了异常并做了日志输出。理解了事务代理的机制之后这个问题一眼就能定位。6. 学习过程中最常见的坑和排查技巧实录这部分我想把自己实际踩过、以及身边很多初学者都遇到过的坑集中列成一张速查表。每一项都是真实的调试经历建议你遇到类似问题的时候优先对照这里。6.1 环境启动类问题Tomcat 启动时端口被占用8080 被其他进程占用了。排查方式确认占用进程要么改端口要么结束占用进程。部署时项目显示没有 ArtifactIDEA 里部署 Web 项目需要手动配置 war exploded 的部署方式很多人忘记这一步。启动后访问 404先确认 URL 路径和项目 context path 对不对再确认文件放在了 webapp/WEB-INF 里以及 web.xml 是否加载到了 Servlet。ClassNotFoundException多半是依赖没有打包到 WEB-INF/lib需要在 IDEA 的 Artifacts 里把依赖加进去。6.2 依赖与编译类问题出现两个 Spring 版本使用 mvn dependency:tree 查看依赖树找出传递依赖冲突。Spring XML 文件开头报 schema 相关错误一般是 applicationContext.xml 里的 xsd 网址访问不到检查是否联网或者本地有没有对应版本。明明改了数据库配置但启动还是连接的旧库检查编译后的 target 目录里 applicationContext 相关的配置文件是否更新有时候只是没 clean 导致旧配置还在。6.3 设计与配置类问题Service 层加了 Transactional 但事务不生效可能原因1类没有被 Spring 管理没有加 Service2自调用方法Spring 代理不会拦截同一个类内部的方法3异常被 catch 了回滚失效。SpringMVC 请求转发到 JSP 时路径不对检查视图解析器配置里的 prefix 和 suffix以及 JSP 文件所在的目录是不是在 WEB-INF 下面。MyBatis 的 Mapper 接口和 XML 绑定不上检查 namespace 是否等于接口全限定名SQL id 是否等于方法名以及 XML 文件有没有放进 target/classes。6.4 这些问题为什么值得专门记录很多初学者遇到这些问题会觉得很挫败觉得“是我太笨了”。实际上这些坑几乎所有人都会踩一遍踩过一次、记录一次、排查一次后面的速度会快很多。我自己的习惯是每次排查完一个问题就整理一个短小的记录包含现象、排查命令、最终原因、解决方案。一周之后回头看你会发现自己解决问题的能力增长非常快。7. 建议的学习节奏与配套练习方式如果不需要赶时间我的建议是用大约 6 到 8 周来走完上面这条主线。不需要每天高强度学习但一定要保证每个知识点都有代码和实践支撑。7.1 一套可执行的时间安排第 1 周JavaWeb 基础。重点掌握 HTTP、Servlet、Cookie/Session、Filter。手动写一个简单的登录注册页面数据可以暂时存在内存集合理。第 2 周Maven。先用三天搞清楚 pom、依赖、生命周期再用一周时间把一个之前手写的 Web 项目改造成 Maven 项目。第 3 到 4 周Spring 和 SpringMVC。用 XML 配置一个 IOC 容器定义一个切面再分别练习 SpringMVC 的表单提交、参数绑定、JSON 返回。完成 Spring 管业务、SpringMVC 管控制层的小整合。第 5 周MyBatis。用 XML 方式完成单表增删改查、多表查询、动态 SQL。再把 MyBatis 接入 Spring。第 6 到 8 周SSM 整合做项目。建议做一个有用户登录、列表展示、新增编辑、条件查询的小管理后台每个功能都用一套完整链路前端页面 → Controller → Service → Mapper → 数据库。7.2 练习项目怎么选、怎么做很多人做项目时喜欢找那种功能非常复杂的大项目但我觉得第一个 SSM 项目功能在精不在多。哪怕只是一个用户管理系统只要你能自己独立把登录、增删改查、分页、条件查询、事务这些环节全部打通你对 JavaEE 的理解就已经超过不少工作了几个月但只会照抄代码的人了。练习过程中要注意不要一上来就打开视频跟着敲。建议先自己想想功能流程、数据库表怎么建、接口怎么分然后再看参考实现。遇到 bug 时先打印日志、断点调试别急着看下一节视频。做项目时我还推荐一个做法给自己加一个额外的需求比如给用户表加个状态字段实现禁用用户不能登录的逻辑。这种超出原教程的小需求最能锻炼你独立排查和设计的能力。7.3 面试常问的串联问题学完这一整套之后你其实已经可以回答不少高频面试题了。试着把这些题目按主线回答一遍输入一个 URL 到页面展示出来中间发生了什么Servlet 和 Filter 的区别为什么用 Maven依赖冲突怎么解决Spring 的 IOC 是什么AOP 用在什么场景SpringMVC 的请求流转过程MyBatis 的 #{} 和 ${} 区别为什么说 #{} 能防 SQL 注入事务失效的常见原因有哪些把这几个问题讲清楚你不但能建立起知识之间的联系面试的时候也会更有底气。最后再分享一个小经验学习 JavaEE 千万别只看不写。看视频的时候什么都明白关掉视频一上手就各种报错这种感觉太正常了。报错不是坏事它是在逼你去看底层机制。我刚学 Spring 的时候光是容器初始化报错就调了两天但就是在反复排查的过程中把 Bean 的生命周期和依赖注入真正理解透了。框架可以越出越新但底层这套“请求-处理-数据”的逻辑永远是 JavaWeb 开发的基本功。后面就算你切换到 SpringBoot、SpringCloud这段基础也会一直陪着你。