运行一个servlet项目
1. 创建项目
使用 IDEA 创建一个 Maven 项目.
- 菜单 -> 文件 -> 新建项目 ->
Maven
创建好后的项目:
2. 引入依赖
Maven
项目创建完毕后, 会自动生成一个 pom.xml
文件.
我们需要在 pom.xml
中引入 Servlet API
依赖的 jar
包.
- 在中央仓库 https://mvnrepository.com/ 中搜索 “
servlet
”, 一般第一个结果就是.
- 选择版本(点击版本号). 我的
tomcat
版本是8.5.49,对应使用的servlet
版本为 3.1.0 版本。可以在 http://tomcat.apache.org/whichversion.html 查询版本对应关系. - 把中央仓库中提供的
xml
复制到项目的pom.xml
中
修改后的pom.xml
:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>servlet-test</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>servlet-test Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>servlet-test</finalName>
</build>
</project>
这个时候点击右上角的,如果没有:
3. 创建目录
当项目创建好了之后, IDEA 会帮我们自动创建出一些目录. 形如
-
src
表示源代码所在的目录 -
main/resources
表示项目的一些资源文件所在的目录. 此处暂时不关注. -
main/webapp
webapp
目录就是未来部署到Tomcat
中的一个重要的目录.
当前我们可以往 webapp
中放一些静态资源, 比如 html
, css
等. 在这个目录中还有一个重要的文件 web.xml
. Tomcat
找到这个文件才能正确处理 webapp
中的动态资源.
1) 创建 java 目录
在 main
目录下, 和resources
目录并列, 创建一个 java 目录 .
结果如下:
4. 编写代码
在 java 目录中创建一个类 HelloServlet
, 代码如下:
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;
//注解的方式注册请求路由
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取前端参数
String name = req.getParameter("name");
// 编码设置方式1
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html; charset=utf-8");
// 将结果返回给前端
resp.getWriter().println("Jackson,");
// System.out.println("hello");
resp.getWriter().write("hello");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//将请求转发到 doget 方法中
this.doGet(req,resp);
}
}
- 在
src/main
下创建Java包,然后在Java包下创建一个类。 - 在这个类上方加上
@WebServlet("/hello")
注解, 表示Tomcat
收到的请求中,路径为/hello
的请求才会调用HelloServlet
这个类的代码.(这个路径未包含Context Path
) - 重写
doGet
方法.doGet
的参数有两个, 分别表示收到的HTTP 请求
和要构造的HTTP 响应
.这个方法会在Tomcat
收到GET
请求时触发 -
HttpServletRequest
表示HTTP 请求
.Tomcat
按照HTTP
请求的格式把 字符串 格式的请求转成了一个HttpServletRequest
对象. 后续想获取请求中的信息(方法, url, header, body 等) 都是通过这个对象来获取. -
HttpServletResponse
表示HTTP 响应
. 代码中把响应对象构造好(构造响应的状态码, header, body 等) -
resp.getWriter()
会获取到一个流对象, 通过这个流对象就可以写入一些数据, 写入的数据会被构造成一个HTTP
响应的body
部分, Tomcat 会把整个响应转成字符串, 通过 socket 写回给浏览器.
注意:
-
- 我们的代码不是通过
main
方法作为入口了.main
方法已经被包含在Tomcat
里, 我们写的代码会被Tomcat
在合适的时机调用起来. 此时我们写的代码并不是一个完整的程序, 而是Tomcat
这个程序的一小部分逻辑.
- 我们的代码不是通过
-
- 我们随便写个类都能被
Tomcat
调用嘛? 满足啥样条件才能被调用呢? 主要满足三个条件:
- 我们随便写个类都能被
a) 创建的类需要继承自 HttpServlet
b) 这个类需要使用 @WebServlet
注解关联上一个 HTTP
的路径
c) 这个类需要实现 doXXX
方法.
当这三个条件都满足之后, Tomcat
就可以找到这个类, 并且在合适的时机进行调用.
5. 打包程序
使用 maven
进行打包. 打开 maven 窗口 (一般在 IDEA 右侧就可以看到 Maven 窗口, 如果看不到的话, 可以通过 菜单 -> View -> Tool Window -> Maven 打开)
然后展开 Lifecycle
, 双击 package
即可进行打包.
如果比较顺利的话, 能够看到 SUCCESS 这样的字样:
如果代码/配置/环境存在问题, 可能会提示 BUILD FAILED
, 可以根据具体提示的错误信息具体解决.
6. 部署程序
把 war 包拷贝到 Tomcat
的 webapps
目录下.
(1)从项目的target
目录下找到.war
包,将这个包复制到Tomcat
的 webapps
目录下.
7. 验证程序
(1)启动Tomcat
(点击tomcat
的bin
目录下的startup.bat
)Tomcat
就会自动把 war
包解压缩.
看到这个日志说明 Tomcat 已经正确识别了这个 webapp.
(2)此时通过浏览器访问 http://localhost:8080/servlet-test/hello,就可以看到结果了.
更方便的部署方式
手动拷贝 war 包到 Tomcat 的过程比较麻烦. 我们还有更方便的办法.
此处我们使用 IDEA 中的 Smart Tomcat 插件完成这个工作.
如果你的idea是社区版(专业版不用安装,idea已经内置了):
安装 Smart Tomcat 插件
- 菜单 -> 文件 ->
Settings
- 选择
Plugins
, 选择Marketplace
, 搜索 “tomcat
”, 点击 “Install
”. (注意: 安装过程必须要联网. )
配置 Smart Tomcat 插件
- 点击右上角的 “
Add Configuration
”
- 选择左侧的 “
Smart Tomcat
”
- 在
Name
这一栏填写一个名字(可以随便写)
在Tomcat Server
这一栏选择Tomcat
所在的目录. 其他的选项不必做出修改.
- 点击
OK
之后, 右上角变成了
点击绿色的三角号,IDEA
就会自动进行编译, 部署, 启动Tomcat
的过程.
此时Tomcat
日志就会输出在IDEA
的控制台中, 可以看到现在就不再乱码了.
- 访问页面.
在浏览器中使用http://localhost:8080/servlet-test/hello访问页面.
访问出错怎么办?
出现 404
404 表示用户访问的资源不存在. 大概率是 URL
的路径写的不正确.
错误实例1: 少写了 Context Path
通过 /hello 访问服务器
错误实例2: 少写了 Servlet Path
通过/ServletHelloWorld
访问服务器
错误实例3: Servlet Path
写的和 URL
不匹配
修改 @WebServlet
注解的路径
重启 Tomcat
服务器.URL
中的路径写作 “/hello
” , 而代码中写作的 Servlet Path
为 “/helloServlet
”, 两者不匹配.
错误实例4: web.xml
写错了
清除 web.xml
中的内容,重启 Tomcat
服务器.
通过浏览器访问 URL
, 可以看到:
出现 405
405 表示对应的 HTTP
请求方法没有实现.
**错误实例:**没有实现 doGet
方法.
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
}
重启 Tomcat
服务器.
在浏览器中访问, 可以看到:
在浏览器地址栏直接输入 URL
, 会发送一个 HTTP GET
请求.
此时就会根据 /ServletHelloWorld/hello
这个路径找到 HelloServlet
这个类. 并且尝试调用HelloServlet
的 doGet
方法.
但是如果没有实现 doGet
方法, 就会出现上述现象.
出现 500
往往是 Servlet
代码中抛出异常导致的.
错误实例:
修改代码
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String s = null;
resp.getWriter().write(s.length());
}
}
重启 Tomcat
服务器.
重新访问页面, 可以看到:
在页面上已经有具体的异常调用栈.
异常信息里已经提示了出现异常的代码是 HelloServlet.java 的第 13 行.
resp.getWriter().write(s.length());
仔细检查这里的代码就可以看到空指针异常.
出现 “空白页面”
错误实例:
修改代码, 去掉 resp.getWritter().write()
操作.
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("hello");
}
}
重启服务器,
访问服务器, 可以看到一个空白页面:
出现 “无法访问此网站”
一般是 Tomcat
启动就失败了.
错误实例: Servlet Path
写错了.
应该写作 “/hello
”, Tomcat
在启动的时候已经提示了相关的错误.
Tomcat 启动的日志里面报错信息可能比较多, 需要耐心观察, 找到关键的提示.
看到的现象:
小结:
-
4xx
的状态码表示路径不存在, 往往需要检查URL
是否正确, 和代码中设定的Context Path
以及Servlet Path
是否一致. -
5xx
的状态码表示服务器出现错误, 往往需要观察页面提示的内容和Tomcat
自身的日志, 观察是否存在报错. - 出现连接失败往往意味着
Tomcat
没有正确启动, 也需要观察Tomcat
的自身日志是否有错误提示. - 空白页面这种情况则需要我们使用抓包工具来分析
HTTP
请求响应的具体交互过程.
在 Servlet 的代码中我们并没有写 main 方法, 那么对应的 doGet 代码是如何被调用的呢? 响应又是如何返回给浏览器的?文章来源:https://www.toymoban.com/news/detail-514162.html
Tomcat 的定位
我们自己的实现是在 Tomcat 基础上运行的。
当浏览器给服务器发送请求的时候, Tomcat 作为 HTTP 服务器, 就可以接收到这个请求.
HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作. 如下图所示:
更详细的交互过程可以参考下图:
文章来源地址https://www.toymoban.com/news/detail-514162.html
- 接收请求:
用户在浏览器输入一个 URL
, 此时浏览器就会构造一个 HTTP 请求
.
这个 HTTP 请求会经过网络协议栈逐层进行封装
成二进制的bit 流
, 最终通过物理层的硬件设备转换成光信号/电信号
传输出去.
这些承载信息的光信号/电信号通过互联网上的一系列网络设备, 最终到达目标主机(这个过程也需要网络层和数据链路层参与).
服务器主机收到这些光信号/电信号, 又会通过网络协议栈逐层进行分用
, 层层解析, 最终还原成 HTTP 请求
. 并交给 Tomcat 进程进行处理(根据端口号确定进程)Tomcat
通过Socket
读取到这个请求(一个字符串), 并按照 HTTP 请求的格式来解析这个请求
, 根据请求中的Context Path
确定一个webapp
, 再通过Servlet Path
确定一个具体的类
. 再根据当前请求的方法 (GET/POST/…), 决定调用
这个类的doGet
或者doPost
等方法. 此时我们的代码中的 doGet / doPost 方法的第一个参数 HttpServletRequest 就包含了这个 HTTP 请求的详细信息. - 根据请求计算响应:
在我们的 doGet / doPost 方法中, 就执行到了我们自己的代码. 我们自己的代码会根据请求中的一些信息, 来给HttpServletResponse 对象设置一些属性
. 例如状态码, header, body 等. - 返回响应:
我们的 doGet / doPost 执行完毕后,Tomcat
就会自动把HttpServletResponse
这个我们刚设置好的对象转换成一个符合 HTTP 协议的字符串
, 通过Socket
把这个响应发送出去.
此时响应数据在服务器的主机上通过网络协议栈层层 封装, 最终又得到一个二进制的 bit 流, 通过物理层硬件设备转换成光信号/电信号传输出去.
这些承载信息的光信号/电信号通过互联网上的一系列网络设备, 最终到达浏览器所在的主机(这个过程也需要网络层和数据链路层参与).
浏览器主机收到这些光信号/电信号, 又会通过网络协议栈逐层进行 分用, 层层解析, 最终还原成 HTTP 响应, 并交给浏览器处理.
浏览器也通过 Socket 读到这个响应(一个字符串), 按照 HTTP 响应的格式来解析这个响应. 并且把 body 中的数据按照一定的格式显示在浏览器的界面上.
到了这里,关于Servlet 运行和运行原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!