① 一个已经注册的Servlet可以被多次映射即:
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<!-- servlet的注册名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet类的全路径(包名+类名) -->
<servlet-class>com.hsp.servlet.MyServlet1</servlet-class>
</servlet>
<!-- 对一个已经注册的servlet的映射 -->
<servlet-mapping>
<!-- servelt的注册名 -->
<servlet-name>MyServlet1</servlet-name>
<!-- servlet的访问路径 -->
<url-pattern>/MyServlet1</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>MyServlet1</servlet-name>
<url-pattern>/hsp</url-pattern>
</servlet-mapping>
① 当映射一个servlet时候,可以多层 比如
<url-pattern>/servlet/index.html</url-pattern> ok
从这里还可以看出,后缀名是 html不一定就是html,可能是假象.
① 使用通配符在servlet映射到URL中
有两种格式:
第一种格式 *.扩展名 比如*.do *.ss
第二种格式 以 /开头 同时以/*结尾 比如 /* /news/*
通配符练习题:
l Servlet1 映射到 /abc/*
l Servlet2 映射到 /*
l Servlet3 映射到 /abc
l Servlet4 映射到 *.do
问题(面试题):
l 当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
l 当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
l 当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
l 当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
l 当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
在匹配的时候,要参考的标准:
(1) 看谁的匹配度高,谁就被选择
(2) *.do 的优先级最低
① Servlet单例问题
当Servlet被第一次访问后,就被加载到内存,以后该实例对各个请求服务.即在使用中是单例.
因为 Servlet是单例,因此会出现线程安全问题:比如:
售票系统. 如果不加同步机制,则会出现问题:
这里我给大家一个原则:
(1) 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制
synchronized (对象){
//同步代码
}
(2)如果一个变量不需要共享,则直接在doGet()或者doPost()定义.这样不会存在线程安全问题
① servlet 中的 <load-on-startup>配置
需求: 当我们的网站启动的时候,可能会要求初始化一些数据,(比如创建临时表),在比如:
我们的网站有一些要求定时完成的任务[ 定时写日志,定时备份数据.. 定时发送邮件..]
解决方法: 可以通过 <load-on-startup>配合 线程知识搞定.
先说明<load-on-startup>: 通过配置<load-on-startup> 我们可以指定某个Servlet自动创建.
我们来模拟一个定时发送电子邮件的功能:
实现思路:
sendEmailTable
id content sendtime
1 “hello” 2011-11-11 20:11
2 “hello2” 2012-11-11 10:00
看看如何线程去完成任务:
这里的代码请参考项目:
SendMailThread.java
package com.hsp.model;
public class SendEmailThread extends Thread{
@Override
public void run() {
int i=0;
try {
while(true){
//每休眠一分钟,就去扫表sendmail, 看看那份信件应当被发出
Thread.sleep(10*1000);
System.out.println("发出 第"+(++i)+"邮件");//javamail
}
} catch (Exception e) {
e.printStackTrace();
// TODO: handle exception
}
}
}
MyInitServlet1.java
public void init() throws ServletException {
// Put your code here
System.out.println("MyInitServlet1 的init被调用..");
//完成一些初始化任务
System.out.println("创建数据库,表,读取参数");
//创建一个线程
SendEmailThread sendEmailThread=new SendEmailThread();
sendEmailThread.start();
}
说明:
<!-- 1表示该servlet被 init的顺序 -->
<load-on-startup>1</load-on-startup>
- ServletConfig对象
该对象主要用于 读取 servlet的配置信息.
案例:
<servlet>
<servlet-name>ServletConfigTest</servlet-name>
<servlet-class>com.hsp.servlet.ServletConfigTest</servlet-class>
<!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</servlet>
如何使用
String encoding=this.getServletConfig().getInitParameter("encoding");
补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置:
<!-- 如果这里配置参数,可被所有servlet读取 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
如果要把所有的参数都读取,则使用 如下方法 :
Enumeration<String> names=this.getServletConfig().getInitParameterNames();
while(names.hasMoreElements()){
String name=names.nextElement();
System.out.println(name);
System.out.println(this.getServletConfig().getInitParameter(name));
}