Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一
我们可以像学习Java基础一样,通过API来学习Servlet
这里需要注意的是,在我们之前JDK的API中是没有Servlet规范的相关内容,需要使用JavaEE的API
目前在Oracle官网中的最新版本是JavaEE8,该网址中介绍了JavaEE8的一些新特性
当然,我们可以通过访问官方API,学习和查阅里面的内容
打开官方API网址,在左上部分找到javax.servlet包,在左下部分找到Servlet
通过阅读API,我们得到如下信息:
第一:Servlet是一个运行在web服务端的java小程序
第二:它可以用于接收和响应客户端的请求
第三:要想实现Servlet功能,可以实现Servlet接口,继承GenericServlet或者HttpServlet
第四:每次请求都会执行service方法
第五:Servlet还支持配置
具体请看下图:
创建一个 WEB 项目
创建一个类继承 GenericServlet
包:com.itheima.servlet
类:ServletDemo1
GenericServlet介绍:implements Servlet,实现了Servlet里的大部分方法,只有一个service方式是抽象的,我们只需要实现这个方法即可
重写 service 方法
package 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{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service方法执行了...");
}
}
在 web.xml 中配置 Servlet
<servlet>
<servlet-name>servletDemo01servlet-name>
<servlet-class>servlet.ServletDemo01servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo01servlet-name>
<url-pattern>/servletDemo01url-pattern>
servlet-mapping>
部署并启动项目:配置项目虚拟路径:/demo1
通过浏览器测试
整个过程如下图所示:
一句话总结执行过程:
浏览器——>Tomcat服务器——>我们的应用——>应用中的web.xml——>Servlet——>响应浏览器
步骤
创建一个类继承 HttpServlet
//servlet_demo1新建:ServletDemo02.java
package 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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("方法执行了...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//post请求方式一般与get请求方式处理的逻辑一样,所以直接调用doGet
doGet(req,resp);
}
}
在 web.xml 中配置 Servlet
<servlet>
<servlet-name>servletDemo02servlet-name>
<servlet-class>servlet.ServletDemo02servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo02servlet-name>
<url-pattern>/servletDemo02url-pattern>
servlet-mapping>
部署并启动项目
通过浏览器测试
对象的生命周期,就是对象从出生到死亡的过程。即:出生 -> 活着 -> 死亡。官方说法是对象创建到销毁的过程
出生:请求第一次到达 Servlet 时,对象就创建出来,并且初始化成功。只出生(创建)一次,将对象放到内存中
活着:服务器提供服务的整个过程中,该对象一直存在,每次都是执行 service 方法
死亡:当服务停止时,或者服务器宕机时,对象死亡
结论:Servlet 对象只会创建一次,销毁一次。所以 Servlet 对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么我们就称它为单例模式
代码
创建ServletDemo03
package 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 {
@Override
public void init() throws ServletException {
System.out.println("对象创建并初始化了...");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("接收到了客户端的请求...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
@Override
public void destroy() {
System.out.println("对象销毁了...");
}
}
配置Servlet
<servlet>
<servlet-name>servletDemo03servlet-name>
<servlet-class>servlet.ServletDemo03servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo03servlet-name>
<url-pattern>/servletDemo03url-pattern>
servlet-mapping>
部署并启动
由于 Servlet 采用的是单例模式,也就是整个应用中只有一个实例对象。所以我们需要分析这个唯一的实例对象中的类成员是否线程安全
模拟用户登录功能来查看 Servlet 线程是否安全
结论:一个浏览器代表一个线程,多个浏览器代表多个线程。按理说我们期望的应该是每个浏览器查看的都应该是自己的用户名。而现在的结果是浏览器中数据混乱。因此,我们可以认为 Servlet 是线程不安全的!
解决:定义类成员要谨慎。如果是共用的,并且只会在初始化时赋值,其他时间都是获取的话,那么是没问题的。如果不是共用的,或者每次使用都有可能对其赋值,那就要考虑线程安全问题了,可以将其定义到 doGet 或 doPost 方法内或者使用同步功能即可。
案例演示
新建ServletDemo4
package 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;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//2.获取用户名
username = req.getParameter("username");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.获取输出流对象
PrintWriter pw = resp.getWriter();
//4.响应给客户端浏览器
pw.print("welcome:" + username);
//5.关流
pw.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
Servlet配置
<servlet>
<servlet-name>servletDemo04servlet-name>
<servlet-class>servlet.ServletDemo04servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo04servlet-name>
<url-pattern>/servletDemo04url-pattern>
servlet-mapping>
演示
解决1:将username由成员变量,放到方法中
package 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;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = null;//谷歌浏览器进来有一个username,火狐进来也有一个username,所以不会覆盖
//2.获取用户名
username = req.getParameter("username");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.获取输出流对象
PrintWriter pw = resp.getWriter();
//4.响应给客户端浏览器
pw.print("welcome:" + username);
//5.关流
pw.close();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
使用同步代码块
package 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;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// String username = null;
synchronized (this) {
//锁需要唯一,Servlet对象就是唯一的,所以用this
//2.获取用户名
username = req.getParameter("username");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//3.获取输出流对象
PrintWriter pw = resp.getWriter();
//4.响应给客户端浏览器
pw.print("welcome:" + username);
//5.关流
pw.close();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
注意:优先级问题。越是具体的优先级越高,越是模糊通用的优先级越低。第一种 -> 第二种 -> 第三种
此种方式,只有和映射配置一模一样时,Servlet才会接收和响应来自客户端的请求。
例如:映射为:/servletDemo5
访问URL:http://localhost:8080/demo1/servletDemo5
新建ServletDemo5
package 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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ServletDemo05执行了...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
配置Servlet
<servlet>
<servlet-name>servletDemo05servlet-name>
<servlet-class>servlet.ServletDemo05servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo05servlet-name>
<url-pattern>/servletDemo05url-pattern>
servlet-mapping>
此种方式,只要符合目录结构即可,不用考虑结尾是什么。
例如:映射为:/servlet/*
访问URL:http://localhost:8080/demo1/servlet/itheima
http://localhost:8080/demo1/servlet/itcast
这两个URL都可以。因为用的*,表示/servlet/后面的内容是什么都可以。
我们还是使用ServletDemo5,只需要修改配置即可(把上一个具体名称的配置屏蔽掉)
<servlet>
<servlet-name>servletDemo05servlet-name>
<servlet-class>servlet.ServletDemo05servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo05servlet-name>
<url-pattern>/servlet/*url-pattern>
servlet-mapping>
此种方式,只要符合固定结尾格式即可,其前面的访问URI无须关心(注意协议,主机和端口必须正确)
例如:映射为:*.do
访问URL:http://localhost:8080/demo1/aaa.do
http://localhost:8080/demo1/bbb.do
这两个URL都可以方法。因为都是以.do作为结尾,而前面用*号通配符配置的映射,所有无须关心。
依然使用ServletDemo5,修改配置即可
2
servletDemo05
servlet.ServletDemo05
servletDemo05
*.do
我们可以给一个 Servlet 配置多个访问映射,从而根据不同的请求路径来实现不同的功能
场景分析:
案例:新建ServletDemo6
package 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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 定义一个商品金额
int money = 1000;
//2. 获取访问的资源路径
String name = req.getRequestURI();
name = name.substring(name.lastIndexOf("/"));
//3. 条件判断
if("/vip".equals(name)) {
//如果访问资源路径是/vip 商品价格为9折
System.out.println("商品原价为:" + money + "。优惠后是:" + (money*0.9));
} else if("/vvip".equals(name)) {
//如果访问资源路径是/vvip 商品价格为5折
System.out.println("商品原价为:" + money + "。优惠后是:" + (money*0.5));
} else {
//如果访问资源路径是其他 商品价格原样显示
System.out.println("商品价格为:" + money);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);
}
}
配置Servlet
<servlet>
<servlet-name>servletDemo06servlet-name>
<servlet-class>servlet.ServletDemo06servlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletDemo06servlet-name>
<url-pattern>/itheima/*url-pattern>
servlet-mapping>
优势:减少对服务器内存的浪费。提高了服务器启动的效率
弊端:如果有一些要在应用加载时就做的初始化操作,无法完成
2. 服务器加载时创建
优势:提前创建好对象,提高了首次执行的效率。可以完成一些应用加载时要做的初始化操作
弊端:对服务器内存占用较多,影响了服务器启动的效率
标签中,添加
标签。正整数代表服务器加载时创建,值越小、优先级越高。 负整数或不写代表第一次访问时创建
如果两个Servlet都要配置为正整数,那么值小的优先级高
配置:修改ServletDemo3的配置,增加load-on-startup
<servlet>
<servlet-name>servletDemo03servlet-name>
<servlet-class>servlet.ServletDemo03servlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>servletDemo03servlet-name>
<url-pattern>/servletDemo03url-pattern>
servlet-mapping>
效果:如果不配置,是在访问ServletDemo3 的时候初始化,如果配置,那就是在启动tomcat的时候初始化
默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中。
它的映射路径是
,我们在发送请求时,首先会在我们项目中的 web.xml 中查找映射配置,找到则执行
但是当找不到对应的 Servlet 路径时,就去找默认的 Servlet,由默认 Servlet 处理。所以,一切都是 Servlet。
访问一个不存在的url
生命周期:和 Servlet 相同
由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同
这里需要注意的是,如果Servlet配置了
,那么ServletConfig也会在应用加载时创建
在
标签中,通过
标签来配置。有两个子标签。
:代表初始化参数的 key。
:代表初始化参数的 value。
一个init-param配置一个信息,一个信息由name和value组成
案例
新建项目:servlet_demo2
src中新建包:servlet
新建类:ServletConfigDemo
package 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-name>servletConfigDemoservlet-name>
<servlet-class>servlet.ServletConfigDemoservlet-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>descparam-name>
<param-value>This is ServletConfigparam-value>
init-param>
servlet>
<servlet-mapping>
<servlet-name>servletConfigDemoservlet-name>
<url-pattern>/servletConfigDemourl-pattern>
servlet-mapping>
代码:接着在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 之间的数据共享。
上下文理解:环境,不同环境给我们带来的信息是不一样的。所以环境中有很多信息,数据,也就是环境是用于存储数据的。
生命周期:应用一加载则创建,应用被停止则销毁。
ServletContext图示:
ServletContext 并不属于某个 Servlet 的配置,而是针对于整个应用的配置,也叫全局的初始化参数
在
标签中,通过
标签来配置。有两个子标签
:代表全局初始化参数的 key
:代表全局初始化参数的 value
案例:新建ServletContextDemo
package 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-name>servletContextDemoservlet-name>
<servlet-class>servlet.ServletContextDemoservlet-class>
servlet>
<servlet-mapping>
<servlet-name>servletContextDemoservlet-name>
<url-pattern>/servletContextDemourl-pattern>
servlet-mapping>
<context-param>
<param-name>globalEncodingparam-name>
<param-value>UTF-8param-value>
context-param>
<context-param>
<param-name>globalDescparam-name>
<param-value>This is ServletContextparam-value>
context-param>
web-app>
掌握: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);
}
效果
常用方法2
代码:
//修改ServletContextDemo:存储数据
//向域对象中存储数据
context.setAttribute("username","zhangsan");
//修改ServletConfigDemo:获取数据
//获取ServletContextDemo设置共享的数据
Object username = context.getAttribute("username");
System.out.println(username);
效果
我们使用的是 Tomcat 9 版本。JavaEE 规范要求是 8 。对应的 Servlet 版本应该是 4.x 版本。但是,在企业开发中,稳定要远比追求新版本要重要。所以我们会降版本使用,用的是 Servlet 3.1 版本
其实我们之前的操作全都是基于 Servlet 2.5 版本规范的,也就是借助于配置文件的方式。后来随着软件开发逐步的演变,基于注解的配置开始流行。而 Servlet 3.0 版本也就开始支持注解开发了
Servlet 3.0 版本既保留了 2.5 版本的配置方式,同时又支持了全新的注解配置方式。它可以完全不需要 web.xml 配置文件,就能实现 Servlet 的配置,同时还有一些其他的新特
总结:
新建项目:servlet_demo3
配置Java EE8
新建之后
新建类:servlet.ServletDemo1
package 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 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 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 的文件
文件中的内容为容器实现类的全类名
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"); //映射访问资源路径
}
部署并启动项目
通过浏览器测试
创建一个 web 项目:servlet_test,配置虚拟目录/stu
创建一个用于保存学生信息的 html 文件:web下新建addStudent.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>
创建一个类servlet.StudentServlet,继承 HttpServlet
重写 doGet 和 doPost 方法
package 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.htmlwelcome-file>
welcome-file-list>
<servlet>
<servlet-name>studentServletservlet-name>
<servlet-class>servlet.StudentServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>studentServletservlet-name>
<url-pattern>/studentServleturl-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();
}
部署并启动项目
通过浏览器测试