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

       上篇文章中,准备好了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对资源的拦截.


       现在依次介绍4xml文件.

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中的配置的一些解释,以前也没这么研究过,还是有很多不明白的,自己也没懂.
 不过觉得看源码是很有用的.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值