spring是目前最流行的框架。创建java web项目时,我们首先会遇到的配置文件就是web.xml,这是javaweb为我们封装的逻辑,不在今天的研究中。下面我们将简单讲讲web.xml中的配置。
一、一个空的web.xml
1
|
2
3
4
5
6
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< web-app version = "3.0" xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xmlns = " http://java.sun.com/xml/ns/javaee " xmlns:web = " http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd "
xsi:schemaLocation = " http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd "
id = "WebApp_ID" >
</ web-app >
|
二、标签介绍
web.xml中比较常见的标签以及其加载顺序为:
context-param > listener > filter > servlet
1、 <display-name>Archetype Created Web Application</display-name>
display-name 是标识项目的名称,这个不是很常用,可有可无的,或者说不需要我们去在意的东西。
2、 <context-param>
1
|
2
3
4
|
< context-param >
< param-name >webAppRootKey</ param-name >
< param-value >60000</ param-value >
</ context-param >
|
context-param 是web.xml首先加载的标签,其下子标签有param-name和param-value.
此所设定的参数,在JSP网页中可以使用下列方法来取得:
1
|
|
${initParam.webAppRootKey}
|
若在Servlet可以使用下列方法来获得:
String param_name=getServletContext().getInitParamter(“webAppRootKey”);
3、listener
1
|
2
3
|
< listener >
< listener-class >org.springframework.web.context.request.RequestContextListener</ listener-class >
</ listener >
|
listenter在项目开始的时候就注入进来,尽在context-param之后,所以正常我们将spring配置在listener 中,这样方法spring 初始化相关的bean。
4、filter
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
< filter >
< filter-name >CharacterEncodingFilter</ 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 >CharacterEncodingFilter</ filter-name >
< url-pattern >/*</ url-pattern >
</ filter-mapping >
|
filter起到一个过滤的作用,在servlet执行前后,像上面的配置就是在过滤servlet前将编码转换UTF-8,filter-mapping 则是将filter和url路径进行映射。其中init-param则是将初始化需要的参数传入到filter-class中从而进行初始化。filter和filter-mapping中的name必须是相同的,才能起到映射的作用,而filter-mapping 中的url-pattern则是匹配请求路径的。上面‘/*'表示过滤所有请求的servlet,如果写成‘/zxh',则过滤http://localhost:8080/项目名/zxh这个请求。
5、servlet
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
< servlet >
<!-- 配置DispatcherServlet -->
< servlet-name >springMvc</ servlet-name >
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
<!-- 指定spring mvc配置文件位置 不指定使用默认情况 -->
< init-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:spring/spring-mvc.xml</ param-value >
</ init-param >
<!-- 设置启动顺序 -->
< load-on-startup >1</ load-on-startup >
</ servlet >
<!-- ServLet 匹配映射 -->
< servlet-mapping >
< servlet-name >springMvc</ servlet-name >
< url-pattern >*.zxh</ url-pattern >
</ servlet-mapping >
|
servlet和filter类似,需要先指定servlet对应的class类,然后将这个类和utl路径请求地址进行映射。这里不多说了。
以上就是web.xml文件中出现最多的几个标签。其他的比如:
6、欢迎页
1
|
2
3
|
< welcome-file-list >
< welcome-file >login.jsp</ welcome-file >
</ welcome-file-list >
|
7、错误页
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<!-- 后台程序异常错误跳转页面 -->
< error-page >
< exception-type >java.lang.Throwable</ exception-type >
< location >/views/error.jsp</ location >
</ error-page >
<!-- 500跳转页面-->
< error-page >
< error-code >500</ error-code >
< location >/views/500.jsp</ location >
</ error-page >
<!-- 404跳转页面 -->
< error-page >
< error-code >404</ error-code >
< location >/views/404.jsp</ location >
</ error-page >
|
三、示例
1、spring 框架解决字符串编码问题:过滤器 CharacterEncodingFilter(filter-name)
2、在web.xml配置监听器ContextLoaderListener(listener-class)
ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
3、部署applicationContext的xml文件:contextConfigLocation(context-param下的param-name)
4、DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理。
DispatcherServlet(servlet-name、servlet-class、init-param、param-name(contextConfigLocation)、param-value)
在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
<? xml version = "1.0" encoding = "UTF-8" ?>
< web-app version = "3.0" xmlns = " http://java.sun.com/xml/ns/javaee "
xmlns:xsi = " http://www.w3.org/2001/XMLSchema-instance "
xsi:schemaLocation = " http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd " >
<!-- 在Spring框架中是如何解决从页面传来的字符串的编码问题的呢?
下面我们来看看Spring框架给我们提供过滤器CharacterEncodingFilter
这个过滤器就是针对于每次浏览器请求进行过滤的,然后再其之上添加了父类没有的功能即处理字符编码。
其中encoding用来设置编码格式,forceEncoding用来设置是否理会 request.getCharacterEncoding()方法,设置为true则强制覆盖之前的编码格式。-->
< filter >
< filter-name >characterEncodingFilter</ 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 >characterEncodingFilter</ filter-name >
< url-pattern >/*</ url-pattern >
</ filter-mapping >
<!-- 项目中使用Spring 时,applicationContext.xml配置文件中并没有BeanFactory,要想在业务层中的class 文件中直接引用Spring容器管理的bean可通过以下方式-->
<!--1、在web.xml配置监听器ContextLoaderListener-->
<!--ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。
它的API说明
第一段说明ContextLoader可以由 ContextLoaderListener和ContextLoaderServlet生成。
如果查看ContextLoaderServlet的API,可以看到它也关联了ContextLoader这个类而且它实现了HttpServlet这个接口
第二段,ContextLoader创建的是 XmlWebApplicationContext这样一个类,它实现的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext->
BeanFactory这样一来spring中的所有bean都由这个类来创建
IUploaddatafileManager uploadmanager = (IUploaddatafileManager) ContextLoaderListener.getCurrentWebApplicationContext().getBean("uploadManager");
-->
< listener >
< listener-class >org.springframework.web.context.ContextLoaderListener</ listener-class >
</ listener >
<!--2、部署applicationContext的xml文件-->
<!--如果在web.xml中不写任何参数配置信息,默认的路径是"/WEB-INF/applicationContext.xml,
在WEB-INF目录下创建的xml文件的名称必须是applicationContext.xml。
如果是要自定义文件名可以在web.xml里加入contextConfigLocation这个context参数:
在<param-value> </param-value>里指定相应的xml文件名,如果有多个xml文件,可以写在一起并以“,”号分隔。
也可以这样applicationContext-*.xml采用通配符,比如这那个目录下有applicationContext-ibatis-base.xml,
applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都会一同被载入。
在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。-->
< context-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:spring/applicationContext.xml</ param-value >
</ context-param >
<!--如果你的DispatcherServlet拦截"/",为了实现REST风格,拦截了所有的请求,那么同时对*.js,*.jpg等静态文件的访问也就被拦截了。-->
<!--方案一:激活Tomcat的defaultServlet来处理静态文件-->
<!--要写在DispatcherServlet的前面, 让 defaultServlet先拦截请求,这样请求就不会进入Spring了,我想性能是最好的吧。-->
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.css</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.swf</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.gif</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.jpg</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.png</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.js</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.html</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.xml</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.json</ url-pattern >
</ servlet-mapping >
< servlet-mapping >
< servlet-name >default</ servlet-name >
< url-pattern >*.map</ url-pattern >
</ servlet-mapping >
<!--使用Spring MVC,配置DispatcherServlet是第一步。DispatcherServlet是一个Servlet,,所以可以配置多个DispatcherServlet-->
<!--DispatcherServlet是前置控制器,配置在web.xml文件中的。拦截匹配的请求,Servlet拦截匹配规则要自已定义,把拦截下来的请求,依据某某规则分发到目标Controller(我们写的Action)来处理。-->
< servlet >
< servlet-name >DispatcherServlet</ servlet-name > <!--在DispatcherServlet的初始化过程中,框架会在web应用的 WEB-INF文件夹下寻找名为[servlet-name]-servlet.xml 的配置文件,生成文件中定义的bean。-->
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
<!--指明了配置文件的文件名,不使用默认配置文件名,而使用dispatcher-servlet.xml配置文件。-->
< init-param >
< param-name >contextConfigLocation</ param-name >
<!--其中<param-value>**.xml</param-value> 这里可以使用多种写法-->
<!--1、不写,使用默认值:/WEB-INF/<servlet-name>-servlet.xml-->
<!--2、<param-value>/WEB-INF/classes/dispatcher-servlet.xml</param-value>-->
<!--3、<param-value>classpath*:dispatcher-servlet.xml</param-value>-->
<!--4、多个值用逗号分隔-->
< param-value >classpath:spring/dispatcher-servlet.xml</ param-value >
</ init-param >
< load-on-startup >1</ load-on-startup > <!--是启动顺序,让这个Servlet随Servletp容器一起启动。-->
</ servlet >
< servlet-mapping >
<!--这个Servlet的名字是dispatcher,可以有多个DispatcherServlet,是通过名字来区分的。每一个DispatcherServlet有自己的WebApplicationContext上下文对象。同时保存的ServletContext中和Request对象中.-->
<!--ApplicationContext是Spring的核心,Context我们通常解释为上下文环境,我想用“容器”来表述它更容易理解一些,ApplicationContext则是“应用的容器”了:P,Spring把Bean放在这个容器中,在需要的时候,用getBean方法取出-->
< servlet-name >DispatcherServlet</ servlet-name >
<!--Servlet拦截匹配规则可以自已定义,当映射为@RequestMapping("/user/add")时,为例,拦截哪种URL合适?-->
<!--1、拦截*.do、*.htm, 例如:/user/add.do,这是最传统的方式,最简单也最实用。不会导致静态文件(jpg,js,css)被拦截。-->
<!--2、拦截/,例如:/user/add,可以实现现在很流行的REST风格。很多互联网类型的应用很喜欢这种风格的URL。弊端:会导致静态文件(jpg,js,css)被拦截后不能正常显示。 -->
< url-pattern >/</ url-pattern > <!--会拦截URL中带“/”的请求。-->
</ servlet-mapping >
< welcome-file-list > <!--指定欢迎页面-->
< welcome-file >login.html</ welcome-file >
</ welcome-file-list >
< error-page > <!--当系统出现404错误,跳转到页面nopage.html-->
< error-code >404</ error-code >
< location >/nopage.html</ location >
</ error-page >
< error-page > <!--当系统出现java.lang.NullPointerException,跳转到页面error.html-->
< exception-type >java.lang.NullPointerException</ exception-type >
< location >/error.html</ location >
</ error-page >
< session-config > <!--会话超时配置,单位分钟-->
< session-timeout >360</ session-timeout >
</ session-config >
</ web-app >
|
四、spring加载
通过上面的了解,我们可以看出spring核心配置文件就是listener那块。在监听之前我们已经通过context-param将spring配置文件传到上下文中了(application)。下面我们就来看看spring是如何工作的吧
第一步:
点开listener源码,我们发现他有下面几个方法。和继承的关系。我们发现他实现了ContextLoaderListener这个接口,这个接口在参数设置好之后自动执行contextInitialized方法的。
那么我们来看看contextInitialized方法
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null ) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!" );
}
Log logger = LogFactory.getLog(ContextLoader. class );
servletContext.log( "Initializing Spring root WebApplicationContext" );
if (logger.isInfoEnabled()) {
logger.info( "Root WebApplicationContext: initialization started" );
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if ( this .context == null ) {
this .context = createWebApplicationContext(servletContext);
}
if ( this .context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this .context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null ) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this .context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader. class .getClassLoader()) {
currentContext = this .context;
}
else if (ccl != null ) {
currentContextPerThread.put(ccl, this .context);
}
if (logger.isDebugEnabled()) {
logger.debug( "Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]" );
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info( "Root WebApplicationContext: initialization completed in " + elapsedTime + " ms" );
}
return this .context;
}
catch (RuntimeException ex) {
logger.error( "Context initialization failed" , ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error( "Context initialization failed" , err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
|
仔细研究官方解释,就是在这里初始化application,这里会用到contextClass+contextConfigLocation两个参数,如果contextClass在context-param提供了,我们就会根据这一个class去初始化application,很显然我们正常配置都没有配这个,而是配置了后者,配置了后者就会去根据contextConfigLocation中提供的配置文件去解析然后创建相关的bean和application操作,这个方法的最后会执行configureAndRefreshWebApplicationContext方法。这个方法就是在根据contextConfigLocation提供的配置文件中创建相关的bean。
五、springMVC 加载
springMVC其实和spring是一样的,但是他不用再程序开始时访问
1
|
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
< servlet >
<!-- 配置DispatcherServlet -->
< servlet-name >springMvc</ servlet-name >
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class >
<!-- 指定spring mvc配置文件位置 不指定使用默认情况 -->
< init-param >
< param-name >contextConfigLocation</ param-name >
< param-value >classpath:spring/spring-mvc.xml</ param-value >
</ init-param >
<!-- 设置启动顺序 -->
< load-on-startup >1</ load-on-startup >
</ servlet >
<!-- ServLet 匹配映射 -->
< servlet-mapping >
< servlet-name >springMvc</ servlet-name >
< url-pattern >*.zxh</ url-pattern >
</ servlet-mapping >
|
看DispatcherServlet源码中对contextConfigLocation参数的解释
上面明确指出我们这个参数给XmlWebApplicationContext类的,我们在进入XmlWebApplicationContext类看看究竟。
这样我们很容易理解为什么springmvc默认的配置文件会在WEB-INF/application.xml中的吧。
在dispatcherservlet中有一个初始化方法,这里就初始化配置中一些东西,比如说文件上传适配器的配置等等。
1
|
2
3
4
5
6
7
8
9
10
11
|
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
|
总结
spring+springmvc在配置中主要就是上面的两个配置,当然spring的强大不是我们一两天能够研究来的,我上面只是简单的研究讨论了一下。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://blog.csdn.net/liuqz2009/article/details/72833678