Servlet——开发细节+ServletConfig对象

24 篇文章 15 订阅
19 篇文章 4 订阅
 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的对外访问路径。

  1. ★这里需要注意的是,一个servlet可以被多次映射,也即一个Servlet可以有多个<servlet-mapping>,对外提供多个访问路径。举例如下:

<servlet>
    <servlet-name>MyServlet1</servlet-name>
    <servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
  	</servlet>

  	<servlet-mapping>
    	<servlet-name>MyServlet1</servlet-name>
    	<url-pattern>/MyServlet1</url-pattern>
  	</servlet-mapping>
  
  	<servlet-mapping>
    	<servlet-name>MyServlet1</servlet-name>
    	<url-pattern>/Gavin.html</url-pattern>
</servlet-mapping>

<servlet-mapping>
    	<servlet-name>MyServlet1</servlet-name>
   	 	<url-pattern>/servlet/Gavin.html</url-pattern>
 </servlet-mapping>

这里可以看到,我们将MyServlet1映射成了一个名字为MyServlet1,另一个名字为Gavin.html,还有一个名字为/servlet/Gavin.html。这里也得出结论:

★后缀名为html的资源不一定真的就是html

★映射的名字可以有多级,有多个斜杠


      ★在Servlet映射到的URL中也可以用*通配符,但只能有两种固定的格式,一种格式是“*.扩展名”,另一种是以正斜杠(/)开头并以”/*”结尾。

<servlet-mapping>
   		<servlet-name>AnyName</servlet-name>
  	 	<url-pattern>/*</url-pattern>
 	</servlet-mapping>

<servlet-mapping>
    	<servlet-name>AnyName</servlet-name>
   	 	<url-pattern>/news/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
    	<servlet-name>AnyName</servlet-name>
   	 	<url-pattern>*.do</url-pattern>
</servlet-mapping>

则第一种可以匹配任何名字的servlet,第二种可以匹配前面有一层为newsservlet,这种方法可以应用在:比如一个网站要对新闻版块进行整改,则可以用这种方法将新闻版块的请求指向其他地方,将其暂时关闭。第三种匹配后缀为doservlet


匹配原则:在匹配的时候,(1)看谁的匹配度高,谁就被选中;(2)【*.后缀名】的优先级最低,实在没有匹配项的时候才匹配这个。


看一个面试题:


对于如下的一些映射关系:

  • Servlet1映射到/abc/*

  • Servlet2映射到/*

  • Servlet3映射到/abc

  • Servlet映射到*.do

  1. 当请求URL为“/abc/a.html”,“/abc/*”和”/*”都匹配,哪个Servlet响应?

    答案:Servlet1

  2. 当请求URL为“/abc”时,”/abc/*””/abc””/*”都匹配,哪个Servlet响应?

    答案:Servlet3

  3. 当请求URL为“/abc/a.do”,“/abc/*”和” *.do”都匹配,哪个Servlet响应?

    答案:Servlet1

  4. 当请求URL为“/a.do”,“/*”和”*.do”都匹配,哪个Servlet响应?

    答案:Servlet2à*.后缀名】的优先级最低

5、当请求URL为“/xxx/yyy/a.do”,“/*”和” *.do”都匹配,哪个Servlet响应?


答案:Servlet2à还是*.后缀名】的优先级最低


通配符的价值在于可以在网站某版块或者整个网站进行维护时,进行暂时的关闭版块或网站。


(四)Servlet是一个供其他java程序(Servlet引擎)调用的java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度


(五)针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,(单例模式)也就是说Servlet实例一旦创建,它就会驻留在内存中,为后续的其他请求服务,直至web容器退出/或者reloadweb运用servlet实例对象才会销毁。

      Servlet单例模式存在线程安全问题,要注意并发处理,比如买票系统,票是所有客户端共享的,那么售票的代码应该使用同步机制。

      synchronized(this){


}

如果一个变量不是共享的,就不需要设置为成员变量,只需要在doGet或者doPost方法中定义为局部变量即可。


(六)在Servlet的整个生命周期内,Servletinit方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servletservice方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,service方法再根据请求方式分别调用doXXX方法。


(七)★如果在<servlet>元素中配置了一个<load-on-startup>元素,那么web应用程序启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法。

      用途:为web应用写一个InitServlet,这个Servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据。或者是启动一个后台线程,定时去完成某些工作(比如每隔10秒发一封电子邮件)

      举例:

      新建ServletInitServlet,其代码如下:

package com.gavin.servlet;

import java.io.IOException;
import java.io.PrintWriter;

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

public class InitServlet extends HttpServlet {
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	}

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

		this.doGet(request, response);
	}

	//初始化函数
	public void init() throws ServletException {
		System.out.println("InitServlet的init函数被调用...");
		System.out.println("创建库、表...或者定时任务...");
	}

}

其中只写了init函数的代码。在web.xml部署如下,其不用<servlet-mapping>映射,因为它只要在启动web应用时调用,而不需要外部访问


<servlet>
    <servlet-name>InitServlet</servlet-name>
    <servlet-class>com.gavin.servlet.InitServlet</servlet-class>
    <!-- 这里的1表示所有自启动的servlet的启动顺序,可以用1、2、3... -->
    <load-on-startup>1</load-on-startup>
  </servlet>

这里的1表示所有自启动的servlet的启动顺序,可以用123...

启动Tomcat服务器,可以看到:



启动Tomcat服务器的同时,这个Servlet已经被装载到内存了。


这里我们来模拟一个定时发送电子邮件的功能,实现思路:

这里当用户设定了一个定时发送邮件的任务后,数据库里肯定存在一张表,大概如下:


Id

Content

sendTime

1

Hello

2014-5-18 00:00

2

Happy Birthday

2014-5-20 13:14

这里只是做一个简单的模拟,新建一个sendMainThread线程类

package com.gavin.model;

public class SendMailThread extends Thread {
	public void run() {
		int i = 0;
		while (true) {
			try {
				// 每休眠一分钟,就去扫表sendmail,看看哪些信件应当发送
				Thread.sleep(1000 * 10);
				System.out.println("发出 第" + (++i) + "封信件");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
}

InitServlet中创建该线程,并启动即可

public void init() throws ServletException {
		System.out.println("InitServlet的init函数被调用...");
		System.out.println("创建库、表...或者定时任务...");
		//创建一个线程
		SendMailThread sendMailThread = new SendMailThread();
		sendMailThread.start();
	}

效果:


当然真实的情况应该是要比对数据库中的时间的。


大型的网站会有多个自启动的Servlet,这里要用123….表示启动的顺序。前面也提到了!


ServletConfig对象

      ◆在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。

      ◆当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。


如下:

<servlet>
    <servlet-name>MyServlet1</servlet-name>
    <servlet-class>com.gavin.servlet.MyServlet1</servlet-class>
    <!-- 这里可以给servlet配置信息,这里的配置信息,只能被该servlet读取 -->
    <init-param>
    	<param-name>encoding</param-name>
    	<param-value>utf-8</param-value>
    </init-param>
  </servlet>

说明:这里的配置参数方法,只能被该servlet读取,而不能被其他servlet使用

Servlet程序中,可以读取出设置参数,如下:

response.setCharacterEncoding(this.getInitParameter("encoding"));

如果有多个参数,可以使用getInitParameterNames()方法,该方法返回枚举类型Enumeration,可以通过for循环拿到对应的参数名称,然后通过参数名称再通过上述方法拿到参数,当然也可以一个个拿到。

◆当然,还有一种全局的参数设置,<context-param>节点也可以配置初始化参数,并且可以被所有servlet读取

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值