Sevlet

Servlet 是什么

Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一 个 web app.

Tomcat 是一个 HTTP 服务器.这个服务器不光自身有很多功能,同时开放了一组 API 可以让程序猿来使用.基于 Tomcat 来进行二次开发,写更多的业务逻辑.

Tomcat 上提供的这组 API ,就叫做 Servlet .

换句话说,其他的服务器,有的呢提供API,有的呢,没提供......提供 API 的可能也支持 Servlet,也可能是其他的.....

在 Java 世界里,Tomcat 和 Servlet 还是非常主流的开发方式.

(String Web 其实也是基于 Servlet, 在 Servlet 基础上封住了下,当代吗写起来更简洁了,但是底层 还是 Servlet)

之前写的 TCP 服务器:

1.初始化

2.进入循环(

a.读取请求

b.根据请求计算响应

c.把响应返回)

基于 Servlet 开发,要做的事情也差不多是这样

1.初始化,允许程序猿注册一个 类 到 Tomcat 中,让这个类和 HTTP 请求中的一个特定请求相关联(类似于 JS, 给俺妞妞关联一个点击事件)

2.进入循环(循环的处理很多很多请求)(

a.读取 HTTP 请求, Servlet 解析这个请求字符串.生成一个 HttpServletRequest 对象.

b.根据请求对象生成一个 HttpServletRequest 对象(表示响应).根据请求生成响应,这个过程,就是初始化阶段注册的类里面的代码完成的.

c.把 HttpServletRequest 对象转换成 HTTP 响应,返回给浏览器)

第一个 Servlet 程序

我们写一下这个代码

1.创建一个 Servlet 的项目.(Maven)

2.引入依赖.(引入 Servlet api 的 jar 包)

中央仓库网址

https://mvnrepository.com/

版本选择 3.1

点进去之后

这一段代码复制粘贴到 IDEA

3.编写代码

先写一个简单的 hello world

创建好一个类

下面写具体的方法

 这个代码和以往写的代码有很大的差别!!!

之前的代码,都有一个 main 方法,程序运行就是从这个main方法来开始运行的.

Servlet 里面,代码中没有 main 方法(main 方法在 Tomcat 中呢) 咱们写的代码不是自己手动调用的,而是 Tomcat 在合适的时机自动调用.像这样的情况就可以把 Servlet 理解成一个"框架".

4.创建一些必要的目录和文件~~

编写 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>

5. 打包程序,把咱们当前的项目的代码,进行编译,并且打一个压缩包出来.

直接基于 maven 来进行打包

war 包和 jar 包的区别

jar 包是普通的 java 程序打包的结果. 里面会包含一些 .class 文件.

war 包是 java web 的程序, 里面除了会包含 .class 文件之外, 还会包含 HTML, CSS, JavaScript, 图 片, 以及其他的 jar 包. 打成 war 包格式才能被 Tomcat 识别.

所以就得修改 maven 中的 pom.xml 的配置,修改打包类型为 war.

然后在重新打包一次

6.部署程序

把 war 包拷贝到 Tomcat 的 webapps 目录中即可

在部署环节,还有更简单的办法,可以使用 IDEA 中的 smart tomcat 插件来简化 打包 + 部署(一件事的打包和部署)

7.验证一下程序是否正确工作~

通过浏览器方问一下 Tomcat, 构造一个特定的请求.触发到 HelloServlet 的代码

IDEA 的插件

Smart Tomcat 插件

什么是插件(plugin)

IDEA 这样的程序虽然功能强大, 但是也无法面面俱到. 对于一些特殊场景的功能, 开发者就可以 开发一些 "插件". 如果需要这个插件, 就单独安装.

插件就是对程序的一些特定场景, 做出一些特定的功能的扩展.

1

计算机中的很多程序,都是基于"插件体系"

最早的知名插件体系的程序   编辑器中的 Vim 和 Emacs (记事本) 搭配一些额外的插件

后来又有了一个很知名的程序

 安装 Smart Tomcat

 安装完毕之后还需要简单配置一下 Smart Tomcat~

有很多人 IDEA 用的多了,就误以为 Tomcat 也是 IDEA 的一部分(是 IDEA 的一个功能)

Servlet 编码中一些常见的问题

出现 404

404 表示用户访问的资源不存在. 最大的原因就是 URL 的路径写错了!!

如果 web.xml 写错了,也可能导致出现 404

路径虽然没有写错,但是web.xml是空着的,写错的.

观察 Tomcat日志,是能看出一些异常的

在 web 开发阶段(Maven),一旦程序错误,经常会报出大段大段的错误提示....

遇到这种情况不要慌,一定要耐心读一读,都是能读懂的!!!

还有的直接把一大段错误提示,直接粘贴到翻译软件/百度里搜......这是不太靠谱的......

一般这种一大段的提示,关键信息都在上面

出现 405

最主要的原因,请求的方法和代码中重写的方法对不上号~~

出现 500

更好处理,出现 500 最主要的原因就是代码中抛异常了.页面上或者是 tomcat 日志里会明确提示出异常的调用栈等详细信息

出现 "空白页面"

出现 "无法访问此网站"

(一般就是 Tomcat 启动就失败了)

Servlet 运行原理

在写 Servlet 代码的时候,最明显的一点感受就是 Servlet 并不需要去写 main 方法,它的代码是由 Tomcat 自动来去进行调用的,这样的一个过程要自己仔细体会.

Tomcat 的定位

我们自己的实现是在 Tomcat 基础上运行的。

当浏览器给服务器发送请求的时候, Tomcat 作为 HTTP 服务器, 就可以接收到这个请求. HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作.

更详细的交互过程可以参考下图:

Tomcat 的伪代码

就是说:如果让我们自己写一个 Tomcat ,或者让我们去写一个HTTP服务器,大概要这么写?
下面我就以 伪代码的形式来给大家介绍一下。

伪代码:
这个代码并不能真正的编译运行,因此我们不必拘泥于语法的具体形式。
我们主要通过伪代码来理解:实现某个功能的大致逻辑体系。
借助伪代码来疏通某部分的“逻辑阻塞”,构造出较为完整的实现逻辑。
&ensp;
其实伪代码这种,在很多资料书中都会用到。
比如:
与算法相关的一些书,很多都是使用伪代码来描述的。
例如《算法导论》,它里面几乎都是通过伪代码的方式 来描述 算法的具体实现。

下面是 关于 Tomcat的初始化流程 的 伪代码。
大家简单扫一遍,我会在代码下面进行解析。

class Tomcat {// 用来存储所有的 Servlet 对象private List<Servlet> instanceList = new ArrayList<>();public void start() {
// 根据约定,读取 WEB-INF/web.xml 配置文件;
// 并解析被 @WebServlet 注解修饰的类
// 假定这个数组里就包含了我们解析到的所有被 @WebServlet 注解修饰的类.Class<Servlet>[] allServletClasses = ...;
// 这里要做的的是实例化出所有的 Servlet 对象出来;for (Class<Servlet> cls : allServletClasses) {
// 这里是利用 java 中的反射特性做的
// 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
// 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
// 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。Servlet ins = cls.newInstance();instanceList.add(ins);}
// 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;for (Servlet ins : instanceList) {ins.init();}
// 利用我们之前学过的知识,启动一个 HTTP 服务器
// 并用线程池的方式分别处理每一个 RequestServerSocket serverSocket = new ServerSocket(8080);
// 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况ExecuteService pool = Executors.newFixedThreadPool(100);while (true) {Socket socket = ServerSocket.accept();
// 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的pool.execute(new Runnable() {doHttpRequest(socket);});}
// 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;for (Servlet ins : instanceList) {ins.destroy();}}public static void main(String[] args) {new Tomcat().start();}
}

Tomcat 处理请求流程 部分

    class Tomcat {void doHttpRequest(Socket socket) {
// 参照我们之前学习的 HTTP 服务器类似的原理,进行 HTTP 协议的请求解析,和响应构建HttpServletRequest req = HttpServletRequest.parse(socket);HttpServletRequest resp = HttpServletRequest.build(socket);
// 判断 URL 对应的文件是否可以直接在我们的根路径上找到对应的文件,如果找到,就是静态内容
// 直接使用我们学习过的 IO 进行内容输出if (file.exists()) {
// 返回静态内容return;}
// 走到这里的逻辑都是动态内容了
// 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
// 最终找到要处理本次请求的 Servlet 对象Servlet ins = findInstance(req.getURL());
// 调用 Servlet 对象的 service 方法
// 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了try {ins.service(req, resp);} catch (Exception e) {
// 返回 500 页面,表示服务器内部错误}}}

Servlet 的 service 方法的实现 部分

    class Servlet {public void service(HttpServletRequest req, HttpServletResponse resp) {String method = req.getMethod();if (method.equals("GET")) {doGet(req, resp);} else if (method.equals("POST")) {doPost(req, resp);} else if (method.equals("PUT")) {doPut(req, resp);} else if (method.equals("DELETE")) {doDelete(req, resp);}
......}}

小结

这一块的核心逻辑,主要分成两个部分来理解。

1、初始化 / 准备工作
   准备工作:把 Servlet 实例给加载起来。

2、处理请求
根据 URL找到匹配的 Servlet 类,再来去调用 Servlet 里面对应的方法、

另外,在讨论到这整套流程过程中,涉及到了 关于 Servlet 的 关键方法,主要由三个:

1、init:初始化阶段,对象创建好了之后,就会执行到。另外,用户可以重写这个方法,来执行一些初始化的操作。

2、destroy:退出主循环,Tomcat 结束运行之前回调用。主要是用来 释放资源。

3、service:在处理请求的阶段来调用,每次来个请求都需要调用一次 service。

注意! init 和 destroy 方法,都是一个 Servlet 对象调用一次。
而 service 可能会被一个对象,给调用很多次。
毕竟我们大部分时候,进入一个网站都是有目的,至少UI浏览一下,在浏览的过程中就需要进行多次交互,也就会发送多次请求,service 自然也就会被调用多次。

这几个方法的调用时机,都是比较固定的。
我们就把这几个关键方法,以及它们的调用时机,称为 Servlet 的 生命周期。

生命周期,这个词是计算机里一个挺常见的术语。
它的意思就是:什么时候该做什么事情。
比如:
我们在上学,该做的事情就是 学习。
我们在工作,该做的事情就是 挣钱。
稳定之后,该做大的事情就是找对象,结婚生子了。

也就是说,在人生的每一个阶段,我们都是有事可做的。
这就是 一个普通人 的 生命周期。

我们的代码,也是类似的。
很多的对象,也是会划分出几个阶段。
这个对象,第一阶段做什么,第二阶段做什么…
所以这里划分出的这些阶段,以及每个阶段执行的时机,就就叫做 声明周期。

Servlet API 详解

前面介绍的是 Servlet 基本用法 + 运行原理 ~ Serlevt 是如何工作的~~

接下来来看 Servlet 的使用细节~

学习 Sevlet 的具体使用,核心就掌握 三个 类就够用了~~

1.HttpServlet

2.HttpServletRequest

3.HttpServletResponse

HttpServlet

继承 HttpServlet 是为了重写这里的一些方法,重写方法的目的则是为了能够把程序猿定义的逻辑给插入到 Tpmcat 这个 "框架" 中~~ 好让 Tomcat 能够进行调用~~

类似于这样的操作,之前也有

Comparable

Comparator

多线程

继承 Thread 重写 run,

然后在其他线程中,调用 Start, 就可以创建线程,并执行咱们刚才写的代码了~~

让程序猿把自定义代码插入到一个代码框架中,办法是很多的,这种基于多态的方式虽然能实现,但是这是一种比较 "经典" 的做法.

实际上其他的语言中,还有更加方便简洁的做法~~

典型的,就是 JS ~ button.onclick = function{

}

在 JS 中只要简单的赋值一个函数过去即可~~

HttpServlet 的 核心方法

一个常见的面试题:

说一下 Servlet 的生命周期~~

变量的申明周期,指的是,变量是咋来的,又咋没的,什么时候被创建,什么时候被销毁,这个都比较简单.

Servlet 此处说的生命周期,不光是包含 Servlet 是咋来的,以及咋没的,还包括中间的一些过程和状态~~

这个问题我们只要回答三句话:

1. Servlet 在实例化之后调用一次 init

2. Servlet 每次收到请求,调用一次 service

3. Servlet 在销毁之前,调用一次 destroy

处理 GET  POST 请求

 

HttpServletRequest

这个类表示一个 HTTP 请求~~

理解这个类的前提就是理解 HTTP 协议的格式~~

核心方法

写两个具体案例来感受一下 HttpServletRequest 这个类的使用情况

代码示例一:打印请求信息

代码示例二:获取 GET 请求中的参数

尤其是 query String 中的参数

query String 里面内容,是程序猿自定义的内容~~

每个键值对的 键 和 值都是程序猿自己定义好的~

代码示例: 获取 POST 请求中的参数(1)

POST 请求中的参数,主要是放在 body 找那个.(POST也是可以在 query string 中放参数的,单数比较少见)

POST 请求的 body 中的格式又有好几种方式~

1.application/x-www-form-urlencoded

a=10&b=20 类似于 query string 格式

2.mutlipart/form=data

这种格式比较复杂,主要是用来提交文件的. 生成一个分隔符~~

3.application/json

{

a:10,

b:20

}

第一种直接还是使用 getParameter 方法来获取~(和获取 query string 没区别)

这种方式直接还是使用 getParameter 来获取. 代码和获取 query string 的方式差不多~

第三种

如果 body 是 json 格式,就可以把整个 body 的字符串都单独取出来,然后进行解析~

当前是把整个 body 视为一个整体字符串了.

更多是需要解析 json 格式的 body,拿到 userId 和 classId 里面具体的值~

怎么拿到这个值呢,这里面就需要对 json 进行解析.

json 格式本身解析气是比较复杂的~(json里面能嵌套)

就相当于这样.

套娃的过程也挺复杂的,光手动进行解析并不容易,而且容易出错,更好的办法是直接使用第三方库~

Java 世界中能够解析 json 的第三方库,有很多~~

这里只说 Jackson .

因为这些库的用法和性能等等方面其实都差不多.

Jackson 是 Stirng 全家桶里面指定使用的 JSON 库......

Java 中要想引入第三方库,就可以使用 maven 从中央仓库下载

小结

通过上面的几个案例,主要演示了 HttpServletRequest 这个类的基本用法~~

结合 HTTP 协议的格式,来理解 HttpServletRequest 中提供的方法~

平时使用这个 HttpServletRequest 最常用的工作,就是获取到请求中的参数~

参数又通过三种方式提供过来:

1.通过 query string.  getParameter 方法来获取

2.通过 body(application/x-www-form-urlencoded)  getParameter 方法来获取

3.通过 body(application/json)  先把整个 body 读取出来,然后在使用 json 库来解析.

补充:

在这几个案例里面没构造 HTTP 请求,都是通过了自己写一个页面,使用 form 表单 或者 ajax 来构造请求~~

这种构造请求的方式 会比较麻烦一些~

更简单的办法就是可以使用一些专门的第三方工具来构造请求~~

HTTP 请求来说,构造请求的工具有很多~~

Postman 也是其中的佼佼者

HttpServletResponse

HttpServletResponse 和 HTTP 协议的响应格式,是对应的~~

核心方法

HttpServletRequest,里面的内容,是客户端构造的.服务器需要做的是获取到这里的内容(尤其是程序猿自定义的数据)

HttpServletResponse,里面的内容,是服务器构造的,要返回给客户端~

对于 HTTP 响应来说,header 中的 Key 并不要求非得是唯一的.有些 Key 可以重复出现.

典型的就是 Set-Cookie 属性

如何构造一个重定向响应呢?

把状态码设为 302,在 header 中设置 Location 就可以了.

代码示例: 设置状态码

代码示例: 设置状态码

实现让页面自动刷新~

HTTP 响应中可以设置一个 hearder ,Refresh,值就是刷新的间隔时间(单位 s)

代码示例: 重定向

重定向就是"呼叫转移"

302

Location 字段,描述了重定向的位置~

总结

当前就已经把 HttpServlet  HttpServletRequest  HttpServletResponse 三个核心类介绍完了.

现在已经对 Servlet 有了初步的认识,就好比该有的基本工具该做的准备工作都完成了,接下来基于当前的这些已经学过的东西,来实现一些具体的案例,通过这些案例再来进一步的体会一下Servlet的基本使用.

代码示例: 服务器版表白墙

【Java成王之路】EE初阶第二十四篇: Servlet相关推荐

  1. 【Java成王之路】EE初阶第十四篇:(网络原理) 4

    上节回顾 TCP的核心就是可靠性!! 1.确认应答.保证可靠性的核心机制.针对传输数据以字节为单位进行编号. 2.超时重传: ①.传输的数据丢了 ②.ack应答报文丢了 都要重传 超时时间是动态变化的 ...

  2. 【Java成王之路】EE初阶第二十三篇: HTTP协议和Tomcat

    目录 前言 HTTP 协议 什么是HTTP协议 回顾一下应用层协议 理解 HTTP 协议的工作过程 抓包工具的使用 HTTP协议的详细格式 + 信息 HTTP请求的格式 HTTP响应的格式 HTTP协 ...

  3. 【Java成王之路】EE初阶第十篇:(网络编程) 4

    上节回顾 套接字,TCP版本的套接字 API ServerSocket 服务器这边使用的 Socket: 服务器和客户端都需要使用 对于服务器来说: 1.创建ServerSocket 关联上一个端口号 ...

  4. Python之路【第二十四篇】Python算法排序一

    什么是算法 1.什么是算法 算法(algorithm):就是定义良好的计算过程,他取一个或一组的值为输入,并产生出一个或一组值作为输出.简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果. ...

  5. Java成神之路技术整理

    转载自 Java成神之路技术整理 以下是Java技术栈微信公众号发布的所有关于 Java 的技术干货,会从以下几个方面汇总,本文会长期更新. Java 基础篇 Java 集合篇 Java 多线程篇 J ...

  6. Alibaba技术专家倾心五年打造 Java成神之路:基础篇

    近日里,很多人邀请我回答各种j2ee开发的初级问题,我无一都强调java初学者要先扎实自己的基础知识,那什么才是Java的基础知识?又怎么样才算掌握了java的基础知识呢?这个问题还真值得仔细思考. ...

  7. Python之路【第十四篇】:AngularJS --暂无内容-待更新

    Python之路[第十四篇]:AngularJS --暂无内容-待更新 转载于:https://www.cnblogs.com/weiman3389/p/6224181.html

  8. 【零基础学Java】—ArrayList集合概述和基本使用(十四)

    [零基础学Java]-ArrayList集合概述和基本使用(十四) 一.什么是ArrayList类以及注意事项 java.util.ArrayList是大小可变的数组的实现,存储在内的数据称为元素,此 ...

  9. Java成神之路[转]

    阿里大牛珍藏架构资料,点击链接免费获取 针对本文,博主最近在写<成神之路系列文章> ,分章分节介绍所有知识点.欢迎关注. 主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 ...

最新文章

  1. ajax post请求,后台servlet来接收
  2. 基于KNN的相关内容推荐
  3. js中字符串转为对象或者json
  4. webservice 缓存机制
  5. 轻松学会多线程(四)——synchronized同步keyword知多少
  6. dijkstra 算法_路径规划算法总结
  7. 数据库学习(Oracle)
  8. Internet Explorer 7 功能
  9. [Unity3D]自己动手重制坦克舰队ArmadaTank
  10. java 仿百度文库源码_Java模拟实现百度文档在线浏览
  11. Unity 之 获取物体的旋转角正确数值
  12. NmRF:从RNA序列中鉴定多物种RNA2‘-o-甲基化修饰位点(假尿苷位点)
  13. 六西格玛质量管理慕课答案
  14. 如何解决audiodg占用内存高(停止与重启audiodg服务)
  15. 猜一宋词名句 Java_古诗词名言名句大全之宋词名句集锦
  16. 一个表写给另一个表的情书!
  17. EXCEL获取今天是今年的第几周
  18. 解决Google浏览器卸载后无法重新安装的问题
  19. 一日之计在于晨,晨跑带来的不止是健康,还有乐观积极的人生态度
  20. Win10+Ubuntu双系统安装教程

热门文章

  1. 【踩坑笔记】从零开始部署安装Stable Diffusion 2 WebUI
  2. 英语学习的方法(1)
  3. 国内唯美花海 新娘绝美婚纱照
  4. discuz 搬迁服务器时,根域名访问 主动跳到 门户列表页问题
  5. 使用RestTemplate:报错Could not extract response: no suitable HttpMessageConverter found for response typ
  6. stm32利用外部中断控制小台灯
  7. 启英泰伦CI-C22GS02(ci1122)单麦离线智能语音模块制作声控小台灯
  8. mysql sql stuff函数_SQL常用函数之一 Stuff()
  9. 那些可多人协作编辑的在线文档工具
  10. Oracle Linux 迷途知返