JavaWeb中的Servlet概述,javawebservlet概述
JavaWeb中的Servlet概述,javawebservlet概述
首先说一下Servlet是什么?
Java Servlet实际上是一个java类,Java Servlet实际上是一个java类,Java Servlet实际上是一个java类,重要的事说三遍。
只不过这个类必须运行在具有JavaServlet规范解释器的Web服务器上(例如Tomcat)
在这些支持规范解释器的服务器(例如Tomcat)上,一般都具有一个Servlet容器,当一个web请求到达服务器时,这个请求就会被委派到这个Servlet容器中,成为Servlet容器的管理对象,即这个Servlet对象就是当前浏览器的http请求(暂且这样理解,通俗易懂)
实际上:Java Servlet是运行在Web服务器(Tomcat之类)上的程序,作为web浏览器(或其他Http客户端的请求)和Tomcat服务器(Http服务器)上的数据库或应用程序之间的中间层,使用Servlet,不但可以收集网页表单的用户输入,也可以将数据库中的记录展示到网页上。
还是不明白Servlet是什么的,请直接跳到下面的代码实例去学习,从其代码层面理解,至于其生命周期,service方法可以先不了解。
Servlet能做什么:
1.读取浏览器发送的显示数据,表单等
2.读取浏览器发送的隐式数据,例如Cookies等
3.发送显示数据到浏览器
4.发送隐式的Http响应到浏览器,例如Cookies等
Servlet的生命周期:
当Http请求被委派到Servlet容器时,Servlet容器就会创建Servlet,创建该Servlet时,容器会调用Init方法。
注意,后续相同的http请求不会再创建Servlet,也不会再调用init方法(因为此时Servlet容器中已经存在了)
容器在调用init方法时,会简单的创建/加载一些数据,这些数据随着Servlet的存在而存在。
service() 方法:
service() 方法是执行实际任务的主要方法。
Web 服务器调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。
每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。
service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。
service() 方法也是由容器调用,所以不用对 service() 方法做任何动作。
只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。
doget(),doPost()方法
doGet() 方法:请求中不指定表单,
doPost() 方法:请求中指定表单。
比如说在浏览器的某个页面中有两个提交按钮,
按钮1提交的内容中有表单,那么你就需要使用dopost方法,进而再做一些处理。
按钮2提交的内容中无表单,那么你就需要使用doget方法,进而再做一些处理。
destroy() 方法
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。
destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
代码实例:
Servlet 是服务 HTTP 请求并实现 javax.servlet.Servlet 接口的 Java 类,下面的代码是web中常用的HttpServlet.
Web 应用程序开发人员通常编写 Servlet 来扩展 javax.servlet.http.HttpServlet,并实现 Servlet 接口的抽象类专门用来处理 HTTP 请求。
// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
// 扩展 HttpServlet 类
public class HelloWorld extends HttpServlet {
private String message;
public void init() throws ServletException
{
// 执行必需的初始化
message = "Hello World";
}
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
// 设置响应内容类型
response.setContentType("text/html");
// 实际的逻辑是在这里
PrintWriter out = response.getWriter();
out.println("<h1>" + message + "</h1>");
}
public void destroy()
{
// 什么也不做
}
}
不明白?不明白就要先大致了解Servlet的底层实现,具体看下面。
Servlet的底层实现:
在Servlet编程中我们必须使用到javax.servlet 和 javax.servlet.http这两个包以及其下面的类和接口。
在所有的类和接口中,javax.servlet.servlet 接口最为重要。因为所有的servlet程序都必须实现该接口或者继承实现了该接口的类。
这个接口定义了初始化 servlet 的方法、为请求提供服务的方法和从服务器移除 servlet 的方法。这些方法称为生命周期方法,它们是按以下顺序调用的:
1.构造 servlet,然后使用 init 方法将其初始化。
2.处理来自客户端的对 service 方法的所有调用。
3.从服务中取出 servlet,然后使用 destroy 方法销毁它,最后进行垃圾回收并终止它。
以下是Servlet的源码,他是一个接口:
package javax.servlet;
import java.io.IOException;
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
再说一下GenericServle:
GenericServlet 实现 Servlet 和 ServletConfig 接口,对这两个接口中的方法进行了简单实现。
GenericServlet 使编写 servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单版本,以及 ServletConfig 接口中的方法的简单版本。
GenericServlet 还实现 log 方法,在 ServletContext 接口中对此进行了声明。
要编写一般的 servlet,只需重写抽象 service 方法即可。
看一下其源码:
public abstract class GenericServlet
implements Servlet, ServletConfig, java.io.Serializable
{
//私有变量,保存 init()传入的ServletConfig对象的引用
private transient ServletConfig config;
public GenericServlet() { }
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init(); //调用了无参的 init()方法
}
//无参的init()方法
public void init() throws ServletException {
}
//空实现了destroy方法
public void destroy() { }
//实现了接口中的getServletConfig方法,返回ServletConfig对象
public ServletConfig getServletConfig()
{
return config;
}
//该方法实现接口<Servlet>中的ServletInfo,默认返回空字符串
public String getServletInfo() {
return "";
}
//当HttpServlet继承GenericServlet抽象类时需要实现service方法
public abstract void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
//得到ServletContext实例
public ServletContext getServletContext() {
return getServletConfig().getServletContext();
}
//得到servlet的配置参数
public String getInitParameter(String name) {
return getServletConfig().getInitParameter(name);
}
//得到servlet的配置参数名
public Enumeration getInitParameterNames() {
return getServletConfig().getInitParameterNames();
public String getServletName() {
return config.getServletName();
}
public void log(String msg) {
getServletContext().log(getServletName() + ": "+ msg);
}
public void log(String message, Throwable t) {
getServletContext().log(getServletName() + ": " + message, t);
}
}
HttpServlet源码:
在上面的GenericServlet中,已经对Servlet和ServletConfig进行了简单实现,这次我们需要使用http,所以我们需要对上面的实现进一步进行修改。
所以创建了一个HttpServlet抽象类,该类中含有我们需要使用的HttpServletRequest和HttpServletResponse。
这两个对象有必要说一下:
这两个对象都是接口,他们的父类也是接口,分别是ServletRequest和ServletResponse。
Servlet理论上可以处理多种形式的请求响应 ,http只是其中之一 ,所以这里的http开头的接口多了一些针对http协议的方法。
此时,你要明白,httpServlet中的doget和dopost方法中的形参都是tomcat传给他的,都是已经处理过的。
这时候如果你不明白继承了HttpServlet,重写其方法,就能完成你所需的操作,那么你就要去看一些多态的资料的。
这里举一个简单的例子:
假如说HttpServlet是动物类,你创建了一个猫类,即httpServletA,它继承了动物类,那么当你把动物类的方法覆盖掉(doget,dopost等),容器tomcat就会调用猫类的方法,没有猫类的方法就回去调用动物类的方法,这叫向上转型。
而猫类里面的doget和dopost方法里面的参数HttpServletRequest和HttpServletResponse,是怎么将ServletRequest转为HttpServlet的呢?
仔细想一下,HttpServletRequest是接口,ServletRequest也是接口,此时如果创建一个实体类,实现这两个接口,理论上来说向下转型是肯定没有问题的。
因而,转换为HttpServletRequest是没有问题的。
举个例子:假设ServletRequest是动物接口,HttpServletRequest是猫科动物接口,而实现类则为猫
当我们在doGet方法中,我们需要使用到的是猫(上述的实体类),所以用猫科动物这个称呼(调用)猫不会有问题!用动物这个称呼(调用)猫也不会有问题!
至于猫这个实现类是谁去实现的,里面的数据是什么,我们没必要去管它,那是tomcat的事。
我们只需要明白我们经历了什么,要做一些什么。
//继承GenericServlet抽象类
public abstract class HttpServlet extends GenericServlet
implements Serializable
{
public HttpServlet()
{
}
//get请求,自己的扩展类中需要覆写该方法
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);
}
//post请求,自己的扩展类中需要覆写该方法
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 doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
}
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);
}
protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String CRLF = "\r\n";
String responseString = (new StringBuilder()).append("TRACE ").append(req.getRequestURI()).append(" ").append(req.getProtocol()).toString();
for(Enumeration reqHeaderEnum = req.getHeaderNames(); reqHeaderEnum.hasMoreElements();)
{
String headerName = (String)reqHeaderEnum.nextElement();
responseString = (new StringBuilder()).append(responseString).append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName)).toString();
}
responseString = (new StringBuilder()).append(responseString).append(CRLF).toString();
int responseLength = responseString.length();
resp.setContentType("message/http");
resp.setContentLength(responseLength);
ServletOutputStream out = resp.getOutputStream();
out.print(responseString);
out.close();
}
//重载service(ServletRequest req, ServletResponse resp)方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
//判断客户端的请求方式
if(method.equals("GET"))
{
long lastModified = getLastModified(req);
if(lastModified == -1L)
{
doGet(req, resp);
} else
{
long ifModifiedSince = req.getDateHeader("If-Modified-Since");
if(ifModifiedSince < (lastModified / 1000L) * 1000L)
{
maybeSetLastModified(resp, lastModified);
doGet(req, resp); //执行doGet方法,所以需要覆写doGet方法
} else
{
resp.setStatus(304);
}
}
} else
if(method.equals("HEAD"))
{
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else
if(method.equals("POST"))
doPost(req, resp); //执行doPost方法,所以需要覆写doPost方法
else
if(method.equals("PUT"))
doPut(req, resp);
else
if(method.equals("DELETE"))
doDelete(req, resp);
else
if(method.equals("OPTIONS"))
doOptions(req, resp);
else
if(method.equals("TRACE"))
{
doTrace(req, resp);
} else
{
String errMsg = lStrings.getString("http.method_not_implemented");
Object errArgs[] = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
//重要
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
HttpServletRequest request;
HttpServletResponse response;
//将请求ServletRequest强转为HttpServletRequest,调用service(HttpServletReqeust req,HttpServletResponse resp)方法
try
{
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
}
catch(ClassCastException e)
{
throw new ServletException("non-HTTP request or response");
}
service(request, response); //调用service(HttpServletReqeust req,HttpServletResponse resp)方法
}
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 ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
}
到这里你一定要明白,我们编写网页时用的Servlet是服务器自动创建的,不是你创建的。
如果你想自己在本机试一下Servlet的创建过程请参考知乎上一篇文章:https://www.zhihu.com/question/21416727
在实现编码中,我们经常用到的就是基于http协议的Servlet实现,因为我们的网页想通过服务器获取一些数据时,必然要使用http协议.
在这个时候,服务器就要将我们原本的可以使用的但不完善支持http协议的Servlet进行扩展,扩展为可以完善支持http协议的Servlet,即HttpServlet。
至此Servlet的基本内容就在这里,更详细的各位可以参考下面的博客:
http://www.cnblogs.com/xdp-gacl/p/3760336.html
http://www.runoob.com/servlet/servlet-life-cycle.html
http://blog.csdn.net/xiaoxing1521025/article/details/8290092
相关文章
- 暂无相关文章
用户点评