Servlet
一、 第一个 Servlet 实现
Servlet 是 Server 与 Applet 的缩写,是服务端小程序的意思。使用 Java 语
言编写的服务 器端程序,可以像生成动态的 WEB 页, Servlet
主要运行在服务器端,并由服务器调用执行, 是一种按照 Servlet
标准来开发的类。 是 SUN 公司提供的一门用于开发动态 Web 资源的技
术。(言外之意:要实现 web 开发,需要实现 Servlet 标准)Servlet
本质上也是 Java 类,但要遵循 Servlet 规范进行编写,没有
main()方法,它的创 建、使用、销毁都由 Servlet 容器进行管理(如
Tomcat)。(言外之意:写自己的类,不用写 main 方法,别人自动调用)
Servlet 是和 HTTP 协议是紧密联系的,其可以处理 HTTP 协议相关的所有
内容。这也是 Servlet 应用广泛的原因之一。
提供了 Servlet 功能的服务器,叫做 Servlet 容器,其常见容器有很多,如
Tomcat, Jetty, WebLogic Server, WebSphere, JBoss 等等。
1. 实现
1.1新建Servlet继承HttpServlet类
1)、新建普通java类
2)、继承HttpServlet类
3)、重写service()方法
4)、配置web.xml文件,设置servlet对外访问 路径
注意事项:
1)、web.xml改动之后必须重启服务器
2)、url-pattern的值必须唯一
java.lang.IllegalArgumentException: The servlets named [servelt01] and
[servlet02] are both mapped to the url-pattern [/ser01] which is not
permitted
3)、servlet-mapping标签中的servlet-name的值必须是已存在的值(servalet标签中的servlet-name)
java.lang.IllegalArgumentException: Servlet mapping specifies an unknown
servlet name servelt02
4)、servlet标签中servlet-name要与servlet-mapping标签中的servlet-name的值保持一致
(servlet标签中servlet-name存在)
如果不一致,代码不会报错,只是访问的不是你的指定资源
5)、servlet标签中的servlet-class的路径不能写错
java.lang.ClassNotFoundException: com.shsxt.servlet.Servlet04
6)、servlet-mapping标签中的url-pattern的值前面必须加"/"
java.lang.IllegalArgumentException: Invalid
servlet mapping
7)、servlet标签中的servlet-name的值必须唯一
Duplicate unique value [servlet01] declared for identity constraint
"web-app-servlet-name-uniqueness" of element "web-app".
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 新建Servlet 继承HttpServlet类
* 1、新建普通java类
* 2、继承HttpServlet类
* 3、重写service()方法
* 4、配置web.xml文件,设置servlet对外访问 路径
* @author Lisa Li
*
*/
@SuppressWarnings("serial")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
System.out.println("Servlet01的创建....");
}
}
配置 web.xml
servletDemo
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
server01
com.shsxt.servlet.ServletDemo01
server01
/ser01
servlet01
com.shsxt.servlet.servlet01
servlet01
/ser02
5)、 发布项目并启动服务
到此,需要编写和配置的地方已经完成,项目已经完整了,但是如果需要外
界能够访问, 还需要将项目发布到服务器上并运行服务器
注意 url 的格式正确, tomcat 的端口为 8080。
6)、 访问并查看结果
在项目正确发布到服务器上之后,用户即可通过浏览器访问该项目中的资源。
到这里我们的第一个 Servlet 就实现了!
1.2方式二:继承GenericServlet类
* 1、新建普通java类
* 2、继承GenericServlet类
* 3、重写service()方法
* 4、配置web.xml文件,设置servlet对外访问 路径
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 方式二:继承GenericServlet类
* 1、新建普通java类
* 2、继承GenericServlet类
* 3、重写service()方法
* 4、配置web.xml文件,设置servlet对外访问 路径
* @author Lisa Li
*
*/
@SuppressWarnings("serial")
public class Servlet02 extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("Servlet02.....");
}
}
1.3方式三:实现Servlet接口
* 1、新建普通java类
* 2、实现Servlet接口
* 3、重写service()方法
* 4、配置web.xml文件,设置servlet对外访问 路径
public class Servlet03 implements Servlet {
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
System.out.println("Servlet03....");
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
2. 工作原理
执行过程
客户端发出请求 根据 web.xml 文件的配置,找到对应的 读取中的值 找到
对应的 找到该 class 并加载执行该 class,返回结果 由 Web 服务器将结果响
应给客户端
3. Servlet 的生命周期
Servlet 没有 main()方法,不能独立运行,它的运行完全由 Servlet 引擎来控
制和调度。 所谓生命周期,指的是 servlet 容器何时创建 servlet
实例、何时调
用其方法进行请求的处理、
何时并销毁其实例的整个过程。(此处讨论默认的生命周期)
实例和初始化时机
当请求到达容器时,容器查找该 servlet 对象是否存在,如果不存在,则会
创建实例并 进行初始化。
就绪/调用/服务阶段
有请求到达容器,容器调用 servlet 对象的 service()方法,处理请求的方法在
整个声明周 期中可以被多次调用;
HttpServlet 的 service()方法,会依据请求方式来调用 doGet()或者 doPost()
方法。但是, 这两个 do 方法默认情况下,会抛出异常,需要子类去
override。
销毁时机
当容器关闭时(应用程序停止时),会将程序中的 Servlet 实例进行销毁。
上述的生命周期可以通过 Servlet 中的生命周期方法来观察。在 Servlet 中
有三个生命周 期方法,不由用户手动调用,而是在特定的时机有容器自动调用,
观察这三个生命周期方法 即可观察到 Servlet 的生命周期。
1)init 方法,在 Servlet 实例创建之后执行(证明该 Servlet
有实例创建了)
2)service 方法,每次有请求到达某个 Servlet
方法时执行,用来处理请求(证
明该 Servlet 进行 服务了)
3)destroy 方法, Servlet 实例销毁时执行(证明该 Servlet
的实例被销毁了)
@SuppressWarnings("serial")
public class Servlet04 extends HttpServlet {
/**
* 初始化,服务器方式,由服务器调用
* 只会调用一次,当第一次请求时
* 当请求到达servlet时,servlet容器会判断该实例是否存在,如果不存在,才会调用该方法
*/
@Override
public void init() throws ServletException {
System.out.println("Servlet04 init....");
}
/**
* 服务/调用方法,服务器方式,由服务器调用
* 可以调用多次,每次请求到达时都会调用
*/
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet04...");
}
/**
* 销毁方法,服务器方式,由服务器调用
* 只会调用一次,容器关闭时(正常关闭时才会打印)
*/
@Override
public void destroy() {
System.out.println("Servlet04 destroy...");
}
}
3.1Servlet 的生命周期,
简单的概括这就分为四步:
servlet 类加载-->实例化-->服务-->销毁。下面我们描述一下 Tomcat 与
Servlet 是如何工作的,看看下面的时序图。
1)、 Web Client 向 Servlet 容器(Tomcat)发出 Http 请求
2)、 Servlet 容器接收 Web Client 的请求
3)、 Servlet 容器创建一个 HttpRequest 对象,将 Web Client 请求的信息封
装到这个对象 中
4)、 Servlet 容器创建一个 HttpResponse 对象
5)、 Servlet 容器调用 HttpServlet 对象的 service 方法,把 HttpRequest
对
象与 HttpResponse 对象作为参数,传给 HttpServlet 对象
6)、 HttpServlet 调用 HttpRequest 对象的有关方法,获取 Http 请求信息
7)、 HttpServlet 调用 HttpResponse 对象的有关方法,生成响应数据
8)、 Servlet 容器把 HttpServlet 的响应结果传给 Web Client
4. Servlet的配置
Servlet 除了配置基本的访问信息,还可以配置初始化参数,自启动等,并
且一个 Servlet 可以配置多个访问路径(),还可以使用通配符"*"。
4.1、初始化参数
* 设置在web.xml中的servlet标签中
*
*
*
*
4.2、自启动(服务器启动时自动实例化servlet)
*设置在web.xml中的servlet标签中,要写在init-param标签之后
*
*值越小,优先级越高
4.3、servlet配置多个访问路径
*以Servlet05为例:
a. 只设置一个路径
*
b.设置多个路径
*
*
c.以指定路径开头的所有资源路径
*
d.以指定后缀结尾的所有资源路径
e.所有路径都可以访问
*通配符"*"
1、"*"只能放在最前面或者最后面,不能放在中间,不能单独使用,不能和字母拼接
2、值越精准,优先级越高
普通Servlet05类
*/
@SuppressWarnings("serial")
public class Servlet05 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("Servlet05....");
}
@Override
public void init(ServletConfig config) throws ServletException {
// 得到指定名称的的初始化的值
String encode = config.getInitParameter("encode");
System.out.println(encode);
}
}
web.xml配置
servlet05
com.shsxt.servlet.Servlet05
encode
UTF-8
1
servlet05
/*
二、WEB请求和常用对象
1、 请求的方式
要访问服务器首先需要由客户端主动发出请求,在实际的操作中,我们可以
通过多种方式向服务器发起请求。
根据不同的场景需求,使用不同的请求方式可以达到不同的效果。
1.1. 地址栏输入
在浏览器地址栏直接输入要访问的地址即可,此种方式可以看做是访问服务
器的起始操作。
http://ip:port/path
1.2. 超链接
使用超链接也可以向服务器发出请求
尚学堂
1.3. Form 表单
当需要向服务器发送请求,并且传输一些用户输入的数据时,我们优先选择form
表单的方式发起请求
**1.4. ajax
**通过 ajax 发起的请求,属于异步请求,能实现局部刷新的效果,是一种比
较常用的请求方式。
通过 jQuery 中的 ajax(),get(),post(),getJSON()等方法都能发送请求
1.5. 请求转发
通过服务器内部将请求进行一次转发,可以请求到其他资源。
1.6. 重定向
服务器通过给定一个新资源的地址,响应会客户端后,客户端自动再次发送
一个请求到新资源的地址处。
2、 HttpServletRequest 对象
2.1. 介绍
HttpServletRequest 对象:
主要作用是用来接收客户端发送过来的请求信息,
例如:请求的参数,发送的头信息等都属于客户端发来的信息,
service()方法中形参接收的是 HttpServletRequest
接口的实例化对象,表示该对象主要应用在HTTP 协议上,该对象是由 Tomcat
封装好传递过来。
HttpServletRequest 是 ServletRequest 的子接口, ServletRequest 只有一个
子接口,就是 HttpServletRequest。既然只有一个子接口为什么不将两个接口合
并为一个?
从长远上讲:现在主要用的协议是 HTTP 协议,但以后可能出现更多新的
协议。若以后想要支持这种新协议,只需要直接继承 ServletRequest 接口就行
了。
在 HttpServletRequest 接口中,定义的方法很多,但都是围绕接收客户端参
数的。但是怎么拿到该对象呢?不需要,直接在 Service
方法中由容器传入过来,而我们需要做的就是取出对象中的数据,进行分析、处理。
2.2. 常用形式
package com.shsxt.servlet;
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 常用方法
* @author Lisa Li
*
*/
@SuppressWarnings("serial")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet01.....");
System.out.println("==============常用方法============");
// 获取请求的完整路径 (从http到"?"前面)
String url = request.getRequestURL() + "";
System.out.println("获取请求的完整路径:" + url);
// 获取请求的部分路径 (从端口后"?"前面)
String uri = request.getRequestURI();
System.out.println("获取请求的部分路径:" + uri);
// 获取请求的参数字符串 (从"?"开始到最后)
String queryString = request.getQueryString();
System.out.println("获取请求的参数字符串:" +queryString);
// 获取请求类型 (GET/POST)
String method = request.getMethod();
System.out.println("获取请求类型:" + method);
// 获取请求协议版本
String p = request.getProtocol();
System.out.println("获取请求协议版本:" + p);
// 获取站点名
String contextPath = request.getContextPath();
System.out.println("获取站点名:" + contextPath);
System.out.println("===========获取请求头==========");
// 获取指定请求头
String host = request.getHeader("host");
System.out.println("Host:" + host);
// 获取所有请求头的名称枚举集合
Enumeration enumeration = request.getHeaderNames();
while(enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
System.out.println("==========获取请求的参数===========");
// 获取指定名称的参数值
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
System.out.println("用户名:" + uname + ",用户密码:" +upwd);
// 获取指定名称的参数的所有值
String[] hobbys = request.getParameterValues("hobby");
// 判断并遍历
if (hobbys != null && hobbys.length > 0) {
for (String hobby : hobbys) {
System.out.println("爱好:" + hobby);
}
}
}
}
2.3 请求乱码解决
由于现在的 request 属于接收客户端的参数,所以必然有其默认的语言编码,
主要是由于在解析过程中默认使用的编码方式为 ISO-8859-1(此编码不支持中
文),所以解析时一定会出现乱码。要想解决这种乱码问题,需要设置 request
中的编码方式,告诉服务器以何种方式来解析数据。或者在接收到乱码数据以后,再通过相应的编码格式还原。
1)POST请求
* Tomcat8乱码
* Tomcat7乱码
*
2)GET请求
* Tomcat7乱码
* Tomcat8不会乱码
*
3)解决POST请求乱码:
* request.setCharacterEncoding("UTF-8"); //
设置服务器的编码方式,该方式只对post请求生效,如果是get请求没有任何效果
* new
String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
4)解决GET请求乱码:(如果原来不乱码,通过new
String()去处理,会出现另外一种乱码)
* new
String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
*
5)总结 :
* Post请求:无论什么版本的服务器,都乱码
* Get请求:Tomcat8及以上版本,不乱码;Tomcat7及以下版本乱码。
测试页面index.html
登录
servlet 程序
@SuppressWarnings("serial")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet02.....");
/* POST 请求*/
// 解决POST请求乱码问题
// request.setCharacterEncoding("UTF-8"); // 设置服务器的编码方式,该方式只对post请求生效,如果是get请求没有任何效果
// 接收参数
String uname = request.getParameter("uname");
//String upwd = request.getParameter("upwd");
System.out.println("姓名:" + uname);
// System.out.println("密码:" + upwd);
/* GET请求 */
String userName = new String(uname.getBytes("ISO-8859-1"),"UTF-8");
System.out.println("userName:" + userName);
}
2.4. 请求转发
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,
此时会将请求对象进行保存,地址栏中的 URL 地址不会改变,得到响应后,服
务器端再将响应发送给客户端, 从始至终只有一个请求发出。
实现方式如下,达到多个资源协同响应的效果。
request.getRequestDispatcher(url).forward(request, response);
* 1、服务器行为,服务器行为
* 2、地址栏不会发生改变
* 3、只有一次请求,request对象共享
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 请求转发
* request.getRequestDispatcher(url).forward(request, response);
*
* 1、服务器行为,服务器行为
* 2、地址栏不会发生改变
* 3、只有一次请求,request对象共享
* @author Lisa Li
*
*/
@SuppressWarnings("serial")
public class Servlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet03....");
// 获取参数
String uname = request.getParameter("uname");
System.out.println("Servlet03:" + uname);
// 请求转发跳转到指定页面
// request.getRequestDispatcher("index.html").forward(request, response);
// 请求转发跳转到指定servlet
request.getRequestDispatcher("ser04").forward(request, response);
}
}
2.5. request 作为域对象
通过该对象可以在一个请求中传递数据,作用范围: 在一次请求中有效,即
服务器跳转有效。
request.setAttribute():设置域对象内容;
request.getAttribute(String name):获取域对象内容;
request.removeAttribute(String name): 删除域对象内容
。
request 域对象中的数据在一次请求中有效,则经过请求转发, request 域
中的数据依然 存在,则在请求转发的过程中可以通过 request
来传输/共享数据。
package com.shsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* request域对象
* 将数据存到request作用域中,前台页面(JSP)从作用域中获取域对象的值
*
* setAttribute(name,value):设置作用域,name是字符串类型,value是object类型
* getAttribute(name):获取指定名称的域对象的值,返回的是object类型
* removeAttribute(name):移除指定名称的域对象的值
*
* @author Lisa Li
*
*/
@SuppressWarnings("serial")
public class Servlet05 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet05....");
// setAttribute(name,value):设置作用域,name是字符串类型,value是object类型
request.setAttribute("userName", "Lisa");
// 请求转发跳转到index.jsp
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}