一、学习目标
- 理解Servlet的工作原理
- 理解Servlet的生命周期
- 掌握常用的Servlet API
- 会使用Servlet处理用户的请求
- 会通过注解配置Servlet
二、Servlet和Servlet容器
JavaWeb程序,运行于服务器端、运行时需要Servlet容器支持
Servlet
- 一个基于Java技术的Web组件
- 用于处理Web请求,生成动态内容
- 运行于服务器端,由Servlet容器创建并调用
Servlet容器
用于管理Servlet,包括加载、实例化和销毁Servlet
三、Servlet与JSP之间的关系
创建index.jsp文件,输出 “这是我的JSP页面!”
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>测试JSP</title><head>
<body>这是我的JSP页面!<br></body>
</html>
启动项目,访问index.jsp,生成index_jsp.java文件
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements …// 省略部分代码{
out.write("<html>\n");
out.write(" <head>\n");
out.write(" <title>测试JSP</title>\n");
out.write(" </head>\n");
out.write(" <body>\n");
out.write("这是我的JSP页面!<br>\n");
out.write(" </body>\n");
out.write("</html>\n");
// 省略部分代码
}
结论: JSP就是Servlet
JSP在运行时,Web容器会将其翻译成一个Servlet类,执行这个Servlet类中的方法,向浏览器动态响应内容。
四、Servlet体系结构
4.1Servlet结构图
4.2Servlet 4.0.1 API的两个包
1、javax.servlet包
定义并描述Servlet组件和运行环境之间的协定
通用的不依赖协议的Servlet API定义在此包中
主要包括Servlet
、ServletRequest
、ServletResponse
、ServletConfig
、ServletContext
接口及抽象类 GenericServlet
2、javax.servlet.http
支持HTTP协议的Servlet API定义在此包中
主要包括 HttpServlet、HttpServletRequest、 HttpServletResponse等
4.3Servlet接口
Servlet接口中定义了Servlet对象必须实现的方法
目录 | 说明 |
---|---|
void init(ServletConfig config) | Servlet对象的初始化方法 由Servlet容器调用 |
void service(ServletRequest request, ServletResponse response) | 处理客户端的请求 由Servlet容器调用 |
void destroy() | 释放Servlet对象所使用的资源 由Servlet容器调用 |
ServletConfig getServletConfig() | 返回传递给init()方法的ServletConfig对象,该对象包含此Servlet的初始化和启动参数 |
String getServletInfo() | 返回字符串文本形式的Servlet相关信息 |
4.4GenericServlet抽象类
提供了Servlet与ServletConfig接口方法的默认实现,但不包括service()方法
目录 | 说明 |
---|---|
public void init(ServletConfig config) | 实现Servlet接口中init(ServletConfig config)方法将ServletConfig实例进行保存以备用 |
public void init() | 用于在子类中重写,以实现用户订制的初始化工作 |
public String getInitParameter(String name) | 返回web.xml中名称为name的初始化参数的值 |
public ServletContext getServletContext() | 返回ServletContext对象的引用 |
4.5HttpServlet抽象类
针对HTTP协议提供了相关的支持,我们创建Servlet都是继承自HttpServlet
目录 | 说明 |
---|---|
public void service(ServletRequest request,ServletResponse response) | 实现GenericServlet抽象类中的service()方法,根据请求方法的类型调用相应的doGet()或doPost方法 |
protected void service(HttpServletRequest request, HttpServletResponse response) | 接收HTTP请求,并将它们分发给此类中定义的一系列doXxx()方法 |
protected void doXxx(HttpServletRequest request,HttpServletResponse response) | 根据请求方式的不同分别调用的相应处理方法,如doGet()、doPost()等 |
4.6ServletContext接口
ServletContext接口主要用于获取Web应用上下文,与Servlet容器进行通信,application内置对象即为ServletContext实例。
目录 | 说明 |
---|---|
String getInitParameter(String name) | 获取应用范围中名为name的初始化参数值,在web.xml中使用<context-param> 元素定义 |
void setAttribute(String name, Object object) | 设置名称为name的属性 |
Object getAttribute(String name) | 获取名称为name的属性 |
void removeAttribute(String name) | 从Servlet上下文中删除指定名称的属性 |
String getRealPath(String path) | 返回参数所代表目录的真实路径 |
void log(String message) | 记录一般日志信息 |
4.5请求响应相关结构
4.6ServletRequest接口
ServletRequest接口主要用于获取客户端请求数据
目录 | 说明 |
---|---|
Object getAttribute(String name) | 获取请求域中名称为name的属性值 |
void setAttribute(String name, Object object) | 在请求域中保存名称为name的属性 |
void removeAttribute(String name) | 清除请求域中名字为name的属性 |
String getCharacterEncoding() | 返回请求体所使用的字符编码 |
void setCharacterEncoding(String charset) | 设置请求体的字符编码 |
String getParameter(String name) | 返回指定请求参数的值 |
String [ ] getParameterValues(String name) | 返回指定请求参数的全部值 |
RequestDispatcher getRequestDispatcher(String path) | 返回指向指定路径的请求分发对象 |
4.7HttpServletRequest接口
HttpServletRequest接口继承
ServletRequest
接口中的方法,增加了用于读取HTTP请求信息的方法
目录 | 说明 |
---|---|
String getContextPath() | 返回请求的上下文路径,上下文路径是请求URI的开始部分 |
Cookie [ ] getCookies() | 返回客户端在此次请求中发送的Cookie对象 |
HttpSession getSession() | 返回和此次请求相关联的session对象,若没有为客户端分配session对象,则创建一个新的 |
String getMethod() | 返回此次请求所使用的HTTP方法的名字,如GET、POST |
String getHeader(String name) | 获取指定的请求头信息 |
4.8ServletResponse接口
ServletResponse接口中设置响应参数和向客户端发送响应数据
目录 | 说明 |
---|---|
PrintWriter getWriter() | 返回用于向客户端发送文本的PrintWrite对象 |
String getCharacterEncoding() | 返回发送响应正文所使用的字符编码 |
void setCharacterEncoding(String charset) | 为即将发送到客户端的响应设置字符编码 |
void setContentType(String type) | 设置发送到客户端的响应的内容类型 |
ServletOutputStream getOutputStream() | 返回适合于在响应中写入二进制数据的ServletOutputStream对象 |
4.9HttpServletResponse接口
HttpServletResponse接口继承
ServletResponse
接口中的方法,增加了适用于HTTP响应的新方法
目录 | 说明 |
---|---|
void addCookie(Cookie cookie) | 向响应中增加一个cookie 多次调用,可设置多个cookie |
void addHeader(String name, String value) | 向响应中添加一个名称为name、值为value的响应报头 |
void sendRedirect(String location) | 向客户端发送一个临时的重定向响应,以便客户端访问新的URL |
void encodeRedirectURL(String url) | 使用session ID对用于重定向的URL进行编码 |
五、Servlet生命周期
Servlet生命周期包含四个阶段
Servlet生命周期演示
观察Servlet中各方法什么时候触发执行,和执行的顺序
创建一个Servlet,继承HttpServlet接口
@WebServlet("/helloServlet")
public class HelloServlet extends HttpServlet {
//省略部分代码...
}
重写init()方法
/**初始化方法*/
@Override
public void init() throws ServletException {
System.out.println("初始化时,执行init()方法!");
}
重写doGet()、doPost()方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("处理请求时,执行doGet()方法!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("处理请求时,执行doPost()方法!");
}
重写destroy()方法
@Override
public void destroy() {
System.out.println("释放系统资源时,执行destroy()方法!");
}
测试访问:
第1次访问
http://localhost:8080/jsp06/helloServlet
控制台运行结果:
第2次访问
http://localhost:8080/jsp06/helloServlet
控制台运行结果:
点击停止服务按钮后控制台输出结果
六、Servlet的使用
需求: 使用Servlet作为控制器实现用户登录功能
分析:
1. 创建LoginServlet
2. 继承HttpServlet类
3. 重写doGet()和doPost()方法
4. 创建login.jsp页面
5. 设计登录表单
6. 配置Servlet
步骤: 1.创建LoginServlet——>2.继承HttpServlet类——>3.重写doGet()和doPost()方法
package com.bookshop.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 登录控制器
* @author Aiden
*/
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = -3922210057279156283L;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String loginId = request.getParameter("loginId");
String loginPwd = request.getParameter("loginPwd");
if ("admin".equals(loginId) && "123456".equals(loginPwd)) {
response.sendRedirect("index.jsp");
}else{
out.print("<script>alert('账号或密码错误');location.href='login.jsp';</script>");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//doGet() 和doPost()方法分别用于处理不同类型的请求,但由于其业务代码基本相同,实际开发中可以使用一个方法调用另一个
doGet(req,resp);
}
}
步骤4创建login.jsp页面;步骤5设计登录表单
<form id="login" action="LoginServlet" method="post">
<p>账号:<input type="text" id="loginId" name="loginId"></p>
<p>密码:<input type="text" id="loginPwd" name="loginPwd"></p>
<p><input type="submit" value="登录" name="btnLogin"></p>
</form>
form表单的action属性对应Servlet的访问路径
web.xml文件中的<url-pattern>
@WebServlet注解的urlPatterns
属性
input标签中定义的参数,可从HttpServletRequest对象中获取
步骤6配置Servlet
方式1:通过部署描述文件(web.xml)配置Servlet
<!--配置Servlet-->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.bookshop.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
方式2:通过注解配置Servlet
/**
* 登录控制器
* 1.创建Servlet
* 2.添加注解 @WebServlet
* 3.继承HttpServlet
* 4.重写 doGet / doPost
* @author Aiden
*/
@WebServlet(name="LoginServlet",urlPatterns = {"/LoginServlet"},loadOnStartup = -1)
public class LoginServlet extends HttpServlet {
//省略doGet、doPost方法实现
}
@WebServlet注解常用属性
目录 | 数据类型 | 说明 |
---|---|---|
name | String | 指定Servlet名称,默认为类的全限定名 |
urlPatterns | String [] | 指定一组Servlet的URL匹配模式 |
loadOnStartup | int | 指定Servlet的加载顺序 |
initParams | WebInitParam [] | 指定一组Servlet初始化参数 |
七、获取Servlet初始化参数
使用注解定义初始化参数
@WebServlet(name="LoginServlet",urlPatterns = {"/LoginServlet"}, loadOnStartup = -1,initParams = {@WebInitParam(name="loginId",value="admin"),@WebInitParam(name="loginPwd",value="admin")})
public class LoginServlet extends HttpServlet {
// 省略部分代码…
}
获取初始化参数,使用PrintWriter对象输出参数内容到页面
PrintWriter out = resp.getWriter();
ServletConfig servletConfig = this.getServletConfig();
out.append("loginId:" + servletConfig.getInitParameter("loginId")+<br>");
out.append("loginPwd:" + servletConfig.getInitParameter("loginPwd");
out.flush(); // 输出内容到页面
out.close();
访问当前Servlet,测试调用
loginId:admin
loginpwd:admin
动态获取初始化参数
获取所有初始化参数名
ServletConfig servletConfig = this.getServletConfig();
Enumeration<String> paramNames = servletConfig.getInitParameterNames();
遍历初始化参数名数组,获取初始化参数值
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
String value = servletConfig.getInitParameter(paramName);
}
经验: 使用getInitParameterNames() 方法可以在未知参数名的情况下获取到所有初始化参数,减少硬编码
八、访问应用上下文
web.xml中添加如下配置:
语法说明:
<context-param>
元素声明Web应用的全局范围参数 <param-name>
:参数名<param-value>
:参数值
<context-param>
<param-name>adminEmail</param-name>
<param-value>admin@hotmail.com</param-value>
</context-param>
获取初始化参数,输出到页面
PrintWriter out = resp.getWriter();
ServletConfig servletConfig = this.getServletConfig();
String adminEmail = this.getServletContext().getInitParameter("adminEmail");
out.println("站内管理员邮箱:" + adminEmail);
// 省略部分代码 …
运行结果:
站内管理员邮箱:admin@hotmail.com
九、JSP对比Servlet
JSP:在HTML页面嵌入Java代码和JSP标记
1.便于表现层开发
2.前后端代码混乱,不利于代码重用和模块化开发
Servlet:在Java类中输出HTML代码
1.便于代码重用和模块化开发
2.不利于开发表现层功能、开发效率低
总结对比:
JSP便于开发表示层组件,而Servlet适合编写流程控制代码。针对两者特点,开发Web应用时,通常会将其结合使用。
十、使用Servlet实现控制器
10.1Servlet的职责
1. 充当控制器的角色,接受请求
2. 负责实例化JavaBean对象处理业务逻辑
3. 为JSP页面准备封装数据的JavaBean对象
4. 将请求分发给适当的JSP页面来产生响应
10.2使用Servlet改造第三波书店系统
创建Servlet
@WebServlet(name = "BookServlet", urlPatterns = "/BookServlet")
public class BookServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//操作类型
String action = request.getParameter("action");
if("select".equals(action)) {//查询所有图书列表...
}else if("details".equals(action)){//查询单本图书信息...
}else if("insert".equals(action)){//新增图书信息...
}else if("toUpdate".equals(action)){//跳转至修改图书页面...
}else if("update".equals(action)){//修改图书信息...
}else if("delete".equals(action)){//删除图书信息...
}
}
修改页面链接
<a href="BookServlet?action=select">查询所有图书</a>
<a href="BookServlet?action=details&bookId=1">查询所有图书</a>
总结
思维导图
学习讨论群: 617530501