Servlet是开发Servlet的主要技术。掌握Servlet API是成为一名强大的Java Web开发者的基本条件。
Servlet API有以下4个包:
javax.servlet,其中包含定义Servlet和Servlet容器之间契约的类和接口。
javax.servlet.http,其中包含定义HTTP Servlet和Servlet容器之间契约的类和接口。
java.servlet.annotation
java.servlet.descriptor
javax.servlet中的主要类型:
Servlet接口中定义了5个方法:
注意:编写Java方法签名的惯例是,对于与包含该方法的类型不处于同一个包中的类型,要使用全类名。
init、service和destroy是生命周期方法。Servlet容器根据以下规则调用这些方法。
另外两个方法是非生命周期方法。
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;
/**
* Created by Administrator on 2018/7/30.
*/
@WebServlet(urlPatterns = "/my")
public class MyServlet implements javax.servlet.Servlet {
private transient ServletConfig servletConfig;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig = servletConfig;
}
@Override
public ServletConfig getServletConfig() {
return servletConfig;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
String servletName = servletConfig.getServletName();
servletResponse.setContentType("text/html");
PrintWriter writer = servletResponse.getWriter();
writer.print(
"Hello from " + servletName + ""
);
}
@Override
public String getServletInfo() {
return "My Servlet!";
}
@Override
public void destroy() {
}
}
jdk1.8.0_60\jre\lib\ext
,重新编译。(文件编码问题自行解决) 对于每一个HTTP请求,Servlet容器都会创建一个ServletRequest实例,并将它传给Servlet的Service方法。
getParameter是在ServletRequest中最常用的方法。该方法通常用于返回HTML表单域的值。示例如下:
//uri
http://domain/context/servletName?id=123
//getParameter
String id = request.getParameter("id"); //如果参数不存在,则返回null
Servlet容器在调用Service方法前,会创建一个ServletResponse,并将它作为第二个参数传给Service方法。
ServletResponse隐藏了向浏览器发送响应的复杂过程。
在ServletResponse中定义的方法之一是getWriter方法,它返回了一个可以向客户端发送文本的java.io.PrintWriter。
默认情况下,PrintWriter对象使用ISO-8859-1编码。
在向客户端发送响应时,大多数时候是将它作为HTML发送。因此,你必须非常熟悉HTML。
在发送任务HTML标签前,应该先调用setContentType方法,设置响应的内容类型为“text/html”。
当容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig。
ServletConfig封装了@WebServlet或者部署描述符(web.xml)中的配置信息。通过这种方式传入的每一条信息都叫一个初始参数。一个初始参数有key和value两个元件。
为了从Servlet内部获取到初始参数的值,ServletConfig提供了几个方法:
//1.获取一个初始参数值
java.lang.String getInitParameter(java.lang.String name)
//2.获取所有初始参数名称的一个Enumeration
java.util.Enumeration.lang.String> getInitParameterNames()
ServletConfig还提供了getServletContext方法,可以从Servlet内部获取ServletContext。
非完整示例代码:
@WebServlet(name = "MyServlet",
urlPatterns = {"/my"},
initParams = {
@WebInitParam(name = "admin", value = "mh"),
@WebInitParam(name = "email", value = "[email protected]")
}
)
public class MyServlet implements javax.servlet.Servlet {
....
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
}
....
}
另一种方法是,在部署描述符中传入初始参数。在这里使用部署描述符,比使用@WebServlet更容易,因为部署描述符是一个文本文件,不需要重新编译Servlet类,就可以对它进行编辑。
ServletContext表示Servlet应用程序。每个Web应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机只有一个ServletContext对象。
通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。
前面的例子展示了如何通过实现Servlet接口来编写Servlet。但你注意到没有,它们必须给Servlet接口中的所有方法都提供实现,即便其中有一些方法根本不需要包含任何代码。此外,还需要将ServletConfig对象保存到类级变量中。
为了使代码更加简洁,GenericServlet抽象类出现了,它实现了GenericServlet接口,并完成以下任务:
为Servlet接口中的所有方法提供默认的实现。
示例:
@WebServlet(name = "MyGenericServlet",
urlPatterns = {"/myGeneric"},
initParams = {
@WebInitParam(name = "admin", value = "mh"),
@WebInitParam(name = "email", value = "[email protected]")
}
)
public class MyGenericServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException {
ServletConfig servletConfig = getServletConfig();
String admin = servletConfig.getInitParameter("admin");
String email = servletConfig.getInitParameter("email");
PrintWriter writer = servletResponse.getWriter();
writer.print(
"Admin: " + admin +
"
Eamil:" + email + ""
);
}
}
MyGenericServlet扩展了GenericServlet,而不是实现了Servlet接口,使代码更加简洁。
通过URL调用MyGenericServlet:http://localhost:8080/servlet/myGeneric,结果如下:
javax.servlet.http中包含了用于编写Servlet应用程序的类和接口。其中许多类型覆盖了javax.servlet中的类型。
下图展示了javax.servlet.http中的主要类型:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
像往常一样,Servlet容器调用javax.servlet.Servlet中原始的Service方法。HttpServlet中的实现如下:
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("non-HTTP request or response");
}
this.service(request, response);
}
HttpServlet中新的service方法会检验用来发送请求的HTTP方法(通过调用request.getMethod),并调用以下方法之一:doGet、doPost、doHead、doPut、doTrace、doOptions和doDelete。这7种方法中每一种方法都表示一个HTTP方法。doGet和doPost是最常用的。因此,不再需要覆盖Service方法了,只要覆盖doGet或者doPost,或者覆盖doGet和doPost即可。总之,HttpServlet有两个特性在GenericServlet中尚未体现出来。
HttpServletRequest表示HTTP环境下的Servlet请求,它扩展了ServletRequest接口,并添加了几个方法,如下:
//返回表示请求上下文的请求URI部分
String getContextPath();
//返回一个Cookie对象数组
Cookie[] getCookies();
//返回指定HTTP标题的值
String getHeader(String var1);
//返回生成这个请求的HTTP方法名称
String getMethod();
//返回请求URL中的查询字符串
String getQueryString();
//返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象。
HttpSession getSession();
//返回与这个请求相关的会话对象。如果有,且参数为true,将创建一个新的会话对象。
HttpSession getSession(boolean create);
HttpServletResponse表示HTTP环境中的Servlet响应。下面是其中的部分方法:
//给这个响应对象添加一个cookie
void addCookie(Cookie var1);
//给这个响应对象添加一个header
void addHeader(String var1, String var2);
//发送一条响应码,将浏览器跳转到指定的位置
void sendRedirect(String var1) throws IOException;
一个Web应用程序中几乎总会包含一个或者多个HTML表单,供用户输入值。你可以轻松地将一个HTML表单从一个Servlet发送到浏览器。当用户提交表单时,在表单元素中输入的值就会被当作请求参数发送到服务器。
HTML输入域的值会被当作字符串发送到服务器。空的输入域对应空的字符串。
HTML的select元素会发送一个字符串。包含多个值的select元素发送一个字符串数组。
单选框将被选中按钮的值发送到服务器。如果没有选择按钮,不发送任何值,getParameter(fieldName)返回null。
如果一个表单中包含多个输入同名的元素,那么所有值都会被提交,并且必须利用request.getParameterValues来获取它们。getParameter将只返回最后一个值。
示例代码:
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;
/**
* Created by Administrator on 2018/7/30.
*/
@WebServlet(name = "MyHttpServlet",urlPatterns = "/myHttpServlet")
public class MyHttpServlet extends HttpServlet {
private static final long serialVersionUID = 54L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("");
writer.print("");
writer.print("name:"+request.getParameter("name")+"
");
writer.print("pwd:"+request.getParameter("pwd"));
writer.print("");
writer.print("");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.print("");
writer.print("");
writer.print(");
writer.print("
");
writer.print("");
writer.print("");
writer.print("");
writer.print("");
writer.print("");
}
}
访问地址:http://localhost:8080/servlet/myHttpServlet
响应结果:
部署描述符总是命名为web.xml,并且放在WEB-INF目录下。可以在其中配置Servlet的映射。示例如下:
public class MyHttpServlet extends HttpServlet {
private static final long serialVersionUID = 5432L;
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
......
}
}
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>MyHttpServletservlet-name>
<servlet-class>MyHttpServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>MyHttpServletservlet-name>
<url-pattern>/myHttpServleturl-pattern>
servlet-mapping>
web-app>
使用部署描述符的好处: 如需修改配置项,如Servlet的路径/添加初始参数,不需要重新编译类。
如果@WebServlet中的定义与部署描述符中的定义冲突,则以部署描述符定义为准。