[java]servlet编程

1.Servlet概述

Servlet是sun公司提供的一门用于开发动态web资源的技术。

Sun公司在其API中提供了一个servlet接口,用户若想使用Java程序开发一个动态web资源,只需编写一个servlet接口的实现类,并把这个类部署到web服务器中,就算开发好了一个动态web资源。

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

2.Servlet开发步骤

2.1手动开发Servlet程序

1)建立web应用目录结构。如:

-baidu
    -WEB-INF
        -classes
 
 
  • 1
  • 2
  • 3

2)在classes目录下建立FirstServlet.java代码,代码如下:

package com.baidu.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class FirstServlet extends GenericServlet {
    @Override
    public void service(ServletRequest request, ServletResponse response)throws ServletException, IOException {
        response.getOutputStream().write("hello servlet!!!".getBytes());
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3)设置servlet-api.jar的类路径(CLASSPATH),编译Java源文件。

set CLASSPATH=C: \tomcat6\lib\servlet-api.jar;
javac -d FirstServlet.java
 
 
  • 1
  • 2

* 也可使用javac -cp C: \tomcat6\lib\servlet-api.jar -d FirstServlet.java

4)在WEB-INF目录下建立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>FirstServlet</servlet-name>
        <servlet-class>com.baidu.servlet.FirstServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FirstServlet</servlet-name>
        <url-pattern>/first</url-pattern>
    </servlet-mapping>
</web-app>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

5)把web应用拷贝到tomcat/webapps目录下 
6)启动tomcat,在浏览器输入:http://localhost:8080/baidu/first,进行测试!

2.2 MyEcplise开发Servlet程序

1)在eclipse中新建一个web project工程,eclipse会自动创建下图所示目录结构: 
这里写图片描述 
example目录: web工程的名称,该工程部署时,在webapps目录下就会有一个example的web应用。

src目录:Java程序的开发目录,该目录下编写的所有java程序在部署时,会自动部署到example/web-inf/classes目录下。

WebRoot:webroot对应于web应用的根目录,该目录下的所有子目录和子文件在部署时,会原封不动的发布到web应用目录下。

2)在Ecplise里面配置Tomcat服务器 
找到windows->Preferences->MyEcplise->Servers->Tomcat6.x,然后按下图设置: 
这里写图片描述

=== 记得选择“Enable”,这样服务器才能在Ecplise的servers窗口被看到。===

3.Servlet的执行过程

浏览器输入:http://localhost:8080/demo10/hello

http:// http协议 
1)本地hosts文件查询域名和ip的映射 
2)找不到,联网到运营商的DNS服务起器找域名和ip的映射

8080 端口 
tomcat:8080

/demo10 站点下的web应用名称

/hello 资源名称。截取到/hello 字符串 
1)在demo10应用下的web.xml文件中查找是否存在匹配的url-pattern 
2)使用servlet的内部名称在web.xml文件中查找是否存在相同名称的servlet配置 
3)得到对应的servlet-class内容。 
字符串: gz.baidu.a_servlet.HelloServlet

通过反射构造HelloServlet对象,调用方法(doGet…….) 
输出内容到浏览器,看到效果!!!

这里写图片描述

4.Servlet的编写方式

Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServletHttpServlet

HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。

HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

5.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的对外访问路径。

Servlet映射的方式: 
1)映射到一个具体的地址: 
<url-pattern>/first</url-pattern> 
映射到具体地址是,必须以 / 开头

2)在后面使用通配符: 
<url-pattern>/first/*</pattern>

3)在前面使用通配符 
<url-pattern>*.do</url-pattern> 
表示只要以.do结尾的请求都会调用这个servlet

注意:不能出现这种形式<url-pattern>/first/*.do</url-pattern>

=========一些重要的问题=============== 
对于如下的一些映射关系: 
Servlet1 映射到 /abc/* 
Servlet2 映射到 /* 
Servlet3 映射到 /abc 
Servlet4 映射到 *.do

问题: 
当请求URL为“/abc/a.html”,“/abc/”和“/”都匹配,哪个servlet响应 
Servlet引擎将调用Servlet1。 
当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应 
Servlet引擎将调用Servlet3。 
当请求URL为“/abc/a.do”时,“/abc/”和“.do”都匹配,哪个servlet响应 
Servlet引擎将调用Servlet1。 
当请求URL为“/a.do”时,“/”和“.do”都匹配,哪个servlet响应 
Servlet引擎将调用Servlet2。 
当请求URL为“/xxx/yyy/a.do”时,“/”和“.do”都匹配,哪个servlet响应 
Servlet引擎将调用Servlet2。

6.Servlet的生命周期

6.1 Servlet中四个重要的生命周期方法

Servlet是受容器管理的,其生命周期都是由容器负责,包括如下几个阶段:

1) Servlet的类加载与实例化(调用构造方法) 
2) Servlet实例的初始化(调用init方法) 
3) Servlet提供服务(调用service方法) 
4) Servlet的销毁(调用destroy方法)

这里写图片描述

1)Servlet的类加载与实例化(指定Servlet对象创建时机) 
默认情况下,第一次访问时加载Servlet类并进行实例化。 
在部署时通过ClassLoader直接载入并实例化 
 配置式加载,通过load-on-startup 
 数值从0开始计数,值越低,那么载入的优先级越高。

 <servlet>
    <servlet-name>s1</servlet-name>
    <servlet-class>com.S1Servlet</servlet-class>
    <load-on-startup>3</load-on-startup>
</servlet>
<servlet>
    <servlet-name>s2</servlet-name>
    <servlet-class>com.S2Servlet</servlet-class>
    <load-on-startup>2</load-on-startup>
 </servlet>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

load-on-startup: 表示Servlet在部署时通过ClassLoader直接载入并初始化, 
数值越低(从0开始计数),载入的优先级越高。否则,用户第一次访问的时候才实例化Servlet。 
值相同,一般按在web.xml文件中的出现的顺序执行。

2)Servlet实例的初始化 
对Servlet将要使用的资源作初始化,如读入配置文件信息等(只执行一次)。 
容器是通过调用servlet的init方法来初始化servlet实例 
在此过程中,容器会创建ServletConfig对象并把它作为init方法的参数传入。 
该配置对象允许servlet从访问Web应用的配置信息中读取出初始化参数的名-值对。

init(ServletConfig config) 
该方法是在Servlet接口里提供的

init() 
该方法是在GenericServlet另外提供的目的是使得开发人员更简单的定制初始化动作开发人员可以对此方法进行重写。

3)Servlet提供服务(调用service方法) 
 初始化后,Servlet实例就成为了真正意义上的Servlet对象 
 容器会调用servlet的service()方法,向客户端提供服务 
 service()能够被多客户端多次调用(每个请求都要执行一次)

4)Servlet的销毁(调用destory方法) 
Servlet容器通过调用servlet的destroy()方法来终止一个servlet。 
destory方法在We服务器停止或Web应用被停止/重新加载时被调用。通常完成一些资源释放,停止后台程序等工作。释放或销毁一些非内存资源。destory只会调用一次。

6.2 伪代码模拟tomcat服务器如何调用servlet生命周期

浏览器输入: http://localhost:8080/demo10/hello

得到字符串: gz.baidu.a_servlet.HelloServlet

1)tomcat服务器通过反射构造对象 
1.1 得到字节码对象 
Class clazz = Class.forName(“gz.baidu.a_servlet.HelloServlet “); 
1.2 构造对象 
Object hello = clazz.newInstance(); –1) servlet的构造方法被调用

2)tomcat服务器调用init方法 
2.1 得到init方法对象 
Method m = clazz.getDeclareMethod(“init”,ServeletConfig.class); 
2.2 执行方法 
m.invoke(hello,config); –2)servlet的init方法被调用

3)tomcat服务器创建request和response对象,调用service方法 
2.1 得到service方法对象 
Method m 
= clazz.getDeclareMethod(“service”,HttpServletRequest.class,HttpServletRespnose.class); 
2.2 执行方法 
m.invoke(hello,request,response); –3)servlet的service方法被调用

4)tomcat服务器停止或web应用重新部署时,tomcat服务器调用destroy方法 
2.1 得到destroy方法对象 
Method m = clazz.getDeclareMethod(“destroy”,null) 
2.2 执行方法 
m.invoke(hello,null); –4)servlet的destroy方法被调用

6.3时序图描述servlet执行过程

这里写图片描述

7.Servlet线程安全问题

这里写图片描述

Servlet在web容器里是单实例多线程的。当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题

解决办法的两种办法: 
1)synchronized同步方式操作(可能会影响访问效率) 
2)SingleThreadModel接口(已经过时) 
如果某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。 
SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增加实现SingleThreadModel接口的声明即可。 
对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每个线程分别调用一个独立的Servlet实例对象。 
实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,因为Servlet引擎会创建多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过时的)。

开发出线程安全的Servlet的两点建议: 
1)将参数变量本地化。因为多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量(避免在servlet中使用实例变量)。 
例如:String user = “”; 
user = request.getParameter(“user”); 
2)确实需要访问全局资源时,考虑同步块(synchronized)操作。在使用同板块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。

8 ServletConfig对象

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

 <servlet>
        <servlet-name>FirstServlet</servlet-name>
        <servlet-class>com.baidu.servlet.FirstServlet</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>GBK</param-value>
        </init-param>
</servlet>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

ServletConfig的API: 
java.lang.String getInitParameter(java.lang.String name) –得到参数 
java.util.Enumeration getInitParameterNames()

ServletContext getServletContext() 得到servlet上下文对象 
java.lang.String getServletName() 得到servlet名称

主要用来读取web.xml中配置的Servlet初始信息,不能被其它Servlet共享。还可以用于访问ServletContext。

阅读ServletConfig API,并举例说明该对象的作用: 
获得字符集编码 
获得数据库连接信息 
获得配置文件

9.ServletContext对象

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用

ServletContext对象被包含在ServletConfig对象中,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得对ServletContext对象的引用。

由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。

查看ServletContext API文档,了解ServletContext对象的功能。

ServletContext应用场景: 
1) 多个Servlet通过ServletContext对象实现数据共享。

保存数据
public class ScopeDemo1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 把数据存储到ServletContext域对象
         */
        ServletContext context = this.getServletContext();
        //context.setAttribute("name", "eric");
        List list = new ArrayList();
        list.add("eric");
        list.add("jacky");
        list.add("rose");
        context.setAttribute("list", list);
        System.out.println("保存成功");
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
取出数据
public class ScopeDemo2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 从ServletContext域对象中取出数据
         */
        ServletContext context = this.getServletContext();
        //String name = (String)context.getAttribute("name");
        List list = (List)context.getAttribute("list"); 
        System.out.println(list);
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2) 获取WEB应用的初始化参数。

<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">
    <!-- 全局参数配置 -->
    <context-param>
        <param-name>AAA</param-name>
        <param-value>AAA'value</param-value>
    </context-param>
    <context-param>
        <param-name>BBB</param-name>
        <param-value>BBB'value</param-value>
    </context-param>
</web-app>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
/**
 * 【context对象作用2】-获取全局参数
 */
public class ContextDemo2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        /**
         * 得到全局参数
         */
        ServletContext context = this.getServletContext();
        System.out.println(context.getInitParameter("AAA"));    
        //遍历所有参数
        Enumeration<String> enums = context.getInitParameterNames();
        while(enums.hasMoreElements()){
            String paramName = enums.nextElement();
            String paramValue = context.getInitParameter(paramName);
            System.out.println(paramName+"="+paramValue);
        }           
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

3) 实现Servlet的转发。

/**
 * 【context对象作用4】--请求转发
 */
public class ForwardDemo extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         // 转发:服务器行为
         // :/
        ServletContext context = this.getServletContext();
        RequestDispatcher rd = context.getRequestDispatcher("/hello.html");
        rd.forward(request, response);
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4) 利用ServletContext对象读取资源文件。 
 得到文件路径 
 读取资源文件

/**
 * 【context对象作用5】--读取web项目的资源文件
 */
public class ResourceDemo extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        /**
         * 1)getRealPath()  获取资源文件的真实路径
         */
        String path = this.getServletContext().getRealPath("/WEB-INF/classes/news.properties");
        System.out.println(path);

        /**
         * 2)getResourceAsStream() 获取资源文件的输入流
         */
        InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/news.properties");

        FileInputStream in = new FileInputStream(new File(path));
        //1)使用Properteis对象
        Properties prop = new Properties();
        //2)使用load方法加载properties文件
        prop.load(in);
        //3)通过getProperty()获取内容
        System.out.println(prop.getProperty("name"));
        System.out.println(prop.getProperty("password"));       
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值