Servlet
- Servlet是Java提供的一门动态web资源开发技术,其实就是一个接口(规范),将来我们需要自定义Servlet类实现Servlet接口即可,并由web服务器运行Servlet。
快速入门
- 创建Web项目,导入Servlet依赖坐标
-
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency>
-
- 定义一个类,实现Servlet接口,并重写其中的方法,并在service方法中输出一句话
- 使用注解方式配置@WebServlet,配置该Servlet的访问路径(就是这个Servlet处理哪些请求)
- 访问,启动tomcat,输入url地址,访问对应的Servlet类
- 通过maven插件的方式来启动tomcat服务器,然后在浏览器中输入对应的url地址
- 通过maven插件的方式来启动tomcat服务器,然后在浏览器中输入对应的url地址
Servlet执行流程
- Servlet由web服务器创建,其中的方法也由web服务器来调用
Servlet生命周期
- Servlet运行在web服务器中(Servlet容器)、其生命周期由容器管理,分为四个阶段
- 加载实例化:默认情况下,在Servlet第一次被访问时,有容器创建Servlet对象
- loadStartup
- 负整数:Servlet对象第一次被访问是创建
- 正整数或0:服务器启动时,创建Servlet对象,数字越小优先级越高
- loadStartup
- 初始化:在Servlet实例化之后,容器调用其中的init()方法初始化Servlet对象,完成加载配置文件、创建连接等功能,该方法只调用一次。
- 处理请求:每当请求Servelt时,Servlet容器都会调用Servlet的service()方法对请求进行处理
- 服务终止:当释放内存或容器关闭的时候,容器都会调用Servlet中的destroy()方法,完成资源的释放,在destroy()方法调用之后,容器会释放这个Servlet实例对象,该实例对象随后会被Java的垃圾回收器所回收。
- 加载实例化:默认情况下,在Servlet第一次被访问时,有容器创建Servlet对象
Servlet体系结构
- 方法
- 除了上述三个必须执行的方法之外,还有两个方法
-
// 获取ServletConfig对象public ServletConfig getServletConfig() {return null;}// 获取Servlet信息public String getServletInfo() {return null;}
-
- 除了上述三个必须执行的方法之外,还有两个方法
- 体系结构
-
GenericServlet类实现类Servlet接口,HttpServlet类(对HTTP协议封装的Servlet类)继承GenericServlet类
- 我们将来开发B/S框架的web项目,都是针对HTTP协议,所以我们自定义Servlet,继承HttpServlet即可,在自定义的Servlet类中编写处理get/post请求的方法即可。
-
- HttpServlet中为什么要根据请求方式的不同,调用不同的方法,以及如何调用
- 在接口Servlet的Service方法中,会对请求的参数信息进行处理,但是不同请求的参数位置不同,get请求的请求参数就在请求行中,post请求的请求参数在请求体中,所以要使用不同的请求逻辑。而这些逻辑被封装到HttpServlet类中,我们创建的Servlet类直接继承HttpServlet类即HttpServlet类的源码如下()
-
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) //package javax.servlet.http;import java.io.IOException; import java.lang.reflect.Method; import java.text.MessageFormat; import java.util.Enumeration; import java.util.ResourceBundle; 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 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");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 {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 Method[] getAllDeclaredMethods(Class<? extends HttpServlet> c) {Class<?> clazz = c;Method[] allMethods;for(allMethods = null; !clazz.equals(HttpServlet.class); clazz = clazz.getSuperclass()) {Method[] thisMethods = clazz.getDeclaredMethods();if (allMethods != null && allMethods.length > 0) {Method[] subClassMethods = allMethods;allMethods = new Method[thisMethods.length + allMethods.length];System.arraycopy(thisMethods, 0, allMethods, 0, thisMethods.length);System.arraycopy(subClassMethods, 0, allMethods, thisMethods.length, subClassMethods.length);} else {allMethods = thisMethods;}}return allMethods != null ? allMethods : new Method[0];}protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Method[] methods = this.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;for(int i = 0; i < methods.length; ++i) {String methodName = methods[i].getName();if (methodName.equals("doGet")) {ALLOW_GET = true;ALLOW_HEAD = true;} else if (methodName.equals("doPost")) {ALLOW_POST = true;} else if (methodName.equals("doPut")) {ALLOW_PUT = true;} else if (methodName.equals("doDelete")) {ALLOW_DELETE = true;}}StringBuilder allow = new StringBuilder();if (ALLOW_GET) {allow.append("GET");}if (ALLOW_HEAD) {if (allow.length() > 0) {allow.append(", ");}allow.append("HEAD");}if (ALLOW_POST) {if (allow.length() > 0) {allow.append(", ");}allow.append("POST");}if (ALLOW_PUT) {if (allow.length() > 0) {allow.append(", ");}allow.append("PUT");}if (ALLOW_DELETE) {if (allow.length() > 0) {allow.append(", ");}allow.append("DELETE");}if (ALLOW_TRACE) {if (allow.length() > 0) {allow.append(", ");}allow.append("TRACE");}if (ALLOW_OPTIONS) {if (allow.length() > 0) {allow.append(", ");}allow.append("OPTIONS");}resp.setHeader("Allow", allow.toString());}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<String> 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());}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 = req.getDateHeader("If-Modified-Since");if (ifModifiedSince < lastModified) {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 {if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {HttpServletRequest request = (HttpServletRequest)req;HttpServletResponse response = (HttpServletResponse)res;this.service(request, response);} else {throw new ServletException("non-HTTP request or response");}} }
-
我们可以看到其中对于Http中的其中不同的请求方式都进行了判断,并且进行了封装,我们自定义的Servlet类继承HttpServlet类就可以,然后重写其中的不同的方法来处理不同类型的请求即可,简单讲就是HttpServlet类帮我们完成了url请求的类型的判断,我们只需要完成对于不同请求类型的处理逻辑即可。
-
- 在接口Servlet的Service方法中,会对请求的参数信息进行处理,但是不同请求的参数位置不同,get请求的请求参数就在请求行中,post请求的请求参数在请求体中,所以要使用不同的请求逻辑。而这些逻辑被封装到HttpServlet类中,我们创建的Servlet类直接继承HttpServlet类即HttpServlet类的源码如下()
Servlet urlPattern配置
- urlParttern就是设置Servlet类访问路径,即该请求被哪一个Servlert来进行逻辑处理,在实际的开发过程中,前后端应该是通过需求文档来确定访问路径的(产品经理提供好)
- 一个Servlet可以配置多个访问路径
- urlParttern配置规则
- 精确匹配
- 目录匹配
- 拓展名匹配
- 任意匹配
- /和/*的区别(这两个在以后的servlet访问路劲中尽量不要使用)
- 当我们的项目中的Servlet配置了“/”,会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上的时候,就会调用该默认的servlet,该默认Servlet会处理项目中静态资源的访问,如果覆盖掉就无法范文静态资源(html页面等.)。
- 当我们项目中的配置了“/*“,意味该Servlet匹配任意访问路径
- 优先级
- 精确路径》目录路径》拓展名路径》/*》/
- 精确度来划分(在一个项目应该指挥只会使用一种方式来进行配置)
xml配置方式编写Servlet
- 以后学习框架很多都是全注解开发,就是用注解来讲xml配置方式给替代掉,使用起来非常方柏霓,但学习xml配置方式也有助于我理解注解配置方式,要理解xml配置方式,就需要学习Spring的原理了,可以参考我在Spring专栏的相关文章。
- 编写好Servlet类之后,我们需要在web.xml配置文件中,进行对应的映射