Servlet 是一种实现动态页面的技术。是一组 Tomcat 提供给程序猿的 API,帮助程序猿简单高效的开发一个 web app。
HTTP 服务器,本质上就是一个 TCP 服务器,只不过在此基础上加了一些按照 HTTP 协议格式进行解析 / 构造的代码。咱们写网站后端,要做的就是调用 Tomcat 提供的API进行二次开发。
静态页面也就是内容始终固定的页面。即使 用户不同/时间不同/输入的参数不同,页面内容也不会发生变化 (除非网站的开发人员修改源代码,否则页面内容始终不变) ~~
对应的,动态页面指的就是 用户不同/时间不同/输入的参数不同,页面内容会发生变化。
举个例子:
Tomcat 的主页 https://tomcat.apache.org/ 就是一个静态页面:
而 B 站的主页 https://www.bilibili.com/ 则是一个动态页面:
- 静态页面:页面内容是固定的 (以文件的形式静静躺在硬盘的指定目录中)!
无论什么时候访问,无论什么人来访问,得到的页面效果都一样 ~~- 动态页面:不是一个真实的硬盘文件,而是通过代码在内存中构造出的一个 “虚拟的资源”!
这就可以根据访问时间的不同,访问人的不同,访问时带有的参数不同,来构造出不同的页面 ~~
构建动态页面的技术有很多,每种语言都有一些相关的库 / 框架来做这件事。
Servlet 就是 Tomcat 这个 HTTP 服务器提供给 Java 的一组 API (来进行二次开发),来完成构建动态页面这个任务。
Servlet 主要做的工作:
当然,Servlet 还支持一些其他的辅助功能,此处暂时先不介绍。
简而言之,Servlet 是一组 Tomcat 提供的 API,让程序猿自己写的代码能很好的和 Tomcat 配合起来,从而更简单的实现一个 web app,而不必关注 Socket、HTTP协议格式、多线程并发等技术细节,降低了 web app 的开发门槛,提高了开发效率。
使用 IDEA 创建一个 Maven 项目。
1)菜单 -> 文件 -> 新建项目 -> Maven
2)选择项目要存放的目录
3)创建完成
此处创建了一个 Maven 项目,Maven 是啥?
Maven 是一个构建工具 (build),包括但不限于编译、打包、部署…
之前咱们写代码,都是直接在idea里,点击main方法前面的三角号就自动编译运行了,这针对一些比较简单的程序还好。如果是一些更复杂的程序,尤其是有多个模块并且相互依赖,比如A依赖B,B依赖C,此时你要想编译运行A,就必须要先编译运行B;要想编译运行B,就需要先编译运行C…
构建工具就是为了解决这个问题,使我们在开发比较复杂的项目时,也可以比较方便地进行编译和打包操作!咱们使用 Maven 主要就是借助 Maven 进行编译、打包、管理依赖…
(在 Java 中,类似于 Maven 的构建工具是比较多的:Ant、Gradle…)
&emp;Maven 项目创建完毕后, 会自动生成一个 pom.xml 文件。我们需要在 pom.xml 中引入 Servlet API 依赖的 jar 包。
1)在 Maven中央仓库中搜索 “servlet”,一般都是第一个结果。
Servlet 的版本要和 Tomcat 匹配,如果我们使用 Tomcat 8.5,那么就需要使用 Servlet 3.1.0,可以在 这个网址:https://tomcat.apache.org/whichversion.html 查询版本对应关系。
3)把中央仓库中提供的 xml 复制到项目的 pom.xml 中
修改后的 pom.xml 形如:
第一次使用可能有标红的现象,把文件下载下来了,标红就没有了。
关于 groupId, artifactId, version
如果我们要把这个写的代码发布到中央仓库上,那么就需要设定好这几个 ID 了
- groupId: 表示组织名称
- artifactId: 表示项目名称
- version: 表示版本号
中央仓库就是按照这三个字段来确定唯一一个包的 ~~
红色方框圈出来的部分, 就是这个 jar 包的 groupId, artifactId, version:
当项目创建好了之后, IDEA 会帮我们自动创建出一些目录。形如:
虽然当下maven 帮我们创建了一些目录,但是还不足以支撑咱们写一个Servlet项目,因此需要手动的再创建一些目录和文件出来。
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 Applicationdisplay-name>
web-app>
在 java 目录中创建一个类 HelloServlet,代码如下:
解释:
上面的代码虽然只有寥寥几行,但是包含的信息量是巨大的!
- 我们的代码不是通过 main 方法作为入口了。main 方法已经被包含在 Tomcat 里,我们写的代码会被 Tomcat 在合适的时机调用起来。此时我们写的代码并不是一个完整的程序,而是 Tomcat 这个程序的一小部分逻辑。
- 我们随便写个类都能被 Tomcat 调用吗?满足啥样条件才能被调用呢?主要满足三个条件:
a) 创建的类需要继承自 HttpServlet;
b) 这个类需要使用 @WebServlet 注解关联上一个 HTTP 的路径;
c) 这个类需要实现 doXXX 方法。
当这三个条件都满足之后,Tomcat 就可以找到这个类,并且在合适的时机进行调用。
使用 Maven 进行打包。打开 Maven 窗口 (一般在 IDEA 右侧就可以看到 Maven 窗口。如果看不到的话,可以通过 菜单 -> View -> Tool Window -> Maven 打开),然后展开 Lifecycle,双击 package 即可进行打包。
如果成功的话,会出现下面的字样:
如果代码/配置/环境存在问题, 可能会提示 BUILD FAILED, 可以根据具体提示的错误信息具体解决。
打包成功后,可以看到在 target 目录下,生成了一个 jar 包:
这样的 jar 包并不是我们需要的,Tomcat 需要识别的是另外一种 war 包格式。另外这个 jar 包的名字太复杂了,我们也希望这个名字能更简单一点。
war 包和 jar 包的区别:
- jar 包是普通的 java 程序打包的结果,里面会包含一些 .class 文件。
- war 包是 java web 的程序,里面除了会包含 .class 文件之外,还会包含 HTML、CSS、JavaScript、图片、以及其他的 jar 包。打成 war 包格式才能被 Tomcat 识别!!!
ServletHelloWorld-1.0-SNAPSHOT.jar 的由来:( pom.xml 文件中)
相当于把 artifactId 和 version 拼接起来了。
在 pom.xml 中新增一个 packing 标签,表示打包的方式是打一个 war 包:
<packaging>warpackaging>
在 pom.xml 中再新增一个 build 标签, 内置一个 finalName 标签, 表示打出的 war 包的名字是HelloServlet:
<build>
<finalName>yyhjavafinalName>
build>
重新使用 maven 打包,可以看到生成的新的 war 包的结果:
把 war 包拷贝到 Tomcat 的 webapps 目录下:
1)打开war的位置:
2)复制黏贴到tomcat文件夹下:
3)启动 tomcat:(双击 bin 目录的 startup.bat)
看到这个日志说明 Tomcat 已经正确识别了 ServletHelloWorld 这个 webapp。
此时通过浏览器访问 http://127.0.0.1:8080/yyhjava/hello,就可以看到结果了:(记得启动 tomcat)
URL 中的 PATH 分成两个部分:其中 HelloServlet 为 Context Path,hello 为 Servlet Path。
学到这里,有些同学会纳闷,通过这么麻烦的方式得到的页面也不过如此,为啥还要通过 Tomcat 这么折腾???
- 获得的是动态页面! 是通过 Java 代码生成的 ~~ (假如我们这里加个时间戳输出的话,页面内容每次刷新都会不一样!)
- 并且 双击本地打开只能访问自己电脑的;使用 Tomcat 可以通过网络访问到别人电脑的网页! 但是此时并不可以,因为不在同一个局域网中 (NAT机制)!
注意: 127.0.0.1 为环回 IP,表示当前主机。此时别人无法通过这个 IP 访问到本地电脑上的页面。内网 IP 是会重复的!要想能够远程访问,势必要有一个外网 IP,怎样才能有外网 IP?可以使用云服务器 ~~ (后续讲解)
上述这七个步骤是针对一个新的项目。项目创建好之后,后续修改代码时前三个步骤就不必重复了,直接从4-7进行操作即可。其中 打包程序 和 部署程序 可以进行优化!!!
我们使用 IDEA 中的 Smart Tomcat 插件完成这个工作!
2)选择 Plugins,选择 Marketplace,搜索 “tomcat”,点击 “Install”
3)安装完毕之后,会提示 “重启 IDEA”
3)在 Name 这一栏填写一个名字 (可以随便写);在 Tomcat Server 这一栏选择 Tomcat 所在的目录,其他的选项不必做出修改
其中 Context Path 默认填写的值是项目名称。
点击绿色的三角号,IDEA 就会自动进行编译、部署、启动 Tomcat 的过程:
有的同学可能会出现下图这种情况,这是因为端口已经被服务器绑定了,再次启动一个程序绑定同一个端口,就会出现这个错误。解决方法就是关闭掉之前打开的 tomcat 即可。
5)访问页面
在浏览器中使用 http://127.0.0.1:8080/yyhjava/hello 访问页面。
tomcat 运行方式有很多种:
1)直接通过 bin 目录里 startup 运行,手动拷贝 war 包过去。
2)直接通过 java 代码,调用 tomcat 的 jar 包运行。则不需要调用的时候指定 tomcat 加载哪个 webapp (Smart Tomcat 的方式)。因此,在 webapp 下不会有 war 包,也不会有欢迎页面 (没有加载 webapps 目录下的东西)!并且两者 Context path 也不同!
以上两种运行方式的区别一定要注意!!!
404 表示用户访问的资源不存在。
1)你请求的资源路径写的不对
2)路径虽然对,但是服务器没有正确把资源加载起来
错误实例1: 少写了 Context Path
通过 /hello 访问服务器
错误实例2: 少写了 Servlet Path
通过 /ServletHelloWorld 访问服务器
错误实例3: Servlet Path 写的和 URL 不匹配
这里是hello:
少了一个o:
错误实例4: web.xml 写错了
清除 web.xml 中的内容,重启 Tomcat 服务器。通过浏览器访问 URL, 可以看到:
405 表示对应的 HTTP 请求方法没有实现。
错误实例: 没有实现 doGet 方法
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
}
重启 Tomcat 服务器,在浏览器中访问,可以看到:
在浏览器地址栏直接输入 URL,会发送一个 HTTP GET 请求。
此时就会根据 /ServletHelloWorld/hello 这个路径找到这个类 并且尝试调用
HelloServlet 的 doGet 方法。
但是如果没有实现 doGet 方法,就会出现上述现象。
往往是 Servlet 代码中抛出异常导致的。
重启 Tomcat 服务器,重新访问页面,可以看到:
在页面上已经有具体的异常调用栈,异常信息里已经提示了出现异常的代码是 HelloServlet.java 的第 15 行。仔细检查这里的代码就可以看到空指针异常。
错误实例: 我们修改代码,去掉 resp.getWritter().write() 操作。
重启服务器,访问服务器,可以看到一个空白页面:
一般是 Tomcat 启动就失败了。
错误实例: Servlet Path 写错了。应该写作 “/hello”。
Tomcat 在启动的时候已经提示了相关的错误。Tomcat 启动的日志里面报错信息可能比较多,需要耐心观察,找到关键的提示。
初学 Servlet,遇到的这类问题会非常多。我们不光要学习 Servlet 代码的基本写法,也要学习排查错误的思路。
熟悉 HTTP 协议能够让我们调试问题事半功倍:
观察日志是调试程序的重要途径!Tomcat 的日志往往很多,需要耐心阅读、经常阅读,熟练了就能更快速找到问题了 ~~