这里使用5.3.8版本Spring框架。基于Servlet API,必须引入servlet-api依赖。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.black</groupId> <artifactId>spring-springmvc-xml</artifactId> <packaging> war</packaging> <version>0.0.1-SNAPSHOT</version> <name>spring-springmvc-xml Maven Webapp</name> <url>http://maven.apache.org</url> <!-- 定义Spring版本 --> <properties> <spring.verson>5.3.8</spring.verson> </properties> <dependencies> <!-- 引入 Spring Framework jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.verson}</version> </dependency> <!-- 引入 Spring MVC jar包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.verson}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.verson}</version> </dependency> <!-- 引入 servlet-api (不希望打到war包中,有可能tomcat容器就已经带有这个包了)--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!-- 日志 jar --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jcl</artifactId> <version>${spring.verson}</version> </dependency> <!-- 日志:slf4j + logback --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.31</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> <scope>compile</scope> </dependency> </dependencies> <build> <finalName>spring-springmvc-xml</finalName> </build> </project>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <!-- 指定 Root WebApplicationContext xml配置文件 --> <!-- 如果不配置 contextConfigLocation这个属性,那么,自动会去加载 WEB-INF/applicationContext.xml 如果没有则报异常--> <!-- 如果不需要 WebApplicationContext 继承关系则, contextConfigLocation 的 value 设置为 空 --> <!-- (一般上不用WebApplicationContext继承关系) --> <!-- context-param 更详实说明看 【11.1 web.xml context-param说明】--> <context-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </context-param> <!-- 1、定义上下文监听 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 2、定义 dispatcherServlet--> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 如果不配置 contextConfigLocation 则默认加载 WEB-INF/${servlet-name}-servlet.xml--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-context.xml</param-value> </init-param> <!-- web应用一启动就初始化这个servlet --> <load-on-startup>1</load-on-startup> </servlet> <!-- 3、定义 dispatcherServlet--> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <!-- 注意:dispatcherServlet必须是“/”, 不能是“/*”; --> <!-- 如果是“/*”,那么当返回modelAndView是个jsp时,它会继续走这个servlet去找“/WEB-INF/.../*.jsp”对应的controller --> <url-pattern>/</url-pattern> </servlet-mapping> <display-name>spring-web-application</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
位置:/src/main/resource/spring-context.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 定义 handlerMapping(根据url 查找 Controller) --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!-- 定义视图解析器(根据视图名解析为对应的jsp) --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"></property> <property name="suffix" value=".jsp"></property> </bean> <!-- 定义controller --> <bean id="/welcome" class="com.black.app.controller.WelcomeController" /> </beans>
位置:/src/main/resource/logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" > <!--0. 日志格式 --> <property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5p] [%-10.15t] %20.30logger{30}.%M[line:%L]: %m%n}"/> <!-- 时间戳 --> <timestamp key="file_name_date" datePattern="yyyyMMdd"/> <!--1. 记录日志到文件--> <appender name="LogFile" class="ch.qos.logback.core.FileAppender"> <!-- 日志文件名 --> <file>${file_name_date}/log-info-${file_name_date}.log</file> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <!-- 设置字符集 --> <charset>UTF-8</charset> </encoder> </appender> <!--1. 输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <!-- 设置字符集 --> <charset>UTF-8</charset> </encoder> </appender> <root> <appender-ref ref="LogFile" /> <appender-ref ref="CONSOLE" /> </root> </configuration>
package com.black.app.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; public class WelcomeController implements Controller { private static Logger logger = LoggerFactory.getLogger(WelcomeController.class); public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.info("WelcomeController#handleRequest 开始处理..."); //获取请求参数-姓名 String name = request.getParameter("name"); //如果在windows乱码则进行转码 name = new String(name.getBytes("ISO8859-1"),"UTF-8"); logger.info("WelcomeController#handleRequest 请求参数:." + name); ModelAndView view = new ModelAndView(); view.addObject("name", name); //返回 welcome.jsp view.setViewName("welcome"); logger.info("WelcomeController#handleRequest 处理结束。"); return view; } }
位置:/src/main/webapp/WEB-INF/welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <body> <h2>欢迎【<%= request.getAttribute("name")%>】同学,来到我的 spring-springmvc-xml web应用</h2> </body> </html>
maven compile package
war包路径:spring-springmvc-xml\target\spring-springmvc-xml.war
将spring-springmvc-xml.war部署 apache-tomcat 下。
(1)将 spring-springmvc-xml.war 拷贝到 apache-tomcat-7.0.91\webapps\
(2)编写 apache-tomcat-7.0.91\conf\server.xml
<!-- 设置8180端口 --> <Connector port="8180" protocol="HTTP/1.1" connectionTimeout="20000" edirectPort="9000" /> ... <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- 增加 context标签 --> <Context docBase="spring-springmvc-xml" path="/" reloadable="true"/> </Host> ...
(3)启动 apache-tomcat
apache-tomcat-7.0.91\bin\startup.bat
如果闪退,记得将安装目录添加到配置环境变量CATALINA_HOME=E:\work\software\apache-tomcat-7.0.91 :
(4)启动后控制台打印:
(5)启动后,war包被解压,应用放在webapps/spring-springmvc-xml 下:
(1)访问首页:http://localhost:8180/spring-springmvc-xml/
(2)访问欢迎页:http://localhost:8180/spring-springmvc-xml/welcome?name=小明
http://localhost:8180/spring-springmvc-xml/welcome?name=小红
context-param 里的 contextConfigLocation 和 init-param 的contextConfigLocation有什么区别?
(1)context-param 里的配置参数是所有的 servlet 实例共享的。
(2)context-param 里的contextConfigLocation 是 Root WebApplicationContext,是可以被很多 DispatcherServlet 实例继承的; init-param 的contextConfigLocation 是 WebApplicationContext ,只能当前 DispatcherServlet 实例拥有的配置,与其他 servlet(不仅仅是DispatcherServlet实例) 不共享。
(3)如果不需要 WebApplicationContext 的继承关系,则 context-param 里的contextConfigLocation 配置是:
<context-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </context-param>
如果需要 WebApplicationContext 的继承,则 context-param 里的contextConfigLocation 配置是:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
如果需要继承 Root WebApplicationContext 的,则 init-param 里的contextConfigLocation 配置是:
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-context.xml</param-value> </init-param>
Spring 官方文档中的继承关系:
对应 web.xml 示例:
<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/root-context.xml</param-value> </context-param> <servlet> <servlet-name>app1</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app1-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app1</servlet-name> <url-pattern>/app1/*</url-pattern> </servlet-mapping> </web-app>
(4) 如果context-param 不配置 contextConfigLocation 参数, 那么默认会加载 /WEB-INF/applicationContext.xml 文件;
如果文件不存在,则会报错:
2021-07-19 00:42:41.802 [INFO ] [ost-startStop-1] o.s.web.context.ContextLoader.initWebApplicationContext[line:271]: Root WebApplicationContext: initialization started 2021-07-19 00:42:42.081 [DEBUG] [ost-startStop-1] w.c.s.XmlWebApplicationContext.prepareRefresh[line:629]: Refreshing Root WebApplicationContext 2021-07-19 00:42:42.225 [ERROR] [ost-startStop-1] o.s.web.context.ContextLoader.initWebApplicationContext[line:313]: Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/applicationContext.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:224) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:195) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:671) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:401) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:292) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5157) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5680) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1018) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:994) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1127) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:2021) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml] at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:159) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ... 25 common frames omitted
(5) 如果 dispatcherServlet init-param 不配置 contextConfigLocation 参数,会自动去加载 “/WEB-INF/${servletname}-servlet.xml” 即/WEB-INF/dispatcherServlet-servlet.xml ;如果文件不存在 那么会报错:
2021-07-19 00:39:47.019 [DEBUG] [ost-startStop-1] w.c.s.XmlWebApplicationContext.prepareRefresh[line:629]: Refreshing WebApplicationContext for namespace 'dispatcherServlet-servlet' 2021-07-19 00:39:47.031 [ERROR] [ost-startStop-1] o.s.w.s.DispatcherServlet.initServletBean[line:534]: Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from ServletContext resource [/WEB-INF/dispatcherServlet-servlet.xml]; nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcherServlet-servlet.xml] at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:188) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:224) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:195) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:671) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:702) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:668) at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:716) at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:591) at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:530) at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:170) at javax.servlet.GenericServlet.init(GenericServlet.java:158) at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1230) at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1174) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1066) at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5409) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5707) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1018) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:994) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1127) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:2021) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/dispatcherServlet-servlet.xml] at org.springframework.web.context.support.ServletContextResource.getInputStream(ServletContextResource.java:159) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ... 32 common frames omitted
Spring MVC 的9大组件
Bean type | 解释 |
---|---|
HandlerMapping | 映射一个请求到一个Handler(有一堆拦截器); 主要有两个实现:RequestMappingHandlerMapping(支持@RequestMapping注解)和 SimpleUrlHandlerMapping(URL 映射到 一个 Handler) |
HandlerAdapter | 帮助DispatcherServlet调用handler |
HandlerExceptionResolver | 解决异常的策略 |
ViewResolver | 根据逻辑视图名解析出真实的视图 |
LocaleResolver,LocaleContextResolver | 解析器 Locale,为了提供国际化视图 |
ThemeResolver | 解析应用能够使用的主题 |
MultipartResolver | 解析multi-part请求 |
FlashMapManager | 重定向时可以将一个请求的属性传给另一个请求 |