一、什么是Servlet?
顾名思义,server applet ,运行在服务器端的Java小程序,定义了一个类被浏览器访问的规则,是一个接口。
功能:接受请求、处理请求、作出响应二、Servlet初涉
(1)原始的开发流程
1--创建web项目
2--定义一个Java类,实现Servlet接口
3--重写所有未实现方法(5个)
4--在web.xml配置Servlet
(2)实现的五个方法的说明
package org.wzj.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { //方法1 } @Override public ServletConfig getServletConfig() { //方法2 return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException{ //方法3 } @Override public String getServletInfo() { //方法4 return null; } @Override public void destroy() { //方法5 } }
方法1的说明:默认情况下,当Servlet第一次被创建时,调用此init()方法;那么Servlet什么时候被创建呢?你第一次客户端请求的时候,服务器(容器--引擎)就会读取web.xml配置文件,通过servlet和servlet-mapping的标签获取类的全路径名,然后通过反射创建Servelt对象,调用init()方法,进行初始化,此方法只调用一次。
特点:只执行一次,Servlet是单例的,但是可能会存在线程安全问题,尽量不要定义成员变量。
初始化的功能:一般做一些准备工作
问题:准备工作(写了大量的代码),比较耗时,用户体验不好!
需求:在服务器一开启,我就把初始化的工作准备好
我们可以在web.xml中配置init方法的初始化时机(那用户在再来请求的时候,就不用再等待初始化了)
说明1:-1是默认值,表示用户第一次请求的时候,才去执行init方法
说明2:非负整数,服务器一开启就执行init方法,数值越小执行的时机越早(可以在一个web.xml中配置多个servlet)
简单的配置:在web.xml的<servlet>标签中配置<load-on-startup>
用法:建立数据库的连接,获取配置信息。
方法2的说明:获取代当前Servlet在web.xml中的配置信息;
说明:当servlet配置了初始化参数之后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象(服务器创建)中,并在调用servlet的init方法时,将ServletConfig对象传递给Servlet,进而可以通过servlet对象得到当前servlet的初始化参数信息。
具体方式:在Servlet 的配置文件中,用一个或多个<init-param>标签(键值对的形式)为当前Servlet配置一些初始化参数。
注意:一个servlet被实例化后,任何客户端在任何时候访问有效(但仅对本servlet有效),一个servlet的ServletConfig对象不能被另一个servlet访问。
用法:将数据库信息、编码方式等配置信息放在web.xml中,如果以后数据库的用户名、密码改变了,则直接很方便地修改web.xml就行了,避免了直接修改源代码的麻烦。
配置对象:ServletConfig
特点:是一个接口,在Servlet初始化的时候,由服务器创建其子类对象,将配置信息封装到对象中传递给init()方法
常用的方法:
(1) String getInitParameter(String name) --键找值
(2) Enumeration getInitParameterNames() --获取当前Servlet所有初始化参数的名字组成的枚举
(3)String getServletName() -- 获取当前Servlet在web.xml中配置的名字(别名)
(4)ServletContext getServletContext() -- 获取代表当前Web应用的ServletContext(上下文--全局域)对象(重点!!!)
前提:全局域对象有内容--键值对的形式
具体使用: 要想使用该方法获取ServletConfig对象,则需要提升config对象的作用域。
(1)声明 私有的成员变量ServletConfig(2)在init方法中赋值
(3)在getServletConfig方法中 获取;
关于初始化时机和配置信息在web.xml中如下:
<?xml version="1.0" encoding="UTF-8"?> <!--.rsd作为xml的约束文档--> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--一个web.xml可以配置多个servlet--> <servlet> <!--servlet的别名(随便起)--> <servlet-name>haha</servlet-name> <!--servlet的全路径名称(包含包名)--> <servlet-class>org.wzj.servlet.MyServlet</servlet-class> <!--初始化参数的配置信息(在加载时机之前)(可以配置多个参数)--> <init-param> <param-name>username</param-name> <param-value>Jane</param-value> </init-param> <!--初始化的加载时机(服务器开启之后,客户端请求之前完成)--> <load-on-startup>-1</load-on-startup> </servlet> <servlet-mapping> <!--当前servlet的映射信息--> <servlet-name>haha</servlet-name> <url-pattern>/MyServlet</url-pattern> </servlet-mapping> </web-app>
Java代码(原始的创建Servlet的方式--继承Servlet接口的形式)
package org.wzj.servlet; import javax.servlet.*; import java.io.IOException; public class MyServlet implements Servlet { //提升作用域(成员变量)并提供一个公共的接口供外界访问--屏蔽具体的细节 private ServletConfig servletConfig; @Override public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig=servletConfig; System.out.println("servlet对象创建成功,并成功进行init()初始化!"); } /** * 说明:提供公共的方法供外界访问 * @return */ @Override public ServletConfig getServletConfig() { return servletConfig; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException,IOException{ System.out.println("servlet开始建功立业!"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { System.out.println("Servlet即将谢幕!"); } }
方法3的说明:获取请求,然后处理客户端的请求并给予反馈
特点:客户端每请求一次,服务器就会单独开辟一个线程,执行一次
方法4的说明:返回一个String类型的字符串(纯文本),包含Servlet的一些基本信息(作者、版本、版权等)--了解即可
方法5的说明:将servlet对象从服务中移除(服务器正常关闭也会调用)
时机:容器检测到一个servlet对象从服务器要从服务中移除时,会调用该方法,该对象一段时间内会被Java的垃圾回收器所回收。
作用:释放该servlet占用的资源,保存数据到持球存储设备中(硬盘、U盘等)
常见:内存中的数据保存到数据库中,关闭数据库的连接等,主要是一些善后工作。
三、Servlet的生命周期
Servlet的生命周期方法:创建(init)---提供服务(service)---销毁(destroy)
回顾:多线程的生命周期
四、Servlet的原理
五、Servlet创建方式
(1) 实现Servlet
不好:有些方法没有用,方法赘余!
(2)继承GenericServlet(了解即可)
1、采用适配器模式(GenericServlet除了service没有实现之外,其余的四个方法都实现了!是一个抽象类)
2、对ServletConfig进行优化,提升config对象的作用域(私有的成员变量)
3、实现了ServletConfig接口,简化对config对象的使用方式(因此也是ServletConfig的对象,不需要层层调用了!)
缺点:由于service有7种提交方式,目前浏览器仅实现两种(Get和Post的提交方式),其他方法(预留)也无用
(3)继承HttpServlet(最终版--对http协议的封装)
特点1:继承体系--继承自GenericServlet
特点2:重写doGet()和doPost()的方法
注意:去掉super.doGet()super.doPost()--完全重写,不需要父类的功能。
说明:常在Get或Post中调用另外一个的该方法(后续报道!!!)
-------------------------------
六、ServletContext接口
说明:表示一个Web应用程序的上下文(全局域对象),在它所代表的范围内可以共享数据
特点:是单例的,Web容器在启动时会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
说明:一个Web应用中的所有Servlet共享同一个ServletContext对象(不管这些Servlet是否为同一个客户进行服务),因此Servlet对象之间可以通过ServletContext对象来实现通信。ServletContext对象通常也被称之为context域对象,该对象中维护了ServletContext对象的引用。
(1)获取ServletContext对象方式
方式1:this.getServletConfig().getServletContext()
原因:Servlet容器在Servlet初始化期间,向其传递ServletConfig对象,而ServletConfig对象中维护了ServletContext对象的引
用,可以通过getServletContext()的方式获取该对象
方式2:this.getServletContext()
原因:GenericServlet抽象类继承了ServletConfig,this也相当于ServletConfig的对象,所以可以直接调用。
说明:方式1和方式2获取的对象是一致的,都是通过ServletConfig对象中的getServletContext()方法获取的。
ServletContext常用的方法:
ServletContext的作用1:在域的范围内共享数据
1)setAttribute("键--字符串",值);
功能:设置共享数据(一定要有意义!)
结果:共享数据存储在全局域中,当前Web的其它servlet也可以访问。
2)getAttribute("键"):
功能:获取共享属性
3)getAttributeNames();
注意:返回的是枚举(Enumeration)类型
4) removeAttribute("键")
说明:删除对应的共享属性(配置文件中的无法删除)
5)getInitParameter("键");
6)getInitParameterNames()
说明:获取配置信息中所有的键(枚举的形式)
说明:为Servlet上下文定义初始化参数.可以被整个Web应用程序所使用。在web.xml中的<context-param>定义上下文初始化
参数,上面的两个方法用于访问这些参数。
测试:在web中写一个login,html的表单提交,提交到Servlet01,在Servlet01中设置上下文共享数据,在Servlet02中看是否获取
配置信息(在web-app第一个子节点)
<!--(1)给上下文对象配置参数--> <context-param> <param-name>id</param-name> <param-value>001</param-value> </context-param>
Servlet01
package org.wzj.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class Servlet01 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //(1)获取上下文对象(简易方式) ServletContext context = this.getServletContext(); //(2)存储数据 context.setAttribute("name","Servlet"); //(3)获取web.xml中配置的上下文初始化参数 String id = context.getInitParameter("id"); System.out.println(id); //(4)移除此id对应的配置参数,在另外一个Servlet中是否能获取到 //说明:移除共享属性(只能移除在其它servlet中设置的共享数据,不能移除web,xml中的) } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request,response); } }
Servlet02
package org.wzj.servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.Enumeration; public class Servlet02 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //需求:获取上下文共享的数据 //(1)获取上下文的对象 ServletContext context = this.getServletContext(); //(2)获取全部的上下文配置信息(共享数据)--键的集合 Enumeration<String> initParameterNames = context.getInitParameterNames(); //(3)注意枚举的遍历方式 if(initParameterNames!=null){ while(initParameterNames.hasMoreElements()){ String parm = initParameterNames.nextElement(); String id = context.getInitParameter(parm); System.out.println(id); } } //(4)获取其它Servlet传递过来的数据(共享数据) String username = (String) context.getAttribute("name"); System.out.println(username); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-----------------------------------
思考:在普通项目下通过src获取项目下的文件(前提是在src下)或者当前项目下,那么在Web项目呢?
作用2:获取文件运行的真实路径(服务器路径)
测试(三种情况):
* 1.web下:项目根目录下
* 2.WEB-INF下:项目根目录下/WEB-INF
* 3.src下: 项目根目录下/WEB-INF/classes%1、getRealPath()
说明:返回的是资源在服务器文件系统(硬盘)的真实路径(文件的绝对路径)
服务器路径:看项目发布后资源文件在硬盘的的位置(可以明白),而不是在IDEA中文件位置!!!
相关代码
import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; //说明:通过注解形式,name可以不写,但value(映射信息必须有!) public class Servlet01 extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //需求1:获取src下的b.txt //错误的方式(竟然成功了!!!--值得深思) File file = new File("src/b.txt"); System.out.println(file); //标准方式 ServletContext context = this.getServletContext(); //获取文件的真实(服务器的)路径 String realPath = context.getRealPath("/WEB-INF/classes/b.txt"); //原因:项目发布后,服务器路径中的src的文件是在\ServletWeb02\WEB-INF\classes中 //说明:"/"就表示当前的上下文路径--ServletWeb02 System.out.println(realPath); //需求2:获取a.txt(/ServletWeb02) String realPath1 = context.getRealPath("/a.txt"); System.out.println(realPath1); //需求3:获取c.txt(web/WEB-INF/)--不存在web的事情!!! context.getRealPath("/WEB-INF/c.txt"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
说明:ServletContext只能用于web环境获取路径
%2、getResource()
思考:如果是非web环境,则使用什么来获取真实路径?
答:ClassLoader类加载器
需求:我Web项目里有一个普通的java工具类,我想通过Java类获取文件的真实路径 那我就用不了ServletContext
import java.net.URL; public class JavaUtils { private static JavaUtils javaUtils; public static void main(String[] args) { //说明:Web项目中,普通Java类访问文件的情况 //方式1: //1.获取该类对应的类加载器对象 ClassLoader loader = javaUtils.getClass().getClassLoader(); //2.获取文件运行的真实路径 //说明:Resource表示src URL url = loader.getResource("b.txt"); System.out.println(url); //------------------------- //方式2:返回的是输出流对象--------'/'表示src目录 JavaUtils.class.getResourceAsStream("/b.txt"); } }
注意:类加载器来获取路径也有局限性,只能获取src目录下的文件。
思考3:如果在Servlet中要使用工具类获取文件的路径呢?
答:与ServletContext有关的,你懂的!!!
------------------------------
Servlet的工作原理
--------------------
打war包--项目上线,要部署项目(回顾项目的三种发布方式!!!)
方式1:手动打war包
找到文件的webapp中的路径(服务器路径),压缩成zip格式后,修改后缀名,放到服务器路径即可,此时会自动解压,切删除war包对应的解压文件也会删除!!!
方式2:IDEA自动打war包
(1)知道war包的路径--并勾选主build ...
(2)build --