绝对路径${pageContext.request.contextPath}用法及其与web.xml中Servlet的url-pattern匹配过程

本文解析了JavaWeb项目中实现商品添加功能的具体步骤。详细介绍了add.jsp页面的构成及其与后端交互的过程,包括使用${pageContext.request.contextPath}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以系统的一个“添加商品”的功能为例加以说明,系统页面为add.jsp,如图一所示:


图一  添加商品界面

系统的代码目录结构及add.jsp代码如图二所示:


图二   系统的代码目录结构及add.jsp代码

${pageContext.request.contextPath}用于解决使用相对路径时出现的问题,它的作用是取出所部署项目的名字。

对于图片文件,如图二所示${pageContext.request.contextPath}/bookcover/101.jpg”使用的是绝对路径,${pageContext.request.contextPath}返回的是”/test”【注意:很多地方写的返回值是test/”,这是不对的】,拼接之后路径就变成:“/test/bookcover/101.jpg”。如果使用相对路径则为:“../../bookcover/101.jpg”(相对于add.jsp页面)。其他的CSS文件、Js文件、Jsp文件与图片文件相似,使用方法一样。

JavaWeb项目中,Jsp页面的form表单的action属性也常常会使用${pageContext.request.contextPath}来表示请求路径。如图二中【没有使用框架】的form表单的action属性为:action="${pageContext.request.contextPath }/servlet/addBookServlet"。要理解这个请求地址,必须先了解web.xml【注意:web.xml必须放在WEB-INF文件夹下,原因见博客:http://blog.csdn.net/sun9528/article/details/72423112】的写法:

①完全匹配:以“/”开头,以字母(非“*”)结束

   如:上面提到的本项目中:<url-pattern>/servlet/addBookServlet</url-pattern>

②目录匹配:以“/”开头且以“/*”结尾

   如:<url-pattern>/test/*</url-pattern>

   <url-pattern>/*</url-pattern>

③扩展名匹配:以“*.”开头,以扩展名结束

   如:<url-pattern>*.do</url-pattern>

④“/”用来表明对应的Servlet为应用默认的Servlet。在这种情况下Servlet路径是请求的URI去掉上下文路径并且路径信息为null

本项目中“商品添加”功能的web.xml配置如下:

  <servlet>
	    <servlet-name>AddBookServlet</servlet-name>
	    <servlet-class>com.itheima.web.servlet.AddBookServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
	    <servlet-name>AddBookServlet</servlet-name>
	    <url-pattern>/servlet/addBookServlet</url-pattern>
  </servlet-mapping>

当点击了页面提交表单的命令之后,一个请求发送到servlet容器,servlet容器先会将请求的url减去当前应用上下文的路径作为servlet的映射url。访问的是http://localhost:8080/test/servlet/addBookServlet,我的应用上下文是test,容器会将http://localhost:8080/test去掉,剩下的/servlet/addBookServlet部分拿来做servlet的映射匹配。很明显可以通过图三的形式在web.xml中找到请求的动作类(url-pattern--->servlet-name--->servlet-class)。动作类为:com.itheima.web.servlet.AddBookServlet。然后由动作类在进行一些后台操作。


图三 url-pattern--->servlet-name--->servlet-class

 



<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- 1. 字符编码过滤器(必须放在第一个filter) --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 2. 静态资源处理过滤器(新增) --> <filter> <filter-name>staticResourceFilter</filter-name> <filter-class>org.springframework.web.filter.ResourceUrlEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>staticResourceFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 3. Spring MVC 前端控制器 --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/spring/spring-mvc.xml</param-value> </init-param> <init-param> <param-name>throwExceptionIfNoHandlerFound</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <!-- 4. 静态资源放行配置(关键修改) --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/statics/*</url-pattern> <url-pattern>/images/*</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.gif</url-pattern> <url-pattern>*.ico</url-pattern> <url-pattern>*.woff</url-pattern> <url-pattern>*.woff2</url-pattern> <url-pattern>*.ttf</url-pattern> <url-pattern>*.svg</url-pattern> </servlet-mapping> <!-- 5. Spring MVC 映射(必须放在静态资源之后) --> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 6. 错误页面配置(可选) --> <error-page> <error-code>404</error-code> <location>/WEB-INF/views/error/404.jsp</location> </error-page> <!-- 7. 欢迎页配置 --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>/这是web.xml界面/<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>流浪狗救助站 - 首页</title> <link rel="stylesheet" href="${pageContext.request.contextPath}/statics/css/style.css" /> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <script> $(document).ready(function() { // 动态数字动画效果 $('.stat-number').each(function() { var $this = $(this); var target = parseInt($this.text().replace('+', '')); var current = 0; var increment = target / 50; // 控制动画速度 var timer = setInterval(function() { current += increment; if (current >= target) { clearInterval(timer); current = target; $this.text(target + '+'); } else { $this.text(Math.floor(current) + '+'); } }, 20); }); // 平滑滚动到锚点 $('a[href^="#"]').on('click', function(event) { event.preventDefault(); $('html, body').animate({ scrollTop: $($.attr(this, 'href')).offset().top }, 800); }); }); </script> </head> <body> <header class="navbar"> <div class="nav-container"> <ul class="nav-menu"> <li class="active"><a href="${pageContext.request.contextPath}/views/user/home.jsp">首页</a></li> <li><a href="${pageContext.request.contextPath}/dogs">待领养狗狗</a></li> <li><a href="${pageContext.request.contextPath}/views/user/about.jsp">关于我们</a></li> <li><a href="${pageContext.request.contextPath}/views/user/contact.jsp">联系我们</a></li> <c:if test="${not empty sessionScope.user}"> <li><a href="${pageContext.request.contextPath}/logout">退出登录</a></li> </c:if> </ul> </div> </header> <div class="hero"> <h1 class="hero-title">为流浪狗发声,让世界更美好</h1> <p class="hero-subtitle">携手保护流浪动物,共建和谐生态环境</p> <div class="btn-container"> <a href="${pageContext.request.contextPath}/views/login.jsp" class="btn btn-primary">立即行动</a> <a href="#about-section" class="btn btn-secondary">了解更多</a> </div> </div> <section class="stats"> <div class="stat-item"> <div class="stat-number">25+</div> <div class="stat-label">救助项目</div> </div> <div class="stat-item"> <div class="stat-number">1200+</div> <div class="stat-label">志愿者</div> </div> <div class="stat-item"> <div class="stat-number">50+</div> <div class="stat-label">合作伙伴</div> </div> </section> <!-- 新增的详细介绍部分 --> <section id="about-section" class="about-section"> <div class="container"> <h2>关于潦草小狗救助站</h2> <div class="about-content"> <div class="about-text"> <h3>我们的使命</h3> <p>潦草小狗救助站成立于2010年,是一个非营利性组织,致力于为无家可归的流浪狗提供庇护、医疗和寻找永久家庭的机会。我们相信每只狗都值得被关爱和保护。</p> <h3>我们的工作</h3> <p>我们的工作包括:</p> <ul> <li>救助街头流浪狗并提供临时庇护</li> <li>为狗狗提供必要的医疗护理和绝育服务</li> <li>通过领养计划为狗狗寻找永久家庭</li> <li>开展公众教育活动,提高动物保护意识</li> <li>倡导动物福利政策的改进</li> </ul> <h3>我们的成就</h3> <p>自成立以来,我们已经:</p> <ul> <li>救助了超过5000只流浪狗</li> <li>为3000多只狗狗找到了永远的家</li> <li>开展了200多场公众教育活动</li> <li>建立了覆盖全市的志愿者网络</li> </ul> </div> <div class="about-image"> <img src="${pageContext.request.contextPath}/images/rescue-dog.jpg" alt="被救助的狗狗"> </div> </div> </div> </section> <section class="how-to-help"> <div class="container"> <h2>如何帮助它们</h2> <div class="help-options"> <div class="help-option"> <div class="help-icon">🏠</div> <h3>领养</h3> <p>给无家可归的狗狗一个温暖的家。领养不仅拯救了一只狗的生命,也为其他需要救助的狗狗腾出了空间。</p> <a href="${pageContext.request.contextPath}/dogs" class="btn btn-small">查看待领养狗狗</a> </div> <div class="help-option"> <div class="help-icon">🤝</div> <h3>志愿者</h3> <p>加入我们的志愿者团队,参狗狗的日常照顾、遛狗、清洁等工作。您的每一分钟都能带来改变。</p> <a href="${pageContext.request.contextPath}/views/user/contact.jsp" class="btn btn-small">成为志愿者</a> </div> <div class="help-option"> <div class="help-icon">💝</div> <h3>捐赠</h3> <p>您的捐款将直接用于狗狗的食物、医疗和庇护所运营。每一分钱都能帮助改善狗狗的生活,助力它们走向更好的未来。</p> <a href="#" class="btn btn-small">立即捐赠</a> </div> </div> </div> </section> </body> </html>/这是index.jsp,为什么css文件不体现
最新发布
07-11
%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta charset="utf-8"> <!-- 标题栏LOGO --> <link rel="icon" type="image/x-icon" href="/favicon.ico"> <!--字体图标--> <link href="javaex/pc/css/icomoon.css" rel="stylesheet" /> <!--动画--> <link href="javaex/pc/css/animate.css" rel="stylesheet" /> <!--骨架样式--> <link href="javaex/pc/css/common.css" rel="stylesheet" /> <!--皮肤(缇娜)--> <link href="javaex/pc/css/skin/tina.css" rel="stylesheet" /> <!--jquery,不可修改版本--> <script src="javaex/pc/lib/jquery-1.7.2.min.js"></script> <!--全局动态修改--> <script src="javaex/pc/js/common.js"></script> <!--核心组件--> <script src="javaex/pc/js/javaex.min.js"></script> <!--表单验证--> <script src="javaex/pc/js/javaex-formVerify.js"></script> <title>星云图书馆后台管理</title> <style> </style> </head> <body> <!--顶部导航--> <div class="admin-navbar"> <div class="admin-container-fluid clear"> <!--logo名称--> <div class="admin-logo">星云图书管理系统</div> <!--右侧--> <ul class="admin-navbar-nav fr"> <li> <a href="javascript:;">欢迎您,<span id="nickname"> <c:if test="${not empty loginUser}"> ${loginUser.nickname} </c:if> </span></a> <ul class="dropdown-menu" style="right: 10px;"> <li><a href="${pageContext.request.contextPath}/login?method=loginOut">退出当前账号</a></li> </ul> </li> </ul> </div> </div> <!--主题内容--> <div class="admin-mian"> <!--左侧菜单--> <div class="admin-aside admin-aside-fixed"> <!-- 应用标题 --> <div id="admin-toc" class="admin-toc"> <div class="menu-box"> <div id="menu" class="menu"> <ul> <li class="menu-item hover"> <a href="javascript:page('${pageContext.request.contextPath}/welcome.jsp');"><i class="icon-home2"></i>首页</a> </li> <li class="menu-item"> <a href="javascript:;">图书管理<i class="icon-keyboard_arrow_left"></i></a> <ul> <li><a href="javascript:page('${pageContext.request.contextPath}/book/book-list.jsp');">图书列表</a></li> <li><a href="javascript:page('${pageContext.request.contextPath}/book/book-add.jsp');">图书上架</a></li> </ul> </li> <li class="menu-item"> <a href="javascript:;">借阅管理<i class="icon-keyboard_arrow_left"></i></a> <ul> <li><a href="javascript:page('${pageContext.request.contextPath}/borrow/book-search.jsp');">搜索图书</a></li> <li><a href="javascript:page('${pageContext.request.contextPath}/borrow/borrow.jsp');">借阅图书</a></li> <li><a href="javascript:page('${pageContext.request.contextPath}/borrow/back.jsp');">归还图书</a></li> </ul> </li> <li class="menu-item"> <a href="javascript:;">读者管理<i class="icon-keyboard_arrow_left"></i></a> <ul> <li><a href="javascript:page('${pageContext.request.contextPath}/reader/reader-list.jsp');">读者列表</a></li> <li><a href="javascript:page('${pageContext.request.contextPath}/reader/reader-add.jsp');">读者添加</a></li> </ul> </li> <li class="menu-item"> <a href="javascript:;">用户中心<i class="icon-keyboard_arrow_left"></i></a> <ul> <li><a href="javascript:page('user/user-info.html');">个人信息</a></li> <li><a href="javascript:page('user/user-list.html');">用户管理</a></li> <li><a href="javascript:page('user/user-add.html');">添加管理员</a></li> </ul> </li> </ul> </div> </div> </div> </div> <!--iframe载入内容--> <div class="admin-markdown"> <iframe id="page" src="${pageContext.request.contextPath}/welcome.jsp" ></iframe> </div> </div> </body> <script> var hightUrl = "xxxx"; javaex.menu({ id : "menu", isAutoSelected : true, key : "", url : hightUrl }); $(function() { // 设置左侧菜单高度 setMenuHeight(); }); /** * 设置左侧菜单高度 */ function setMenuHeight() { var height = document.documentElement.clientHeight - $("#admin-toc").offset().top; height = height - 10; $("#admin-toc").css("height", height+"px"); } // 控制页面载入 function page(url) { $("#page").attr("src", url); } $(document).ready(function(){ // 页面一加载, 读取登录用户信息 // get读取参数 // $.get("/user/currUser", function(data){ // var code = data.code; // var user = data.data; // if (code == 200) { // // 设置用户昵称 // $("#nickname").text(user.nickname); // } // // return false; // }); }); </script> </html> 此代码中出现Cannot resolve taglib with uri http://java.sun.com/jsp/jstl/core Cannot resolve symbol 'c:if' Cannot resolve symbol 'c:if'这些错误,如何改正这些错误
06-20
(一)项目构建 使用 Maven 构建项目,在pom.xml中引入 Spring MVC 相关依赖,如spring - webmvc,配置 ServletJSP 等相关依赖,确保项目具备 Spring MVC 运行环境 。示例关键依赖配置: <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring - webmvc</artifactId> <version>5.3.18</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet - api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp - api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <!-- 其他如JSTL等依赖按需添加 --> </dependencies> (二)Spring MVC 配置 DispatcherServlet 配置:在 Web.xml(或 Servlet 3.0 + 环境下用 Java 配置)中配置 DispatcherServlet,指定 Spring MVC 配置文件位置,使其能拦截处理请求 。示例 Web.xml 配置: <servlet> <servlet - name>springmvc</servlet - name> <servlet - class>org.springframework.web.servlet.DispatcherServlet</servlet - class> <init - param> <param - name>contextConfigLocation</param - name> <param - value>classpath:springmvc - servlet.xml</param - value> </init - param> <load - on - startup>1</load - on - startup> </servlet> <servlet - mapping> <servlet - name>springmvc</servlet - name> <url - pattern>/</url - pattern> </servlet - mapping> Spring MVC 配置文件(springmvc - servlet.xml):开启组件扫描(扫描控制器等组件)、视图解析器(配置前缀后缀,解析 JSP 视图)、开启注解驱动等 。示例: <context:component - scan base - package="com.example.controller"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB - INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation - driven/> 三)功能模块实现 1. 用户登录验证 o 控制器(Controller):创建LoginController,编写方法处理/login请求(对应login.jsp表单提交),接收用户名、密码参数(可通过@RequestParam注解),进行简单验证(如硬编码用户名 “admin”、密码 “123” 模拟,实际可连数据库查询),验证成功用return "redirect:/main";重定向到主页控制器方法,失败则带错误信息(通过model.addAttribute)返回login视图(即login.jsp )。示例代码: package com.example.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class LoginController { @RequestMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { if ("admin".equals(username) && "123".equals(password)) { return "redirect:/main"; } else { model.addAttribute("error", "用户名或密码错误"); return "login"; } } 2. 登录页面(login.jsp):使用 Spring 表单标签库(需引入相关标签库)或普通 HTML 表单,提交到/login,显示错误信息(通过 EL 表达式${error} )。示例关键代码: <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %> <html> <body> <form:form action="/login" method="post"> 用户名:<form:input path="username"/><br> 密码:<form:password path="password"/><br> <input type="submit" value="登录"> </form:form> <c:if test="${not empty error}"> <p style="color:red">${error}</p> </c:if> </body> </html> 3. 访问控制(拦截器实现) o 创建拦截器类:实现HandlerInterceptor接口,在preHandle方法中检查会话是否有用户登录标识(如session.getAttribute("user") ,假设登录成功时在会话存user对象),无则redirect到/login并返回false拦截,有则返回true放行 。示例: package com.example.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("user"); if (user == null) { response.sendRedirect(request.getContextPath() + "/login"); return false; } return true; } } 4. 配置拦截器:在 Spring MVC 配置文件(springmvc - servlet.xml)中注册拦截器,指定拦截路径(如/main )。示例: <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/main"/> <bean class="com.example.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> 5. 会话管理(登出功能) o 控制器方法:在MainController中编写处理登出的方法,调用session.invalidate()销毁会话,然后redirect到登录页 。示例: package com.example.controller; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class MainController { @RequestMapping("/main") public String main() { return "main"; } @RequestMapping("/logout") public String logout(HttpSession session) { session.invalidate(); return "redirect:/login"; } } 6. 主页(main.jsp):添加 “退出” 链接, href 指向/logout 。示例: <html> <body> <h1>欢迎访问主页</h1> <a href="${pageContext.request.contextPath}/logout">退出</a> </body> </html>
06-05
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 明确指定只扫描Controller --> <context:component-scan base-package="com.itheihei" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:resources mapping="/js/**" location="/js/"/> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:annotation-driven/> </beans><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 排除Controller,只扫描Service/Repository等 --> <context:component-scan base-package="com.itheihei"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>@Controller public class AccountController { @Autowired AccountService accountService; @RequestMapping("findAllAccounts") public String findAllAccounts() { System.out.println("方法成功执行"); return "list"; } } <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首页</title> </head> <body> <a href="${pageContext.request.contextPath}/findAllAccounts">查看所有用户信息</a> </body> </html><?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> <!-- 将所有请求映射到 dispatcherServlet --> </servlet-mapping> </web-app>为什么会404
05-14
<think>好的,我现在需要解决用户在Spring MVC配置中遇到的404错误问题,用户提到了context:component-scan、viewResolver和mvc:annotation-driven这几个配置点。首先,我得回忆一下这些组件的作用以及它们如何影响Spring MVC的运行。 首先,用户提到的404错误通常是因为请求无法映射到对应的控制器方法,或者视图解析失败。根据之前的回答,视图解析失败可能和viewResolver的配置有关,比如前缀后缀是否正确,或者模板位置是否对。但用户现在更关注的是配置问题,特别是组件扫描和注解驱动的配置,所以需要结合用户提供的引用内容来分析。 引用[1]和[3]提到,mvc:annotation-driven标签由AnnotationDrivenBeanDefinitionParser处理,它会注册处理@RequestMapping的处理器映射和适配器,如RequestMappingHandlerMapping和RequestMappingHandlerAdapter。如果缺少这个配置,Spring MVC可能无法识别控制器中的注解,导致请求无法被正确路由,从而出现404错误。引用[2]也指出,当同时使用mvc:default-servlet-handler和mvc:annotation-driven时,需要确保两者都正确配置,否则可能导致处理器无法注册。此外,引用[4]列出了多个HandlerMapping和HandlerAdapter的实现,说明不同的配置会影响这些组件的注册。 接下来是context:component-scan,它用于扫描指定包下的组件,包括@Controller注解的类。如果包路径配置错误,Spring可能无法检测到控制器,导致请求无法处理。需要检查base-package是否正确,是否覆盖了所有控制器所在的包。 viewResolver的配置问题可能导致视图名称无法正确解析为实际视图文件,比如JSP或Thymeleaf模板。例如,InternalResourceViewResolver的前缀和后缀是否正确,或者Thymeleaf的配置是否完整。如果视图解析器没有正确配置,即使控制器返回了正确的视图名称,系统也无法找到对应的视图文件,进而导致404错误。 此外,用户可能没有正确配置mvc:annotation-driven,导致缺少必要的HandlerMapping和HandlerAdapter。例如,如果没有启用注解驱动,即使有@Controller注解,Spring MVC也无法处理@RequestMapping等注解,从而导致请求无法映射到控制器方法。 现在需要综合这些信息,给出具体的配置检查和解决方案。比如,检查组件扫描的包路径是否正确,确保mvc:annotation-driven已启用,并正确配置视图解析器的前缀和后缀。同时,可能需要检查依赖是否完整,比如是否缺少Spring MVC或模板引擎的相关库。 另外,用户可能在配置多个视图解析器时没有正确设置order属性,导致解析顺序混乱。或者静态资源处理配置不当,导致请求被错误地拦截,无法到达控制器。例如,如果静态资源处理配置为拦截所有请求,而控制器路径没有被正确排除,也会导致404错误。 还需要考虑是否在web.xml中正确配置了DispatcherServlet,并指定了正确的上下文配置位置。如果DispatcherServlet的映射路径有误,比如配置为“/”但其他静态资源未正确处理,也可能导致问题。 最后,建议用户查看日志,确认是否有相关的错误信息,比如未找到处理器映射或视图解析失败的具体原因,这有助于更快定位问题。</think>### Spring MVC 404错误配置问题解析 #### 核心配置关联分析 以下三个配置项的协同作用是Spring MVC正常工作的关键: 1. **`<context:component-scan>`**:控制器扫描注册 2. **`<mvc:annotation-driven>`**:注解处理器激活 3. **视图解析器**:模板路径映射 #### 1. 组件扫描配置问题 **错误表现**:控制器类未被Spring容器管理,导致请求无匹配处理器 ```xml <!-- 错误示例:包路径未覆盖控制器所在位置 --> <context:component-scan base-package="com.example.dao"/> <!-- 正确配置 --> <context:component-scan base-package="com.example.controller"/> ``` - **验证方法**:启动时查看日志中的`Mapped "{路径}" onto ...`信息[^4] - **典型错误**:多层包结构未使用通配符,例如`base-package="com.example"`可扫描所有子包 #### 2. 注解驱动缺失 **错误表现**:即使有`@Controller`注解,也无法处理请求 ```xml <!-- 必须配置注解驱动才能启用@RequestMapping等注解 --> <mvc:annotation-driven/> ``` - **底层机制**:该配置会注册`RequestMappingHandlerMapping`和`RequestMappingHandlerAdapter`[^1][^4] - **依赖影响**:若同时使用`<mvc:default-servlet-handler>`,必须注解驱动共存[^2] #### 3. 视图解析器配置要点 **JSP标准配置示例**: ```xml <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> ``` **Thymeleaf配置示例**: ```java @Bean public SpringResourceTemplateResolver templateResolver() { SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver(); resolver.setPrefix("classpath:/templates/"); resolver.setSuffix(".html"); return resolver; } ``` - **路径验证**:`prefix + 视图名 + suffix`应指向实际文件路径 - **优先级问题**:多视图解析器需设置`order`属性 #### 4. 综合配置检查清单 | 检查项 | 验证方法 | 相关引用 | |-----------------------|---------------------------------|----------| | 控制器包路径覆盖 | 查看`@Controller`类是否在扫描范围内 | [^3] | | 注解驱动生效状态 | 检查是否注册`RequestMappingHandlerAdapter` | [^1][^4] | | 视图路径拼接结果 | 手动拼接`前缀+视图名+后缀`验证文件是否存在 | [^2] | | 静态资源冲突 | 测试直接访问JSP文件是否正常 | [^2] | #### 5. 典型错误场景 **场景一**:缺少`<mvc:annotation-driven>` ```log WARN o.s.web.servlet.PageNotFound - No mapping for GET /user/list ``` **解决方法**:添加注解驱动配置[^1] **场景二**:视图解析器后缀缺失 ```java @Controller public class UserController { @RequestMapping("/profile") public String showProfile() { return "user/profile"; // 实际需要user/profile.jsp } } ``` **解决方法**:检查视图解析器的`suffix`属性配置 --- ### 相关问题 1. 如何验证`<mvc:annotation-driven>`是否生效? 2. 组件扫描注解驱动的加载顺序有何影响? 3. 多个视图解析器共存时如何确定优先级?
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值