Servlet 概念
Servlet( Server Applet ),全称Java Servlet是运行在Web服务器或应用服务器上的程序,是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
个人理解:Servlet就是作为客户端界面和服务器端中间层的处理程序。
其作用主要是:
- 接受用户端(浏览器)的Request请求数据
- 处理请求并生成结果,可能需要访问数据库。
- 返回Response响应到用户端。
Servlet生命周期
1.init()方法,Servlet 通过调用 init () 方法进行初始化。
init()方法只在第一次创建Servlet时被调用一次,在后续每次用户请求时不再调用。
2. service()方法,Servlet 调用 service() 方法来处理客户端的请求。
service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
doGet() 和 doPost() 方法是每次服务请求中最常用的方法。
2.1 doGet()方法
GET 请求来自于:1. 一个 URL 的正常请求,2. 一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
GET调用会在URL里显示正传送给SERVLET的数据,这在系统的安全方面可能带来一些问题,比如用户登录,表单里的用户名和密码需要发送到服务器端, 若使用Get调用,就会在浏览器的URL中显示用户名和密码。
2.2 doPost()方法
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
Post通过HTTP post机制,将表单内的信息放在Form中传递给服务器。好处是可以隐藏传送给服务器的任何数据。Post适合发送大量的数据。
3. destroy()方法,Servlet 通过调用 destroy() 方法终止(结束)。
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。
destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
4. 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
实现Servlet接口的三种方式
1. Servlet接口
Servlet 类提供了五个方法,其中三个生命周期方法和两个普通方法。
但是通过实现Servlet接口来编写Servlet必须要实现接口中定义的所有方法,还需要自己手动的维护ServletConfig这个对象的引用,所以基本不会用这种方法实现Servlet。
以下是Servlet接口代码:
package javax.servlet;
import java.io.IOException;
public interface Servlet {
//生命周期方法:当Servlet第一次被创建对象时执行该方法,该方法在整个生命周期中只执行一次
void init(ServletConfig var1) throws ServletException;
//生命周期方法:对客户端响应的方法,该方法会被执行多次,每次请求该servlet都会执行该方法
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
//生命周期方法:当Servlet被销毁时执行该方法
void destroy();
//两个普通方法
ServletConfig getServletConfig();
String getServletInfo();
}
1.1 ServletRequest接口
public interface ServletRequest {
int getContentLength();//返回请求主体的字节数
String getContentType();//返回主体的MIME类型
String getParameter(String var1);//返回请求参数的值
}
getParameter是在ServletRequest中最常用的方法,可用于获取查询字符串的值。
例:URL = "http://localhost:8080/ProjectName/FormName?username=root&password=123”
利用**getParameter(“username”)**即可得到username的值为root
1.2 ServletResponse接口
public interface ServletResponse {
String getCharacterEncoding();
String getContentType();
ServletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() throws IOException;
void setCharacterEncoding(String var1);
void setContentLength(int var1);
void setContentType(String var1);
void setBufferSize(int var1);
int getBufferSize();
void flushBuffer() throws IOException;
void resetBuffer();
boolean isCommitted();
void reset();
void setLocale(Locale var1);
Locale getLocale();
}
其中getWriter方法,它返回了一个可以向客户端发送文本的的Java.io.PrintWriter对象。
在发送HTML之前,应该先调用setContentType(“text/html;charset=UTF-8”)方法
- 将“text/html”作为一个参数传入,告诉浏览器响应的内容类型为HTML,需要以HTML的方法解释响应内容而不是普通的文本
- 加上“charset=UTF-8”改变响应的编码方式以防止发生中文乱码现象。
2. GenericServlet类
GenericServlet 是一个抽象类,为Servlet接口中的所有方法提供了默认的实现。通过继承该类,实现Servlet只需要更改自己的需要的部分。
在 GenericServlet 中,主要完成了以下任务:
- 将 init() 中的 ServletConfig 参数赋给了一个内部的ServletConfig引用从而来保存ServletConfig对象,可以由 getServletConfig()方法获得;
- 为Servlet 所有方法提供默认实现;
- 可以直接调用 ServletConfig 中的方法;
如果继承GenericServlet类的话,我们必须重写 service() 方法来对处理请求。
GenericServlet类的基本结构:
abstract class GenericServlet implements Servlet,ServletConfig{
//GenericServlet通过将ServletConfig赋给类级变量
private ServletConfig Config;
public void init(ServletConfig servletConfig) throws ServletException {
this.servletConfig=servletConfig;
/*自定义不带参数的init()的原因是?见下方*/
this.init();
}
//自定义的init()方法,可以由子类覆盖
public void init(){
}
//实现service()空方法,并且声明为抽象方法,强制子类必须实现service()方法
public abstract void service(ServletRequest request,ServletResponse response)
throws ServletException,java.io.IOException{
}
//实现空的destroy方法
public void destroy(){ }
}
自定义不带参数init()方法的原因:
如果在类中覆盖了GenericServlet抽象类的init(ServletConfig servletConfig)方法,那么程序员就必须手动的去维护ServletConfig对象了,这样会给程序员带来很大的麻烦。
这个不带参数的 init() 方法,是在ServletConfig对象被赋给ServletConfig引用后,由第一个带参数的init(ServletConfig servletconfig)方法调用的,那么这意味着,当程序员如果需要覆盖这个GenericServlet的初始化方法,则只需要覆盖那个不带参数的init( )方法就好了,此时,servletConfig对象仍然有GenericServlet保存着。
3. HttpServlet类
HttpServlet 也是一个抽象类,它进一步继承并封装了 GenericServlet,使得使用更加简单方便,由于是扩展了 Http 的内容,所以还需要使用 HttpServletRequest 和 HttpServletResponse,这两个类分别是 ServletRequest 和 ServletResponse 的子类。
开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。
abstract class HttpServlet extends GenericServlet{
//HttpServlet类中的service()方法
protected void service(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse){
//该方法通过httpServletRequest.getMethod()判断请求类型,
//并调用以下方法之一:doGet,doPost,doHead,doPut,doTrace,doOptions和doDelete
//其中doGet() doPost()是最常用的
//所以,通过继承HttpServlet类,不再需要覆盖service方法,只需要覆盖doGet或者doPost就好了。
//以下具体实现省略
}
//必须实现父类GenericServlet的service()方法
public void service(ServletRequest servletRequest,ServletResponse servletResponse){
HttpServletRequest request;
HttpServletResponse response;
try{
request=(HttpServletRequest)servletRequest;
response=(HttpServletResponse)servletResponse;
}catch(ClassCastException){
throw new ServletException("non-http request or response");
}
//调用自己的service()方法
this.service(request,response);
}
}
HttpServlet有两个特性是GenericServlet所不具备的:
- 不用覆盖service方法,而是覆盖doGet()或者doPost()方法。在少数情况,还会覆盖其他的5个方法。
- 使用的是HttpServletRequest和HttpServletResponse对象。
3.1 HttpServletRequest接口
HttpServletRequest扩展于ServletRequest接口,并添加了几个方法。
因为Request代表请求,所以我们可以通过该对象分别获得HTTP请求的请求行,请求头和请求体。
String getContextPath();//返回请求上下文的请求URI部分
Cookie[] getCookies();//返回一个cookie对象数组
String getHeader(String var1);//返回指定HTTP标题的值
String getMethod();//返回生成这个请求HTTP的方法名称
String getQueryString();//返回以GET方式提交,URL地址后的参数字符串
HttpSession getSession();//返回与这个请求相关的会话对象
3.2 HttpServletResponse接口
HttpServletResponse接口,它继承自ServletResponse接口,专门用来封装HTTP响应消息。
由于HTTP请求消息分为状态行,响应消息头,响应消息体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法。
void addCookie(Cookie var1);//给这个响应添加一个cookie
void addHeader(String var1, String var2);//给这个请求添加一个响应头
void sendRedirect(String var1) throws IOException;//发送一条响应码,讲浏览器跳转到指定的位置
void setStatus(int var1);//设置响应行的状态码