Servlet
1. Servlet 配置方式
1.1 web.xml XML文件方式
web.xml
整个项目的配置文件,可以配置项目启动参数,Servlet 配置参数,过滤器 Filter ,监听器 Listener
<!-- servlet 标签,对应 Servlet 程序 里面包含有两个内容 servlet-name, servlet-class -->
<servlet>
<!-- servlet-name 【定义】当前 Servlet 程序在整个 Web Application web.xml 文件中的唯一名称 -->
<servlet-name>WebXmlConfigServlet</servlet-name>
<!--
servlet-class 对应当前 Servlet 程序对应的完整的包名.类名,可以提供给Tomcat服务器明确操作 Servlet 程
序对应类是哪一个 这里存在反射操作。
-->
<servlet-class>com.qfedu.a_conf.WebXmlConfigServlet</servlet-class>
</servlet>
<!-- servlet-mapping servlet 映射。Servlet程序 Tomcat 服务器资源匹配规则设置 包含 servlet-name url-pattern -->
<servlet-mapping>
<!-- 明确当前匹配规则对应的 Servlet 程序是哪一个 要求匹配的 servlet-name 在 web.xml 文件中存在 -->
<servlet-name>WebXmlConfigServlet</servlet-name>
<!--
当前资源匹配规则/资源匹配名称 资源名称在整个 Web Application 唯一
存在规范 【精确匹配,模糊匹配】
浏览器 URL
http://localhost:8080/Day38/webXmlConfig 当前资源对应的URL
-->
<url-pattern>/webXmlConfig</url-pattern>
</servlet-mapping>
package com.qfedu.a_conf;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* web.xml 配置 Servlet 程序
*
* @author Anonymous 2022/4/14 9:25
*/
public class WebXmlConfigServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().append("<h1>Web.xml Config Servlet</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.2 @WebServlet 注解方式
package com.qfedu.a_conf;
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 资源
*
* @author Anonymous 2022/4/14 10:44
*/
/*
@WebServlet() 配置 Servlet 程序的注解
/annotationConfig 当前 Servlet 程序资源名称
*/
@WebServlet("/annotationConfig")
public class AnnotationConfigServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().append("<h1>Annotation Config Servlet</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
1.3 xml文件方式和注解方式对比
web.xml
1. 适用于任意 Servlet 版本
2. 配置较为繁琐,阅读性一般
3. 【优势】可以避免资源冲突,xml 中有资源冲突直接报错
@WebServlet 注解方式
1. 适用于 3.0 以上版本 Servlet
2. 配置方便,操作简单
3. 【劣势】如果出现资源冲突问题,Tomcat 启动阶段提示
1.4 注解资源冲突导致Tomcat启动失败【仅讲一次,后期出现自行解决】
注解导致 Tomcat 启动失败
Caused by: java.lang.IllegalArgumentException:
因为:
java.lang.IllegalArgumentException 非法参数异常
The servlets named [com.qfedu.a_conf.AnnotationConfigServlet] and
Servlet 程序名称 com.qfedu.a_conf.AnnotationConfigServlet 和
[com.qfedu.a_conf.TestServlet] are both mapped to the url-pattern
Servlet 程序名称 com.qfedu.a_conf.TestServlet 同时映射资源匹配规则
[/annotationConfig] which is not permitted
/annotationConfig 这样操作是不被允许的
2. Servlet 到底是怎么运行的
2.1 Tomcat 容器概念
![](img/01-Tomcat%E5%AE%B9%E5%99%A8%E6%A6%82%E5%BF%B5%E5%9B%BE%E4%BE%8B.png)
2.2 web.xml 流程分析
![](img/02-xml%E6%96%87%E4%BB%B6tomcat%E8%A7%A3%E6%9E%90%E8%B5%84%E6%BA%90%E6%B5%81%E7%A8%8B.png)
2.3 注解方式分析
![](img/03-%E6%B3%A8%E8%A7%A3%E6%96%B9%E5%BC%8FTomcat%E8%A7%A3%E6%9E%90%E8%B5%84%E6%BA%90%E6%B5%81%E7%A8%8B.png)
3. Servlet 配置参数
3.1 涉及到 Servlet 相关方法
1. 通过 Request 请求对象 或者 this 获取 servletConfig 对象
ServletConfig getServletConfig();
2. 可以通过该 ServletConfig 获取 配置参数
String getParameter(String name);
3.2 web.xml 配置参数
<!--
Servlet 配置选项
Servlet 标签配置 1, 2
3 ==> 完成一个规范的完整的 servlet-mapping 标签
1. 开机自启 Tomcat 服务器启动,对应 Servlet 程序启动,Tomcat 服务器已经实例化对应 Servlet 程序。
一定会执行对应 Servlet 程序的构造方法。
load-on-startup 设置属性为 1 Tomcat会在启动过程中直接加载准备 Servlet 程序
2. Servlet 配置参数 init-param 包含标签 param-name 和 param-value 键值对形式数据
参数内容可以多个,可以并行多个 init-param
3. 可以给予一个 Servlet 多个匹配规则
/webXmlConfigOption
/webXmlco
使用 Servlet-mapping 配置同一个 servlet-name 映射关系
不同的是 url-pattern
-->
<servlet>
<servlet-name>WebXmlConfigOptionServlet</servlet-name>
<servlet-class>com.qfedu.b_configOption.WebXmlConfigOptionServlet</servlet-class>
<!-- servlet 初始化参数 -->
<init-param>
<!-- param-name 初始化参数名称 -->
<param-name>logFilePath</param-name>
<!-- param-value 初始化参数对应数据 -->
<param-value>./log/application.log</param-value>
</init-param>
<!-- servlet 初始化参数 -->
<init-param>
<!-- param-name 初始化参数名称 -->
<param-name>imgPath</param-name>
<!-- param-value 初始化参数对应数据 -->
<param-value>./img/</param-value>
</init-param>
<!-- 开机自启 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!--
下方两个 servlet-mapping servlet-name 一致 url-pattern 不一致
用户申请资源可以使用任意一个!!!
-->
<servlet-mapping>
<servlet-name>WebXmlConfigOptionServlet</servlet-name>
<url-pattern>/webXmlConfigOption</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>WebXmlConfigOptionServlet</servlet-name>
<url-pattern>/webXmlco</url-pattern>
</servlet-mapping>
package com.qfedu.b_configOption;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author Anonymous 2022/4/14 14:06
*/
public class WebXmlConfigOptionServlet extends HttpServlet {
/**
* WebXmlConfigOptionServlet 无参数构造方法,提示打印,用于展示
* Servlet 程序在 Tomcat 启动阶段,启动完毕,开机自启
*/
public WebXmlConfigOptionServlet() {
System.out.println("WebXmlConfigOptionServlet Constructor called.....");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ServletConfig Servlet 配置对象
ServletConfig servletConfig = this.getServletConfig();
System.out.println(servletConfig);
System.out.println("logFilePath : " + servletConfig.getInitParameter("logFilePath"));
System. out.println("imgPath : " + servletConfig.getInitParameter("imgPath"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
3.3 注解方式配置参数
package com.qfedu.b_configOption;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* WebServlet 注解方式配置 Servlet 参数
* value 和 urlPatterns
* 配置参数类型都是 String[] 字符串数组,用于配置当前 servlet 的资源名称
* 两者不可以同时存在,如果当前 @WebServlet("一个数据") 默认对应 value
* loadOnStartup
* 开机自启 给予参数 1 ,表示当前 Servlet 程序在 Tomcat 启动过程中会自动加载
* initParams
* 配置当前 Servlet 程序的 初始化参数 @WebInitParam(name =?, value=?)
* 对应的是一个 web参数初始化类型数组 @WebInitParam[]
*
* @author Anonymous 2022/4/14 14:42
*/
@WebServlet(
value = {"/annotationConfigOption", "/annotationCO"},
loadOnStartup = 1,
initParams = {
@WebInitParam(name = "logFilePath", value = "./log/application.log"),
@WebInitParam(name = "imgPath", value = "./img/"),
}
)
public class AnnotationConfigOptionServlet extends HttpServlet {
public AnnotationConfigOptionServlet() {
System.out.println("AnnotationConfigOptionServlet Constructor Called");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletConfig servletConfig = this.getServletConfig();
System.out.println("logFilePath : " + servletConfig.getInitParameter("logFilePath"));
System.out.println("imgPath : " + servletConfig.getInitParameter("imgPath"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
4. Servlet 资源匹配规则
4.1 精准匹配
package com.qfedu.c_urlpattern;
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 精准明确的 urlPattern 匹配规则
* 给予在当前 Web Application 中明确唯一的资源名称
*
* @author Anonymous 2022/4/14 15:44
*/
@WebServlet(urlPatterns = {"/url1", "/urlPattern", "/up1"})
public class UrlPatternOneServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().append("<h1>" + req.getRequestURI() + "</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
4.2 拓展名匹配
package com.qfedu.c_urlpattern;
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;
import java.lang.reflect.InvocationTargetException;
/**
* 后缀名/拓展名匹配
* * 是匹配规则通配符不限制一定的匹配资源名称
* 使用后缀名/拓展名匹配 匹配规则不是 / 开头,而且 * 开头
*
* value = {"*.action", "*.do"}
* 资源名称要求.action 或者 .do 结尾,其他不限制
* http://localhost:8080/Day38/student.action
* http://localhost:8080/Day38/student.do
*
* http://localhost:8080/Day38/addStudent.do
* http://localhost:8080/Day38/updateStudent.do
* http://localhost:8080/Day38/removeStudent.do
* http://localhost:8080/Day38/findStudent.do
* http://localhost:8080/Day38/addStudent.action
* http://localhost:8080/Day38/updateStudent.action
* http://localhost:8080/Day38/removeStudent.action
* http://localhost:8080/Day38/findStudent.action
*
* @author Anonymous 2022/4/14 15:44
*/
@WebServlet(value = {"*.action", "*.do"})
public class UrlPatternTwoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri = req.getRequestURI();
// /Day38/findStudent.action 获取用户请求资源对应的 方法名信息
String methodName = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));
System.out.println(methodName);
try {
// 当前 Servlet 对象获取 Class 对象,同时获取对应成员方法对象 invoke 执行
// this 表示当前执行 Servlet 程序对象
this.getClass().getMethod(methodName).invoke(this);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
resp.getWriter().append("<h1>").append(uri).append("</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
public void addStudent() {
System.out.println("Add Student Method running...");
}
public void updateStudent() {
System.out.println("Update Student Method running...");
}
public void removeStudent() {
System.out.println("Remove Student Method running...");
}
public void findStudent() {
System.out.println("Find Student Method running...");
}
}
4.3 路径匹配
package com.qfedu.c_urlpattern;
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 资源匹配规则
* /user/*
* 路径匹配 + 通配符
* 要求用户在请求资源时必须 user 路径开头,后续不限
* 后期可以将与用户操作相关的资源匹配规则都是按照虚拟路径方式配置
* 例如:
* 用户相关资源 登陆,注册,修改,更新
* /user/login
* /user/register
* /user/change
* /user/update
* 可以根据 user 之后的信息来选择执行的功能内容,后期也可以限制用户满足条件
* 才可以进入就 user 虚拟路径进行操作范围【过滤器】
*
* /user/test
* 路径匹配 + 精确匹配
* @author Anonymous 2022/4/14 15:44
*/
//@WebServlet("/user/*")
@WebServlet("/user/test")
public class UrlPatternThreeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().append("<h1>").append(req.getRequestURI()).append("</h1>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
5. 小案例
5.1 用户发送参数到 Servlet 程序
![](img/04-%E8%B5%84%E6%BA%90%E6%8F%90%E4%BA%A4%E5%88%B0Servlet%E7%A4%BA%E6%84%8F%E5%9B%BE.png)
<!-- 当前 HTML 文件在 web 目录下!!! -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<form action="register" method="post">
<span>名字</span><input type="text" name="name"><br>
<span>年龄</span><input type="text" name="age"><br>
<span>性别</span><input type="radio" name="gender" value="0">男 <input type="radio" name="gender" value="1">女 <br>
<input type="submit" value="提交">
</form>
</body>
</html>
package com.qfedu.d_userData;
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;
/**
* @author Anonymous 2022/4/14 16:44
*/
@WebServlet("/register")
public class RegisterUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
发现中文不支持,修改请求数据编码集
通过 HttpServletRequest 对象调用 setCharacterEncoding 方法,统一请求编码集
改为 utf-8
*/
req.setCharacterEncoding("utf-8");
/*
用户请求数据是通过 HTTP 协议请求头提交的,HTTP请求头对应 HttpServletRequest 对象。
可以通过 Request 对象调用
String getParameter(String parameterName)
获取用户请求指定参数名称的数据
*/
String name = req.getParameter("name");
String age = req.getParameter("age");
String gender = req.getParameter("gender");
System.out.println("Name : " + name);
System.out.println("Age : " + age);
System.out.println("Gender : " + ("0".equals(gender) ? "男" : "女"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}