一、Servlet简介

1、Servlet是sun公司提供的一门用于开发动态web资源的技术,Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:

1.编写一个Java类,实现servlet接口.2.把开发好的Java类部署到web服务器中.例:

package com.itcast.servlet;

import java.io.IOException;
import javax.servlet.*; public class ServletTest extends GenericServlet{
@Override
public void service(ServletRequest arg0, ServletResponse arg1)
throws ServletException, IOException {
arg1.getOutputStream().write("ServletTest".getBytes());
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<servlet>
<servlet-name>ServletTest</servlet-name>
<servlet-class>com.itcast.servlet.ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletTest</servlet-name>
<url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
</web-app>

浏览器中输入http://localhost:8080/工程名(可选)/ServletTest即可看到显示的内容.

二、Servlet在web应用中的位置

ps:web应用目录也就是web根目录.

三、servlet的调用过程和生命周期

1、从浏览器输入http://localhost:8080/servletTest/ServletDemo,到看到hello word!页面的整个访问流程:

1>浏览器根据localhost:8080基于TCP连接,连接到web服务器

2>发送http请求到web服务器

3>web服务器从客户端发送的HTTP请求中依次解析出客户端要访问的主机、web应用、web资源

4>根据web.xml文件找到要访问的servlet资源,不管是不是静态资源都走servlet,静态资源由缺省的servlet管理,这个servlet在tomcat中,利用反射创建servlet实例对象,经过测试发现无论多少个客户端,servlet只在第一次被访问时创建一个

5>servlet实例对象调用init方法完成servlet对象的初始化

6>创建代表请求的request对象和代表响应的response对象(request和response在每次请求时都会创建),然后调用service方法响应客户端请求

7>service执行会向response对象写入向客户端输出的数据

8>服务器从response中取出数据,构建一个HTTP响应,返回给客户端

9>浏览器解析HTTP响应,提取数据显示

2、servlet生命周期

在客户端第一次访问的时候创建servlet对象,执行init方法完成初始化,之后这个servlet对象常驻内存,然后执行service响应客户端请求,每次请求来了都会执行该方法,在服务器关闭的时候执行destory方法摧毁servlet对象.

四、在Eclipse中开发Servlet

1、在eclipse中新建一个web project工程,eclipse会自动创建下图所示目录结构:

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

五、Servlet的一些细节

1、同一个Servlet可以被映射到多个URL上,即多个<servlet-mapping>元素的<servlet-name>子元素的设置值可以是同一个Servlet的注册名.

2、在Servlet映射到的URL中也可以使用*通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,另一种格式是以正斜杠(/)开头并以“/*”结尾.(/adc/*.do这种是错误的)这样有时一个URL可以匹配多个映射,例:

3、Servlet是一个供其他Java程序(Servlet引擎也就tomcat服务器)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度.针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁.在Servlet的整个生命周期内,Servlet的init方法只被调用一次.而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法.对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doXXX方法.那么有个问题大量并发的请求下会创建很多request和response服务器会不会崩掉呢,这里不会,因为request和response的生命周期很短,一闪而过,这样不会同时创建很多的对象.

4、如果在<servlet>元素中配置了一个<load-on-startup>元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法,中间数字代表启动级别,越小越先启动.

<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<load-on-startup></load-on-startup>
</servlet>

5、缺省的servlet

如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet. 凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求. 在<tomcat的安装目录>\conf\web.xml文件中(这个文件是所有web应用共享的),注册了一个名称为org.apache.catalina.servlets.DefaultServlet的Servlet,并将这个Servlet设置为了缺省Servlet,并且设置了<load-on-startup>1</load-on-startup>,也就是服务器启动的时候就创建了这个servlet.当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Servlet,也就是所有的请求过来都会先访问servlet,如果servlet能与对于的请求URL匹配,则访问servlet资源,如果servlet资源没有与URL匹配的,那么就会去访问这个缺省的servlet,去静态资源中寻找,如果还找不到就会返回客户端找不到资源页面.所以自己不要映射缺省的servlet,否则所有的静态资源将不能访问.

六、Servlet的线程安全问题

1、当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,比如同一个文件,数据,数据库等等,就有可能引发线程安全问题.

例1,这个代码是不会有线程问题,因为没有共享资源,每个线程来了都会创建一个i:

public class ServletTest extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int i=;
i++;
resp.getOutputStream().write(("i="+i).getBytes());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}

例2,这个代码有线程问题,i是共享资源,

public class ServletTest extends HttpServlet{
int i=;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
i++;
resp.getOutputStream().write(("i="+i).getBytes());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}

例3:这个代码也有线程问题,静态变量是共享的,person类里面有一个静态的age

public class ServletTest extends HttpServlet{
int i=;
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Person p = new Person();
p.age++;
resp.getOutputStream().write(("p.age"+p.age).getBytes());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}

ps:这里面就有一个可能引发内存泄露的问题,比如Person里面有一个static的list,每个线程来了add一个元素,过段时间系统就会崩掉,这种静态的集合元素很容易引发内存泄露.

2、解决方法

  1>在共享资源上加同步块,但是不使用这种情况,否则客户端可能等很长时间.

  2>servlet实现SingleThreadModel接口(这时一个标记接口,里面啥都没有),但是servlet引擎在处理客户端请求的时候会针对每次请求创建一个servlet,自然没有线程问题,但是很明显时间久了会使内存崩溃,而且还有问题如下:

public class ServletTest extends HttpServlet implements SingleThreadModel{
int i=;
@Override//该子类方法不能抛出比父类更多的异常,所以很多异常必须处理
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
i++;
resp.getOutputStream().write(("i="+i).getBytes());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}

多个客户端访问,看到的i都是1,很明显不是我们想要的,所以这种方式已经废弃了,到目前为止,其实servlet还没有很好的处理线程问题.

七、把servlet自身学明白,再把服务器传递给servlet的对象搞明白(servlet是由服务器来调用的),整个servlet就学通了,服务器传递给servlet的对象有Request、Response、ServletConfig、ServletContext、Cookie、Session等.

1、ServletConfig

在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数.当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet(其实是一个servlet一个ServletConfig).进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息.例:

//ServletConfig用于封装servlet的配置
public class ServletConfigTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到一个参数
String value=this.getServletConfig().getInitParameter("data");
//得到所有的
Enumeration e= this.getInitParameterNames();
while(e.hasMoreElements()){
String a=(String) e.nextElement();
String v=this.getServletConfig().getInitParameter(a);
System.out.println(a+"="+v);
}
}
}
<servlet>
<servlet-name>ServletDemo5</servlet-name>
<servlet-class>cn.itcast.ServletDemo5</servlet-class>
<init-param>
<param-name>data</param-name>
<param-value>xxxx</param-value>
</init-param>
<init-param>
<param-name>data2</param-name>
<param-value>yyyy</param-value>
</init-param>
</servlet>

ps:这个对象的用处是有些数据不要程序中写死,可以通过配置的形式传递个程序,这样以后修改的话不用重新修改源代码编译,直接修改配置文件即可,而且写在配置中方便查找.

2、ServletContext

WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用,在服务器关闭时销毁,与具体的请求无法,注意这里与ServletConfig生命周期的区别.ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象.由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯.ServletContext对象通常也被称之为context域对象(ServletContext其实是一个容器,这个容器的作用范围是web应用程序范围).拿到ServletContext的两种方式如下:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//得到servletContext
ServletContext context=this.getServletConfig().getServletContext();
ServletContext context2=this.getServletContext();//可直接拿到
}

3、servletContext的应用场景

1、多个Servlet通过ServletContext对象实现数据共享,例:

public class ServletDemo8 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String value = (String) this.getServletContext().getAttribute("data");
response.getOutputStream().write(value.getBytes());
} }
public class ServletDemo7 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.getServletContext().setAttribute("data",);
}
}

ps: servletContext的这个应用场景可以用在聊天室中,具体写法,略.

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

web.xml中使用context-param配置,然后使用类似ServletConfig获取配置的getInitParameter,getInitParameter这俩个方法来拿到参数,类似数据库等数据可以这样配置.

 <web-app>
<context-param>
<param-name>data</param-name>
<param-value>zzzz</param-value>
</context-param>
</web-app>

3、实现Servlet的转发(转发客户端只有一次请求,重定向有多次)

因为servlet中不适合做输出,要使用一行一行write,一般转发给jsp去处理,开发中大量使用,例:

public class ServletDemo10 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String data="aaaaaaaaaa";
     //目前只学了这种,但是有线程问题
     this.getServletContext().setAttribute("data", data);
RequestDispatcher rd=this.getServletContext().getRequestDispatcher("/1.jsp");
rd.forward(request, response);
}
}
<html>
<body>
<font color="red">
<%
String data = (String)application.getAttribute("data");//application就是ServletContext
out.write(data);
%>
</font>
</body>
</html>

ps:线程问题,当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,如果他们都访问ServletContext时,这个ServletContext就是一个共享资源,会有线程问题,比如多个线程同时set一个key为data的数据,那么后一个线程可能覆盖前一个线程的值,从而出现问题,所以开发中这里一般使用request域.

4、利用ServletContext对象读取资源文件

1>第一种方式

private void test1() throws IOException {
    //注意目录的正确书写
InputStream in=this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
    //这时读取properties的固定步骤
Properties props=new Properties();
props.load(in);
System.out.println(props.getProperty("url"));
}

2、只用传统方式如下是不行的,如下:

private void test4() throws IOException {
//这种相对路径是tomcat的bin目录,所以这种方法要在该目录下建立文件夹classes,并把文件放在这里
FileInputStream in2=new FileInputStream("classes/db.properties");
Properties props=new Properties();
props.load(in2);
System.out.println(props.getProperty("url"));
}

3、先得到绝对路径,在用传统方式是可以的,这种相对于第一种方式来说也是有需求的,比如下载中要获得文件的名称,第一种方式直接转为了留无法获得,而这种通过截取path即可得到文件名.

private void test5() throws IOException {
//得到绝对路径
String path=this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");
FileInputStream in2=new FileInputStream(path);
Properties props=new Properties();
props.load(in2);
System.out.println(props.getProperty("url"));
}

ps:上面是在servlet中通过ServletContext来读取资源文件,但是实际开发中像加载数据库等配置文件是不会在servlet中来读取的,一般在dao中读取,这时按如下方式读取,不能传递ServletContext对象到dao层,破坏了软件编程思想.

//如果读取资源文件的程序不是servlet的话,
//就只能通过类转载器去读了,文件不能太大,太大会直接撑破内存,那么大文件怎么读取呢?
//用传递参数方法不好,耦合性高
public class UserDao { private static Properties dbconfig=new Properties();
static {
//方式一,这种类加载器只会加载一次,如果后期db.properties修改的话程序无法读到
InputStream in=UserDao.class.getClassLoader().getResourceAsStream("db.properties");
try {
dbconfig.load(in);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
//方式二,后期db.properties修改的话程序可以读到(建议使用)
URL url=UserDao.class.getClassLoader().getResource("db.properties");
String str=url.getPath();
//file:/C:/apache-tomcat-7.0.22/webapps/day05/WEB-INF/classes/db.properties
try {
InputStream in2=new FileInputStream(str);
try {
dbconfig.load(in2);
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
} catch (FileNotFoundException e1) {
throw new ExceptionInInitializerError(e1);
}
}
public void update() {
System.out.println(dbconfig.get("url"));
}
}

注:对于不经常变化的数据,在servlet中可以为其设置合理的缓存时间值,以避免浏览器频繁向服务器发送请求,提升服务器的性能.略

javaEE(3)_servlet基础的更多相关文章

  1. javaEE与JSP基础

     JSP基础 1. jsp的作用:  * Servlet:    > 缺点:不适合设置html响应体,需要大量的response.getWriter().print("<html ...

  2. JavaEE Day09 JavaScript基础

    之前学了html.css两种静态资源 JavaScript是另一种静态资源,今日内容[重点]:JavaScript(是一门编程语言,2days)基础 一.JavaScript简介 1.概念 JavaS ...

  3. _web基础_servlet基础

    一.了解Servlet的概念 Servlet定义:Servlet是基于Java技术的Web组件,由容器管理并产生动态的内容.Servlet引擎作为WEB服务器的扩展提供支持Servlet的功能.Ser ...

  4. javaEE(16)_Servlet监听器

    一.监听器原理 1.监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行. 2.监听器典型案例 ...

  5. javaEE(15)_Servlet过滤器

    一.Filter简介 1.Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, ...

  6. 01 HTTP协议_servlet基础

    一.定义 http(Hyper Text Transfer Protocol):超文本传输协议 二.作用 数据传输 三.概念 HTTP消息: 1.客户端发向服务器的请求消息 2.服务器回给客户端的响应 ...

  7. 添物不花钱学JavaEE(基础篇)-综述

    JavaEE由一堆基础标准组成.JavaEE开发一般需要如下工具和掌握如下内容: Java环境 Eclipse或其他开发工具 Tomcat容器或类似软件 Jsp/Servlet/Web/JDBC的掌握 ...

  8. JavaEE-01 JSP动态网页基础

    学习要点 B/S架构的基本概念 Web项目的创建和运行 JSP页面元素 MyEclipse创建和运行Web项目 Web程序调试 Web简史 web前端技术演进三阶段 WEB 1.0:信息广播. WEB ...

  9. IO笔记(学习尚硅谷java基础教程)

    一.基础知识 1. 在普通方法和测试方法中文件路径的差异 在普通方法中:文件路径相当于在当前项目中,而不是当前Module(以项目为基准) 在测试方法中:文件路径相当于在当前Module中,而不是当前 ...

随机推荐

  1. 51nod 1456【强连通,缩点,并查集】

    话说这道题的机遇是看到了http://blog.csdn.net/u010885899/article/details/50611895很有意思:然后就去补了这题 题意: 建最少的边使得给出的点相连. ...

  2. 换装demo随手记

    1 修补demo错误,使VirtualWorldExample可正常运行 CharacterGenerator.AssetbundleBaseURL 做如下修改 public static strin ...

  3. c语言里面你不知道的break与switch,contiune的用法

    前言:最近上完课在宿舍闲来无事,就拿起了C Primer Plus 这本书看,是自己入门编程的第一门语言:看了一些基本语法知识点,最让我需要总一下的是就是标题所说的这个语法知识点,记得大一的时候去考计 ...

  4. extern使用方法总结!(转)

    extern 在源文件A里定义的函数,在其它源文件里是看不见的(即不能访问).为了在源文件B里能调用这个函数,应该在B的头部加上一个外部声明: extern   函数原型: 这样,在源文件B里也可以调 ...

  5. shell 中的if语句

    if [ t != "." -a t != ".." ] 之前一直不知道 -a 是什么意思,后来才知道     -a = and  ;    -o = or

  6. MDX查询语句

    另:15个经典的MDX查询语句 另:http://www.cnblogs.com/biwork/p/3437959.html 1.排名+排序+量值过滤: WITH member [Measures]. ...

  7. 怎么样去优化我们的SQL语句

    1.改写in 在SQL语言中,一个查询块可以作为另一个查询块中谓词的一个操作数.因此,SQL查询可以层层嵌套.例如在一个大型分布式数据库系统中,有订单表Order.订单信息表OrderDetail,如 ...

  8. 按位&按位|按位~的详解

    十进制转二进制: 例:十进制(5)---->二进制(00000101) 将整数除二取余,继续用除二的结果除二取余,最后将结果从下往上连接起来,不足八位,前面填0 二进制转十进制 例:二进制(00 ...

  9. ajax学习和总结

    Jquery AJAX http://www.cnblogs.com/jayleke/archive/2012/08/10/2633174.html http://www.php100.com/htm ...

  10. Yslow使用方法

    Yslow是雅虎开发的基于网页性能分析浏览器插件,从年初我使用了YSlow后,改变了博客模板大量冗余代码,不仅提升了网页的打开速度,这款插件还帮助我分析了不少其他网站的代码,之前我还特意写了提高网站速 ...