1、Servlet是什么:
Servlet(Server Applet),是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。
2、手动创建一个简单的Servlet示例:
新建个web工程
File-New-Web Project-Test,直接下一步,Finish
新建一个com.test.servlet包
在这个包下建个Servlet,右击-New-Servlet,名称ServletDemo1,继承javax.servlet.http.HttpServlet
Finish
3、Servlet调用过程分析:
代码演示调用顺序:注意这里是继承GenericServlet,这个是HttpServlet的父类(可以查看J2EE5.chm帮助)
public class ServletDemo1 extends GenericServlet {
public ServletDemo1() {
System.out.println("构造函数");
}
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("初始化");
}
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
System.out.println("处理请求");
}
@Override
public void destroy() {
System.out.println("我被销毁了");
}
}
输入网址:http://localhost:8080/Demo/servlet/ServletDemo1
运行的结果:
构造函数
初始化了
处理请求
注意:destroy是在服务器程序停止运行的时候调用,tomcat6.0可以进入后台停止服务.
默认情况下,servlet对象在第一次请求的时候调用构造函数创建, 创建之后自动调用带参的init方法,
然后调用service方法.destroy方法在停止服务器或者停止应用的时候调用。
整个过程中,init方法和destroy方法只会调用一次,而service方法会反复调用。
4、web.xml文件的配置:
你创建了一个Servlet看看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">
<servlet>
<servlet-name>ServletDemo1</servlet-name>//这个是java的类名,通过这个和servlet标签匹配上
<servlet-class>com.test.servlet.ServletDemo1</servlet-class>//这个是java类的地址,真正运行的程序
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>//这个是java的类名,通过这个和servlet标签匹配上
<url-pattern>/servlet/ServletDemo1</url-pattern>//这个是url的地址,
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
5、servlet的执行调用过程:
servlet执行调用过程.png
6、servlet的URL配置:
就是配置:<url-pattern>/servlet/ServletDemo1</url-pattern>
http://localhost:8080/Demo/servlet/ServletDemo1 这个就是你浏览器访问的地址
写法有两种:
1. 以/开头: /代表的是工程路径(/工程名称) 必须要加/
2. 以*开头: 必须要加后缀名(后缀名任意) 后缀名不能用*
3. 如果只是配置一个/,那么此Servlet就是一个默认的servlet,它用来处理所有找不到匹配的url的请求
注意: /*.后缀名此种情况允许
配置优先级: 精确匹配 > 以/开头的匹配 > 以*开头的匹配
7、serlvet创建的时机:
可以通过配置web.xml文件来改变创建servlet的时机
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>com.test.servlet.ServletDemo1</servlet-class>
<!-- 启动时加载 数字代表了启动的顺序-->
<load-on-startup>2</load-on-startup>
</servlet>
8、编写servlet的三种方法:
可以直接在myeclipse中新建,继承类
a.采用实现servlet接口(不推荐)
b.采用继承GenericServlet类( 不推荐)
c.采用继承HttpServlet(推荐)
封装度越高,那么自由度就会越低。
9、修改Servlet模板:
我们在用myeclipse创建Servlet的时候,会有很多我们不需要的东西。
a.找到你的myeclipse的安装路径中的 com.genuitec.eclipse.wizards_11.5.0.me201310291746.jar这个文件
b.把这个文件复制到桌面,使用rar打开,在templates的文件夹中有个Servlet.java
c.拖到桌面来,修改里面的模板。
e.然后在拖回去,把原来的那个jar文件替换掉。
f.重启myeclipse就可以了。
10、线程的安全问题:
Servlet的设计是一个单实例多线程。
线程安全要求将变量创建成一个局部变量,而不要创建成实例变量。
如果定义为全局变量,那么每个访问者都改变这个变量,值就乱掉了。
例如:(我们不要这样去定义)
public class ServletDemo7 extends HttpServlet{
int a = 0 ;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
a++ ;
System.out.println(Thread.currentThread().getName() + ":" + a);
try {
Thread.sleep(5000) ;
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":" + a);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
11、获取ServletConfig对象的两种方式:
servletConfig的作用:就是拿取servlet的相关配置.也就是拿去web.xml里面的配置信息。
1.通过带参的init方法获取。
因为如果你写没有带参的init方法,ServletConfig config这个就不会初始化。就获取不到了。
2. 采用servlet实例拿取(不要写带参的init方法)
因为看底层的代码,this.getServletConfig()其实返回的就是一个父类的config,
没有调父类的带参init,所以父类的config就没有实例化,返回的就是一个null值
如果一定要写带参的init方法,就必须手动调用super(config),手动初始化下。
例如:
public class ServletConfig1 extends HttpServlet {
ServletConfig config ;
@Override
public void init(ServletConfig config) throws ServletException {//第一次调用的时候就把config传过来了,所以不写super也可以拿到config
super.init(config) ;//这个是如果用第二种方法,一定要写这句,用第一种可以不用写
this.config = config ;//第一种方法
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletConfig sc = this.getServletConfig() ;//第二种方法
//System.out.println(config == sc);
System.out.println(sc);
System.out.println(config == sc);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
注意:init方法只是在第一次访问的时候调用。系统默认调用的是带参的init方法。
12、ServletConfig对象的应用-拿取配置信息:
web.xml的参数配置如下:(一个servlet的参数)
<servlet>
<servlet-name>ServletConfig1</servlet-name>
<servlet-class>com.test.servletconfig.ServletConfig1</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>张三</param-value>
</init-param>
<init-param>
<param-name>age</param-name>
<param-value>20</param-value>
</init-param>
</servlet>
例如:
public class ServletConfig1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//拿到servletConfi对象
ServletConfig sc = this.getServletConfig() ;//这里没有init方法,系统自动调用带参的init,所以不会是null
//拿取配置的单个信息
String name0 = sc.getInitParameter("name") ;
System.out.println(name0);
//拿取配置的多个信息
Enumeration<String> enu = sc.getInitParameterNames() ;
while(enu.hasMoreElements()){
String name = enu.nextElement() ;
System.out.println(name + ":" + sc.getInitParameter(name));
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
运行的结果:
张三
name:张三
age:20
13、ServletContext介绍:
每个web应用都有一个唯一的servletContext对象
在每个应用加载的时候,服务器就会创建servletContext对象
生命周期很长
ServletContext对象是一个域对象
14、获取servletContext对象的三种方式:
1. 采用servletConfig对象获取
2. 采用servlet实例对象获取
3. 采用request对象获取
例如:
public class ServletContext1 extends HttpServlet {
ServletContext sc ;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config) ;
sc = config.getServletContext() ;//第一种方式
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc1 = this.getServletContext() ;//第二种方式
System.out.println(sc);
System.out.println(sc1 == sc);
ServletContext sc2 = request.getSession().getServletContext() ;//第三种方式
System.out.println(sc2 == sc);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
运行的结果:
org.apache.catalina.core.ApplicationContextFacade@3e403c23
true
true
可以看到这三种方式拿到的context都是一样的。
15、ServletContext的一些应用:
a.获取全局对象中存储的数据
例如:
在ServletContext2.java中存数据
public class ServletContext2 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = this.getServletContext() ;//获取全局对象
sc.setAttribute("name", "张三") ;//存储数据
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在ServletContext3对象中取数据
public class ServletContext3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = this.getServletContext() ;//拿取全局对象
String name = (String)sc.getAttribute("name") ;//从sc中拿取数据
System.out.println(name);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
我们访问ServletContext3这个Servlet:http://localhost:8080/Demo/servlet/ServletContext3
运行的结果:张三
b.获取全局配置参数:(这个和ServletConfig的功能差不多)
前提你已经在web.xml中配置了参数
例如:
public class ServletContext4 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = this.getServletContext() ;//拿到全局对象
String name0 = sc.getInitParameter("name") ;//获取单个配置参数(获取姓名)
System.out.println(name0);
Enumeration<String> enu = sc.getInitParameterNames() ;//拿取多个配置参数的值
while(enu.hasMoreElements()){
String name = enu.nextElement() ;
System.out.println(name + ":" + sc.getInitParameter(name));
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
c.请求转发:
例如:
在ServletContext5.java中获取request
public class ServletContext5 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = this.getServletContext() ;//拿到全局对象
request.setAttribute("name", "张三") ;
//拿到请求转发器,指定你需要转发的地址
RequestDispatcher rd = sc.getRequestDispatcher("/servlet/ServletContext6") ;
rd.forward(request, response) ;//转发过去
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
在ServletContext6.java中处理请求
public class ServletContext6 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String name = (String)request.getAttribute("name") ;
System.out.println("在这里处理转发过来的数据: " + name);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
我们访问:http://localhost:8080/Demo/servlet/ServletContext5
运行的结果:
在这里处理转发过来的数据: 张三
d.获取资源文件:
16、获取资源文件:
获取资源文件有三种方式:
1.采用 ServletContext对象获取
2.采用ResourceBundle类来获取
3.采用类加载器获取(推荐使用)
3个资源文件的路径为:
p1.properties:在src目录下
p2.properties:在包名下
p3.properties:在工程目录下,D:\tomcat\apache-tomcat-7.0.77\webapps\Demo\p3.properties
例如:
1.采用 ServletContext对象获取(只是路径不同而已):
// 获取p1资源文件的内容
public void test11() {
ServletContext sc = this.getServletContext();// 拿到全局对象
// 获取p1.properties文件的路径
String path = sc.getRealPath("/WEB-INF/classes/p1.properties");
System.out.println(path);
Properties pro = new Properties();// 创建一个Properties对象
try {
pro.load(new FileReader(path));// 加载文件
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(pro.get("k"));// 读取k的值
}
// 获取p2资源文件的内容
public void test12() {
ServletContext sc = this.getServletContext();// 拿到全局对象
// 获取p1.properties文件的路径
String path = sc.getRealPath("/WEB-INF/classes/com/test/context/p2.properties");
System.out.println(path);
Properties pro = new Properties();// 创建一个Properties对象
try {
pro.load(new FileReader(path));// 加载文件
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(pro.get("k"));// 读取k的值
}
// 获取p3资源文件的内容
public void test13() {
ServletContext sc = this.getServletContext();// 拿到全局对象
// 获取p1.properties文件的路径
String path = sc.getRealPath("/p3.properties");
System.out.println(path);
Properties pro = new Properties();// 创建一个Properties对象
try {
pro.load(new FileReader(path));// 加载文件
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(pro.get("k"));// 读取k的值
}
2.采用ResourceBundle类来获取:
// 采用resourceBunble拿取资源文件:获取p1资源文件的内容 默认路径是src,对用到web环境就是classes目录
public void test21() {
// 拿取ResourceBundle对象(专门用来获取properties文件的信息)
ResourceBundle rb = ResourceBundle.getBundle("p1");
System.out.println(rb.getString("k"));
}
// 采用resourceBunble拿取资源文件:获取p2资源文件的内容
public void test22() {
// 拿取ResourceBundle对象(专门用来获取properties文件的信息)
ResourceBundle rb = ResourceBundle.getBundle("com.test.context.p2");
System.out.println(rb.getString("k"));
}
3.采用类加载器获取:
// 采用类加载器拿取资源文件:获取p1资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
public void test31() {
// 获取类加载器的方式
/*
* 1. 通过类名 ServletContext7.class.getClassLoader()
* 2. 通过对象this.getClass().getClassLoader()
* 3. Class.forName("ServletContext7").getClassLoader()
*/
InputStream in = this.getClass().getClassLoader().getResourceAsStream("p1.properties");
Properties pro = new Properties();// 创建Properties对象
try {
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(pro.getProperty("k"));// 拿取文件的数据
}
// 采用类加载器拿取资源文件:获取p2资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
public void test32() {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("com/test/four/p2.properties");
Properties pro = new Properties();// 创建Properties对象
try {
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(pro.getProperty("k"));// 拿取文件的数据
}
// 采用类加载器拿取资源文件:获取p3资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
public void test33() {
InputStream in = this.getClass().getClassLoader().getResourceAsStream("../../p3.properties");
Properties pro = new Properties();// 创建Properties对象
try {
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(pro.getProperty("k"));// 拿取文件的数据
}
// 采用类加载器拿取资源文件:获取p3资源文件的内容 : 默认路径是src,对用到web环境就是classes目录
public void test34() {
URL url = this.getClass().getClassLoader().getResource("p1.properties") ;
String path = url.getPath() ;
Properties pro = new Properties();// 创建Properties对象
try {
pro.load(new FileReader(path));
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(pro.getProperty("k"));// 拿取文件的数据
}
三种方式优缺点:
a): 采用servletContext对象获得.
优点: 任意文件,任意路径都可获得
缺点: 必须在web环境下
b): 采用resourceBundle获得
优点: 非web环境下
缺点: 只能获取properties文件
c): 采用类加载器获得
优点: 任意路径,任意文件