Servlet入门

Servlet是JavaWeb三大组件(Servlet,Filter,Listener)之一,是SUN公司提供的一门动态资源开发的技术,下面简单记录一下如何在IDEA下创建一个自定义Servlet、如何修改Servlet模板、Servlet运行过程简单分析等。

IDEA创建自定义Servlet

Servlet是顶级接口,下面是GenericServlet抽象类,这个抽象类实现了Servlet的大部分方法,只有一个抽象方法service。如果要做web应用,需要扩展为httpServlet,它实现了Http协议。上一篇Tomcat入门已经介绍了手写一个简单Servlet并放到tomcat目录下,这里使用IDEA来创建并完成部署。

(1)新建一个新项目,选择Java Enterprise,Application Server中找到自己安装的tomcat,选择Web Application,点击next。

(2)Project name输入自己的项目名,这点类似eclipse,可以看到它的位置在D盘的IDEAproject目录下,IDEAproject类似eclipse中的workspace工作空间,点击finish。

(3) IDEA新建的项目,WEB-INF下是没有classes和lib的,需要手动建立文件夹并关联项目。

 

进入project structure设置界面(IDEA在eclipse使用习惯下使用ctrl+shift+alt+S),需设置java编译后输出的class路径和外部导入jar包的路径lib,就是刚才创建的目录。

class输出文件夹关联设置:

lib文件夹关联设置,选择Jar Directory:

勾选lib后确认。

(4) 设置项目部署的位置,这里修改为部署到tomcat的webapp目录下。

(5)配置Tomcat服务器,选择Server选项,可以修改服务器名,After lauch不勾选,选择就是使用默认打开地址,这里使用我们自己的打开路径,因此不勾选。On frame deactivation设置为Update classes and resources,代表鼠标离开IDEA界面也可以实现类和资源的更新。最后将Deploy application configured in Tomcat instance勾选上,代表支持热部署?

继续选择Deployment,Application Context名字设置和工程名字一样的名字,点击OK就完成前期基本配置。

自定义一个Servlet 

如图,IDEA中可以方便的创建servlet(选择Create New Servlet),只需要我们重写doGet方法和doPost方法。

自动生成代码如下,在Servlet3.0版本中,除了配置web.xml来配置servlet,还可以使用注解的方式,两者都可以实现,但是不能共存,否则启动tomcat就会报错。

 1 package com.boe.servlet;
 2 
 3 import javax.servlet.ServletException;
 4 import javax.servlet.annotation.WebServlet;
 5 import javax.servlet.http.HttpServlet;
 6 import javax.servlet.http.HttpServletRequest;
 7 import javax.servlet.http.HttpServletResponse;
 8 import java.io.IOException;
 9 
10 //@WebServlet("/MyFirstServlet")
11 public class MyFirstServlet extends HttpServlet {
12     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
13         //测试向浏览器发送一段文字
14         response.getWriter().write("<a style='color:blue;font-family:微软雅黑;font-size:20px'>this is my first servlet</a>");
15     }
16 
17     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
18         doPost(request, response);
19     }
20 }

等效web.xml中的如下配置

1     <!--配置servlet-->
2     <servlet>
3         <servlet-name>myservlet</servlet-name>
4         <servlet-class>com.boe.servlet.MyFirstServlet</servlet-class>
5     </servlet>
6     <servlet-mapping>
7         <servlet-name>myservlet</servlet-name>
8         <url-pattern>/MyFirstServlet</url-pattern>
9     </servlet-mapping>

部署完成后启动tomcat,访问servlet可以正常向页面返回信息(暂时不考虑中文乱码问题,后续考虑),以下是部署到tomcat的webapp下的目录结构。

测试结果。

这样就完成了一个基本的Servlet,查看HttpServlet源码,发现service方法底层会根据method类型,执行不同的方法,如GET和POST请求,就会执行doGet和doPost方法,因此重写这两个方法,跟重写service方法效果一样,以下为service方法源码。

 1     protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 2         String method = req.getMethod();
 3         long lastModified;
 4         if (method.equals("GET")) {
 5             lastModified = this.getLastModified(req);
 6             if (lastModified == -1L) {
 7                 this.doGet(req, resp);
 8             } else {
 9                 long ifModifiedSince;
10                 try {
11                     ifModifiedSince = req.getDateHeader("If-Modified-Since");
12                 } catch (IllegalArgumentException var9) {
13                     ifModifiedSince = -1L;
14                 }
15 
16                 if (ifModifiedSince < lastModified / 1000L * 1000L) {
17                     this.maybeSetLastModified(resp, lastModified);
18                     this.doGet(req, resp);
19                 } else {
20                     resp.setStatus(304);
21                 }
22             }
23         } else if (method.equals("HEAD")) {
24             lastModified = this.getLastModified(req);
25             this.maybeSetLastModified(resp, lastModified);
26             this.doHead(req, resp);
27         } else if (method.equals("POST")) {
28             this.doPost(req, resp);
29         } else if (method.equals("PUT")) {
30             this.doPut(req, resp);
31         } else if (method.equals("DELETE")) {
32             this.doDelete(req, resp);
33         } else if (method.equals("OPTIONS")) {
34             this.doOptions(req, resp);
35         } else if (method.equals("TRACE")) {
36             this.doTrace(req, resp);
37         } else {
38             String errMsg = lStrings.getString("http.method_not_implemented");
39             Object[] errArgs = new Object[]{method};
40             errMsg = MessageFormat.format(errMsg, errArgs);
41             resp.sendError(501, errMsg);
42         }
43 
44     }

访问原理分析

如下是request请求头和请求行里的内容,请求行里host为localhost代表访问的虚拟主机,另外默认端口号是80,通过这两个说明访问的是本机的tomcat服务器。如果Host中没写localhost就访问默认虚拟主机,这个在tomcat的server.xml中Engine标签的defaultHost属性指定了。然后请求行里还包括访问的资源路径,如MyServlet就是一个web应用的虚拟路径,通过它可以找到实际web资源的目录,这里使用的是第二种虚拟路径-实际路径映射的配置,可以在IDEA的tomcat目录下,找到同名的xml文件,里面写的就是实际资源的路径。

以下为文件路径和内容。

然后确定了web资源的位置后,最后需读取web.xml或者@WebServlet中配置的关系,来确定要访问的真实资源,这里web.xml中就指定了真实资源的位置,即com/boe/servlet/MyFirstServlet,这是一个手写的servlet,访问它后执行doGet方法,最后返回一个字符到页面。

访问静态资源

前面tomcat入门就知道,web目录下,WEB-INF目录外的图片,音频等资源为静态资源,也可以直接访问。本次将一张图片放到了web目录下,重新设置部署后可以直接读取图片内容,如下所示。

放入图片,到web目录下,注意不要放到WEB-INF下,万一放到WEB-INF下也可以,但是需要先创建一个static文件夹,将图片放入,也可以直接访问。

设置资源

重新部署后访问结果,发现可以直接访问。

为什么可以访问静态资源呢,首先会读取当前web应用下的web.xml,匹配所有url-pattern发现没有匹配的资源,然后会读取conf/web.xml,调用缺省的servlet来匹配静态资源,如果匹配到就显示,没有就报错404。

servlet模板修改

Servlet默认的模板是包含name属性和value属性的,对应就是web.xml中的servlet-name和url-pattern,并且doGet方法和doPost需要单独实现,这里可以修改。

这样修改后的,就只有省略value属性后的地址,如果有多个参数,value就不能省略了。

Servlet运行过程与生命周期

运行过程:

i. 通过Host标签确定访问虚拟主机。
ii. 通过资源名称部分确定访问的是哪一个web应用,可以设置缺省web应用。
iii. 通过资源名称部分确定访问的是哪一个web资源,这里就是servlet或者图片。
iv. 确定是哪一个Servlet资源后,会创建对应Servlet对象,执行其中的service方法,这里是执行doGet方法和doPost方法,本质上一样。
v. 在service方法执行完成之后,会将response缓冲区中的内容在服务器组织成一定结构。
vi. 最终将组织好的结果数据响应到浏览器中。
 
生命周期:
在Servlet被初次访问的时候,会在tomcat内存中创建一个当前Servlet的对象,并且会立刻调用init方法完成初始化的操作。这个对象会驻留在内存中的,再次访问这个servlet时,都是访问这个对象,当web应用移除后,就会自动调用destroy方法完成销毁,人为调用这个方法无效。 
 

参考博文:

(1)https://www.cnblogs.com/zyx110/p/10771172.html servlet

原文地址:https://www.cnblogs.com/youngchaolin/p/11502655.html