Servlet

Servlet

Servletsun公司提供的一种用于开发动态web资源的技术

为了方便web服务器对动态web资源的管理,sun公司在其api中定义了一个Servlet接口

服务器针对接口进行调用,我们编写的应用程序针对接口进行实现

 

习惯性地,我们把实现了Servlet接口的java类统称为Servlet

1. javaweb 学什么

用 java 语言开发动态的web资源,接下来就是介绍如何开发动态的web资源

对于java程序员而言,所谓动态web资源就是可以运行在服务器上的java程序

2. 实现服务器管理java程序

开发人员写好一个java,到底有哪些方法tomcat服务器是不可能知道的

tomcat服务器需要执行我们编写的java类就需要知道我们的java类有哪些方法,然后在适当的时间调用这些方法所以我们在写的java程序要想运行在服务器上就必须要实现一个特殊的接口 Servlet.java

 

interface Servlet { ... }

Servlet 接口中就定义了可以被tomcat服务器调用的java方法

通常来讲,我们将实现了Servlet接口的java类称之为 Servlet

 

编写好的Servlet需要web.xml文件中做配置才能供外界访问

 

3. 实现第一个Servlet程序

3.1  写一个java类实现Servlet接口

package cn.itcast.servlet;

 

import java.io.*;

import javax.servlet.*;

 

public class HelloWorldServlet extends GenericServlet

{

 

// 实现 service 方法

public void service(ServletRequest request,ServletResponse response)

throws ServletException,java.io.IOException  {

 

// 向浏览器输出一句话

PrintWriter out = response.getWriter();

out.write("hello world!!!");

 

}

 

public void init()throws ServletException {

// 初始化 servlet 时被调用

System.out.println("init()");

}

 

public void destroy() {

// 摧毁 servlet 时被调用

System.out.println("destroy()");

}

}

 

 

3.2.  导入 servlet jar

set classpath=%classpath%;D:\apache-tomcat-6.0.20\lib\servlet-api.jar 3.3. 编译带包的类

javac -d . HelloWorldServlet.java

3.4. 将包拷贝至 day05/WEB-INF/classes 目录下  --> 发布 web 工程

 

3.5. 在 web.xml 文件中做映射

<!-- servlet映射 -->

<!-- servlet元素用于给一个类起别名 -->

<servlet>

<servlet-name>HelloWorldServlet</servlet-name>

<servlet-class>cn.itcast.servlet.HelloWorldServlet</servlet-class>

</servlet>

<!-- servlet-mapping元素用于将一个Servlet映射到url -->

<!—url必须以/开头,表示当前web应用即上下文路径 -->

<servlet-mapping>

<servlet-name>HelloWorldServlet</servlet-name>

<url-pattern>/HelloWorldServlet</url-pattern>

</servlet-mapping>

 

注意: servlet 对象一旦创建就会驻留在内存中,为所有的请求服务,什么时候销毁

直到服务器关闭时或web应用被移除才销毁

 

3.6. Servlet 执行流程图

 

 

4. 用 eclipse 工具开发 Servlet

 4.1. 建一个 web project

 4.2. src下建包,创建一个java类实现Servlet接口

 4.3  在 Webroot\WEB-INF\web.xml 做 servlet 映射

4.4  配置 tomcat 服务器

window--> preferences --> tomcat6.x

4.5  web工程发布至tomcat 服务器

发布的web应用名称可以配置: web工程右键 选properties-->myeclipse-->web

默认情况使用工程名作为发布后的web应用名

 

4.6 启动tomcat服务器运行程序

 

5. HttpServlet对象

一般来讲我们开发一个Servlet会去继承 HttpServlet

在 eclipse 下开发Servlet 可以直接新建一个Servlet, 覆写 HttpServlet 的 doGetdoPost方法

继承 HttpServlet 的原因是: HttpServlet实现了service方法,将ServletRequstServletResponse

强转为子类 HttpServletRequestHttpServletResponse,让我们用起来更加方便,同时,在service方法中,它判断了请求方式,根据请求方式来调用 doGet 和 doPost

 

 Servlet 细节

1. * 号统配符

一个Servlet可以映射为多个路径

在映射 Servlet 路径时可以使用‘/*’ 或 ‘*.扩展名’ 的形式

注意两者不能同时使用

/* 具有较高的优先级

 

2. load-on-startup 元素

<servlet>元素下可以配置< load-on-startup>子元素,

配置方式如下:

<load-on-startup>1</load-on-startup>

如果一个Servlet配置了该项,web容器会在web应用被加载时就初始化该Servlet,数字越小则越先初始化

 

3. tomcat\conf\web.xml

服务器下所有web 应用中的web.xml 都会自动继承该文件中所有的配置

http://localhost:8080/day05/a.html     a.html是资源名

上面的url访问的urlweb.xml文件中并没有配置

此时会去访问缺省的Servlet,在tomcat\conf\web.xml文件中就配置了一个缺省的DefaultServlet  DefaultServlet帮我们去web应用下读取 a.html 文件,并打给浏览器,如果没有发送 404 页面

也就说,我们通过ie访问服务器访问的都是 Servlet

 

4. Servlet线程安全问题

解决Servlet线程安全问题: 加上同步的锁(lock)

 

 实现SingleThreadModel接口的Servlet

服务器会做判断,当有请求过来,如果Servlet对象忙着呢,服务器会再创建一个Servlet对象为用户

提供服务,如果Servlet闲置,就直接提供服务

这样的方式实际上是回避了线程安全问题, 单线程访问Servlet, 这样的方式不可取

 ServletConfig 对象

 

作用 : 封装 Servlet 初始化参数

1. 可以在 web.xml 文件中 Servlet 元素下 为Servlet配置初始化参数

<init-param>

     <param-name>name</param-name>

     <param-value>aaaa</param-value>

</init-param>

2. web 容器在初始化Servlet时,会将初始化参数封装到一个 ServletConfig 对象中,传给init方法

3. 我们在Servlet 中覆写 init方法,就可以获得ServletConfig

4. 父类 GenericServlet 中定义了一个成员变量用于记住此对象,并提供了 getServletConfig 方法

我们可以直接调用此方法 获得 config 对象

5. 再调用 getInitParameter(name) 方法获得想要配置项

// 指定编码

// 获得ServletConfig 对象

ServletConfig config = getServletConfig();

String encoding = config.getInitParameter("encoding");

System.out.println("encoding=" + encoding);

ServletContext 对象

 

1. ServletContext对象代表整个web应用

2. ServletContext对象是一个域对象(可以存储数据的对象)

ServletContext对象的内部维护了一个map集合, keyString类型 valueObject类型

class ServletContext {

private Map<String, Object> map ; 

}

通常来讲,我们会将全局的数据存入 ServletContext 域对象

3. ServletContext 作为域对象, 多个Servlet 可以共享数据

Servlet6

// 1. 获得ServletContext 对象

ServletContext context = getServletContext();

// 2. 存入域

context.setAttribute(“name”, “zhangsan”);

Servlet7

// 获得 context 域, getAttribute

String name = (String) getServletContext().getAttribute("name");

4.获取web应用的初始化参数

getContext().getInitParameter(“name”);

5. 统计一个web应用的访问量

   在 context 域中维护一个count变量

  访问Servlet时,取出变量 加1

6. 实现请求转发

实现请求转发需要用到 转发对象 RequestDispatcher 

有一个 forward 方法能转发请求

7. 如何读取工程中的文件

7.1.  读取web工程下的资源文件

// 获得绝对路径

      String realPath = ServletContext.getRealPath(相对web应用的路径);

注意URL url =  ServletContext.getResource();  weburl

// 获得与文件关联的流

InputStream in=

 ServletContext.getResourceAsStream(“WEB-INF/classes/config.properties”;

7.2   读取java工程下的文件

// 不能相对虚拟机目录 不能用绝对路径

  // 只能类加载的方式读

// 获得 流

ClassLoader classLoader = Demo.class.getClassLoader();

InputStream in = classLoader.getResourceAsStream("a.txt");

// 获得绝对路径

URL url = Demo.class.getClassLoader().getResource("a.txt");

String path = url.getPath();

类加载方式缺点

1) 不能读取类路径以外文件

2)  由于需要加载到内存,不能读大文件

web工程中如果用类加载的方式读

类加载实际上读取的是内存中加载的文件,此时将读不到硬盘上资源文件的修改

解决办法Demo.class.getClassLoader().getResource("a.txt").getPath()

通过绝对路径去读硬盘上的文件  避开内存的文件

Servlet缓存

 

HttpServlet 的 Service方法中的代码

// 调用方法

long lastModified = getLastModified(req);

// 如果为 -1 ,就直接放行,给最新的

            if (lastModified == -1) {

                doGet(req, resp);

}

// 方法返回不是-1  else {

// 读取IE发送的头If-Modified-Since

                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);

// 拿着客户端的时间头和方法的返回值比较

                if (ifModifiedSince < (lastModified / 1000 * 1000)) {

                    // If the servlet mod time is later, call doGet()

                    // Round down to the nearest second for a proper compare

                    // A ifModifiedSince of -1 will always be less

// 方法的返回值大于ie发送过来的时间头

// 重新向浏览器发送了一个时间头

                    maybeSetLastModified(resp, lastModified);

// 放行, 发送页面

                    doGet(req, resp);

                } else {

// 方法的返回值没有大于ie发送过来的时间头

// 发送 304 状态码,让用户去读缓存

                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

                }

            }

 

posted on 2013-07-11 08:46  笨'小孩  阅读(533)  评论(0编辑  收藏  举报

导航