文章目录
一、需求
校验注册时,用户名是否被占用。通过客户端向一个Servlet发送请求,携带username,如果用户名是 'atguigu'
,则向客户端响应 NO,如果是其他,响应YES
二、创建Web项目
三、引入servlet-api依赖
一共有三种方法
1)引入到父项目中
在父项目的根目录新建lib文件夹,然后将servlet-api引入。
这种情况是在很多个Module共享的,默认情况下和module是没有关系的。
第一步:右击,将它添加为库
然后从子项目中引用它
加进来后,表示这个module依赖这个Library,但是这个Module里有一个artifact部署包,它是已经生成了。
-
方法一:将artifact删掉,重新建一个
-
方法二:点击Problems,将lib加入进入
2)引入到模块中(推荐)
在当前项目的 web\WEB-INF
下新建lib文件夹,导入 servlet-api
缺点:只能是当前 module
独享。如果有第二个 module
,我们需要再次重复的新建 lib
。
优点:启动项目的时候会自动将lib加进去
3)将Tomcat依赖加入进来
找到库(Library),将tomcat依赖导入进来
查看外部库,可以看见tomcat库已包含了servlet-api
三种导入方式对比
如果使用第二种方式进行导入,那么就就需要手动进行构建
并且需要将IDEA构建好的App手动发布到Tomcat中
此时就会出现部署包和Tomcat的lib下有相同一份jar包。
Tomcat的lib目录不仅仅用于Tomcat本身,还用于所有部署进Tomcat所共享的jar包。
回忆一下:
lib:Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的jar包了,所以建议只把Tomcat需要的jar包放到这个目录下;
解释:Tomcat本身也是用java和c写的程序,它本身也是一个项目,所以它本身也依赖一些jar包类;而且Tomcat编译和构建后,就会产生很多很多的jar文件,因此这里面就可以理解为它是Tomcat程序本身的一些jar包。
但是我们并不会将部署的项目所依赖的jar包放到这个lib里,因为这个lib中是公用的,但是并不是所有的项目都需要这个lib中的所有的jar包。
不仅会出现jar包重复,而且还有可能会发生依赖冲突。
但如果只在当前项目导入Tomcat的依赖,旁边的Provided表示依赖的作用域。
main目录(空间) | test目录(空间) | 开发过程(时间) | 部署到服务器(时间) | |
---|---|---|---|---|
provided | 有效 | 有效 | 有效 | 无效 |
provided:在开发过程中需要用到的 "服务器上的jar包"
通常以 provided
范围依赖进来。比如 servlet-api、jsp-api
。而这个范围的 jar 包之所以不参与部署、不放进 war 包,就是避免和服务器上已有的同类 jar 包产生冲突,同时减轻服务器的负担。说白了就是:服务器上已经有了,你就别带啦!
因此我们通过这种方式导入进来的依赖,我们只是在编码的时候有这个依赖,真正进行项目构建和打包的时候,它是不携带Tomcat所导进来的jar包的。
但如果后续我们需要导MySQL的jar包、druid的jar包,那还是需要往 WEB-INF/lib
中放的,因为服务器不提供。
四、开发一个UserServlet
- 自定义一个类,本来是需要实现Servlet接口,但是Servlet接口中方法中太多了,但我们只需要重写service方法,因此我们可以继承HttpServlet类:HttpServlet继承了GenericServlet抽象类,而GenericServlet抽象类实现了Servlet接口,因此HttpServlet也就间接的实现了Servlet接口
- 重写service方法,该方法主要就是用于处理用户请求的服务方法
- HttpServletRequest 代表请求对象,是由请求报文经过tomcat转换而来的,通过该对象可以获取请求中的信息
- HttpServletResponse 代表响应对象,该对象会被tomcat转换为响应的报文,通过该对象可以设置响应中的信息
- Servlet对象的生命周期(创建,初始化,处理服务,销毁)是由tomcat管理的,无需我们自己new
- HttpServletRequest、HttpServletResponse 两个对象也是由tomcat负责转换,再调用service方法时传入给我们用的
src/com/atguigu/servlet/UserServlet.java
/*
* servlet 开发流程
* 1 创建 javaWEB 项目,同时将 tomcat 添加为当前项目的依赖
* 2 重写 service 方法 service(HttpServletRequest req, HttpServletResponse resp)
* 3 在 service 方法中,定义业务处理代码
*
*/
public class UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1 从request对象中获取请求中的任何信息(username参数)
// form表单请求过来的有可能是get请求方式(?后key=value),也有可能是post请求方式(请求体里key=value),但不管是哪种请求方式,都是key=value
String username = request.getParameter("username"); // 根据参数名获取参数值,无论参数是在url后,还是在请求体中,只要是键值对形式的,都可以获取到
// 2 处理业务的代码
String info = "YES";
if (!"atguigu".equals(username)) {
info = "NO";
}
// 3 将更响应的数据放入response
// 该方法返回的是一个向响应体中打印字符串的打印流,你通过这个流进行数据输出的时候,数据会放到response存储响应体的那个区间
PrintWriter writer = response.getWriter();
writer.write(info);
}
}
五、在 web.xml
为 UseServlet
配置请求的映射路径
1)代码示例
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<servlet>
<!--给UserServlet起一个别名-->
<servlet-name>userServlet</servlet-name>
<servlet-class>com.atguigu.servlet.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<!--关联别名和映射路径-->
<servlet-name>userServlet</servlet-name>
<!--可以为一个Servlet匹配多个不同的映射路径,但是不同的Servlet不能使用相同的url-pattern-->
<url-pattern>/userServlet</url-pattern>
<!-- <url-pattern>/userServlet2</url-pattern>-->
<!--
/ 表示通配所有资源,不包括jsp文件
/* 表示通配所有资源,包括jsp文件
/a/* 匹配所有以a前缀的映射路径
*.action 匹配所有以action为后缀的映射路径
-->
<!-- <url-pattern>/*</url-pattern>-->
</servlet-mapping>
</web-app>
2)使用问题
Servlet
并不是文件系统中实际存在的文件或者目录,所以为了能够请求到该资源,我们需要为其配置映射路径servlet
的请求映射路径配置在web.xml
中servlet-name
作为servlet的别名,可以自己随意定义,见名知意就好url-pattern
标签用于定义Servlet的请求映射路径- 一个servlet可以对应多个不同的
url-pattern
- 多个servlet不能使用相同的
url-pattern
一个 <servlet-name>
允许对应多个 <servlet-pattern>
,无论请求的是哪个 <url-pattern>
,都会对应到 Demo02Servlet
上
<servlet-mapping>
<servlet-name>Demo02Servlet</servlet-name>
<url-pattern>/demo02</url-pattern>
<url-pattern>/demo03</url-pattern>
</servlet-mapping>
但是一个 <url-pattern>
不能对应多个 <servlet-name>
一个servlet
允许对应多个servlet-mapping
,无论发给哪个 <url-pattern>
(但是url-pattern互相需要不同),都是对应一个servlet。这样可以在servlet当中获取我们到底是通过哪个URL请求过来的。根据不同URL发送的请求,可以执行不同的业务逻辑。
<servlet>
<servlet-name>Demo02Servlet</servlet-name>
<servlet-class>com.atguigu.servlets.Demo02Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Demo02Servlet</servlet-name>
<url-pattern>/demo02</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Demo02Servlet</servlet-name>
<url-pattern>/demo021</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Demo02Servlet</servlet-name>
<url-pattern>/demo022</url-pattern>
</servlet-mapping>
但是一个servlet-mapping
不能对应多个servlet
。
既然两种方式都可以,那不如使用第一种方式,这样就不需要写很多个 <servlet-mapping>
了。
3)特殊写法
上面我们写的都是 url-pattern
的精确匹配, url-pattern
中可以使用一些通配写法进行模糊匹配
表达式 | 描述 |
---|---|
/ | 通配所有资源, 不包括jsp文件 |
/* | 通配所有资源, 包括jsp文件(就算这个jsp文件已经有了,也会被这个Servlet所匹配到,从而不走jsp文件) |
/a/* | 匹配所有以a前缀的映射路径,多级路径也是可以匹配的 |
*.action | 匹配所有以 .action 为后缀的映射路径1.不要写成 /*.action ,因为 /* 已经是全部资源了,.action 已经没有意义了,并且写成 /*.action 会报错2.前面有多个路径也是可以匹配到的 /a/b/c/xxx.action |
六、开发一个form表单,向servlet发送一个get请求并携带username参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- http://127.0.0.1:8080/demo02/userServlet -->
<!-- 请求体
username=zhangsan
-->
<form method="get" action="userServlet">
用户名:<input type="text" name="username"><br>
<input type="submit" value="校验">
</form>
</body>
</html>
七、启动项目,访问index.html,提交表单测试
将部署的项目改为 web02
使用debug模式运行测试,如果就写到 http://127.0.0.1:8080/web02
,它默认就是去找index.html | index.htm | index.jsp
在表单中填入 atguigu
,点击测试,此时断点就会生效
八、流程 & 映射关系图
- 用户发请求:
action="userServlet"
- 服务器(tomcat,项目)中,web.xml中找到
servlet-mapping
中的url-pattern = /userServlet
- 找
servlet-name = userServlet
- 找和
servlet-mapping
中servlet-name
一致的servlet
- 找到
servlet
中的servlet-class
就能通过<servlet>
找到com.atguigu.servlet.userServlet
类 - tomcat会将字节码文件加载进内存,并且通过反射创建其对象
- 然后 tomcat 执行userServlet实例中的service方法