Servlet 是一种实现动态页面的技术. 是一组 API, 帮助程序猿简单高效的开发一个 web app.
静态页面: 内容始终固定的页面. 即使 用户不同/时间不同/输入的参数不同 , 页面内容也不会发生变化.
动态页面: 用户不同/时间不同/输入的参数不同, 页面内容会发生变化.
构建动态页面的技术有很多, 每种语言都有一些相关的库/框架来做这件事.
Servlet 就是 Java 的一组 API, 来完成构建动态页面这个任务.
Tomcat是一个Servlet容器,提供了一个运行 Servlet 和 JavaServer Pages(JSP)的环境。程序员可以使用 Tomcat 来部署和运行 Servlet。
简而言之, Servlet 是一组 Tomcat 提供的 API, 让程序猿自己写的代码能很好的和 Tomcat 配合起来, 从而更简单的实现一个 web app.
而不必关注 Socket, HTTP协议格式, 多线程并发等技术细节, 降低了 web app 的开发门槛, 提高了开发效率.
使用 IDEA 创建一个 Maven 项目.
Maven 项目创建完毕后, 会自动生成一个 pom.xml 文件.
我们需要在 pom.xml 中引入 Servlet API 依赖的 jar 包.
Servlet 的版本要和 Tomcat 匹配.
如果我们使用 Tomcat 8.5, 那么就需要使用 Servlet 3.1.0
可以在 http://tomcat.apache.org/whichversion.html 查询版本对应关系.
修改后的 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>ServletHelloWorld</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>
标签内部放置项目依赖的 jar 包. maven 会自动下载依赖到本地.
注意, 如果首次使用, 代码可能标红, 标红表示还没有下载完, 可以 刷新一下试试.
关于 groupId, artifactId, version
groupId: 表示组织名称
artifactId: 表示项目名称
version: 表示版本号
中央仓库就是按照这三个字段来确定唯一一个包的.
红色方框圈出来的部分, 就是这个 jar 包的 groupId, artifactId, version
当项目创建好了之后, IDEA 会帮我们自动创建出一些目录. 形如
这些目录中:
这些目录还不够, 我们还需要创建一些新的目录/文件.
创建 webapp 目录
在 main 目录下, 和 java 目录并列, 创建一个 webapp 目录 (注意, 不是 webapps).
创建 web.xml
在 webapp 目录内部创建一个 WEB-INF 目录, 并创建一个 web.xml 文件
编写 web.xml
往 web.xml 中拷贝以下代码. 通过 web.xml Tomcat 才知道要加载哪些文件并运行起来.
<!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 中的动态资源.
在 java 目录中创建一个类 HelloServlet, 代码如下:
@WebServlet("/hello") // 注意必须以 / 开头, 不能只写一个 hello
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("hello"); // 只是让服务器在自己的控制台打印
resp.getWriter().write("hello"); // 真正干活写数据的方法
}
}
创建一个类 HelloServlet , 继承自 HttpServlet
在这个类上方加上 @WebServlet(“/hello”) 注解, 表示 Tomcat 收到的请求中, 路径为 /hello的请求才会调用 HelloServlet 这个类的代码. (这个路径只是Servlet Path, 未包含 Context Path)
重写 doGet 方法. doGet 的参数有两个, 分别表示收到的 HTTP 请求 和要构造的 HTTP 响应. 这个方法会在 Tomcat 收到 GET 请求时触发, 而不用我们手动调用.
注意要删除 super.doGet (req, resp); 这行代码, 这行代码内部就是直接返回错误页面.
HttpServletRequest 表示 HTTP 请求. Tomcat 按照 HTTP 请求的格式把 字符串 格式的请求转成了一个 HttpServletRequest 对象. 后续想获取请求中的信息(方法, url, header, body 等) 都是通过这个对象来获取.
HttpServletResponse 表示 HTTP 响应. 代码中把响应对象构造好(构造响应的状态码, header, body 等)
resp.getWriter() 会获取到一个流对象, 通过这个流对象就可以写入一些数据, 写入的数据会被构造成一个 HTTP 响应的 body 部分, Tomcat 会把整个响应转成字符串, 通过 socket 写回给浏览器.
这个代码虽然只有寥寥几行, 但是包含的信息量是巨大的.
使用 maven 进行打包. 打开 maven 窗口 (一般在 IDEA 右侧就可以看到 Maven 窗口, 如果看不到的话, 可以通过 菜单 -> View -> Tool Window -> Maven 打开)
然后展开 Lifecycle , 双击 package 即可进行打包.
打包成功后, 可以看到在 target 目录下, 生成了一个 jar 包.
这样的 jar 包并不是我们需要的, Tomcat 需要识别的是另外一种 war 包格式.
另外这个 jar 包的名字太复杂了, 我们也希望这个名字能更简单一点.
war 包和 jar 包的区别:
ServletHelloWorld-1.0-SNAPSHOT.jar 的由来:
这个名字来源于 pom.xml 中的 artifactId 和 version
相当于把 artifactId 和 version 拼接起来了.
打为 war 包并重新命名:
<packaging>war</packaging>
<build>
<finalName>ServletHelloWorld</finalName>
</build>
完整的 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>ServletHelloWorld</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>
<packaging>war</packaging>
<build>
<finalName>ServletHelloWorld</finalName>
</build>
</project>
重新使用 maven 打包, 可以看到生成的新的 war 包的结果.
把 war 包拷贝到 Tomcat 的 webapps 目录下.
启动 Tomcat (运行 Tomcat 目录下的 bin 包中的 startup.bat (Windows) / startup.sh (Linux)), Tomcat 就会自动把 war 包解压缩.
看到这个日志说明 Tomcat 已经正确识别了 ServletHelloWorld 这个 webapp.
此时通过浏览器访问 http://127.0.0.1:8080/ServletHelloWorld/hello
就可以看到结果了.
注意: URL 中的 PATH 分成两个部分, 其中 HelloServlet 为 Context Path,就是打的包的名字, hello 为 Servlet Path, 是代码中 @WebServlet 注解里面的路径
可以这么认为:
一个 Tomcat 上可以同时部署多个网站, 一个网站上又有多个页面, Context Path 是告诉 Tomcat 要访问的是哪个网站, Servlet Path 是告诉 Tomcat 要访问的是 Tomcat 上的哪个页面.
手动拷贝 war 包到 Tomcat 的过程比较麻烦. 我们还有更方便的办法.
此处我们使用 IDEA 中的 Smart Tomcat 插件完成这个工作.
点击绿色的三角号, IDEA 就会自动进行编译, 部署, 启动 Tomcat 的过程.
注意:
在浏览器中使用 http://127.0.0.1:8080/ServletHelloWorld/hello 访问页面.
注意路径的对应关系, 与上面不同了, Context Path 变成了我们配置 Smart Tomcat 时的 Context Path
使用 Smart Tomcat 部署的时候, 我们发现 Tomcat 的 webapps 内部并没有被拷贝一个 war 包, 也没有看到解压缩的内容.
所以并没有真正打包. Smart Tomcat 相当于是在 Tomcat 启动的时候直接引用了项目中的 webapp 和 target 目录.
注意: Tomcat 和 IDEA 是两个独立的程序, Tomcat 不是 IDEA 功能的一部分, Smart Tomcat 是第三方工具, 将 Tomcat 和 IDEA 连接起来了.