JAVAWEB开发之Servlet和ServletContext详解(5)

Servlet简介

(1)Servlet是sun公司提供的一门专门用于开发动态web资源的技术
(2)Sun公司在其API中提供了一个Servlet接口,若用户想要开发一个动态web资源(即开发一个JAVA程序向浏览器输出数据),需要完成以下两个步骤:
  • 编写一个JAVA类,实现Servlet接口。
  • 把开发好的JAVA类部署到web服务器中。
(3)快速入门,用Servlet向浏览器输出“hello Servlet”
  • 阅读Servlet API,解决两个问题:
  • 输出Hello Servlet的JAVA代码应该写在Servlet的那个方法中
  • 如何向IE浏览器输出数据?
* 编写一个类,实现Servlet接口,重写5个方法。
* 编写一个类,继承GenericServlet类,重写一个方法。
* 配置文件,配置Servlet信息。(必须会)
<!-- 先配置Servlet信息 -->
<servlet>
<!-- 配置Servlet名称,名称必须唯一 -->
<servlet-name>ServletDemo1</servlet-name>
<!-- 配置Servlet的完全路径(包名+类名) -->
<servlet-class>cn.itcast.servlet.ServletDemo1</servlet-class>
</servlet>

<!-- 配置Servlet映射(访问路径) -->
<servlet-mapping>
<!-- 配置Servlet名称,和上面的名称必须相同 -->
<servlet-name>ServletDemo1</servlet-name>
<!-- 配置虚拟路径(访问路径) -->
<url-pattern>/demo1</url-pattern>
</servlet-mapping>
带包编译:javac -d . FirstServlet.java
设置临时环境:set classpath=%classpath%;servlet-api.jar
(4)什么是Servlet?
实现Servlet接口,重写5个方法
Servlet是一个JAVA小程序,运行在服务器端,接收和响应从客户端(浏览器)发送过来的请求

Servlet在web应用中的位置


按照一种约定俗称的称呼习惯,通常我们也把实现了servlet接口的JAVA程序,称之为Servlet。

1) 在webapps目录下新建一个day04目录下新建一个day04的web应用,在day04下新建一个WEB-INF\classes,在classes新建servlet.
package cn.itcast;
import java.io.*;
import javax.servlet.*;


public class FirstServlet extends GenericServlet{
	
	public void service(ServletRequest req,ServletResponse res)
                      throws ServletException,java.io.IOException
        {
        	String data = "hello servlet!!";
        	OutputStream out = res.getOutputStream();
        	out.write(data.getBytes());	
        }
}
2) 进入到classes目录,编译FirstServlet
set classpath=%classpath%;tomcat\lib\javaee.jar
javac -d . FirstServlet.java
3) 在day04\WEB-INF 目录,新建一个web.xml文件,对Servlet进行配置

<web-app 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"
    version="2.5">
    
    <servlet>
        <servlet-name>FirstServlet</servlet-name>
        <servlet-class>cn.itcast.FirstServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>FirstServlet</servlet-name>
        <url-pattern>/xxx</url-pattern>
    </servlet-mapping>
    
</web-app>
4)启动服务器 在IE输入 http://localhost:80/day04/xxx

在web.xml配置Servlet访问虚拟路径


Servlet的运行过程:
Servlet程序是由WEB服务器调用,web服务器接收到客户端的Servlet访问请求后:
(1)WEB服务器首先检查是否已经装载并创建该Servlet实例对象。如果是,则直接执行第(4)步
,否则执行第(2)步
(2)装载并创建Servlet的一个实例对象
(3)调用Servlet实例对象的init()方法
(4)创建一个用于封装HTTP请求信息的HttpServletRequest对象和一个代表HTTP响应信息的HttpServletResponse对象,然后调用Servlet的service() 方法并将请求和响应对象作为参数传递进去
(5)WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

Servlet具体执行一次请求的步骤如下:
(一)由WEB浏览器向WEB容器发出Http请求

(二)WEB容器会检查是否已经创建与请求对应的Servlet对象,如果不存在,则会创建对应的Servlet对象。

(三)WEB容器接着创建请求和响应对象,将客户端发送请求的信息保存在request对象(HttpServletRequest对象)


(四)调用对应Servlet的service方法

(五)执行service方法中的业务逻辑 根据请求信息 向响应对象写入所要请求的数据


(六)service方法返回

(七)web容器读取响应信息,返回给客户端



在MyEclipse中开发Servlet
在MyEclipse中新建一个 web project工程 会自动创建下图所示的目录:

关于Servlet的生命周期(面试热点)

  • Servlet是一个供其他JAVA程序(Servlet引擎)调用的JAVA类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
  • 针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其他请求进行服务,直至web容器退出,servlet实例对象才会销毁。
  • 在Servlet的整个生命周期内,servlet的init方法只被调用一次,而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service方法,service方法再根据请求方式分别调用doXXX()(doGet、doPost)方法
实例被创建,对外提供服务,销毁。
* Servlet被创建后,然后调用init方法进行初始化
void init(ServletConfig config)
* 从客户端发送所有的请求是service方法进行处理的。
void service(ServletRequest req, ServletResponse res)
* 从服务器中移除服务,调用destroy方法。
void destroy()

* Servlet的生命周期:第一次请求的时候,Servlet实例被创建,立即调用init方法进行初始化。实例通过service方法提供服务。服务器关闭或者移除服务时,调用destroy方法进行销毁。
package cn.itcast.servlet;

import java.io.IOException;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 生命周期
 * @author Administrator
 *
 */
public class ServletDemo2 implements Servlet {
	
	/**
	 * Servlet实例被创建后,调用init方法进行初始化
	 * 	Servlet什么时候被创建呢?
	 * 		* 不是服务器一启动时,实例被创建,第一次访问的时候,实例才被创建。
	 * 	init方法调用几次呢?
	 * 		* 只被调用一次。
	 */
	public void init(ServletConfig config) throws ServletException {
		System.out.println("init...");
	}
	
	/**
	 * service调用几次呢?
	 * 	* 有一次请求,调用一次service方法
	 */
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {
		System.out.println("service...");
	}
	
	/**
	 * Servlet实例什么时候被销毁呢?
	 * 	* 服务器关闭,手动移除。
	 * 	destroy调用几次呢?
	 * 	* 一次	
	 */
	public void destroy() {
		System.out.println("destroy...");
	}
	
	
	
	
	public ServletConfig getServletConfig() {
		return null;
	}
	public String getServletInfo() {
		return null;
	}
}
配置web.xml
<servlet>
  		<servlet-name>ServletDemo2</servlet-name>
  		<servlet-class>cn.itcast.servlet.ServletDemo2</servlet-class>
  	</servlet>
  	<servlet-mapping>
  		<servlet-name>ServletDemo2</servlet-name>
  		<url-pattern>/demo2</url-pattern>
  	</servlet-mapping>



Servlet接口实现类

  • Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。
  • HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
  • HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
  • 阅读HttpServlet API文档
Servlet的关系
Servlet接口
|
GenericServlet(重写5个方法)
|
HttpServlet(继承GenericServlet实现了Servlet接口)
|
MyServlet

为什么会有GenericServlet?为什么会有HttpServlet?
GenericServlet虽然实现了Servlet接口的几个方法,但是并没有指定所使用的协议,而HttpServlet指定了所使用的HTTP协议,SUN公司是出于维护的考虑,一旦出现了别的协议,就可以添加一个新的类似于HttpServlet的类继承自GenericServlet。

查看GenericServlet的init()方法和init(ServletConfig config)
public class ServlerDemo3 extends GenericServlet {

	
	public void init(ServletConfig config) throws ServletException {
	}

	public void init() throws ServletException {
		
	}

	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {

	}

}
点击CRTL 查看如下:进入GenericServlet的类中init方法的实现:
  public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
    }

    public void init() throws ServletException {

    }
    


发现:在方法init(ServletConfig config)方法中调用了init()方法
注意:因此如果想重写init方法,直接重写无参数的init方法即可。
在GenericServlet查看service(ServletRequest req, ServletResponse res)方法的实现
再在HttpServlet中查看service(ServletRequest req, ServletResponse res)和service(HttpServletRequest req, HttpServletResponse resp)方法的实现
在GenericServlet中这第一个方法的实现如下:
 public abstract void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;
    


 
  
 
 
 
可以看到GenericServlet是不直接实现service方法的,而是交给子类去实现的
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
点击打开HttpServlet的源代码,查看以上service方法的实现如下:
 public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;
        
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
    }
}
 protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);        
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

 
 


可以看出真正实现Service方法的是HttpServlet类,而在HttpServlet中service方法会根据请求方式调用对应的doXXX

修改Servlet模板

  • 先找到MyEclipse的安装路径。
  • \myeclipse10.7\Common\plugins\com.genuitec.eclipse.wizards.xxxx.jar
  • 我自己的:com.genuitec.eclipse.wizards_9.0.0.me201211011550.jar
  • 千万别解压,右键--选择压缩工具打开--templates--Servlet.java 拖到桌面进行编辑保存成所需要的模板格式
  • 拖回去之前,先MyEclipse关闭。

配置Servlet自动加载

Servlet默认是在第一次访问的时候创建实例。通过配置,服务器启动,创建实例。
init()方法做初始化的操作,是非常耗费时间的,因此可以配置在服务器启动的时候创建实例。
如果在如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。
配置方法:在<servlet>标签下添加 <load-on-startup></load-on-startup>
值是正整数:如果值越小,优先级越高。
package cn.itcast.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 配置servlet启动时加载
 * @author Administrator
 *
 */
public class ServletDemo5 extends HttpServlet {
	
	/**
	 * 默认的情况下第一次访问的时候init被调用。
	 * 
	 */
	public void init() throws ServletException {
		System.out.println("init...");
		// 初始化数据库的链接
		
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 写的内容
		// 获取表单输入的内容
		// 自己逻辑,通过名称查询数据库,把张三的姓名查到了
		// 把张三返回浏览器
		System.out.println("doGet...");
		// 向页面输出内容
		response.getWriter().write("hello demo5...");
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request,response);
	}
	
}
在web.xml中添加代码如下:
 <!-- 使用模板生成的 -->
  <servlet>
    <servlet-name>ServletDemo5</servlet-name>
    <servlet-class>cn.itcast.servlet.ServletDemo5</servlet-class>
    <load-on-startup>3</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>ServletDemo5</servlet-name>
    <url-pattern>/demo5</url-pattern>
  </servlet-mapping>

配置Servlet路径映射配置

  • 由于客户端是通过URL地址访问web服务器中的资源,所以Servlet程序若想被外界访问,必须把servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
  • <servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name>和<servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。
  • 一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name>和<url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
<web-app>
	<servlet>
		<servlet-name>AnyName</servlet-name>
		<servlet-class>HelloServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>AnyName</servlet-name>
		<url-pattern>/demo/hello.html</url-pattern>
	</servlet-mapping>
</web-app>·

注意:可以在一个<servlet-mapping>标签对内添加多个<url-pattern>标签

Servlet路径映射配置方式

  • 同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名。
  • 在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾。

url-pattern 配置的三种方式:
1、完全路径匹配 以/开始 不能包含通配符* :例如/hello /init
2、目录匹配,以/开始,以/*结尾 例如:/* /aa/* /aaa/bbb/*
3、扩展名匹配,不能以/开始,以 * 开始 例如:*.do *.action
经典错误:/*.do
优先级:完全匹配 > 目录匹配 > 扩展名匹配

举例如下:
对于如下的一些映射关系
Servlet1 映射到/abc/*
Servlet2 映射到/*
Servlet3 映射到/abc
Servlet4 映射到 *.do

问题:
(1)当请求URL为 "/abc/a.html"时,"/abc/*" 和"/*"都匹配,哪个servlet响应
Servlet引擎将调用Servlet1 ,虽然同样是目录匹配 但/abc/* 更近似
(2)当请求URL为 "/abc" 时,"/abc/*" 和 "/abc" 都匹配,哪个servlet响应
Servlet引擎将调用Servlet3时,因为完全路径匹配>目录匹配
(3)当请求URL为"/abc/a.do"时,"/abc/*"和"*.do"都匹配,哪个servlet响应
Servlet将会调用Servlet1,因为目录匹配> 扩展名匹配
(4)当请求URL为"/a.do"时,"/*"和"*.do"都匹配,哪个servlet响应
Servlet引擎将会调用Servlet2,因为目录匹配的优先级大于扩展名匹配
(5)当请求URL为 "/xxx/yyy/a.do"时,"/*"和"*.do"都匹配,哪个Servlet响应
Servlet引擎将调用Servlet2 ,因为目录匹配的优先级大于扩展名匹配


Web开发中的绝对路径和相对路径

路径问题举例如下:
在WebRoot下 新建 1.html
在WebRoot/aa 下新建 2.html
在1.html 和 2.html 分别通过 超链接 访问 HelloServlet


1.html
<h1>相对路径</h1>
<a href="./hello">HelloServlet</a>
<a href="hello">HelloServlet</a>
<h1>绝对路径</h1>
<a href="http://localhost/day5/hello">HelloServlet</a>
<a href="/day5/hello">HelloServlet</a>

2.html
<h1>相对路径</h1>
<a href="../hello">HelloServlet</a>
<h1>绝对路径</h1>
<a href="http://localhost/day5/hello">HelloServlet</a>
<a href="/day5/hello">HelloServlet</a>
</body>

路径分为相对路径和绝对路径两种写法
(1). 相对路径,根据当前资源路径 与 目标资源路径,寻找相对位置关系,通过 . (当前目录) 和 .. (上一级目录) 访问目标资源
1.html 访问 HelloServlet
当前路径 http://localhost/day5/1.html
目标路径 http://localhost/day5/hello
位于同一个目录中 ./hello 、hello ===== 替换当前路径最后一个资源

2.html 访问 HelloServlet
当前路径 http://localhost/day5/aa/2.html
目标路径 http://localhost/day5/hello

上一级目录中 ../hello ===== 替换上一级目录资源

相对路径,总需要分析当前路径与目标路径对应关系,编写规则会根据当前路径不同而不同

(2)绝对路径
带有协议完整路径 (跨网站) http://localhost/day5/hello
以/ 开始路径 (同一个站点内) : /day5/hello

服务器端和客户端对于/ 的区别
客户端访问路径:/day5/hello
服务器内部路径:/hello

结论:web访问中所有资源路径,都使用绝对路径

客户端关于路径问题的编程结论
  • *.html *.jsp 内都使用绝对路径
  • *.css 内部使用相对路径---- 背景图片
  • *.js中使用绝对路径

init方法中的ServletConfig对象

  • 在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。
  • 当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。
ServletConfig对象和配置文件相关:
配置初始化参数:
* 需要在<servlet></servlet>标签下配置
* 如果要是配置在某个servlet的标签下,那么只能在该servlet中获取初始化参数
<init-param>
<param-name>username</param-name>
<param-value>root</param-value>
</init-param>
相关方法如下:
String getServletName() 获取配置文件中servlet的名称
String getInitParameter(String name) 获取初始化参数
Enumeration getInitParameterNames() 获取初始化化参数的名称们
实例如下:
package cn.itcast.servlet;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * ServletConfig对象
 * @author Administrator
 *
 */
public class ServletDemo6 extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 测试ServletConfig对象的api
		// 先获取ServletConfig对象
		ServletConfig config = getServletConfig();
		// 获取配置文件中serlvet的名称
		System.out.println("servlet的名称:"+config.getServletName());
		
		// 获取初始化的参数
		String username = config.getInitParameter("username");
		String password = config.getInitParameter("password");
		System.out.println(username+" : "+password);
		
		Enumeration<String> e = config.getInitParameterNames();
		while(e.hasMoreElements()){
			String name = e.nextElement();
			String value = config.getInitParameter(name);
			System.out.println(name+" : "+value);
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
在web.xml中添加如下内容:
 <!-- 演示初始化参数 -->
  <servlet>
    <servlet-name>ServletDemo6</servlet-name>
    <servlet-class>cn.itcast.servlet.ServletDemo6</servlet-class>
    <!-- 配置初始化参数 -->
    <init-param>
    	<param-name>username</param-name>
    	<param-value>root</param-value>
    </init-param>
    <init-param>
    	<param-name>password</param-name>
    	<param-value>123</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
  <servlet-name>ServletDemo6</servlet-name>
  <url-pattern>/demo6</url-pattern>
 </servlet-mapping>
运行结果如下:


Web应用对象:ServletContext(域对象)

  • WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
  • 一个WEB应用对应一个ServletContext对象
  • ServletConfig对象中维护了ServletContext对象的引用,在开发编写servlet时,可以通过ServletConfig.getServletContext()方法获得ServletContext对象
  • 由于一个WEB应用中的所有Servlet共享一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称为context域对象。
作用如下:
(1)获取WEB应用全局初始化参数
在web.xml中配置
<context-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</context-param>
String getInitParameter(String name)
Enumeration getInitParameterNames()
(2)实现数据共享
void setAttribute(String name, Object object) 存入数据
void removeAttribute(String name) 删除数据
Object getAttribute(String name) 获取数据
(3)读取资源文件
InputStream getResourceAsStream(String path) 通过文件的地址获取输入流
String getRealPath(String path) 通过文件的地址获取文件的绝对磁盘路径
WEB Project读取资源文件:
(1)文件系统路径
getServletContext().getRealPath("/WEB-INF/info.txt")
(2)类路径classpath(src下)
* 通过字节码对象读取Class
getResource("/info.txt").getFile()
* 获取字节码对象Class
类名.class ——静态方法获取
对象.getClass() —— 实例方法

(3)注意:使用基本的FileInputStream 读取相对路径时 是相对于Tomcat安装程序的bin目录,而要想相对路径在Tomcat的webapps的当前应用的根路径,就需要使用getResourceAsStream()方法。
(4)web工程src下的类会被编译到打包项目应用的/WEB-INF/classes/ 目录下
(5)使用类加载器获取的是classpath根路径。
使用技巧如下:
读取web工程中资源文件
在day5工程中创建四个文件
1、在day5工程根目录 创建 1.txt
2、在WebRoot下 创建2.txt
3、在WEB-INF下 创建3.txt
4、在src下创建 4.txt


*** 使用带有main函数java程序(Java Application)读取文件,可以使用相对路径和绝对路径
*** 在Servlet中读取资源文件,必须使用磁盘绝对路径


1.txt因为在WebRoot 外面 不会发布到tomcat服务器,无法在服务器端读取
2.txt --- > getServletContext().getRealPath("/2.txt");
3.txt --- > getServletContext().getRealPath("/WEB-INF/3.txt");
4.txt 位于src下,复制到WEB-INF/classes下 ---> getServletContext().getRealPath("/WEB-INF/classes/4.txt");


通用classpath下文件读取方法 (用来加载器读取)
XXX.class.getResource("/4.txt").getFile();
这里/代表classpath根目录(src 、WEB-INF/classes)
1、java读取
public static void main(String[] args) throws IOException {
// 编写四个文件 路径,调用readfile方法 完成文件读取
// 读取1.txt
String filename1 = "1.txt";
readfile(filename1);
// 读取2.txt
String filename2 = "WebRoot/2.txt";
readfile(filename2);
// 读取3.txt
String filename3 = "WebRoot/WEB-INF/3.txt";
readfile(filename3);
// 读取4.txt
String filename4 = "src/4.txt";
readfile(filename4);
// 读取4.txt
String filename5 = FileReaderTest.class.getResource("/4.txt").getFile();
readfile(filename5);

}

public static void readfile(String filename) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
filename));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}

bufferedReader.close();
}


2、Servlet读取
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 读取 1.txt (不会被发布到tomcat,没法读)
// 读取 2.txt
String filename1 = "/2.txt";
// 根据相对于网站根目录绝对路径 ---- 获得磁盘绝对路径
filename1 = getServletContext().getRealPath(filename1);
System.out.println(filename1);
readfile(filename1);


// 读取3.txt
String filename2 = getServletContext().getRealPath("/WEB-INF/3.txt");
readfile(filename2);


// 读取4.txt
String filename3 = getServletContext().getRealPath(
"/WEB-INF/classes/4.txt");
readfile(filename3);


// 读取4.txt 用类加载器读取
String filename4 = ReadFileServlet.class.getResource("/4.txt")
.getFile();
readfile(filename4);
}
public static void readfile(String filename) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(
filename));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
}

ServletContext实例一:获取全局初始化参数

package cn.itcast.context;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 获取全局初始化参数
 * @author Administrator
 *
 */
public class ContextDemo1 extends HttpServlet {
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 先获取ServletContext对象
		ServletContext context = getServletContext();
		// 获取初始化参数
		String encoding = context.getInitParameter("encoding");
		System.out.println("编码:"+encoding);
		
		Enumeration<String> e = context.getInitParameterNames();
		while(e.hasMoreElements()){
			String name = e.nextElement();
			// 通过name获取值
			String value = context.getInitParameter(name);
			System.out.println(name+" : "+value);
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
在web.xml中添加配置信息

<!-- 配置全局初始化参数 -->
   <context-param>
	<param-name>encoding</param-name>
		<param-value>GBK</param-value>
   </context-param>
   <servlet>
  <servlet-name>ContextDemo1</servlet-name>
  <servlet-class>cn.itcast.context.ContextDemo1</servlet-class>
 </servlet>
<servlet-mapping>
  <servlet-name>ContextDemo1</servlet-name>
  <url-pattern>/context1</url-pattern>
 </servlet-mapping>


ServletContext实例二:获取资源文件



package cn.itcast.context;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 读取资源文件
 * @author Administrator
 *
 */
public class ReadServlet extends HttpServlet {
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		read5();
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}
	
	/**
	 * 通过ServletContext对象获取文件的绝对磁盘路径
	 * 获取src目录下文件
	 * @throws IOException 
	 */
	public void read5() throws IOException{
		// 获取对象
		String path = getServletContext().getRealPath("/WEB-INF/classes/db.properties");
		// System.out.println(path);
		// C:\apache-tomcat-6.0.14\webapps\day09\WEB-INF\classes\db.properties
		
		// 获取输入流
		InputStream in = new FileInputStream(path);
		print(in);
	}
	
	/**
	 * 获取WebRoot目录目录下db.properties文件
	 * @throws IOException
	 */
	public void read4() throws IOException{
		// ServletContext读取文件
		InputStream in = getServletContext().getResourceAsStream("/db.properties");
		// 打印方式
		print(in);
	}
	
	/**
	 * 获取包目录下db.properties文件
	 * @throws IOException
	 */
	public void read3() throws IOException{
		// ServletContext读取文件
		InputStream in = getServletContext().getResourceAsStream("/WEB-INF/classes/cn/itcast/context/db.properties");
		// 打印方式
		print(in);
	}
	
	/**
	 * 获取src目录下db.properties文件
	 * @throws IOException
	 */
	public void read2() throws IOException{
		// ServletContext读取文件
		InputStream in = getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
		// 打印方式
		print(in);
	}
	
	/**
	 * 传统方式读取资源文件
	 * 	交给服务器处理,相对的位置tomcat/bin
	 * @throws IOException 
	 */
	public void read1() throws IOException{
		// 获取输入流
		InputStream in = new FileInputStream("src/db.properties");
		print(in);
	}
	
	/**
	 * 在控制台打印内容
	 * @param in
	 * @throws IOException
	 */
	public void print(InputStream in) throws IOException{
		Properties pro = new Properties();
		// 加载
		pro.load(in);
		// 获取文件中的内容
		String username = pro.getProperty("username");
		String password = pro.getProperty("password");
		String desc = pro.getProperty("desc");
		
		System.out.println("用户名:"+username);
		System.out.println("密码:"+password);
		System.out.println("描述:"+desc);
	}
	
}


ServletContext实例三:域对象(多个Servlet共享数据) 网站计数器

创建两个Servlet,CountServlet专门用于统计访问量,ShowServlet用于显示访问量
CountServlet.java如下:

package cn.itcast.context;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 统计网站的访问次数
 * @author Administrator
 *
 */
public class CountServlet extends HttpServlet {
	
	/**
	 * 实例被创建,调用init方法进行初始化
	 * 	在域对象存入一个变量,赋值为0
	 */
	public void init() throws ServletException {
		// 获取ServletContext对象
		getServletContext().setAttribute("count", 0);
	}

	/**
	 * 每一次访问,都会执行该方法。
	 * 拿出count的变量,值自增,存入到域对象中
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 先获取ServletContext对象
		ServletContext context = getServletContext();
		// 获取count的值,自增
		Integer count = (Integer) context.getAttribute("count");
		// 存入到域对象中
		context.setAttribute("count", ++count);
		
		// 向页面输出内容
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().write("<h3>大爷,欢迎再来哦!!</h3>");
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
ShowServlet.java如下:
package cn.itcast.context;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 显示网站的访问次数
 * @author Administrator
 *
 */
public class ShowServlet extends HttpServlet {

	/**
	 * 获取网站的访问次数,输出到客户端
	 */
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Integer count = (Integer) getServletContext().getAttribute("count");
		// 向页面输出
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().write("<h3>该网站一共被访问了"+count+"次</h3>");
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
在web.xml中添加如下配置:
<servlet>
    <servlet-name>CountServlet</servlet-name>
    <servlet-class>cn.itcast.context.CountServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>ShowServlet</servlet-name>
    <servlet-class>cn.itcast.context.ShowServlet</servlet-class>
  </servlet>
<servlet-mapping>
    <servlet-name>CountServlet</servlet-name>
    <url-pattern>/count</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>ShowServlet</servlet-name>
    <url-pattern>/show</url-pattern>
  </servlet-mapping>


页面定时跳转和重定向

HTTP的协议
* 请求
* referer 记住当前网页的来源
* user-agent 浏览器版本信息
* if-modefied-since

* 响应
* 响应头
* location 和302一起来完成重定向的操作
* refresh 页面的定时刷新
* last-modefied和 if-modefied-since和304状态码一起来控制缓存。

package cn.itcast.http;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 页面定时跳转
 * @author Administrator
 *
 */
public class RefreshServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().write("访问到了...");
		// 页面5秒会跳转
		response.setHeader("refresh", "5;url=/day09/1.html");
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

重定向简单实例:

package cn.itcast.http;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 和location和302一起完成重定向
 * @author Administrator
 *
 */
public class ServletDmo1 extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 向页面输出内容
		response.setContentType("text/html;charset=UTF-8");
		// response.getWriter().write("向班长借钱...");
		// 我没钱
		response.setStatus(302);
		// 告诉我富班长的地址
		response.setHeader("location", "/day09/1.html");
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}


关于缺省的Servlet以及如何在Tomcat服务器打开文件监听:

  • 如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。
  • 凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。
  • 在<tomcat的安装目录>\conf\web.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet。
  • 当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet。
例如:打开一个没有匹配的路径



其实,不存在的路径处理 就交给了Tomcat默认的Servlet进行处理了

打开文件监听之后,就可以查看某个应用下的所有文件了
服务器中的html文件数据的读取由缺省servlet完成
缺省Servlet
1、将服务器静态资源,读取到内存,发送给客户端
2、所有服务器静态资源 都是通过缺省Servlet返回的
3、缺省Servlet 配置 url-pattern 是 /
4、在tomcat/conf/web.xml 查看缺省Servlet配置
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
访问文件夹,listing 为false 显示404 、如果listing 设置为true,访问文件夹时候,显示文件夹下面所有页面



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值