目录
405-Method Not Allowed:表示请求方法不被允许
500-Internal Server Error:表示服务器内部发生错误
1.Servlet是什么
Servlet 是一种实现动态页面的技术、是用 Java 编写的服务器端程序、是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 webapp.
它主要用于处理客户端(通常是浏览器)发送的请求,并生成动态的响应内容返回给客户端。Servlet 运行在 Servlet 容器(如Tomcat等)中,容器负责管理 Servlet 的生命周期,包括创建、初始化、执行服务方法以及销毁等。
通过 Servlet,能够实现与数据库交互、处理业务逻辑、动态生成网页内容等功能,是构建 Web 应用程序的重要组件之一。它具有良好的可扩展性和可维护性,在 Java Web 开发中得到广泛应用
1.1Servlet 主要做的工作
允许程序猿注册一个类, 在 Tomcat 收到某个特定的 HTTP 请求的时候, 执行这个类中的一些代码.
帮助程序猿解析 HTTP 请求, 把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象.
帮助程序猿构造 HTTP 响应. 程序猿只要给指定的 HttpResponse 对象填写一些属性字段, Servlet
就会自动的按照 HTTP 协议的方式构造出一个 HTTP 响应字符串, 并通过 Socket 写回给客户端.
2.第一个Servlet程序
1. 创建项目
使用 IDEA 创建一个 Maven 项目.
1. 菜单 -> 文件 -> 新建项目 -> Maven
项目创建完毕后, 一般右下角会弹出以下对话框. 选择 Enable Auto-Import
2.引入依赖
Maven 项目创建完毕后, 会自动生成一个 pom.xml 文件.
我们需要在 pom.xml 中引入 Servlet API 依赖的 jar 包.
在中央仓库https://mvnrepository.com/ 中搜索 "servlet"
选择版本. 一般我们使用 3.1.0 版本
Servlet 的版本要和 Tomcat 匹配.
可以在 Apache Tomcat® - Which Version Do I Want? 查询版本对应关系.
把中央仓库中提供的 xml 复制到项目的 pom.xml 中
修改后的 pom.xml 形如:
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>messageWall</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
</dependencies>
</project>
<dependencies> 标签内部放置项目依赖的 jar 包. maven 会自动下载依赖到本地.
3.创建目录
1. 创建 webapp 目录
在 main 目录下, 和 java 目录并列, 创建一个 webapp 目录 (注意, 不是 webapps).
2.创建 web.xml
然后在 webapp 目录内部创建一个 WEB-INF 目录, 并创建一个 web.xml 文件
3. 编写 web.xml
往 web.xml 中拷贝以下代码. 具体细节内容我们暂时不关注.
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
</web-app>
webapp 目录就是未来部署到 Tomcat 中的一个重要的目录. 当前我们可以往 webapp 中放一些静态资源, 比如 html , css 等.在这个目录中还有一个重要的文件 web.xml、 Tomcat 找到这个文件才能正确处理 webapp 中的动态资源.
4.编写代码
在 java 目录中创建一个类 HelloServlet, 代码如下:
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp);
System.out.println("hello servlet");
resp.getWriter().write("hello servlet");
}
}
· 创建一个类HelloServlet , 继承自HttpServlet
· 在这个类上方加上@WebServlet("/hello")注解, 表示 Tomcat 收到的请求中, 路径为/hello的请求才会调用 HelloServlet 这个类的代码. (这个路径未包含 Context Path)HttpServletRequest
· 重写doGet 方法. doGet 的参数有两个, 分别表示收到的 HTTP请求和要构造的 HTTP 响应. 这个方法会在 Tomcat 收到 GET 请求时触发
HttpServletRequest表示 HTTP 请求. Tomcat 按照 HTTP 请求的格式把字符串格式的请求转成了一个 HttpServletRequest对象. 后续想获取请求中的信息(方法, url, header, body 等) 都是通过这个对象来获取
HttpServletResponse表示 HTTP 响应. 把响应对象构造好(构造响应的状态码, header, body 等)
resp.getWriter()会获取到一个流对象, 通过这个流对象就可以写入一些数据, 写入的数据会被构造成一个 HTTP 响应的 body 部分, Tomcat 会把整个响应转成字符串, 通过 socket 写回给浏览器.
---------------------------------------------------------------------------------------------------------------------------------
1. 我们的代码不是通过 main 方法作为入口了. main 方法已经被包含在 Tomcat 里, 我们写的代码会被 Tomcat 在合适的时机调用起来.
此时我们写的代码并不是一个完整的程序, 而是 Tomcat 这个程序的一小部分逻辑.
2. 我们随便写个类都能被 Tomcat 调用嘛? 满足啥样条件才能被调用呢?
主要满足三个条件:
a) 创建的类需要继承自 HttpServlet
b) 这个类需要使用 @WebServlet 注解关联上一个 HTTP 的路径
c) 这个类需要实现 doXXX 方法.
当这三个条件都满足之后, Tomcat 就可以找到这个类, 并且在合适的时机进行调用.
5.部署Smart Tomcat插件
安装插件
1. 菜单 -> 文件 -> Settings
2. 选择 Plugins, 选择 Marketplace, 搜索 "tomcat", 点击 "Install".
配置 Smart Tomcat 插件
1. 点击左上角的 "Add Configuration"
2. 选择左侧的 "Smart Tomcat"
3. 在Name这一栏填写一个名字(可以随便写)
在Tomcat Server 这一栏选择 Tomcat 所在的目录. 其他的选项不必做出修改.
其中 Context Path 默认填写的值是项目名称、这会影响到后面咱们的访问页面.
4.点击 OK 之后, 左上角上角变成了
点击绿色的三角号, IDEA 就会自动进行编译, 部署, 启动 Tomcat 的过程.
6.访问页面
在浏览器中使用 http://127.0.0.1:8080/hello_servlet/hello 访问页面.
注意路径对应关系!
hello_servlet来自配置Smart Tomcat中的context path,后面hello来自@WebServlet("/hello")注解
3.常见的HTTP请求错误码
404-NotFound:表示服务器无法找到请求的资源
错误实例1: 少写了 Context Path↓
错误实例2: 少写了 Servlet Path↓
错误实例3: Servlet Path 写的和 URL 不匹配
修改 @WebServlet 注解的路径
错误实例4:web.xml 写错了
清除 web.xml 中的内容、重启 Tomcat 服务器、通过浏览器访问 URL, 可以看到:
在 Tomcat 启动的时候也有相关的错误提示
405-Method Not Allowed:表示请求方法不被允许
405 表示对应的 HTTP 请求方法没有实现.
错误实例: 没有实现 doGet 方法.
讲doGet方法注释掉后重启Tomcat服务器、在浏览器中访问可以看到:
在浏览器地址栏直接输入 URL ,会发送一个 HTTP GET 请求
此时就会根据 /ServletHelloWorld/hello 这个路径找到 HelloServlet 这个类. 并且尝试调用 HelloServlet 的 doGet 方法.但是如果没有实现 doGet 方法, 就会出现上述现象.
500-Internal Server Error:表示服务器内部发生错误
往往是 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 {
// super.doGet(req, resp);
System.out.println("hello servlet");
// resp.getWriter().write("hello servlet");
}
}
重启服务器,访问服务器, 可以看到一个空白页面:
抓包可以看到, 响应 body 中的内容就是 "空数据"
出现 "无法访问此网站"
一般是 Tomcat 启动就失败了.
错误实例: Servlet Path 写错了.
应该写作 "/hello", Tomcat 在启动的时候已经提示了相关的错误.
Tomcat 启动的日志里面报错信息可能比较多, 需要耐心观察, 找到关键的提示.
看到的现象:
小结
初学 Servlet,遇到的这类问题很多. 我们要学习 Servlet 代码的基本写法, 也要学习排查错误的思路.
熟悉 HTTP 协议能够让我们调试问题事半功倍.
4xx 的状态码表示路径不存在, 往往需要检查 URL 是否正确, 和代码中设定的 Context Path 以及 Servlet Path 是否一致.
5xx 的状态码表示服务器出现错误, 往往需要观察页面提示的内容和 Tomcat 自身的日志, 观察是否 存在报错.
空白页面这种情况则需要我们使用抓包工具分析 HTTP 请求响应的具体交互过程
观察日志是调试程序的重要途径. Tomcat 的日志往往很多, 需要同学们耐心阅读, 经常阅读, 熟练了就能更快速的找到问题了.