1.1、用官方的话解释:
Servlet是oracle公司提供的一门用于开发动态web资源的技术,属于javaEE体系中的一种核心规范。
通俗解释一下:就是我们开发人员所编写的一个类,必须直接或者间接实现这个javaEE的核心规范,也就是实现Servlet接口,因为这种类产生的对象可以被浏览器访问到,因此称之为Servlet,并且javaEE中规定了只有Servlet的实现类产生的对象才可以被浏览器访问,就是Servlet.(也就是说这个类要直接或者间接实现了Servlet接口)
package com.briup.web;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class FirstWay implements Servlet {
public FirstWay() {
System.out.println("对象创建了");
}
@Override
public void init(ServletConfig config) throws ServletException {
// TODO Auto-generated method stub
System.out.println("我是init:我被调用了");
}
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("我是service,我被调用了");
}
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("我是destory:我被调用了");
}
}
那么,一个满足servlet的类已经创建好了,接下来抛出疑问
对于整个动态web项目而言,web.xml是最先加载的配置文件,所以在web.xml的方式配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<display-name>firstWay</display-name>
<servlet>
<servlet-name>FirstWay</servlet-name>
<servlet-class>com.briup.web.FirstWay</servlet-class>
<!-- <load-on-startup>1</load-on-startup> -->
</servlet>
<servlet-mapping>
<servlet-name>FirstWay</servlet-name>
<url-pattern>/FirstWay</url-pattern>
</servlet-mapping>
</web-app>
解释:
1、servlet-name:见名知意:servlet的名字,注意要与下面你设置映射的名字对应
2、serlvet-class:serlvet的全限定名
3、load-on-startup:是否在tomcat启动的时候就创建servlet对象,传入一个大于0的整数‘’(默认是浏览器第一次请求的时候创建servlet对象)
4、servlet-mapping:见名知意,设置浏览器的访问映射
5、servlet-name:于上面的对应
6、url-pattern:浏览器的访问映射(假设默认是本机的话,且tomcat的端口号为8080,那么浏览器访问这个servlet的路径为:localhost:8080/项目名/FirstWay)
有了这些基础,让我们访问看看;
@WebServlet(value ="映射路径")
public Fristservlet implement Servelt {
}
通过这个注解也可以设置,是否在启动服务器的时候就创建对象,这里就不演示了,
注意:(一旦使用了注解的方式告诉tomcat如果创建某个对象,就不能在web.xml里面再对这个servlet进行访问设置了)
有了前面的解释,直接上代码然后再分析
package com.briup.web;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
@WebServlet(value = "/secondWay")
public class SecondWayCreate extends GenericServlet {
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("调用了service方法");
}
}
public abstract class GenericServlet implements Servlet, ServletConfig,
可知,这是个抽线类,是servlet接口的实现类,那么GenericServlet间接 实现了servlet接口,
与第一种方式相比:开发者不是必须将一些接口中不必要的方法实现,可以具有选择性,减少了代码量。然而并没有上面ruan用,就是装b而已
直接上代码
package com.briup.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(value = "/ThreeWayCreate")
public class ThreeWayCreate extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
super.doPost(req, resp);
}
}
通过以上代码,可能就有小伙伴要问了
不是说servlet要直接或者间接实现servlet接口吗,不是说浏览器每请求一次就要调用一次service方法吗?方法在哪呢?这不是与前面理论冲突了吗?
我们继续看源码,源码才是道理
我在下面值列举源码里面比较核心的部分,需要理解更加深入了解的小伙伴,直接去看源码,tomcat是开源的
public abstract class HttpServlet extends GenericServlet {
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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
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(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
/*
* Sets the Last-Modified entity header field, if it has not
* already been set and if the value is meaningful. Called before
* doGet, to ensure that headers are set before response data is
* written. A subclass might have set this header already, so we
* check.
*/
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
service(request, response);
}
}
}
分析:
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
} catch (IllegalArgumentException iae) {
// Invalid date header - proceed as if none was set
ifModifiedSince = -1;
}
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
通过传过来的HttpRequest对象,判断请求方式,通过请求方式,决定调用哪个方法(如果请求方式是post方式,那么就会调用doPost(HttpRequest req,HttpRestpone Res)方法)
优点:
注意点:浏览器发起请求调用的一定是servlet种的service方法;
有任何错误或者见解希望各位读者指出互相进步,相互学习。