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运行过程与生命周期
运行过程:
参考博文: