Servlet 是运行在 Java 服务器端的程序,用于接收和响应来自客户端基于 HTTP 协议的请求html
若是想实现 Servlet 的功能,能够经过实现 javax.servlet.Servlet 接口或者继承它的实现类java
核心方法:service(),任何客户端的请求都会通过该方法git
Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一github
咱们能够像学习Java基础同样,经过API来学习Servletweb
这里须要注意的是,在咱们以前JDK的API中是没有Servlet规范的相关内容,须要使用JavaEE的API小程序
目前在Oracle官网中的最新版本是浏览器
固然,咱们能够经过访问tomcat
打开官方API网址,在左上部分找到javax.servlet包,在左下部分找到Servlet,以下图显示:安全
经过阅读API,咱们获得以下信息:服务器
第一:Servlet是一个运行在web服务端的java小程序
第二:它能够用于接收和响应客户端的请求
第三:要想实现Servlet功能,能够实现Servlet接口,继承GenericServlet或者HttpServlet
第四:每次请求都会执行service方法
第五:Servlet还支持配置
具体请看下图:
建立一个 WEB 项目
servlet_demo1
建立一个类继承 GenericServlet
包:com.itheima.servlet
类:ServletDemo1
GenericServlet介绍:implements Servlet,实现了Servlet里的大部分方法,只有一个service方式是抽象的,咱们只须要实现这个方法便可
重写 service 方法
package com.itheima.servlet;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/*
Servlet快速入门1
*/
public class ServletDemo01 extends GenericServlet{
service有两个参数,servletRequest,servletResponse ,这俩分别是处理请求和响应的,后续会详细介绍
在 web.xml 中配置 Servlet
<!--配置快速入门1Servlet-->
<servlet>
<servlet-name>servletDemo01</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo01</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo01</servlet-name>
<url-pattern>/servletDemo01</url-pattern>
</servlet-mapping>
部署并启动项目:配置项目虚拟路径:/demo1
经过浏览器测试
分析图:(下图与实际案例有出入,可是咱们只须要搞清楚Servlet访问流程便可)
咱们经过浏览器发送请求,请求首先到达Tomcat服务器
由服务器解析请求URL,而后在部署的应用列表中找到咱们的应用
接下来,在咱们的应用中找应用里的web.xml配置文件
在web.xml中找到Servlet的配置
找到后执行service方法,最后由ServletDemo1响应客户浏览器
整个过程以下图所示:
一句话总结执行过程:
浏览器——>Tomcat服务器——>咱们的应用——>应用中的web.xml——>Servlet——>响应浏览器
关系视图以下:
Servlet,GenericServlet,HTTPServlet,他们都有service方法
service方法都有俩参数,ServletRequest,ServletResponse
HTTPServlet的参数是HttpServletRequest,HttpServletResponse,他们分别继承自ServletRequest,ServletResponse
这俩参数都是接口,分别处理请求,响应
ServletConfig,处理配置
ServletContext,处理多个Servlet之间信息共享
第一种 实现 Servlet 接口,实现全部的抽象方法。该方式支持最大程度的自定义。
第二种 继承 GenericServlet 抽象类,必须重写 service 方法,其余方法可选择重写。该方式让咱们开发 Servlet 变得简单。可是这种方式和 HTTP 协议无关。
第三种 继承 HttpServlet 抽象类,须要重写 doGet 和 doPost 方法。该方式表示请求和响应都须要和 HTTP 协议相关。
上述前两种都给你们演示过了,咱们接下来来试一下第三种
步骤
建立一个类继承 HttpServlet
//servlet_demo1新建:ServletDemo02.java
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
Servlet快速入门2
*/
public class ServletDemo02 extends HttpServlet {
}
重写 doGet 和 doPost 方法
public class ServletDemo02 extends HttpServlet {
在 web.xml 中配置 Servlet
<!--配置快速入门2Servlet-->
<servlet>
<servlet-name>servletDemo02</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo02</servlet-name>
<url-pattern>/servletDemo02</url-pattern>
</servlet-mapping>
部署并启动项目
经过浏览器测试
对象的生命周期,就是对象从出生到死亡的过程。即:出生 -> 活着 -> 死亡。官方说法是对象建立到销毁的过程
出生:请求第一次到达 Servlet 时,对象就建立出来,而且初始化成功。只出生(建立)一次,将对象放到内存中
活着:服务器提供服务的整个过程当中,该对象一直存在,每次都是执行 service 方法
死亡:当服务中止时,或者服务器宕机时,对象死亡
结论:Servlet 对象只会建立一次,销毁一次。因此 Servlet 对象只有一个实例。若是一个对象实例在应用中是惟一的存在,那么咱们就称它为单例模式
代码
建立ServletDemo03
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
Servlet生命周期
*/
public class ServletDemo03 extends HttpServlet {
配置Servlet
<!--演示Servlet生命周期的配置-->
<servlet>
<servlet-name>servletDemo03</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo03</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo03</servlet-name>
<url-pattern>/servletDemo03</url-pattern>
</servlet-mapping>
部署并启动
说明:init只会执行一次
中止服务
中止tomcat,执行destory
因为 Servlet 采用的是单例模式,也就是整个应用中只有一个实例对象。因此咱们须要分析这个惟一的实例对象中的类成员是否线程安全
模拟用户登陆功能来查看 Servlet 线程是否安全
结论:一个浏览器表明一个线程,多个浏览器表明多个线程。按理说咱们指望的应该是每一个浏览器查看的都应该是本身的用户名。而如今的结果是浏览器中数据混乱。所以,咱们能够认为 Servlet 是线程不安全的!
解决:定义类成员要谨慎。若是是共用的,而且只会在初始化时赋值,其余时间都是获取的话,那么是没问题的。若是不是共用的,或者每次使用都有可能对其赋值,那就要考虑线程安全问题了,能够将其定义到 doGet 或 doPost 方法内或者使用同步功能便可。
案例演示
新建ServletDemo4
package com.itheima.servlet;
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.io.PrintWriter;
/*
Servlet线程安全
*/
public class ServletDemo04 extends HttpServlet{
//1.定义用户名成员变量
private String username = null;
Servlet配置
<!--演示Servlet线程安全的配置-->
<servlet>
<servlet-name>servletDemo04</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo04</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo04</servlet-name>
<url-pattern>/servletDemo04</url-pattern>
</servlet-mapping>
演示
由于须要演示线程安全,因此须要两个浏览器模拟两个线程,因此要开两个浏览器
谷歌浏览器中url传递参数username=aaa
火狐浏览器中url传递参数username=bbb
而后谷歌浏览器先访问,紧接着火狐浏览器访问
结果现象是,俩浏览器都是welcome:bbb
分析
解决1:将username由成员变量,放到方法中
package com.itheima.servlet;
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.io.PrintWriter;
/*
Servlet线程安全
*/
public class ServletDemo04 extends HttpServlet{
//1.定义用户名成员变量
//private String username = null;
使用同步代码块
package com.itheima.servlet;
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.io.PrintWriter;
/*
Servlet线程安全
*/
public class ServletDemo04 extends HttpServlet{
//1.定义用户名成员变量
//private String username = null;
第一种 具体名称的方式。访问的资源路径必须和映射配置彻底相同
第二种 / 开头 + 通配符的方式。只要符合目录结构便可,不用考虑结尾是什么
第三种 通配符 + 固定格式结尾的方式。只要符合固定结尾格式便可,不用考虑前面的路径
注意:优先级问题。越是具体的优先级越高,越是模糊通用的优先级越低。第一种 -> 第二种 -> 第三种
此种方式,只有和映射配置如出一辙时,Servlet才会接收和响应来自客户端的请求。
例如:映射为:/servletDemo5
新建ServletDemo5
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
Servlet不一样映射方式
*/
public class ServletDemo05 extends HttpServlet {
配置Servlet
<!--演示Servlet不一样映射方式-->
<!--具体名称的方式-->
<servlet>
<servlet-name>servletDemo05</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo05</servlet-name>
<url-pattern>/servletDemo05</url-pattern>
</servlet-mapping>
访问:
此种方式,只要符合目录结构便可,不用考虑结尾是什么。
例如:映射为:/servlet/*
这两个URL均可以。由于用的*,表示/servlet/后面的内容是什么均可以。
咱们仍是使用ServletDemo5,只须要修改配置便可(把上一个具体名称的配置屏蔽掉)
<!--/开头+通配符的方式-->
<servlet>
<servlet-name>servletDemo05</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo05</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
访问
此种方式,只要符合固定结尾格式便可,其前面的访问URI无须关心(注意协议,主机和端口必须正确)
例如:映射为:*.do
这两个URL均可以方法。由于都是以.do做为结尾,而前面用*号通配符配置的映射,全部无须关心。
依然使用ServletDemo5,修改配置便可
<!--通配符+固定格式结尾的方式-->
<servlet>2
<servlet-name>servletDemo05</servlet-name>
<servlet-class>com.itheima.servlet.ServletDemo05</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servletDemo05</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
访问
咱们能够给一个 Servlet 配置多个访问映射,从而根据不一样的请求路径来实现不一样的功能
场景分析:
若是访问的资源路径是 /vip 商品价格打9折
若是访问的资源路径是 /vvip 商品价格打5折
若是访问的资源路径是其余 商品价格不打折
案例:新建ServletDemo6
package com.itheima.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
Servlet 多路径映射
*/
public class ServletDemo06 extends HttpServlet {
配置Servlet
<!--演示Servlet多路径映射--> <servlet> <servlet-name>servletDemo06</servlet-name> <servlet-class>com.itheima.servlet.ServletDemo06</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletDemo06</servlet-name> <url-pattern>/itheima/*</url-pattern> </servlet-mapping>
访问
第一次访问时建立
优点:减小对服务器内存的浪费。提升了服务器启动的效率
弊端:若是有一些要在应用加载时就作的初始化操做,没法完成
服务器加载时建立
优点:提早建立好对象,提升了首次执行的效率。能够完成一些应用加载时要作的初始化操做
弊端:对服务器内存占用较多,影响了服务器启动的效率
修改 Servlet 建立时机。在<servlet>
标签中,添加<load-on-startup>
标签。
正整数表明服务器加载时建立,值越小、优先级越高。 负整数或不写表明第一次访问时建立
<load-on-startup>加载顺序的序号</load-on-startup>
序号为1,就是服务器启动时第一个加载
序号为2,就是服务器启动时第二个加载
若是两个Servlet都要配置为正整数,那么值小的优先级高
配置:修改ServletDemo3的配置,增长load-on-startup
<!--演示Servlet生命周期的配置--> <servlet> <servlet-name>servletDemo03</servlet-name> <servlet-class>com.itheima.servlet.ServletDemo03</servlet-class> <!--配置Servlet启动时机 正整数表明服务器启动时建立,负数或不写表明第一次访问时建立--> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>servletDemo03</servlet-name> <url-pattern>/servletDemo03</url-pattern> </servlet-mapping>
效果:若是不配置,是在访问ServletDemo3 的时候初始化,若是配置,那就是在启动tomcat的时候初始化
下图是配置后,启动tomcat打印的
默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中。以下图所示:
它的映射路径是<url-pattern>/<url-pattern>
,咱们在发送请求时,首先会在咱们项目中的 web.xml 中查找映射配置,找到则执行
可是当找不到对应的 Servlet 路径时,就去找默认的 Servlet,由默认 Servlet 处理。因此,一切都是 Servlet。
访问一个不存在的url
这个404界面,其实就是tomcat配置的默认的Servlet处理的结果
ServletConfig 是 Servlet 的配置参数对象,在 Servlet 的规范中,容许为每个 Servlet 都提供一些初始化的配置。因此,每一个 Servlet 都有一个本身的 ServletConfig
做用:在 Servlet 的初始化时,把一些配置信息传递给 Servlet
生命周期:和 Servlet 相同
因为它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,因此生命周期与Servlet相同
这里须要注意的是,若是Servlet配置了<load-on-startup>1</load-on-startup>
,那么ServletConfig也会在应用加载时建立
ServletConfig的配置信息都是键值对的形式
在<servlet>
标签中,经过<init-param>
标签来配置。有两个子标签。
<param-name>
:表明初始化参数的 key。
<param-value>
:表明初始化参数的 value。
一个init-param配置一个信息,一个信息由name和value组成
案例
新建项目:servlet_demo2
src中新建包:com.itheima.servlet
新建类:ServletConfigDemo
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /* ServletConfig的使用 */ public class ServletConfigDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
配置Servlet
<!--配置Servlet--> <servlet> <servlet-name>servletConfigDemo</servlet-name> <servlet-class>com.itheima.servlet.ServletConfigDemo</servlet-class> <!--配置ServletConfig初始化参数--> <init-param> <!--用于获取初始化参数的key--> <param-name>encoding</param-name> <!--初始化参数的值--> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>desc</param-name> <param-value>This is ServletConfig</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>servletConfigDemo</servlet-name> <url-pattern>/servletConfigDemo</url-pattern> </servlet-mapping>
经常使用方法:
掌握getInitParameter()方法
代码:接着在ServletConfigDemo中写代码:
public class ServletConfigDemo extends HttpServlet { //声明ServletConfig配置对象 private ServletConfig config; /* 经过init方法来为ServletConfig配置对象赋值 */ @Override public void init(ServletConfig config) throws ServletException { this.config = config; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //根据key获取value String encodingValue = config.getInitParameter("encoding"); System.out.println(encodingValue); //获取Servlet的名称 String servletName = config.getServletName(); System.out.println(servletName); //获取全部的key Enumeration<String> names = config.getInitParameterNames(); //遍历获得的key while(names.hasMoreElements()) { //获取每个key String name = names.nextElement(); //经过key获取value String value = config.getInitParameter(name); System.out.println("name:" + name + ",value:" + value); } //获取ServletContext对象 ServletContext context = config.getServletContext(); System.out.println(context); //获取ServletContextDemo设置共享的数据 , 这个是在写下个案例的时候添加的 //Object username = context.getAttribute("username"); //System.out.println(username); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
部署项目,配置虚拟目录为demo2,启动tomcat
效果
ServletContext 是应用上下文对象。每个应用中只有一个 ServletContext 对象。
做用:能够得到应用的全局初始化参数和达到 Servlet 之间的数据共享。
上下文理解:环境,不一样环境给咱们带来的信息是不同的。因此环境中有不少信息,数据,也就是环境是用于存储数据的。
生命周期:应用一加载则建立,应用被中止则销毁。
出生——活着——死亡
出生: 应用一加载,该对象就被建立出来了。一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)
活着:只要应用一直提供服务,该对象就一直存在。
死亡:应用被卸载(或者服务器挂了),该对象消亡。
ServletContext图示:
域对象指的是对象有做用域。也就是有做用范围
域对象能够实现数据的共享
不一样做用范围的域对象,共享数据的能力也不同
在 Servlet 规范中,一共有 4 个域对象
ServletContext 就是其中的一个
它也是 web 应用中最大的做用域,也叫 application 域
在整个项目范围均可以使用 应用域共享的数据
它能够实现整个应用以内的数据共享
ServletContext是一个接口,程序运行起来以后打印ServletContext的实例对象,实际上是一个ApplicationContextFacade对象
ApplicationContextFacade是ServletContext的实现类
ServletContext 并不属于某个 Servlet 的配置,而是针对于整个应用的配置,也叫全局的初始化参数
在<web-app>
标签中,经过<context-param>
标签来配置。有两个子标签
<param-name>
:表明全局初始化参数的 key
<param-value>
:表明全局初始化参数的 value
案例:新建ServletContextDemo
package com.itheima.servlet; 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 ServletContextDemo extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
配置Servlet,而且配置ServletContext
<web-app> .... <!--配置Servlet--> <servlet> <servlet-name>servletContextDemo</servlet-name> <servlet-class>com.itheima.servlet.ServletContextDemo</servlet-class> </servlet> <servlet-mapping> <servlet-name>servletContextDemo</servlet-name> <url-pattern>/servletContextDemo</url-pattern> </servlet-mapping> <!--配置ServletContext--> <context-param> <param-name>globalEncoding</param-name> <param-value>UTF-8</param-value> </context-param> <context-param> <param-name>globalDesc</param-name> <param-value>This is ServletContext</param-value> </context-param> </web-app>
注意ServletContext的配置是在wep-app节点下,与servlet配置同级别
经常使用方法
掌握:getContextPath和getRealPath
准备工做:新建三个空的txt文件,以下
代码:继续在ServletContextDemo中写:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取ServletContext对象 ServletContext context = getServletContext(); //获取全局配置的globalEncoding String value = context.getInitParameter("globalDesc"); System.out.println(value); //获取应用的访问虚拟目录 String contextPath = context.getContextPath(); System.out.println(contextPath); //根据虚拟目录获取应用部署的磁盘绝对路径 String realPath = context.getRealPath("/"); System.out.println(realPath); //获取b.txt文件的绝对路径 String b = context.getRealPath("/b.txt"); System.out.println(b); //获取c.txt文件的绝对路径 String c = context.getRealPath("/WEB-INF/c.txt"); System.out.println(c); //获取a.txt文件的绝对路径 String a = context.getRealPath("/WEB-INF/classes/a.txt"); System.out.println(a); }
效果
context.getRealPath("/");获取到的就是当前项目发布的路径
经常使用方法2
代码:
//修改ServletContextDemo:存储数据 //向域对象中存储数据 context.setAttribute("username","zhangsan"); //修改ServletConfigDemo:获取数据 //获取ServletContextDemo设置共享的数据 Object username = context.getAttribute("username"); System.out.println(username);
效果
先访问contextdemo存储数据
再访问configdemo获取数据
咱们使用的是 Tomcat 9 版本。JavaEE 规范要求是 8 。对应的 Servlet 版本应该是 4.x 版本。可是,在企业开发中,稳定要远比追求新版本要重要。因此咱们会降版本使用,用的是 Servlet 3.1 版本
其实咱们以前的操做全都是基于 Servlet 2.5 版本规范的,也就是借助于配置文件的方式。后来随着软件开发逐步的演变,基于注解的配置开始流行。而 Servlet 3.0 版本也就开始支持注解开发了
Servlet 3.0 版本既保留了 2.5 版本的配置方式,同时又支持了全新的注解配置方式。它能够彻底不须要 web.xml 配置文件,就能实现 Servlet 的配置,同时还有一些其余的新特性,咱们在后面的课程中会慢慢学习到
总结:
以前基于配置文件方式,这个是Servlet2.5版本的规范
可是每添加一个Servlet,就须要本身配置一个,感受有点繁琐
Servlet3.0就出现了注解方式,能够省去配置
新建项目:servlet_demo3
配置Java EE8
剩余两步省略
新建以后,项目目录以下
web下没有WEB-INF了,web.xml也没有了
虽然web.xml不用了,可是WEB-INF还须要,因此WEB-INF须要本身建立出来
index.jsp没用,删除便可
新建类:com.itheima.servlet.ServletDemo1
package com.itheima.servlet; 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.IOException; /* 自动注解配置Servlet @WebServlet("Servlet路径") */ @WebServlet("/servletDemo1") public class ServletDemo1 extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet执行了..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
能够正常访问
注解详解
Servlet 3.0 规范除了使用自动注解的配置方式外,还支持手动建立 Servlet 容器的方式
若是使用必须遵循其编写规范。在 3.0 版本加入了一个新的接口:
定义一个类ServletDemo2,继承 HttpServlet
重写 doGet 和 doPost 方法
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /* 手动建立容器配置Servlet */ public class ServletDemo2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("servlet执行了..."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
定义一个类,实现 ServletContainerInitializer 接口
package com.itheima.servlet; import javax.servlet.ServletContainerInitializer; import javax.servlet.ServletContext; import javax.servlet.ServletRegistration; import java.util.Set; /* 注册配置Servlet的功能类 */ public class MyRegister implements ServletContainerInitializer { @Override public void onStartup(Set<Class<?>> set, ServletContext servletContext) { //完成Servlet的建立和配置 } }
在 src 目录下建立一个 META-INF 的包
在 META-INF 包下建立一个 services 的包
在 services 包下建立一个 javax.servlet.ServletContainerInitializer 的文件
文件中的内容为容器实现类的全类名
com.itheima.servlet.MyRegister
在容器实现类中的 onStartup 方法中完成注册 Servlet
public void onStartup(Set<Class<?>> set, ServletContext servletContext) { //完成Servlet的建立和配置 //1.建立Servlet对象 ServletDemo2 servletDemo2 = new ServletDemo2(); //2.在ServletContext中添加Servlet,并获得Servlet的配置对象 ServletRegistration.Dynamic registration = servletContext.addServlet("servletDemo2", servletDemo2); //3.配置Servlet registration.setLoadOnStartup(0); //Servlet加载时机 registration.addMapping("/servletDemo2"); //映射访问资源路径 }
部署并启动项目
经过浏览器测试
效果
访问案例首页,看到一个能够保存学生信息的界面
输入内容,点击保存,经过java服务器,而后最终保存到txt中
最后java服务器返回成功结果
建立一个 web 项目:servlet_test,配置虚拟目录/stu
选择javaee 7,这里咱们仍是用web.xml
建立一个用于保存学生信息的 html 文件:web下新建addStudent.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加学生</title> </head> <body> -- ?username=张三&age=18&score=718 <form action="/stu/studentServlet" method="get" autocomplete="off"> 学生姓名:<input type="text" name="username"> <br/> 学生年龄:<input type="number" name="age"> <br/> 学生成绩:<input type="number" name="score"> <br/> <button type="submit">保存</button> </form> </body> </html>
建立一个类com.itheima.servlet.StudentServlet,继承 HttpServlet
重写 doGet 和 doPost 方法
package com.itheima.servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; public class StudentServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
在 web.xml 文件中修改默认主页和配置 Servlet
<!--修改默认主页--> <welcome-file-list> <welcome-file>/addStudent.html</welcome-file> </welcome-file-list> <!--配置Servlet--> <servlet> <servlet-name>studentServlet</servlet-name> <servlet-class>com.itheima.servlet.StudentServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>studentServlet</servlet-name> <url-pattern>/studentServlet</url-pattern> </servlet-mapping>
在 doGet 方法中接收表单数据保存到文件中,并响应给浏览器结果
// -- ?username=张三&age=18&score=718 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取表单中的数据 String username = req.getParameter("username"); // 获取url后边的?的参数 String age = req.getParameter("age"); String score = req.getParameter("score"); //将数据保存到stu.txt文件中 BufferedWriter bw = new BufferedWriter(new FileWriter("d:\\stu.txt",true)); bw.write(username + "," + age + "," + score); bw.newLine(); bw.close(); //给浏览器回应 PrintWriter pw = resp.getWriter(); pw.println("Save Success~"); pw.close(); }
部署并启动项目
经过浏览器测试