服务端技术|认识servlet

第一章 Servlet

1.1. Servlet简介

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

Servlet是一个小的java程序,能接收和响应从客户端发送过来的请求,使用的是HTTP的协议。

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

编写一个Java类,实现servlet接口。

把开发好的Java类部署到web服务器中。

1.2. Servlet的开发步骤

编写普通的类,实现Servlet接口,重写5个方法。在WEB程序的web.xml文件进行配置

1
2
3
4
5
6
7
8
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>cn.itcast.servlet.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/demo1</url-pattern>
</servlet-mapping>

1.3. 工程目录

1.4. 完成Servlet入门程序

访问流程:

1.5. Servlet生命周期(面试题)

init()方法:服务器调用该方法初始化Servlet

service()方法:初始化完毕,服务器调用该方法响应客户的请求

destroy()方法:服务器调用该方法消灭servlet对象

其中,init()方法只在Servlet第一次被请求加载的时候被调用一次,当有客户再请求Servlet服务时,Web服务器将启动一个新的线程,在该线程中,调用service方法响应客户的请求

总结:

Servlet实例被Tomcat服务器创建,第一次访问时创建(在内存中Servlet是一个单例模式,在开发中要注意,尽量不要定义成员属性),会立即调用init()方法创建,使用service方法对外提供服务,service方法只要有一次请求就会调用一次,当项目被移除,或者tomcat服务器关闭时,会调用destory方法销毁Servlet,destory()也是调用一次,(一般在释放资源是使用)

1.6. 关于Servlet生命周期

Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。

针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。

在Servlet的整个生命周期内,Servlet的init方法只被调用一次。而对一个Servlet的每次访问请求都导致Servlet引擎调用一次servlet的service方法。对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法,service方法再根据请求方式分别调用doGet或doPost方法。

1.7. Servlet的运行过程

Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:

1,.Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。

2.装载并创建该Servlet的一个实例对象。

3.调用Servlet实例对象的init()方法。

4创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。

5.WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

第二章 Servlet接口实现类

二.1. 两个实现类

Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet(抽象类)、HttpServlet(继承GenericServlet)。

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

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

2.2. 当继承了HttpServlet的注意事项

Servlet初始化时覆盖init() ,无需覆盖init(config)

根据Http请求的方式,覆盖相应的doGet或者doPost方法,无需覆盖Service方法

当doGet和doPost代码逻辑相同时,可以相互调用,简化编程

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package cn.yueqian.service;

import java.io.IOException;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Servlet2 extends HttpServlet {

/*
* // doGet处理get请求的数据
*
* @Override protected void doGet(HttpServletRequest req, HttpServletResponse
* resp) throws ServletException, IOException { // 获取客户端的数据
*
* String username = req.getParameter("username"); String password =
* req.getParameter("password");
* System.out.println("get请求:"+"账号是:"+username+"密码是:"+password); }
*
* // doPost处理post请求的数据
*
* @Override protected void doPost(HttpServletRequest req, HttpServletResponse
* resp) throws ServletException, IOException { // 获取客户端的数据 String username =
* req.getParameter("username"); String password = req.getParameter("password");
* System.out.println("post请求:"+"账号是:"+username+"密码是:"+password); }
*/

// 以上的方式,在开发中是不常用的
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取客户端的数据
String username = req.getParameter("username");
String password = req.getParameter("password");
String method = req.getMethod();
System.out.println(method + "请求:" + "账号是:" + username + "密码是:" + password);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 如果,在开发中,get请求的逻辑与post请求的逻辑一样,则可以直接使用将代码到doGet方法中执行
doGet(req, resp);
}
}

2.3. Web开发中的路径问题分析

Web系统中的相对路径和绝对路径

相对路径:hello ./hello ../myweb/hello

绝对路径:/hello /myweb/hello

服务器端和客户端对于/ 的区别l 客户端关于路径问题的编程结论:

*.html *.jsp 内都使用绝对路径

*.css 内部使用相对路径—- 背景图片

*.js中使用绝对路径

在开发中:前端美工人员用相对路径多我们用绝对路径比较多

2.4. init方法中的ServletConfig对象

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

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

阅读ServletConfig API,并举例说明该对象的作用:

获得配置文件,查看struts案例的web.xml文件l

案例:在web.xml文件中配置信息,并读取信息

步骤:

配置web.xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<servlet>
<servlet-name>Servlet3222</servlet-name>
<servlet-class>cn.yueqian.service.Servlet3</servlet-class>
<!-- 在web.xml文件中配置:ServletConfig信息 -->
<init-param>
<param-name>username</param-name>
<param-value>zhangsan</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>aaaaa</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Servlet3222</servlet-name>
<url-pattern>/Servlet3</url-pattern>
</servlet-mapping>

Servlet代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package cn.yueqian.service;

import java.io.IOException;
import java.util.Enumeration;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* ServletConfig对象
* @author newuser
*
*/
public class Servlet3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//得到ServletConfig对象
ServletConfig config = this.getServletConfig();
//得到Servlet名字
String servletName = config.getServletName();
System.out.println("servletName=="+servletName);
//如果你 将一些通用的信息直接写在servlet中,如果数据变化,则要修改源码
String username = config.getInitParameter("username");
String password = config.getInitParameter("password");
System.out.println("username=="+username+",password=="+password);
//读取所有数据
Enumeration<String> names = config.getInitParameterNames();//本质是一个map集合
//遍历枚举
while(names.hasMoreElements()) {
//得到name
String name = names.nextElement();
//得到值
String value = config.getInitParameter(name);
System.out.println("name=="+name+",value=="+value);
}

}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

}

2.5. Web应用对象:ServletContext(重要)

二.6. 域对象的方法

所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:

void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute(“xxx”, “XXX”),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;

Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)servletContext.getAttribute(“xxx”);,获取名为xxx的域属性;

void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;

Enumeration getAttributeNames():获取所有域属性的名称;

二.7. ServletContext应用

获取WEB应用的全局初始化参数 读取:

通过ServletContext对象实现数据共享

案例— 统计站点访问次数l 代码:是用两个Servlet来模拟的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 统计访问量
* @author newuser
*
*/
public class Servlet5 extends HttpServlet{
@Override
public void init() throws ServletException {
//往ServletContext域中存放数据:访问量
ServletContext context = this.getServletContext();
context.setAttribute("count", 0);
}

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context = this.getServletContext();
//获得Context域中的变量:访问量
Integer count = (Integer)context.getAttribute("count");
count++;
//重新设置后ServletContext域中
context.setAttribute("count", count);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

}



/**
* 统计访问量:显示
* @author newuser
*
*/
public class Servlet6 extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//得到ServletContext对象
ServletContext context = this.getServletContext();
//获得Context域中的变量:访问量
Integer count = (Integer)context.getAttribute("count");
//处理中文乱码
resp.setContentType("text/html;charset=UTF-8");

resp.getWriter().append("<h1>访问量---->"+count+"</h1>");

}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}

}