1.Servlet 简介
Servlet 对请求的处理和响应过程可分为以下几个步骤:
(1)客户端发送请求至服务器端;
(2)服务器将请求信息发送至 Servlet ;
(3)Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;
(4)服务器将响应返回给客户端。
Servlet 执行以下主要任务:
- 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
- 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
- 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
- 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
- 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。
2.Servlet基础
2.1 Servlet体系结构
public abstract class HttpServlet extends GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable
2.2 Servlet 接口
Servlet 接口 定义了 Servlet 与 Servlet 容器之间的契约,Servlet 容器将 Servlet 类载入内存,并在 Servlet 实例上调用具体的方法。用户请求致使 Servlet 容器调用 Servlet 的Service 方法,并传入一个 ServletRequest 实例和一个 ServletResponse 实例。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet;
import java.io.IOException;
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
- init():在 Servlet 实例化后,Servlet 容器会调用该方法,初始化该对象。init() 方法有一个类型为 ServletConfig 的参数,Servlet 容器通过这个参数向 Servlet 传递配置信息。 Servlet 使用 ServletConfig 对象从 Web 应用程序的配置信息中获取以名-值对形式提供的初始化参数。
- service():容器调用 service() 方法来处理客户端的请求。
- destroy():Servlet 的销毁方法。容器在终止 Servlet 服务前调用此方法。
- getServletConfig():该方法返回容器调用 init() 方法时传递给 Servlet 对象的 ServletConfig 对象,ServletConfig 对象包含了 Servlet 的初始化参数。
- getServletInfo():返回一个 String 类型的字符串,其中包括了关于 Servlet 的信息。例如作者、描述信息等。
2.3 生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
-
Servlet 通过调用 init () 方法进行初始化。
-
Servlet 调用 service() 方法来处理客户端的请求。
-
Servlet 通过调用 destroy() 方法终止(结束)。
-
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
一个简单的生命周期案例:
package webstudy;
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;
@WebServlet(name = "/life")
public class LifeServlet extends HttpServlet {
public LifeServlet() {
System.out.println(this.getClass().getName()+"构造方法执行");
}
@Override
public void init() throws ServletException {
// 初始化代码...
System.out.println(this.getClass().getName()+"init方法执行");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(this.getClass().getName()+"doGet方法执行");
response.setContentType("text/html");
PrintWriter pw = response.getWriter();
pw.println("<h1> hello first servlet!</h1>");
pw.flush();
pw.close();
}
@Override
public void destroy() {
// 终止化代码...
System.out.println(this.getClass().getName()+"destory方法执行");
}
}
<!--********************* 生命周期,直接执行servlet程序 *********************-->
<servlet>
<servlet-name>LifeServlet</servlet-name>
<servlet-class>webstudy.LifeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LifeServlet</servlet-name>
<url-pattern>/life</url-pattern>
</servlet-mapping>
3. Servlet API 编程常用接口和类
-
GenericServlet 类
-
HttpServlet 类
-
ServletConfig 接口
-
HttpServletRequest 接口
-
HttpServletResponse 接口
-
ServletConfig 接口
3.4.1 GenericServlet 类
GenericServlet 类是一个抽象类,实现了 Servlet 和 ServletConfig 接口,其作用是:
(1)将 init 方法中的 ServletConfig 赋给一个类中成员(ServletConfig config),以便可以通过调用 getServletConfig 获取。
(2)为 Servlet 接口中的所有方法提供默认的实现。
(3)可以通过覆盖没有参数的 init 方法来编写初始化代码,ServletConfig 则仍然由 GenericServlet 实例保存。
(4)开发者可以在不用获得 ServletConfig 对象情况下直接调用 ServletConfig 的方法,例如源代码中的 getServletContext() 方法。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet;
import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
private static final long serialVersionUID = 1L;
private transient ServletConfig config;
public GenericServlet() {
}
public void destroy() {
}
public String getInitParameter(String name) {
return this.getServletConfig().getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
return this.getServletConfig().getInitParameterNames();
}
public ServletConfig getServletConfig() {
return this.config;
}
public ServletContext getServletContext() {
return this.getServletConfig().getServletContext();
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String message) {
this.getServletContext().log(this.getServletName() + ": " + message);
}
public void log(String message, Throwable t) {
this.getServletContext().log(this.getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
public String getServletName() {
return this.config.getServletName();
}
}
一个简单示例:获取初始化参数name:value
package book.ch2;
import javax.servlet.*;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "MyGenericServlet", urlPatterns = { "/generic" }, initParams = {
@WebInitParam(name = "driverClassName", value = "org.postgresql.Driver")})
public class MyGenericServlet extends GenericServlet {
private static final long serialVersionUID = 1L;
public MyGenericServlet() {
super();
}
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String driverClassName = servletConfig.getInitParameter("driverClassName");
String url = servletConfig.getInitParameter("url");
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("driverClassName:" + driverClassName);
}
}
3.4.2 HttpServlet 类
HttpServlet 覆盖了 GenericServlet 中的 Service 方法,并添加了一个新 Service 方法。
新 Service 方法接受的参数是 HTTPServletRequest 和 HttpServletResponse ,而不是 ServletRequest 和 ServletResponse。
原始的 Service 方法将 Servlet 容器的 request 和 response 对象分别转换成 HTTPServletRequest 和 HttpServletResponse,并调用新的 Service 方法。
HTTPServlet 中的 Service 方法会检验用来发送请求的 HTTP 方法(通过调用 request.getMethod)并调用以下方法之一:doGet、doPost、doHead、doPut、doTrace、doOptions 和 doDelete。
这 7 种方法中,doGet 和 doPost 是最常用的。所以,不再需要覆盖 Service 方法了,只须覆盖 doGet 或者 doPost 即可。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet.http;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javax.servlet.DispatcherType;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public abstract class HttpServlet extends GenericServlet {
private static final long serialVersionUID = 1L;
private static final String METHOD_DELETE = "DELETE";
private static final String METHOD_HEAD = "HEAD";
private static final String METHOD_GET = "GET";
private static final String METHOD_OPTIONS = "OPTIONS";
private static final String METHOD_POST = "POST";
private static final String METHOD_PUT = "PUT";
private static final String METHOD_TRACE = "TRACE";
private static final String HEADER_IFMODSINCE = "If-Modified-Since";
private static final String HEADER_LASTMOD = "Last-Modified";
private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
private static final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
public HttpServlet() {
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected long getLastModified(HttpServletRequest req) {
return -1L;
}
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {
this.doGet(req, resp);
} else {
NoBodyResponse response = new NoBodyResponse(resp);
this.doGet(req, response);
response.setContentLength();
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_put_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_delete_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {
String protocol = req.getProtocol();
if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
private static Method[] getAllDeclaredMethods(Class<?> c) {
if (c.equals(HttpServlet.class)) {
return null;
} else {
Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
Method[] thisMethods = c.getDeclaredMethods();
if (parentMethods != null && parentMethods.length > 0) {
Method[] allMethods = new Method[parentMethods.length + thisMethods.length];
System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);
System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);
thisMethods = allMethods;
}
return thisMethods;
}
}
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Method[] methods = getAllDeclaredMethods(this.getClass());
boolean ALLOW_GET = false;
boolean ALLOW_HEAD = false;
boolean ALLOW_POST = false;
boolean ALLOW_PUT = false;
boolean ALLOW_DELETE = false;
boolean ALLOW_TRACE = true;
boolean ALLOW_OPTIONS = true;
Class clazz = null;
try {
clazz = Class.forName("org.apache.catalina.connector.RequestFacade");
Method getAllowTrace = clazz.getMethod("getAllowTrace", (Class[])null);
ALLOW_TRACE = (Boolean)getAllowTrace.invoke(req, (Object[])null);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException var14) {
}
for(int i = 0; i < methods.length; ++i) {
Method m = methods[i];
if (m.getName().equals("doGet")) {
ALLOW_GET = true;
ALLOW_HEAD = true;
}
if (m.getName().equals("doPost")) {
ALLOW_POST = true;
}
if (m.getName().equals("doPut")) {
ALLOW_PUT = true;
}
if (m.getName().equals("doDelete")) {
ALLOW_DELETE = true;
}
}
String allow = null;
if (ALLOW_GET) {
allow = "GET";
}
if (ALLOW_HEAD) {
if (allow == null) {
allow = "HEAD";
} else {
allow = allow + ", HEAD";
}
}
if (ALLOW_POST) {
if (allow == null) {
allow = "POST";
} else {
allow = allow + ", POST";
}
}
if (ALLOW_PUT) {
if (allow == null) {
allow = "PUT";
} else {
allow = allow + ", PUT";
}
}
if (ALLOW_DELETE) {
if (allow == null) {
allow = "DELETE";
} else {
allow = allow + ", DELETE";
}
}
if (ALLOW_TRACE) {
if (allow == null) {
allow = "TRACE";
} else {
allow = allow + ", TRACE";
}
}
if (ALLOW_OPTIONS) {
if (allow == null) {
allow = "OPTIONS";
} else {
allow = allow + ", OPTIONS";
}
}
resp.setHeader("Allow", allow);
}
protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String CRLF = "\r\n";
StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol());
Enumeration reqHeaderEnum = req.getHeaderNames();
while(reqHeaderEnum.hasMoreElements()) {
String headerName = (String)reqHeaderEnum.nextElement();
buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));
}
buffer.append(CRLF);
int responseLength = buffer.length();
resp.setContentType("message/http");
resp.setContentLength(responseLength);
ServletOutputStream out = resp.getOutputStream();
out.print(buffer.toString());
out.close();
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {
if (!resp.containsHeader("Last-Modified")) {
if (lastModified >= 0L) {
resp.setDateHeader("Last-Modified", lastModified);
}
}
}
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
this.service(request, response);
}
}
3.4.3 ServletConfig 接口
Tomcat 初始化一个 Servlet 时,会将该 Servlet 的配置信息封装到一个 ServletConfig 对象中
,通过调用 init(ServletConfig config) 方法将 ServletConfig 对象传递给 Servlet。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet;
import java.util.Enumeration;
public interface ServletConfig {
String getServletName();
ServletContext getServletContext();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
}
一个简单的示例:获取配置信息
package book.ch2;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ServletConfigDemoServlet extends HttpServlet {
private ServletConfig servletConfig;
@Override
public void init(ServletConfig config) throws ServletException {
this.servletConfig = config;
System.out.println("-----------" + servletConfig + "-----------");
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 使用ServletConfig对象获取初始化参数
ServletConfig servletConfig = getServletConfig();
System.out.println("-----------" + servletConfig + "-----------");
String poet = servletConfig.getInitParameter("poet");
String poem = servletConfig.getInitParameter("poem");
// 设置响应到客户端的文本类型为HTML
response.setContentType("text/html;charset=UTF-8");
// 获取输出流
PrintWriter out = response.getWriter();
out.print("<p>获取ServletConfigDenoServlet的初始化参数:");
out.println("</p><p>poet参数的值:" + poet);
out.println("</p><p>poem参数的值:" + poem + "</p>");
out.append("Served at:").append(request.getContextPath());
}
}
web.xml配置
<servlet>
<servlet-name>myServletConfig</servlet-name>
<servlet-class>book.ch2.ServletConfigDemoServlet</servlet-class>
<init-param>
<param-name>poet</param-name>
<param-value>纳兰容若</param-value>
</init-param>
<init-param>
<param-name>poem</param-name>
<param-value>我是人间惆怅客</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myServletConfig</servlet-name>
<url-pattern>/myServletConfig</url-pattern>
</servlet-mapping>
输出结果:
3.4.4 HttpServletRequest 接口
HttpServletRequest 接口继承自 ServletRequest 接口,专门用来封装 HTTP 请求消息
。
由于 HTTP 请求消息分为请求行、请求消息头和请求消息体
3部分,故而在 HttpServletRequest 接口中定义了获取请求行、请求消息头和请求消息体
的相关方法,以及存取请求域属性的方法。
package book.ch2;
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;
@WebServlet("/RequestLineServlet")
public class RequestLineServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RequestLineServlet() {
super();
}
/******************* 获取请求行信息 *******************/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端MIME类型和字符编码方式
response.setContentType("text/html;charset=UTF-8");
// 获取请求使用的HTTP方法
String method = request.getMethod();
// 获取请求行中的资源名部分
String uri = request.getRequestURI();
// 获取使用的协议及版本号
String protocol = request.getProtocol();
// 获取请求URL后面的查询字符串
String queryString = request.getQueryString();
// 获取Servlet所映射的路径
String servletPath = request.getServletPath();
// 获取请求资源所属于的Web应用的路径
String contextPath = request.getContextPath();
// 获取输出流
PrintWriter out = response.getWriter();
out.println("<p>请求使用的HTTP方法:" + method + "</p>");
out.println("<p>请求行中的资源名部分:" + uri + "</p>");
out.println("<p>请求使用的协议及版本号:" + protocol + "</p>");
out.println("<p>请求URL后面的查询字符串:" + queryString + "</p>");
out.println("<p>Servlet所映射的路径:" + servletPath + "</p>");
out.println("<p>请求资源所属于的Web应用的路径:" + contextPath + "</p>");
out.append("Served at:").append(request.getContextPath());
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.4.1 获取请求头信息
package book.ch2;
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;
import java.util.Enumeration;
@WebServlet("/RequestHeadInfoServlet")
public class RequestHeadInfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RequestHeadInfoServlet() {
super();
}
/******************* 获取请求头信息 *******************/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.print("<h3>请求头信息<h3>");
// 获取请求消息中所有头字段
Enumeration headerNames = request.getHeaderNames();
// 使用循环遍历所有请求头,并通过getHeader()方法获取一个指定名称的头字段
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
out.print(headerName + " : " + request.getHeader(headerName) + "<br>");
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.4.2 获取请求参数
获取请求参数:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>个人信息</title>
</head>
<body>
<h2>个人信息</h2>
<hr>
<form action="/RequestParaServlet" method="GET">
<p>用户名:<input type="text" name="username"></p>
<p>昵 称:<input type="text" name="nickname"></p>
<p>爱好:
<input type="checkbox" name="hobby" value="swim">游泳
<input type="checkbox" name="hobby" value="go">围棋
<input type="checkbox" name="hobby" value="music">音乐</p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
package book.ch2;
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;
@WebServlet("/RequestParaServlet")
public class RequestParaServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RequestParaServlet() {
super();
}
/******************* 获取请求参数 *******************/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端MIME类型和字符编码方式
response.setContentType("text/html;charset=UTF-8");
// 设置request对象的解码方式
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String nickname = request.getParameter("nickname");
// 获取输出流
PrintWriter out = response.getWriter();
out.println("<p>用户名:" + username + "</p>");
out.println("<p>昵 称:" + nickname + "</p>");
out.println("<p>爱好:");
// 获取参数名为“hobby”的值
String[] hobbys = request.getParameterValues("hobby");
for (int i = 0; i < hobbys.length; i++) {
if (i < hobbys.length - 1)
out.println(hobbys[i] + ",");
else
out.println(hobbys[i] + "");
}
out.println("</p>");
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.4.3 设置-获取-删除请求域属性
获取请求域属性:
package book.ch2;
import com.mialab.servlet_demo.entity.Book;
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;
import java.util.Date;
import java.util.Enumeration;
@WebServlet("/RequestScopeAttrServlet")
public class RequestScopeAttrServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RequestScopeAttrServlet() {
super();
}
@Override
/******************* 获取请求域属性 *******************/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应的文本类型为HTML,字符编码为UTF-8
response.setContentType("text/html;charset=UTF-8");
// 在request范围内设置名为book的Book对象属性
request.setAttribute("book", new Book(9801, "《Android应用开发实践教程》"));
// 在request范围内设置名为singer的String对象属性
request.setAttribute("singer", "Jessie J,第32届全英音乐奖入围最佳女艺人,《歌手2018》总冠军");
// 在request范围内设置名为newdate的Date对象属性
request.setAttribute("newdate", new Date());
// 从request范围内获取名为book的属性
Book book = (Book) request.getAttribute("book");
// 从request范围内获取名为singer的属性
String singer = (String) request.getAttribute("singer");
// 从request范围内获取名为newdate的属性
Date date = (Date) request.getAttribute("newdate");
// 获取输出流
PrintWriter out = response.getWriter();
out.println("<p>request.getAttribute(\"book\")的值:" + book + "</p>");
out.println("<p>request.getAttribute(\"singer\")的值:" + singer + "</p>");
out.println("<p>request.getAttribute(\"newdate\")的值:" + date + "</p>");
Enumeration<String> names = request.getAttributeNames();
out.println("<p>request请求域中的属性有:");
while (names.hasMoreElements()) {
out.println(names.nextElement() + " ");
}
out.println("</p>");
request.removeAttribute("book");
out.println("<p>执行request.removeAttribute(\"book\")后request请求域中的属性有:");
names = request.getAttributeNames();
while (names.hasMoreElements()) {
out.println(names.nextElement() + " ");
}
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
HttpServletRequest源代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet.http;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
public interface HttpServletRequest extends ServletRequest {
String BASIC_AUTH = "BASIC";
String FORM_AUTH = "FORM";
String CLIENT_CERT_AUTH = "CLIENT_CERT";
String DIGEST_AUTH = "DIGEST";
String getAuthType();
Cookie[] getCookies();
long getDateHeader(String var1);
String getHeader(String var1);
Enumeration<String> getHeaders(String var1);
Enumeration<String> getHeaderNames();
int getIntHeader(String var1);
default HttpServletMapping getHttpServletMapping() {
return new HttpServletMapping() {
public String getMatchValue() {
return "";
}
public String getPattern() {
return "";
}
public String getServletName() {
return "";
}
public MappingMatch getMappingMatch() {
return null;
}
};
}
String getMethod();
String getPathInfo();
String getPathTranslated();
default PushBuilder newPushBuilder() {
return null;
}
String getContextPath();
String getQueryString();
String getRemoteUser();
boolean isUserInRole(String var1);
Principal getUserPrincipal();
String getRequestedSessionId();
String getRequestURI();
StringBuffer getRequestURL();
String getServletPath();
HttpSession getSession(boolean var1);
HttpSession getSession();
String changeSessionId();
boolean isRequestedSessionIdValid();
boolean isRequestedSessionIdFromCookie();
boolean isRequestedSessionIdFromURL();
/** @deprecated */
@Deprecated
boolean isRequestedSessionIdFromUrl();
boolean authenticate(HttpServletResponse var1) throws IOException, ServletException;
void login(String var1, String var2) throws ServletException;
void logout() throws ServletException;
Collection<Part> getParts() throws IOException, ServletException;
Part getPart(String var1) throws IOException, ServletException;
<T extends HttpUpgradeHandler> T upgrade(Class<T> var1) throws IOException, ServletException;
default Map<String, String> getTrailerFields() {
return Collections.emptyMap();
}
default boolean isTrailerFieldsReady() {
return false;
}
}
3.4.5 HttpServletResponse 接口
HttpServletResponse 接口继承自 ServletResponse 接口,专门用来封装 HTTP 响应消息
。由于 HTTP 响应消息分为状态行、响应消息头、消息体
三部分,于是在 HttpServletResponse 接口中也相应定义了向客户端发送响应状态码、响应消息头、响应消息体
的方法。
HttpServletResponse 接口提供的设置状态码并生成响应状态行的方法有以下。
(1)setStatus(int status) 方法:用于设置 HTTP 响应消息的状态码,并生成响应状态行。正常情况下,Web 服务器会默认产生一个状态码为 200 的状态行。
(2)sendError(int sc) 方法和 sendError(int sc, String msg) 方法:第 1 个方法只是发送错误信息的状态码;而第 2 个方法除了发送状态码外,还可以增加一条用于提示说明的文本信息,该文本信息将出现在发送给客户端的正文内容中。
3.4.5.1 响应消息头
package book.ch2;
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;
@WebServlet("/ResponseHeadServlet")
public class ResponseHeadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ResponseHeadServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 5秒后刷新并跳转到我的博客的网站首页
response.setHeader("Refresh", "5;URL=http://www.bithachi.cn");
// 每隔2秒定时刷新当前页面
// response.setHeader("Refresh", "2");
response.getWriter().println(new java.util.Date());// 输出当前时间
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.5.2 响应消息体
package book.ch2;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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.InputStream;
@WebServlet("/ResponsePicServlet")
public class ResponsePicServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ResponsePicServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应消息头Content-Type
response.setContentType("image/jpeg");
// 获取ServletContext对象
ServletContext context = super.getServletContext();
// 获取读取服务器端文件的输入流
InputStream is = context.getResourceAsStream("/images/ch2/abc.jpeg");
// 获取ServletOutputStream输出流
ServletOutputStream os = response.getOutputStream();
int i = 0;
while ((i = is.read()) != -1) {
os.write(i);// 向输出流中写入二进制数据
}
is.close();
os.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
HttpServletResponse源代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet.http;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
import javax.servlet.ServletResponse;
public interface HttpServletResponse extends ServletResponse {
int SC_CONTINUE = 100;
int SC_SWITCHING_PROTOCOLS = 101;
int SC_OK = 200;
int SC_CREATED = 201;
int SC_ACCEPTED = 202;
int SC_NON_AUTHORITATIVE_INFORMATION = 203;
int SC_NO_CONTENT = 204;
int SC_RESET_CONTENT = 205;
int SC_PARTIAL_CONTENT = 206;
int SC_MULTIPLE_CHOICES = 300;
int SC_MOVED_PERMANENTLY = 301;
int SC_MOVED_TEMPORARILY = 302;
int SC_FOUND = 302;
int SC_SEE_OTHER = 303;
int SC_NOT_MODIFIED = 304;
int SC_USE_PROXY = 305;
int SC_TEMPORARY_REDIRECT = 307;
int SC_BAD_REQUEST = 400;
int SC_UNAUTHORIZED = 401;
int SC_PAYMENT_REQUIRED = 402;
int SC_FORBIDDEN = 403;
int SC_NOT_FOUND = 404;
int SC_METHOD_NOT_ALLOWED = 405;
int SC_NOT_ACCEPTABLE = 406;
int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
int SC_REQUEST_TIMEOUT = 408;
int SC_CONFLICT = 409;
int SC_GONE = 410;
int SC_LENGTH_REQUIRED = 411;
int SC_PRECONDITION_FAILED = 412;
int SC_REQUEST_ENTITY_TOO_LARGE = 413;
int SC_REQUEST_URI_TOO_LONG = 414;
int SC_UNSUPPORTED_MEDIA_TYPE = 415;
int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
int SC_EXPECTATION_FAILED = 417;
int SC_INTERNAL_SERVER_ERROR = 500;
int SC_NOT_IMPLEMENTED = 501;
int SC_BAD_GATEWAY = 502;
int SC_SERVICE_UNAVAILABLE = 503;
int SC_GATEWAY_TIMEOUT = 504;
int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
void addCookie(Cookie var1);
boolean containsHeader(String var1);
String encodeURL(String var1);
String encodeRedirectURL(String var1);
/** @deprecated */
@Deprecated
String encodeUrl(String var1);
/** @deprecated */
@Deprecated
String encodeRedirectUrl(String var1);
void sendError(int var1, String var2) throws IOException;
void sendError(int var1) throws IOException;
void sendRedirect(String var1) throws IOException;
void setDateHeader(String var1, long var2);
void addDateHeader(String var1, long var2);
void setHeader(String var1, String var2);
void addHeader(String var1, String var2);
void setIntHeader(String var1, int var2);
void addIntHeader(String var1, int var2);
void setStatus(int var1);
/** @deprecated */
@Deprecated
void setStatus(int var1, String var2);
int getStatus();
String getHeader(String var1);
Collection<String> getHeaders(String var1);
Collection<String> getHeaderNames();
default void setTrailerFields(Supplier<Map<String, String>> supplier) {
}
default Supplier<Map<String, String>> getTrailerFields() {
return null;
}
}
3.4.6 ServletContext 接口
Servlet 容器在启动一个 Web 应用时,会为该应用创建一个唯一的 ServletContext 对象
供该应用中的所有 Servlet 对象共享。Servlet 对象可以通过 ServletContext 对象来访问容器中的各种资源。
获得 ServletContext 对象可以通过以下两种方式:
- 通过 ServletConfig 接口的 getServletContext() 方法获得 ServletContext 对象。
- 通过 GenericServlet 抽象类的 getServletContext() 方法获得 ServletContext 对象,实质上该方法也调用了 ServletConfig 的 getServletContext() 方法。
ServletContext 接口中定义了获取 Web 应用范围的初始化参数的方法,有以下。
(1)方法声明:public String getInitParameter(String name) ;
作用:返回 Web 应用范围内指定的初始化参数值。在 web.xml 中使用 元素表示应用范围内的初始化参数。
(2)方法声明:public Enumeration getInitParameterNames();
作用:返回一个包含所有初始化参数名称的 Enumeration 对象。
3.4.6.1 获取WEB应用的初始化参数
web.xml
<context-param>
<param-name>username</param-name>
<param-value>admin888</param-value>
</context-param>
<context-param>
<param-name>password</param-name>
<param-value>123</param-value>
</context-param>
<context-param>
<param-name>driverClassName</param-name>
<param-value>org.postgresql.Driver</param-value>
</context-param>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:postgresql://127.0.0.1:5432/postgres</param-value>
</context-param>
package book.ch2;
import javax.servlet.ServletContext;
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;
import java.util.Enumeration;
@WebServlet("/GetWebInitParamServlet")
public class GetWebInitParamServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public GetWebInitParamServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端的文本类型为HTML
response.setContentType("text/html;charset=UTF-8");
// 得到ServletContext对象
ServletContext context = this.getServletContext();
// 得到包含所有初始化参数名的Enumeration对象
Enumeration<String> paramNames = context.getInitParameterNames();
// 获取输出流
PrintWriter out = response.getWriter();
// 遍历所有的初始化参数名,得到相应的参数值,打印到控制台
out.print("<h2>当前Web应用的所有初始化参数:</h2>");
// 遍历所有的初始化参数名,得到相应的参数值并打印
while (paramNames.hasMoreElements()) {
String name = paramNames.nextElement();
String value = context.getInitParameter(name);
out.println(name + ":" + value);
out.println("<br>");
}
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.6.2 实现多个Servlet对象共享数据
先访问PutContextDataServlet.java设置共享数据,再访问GetContextDataServlet.java获取共享数据
package com.mialab.servlet_demo;
import javax.servlet.ServletContext;
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;
@WebServlet("/PutContextDataServlet")
public class PutContextDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public PutContextDataServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
// 通过setAttribute()方法设置属性值
context.setAttribute("contextData", "Here is contexData");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
package book.ch2;
import javax.servlet.ServletContext;
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;
@WebServlet("/GetContextDataServlet")
public class GetContextDataServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public GetContextDataServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
ServletContext context = this.getServletContext();
// 通过getAttribute()方法获取属性值
String data = (String) context.getAttribute("contextData");
out.println(data);
System.out.println(data);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
3.4.6.3 读取WEB应用下的资源文件
package book.ch2;
import javax.servlet.ServletContext;
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.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;
@WebServlet("/GetResourceServlet")
public class GetResourceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public GetResourceServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
ServletContext context = this.getServletContext();
// 获取文件绝对路径
String path = context.getRealPath("/WEB-INF/classes/data.properties");
FileInputStream in = new FileInputStream(path);
Properties pros = new Properties();
pros.load(in);
out.println("username = " + pros.getProperty("username") + "<br>");
out.println("password = " + pros.getProperty("password") + "<br>");
out.println("driverClassName = " + pros.getProperty("driverClassName") + "<br>");
out.println("url = " + pros.getProperty("url") + "<br>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
ServletContext.java源代码:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package javax.servlet;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;
public interface ServletContext {
String TEMPDIR = "javax.servlet.context.tempdir";
String ORDERED_LIBS = "javax.servlet.context.orderedLibs";
String getContextPath();
ServletContext getContext(String var1);
int getMajorVersion();
int getMinorVersion();
int getEffectiveMajorVersion();
int getEffectiveMinorVersion();
String getMimeType(String var1);
Set<String> getResourcePaths(String var1);
URL getResource(String var1) throws MalformedURLException;
InputStream getResourceAsStream(String var1);
RequestDispatcher getRequestDispatcher(String var1);
RequestDispatcher getNamedDispatcher(String var1);
/** @deprecated */
@Deprecated
Servlet getServlet(String var1) throws ServletException;
/** @deprecated */
@Deprecated
Enumeration<Servlet> getServlets();
/** @deprecated */
@Deprecated
Enumeration<String> getServletNames();
void log(String var1);
/** @deprecated */
@Deprecated
void log(Exception var1, String var2);
void log(String var1, Throwable var2);
String getRealPath(String var1);
String getServerInfo();
String getInitParameter(String var1);
Enumeration<String> getInitParameterNames();
boolean setInitParameter(String var1, String var2);
Object getAttribute(String var1);
Enumeration<String> getAttributeNames();
void setAttribute(String var1, Object var2);
void removeAttribute(String var1);
String getServletContextName();
Dynamic addServlet(String var1, String var2);
Dynamic addServlet(String var1, Servlet var2);
Dynamic addServlet(String var1, Class<? extends Servlet> var2);
Dynamic addJspFile(String var1, String var2);
<T extends Servlet> T createServlet(Class<T> var1) throws ServletException;
ServletRegistration getServletRegistration(String var1);
Map<String, ? extends ServletRegistration> getServletRegistrations();
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);
javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Class<? extends Filter> var2);
<T extends Filter> T createFilter(Class<T> var1) throws ServletException;
FilterRegistration getFilterRegistration(String var1);
Map<String, ? extends FilterRegistration> getFilterRegistrations();
SessionCookieConfig getSessionCookieConfig();
void setSessionTrackingModes(Set<SessionTrackingMode> var1);
Set<SessionTrackingMode> getDefaultSessionTrackingModes();
Set<SessionTrackingMode> getEffectiveSessionTrackingModes();
void addListener(String var1);
<T extends EventListener> void addListener(T var1);
void addListener(Class<? extends EventListener> var1);
<T extends EventListener> T createListener(Class<T> var1) throws ServletException;
JspConfigDescriptor getJspConfigDescriptor();
ClassLoader getClassLoader();
void declareRoles(String... var1);
String getVirtualServerName();
int getSessionTimeout();
void setSessionTimeout(int var1);
String getRequestCharacterEncoding();
void setRequestCharacterEncoding(String var1);
String getResponseCharacterEncoding();
void setResponseCharacterEncoding(String var1);
}
4. Servlet处理表单数据
表单数据是指通过表单让用户填写内容,然后提交到服务器上;这些数据被称之为表单数据。
Servlet 处理表单数据
可以使用以下的方法:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Servlet处理表单数据</title>
</head>
<body>
<h2>个人信息</h2>
<hr>
<form action="/formtest" method="POST">
<p>
用户名:<input type="text" name="username">
</p>
<p>
密 码 :<input type="password" name="password">
</p>
<p>
性 别 :<input type="radio" name="sex" value="boy"
checked>男<input type="radio" name="sex" value="girl">女
</p>
<p>
家 乡 :<select name="home"><option
value="suzhou">苏州</option>
<option value="shanghai">上海</option>
<option value="nanjing">南京</option>
</select>
</p>
<p>
爱 好: <input type="checkbox" name="hobby"
value="swim">游泳 <input type="checkbox" name="hobby"
value="go">围棋 <input type="checkbox" name="hobby"
value="music">音乐
</p>
<p>
自我介绍:<br>
<textarea name="info" rows="5" cols="26"></textarea>
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
</body>
</body>
</html>
package webstudy;
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;
import java.util.Enumeration;
@WebServlet("/formtest")
public class FormServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public FormServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端MIME类型和字符编码方式
response.setContentType("text/html;charset=UTF-8");
// 设置request对象的解码方式
request.setCharacterEncoding("utf-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String home = request.getParameter("home");
String info = request.getParameter("info");
//获取所有参数
Enumeration<String> enu=request.getParameterNames();
//循环打印jsp的name值
while(enu.hasMoreElements()) {
String paramName = (String) enu.nextElement();
System.out.println(paramName);
}
// 获取输出流
PrintWriter out = response.getWriter();
out.println("<p>用户名:" + username + "</p>");
out.println("<p>密码:" + password + "</p>");
out.println("<p>性别:" + sex + "</p>");
out.println("<p>家乡:" + home + "</p>");
out.println("<p>爱好:");
// 获取参数名为“hobby”的值
String[] hobbys = request.getParameterValues("hobby");
for (int i = 0; i < hobbys.length; i++) {
if (i < hobbys.length - 1) {
out.println(hobbys[i] + ",");
} else {
out.println(hobbys[i] + "");
}
}
out.println("</p>");
out.println("<p>自我介绍:" + info + "</p>");
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
5.Servlet 重定向和请求转发
请求转发
只是把请求转发给服务器上(通常是同一个 Web 应用中)的另一个组件( Servlet 或 JSP等);
重定向
则只是告诉客户(浏览器)去访问另一个 URL(可能是同一个 Web 站点甚至其他站点)。
请求转发
发生在服务器端,由服务器(比如 Servlet)控制;
重定向
发生在客户端,由客户(通常是浏览器)控制。
请求转发
使用 RequestDispatcher 对象的 forward() 或 include()方法。
重定向
则使用 HttpServletResponse 对象的 sendRedirect() 方法。
5.1 重定向
重定向
后则无法在服务器端获取第一次请求对象上保存的信息。比如还是在 Servlet 中将用户名保存到当前 request 对象中,并重定向到一个新的 URL,然后在新 URL 指向的地址中(假设是某个 Servlet)就无法获取原先保存在第一个请求中的信息。很明显,用户名是保存在第一次请求的对象中,但并没有保存在本次(第二次)请求的对象中。
重定向后,浏览器地址栏 URL 变为新的 URL(因为浏览器确实给新的 URL 发送了一个新的请求
)。
访问RedirectServlet,重定向到AnotherServlet
package book.ch2;
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;
@WebServlet("/RedirectServlet")
public class RedirectServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public RedirectServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端的文本类型为HTML
response.setContentType("text/html;charset=UTF-8");
// 输出当前时间
response.getWriter().println(new java.util.Date());
// 进行重定向
response.sendRedirect(request.getContextPath() + "/AnotherServlet");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package book.ch2;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/AnotherServlet")
public class AnotherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public AnotherServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端的文本类型为HTML
response.setContentType("text/html;charset=UTF-8");
// 获取输出流
PrintWriter out = response.getWriter();
// 输出响应结果
out.println("<p>重定向页面</p>");
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
http://localhost:8080/RedirectServlet —> http://localhost:8080/AnotherServlet
5.2 请求转发
请求转发
后可以在服务器端获取本次请求对象上保存的信息(比如在 Servlet 中将用户名保存到当前 request 对象中,转发给另一组件(如 JSP )后,另一组件可以通过 request 对象取得用户名信息)。
请求转发后,浏览器地址栏 URL 不会发生改变
。
RequestDispatcher
对象是通过调用 HttpServletRequest 对象的getRequestDispatcher()方法得到的,所以 forward() 或 include() 本质来说是属于请求对象的方法,所以请求转发始终发生在一个请求当中。
forword() 和 include() 的区别:
forward()
:表示在服务器端从一个 Servlet 中将请求转发到另一个资源(Servlet、JSP 或 HTML 等),本意是让第一个组件对请求做些预处理(或者什么都不做),而让另一组件处理并返回响应。
include()
:表示在响应中包含另一个资源(Servlet、JSP 或 HTML 等)的响应内容,最终被包含的页面产生的任何响应都将并入原来的 response 对象,然后一起输出到客户端。
请求ForwardServlet,转发到OtherServlet
package book.ch2;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/ForwardServlet")
public class ForwardServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ForwardServlet() {
super();
}
/******************* 转发请求 *******************/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 将key为bookname,value为《Android应用开发实践教程》的属性对象存储到request对象中
request.setAttribute("bookname", "《Android应用开发实践教程》");
RequestDispatcher dispatcher = request.getRequestDispatcher("/OtherServlet");
dispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package book.ch2;
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;
@WebServlet("/OtherServlet")
public class OtherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public OtherServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应到客户端的文本类型为HTML
response.setContentType("text/html;charset=UTF-8");
// 从request对象中获取bookname属性值
String bookname = (String) request.getAttribute("bookname");
// 获取输出流
PrintWriter out = response.getWriter();
// 输出响应结果
out.println("<p>请求转发的结果页面</p>");
out.println("读取的request对象的bookname属性值为:" + bookname);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
6. Servlet数据库访问
JDBC(Java DataBase Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 Java API ,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。 JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够更为便利地编写数据库应用程序。
一个示例:
文件结构:
book.sql
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`bookId` int(4) NOT NULL,
`bookName` varchar(50) NOT NULL,
PRIMARY KEY (`bookId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('9801', 'Android应用开发实践教程');
INSERT INTO `book` VALUES ('9802', 'Web应用开发');
INSERT INTO `book` VALUES ('9803', 'iOS程序设计');
测试数据:
package webstudy;
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;
import java.sql.*;
@WebServlet("/jdbctest")
public class JdbcServlet extends HttpServlet {
String JDBC_Driver = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost:3306/message?useSSL=true";
String user = "root";
String password = "123456";
Connection con1 = null;
Statement stmt = null;
ResultSet rs1;
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
Class.forName(JDBC_Driver);
con1 = DriverManager.getConnection(DB_URL, user, password);
stmt = con1.createStatement();
String sql;
sql = "select bookid,bookName from book";
rs1 = stmt.executeQuery(sql);
while (rs1.next()) {
int id = rs1.getInt("bookid");
String bookname1 = rs1.getString("bookName");
out.println("bookid:" + id);
out.println(",bookName:" + bookname1);
out.println("<br />");
}
rs1.close();
stmt.close();
con1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//out.close();
}
}
7. Servlet 异常处理
当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type
元素的 web.xml
中搜索与抛出异常类型相匹配的配置。可以在web.xml
中使用error-page
元素来指定对特定异常 或 HTTP 状态码作出相应的 Servlet 调用。
假设有一个 ErrorHandler
的 Servlet 在任何已定义的异常或错误出现时被调用,以下将是在 web.xml 中创建的项。
<!--********************* 定义 *********************-->
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>book.ch2.ErrorHandlerServlet</servlet-class>
</servlet>
<!--********************* 映射 *********************-->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<!--********************* 相关错误页面 *********************-->
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<error-code>403</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.io.IOException</exception-type>
<location>/ErrorHandler</location>
</error-page>
关于上面的web.xml
中异常处理几点说明:
ErrorHandler 与其他的 Servelt 的定义方式一样,且在 web.xml 中进行配置。
如果有错误状态代码出现,不管为 404(Not Found 未找到)或 403(Forbidden 禁止),则会调用 ErrorHandler。
如果 Web 应用程序抛出 ServletException 或 IOException,Web 容器则会调用 ErrorHandler。
可以定义不同的错误处理程序来处理不同类型的错误或异常。
如果要对所有的异常有一个通用的错误处理程序
,那么应该定义下面的 error-page
,而不是为每个异常定义单独的 error-page 元素:
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/ErrorHandler</location>
</error-page>
一个示例:
<!--********************* 定义 *********************-->
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>book.ch2.ErrorHandlerServlet</servlet-class>
</servlet>
<!--********************* 映射 *********************-->
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<!--********************* 相关错误页面 *********************-->
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/ErrorHandler</location>
</error-page>
package book.ch2;
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;
@WebServlet("/ErrorHandlerServlet")
public class ErrorHandlerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ErrorHandlerServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name");
if (servletName == null) {
servletName = "Unknown";
}
String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");
if (requestUri == null) {
requestUri = "Unknown";
}
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String title = "Servlet处理 Error/Exception";
String docType = "<!DOCTYPE html>\n";
out.println(
docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n");
out.println("<h3>Servlet异常/错误处理</h3>");
if (throwable == null && statusCode == null) {
out.println("<h3>错误信息丢失</h2>");
out.println("请返回 <a href=\"" + response.encodeURL("http://localhost:8080/") + "\">主页</a>。");
} else if (statusCode != null) {
out.println("错误代码 : " + statusCode + "<br><br>");
out.println("Servlet Name : " + servletName + "</br></br>");
out.println("异常类型 : " + throwable.getClass().getName() + "</br></br>");
out.println("请求 URI: " + requestUri + "<br><br>");
out.println("异常信息: " + throwable.getMessage());
} else {
// out.println("<h3>错误信息</h3>");
// out.println("Servlet Name : " + servletName + "</br></br>");
// out.println("异常类型 : " + throwable.getClass().getName() + "</br></br>");
// out.println("请求 URI: " + requestUri + "<br><br>");
// out.println("异常信息: " + throwable.getMessage());
}
out.println("</body>");
out.println("</html>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
package book.ch2;
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;
@WebServlet("/ExceptionServlet")
public class ExceptionServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ExceptionServlet() {
super();
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
int x = 126/0;
//int[] array = {2,4,6};
//System.out.println(array[3]);
//throw new ArrayIndexOutOfBoundsException();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}