目录
一、前置知识:Maven
🍎初识Maven
🍎Maven的使用
二、Servlet
🍑 第一个Servlet程序:hello world
1、创建Maven项目
2、引入依赖
3、创建目录结构
4、编写servlet代码
5、打包
6、部署
7、验证程序
📝一点补充
📝smart tomcat的使用
🍑ServletAPI详解
1、HttpServlet
2、HtttpServletRequest
3、HttpServletResponse
一、前置知识:Maven
🍎初识Maven
Maven,这是我们在编写Servlet代码的时候,要用到的一个常见的工具
Maven, 是Java 世界中的一个非常知名的 “工程管理工具 / 构建工具”。
它的核心功能:
- 1、管理依赖
- 2、构建 / 编译
- 3、打包
有的人可能会产生疑问:编译,不是编译器的工作吗?
和 Maven 有什么关系呢?
其实 Maven 的 构建 / 编译,也是在调用 JDK 来去进行 编译 和 打包 的工作。
但是呢,如果你光用 JDK ,就好像是:
执行这个操作,你去进行编译。
执行下一个操作,你去进行打包。
................
但是,现在 Maven 把 这一系列的操作,都给你串起来了。
用一个成语来形容:一气呵成
因此,Maven 存在的意义:
就是能够直接把这些操作(管理依赖,构建 / 编译,打包)串起来。(一气呵成)
尤其是一些比较大的程序,它里面有很多模块。
你要是每一个模块,都去手动去敲一个命令去编译;或者每一个模块,都去点一下进行打包,这就很麻烦了。
但是,我们如果使用 Maven,就可以一键式的来帮我们把这里的这些操作,全部完成。
对于上面说到的构建/编译,我还知道。可是这个打包和依赖是什么意思
打包:就是把Java代码给构造成jar包,或者是war包。
jar包:其实就是一个特殊的压缩包,类似于 rar。里面就是把 各种 .class 文件,放到一起来。然后,进行压缩得到的包,就是 jar 包。
war包,也是同理。只是与 jar 包,在细节上存在差别。
另外,打包,也是 Maven 调用 JDK 里面的功能来实现的。(强调一下)
依赖:就是你在进行一个A操作之前,先要进行一个B操作。如果没有B操作的实现,你A操作就无法完成。
🌰举个栗子:
要想有老婆,就必须先要有结婚的对象。
要想有结婚的对象,就必须先要有 女朋友。
要想有女朋友,就必须要有自己中意的对象。
其中 结婚的对象,女朋友,中意的对象,都是进行前者操作的必要条件。
两者之间的关系,就被称为 “依赖”。
咱们写代码的时候,也是有很多依赖的。
只是当前阶段,依赖的东西不多。
1、经常会依赖标准库(集合类:Scanner,顺序表,链表等等…)
但是,更严格来说:标准库并不算是依赖。
因为,你只有安装了JDK,这些东西就都会有。【自带的】
但是,要想执行 Java 程序,肯定是需要依赖 JDK 的。
因此,Java 程序 和 JDK 是属于 依赖关系,
但java程序和标准库之间的依赖关系,太勉强了。
2、经常依赖第三方库
第三方库:就是我们写代码的时候,需要引入的一些其它的jar包。
就像前面讲 JDBC编程 的时候,当时就下载了一个 mysql 的驱动包。
当时,我们要想进行 JDBC 编程,这个 驱动包 是必不可少的!
这也就属于依赖。
其实写代码的时候,有时候的依赖也会非常复杂。
你引入了一个第三方库A,而这个 A 又依赖于 库 B,B 由依赖于 C,C又依赖于D,
类似这样的套娃操作,我们要想使用 A,就必要把它前面所依赖的库,全部引入。
如果我们是手动去管理这个依赖,那就会相当的麻烦!!
不光你得研究清楚,每个库都依赖哪些其他库。
而且,还得要研究清楚,这些依赖之间的版本是否匹配的问题。
如果版本不匹配,搭配起来使用,就会有很多莫名其妙的bug存在。
为了解决上述的依赖问题,很多编程员都引入了自己的包管理工具(自动解决依赖)。
Java:Maven,Gradle
Python:pip
JS:npm
各种语言都有着自己的包管理工具。
除了 C++。。。
这就是一个比较悲伤的故事了。
目前为止,C++官方还没有提供这样的一个包管理工具。
第三方的包管理工具是有,但是问题多。
就没有一个像 Maven 这种这么成熟的工具。
————————————————
🍎Maven的使用
对于Maven来说,我们不用下载,因为idea中内置了线程的Maven,我们之间拿来用就好。
下面我们主要介绍在Maven在idea中的使用
1、新建一个Maven项目
2、Maven的使用
🔔首先我们先了解刚刚我们新创建的Maven项目的组成部分
下面我们以mysql驱动包的引入来说明Maven引入依赖的流程
二、Servlet
Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 web app(网页).
🍑 第一个Servlet程序:hello world
1、创建Maven项目
这个步骤我们在Maven介绍中已经介绍过了,这里 不再赘述。
2、引入依赖
因为Servlet这个API部署JDK内置的,而是第三方(Tomcat)提供的,所以我们要想使用,就需要额外的引入Servlet依赖 。
我们借助Maven来引入Servlet依赖——这里我们所导入的第三方库都是从Maven中央仓库中获取的
3、创建目录结构
虽然当下 Maven 帮我们创建了一些目录,但是还不够。
当前这个目录还不足以支撑我们写一个 Servlet 项目,我们这个项目是依赖Tomca服务器,为了符合Tomcat的格式,我们就需要手动创建一些目录和文件。
这些目录和文件的格式是固定的,不要问为啥要创建这样一个目录或者说文件,这是为了符合Tomcat而弄出的硬性要求
其中这个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、编写servlet代码
经过上面的分析,我们可以知道,我具体的servlet代码是要在doGet这个方法中写的,下面我们深入这个方法来看一下
🤔你以为到了这里就大功告成了吗?
我们要实现的是通过在浏览器输入url(发一个HTTP的get请求),进而通过tomcat服务器来调用我们这个doGet。
当我们成功给tomcat发了一个get请求,tomcat怎么知道要调用具体哪个servlet代码呢?
这里我们希望调用我们HelloServlet类中的doGet方法,那么我们就需要给我们这个类添加一个“标识符”,同时把这个标识符写到在浏览器url中中,这样tomcat就能够识别到这个请求具体是要调用哪个servlet代码了。
5、打包
刚刚我们编写的servlet代码是不能单独运行的
我们的servlet程序要卸载Tomcat才能正确执行,这里我们的servlet代码就相当于是一节节的车厢,光有车厢不能跑起来,还需要车头——也就是Tomcat的帮助才能跑起来
打包就是把你车厢和车头连接起来,让车头Tomcat拖着我们的车厢Servlet程序来执行
下面我们看一下打包的具体实现过程
6、部署
把 war 包拷贝到 Tomcat 的 webapps 目录下
让Tomcat(车头)拖着它执行。
7、验证程序
其实就是看看能不能通过tomcat服务器在浏览器来访问我们的servlet代码
📝一点补充
与HTML生成页面不同,我们当前的通过Servlet生成的页面是动态的,根据用户输入的不同,是可以得到不同的显示效果的。
此外当我们修改了servlet代码后,我们需要重写进行打包、部署、然后再验证程序。
注意:我们在重新部署时候,最好重启一下tomcat
不过如果每次改了代码,我们都要重新打包生成一个.war文件,然后再把这个新的.war文件放到tomcat目录中的webapps目录下,然后再找到bin目录下的startup.bat文件重新启动tomcat。
这样子的确十分的麻烦。
为此我们可以借助第三方工具:smart tomcat来简化我们的打包和部署
- smart tomcat这个idea里的一个插件,就 保证我们把tomcat服务器和我们的idea关联起来。保证我们一键式完成打包和部署操作。
- 但是我们要知道idea 和 tomcat是两个独立的程序!!! tomcat部署idea功能的一部分 ,tomcat只是通过idea插件:smart tomcat,来和我们的idea建立起来一个合作的桥梁。
为什么要提这一点?
这是因为后面开发,主要还是通过 idea 调用 Tomcat的方式来进行。
用的时间长了之后,大家就对于 Tomcat的印象,就开始模糊。
甚至会产生 Tomcat 是 idea 功能的一部分,这样的错觉!
以后大家在工作中,会涉及到几个不同的环境。
📝smart tomcat的使用
使用 Smart Tomcat 部署的时候, 我们发现 Tomcat 的 webapps 内部并没有被拷贝一个 war 包,也没有看到解压缩的内容.
Smart Tomcat 相当于是在 Tomcat 启动的时候直接引用了项目中的 webapp 和 target 目录(@WebServlet()中的内容).
🍑ServletAPI详解
1、HttpServlet
相信通过上面我们第一个hello world程序,大家应该已经知道了。我们写的servlet代码总是继承自HttpServlet这个类——我们就是重写其中的doPost、doGet等相关方法来被Tomcat执行调用的
这个过程 和 继承 有关,就会涉及到Java中的一个核心语法 “多态”。
在我们学习Java的时候,多态就是我们一个难啃的骨头。
如果以后在面试的时候,被面试官问到。
让你讲讲对多态的理解,最好方式就是 举例子。
最好举一些有意义的例子,并且最好是关于代码的。
比如:
集合类: List list = new ArrayList<>();
多线程:class Mythred extends Thread{ 重写 run方法 }
像这种平常刷题经常会用到的代码,用来举例是最好的。
另外,Servlet 也是一个很好的例子!
因为我们自己写的代码也是通过继承重写的方式来实现的。
因此在执行的过程,是一定会涉及到 “多态的”!
HttpServlet的核心方法
方法名称 | 调用时机 |
init | 在 HttpServlet 实例化之后被调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/... | 收到其他请求的时候调用(由 service 方法调用) |
我们实际开发的时候主要重写 doXXX 方法, 很少会重写 init / destory / service
🌰这些方法的调用时机, 就称为 "Servlet 生命周期". (也就是描述了一个 Servlet 实例从生到死的过
程)
Servlet生命周期描述的是Servlet创建到销毁的过程:
- 当一个请求从HTTP服务器转发给Servlet容器时,容器检查对应的Servlet是否创建,没有创建就实例化该Servlet,并调用init()方法,init()方法只调用一次,之后的请求都从第二步开始执行;
- 请求进入service()方法,根据请求类型转发给对应的方法处理,如doGet, doPost, 等等
- 容器停止前,调用destroy()方法,进行清理操作,该方法只调用一次,随后JVM回收资源。
注意:Httpservlet实例只是再程序启动时,创建一次,而不是每次收到HTTP请求都重新创建实例
其中的doGet和doPost等doxx方法,是根据HTTP的请求的不同来分别执行的。
doGet处理get请求,doPost处理post请求,doPut处理put请求
2、HtttpServletRequest
核心方法
方法 | 描述 |
String getProtocol() | 返回请求协议的名称和版本。 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。 |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该 请求的 URL 的一部分。 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分。 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串。 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名 称。 |
String getParameter(String name) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组,包含所有给定的请求参数的值, 如果参数不存在则返回 null。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果 长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象. |
打印请求信息
获取get请求的参数
获取post请求的参数
3、HttpServletResponse
同样的,HttpServletResponse 对应到 一个 HTTP 响应。
HTTP 响应中有什么,这里就有什么。Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到
HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过Socket 写回给浏览器
核心方法
方法 | 描述 |
void setStatus(int sc) | 为该响应设置状态码。 |
void setHeader(String name, String value) | 设置一个带有给定的名称和值的 header. 如果 name 已经存在, 则覆盖旧的值. |
void addHeader(String name, String value) | 添加一个带有给定的名称和值的 header. 如果 name 已经存在, 不覆盖旧的值, 并列添加新的键值对 |
void setContentType(String type) | 设置被发送到客户端的响应的内容类型。 |
void setCharacterEncoding(String charset) | 设置被发送到客户端的响应的字符编码(MIME 字符集)例 如,UTF-8。 |
void sendRedirect(String location) | 使用指定的重定向位置 URL 发送临时重定向响应到客户端。 |
PrintWriter getWriter() | 用于往 body 中写入文本格式数据. |
OutputStream getOutputStream() | 用于往 body 中写入二进制格式数据 |
代码案例
自动刷新
- 实现 Servlet, 设置 header, 实现每隔 1s 自动刷新页面的效果. 页面上要显示当前时间戳
2、让页面上能够显示格式化的事前. 例如 2022-01-19 12:00:00
3、重定向:访问 /redirect 路径后, 自动重定向到 搜狗主页 的代码.
光理解了 Servlet API,还不足以支撑我们写出一个功能完整的网站。
还需要理解一个网站的开发过程大概是什么样子的。
理解这里的一些基本的编程思维 和 设计思路。这就需要通过更多的案例,来进行强化了。
下篇博文就让我们一起事情一个服务器版本的表白墙(注意不只是单单的前端HTML文件哦,还有与之相对应的后端代码——说白了就是一个简单的前后端交互的栗子)