- Servlet 是驻留在服务器内存中运行的小程序;
- 一个 Servlet 就是一个 Java 类,且可以通过“请求 - 响应”模型来访问;
- 与 JSP 的模式相反,JSP 是在页面中嵌入 Java 代码,Servlet
是在类中嵌入 HTML 代码。
Tomcat 容器等级
Tomcat 容器分为四个等级,Servlet 的容器管理 Content 容器,一个 Context 对应一个 Web 工程。
自己实现 Servlet
- 继承
HttpServlet
类; - 重写
doGet()
方法或doPost()
方法(不需要覆盖service()
方法,service()
会自行调用 doX); - 在 web.xml 中注册 Servlet。
index.jsp
<body>
<a href="servlet/HelloServlet"> GET 请求 HelloServlet</a>
<form action="servlet/HelloServlet" method="post">
<input type="submit" value="POST 请求 HelloServlet" />
</form>
</body>
HelloServlet.java
public class HelloServlet extends HttpServlet {
public HelloServlet() { super();}
public void destroy() { super.destroy();}
public void init() throws ServletException {}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Get...");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.println("<strong>Hello Servlet!</strong><br>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Post...");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
out.println("<HTML>");
out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
out.println(" <BODY>");
out.println("<strong>Hello Servlet!</strong><br>");
out.println(" </BODY>");
out.println("</HTML>");
out.flush();
out.close();
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!--<display-name></display-name>-->
<!-- 新加入 Servlet 及其映射的路径 -->
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name> <!-- http://localhost:8080/HelloServlet/servlet/hello -->
<url-pattern>/servlet/hello</url-pattern> <!-- 必须以 / 开头,表示根目录 -->
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Servlet 执行流程与生命周期
- 用户在浏览器点击
<a href="servlet/HelloServlet">
- 匹配 web.xml 中的
<url-pattern>/servlet/hello</url-pattern>
- 根据匹配 URL 获取对应的 Servlet 类
<servlet-name>HelloServlet</servlet-name>
- 根据请求方式执行 Servlet 类的 doX 方法
Servlet 经历以下生命周期:
- 初始化、加载、实例化:判断 Servlet 实例是否存在,如不存在则装载 Servlet 类并创建实例(调用构造方法)、调用
init
(ServletConfig)方法; - 响应客户端请求:调用
service
(Servlet Request Servlet Response)方法,并决定调用 doX 方法; - 当服务器关闭时,调用
destroy
方法。
Tomcat 装载 Servlet
在下列时刻 Servlet 容器(如 Tomcat)装载 Servlet:
- 容器启动时自动装载:在 web.xml 文件中添加:
<servlet>
...
<load-on-startup>1</load-on-startup> <!-- 数字越小优先级越高 -->
</servlet>
- 在 Servlet 容器启动后,客户首次向 Servlet 发送请求;
- Servlet 类文件被更新后,重新装载 Servlet。
Servlet 被装载后,Serlet 容器创建一个 Servlet 实例并且调用其 init()
方法进行初始化(整个生命周期中只调用一次)。
Servlet 与 JSP 的关系
Servlet 获取表单数据
entity/User.java
// 用户实体类
public class Users {
private String username; //用户名
private String mypassword; //密码
private String email; //电子邮箱
private String gender; //性别
private Date birthday; //出生日期
private String[] favorites; //爱好
private String introduce; //自我介绍
private boolean flag; //是否接受协议
public Users() {}
// ...省略 getter 和 setter
}
servlet/RegServlet.java
import entity.Users;
public class RegServlet extends HttpServlet {
public RegServlet() {super();}
public void destroy() {super.destroy();}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
Users u = new Users();
String username, mypassword, gender, email, introduce, isAccept;
Date birthday;
String[] favorites;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
username = request.getParameter("username");
mypassword = request.getParameter("mypassword");
gender = request.getParameter("gender");
email = request.getParameter("email");
introduce = request.getParameter("introduce");
birthday = sdf.parse(request.getParameter("birthday"));
if (request.getParameterValues("isAccpet") != null)
isAccept = request.getParameter("isAccept");
else
isAccept = "false";
favorites = request.getParameterValues("favorite");
u.setUsername(username);
u.setMypassword(mypassword);
u.setGender(gender);
u.setEmail(email);
u.setFavorites(favorites);
u.setIntroduce(introduce);
if (isAccept.equals("true"))
u.setFlag(true);
else
u.setFlag(false);
u.setBirthday(birthday);
request.getSession().setAttribute("regUser", u); // 在 JavaBean 中 id 为 “regUser”
request.getRequestDispatcher("../userinfo.jsp").forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void init() throws ServletException {
// Put your code here
}
}
reg.jsp
<body>
<h1>用户注册</h1>
<hr>
<form name="regForm" action="servlet/RegServlet" method="post">
<table border="0" width="800" cellspacing="0" cellpadding="0">
<tr>
<td class="lalel">用户名:</td>
<td class="controler"><input type="text" name="username"/></td>
</tr>
<tr>
<td class="label">密码:</td>
<td class="controler"><input type="password" name="mypassword"></td>
</tr>
<tr>
<td class="label">确认密码:</td>
<td class="controler"><input type="password" name="confirmpass"></td>
</tr>
<tr>
<td class="label">电子邮箱:</td>
<td class="controler"><input type="text" name="email"></td>
</tr>
<tr>
<td class="label">性别:</td>
<td class="controler"><input type="radio" name="gender" checked="checked" value="Male">男<input type="radio" name="gender" value="Female">女
</td>
</tr>
<tr>
<td class="label">出生日期:</td>
<td class="controler">
<input name="birthday" type="text" id="control_date" size="10" maxlength="10" onclick="new Calendar().show(this);" readonly="readonly"/>
</td>
</tr>
<tr>
<td class="label">爱好:</td>
<td class="controler">
<input type="checkbox" name="favorite" value="nba"> NBA
<input type="checkbox" name="favorite" value="music"> 音乐
<input type="checkbox" name="favorite" value="movie"> 电影
<input type="checkbox" name="favorite" value="internet"> 上网
</td>
</tr>
<tr>
<td class="label">自我介绍:</td>
<td class="controler"><textarea name="introduce" rows="10" cols="40"></textarea></td>
</tr>
<tr>
<td class="label">接受协议:</td>
<td class="controler"><input type="checkbox" name="isAccept" value="true">是否接受霸王条款</td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="注册"/>
<input type="reset" value="取消"/>
</td>
</tr>
</table>
</form>
</body>
userinfo.jsp
<%@ page language="java" import="java.util.*,java.text.*" contentType="text/html; charset=utf-8"%>
<body>
<h1>用户信息</h1>
<hr>
<center>
<jsp:useBean id="regUser" class="entity.Users" scope="session"/>
<table width="600" cellpadding="0" cellspacing="0" border="1">
<tr>
<td class="title">用户名:</td>
<td class="content">
<jsp:getProperty name="regUser" property="username"/>
</td>
</tr>
<tr>
<td class="title">密码:</td>
<td class="content">
<jsp:getProperty name="regUser" property="mypassword"/>
</td>
</tr>
<tr>
<td class="title">性别:</td>
<td class="content">
<jsp:getProperty name="regUser" property="gender"/>
</td>
</tr>
<tr>
<td class="title">E-mail:</td>
<td class="content">
<jsp:getProperty name="regUser" property="email"/>
</td>
</tr>
<tr>
<td class="title">出生日期:</td>
<td class="content">
<%
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String date = sdf.format(regUser.getBirthday());
%>
<%=date%>
</td>
</tr>
<tr>
<td class="title">爱好:</td>
<td class="content">
<%
String[] favorites = regUser.getFavorites();
for (String f : favorites) {
%>
<%=f%>
<%
}
%>
</td>
</tr>
<tr>
<td class="title">自我介绍:</td>
<td class="content">
<jsp:getProperty name="regUser" property="introduce"/>
</td>
</tr>
<tr>
<td class="title">是否介绍协议:</td>
<td class="content">
<jsp:getProperty name="regUser" property="flag"/>
</td>
</tr>
</table>
</center>
</body>
路径跳转
相对路径访问 Servlet
<!-- /servlet/HelloServlet 第一个/表示服务器的根目录 -->
<a href="servlet/HelloServlet">访问HelloServlet!</a><br>
绝对路径访问 Servlet
<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!-- 使用绝对路径访问 HelloServlet ,可以使用 path 变量:path变量表示项目的根目录 -->
<a href="<%=path%>/servlet/HelloServlet">访问HelloServlet!</a><br>
重定向
// 请求重定向方式跳转到 test.jsp ,当前路径是 ServletPathDirection/servlet/
response.sendRedirect("test.jsp");
// 使用 request.getContextPath 获得上下文对象
response.sendRedirect(request.getContextPath() + "/test.jsp");
服务器内跳转
// 服务器内部跳转,的斜线表示项目的根目录
request.getRequestDispatcher("/test.jsp").forward(request, response); // 绝对路径
request.getRequestDispatcher("../test.jsp").forward(request, response); // 相对路径