您的位置:首页 > 其它

成绩查询系统--框架篇--配置文件--web.xml

2015-06-17 21:55 351 查看
       上篇文章中,准备好了jar包,接下来就是写配置文件了.(说明一下,使用的IDE是eclipse,而建立的项目是动态web项目).其实不一定要准备好所有的jar,才开始写配置文件,如准备好hibernate的jar之后,就可以写hibernate的配置文件,并写测试代码,测试hibernate是否可用了.

       这配置文件共4个,分别是,web.xml,spring-mvc.xml以及applicationContext.xml,hibernate.cfg.xml.一般是放在项目的WEB-INF文件中,比较安全.其中,web.xml中配置一些监听器和过滤器,在tomcat启动时,读取web.xml,再根据配置在web.xml的配置,去读取spring-mvc.xml,applicationContext.xml.

       而applicationContext.xml是spring的配置文件,用来配置sessionFactory以及事务,这里用的是声明式事务.还有spring-mvc.xml配置的spring-mvc的,主要配置视图解析器,还有扫描包,设置注解驱动,以及配置解除mvc对资源的拦截.





       现在依次介绍4个xml文件.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
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_2_5.xsd"> 
<!-- 上下文初始化参数,找到spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- 找到spring-mvc的配置文件和spring的配置文件 -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml,/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!-- 配置编码过滤器,防止乱码 -->
<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>

</web-app>


 
     该配置文件,从上到下,依次配置了4个点,context-param上下文参数节点,listener监听器节点,servlet节点,和filter过滤节点.从比较简单的开始介绍.

1.filter过滤器节点

<!-- 配置编码过滤器,防止乱码 -->
<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过滤器节点,在这里是配置了一个编码的过滤器,将所有的(/*)的POST请求都拦截下来,强制设置为utf-8的编码,防止编码不一致的乱码,不过只对post请求起作用. 而这个编码的类,是spring-web自己就提供的一个类.


 
  

 
     反编译出来的代码,我给添加了注释.看了源码之后,就更加明白,为什么要那么配置characterEncodingFilter了.

package org.springframework.web.filter;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CharacterEncodingFilter extends OncePerRequestFilter
{
//属性,接收编码和是否强制编码
private String encoding;
private boolean forceEncoding = false;

//设置编码
public void setEncoding(String encoding)
{
this.encoding = encoding;
}

//设置强制编码
public void setForceEncoding(boolean forceEncoding)
{
this.forceEncoding = forceEncoding;
}

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
//只要请求中设置了编码,或者只要设置了编码,并且强制编码为ture,就执行下面的
if ((this.encoding != null) && ((this.forceEncoding) || (request.getCharacterEncoding() == null))) {
//请求就设置编码
request.setCharacterEncoding(this.encoding);
//如果是强制编码
if (this.forceEncoding) {
//则响应也设置编码
response.setCharacterEncoding(this.encoding);
}
}
//到过滤器链的下一个过滤器
filterChain.doFilter(request, response);
}
}

2.listener

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


       监听器节点也是用的spring-web中的一个类



       反编译出来是这样的效果,本类中的代码,很少,基本上都是去调用父类中的方法. 
       

package org.springframework.web.context;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

//ContextLoaderListener监听器,继承ContextLoader,实现了ServletContextListener的两个接口
//contextInitialized和contextDestroyed
public class ContextLoaderListener extends ContextLoader
implements ServletContextListener
{
//构造方式
public ContextLoaderListener()
{
}

//带参数的构造方法,传递参数WebApplicationContext,web应用的上下文
public ContextLoaderListener(WebApplicationContext context)
{
super(context);
}

//上下文初始化
public void contextInitialized(ServletContextEvent event)
{
//调用父类的initWebApplicationContext,初始化web应用上下文方法
initWebApplicationContext(event.getServletContext());
}

//销毁上下文
public void contextDestroyed(ServletContextEvent event)
{
//调用父类的关闭wen应用上下文
closeWebApplicationContext(event.getServletContext());
//以及另一个监听器的清除属性的方法
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
       但是从代码中还是可以看出,主要功能就是接收到web应用中的上下文,将其初始化,或者销毁.而WebApplicationContext ,则是context-param中配置的,所以context-param和listener节点应该是配合使用的.

       下面是我从网上找到的,可能更方便理解.

    Web.xml配置详解之context-param
    context-param的作用是声明应用范围内的上下文初始化参数,范围是整个WEB项目。
初始化过程介绍:
        1.在启动Web项目时,容器(比如Tomcat)会读web.xml配置文件中的两个节点<listener>和<contex-param>。
        2.接着容器会创建一个ServletContext(上下文),应用范围内即整个WEB项目都能使用这个上下文。
        3.接着容器会将读取到<context-param>转化为键值对,并交给ServletContext。
        4.容器创建<listener></listener>中的类实例,即创建监听(备注:listener定义的类可以是自定义的类但必须需要继承ServletContextListener)。
        5.在监听的类中会有一个contextInitialized(ServletContextEvent event)初始化方法,在这个方法中可以通过event.getServletContext().getInitParameter("contextConfigLocation")来得到context-param
设定的值。在这个类中还必须有一个contextDestroyed(ServletContextEvent event)销毁方法.用于关闭应用前释放资源,比如说数据库连接的关闭。
        6.得到这个context-param的值之后,你就可以做一些操作了.注意,这个时候你的WEB项目还没有完全启动完成.这个动作会比所有的Servlet都要早。
        7.由上面的初始化过程可知容器对于web.xml的加载过程是context-param>> listener  >> fileter  >> servlet.

3.context-param节点

<!-- 上下文初始化参数,找到spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

       所以根据上面的说法,这个上下文参数的配置的作用,就是将参数名为contextConfigLocation的,参数值为/WEB-INF/applicationContext.xml初始化到上下文参数中,并且该参数的作用范围为整个应用程序.

        那段初始化的代码,是这样子的。

public class ContextLoader
{                                                                                                       //感觉父类中没用上
public static final String CONTEXT_ID_PARAM = "contextId";
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
public static final String LOCATOR_FACTORY_KEY_PARAM = "parentContextKey";
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
private static final Properties defaultStrategies;                                                    //这个是map
private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread = new ConcurrentHashMap(1);                                                                                            //这个是多线程时的web应用上下文,具体不懂
private static volatile WebApplicationContext currentContext;                                         //initWebApplicationContext方法,就是在给这个属性,赋值;
private WebApplicationContext context;
private BeanFactoryReference parentContextRef;

public ContextLoader()
{
}

public ContextLoader(WebApplicationContext context)
{
this.context = context;
}

//初始化web应用上下文,根据servlet上下文
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
{
//如果上下文中"根web应用上下文属性"不为空,则抛错
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();

//作用,给context(web应用上下文)赋上值
try
{
//如果web应用上下文属性为空,就创建一个web应用上下文
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
//如果是可配置的web应用上下文类型的
if ((this.context instanceof ConfigurableWebApplicationContext)) {
//就强转成可配置的web应用上下文类型
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
//判断若不是活动状态的
if (!cwac.isActive())
{
//并且可配置的web应用上下文的parent属性是空的
if (cwac.getParent() == null)
{
//加载父上下文,应用上下文
ApplicationContext parent = loadParentContext(servletContext);
//并且给可配置的web应用上下文的parent属性赋上值
cwac.setParent(parent);
}
//然后配置并且刷新一下web应用上下文,根据可配置的web应用上下文和servlet上下文
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}

//给servlet上下文的"根web应用上下文属性"设置值,值就是context
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

//从当前线程中获取类加载器
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
//若该类加载和上下文加载器的类加载器是一样的
if (ccl == ContextLoader.class.getClassLoader()) {
//就将web应用上下文,给当前上下文
currentContext = this.context;
}
//若当前线程中,没有类加载器,
else if (ccl != null) {
//则将类加载器和web应用上下文,作为key,value放到当前上下文之前的线程的map中
currentContextPerThread.put(ccl, this.context);
}

//记录bug级别的日志
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}

//记录info级别的日志,并记录时间
if (logger.isInfoEnabled()k) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}

//该初始化的方法,最后会返回准备好的web应用上下文context
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;
}
}

//配置并刷新web应用上下文
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId()))
{
//获取servlet上下文中的初始化参数contextId
String idParam = sc.getInitParameter("contextId");
//不为null的话,这就是可配置的web应用上下文对象的id了
if (idParam != null) {
wac.setId(idParam);
}
else
{
//否则,就用路径来做id
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc
.getContextPath()));
}
}

//设置可配置的web应用上下文对象的servletContext
wac.setServletContext(sc);
//获取servlet上下文中的初始化参数contextConfigLocation,这个就是xml中配置的
String configLocationParam = sc.getInitParameter("contextConfigLocation");
//有值的话,这就是可配置的web应用上下文对象的ConfigLocation了
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}

//获取可配置环境
ConfigurableEnvironment env = wac.getEnvironment();
//初始化属性资源
if ((env instanceof ConfigurableWebEnvironment)) {
((ConfigurableWebEnvironment)env).initPropertySources(sc, null);
}

customizeContext(sc, wac);
//可配置的web应用上下文对象,刷新一下
wac.refresh();
}                                                                                                      //其他代码都省略
}


       其实写完注释,我也没大懂,就只知道大概的东西.还有contextConfigLocation,是上下文的初始化参数.

4.servlet节点

<!-- 找到spring-mvc的配置文件和spring的配置文件 -->
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml,/WEB-INF/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
      在servlet节点中配置了servlet-name为action,其实改为springmvc会更好理解,action是struts中的,而我们的框架是springmvc.

 
     DispatcherServlet是spring-webmvc下的一个类.



       DispatcherServlet是前端控制器设计模式的实现,提供Spring
Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。 
       DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:

1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);

3、  通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

4、通过ViewResolver解析逻辑视图名到具体视图实现;

5、本地化解析;

6、渲染具体的视图等;

7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
       从配置中可以看出,主要是拦截(/)所有请求,然后用DispatcherServlet进行职责调度.
       在容器(Tomcat)启动时,启动自己配置的初始化参数/WEB-INF/spring-mvc.xml,/WEB-INF/applicationContext.xml作为初始化的上下文,而这个上下文的作用范围是只对spring
web mvc的bean有效,如controller.而在context-param的init-param的作用范围是整个应用程序共享的.

       以上就是web.xml中的配置的一些解释,以前也没这么研究过,还是有很多不明白的,自己也没懂. 不过觉得看源码是很有用的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: