💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Servlet入门 ### 基本概述     Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。     Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。 PS:学习Servlet是学习JSP的基础,故很重要。   ### Servlet在网络中的位置 ![](https://box.kancloud.cn/2016-02-23_56cbf5ff00173.jpg) ### Servlet的生命周期 ![](https://box.kancloud.cn/2016-02-23_56cbf5ff2ad54.jpg) 1、WEB服务器(Tomcat)首先会找到该Servlet并装载该Servlet 2、WEB服务器(Tomcat)会创建该Servlet的实例 3、WEB服务器(Tomcat)会调用实例对象的init()方法 4、WEB服务器(Tomcat)创建一个封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用service()方法并将请求对象和响应对象作为参数传递进去。(实现是通过多线程技术) 5、WEB服务器在某种情况,停止对该Servlet支持,Servlet引擎将卸载该Servlet,在卸载之前会调用Servlet的destroy()方法进行销毁 ### 手工开发Servlet的方式 1、在Tomcat主目录的webapps文件夹下建立一个web应用web1 2、在web1下建立文件夹WEB-INF,在该文件夹中建立web.xml [web.xml可以从 ROOT/WEB-INF/web.xml拷贝]  3、在WEB-INF目录下建立classes目录(Servlet在该目录下开发),建立lib目录 4、在classes目录下开发Servlet 5、在web.xml中配置web.xml 6、编译Servlet文件(编译时需要将servlet-api.jar包加入环境变量classpath中,该jar包在Tomcat主目录的lib文件夹下) 7、运行Tomcat 8、访问Servlet ### 开发Servlet的三种方法 #### 1、实现Servlet接口 ~~~ /** 使用实现Servlet接口的方式开发一个Servlet 要求:显示当前时间 */ package com.pc; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Servlet2 implements Servlet{ // 该方法用于初始化Servlet,就是把该Servlet装载入内存,该方法只会被调用一次 public void init(ServletConfig config){ } // 得到ServletConfig对象 public ServletConfig getServletConfig(){ return null; } // 该方法是服务方法,业务逻辑代码写在这 // 该方法每次都会被调用 public void service(ServletRequest req, ServletResponse res) throws ServletException, java.io.IOException{ // 在控制台输出 System.out.println("hello world:" + new java.util.Date().toString()); // 在浏览器返回 res.getWriter().println("hello world:" + new java.util.Date().toLocaleString()); } // 该方法得到Servlet配置信息 public java.lang.String getServletInfo(){ return null; } // 销毁该Servlet,从内存中清除,该方法只会被调用一次 public void destroy(){ } } ~~~   PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下: ~~~ <!-- servlet部署到web.xml文件,该部署配置可以从examples下拷贝 --> <servlet> <!--servlet-name 该名字可以自定义,但是默认就使用servlet的名字 --> <servlet-name>Servlet2</servlet-name> <!--servlet-class要指明该servlet放在那个包下的 --> <servlet-class>com.pc.Servlet2</servlet-class> </servlet> <!-- servlet的映射 --> <servlet-mapping> <!-- 这个servlet-name要和上面的servlet-name名字一样,这样才能匹配的上 --> <servlet-name>Servlet2</servlet-name> <!-- url-pattern 这是访问该servlet的资源部分 默认命名规范:就是该servlet的名字--> <url-pattern>/Servlet2</url-pattern> </servlet-mapping> ~~~ PS: 1、在classes文件夹下编译(当然Servlet文件也应该在这里) javac -encoding UTF-8 -d . Servlet文件名.java 2、不重启更新web应用 首先,在Tomcat主目录的conf文件夹中找到tomcat-users.xml文件,打开它,并在<tomcat-user></tomcat-user>标签中添加如下语句 ~~~ <tomcat-users> <role rolename="manager-gui"/> <user username="tomcat" password="s3cret" roles="manager-gui"/> </tomcat-users> ~~~ 然后,在localhost:8080主界面点击,进入manager界面,找到该应用,点击reload按钮即可。 #### 2、继承GenericServlet类 ~~~ /** 使用继承GenericServlet的方式开发一个Servlet */ package com.pc; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Servlet3 extends GenericServlet{ // 该方法是服务方法,业务逻辑代码写在这 // 该方法每次都会被调用 public void service(ServletRequest req,ServletResponse res) throws ServletException,IOException{ res.getWriter().println("hellow,world, GenericServle."); } } ~~~ PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下: ~~~ <servlet> <servlet-name>Servlet3</servlet-name> <servlet-class>com.pc.Servlet3</servlet-class> </servlet> <servlet-mapping> <servlet-name>Servlet3</servlet-name> <url-pattern>/Servlet3</url-pattern> </servlet-mapping> ~~~ #### 3、继承HttpServlet类 ~~~ /** 使用继承HttpServlet的方式开发一个Servlet 要求:显示当前时间 */ package com.pc; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Servlet4 extends HttpServlet{ // 在HttpServlet中,设计者分别提供了对Post提交和Get提交的处理,默认是get提交 // doGet().doPost()底层也是调用service方法 // 处理Get请求 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException{ resp.getWriter().println("doGet()"); } // 处理Post请求 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ resp.getWriter().println("doPost()"); } } ~~~ PS:不仅要写Servlet文件,还要在web.xml中添加配置信息,配置信息格式如下: ~~~ <servlet> <servlet-name>Servlet4</servlet-name> <servlet-class>com.pc.Servlet4</servlet-class> </servlet> <servlet-mapping> <servlet-name>Servlet4</servlet-name> <url-pattern>/Servlet4</url-pattern> </servlet-mapping> ~~~ ### 使用MyEclipse集成开发环境IDE来开发Web应用 PS:具体的配置步骤可以参考搜索引擎。 #### MyEclipse的开发目录结构 ![](https://box.kancloud.cn/2016-02-23_56cbf5ff553e8.jpg) ### Servlet细节问题 #### 1、一个已经注册的Servlet可以被多次映射 ~~~ <servlet> <description>This is the description of my J2EE component</description> <display-name>This is the display name of my J2EE component</display-name> <!-- servlet的注册名 --> <servlet-name>MyServlet1</servlet-name> <!-- servlet类的全路径(包名+类名) --> <servlet-class>com.web1.servlet.MyServlet1</servlet-class> </servlet> <!-- 对一个已经注册的servlet的映射 --> <servlet-mapping> <!-- servelt的注册名 --> <servlet-name>MyServlet1</servlet-name> <!-- servlet的访问路径 --> <url-pattern>/MyServlet1</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>MyServlet1</servlet-name> <url-pattern>/abc</url-pattern> </servlet-mapping> ~~~ #### 2、当映射一个Servlet时,可以多层映射 ~~~ <url-pattern>/servlet/index.html</url-pattern> ~~~ #### 3、在Servlet使用通配符映射到URL 有两种格式: 第一种格式  *.扩展名  比如 *.do  *.ss 第二种格式  以 / 开头 同时以 /* 结尾  比如  /*   /news/*    通配符案例:     Servlet1 映射到 /abc/*      Servlet2 映射到 /*      Servlet3 映射到 /abc      Servlet4 映射到 *.do  问题: 1、当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应 Servlet引擎将调用Servlet1。 2、当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应 Servlet引擎将调用Servlet3。 3、当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet1。 4、当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet2。 5、当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应 Servlet引擎将调用Servlet2。   在匹配的时候,要参考的标准:     1、看谁的匹配度高,谁就被选择     2、*.do 的优先级最低 #### 4、servlet中的<load-on-startup>配置     当需要在网站启动时,初始化一些资源时可以配置<load-on-startup> ~~~ <servlet> <load-on-startup>1</load-on-startup> </servlet> ~~~ PS:在servlet中如此配置就行,中间的数是整数,越小优先级越高。 配置好了之后,在网站启动时就会调用该Servlet的init()方法,所以可以在该方法中进行需要的初始化步骤,比如定时刷新,建立内存表之类的等等。 ### ServletConfig对象     该对象主要用于读取 servlet的配置信息. 案例: ~~~ <servlet> <servlet-name>ServletConfigTest</servlet-name> <servlet-class>com.web1.servlet.ServletConfigTest</servlet-class> <!-- 这里可以给servlet配置信息,这里配置的信息,只能被该servlet 读取 --> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </servlet> ~~~ 如何使用:在Servlet使用如下语句 ~~~ String encoding = this.getServletConfig().getInitParameter("encoding"); ~~~ 补充说明:这种配置参数的方式,只能被某个Servlet独立使用.如希望让所有的Servlet都去读取某个参数,这样配置: ~~~ <!-- 如果这里配置参数,可被所有servlet读取 --> <context-param> <param-name></param-name> <param-value></param-value> </context-param> ~~~ 读取所有的参数,可以使用如下方法: ~~~ Enumeration<String> names=this.getServletConfig().getInitParameterNames(); while(names.hasMoreElements()){ String name=names.nextElement(); System.out.println(name); System.out.println(this.getServletConfig().getInitParameter(name)); } ~~~ ### 注意事项: 1、Servlet类是单例模式的,所以要注意线程同步情况。 2、Servlet的service()方法,在每次响应时都会调用一次。 3、Servlet的init()初始化方法,destroy()销毁方法只会被调用一次。 4、Servlet的service()方法,会根据客户端的请求方法来决定调用对应的doXXX()方法。 5、不要重写构造方法,因为所继承的HttpServlet及其父类都已经对构造方法进行了某些初始化,当不了解这些系统自带的初始化,然后盲目使用构造方法,可能导致Servlet无法创建实例。 6、不要重写service方法(在继承HttpServlet的情况下),因为其内部有判别客户端请求方法的逻辑和一些其他逻辑。 7、必须重写doPost()或者是doGet()方法中的一个。 8、当想用一种逻辑去处理Get和Post请求,可以采用委托机制,在doPost方法内加入this.doGet(request, response); 或者在doGet方法中加入this.doPost(request, response); 9、继承HttpServlet开发Servlet是最常用的方法。 10、get提交和post提交的区别     10.1、从安全的角度看,get < post,因为get会把提交的信息显示到地址栏。     10.2、从提交内容大小看, get < post, get一般不要大于2k,post理论无限制,但是在实际开发中,建议不要大于64k     10.3、从速度看,get > post,因为get仅仅只是获取数据而已 11、Servlet的映射的后缀名不一定代表它就真的是那格式的文件。       ----------参考《韩顺平.细说Servlet》