ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SSM配置index页面的三种方式与常见坑,从入口到渲染一次讲透

SSM配置index页面的三种方式与常见坑,从入口到渲染一次讲透 刚学 SSM 的时候我干过一件特别傻的事把 index.jsp 往 webapp 根目录一扔启动 Tomcat 直接访问 localhost:8080结果迎面一个大大的 404。后来才慢慢明白SSM 里配 index 页面远不是“放一个文件”那么简单它牵扯到 web.xml 的欢迎页声明、DispatcherServlet 的请求分发、SpringMVC 视图解析器的前缀后缀设置甚至还有静态资源放行和 JSP 编译依赖。这篇博文就把 SSM 配置 index 页面的几种主流实现方式全部拆开讲透适合刚接触 SSM 的初学者也适合那些配了半天欢迎页就是不生效、被 index 跳转绕晕的开发同学。1. 配 index 之前先把请求链路拉直1.1 一次 index 访问到底发生了什么浏览器地址栏输入http://localhost:8080/按下回车到页面最终渲染出来中间经过的环节比你想的多得多。Tomcat 拿到请求后先根据 web.xml 里的welcome-file配置确定默认页面如果这个页面是.jspTomcat 会把请求交给 JSP 引擎编译渲染如果这个页面碰巧匹配了 DispatcherServlet 的映射规则请求才会进入 SpringMVC 的完整流程——HandlerMapping 找 Controller、Controller 返回视图名、ViewResolver 解析成物理视图、再渲染输出。这里有个特别容易踩的坑很多人以为配置了welcome-file就万事大吉结果在 SSM 项目里偏偏失效。原因在于 DispatcherServlet 的url-pattern如果配置成/它会接管所有请求包括根路径的欢迎页请求。Tomcat 的欢迎页机制本质上依赖 DefaultServlet 来处理根路径一旦请求被 SpringMVC 的前端控制器截走welcome-file 这个配置就直接被绕过了。所以理解请求链路比抄一段配置更重要。1.2 谁在做拦截url-pattern 的细节差异DispatcherServlet 在 web.xml 里的映射方式有几种常见写法效果完全不同。/表示拦截所有请求但不包括 JSP因为 Tomcat 对.jsp有专门处理这种配置在 SSM 项目里最常见但必须配合静态资源放行。/*表示拦截所有请求包括 JSP一旦这么配视图解析器返回的 JSP 页面也会被 DispatcherServlet 再拦截一次导致页面永远出不来基本属于自杀式配置。/index.do这种按后缀映射的方式能完美避开静态资源问题但又会让 URL 带上.do尾巴现在很少有人这么干。用生活类比解释一下Tomcat 就像一个公司前台welcome-file 是前台手边的“默认接待名单”DispatcherServlet 则是一个独立工位的经理助理。如果助理把进门的每个人都拉去自己办公室聊一遍/拦截那前台手里的名单自然就失效了。搞清楚这层关系下面所有配置方案你都能理解为什么这样写。2. 三种主流配置方式对比2.1 方式一web.xml 里声明 welcome-file这是最朴素的方式适合入口就是一个静态页面、或者不需要经过 SpringMVC 任何逻辑的场景。在 web.xml 的welcome-file-list里声明一个文件名welcome-file-list welcome-fileindex.html/welcome-file /welcome-file-list注意这里只能写文件名不能写路径访问符。Tomcat 会按声明顺序在 webapp 根目录和各个子目录下查找这个文件。比如声明index.html用户访问http://localhost:8080/时Tomcat 会尝试返回根目录下的index.html。如果项目里同时有index.jsp和index.html以最先命中的为准顺序在前的优先。这个方式的局限性很明显它不经过 SpringMVC所以无法在跳转前做任何逻辑处理比如判断用户是否登录、根据角色跳转不同首页。而且如果 DispatcherServlet 配置了/映射这个欢迎页配置确实可能不生效后面第五章讲排查时会细说。2.2 方式二Controller 里写 RequestMapping(/)这是 SSM 项目里最灵活、也最常用的方式。写一个专门的 Controller把根路径映射到某个视图Controller public class IndexController { GetMapping(/) public String index(Model model) { model.addAttribute(siteName, 我的 SSM 项目); return index; } }当用户访问http://localhost:8080/时请求进入 DispatcherServletHandlerMapping 找到这个IndexController的index方法方法里可以塞数据、可以做校验最后返回逻辑视图名index由视图解析器拼成真实的 JSP 路径完成渲染。我之前在一个后台管理系统里就是这么配的。首页需要根据登录用户的角色展示不同的菜单和统计卡片用这种方式在返回视图之前从 Session 里取用户信息、查一下权限再决定是跳去登录页还是工作台非常自然。动态逻辑需求多的项目优先用 Controller 方式。2.3 方式三springmvc.xml 里的 mvc:view-controller如果首页完全不需要业务逻辑纯粹是跳转到一个 JSP 页面那连 Controller 都不必写直接在 SpringMVC 配置文件中声明mvc:view-controller path/ view-nameindex/这行配置的意思很直白访问/路径时直接转发到逻辑视图名index。比起写一个完整的 Controller 类这种声明式配置更轻量、更直观代码里少一个类就少一份维护成本。但要注意一旦使用了mvc:view-controllerSpringMVC 会基于配置创建专门的 HandlerMapping这会导致原本基于注解的RequestMapping映射失效。解决办法是同时配置mvc:annotation-driven/让两种映射方式共存。这是一个特别容易忽略的细节很多人配了 view-controller 后发现自己原来写的 Controller 接口全 404 了就是少了这一行。2.4 三种方式怎么选配置方式适用场景优点缺点welcome-file纯静态入口页最简单、零代码不经过 SpringMVC无逻辑处理能力Controller 映射首页需要业务逻辑灵活可控支持数据填充多写一个类或方法mvc:view-controller纯转发无逻辑声明式极简需配合 annotation-driven 使用我在实际项目中总结下来的经验是后台管理系统这类需要权限校验的基本都用 Controller 方式一些内部工具系统或者单体应用的纯展示首页用 mvc:view-controller 更干净welcome-file 一般只在新项目骨架搭建阶段临时用一下或者配合纯静态的前端页面部署。3. 实操记录逐步配一个可用的 SSM 首页3.1 项目结构先摆好我下面这套配置基于 Maven 构建的标准 SSM 项目目录结构如下ssm-demo ├── pom.xml └── src/main ├── java │ └── com/demo │ ├── controller/IndexController.java │ ├── service/ │ └── mapper/ ├── resources │ ├── jdbc.properties │ ├── spring/applicationContext.xml │ └── springmvc/springmvc.xml └── webapp ├── WEB-INF │ ├── web.xml │ └── jsp/index.jsp └── static ├── css/style.css └── js/common.js需要说明的是JSP 页面我放在WEB-INF/jsp/而不是 webapp 根目录这是 SSM 项目推荐的做法。WEB-INF 目录下的资源不能被浏览器直接访问只能通过 Controller 内部转发forward来渲染能有效防止用户绕过入口直接访问内部页面。静态资源 css/js 放 webapp 下的 static 目录走单独放行规则。3.2 web.xml 的关键配置web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 display-namessm-demo/display-name !-- Spring 容器配置文件 -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/applicationContext.xml/param-value /context-param !-- 启动时加载 Spring 容器 -- listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener !-- SpringMVC 前端控制器 -- servlet servlet-namedispatcherServlet/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:springmvc/springmvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcherServlet/servlet-name url-pattern//url-pattern /servlet-mapping /web-app这里有两个重点。第一url-pattern//url-pattern表示 DispatcherServlet 接管除 JSP 之外的所有请求根路径访问也会被它处理所以我们的首页跳转逻辑写在 Controller 或 view-controller 里才能生效。第二Spring 容器和 SpringMVC 容器是父子容器关系applicationContext.xml管理 service、mapper 等业务层 Beanspringmvc.xml管理 Controller 和视图解析器分层清晰。3.3 springmvc.xml 配置视图解析器与静态资源放行?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:mvchttp://www.springframework.org/schema/mvc xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd context:component-scan base-packagecom.demo.controller/ mvc:annotation-driven/ !-- 静态资源放行 -- mvc:resources mapping/static/** location/static// !-- 视图解析器 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/jsp// property namesuffix value.jsp/ /bean !-- 方式三声明式首页跳转如果不需要可以删除 -- mvc:view-controller path/ view-nameindex/ /beans视图解析器是 SSM 配 index 页面的核心所在。InternalResourceViewResolver的作用就是把 Controller 返回的逻辑视图名拼接成真实的物理路径Controller 返回index实际渲染的就是/WEB-INF/jsp/index.jsp前缀后缀一拼路径就齐了。如果没有配置这个解析器SpringMVC 默认用BeanNameViewResolverController 返回index时它会去找一个名为index的 View Bean基本等于 404。mvc:resources这块也关键。因为 DispatcherServlet 拦截了/静态资源请求同样会进 SpringMVC 流转如果不放行访问/static/css/style.css时会报 404。mapping指定 URL 匹配规则location指定资源在 webapp 下的物理目录。3.4 Controller 编写与返回逻辑package com.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; Controller public class IndexController { GetMapping(/) public String index(Model model) { model.addAttribute(siteName, SSM Demo); model.addAttribute(welcome, 欢迎使用 SSM 框架); return index; } }这个 Controller 做的事情很简单把两个字符串塞进 Model返回视图名index。页面里用 EL 表达式取出来展示比如${siteName}、${welcome}。实际项目中这里通常会注入 Service查一些数据库里的配置项、统计数据再返回首页就是通过这些动态数据撑起来的。有一点值得注意如果 springmvc.xml 里同时配置了mvc:view-controller path/和这个 Controller 的GetMapping(/)SpringMVC 会使用哪个实测下来mvc:annotation-driven注册的注解映射处理器优先级更高通常以 Controller 为准但这种重叠本身不是好事二选一即可——有逻辑用 Controller没逻辑用 view-controller别两个都写。3.5 页面文件与实测index.jsp放在src/main/webapp/WEB-INF/jsp/下内容不追求花哨能验证效果就行% page contentTypetext/html;charsetUTF-8 languagejava % html head title${siteName}/title /head body h2${welcome}/h2 /body /html启动 Tomcat 后访问http://localhost:8080/请求链路是这样的DispatcherServlet 收到根路径请求 → 走IndexController.index()→ 返回逻辑视图index→InternalResourceViewResolver拼接成/WEB-INF/jsp/index.jsp→ JSP 引擎渲染响应给浏览器。整个过程在控制台可以看到日志输出如果配错了通常会在这一步暴露异常信息。顺便提一句Tomcat 启动时看控制台有时会出现Unable to compile class for JSP类似错误这通常不是 SSM 配置问题而是缺了 JSP 编译依赖第五章单独讲。4. 静态页面与动态页面的 index 整合思路4.1 index.html 放 webapp 根目录时的资源问题有些项目入口不需要动态数据比如营销活动页、展示型官网index 就是一个纯静态 HTML。做法也很直接把index.html放在 webapp 根目录同时确保 springmvc.xml 里配好了对静态资源目录的放行。这种场景下有一个很容易被忽略的坑HTML 页面里的相对路径。如果index.html引用了static/css/style.css直接访问http://localhost:8080/时页面请求的 CSS 路径是/static/css/style.css这个路径能正确匹配mvc:resources的放行规则没问题。但如果页面是下拉菜单展开到某个子路径比如浏览器地址变成http://localhost:8080/some/module而 HTML 里写的是相对路径static/css/style.css浏览器会解析成/some/static/css/style.css直接 404。解决方案是尽量在页面里以/开头的绝对路径引用资源。4.2 为什么推荐把 JSP 放到 WEB-INF/jsp/ 下面我见过不少新手项目把 index.jsp 直接放 webapp 根目录还振振有词说这样简单。等到上线的时候发现问题了用户可以直接访问http://localhost:8080/login.jsp绕过了登录拦截器直接看到登录页面逻辑和安全都出问题。放在WEB-INF/jsp/下用户无法通过 URL 直接访问这个文件只能通过 Controller 内部转发去渲染等于把页面访问口统一收口到入口逻辑上。打个比方WEB-INF 就像是餐厅的后厨客人浏览器只能看菜单Controller 暴露的 URL不能自己闯进后厨端菜。所有菜品都需要服务员视图解析器帮忙端出来。这个习惯养成之后很多安全上的低级问题自然就避开了。4.3 混合场景静态首页 动态登录跳转讲一个实际项目的经验。之前给一个小型 OA 系统做首页产品要求首页展示公司简介和公告但不登录也能看点“进入系统”时要校验登录状态没登录跳去登录页登录成功跳工作台。我当时的方案是首页用index.jspController 方式处理/从数据库加载公告列表展示在页面上页面里的“进入系统”按钮指向/dashboard这个请求被 SpringMVC 拦截器拦截拦截器里判断 Session 有没有用户没有就重定向到/login页面另一个 Controller 处理有就放行到 dashboard 页面。整个链路都是走 Controller 转发没有一个 JSP 是浏览器能直接访问的安全性和灵活性都兼顾到了。这种混合场景其实才是 SSM 项目的常态单纯用一个 welcome-file 或者 view-controller 根本扛不住Controller 方式才是正规军打法。5. 常见问题排查手册5.1 配了 welcome-file 还是 404第一步先确认 web.xml 里的welcome-file-list拼写和路径对不对welcome-file 里只能写文件名不要把WEB-INF/jsp/index.jsp这种冗长路径填进去那样永远不会生效。第二步看 DispatcherServlet 的 url-pattern。如果是/那 welcome-file 大概率被绕过了——建议直接改用 Controller 或 view-controller 方式跳转别再纠结 welcome-file。第三步检查项目构建产物特别是 Maven 项目有时候target/目录里根本没把新增的 jsp 页面打进去ide 显示的目录结构和实际 war 包不一致clean package 一下就好。5.2 首页出来了但 CSS/JS 全挂典型症状是 HTML 结构正常但页面奇丑无比控制台刷一排 404全是 css/js 文件。根因就是 DispatcherServlet 拦截/后静态资源请求没放行。解决方式就是前面讲的mvc:resources mapping/static/** location/static//把静态资源目录和 URL 映射对上。如果配了还是 404检查你页面上引用的资源路径到底是不是/static/开头。有时候前端把资源相对路径写错了比如引用了css/style.css实际文件放在/static/css/style.css浏览器解析不了这不是后端配置能救回来的。5.3 访问 JSP 显示源码或 500如果浏览器直接把 JSP 源码当文本输出说明你的项目没把 JSP 当 JSP 编译这在 Maven 打包后运行时尤其常见。检查 pom.xml 里是否缺了tomcat-embed-jasper依赖如果你用嵌入式 Tomcat 启动或者javax.servlet.jsp相关依赖。在 IDEA 里直接跑 Tomcat 插件时这个依赖经常要被显式申明dependency groupIdorg.apache.tomcat.embed/groupId artifactIdtomcat-embed-jasper/artifactId scopeprovided/scope /dependency如果是 500 错误页除了缺依赖还有可能是 JSP 里引用了不存在的对象比如页面用了${siteName}但 Controller 没往 Model 里塞。把 Tomcat 控制台的异常堆栈翻出来看通常都能定位到具体是哪一行出了问题。5.4 Controller 返回 index 但页面空白或者 404先看视图解析器的前缀后缀。假设你 JSP 实际路径是/WEB-INF/jsp/index.jspprefix 配的是/WEB-INF/suffix 配的是.jsp那 Controller 返回的视图名必须精确是jsp/index反过来 prefix 配/WEB-INF/jsp/时返回index正好。很多人这里不统一要么多写了一层目录要么漏了后缀结果视图解析器拼出来的物理路径根本不存在。另外检查一下返回的字符串有没有多余空格。return index;这种带空格的写法视图解析器会把空格也当成路径的一部分照样 404。这种细节写在代码里肉眼很难发现排查半天往往就是多了一个空格的事。5.5 问题速查表问题现象常见原因解决方向配了 welcome-file 不生效DispatcherServlet 映射/接管请求改用 Controller 或 view-controller首页能打开但样式全挂静态资源没放行加mvc:resources配置访问 JSP 显示源码缺 JSP 编译依赖加 tomcat-embed-jasperController 返回后 404视图解析器前后缀不匹配核对 prefix/suffix 与 JSP 物理路径返回字符串多空格代码细节问题检查 return 语句去掉多余空格配置 view-controller 后注解接口失效缺少 annotation-driven加上mvc:annotation-driven/6. 最后再分享两个小技巧第一个技巧是配置多套 index 的降级策略。我在某个网关类项目里要求首页有一个“系统维护中”的静态提示页还要有一个正常的动态首页。做法很简单Controller 里根据一个配置开关选择返回不同的视图名开关为 true 返回maintenancefalse 返回index。两个 JSP 都放在WEB-INF/jsp/下天然安全运维改个配置重启一下就能切换不需要动代码。第二个技巧跟项目结构有关。新项目搭骨架时我习惯先把 Controller 方式和 view-controller 方式各配一套然后故意把其中一套注释掉再启动观察 404 页面和日志差异。这么折腾一次比看十篇文档都管用能让你对 SpringMVC 的请求流转有体感上的认知。SSM 配置 index 页面其实不复杂核心是搞清楚请求链路上谁是前台、谁是助理、谁在转发、谁在渲染把这几个角色认清了后面遇到 Spring Boot 的欢迎页、Shiro 的登录跳转你都能举一反三。
返回列表