第四章 Servlet技术(上)
Servlet中的常用对象:
- 请求对象(ServletRequest和HttpServletRequest):Servlet从该对象中获取来自客户的信息。
- 响应对象(ServletResponse和HttpServletResponse):Servlet通过该对象来生成响应结果。
- Servelt配置对象(ServletConfig):当容器初始化一个Servlet对象时,会像Servlet提供一个ServletConfig对象,Servlet通过该对象来获取初始化参数以及ServletContext对象。
- Servlet上下文对象(ServletContext):Servlet通过该对象来访问容器为当前web应用提供的各种资源。
4.1 Servlet API
4.1.1 Servlet接口
Servlet API的核心接口是javax.servlet.Servlet接口。所有的Servlet类都必须实现这个接口。在Servlet接口中定义可5个方法,其中3个方法由Servlet容器来调用,容器会在Servlet的生命周期的不同时期调用特定的方法。
- init(ServletConfig config) 方法:该方法负责初始化Servelt对象。容器在创建好Servelt对象后,就会调用该方法。
- service(ServletRequest req, ServletResponse res)方法:负责响应客户的请求,为客户提供响应的服务。容器接收到客户要求访问特定Servlet对象的请求时,就会调用该Servlet对象的service()方法。
- destroy()方法:负责释放对象占用的资源。当Servlet的生命周期结束时,容器会调用此方法。
- getServletConfig():返回一个ServletConfig对象,该对象中包含了Servlet的初始化参数信息。
- gerServletInfo():返回一个字符串,该字符串包含了Servlet的创建者、版本和版本权等信息。
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
4.1.2 GenericServlet抽象类
GenericServlet抽象类为Servlet接口提供了通用实现。它与任何网络应用层协议无关,GenericServlet除了实现了Servlet接口,还实现了ServletConfig接口和Serializable接口。
package javax.servlet;
import java.io.IOException;
import java.util.Enumeration;
import java.util.ResourceBundle;
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable
{
private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
private static ResourceBundle lStrings =
ResourceBundle.getBundle(LSTRING_FILE);
private transient ServletConfig config;
public GenericServlet() { }
public void destroy() {
}
public String getInitParameter(String name) {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameter(name);
}
public Enumeration<String> getInitParameterNames() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getInitParameterNames();
}
public ServletConfig getServletConfig() {
return config;
}
public ServletContext getServletContext() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletContext();
}
public String getServletInfo() {
return "";
}
public void init(ServletConfig config) throws ServletException {
//是当前Servlet对象与传入进来的ServletConfig对象关联
this.config = config;
this.init();
}
public void init() throws ServletException {
}
public void log(String msg) {
getServletContext().log(getServletName() + ": "+ msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletName() {
ServletConfig sc = getServletConfig();
if (sc == null) {
throw new IllegalStateException(
lStrings.getString("err.servlet_config_not_initialized"));
}
return sc.getServletName();
}
}
GenericServlet定义了一个不带参数的init()方法,init(ServletConfig config)方法会调用此方法。对于GenericServlet类的子类,如果希望覆盖父类的初始化行为,有两种方法:
- 覆盖父类的不带参数的init()方法。
public void init(){
//子类的具体初始化行为
....
}
- 覆盖父类的带参数的init(ServletConfig config)方法。如果当前Servlet对象与ServletConfig对象关联,应该在方法中先调用super.init(ServletConfig config)方法:
public void init(ServletConfig config){
super.init();//调用父类的init(config)方法。
//子类的具体初始化行为
....
}
GenericServlet类没有实现Servlet接口中的service()方法,service()方法是GenericServlet中的唯一的抽象方法,它的子类必须实现它,从而为特定的客户端提供具体的请求服务。
GenericServlet实现了ServletConfig中的所有方法。
4.1.3 HttpServlet类
HttpServlet是GenericServlet的子类。为Servlet提供了与HTTP协议相关的通用实现。即HTTPservlet对象适合运行在与客户端采用了HTTP协议的Servlet容器或Web服务器中。
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 protocol = req.getProtocol();
String msg = lStrings.getString("http.method_get_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, 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 protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_put_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(405, msg);
} else {
resp.sendError(400, msg);
}
}
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_delete_not_supported");
if (protocol.endsWith("1.1")) {
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("non-HTTP request or response");
}
this.service(request, response);
}
}
HttpServlet类为每一种请求凡是都提供了相应的服务方法,如doGet()、doPost()、doPut()等doXXX()方法。
HttpServlet实现了Servlet接口中的service(ServletRequest req, ServletResponse res)方法,该方法实际调用的是它的重载方法。
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");
}
//service(ServletRequest req, ServletResponse res)重载方法service(HttpServletRequest req, HttpServletResponse resp)
this.service(request, response);
}
service(HttpServletRequest req, HttpServletResponse resp)方法会根据请求方式的不同调用相应的doXXX()方法。
4.1.4 ServletRequest接口
ServletRequest接口表示来自客户端的请求,当Servlet容器接收到请求时,容器先解析客户端的原始数据,把它包装成一个ServletRequest对象。当容器调用servive()方法时,就会把ServletRequest对象作为参数传给service()方法。
ServletRequest接口提供了一些读取客户端请求数据的方法。
- getContentLength()返回请求正文的长度。如果请求正文的长度未知,放回-1。
- getContentType():获得请求正文的MIME类型,类型未知返回null。
- getInputStream():返回用于读取请求正文的输入流。
- getLocalAddr():返回服务器端的IP地址。
- getLocalName():返回服务器端的主机名。
- getLocalPort():返回服务器端的端口。
- getParameter(String name):根据给定的请求参数名返回来自客户端请求中的匹配的参数值。
- getProtocol():返回通信协议的名称及版本。
- getReader():返回用于读取字符串形式的请求正文的BufferReader对象。
- getRemoteAddr():客户端IP。
- getRemoteHost():客户端主机名。
- getRemotePort():返回客户端的FTP端口号。
用于在请求范围类存取共享数据的方法:
- setAttribute(String name , Object object):保存一个属性,name属性名,object属性值。
- getAttribute(String name):根据属性名获取属性值。
- removeAttribute(String name):在请求范围内根据属性名删除某个属性。
4.1.5 ServletResponse接口
ServletResponse接口中有关响应结果的方法:
- setCharaterEnconding(String charset):设置响应正文的字符集,默认为ISO-8859-1。
- setContentLength(int len):设置响应正文的长度。
- setContentType(String type):设置响应正文的MIME类型。
- getCharaterEncoding:返回响应正文的字符编码。
- setBufferSize(int size):设置用于存放响应正文的缓冲区大小。
- getBufferSzie():获取用于存放响应正文的缓冲区大小。
- reset():清空缓冲区的正文数据,并且清空响应状态代码以及响应头。
- restBuffer():清空缓冲区的正文数据,但不清空响应状态代码以及响应头。
- flushBuffer():强制性的把缓冲区的响应正文数据发送给客户端。
- isCommitted():返回值为boolean,如果为true,表示缓冲区的数据已提交给客户。
- getOubtputStream():返回一个ServeltOutputStream对象,Servlet用它来输出二进制正文数据。
4.1.7 HttpServletResponse 接口
HttpServletResponse提供与HTTP协议相关的方法:
- addHeader(String name, String value):添加响应头。
- sendError(int src):向客户端发送一个代表错误的HTTP响应状态代码。
- sendError(int src, String msg):发送错误代码,并发送错误消息。
- setHeader(String name, String value):设置响应头。
- setStatus(int src):设置HTTP响应状态代码。
- addCookie(Cookie cookie):向HTTP响应中加入一个Cookie。
4.1.8 ServletConfig 接口
当Servlet容器初始化一个Servlet对象时,会为Servelt对象创建一个ServletConfig对象,ServeltConfig包含了Servlet的初始化信息。
//Servelt的实现类GernericServlet中的init方法
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
ServletConfig接口中定义的方法:
/**返回serlve的名字*/
String getServletName();
/**返回一个ServletContext对象*/
ServletContext getServletContext();
/**根据参数名返回初始化参数值*/
String getInitParameter(String var1);
/**Enumeration中包含了所有的初始换参数对象*/
Enumeration<String> getInitParameterNames();
HttpServlet类继承了GenericServlet,而GenericServlet实现了ServeltConfig接口,所以在HttpServlet或GenericServlet类中及其子类中都类直接调用ServeltConfig接口的方法。
4.1.9 ServletContext 接口
ServeltContext 是Servelt与Servlet容器之间进行通信的接口。Servelt容器在启动Web应用时,会为它创建一个ServeltContext对象。一个Web应用中只有唯一的一个ServeltContext对象。
ServletContext提供的方法可以分为以下几种类型:
(1)用于Web应用范围内存取共享数据的方法。
- setAttribute(String name, Object object):设置一个属性。
- getAttribute(String name):根据属性名获取属性值。
- getAttributeNames():返回一个Enumeration对象,该对象包含了所有存在ServletContext中的属性名。
- removeAttribute(String name):根据属性名删除一个属性。
(2)访问当前Web应用的资源。
- getContextPath():返回当前Web应用的URL入口。
- getInitParameter(String name):根据参数名返回初始化参数。
- getParameterNames():返回一个Enumeration对象,该对象包含了所有Web应用范围内的所有初始化参数名。
- getServletContextName():返回web应用的名字。web.xml中
<display-name>
的值。 - getRequestDispatcher():返回一个用于向其他Web组件转发请求的RequestDispatcher对象。
(3)访问Servelt容器中的其他Web应用。
- getContext(String uripath):根据指定参数的URI返回当前容器中其他Web应用的ServletContext对象。
(4)访问Servlet容器相关信息。
- getMajorVersion():Java Servlet API的主版本号。
- getMinorVersion():Java Servlet API的次版本号。
- getServletInfo():Servlet容器的版本和名字。
(5)访问服务器端的文件系统资源。
- getRealPath(String path):根据参数指定的虚拟路径,返回文件系统中的一个真实路径。
- getResource(String path):返回一个映射到参数指定的路径URL。
- getResourceAsStream(String path):返回一个用于读取参数指定的文件输入流。
(6)输出日志。
- log(String msg):向Servlet的日志文件中写日志。
- log(String message, Throwable throwable):向Servlet日志文件中写错误日志及异常的堆栈信息。
4.2 Java Web 应用的生命周期
Java Web应用的生命周期是由Servlet容器控制的。分为3各阶段。
- 启动阶段:加载Web应用有关的数据,创建ServletContext对象,对Filter和一些Servlet组件初始化。
- 运行时阶段:为客户提供服务。
- 终止阶段:释放Web应用说占用的各种资源。
4.2.1 启动阶段
Servlet容器在启动web应用时:
(1)把web.xml文件中的数据加载到内存中。
(2)为Java Web 应用创建ServletContext对象。
(3)对所有的Filter进行初始化。
(4)对需要在Web应用启动时就需要初始化的Servlet进行初始化。
4.2.2 运行时阶段
为客户提供相应的服务。
4.2.3 终止阶段
Servlet容器在终止Java Web应用时,会完成以下操作:
(1)销毁应用中所有处于运行状态的Servlet。
(2)销毁处于运行状态的Filter。
(3)销毁所有与应用相关的对象。如ServletContext等。
4.3 Servlet的生命周期
Java Web应用的生命周期由Servlet容器控制,而Servlet作为Java Web应用的核心组件,其生命周期也是由Servlet容器控制。Servelt的生命周期分为三个阶段。
- 初始化阶段init()。
- 运行时阶段service()。
- 销毁阶段destroy()。
4.3.1 初始化阶段
Servlet初始换阶段分为四个步骤:
- Servlet容器加载Servlet类,把他的class文件中的数据存到内存中。
- Servlet容器创建ServletConfig对象。
- Servlet容器创建Servlet对象。
- Servlet容器调用Servlet的init(ServletConfig config)方法。
4.3.2 运行时阶段
Servlet可以随时响应客户端的请求。当Servlet容器接收到访问特定Servlet客户的请求时,Servlet容器创建针对这个请求的ServeltRequest对象和ServeltResponse对象,然后调用该Servlet对象的service()方法。service()方法通过ServletRequest对象获取客户的请求信息并处理,通过ServletResponse对象生成响应结果。
当Servlet容器把Servlet生成的响应结果发送给客户后,Servlet容器就会销毁ServletReqeuest对象和Response对象。
4.3.3 销毁阶段
当Web应用被终止时,Servlet容器会先调用Web应用中所有Servlet的destory()方法,然后再销毁这些Servlet。
4.4 ServletContext 与 Web应用范围
ServletContext与Web应用具有同样的生命周期,因为Servlet容器在启动Web应用时,就会创建一个唯一的ServletContext对象,当Servlet容器终止一个Web应用时就会销毁ServletContext对象。
ServletContext是被Web应用中的所有Servlet共享的,所以在Web应用范围内可以用ServeltContext来存取共享数据。
4.1.1 在Web应用范围内存放共享数据的范例
package mypack;
public class Counter{
private int count; //计数值
public Counter(){
this(0);
}
public Counter(int count){
this.count=count;
}
public void setCount(int count){
this.count=count;
}
public int getCount(){
return count;
}
public void add(int step){
count+=step;
}
}
package mypack;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class CounterServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)throws ServletException, IOException {
//获得ServletContext的引用
ServletContext context = getServletContext();
// 从ServletContext中读取counter属性
Counter counter = (Counter)context.getAttribute("counter");
// 如果ServletContext中没有counter属性,就创建counter属性
if ( counter == null ) {
counter = new Counter(1);
context.setAttribute("counter", counter);
}
response.setContentType("text/html;charset=GBK");
PrintWriter out = response.getWriter();
out.println("<html><head><title>CounterServlet</TITLE></head>");
out.println("<body>");
// 输出当前的counter属性
out.println("<h1>欢迎光临本站。您是第 " + counter.getCount()+" 位访问者。</h1>");
out.println("</body></html>");
//将计数器递增1
counter.add(1);
out.close();
}
}
package mypack;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class CounterClearServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)throws ServletException, IOException {
//获得ServletContext的引用
ServletContext context = getServletContext();
context.removeAttribute("counter"); //删除counter属性
PrintWriter out=response.getWriter();
out.println("The counter is removed.");
out.close();
}
}
4.4.2 使用ServletContextListener
ServletContextListener接口能够监听ServeltContext对象的生命周期,实际上就是监听Web应用的生命周期。
当Servlet容器启动或终止Web应用时,会触发ServletContextEvent事件。该事件由ServletContextListener来处理。ServletContextListener接口中定义了两个处理ServletContextEvent事件的两个方法:
/**当Servlet容器启动Web应用时调用该方法。调用完该方法后,容器再对Filter初始化,并且对那些在Web应用启动时需要初始化的Servlet进行初始化*/
public void contextInitialized(ServletContextEvent sce);
/**容器终止Web应用时调用。在调用之前,会先销毁所有的Servelt和Filter*/
public void contextDestroyed(ServletContextEvent sce);
4.5 Servlet的服务方法跑出异常
Servlet接口的service()方法完整定义如下:
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
该方法中抛出两个异常:
ServletException:表示当前Servlet进行常规操作时出现异常。
IOException:进行IO操作时出现异常。
ServletException有一个子类UnavailableException,表示无法访问当前Servelt的异常。
4.6 防止页面被客户端缓存
浏览器能够缓存服务端的网页,需要访问这个网页时直接冲缓存中取,不会去请求访问远程服务器资源。
这种技术只适用于缓存服务器的静态资源及不包含敏感数据的网页。对于其他的资源,服务器往往不希望网页被客户端缓存。如:
- 网页中包含随时会被更新的内容。
- 网页中包含敏感数据,如特定的用户账号信息等。
服务器端的HttpServelt可以设置特定的HTTP响应头来禁止客户端缓存网页。
respone.addHeader("Paragma","no-cache");//适用于HTTP/1.0
或
response.setHeader("Cache-Control","no-cache");
或
response.setHeader("Expires","0");
4.7 使用Annotation标注配置Servlet
import javax.servlet.http.HttpServlet;
@WebServlet(name = "annotationServlet", //servlet名字
urlPatterns = {"/annotation"},//servlet访问路径
initParams = {@WebInitParam(name = "color",value = "blue"),
@WebInitParam(name = "size",value = "15")})//初始化参数
public class AnnotationServlet extends HttpServlet {
...
}
@WebServlet注解各个属性的用法
属性 | 类型 | 描述 |
---|---|---|
name | String | 指定Servlet的名字,等价于<servlet-name> ,如果没有,则默认为类的全限定名 |
urlPatterns | String[] | 指定一组Servlet的URL匹配模式,<url-patterns> |
loadOnStartup | int | 指定Servlet的加载顺序 |
initParams | WebInitParam[] | 指定初始化参数 |
description | String | 描述Servelt,<description> |
displayName | String | 指定Servlet的显示名,<desplay-name> |
4.8 处理HTTP请求参数中的中文字符编码
- 对读取到的请求参数进行字符编码转换
String username = request.getParameter("username");
username = new String(username.getBytes("ISO-8859-1"),"GBK");
- 对于POST请求,采用如下方式
request.setCharacterEncoding("GBK");
- 利用ServletContext对象的getRequestCharacterEncoding()和setRequestCharacterEncoding()方法来读取或设置当前Web应用中请求正文数据的字符编码。
- Tocmat的server.xml配置文件中连接器进行配置。
<Connector port="8080" redirectPort="8443" connectionTimeout="20000" protocol="HTTP/1.1" URIEncoding="UTF-8"/>