Servlet live to service clients.
需要记住第二章里没记住的。本章的细节不会在之后的章节再次复述。
勤加训练,记住没有记住的。模拟考试并达到 80% 以上的正确率之前,不能进入下一章的学习。

文章目录

  • 描述servlet生命周期的目的和事件序列-loading-instantiation-init()-service()-destroy()
  • 各种HTTP方法的用途和特点
  • HttpServletRequest-从请求获取信息
    • 回到真正的工作 handle requests 上来。
  • HttpServletResponse-设置响应-获取流
    • 说完了 Request 来说 Response
      • 输出:characters or bytes
  • HttpServletResponse-转发和重定向
    • 有些时候并不想自己来处理 response
    • Servlet redirect makes the *browser* do the work.
    • A request dispatch does the work on the *server* side

描述servlet生命周期的目的和事件序列-loading-instantiation-init()-service()-destroy()

Servlet 只有两种状态,要么不存在(does not exist),要么存在(initialized)。不存在经由 init() 到存在,存在经由 destroy() 到不存在。

类的继承、实现关系
MyServlet->HttpServlet->GenericServlet->Servlet<<interface>>

三大生命周期时刻

When it’s called What it’s for Do you override it
init() after the servlet instance is created bu before the servlet can service any client requests Gives you a chance to initialize your servlet before handing any client requests Possibly(getting a DB connection / registering yourself with other objects
service() the first client request comes in determines the HTTP methods and invokes the matching doGet(), doPost(), etc. No.Very unlikely.
doGet() and/or doPost() service() invokes doGet() or doPost() responsible for whatever the heck your web app is supposed to be DOING. All starts from here. ALWAYS

So the service() -> doGet() method sequence happens each time there’s a client request.

注:这里牵涉到线程的管理(create & allocate)相关知识,需要恶补。

  1. init() 初始化
  2. Servlet初始化之后,第一个 request 的到来让 Container 分配线程并 invokes service()
  3. 然后,service() 又根据请求的类别 Invokes 与请求类别匹配的 doXXX() 方法(我自己覆盖过的方法),
  4. 此后 service() 进程销毁或者放进由 Container 管理的线程池中,
  5. 下一个request来,再从 2 (创建或找一个线程运行 service())来一次,

视资源(resources)限制和容器策略(policies)和配置(configuration)的不同,可运行线程的数目至少和客户端请求的数目一样多,如果请求数超过指定的最大同时运行线程数,那么一些客户端不得不等待。

每个请求在一个单独的线程中运行。容器运行多个线程来处理对单个 servlet 的多个请求。故 “Each instance of the servlet…" 这种说法是错误的。

一个请求一个线程,而不是一个客户一个线程,容器不关心请求时谁发出的——有请求进来就创建一个 thread/stack。

servlet 的生命开始于查找 class files, 通常在 Container 启动时(比如打开 Tomcat)。
Container 启动时,其查看(look)已经部署的 web apps,并查找(searching) servlet class 文件,这是第一步。
第二步,加载(loading),视配置不同,可以在Container startupfirst client use 时发生,无论是那种加载方式,在 servlet 初始化完全完成前,service() 方法都不会运行。亦即 :init() always completes before the first call of service().

初始化,是一个简单对象变成 Servlet 的过程。这个过程中,Servlet 是存在(initialized)和不存在(do not exist)的一个中间状态(“薛定谔的 Servlet”),在成为 Servlet 的过程中,对象会被授予特权,例如,用 ServletContext 引用从容器中获取信息。
记住一点,servlet 的 constructor 里面没有有参数。没有什么事情不能等到 init() 完成之后。

一个正式的 Servlet 比普通的对象(object)多了:

  • A ServletConfig Object (部署时起避免硬编码的作用,如DB,只要此servlet已部署并运行,它就不会更改。一个 servlet 一个)
  • A ServletContext (AppContext, 一个 web app 一个)
    这章只是起一个头,下一章会明说。

各种HTTP方法的用途和特点

HttpServletRequest-从请求获取信息

回到真正的工作 handle requests 上来。

  • 容器实现了 HttpServletRequestHttpServletResponse ,不必操心具体实现过程。
  • 接口可以继承接口。
  • 不讨论 HTTP 以外的协议
  • 不讨论 GET 和 POST 以外的方法(as a web-server/servlet developer)

GET 和 POST 的区别:POST 有 body.
GET 的参数塞在path后面,POST 的参数放在body里面。

GET 参数:大小有限,明码可见,可以被 bookmark (搜索结果页就很适合,整个bookmark起来,下次不必重新输入搜索关键字)——说一千道一万,GET就是用来简单粗暴地“取回”内容的,不会对服务端作任何改变。POST 是为了传需要被处理的数据,它可以用来传递一个查询参数,达到和GET相同的效果,但根本是“上传”,就是要对服务端作出改变。

关键在区分:whether the reqeust is idempotent

支付页面没有即使反馈“正在支付”或者“支付成功”,会让用户以为窗口冻结,反复点按购买按钮,导致重复下单。

幂等性 idempotent 是好的。这意味着你可以一遍又一遍地做同样的事情,而不会产生不想要的副作用!(GET 就是如此)


POST is not idempotent.

注:这里的 idempotent 指的是 the same request can be made twice with no negative consequences on the server,不是 the same request always returns the same response,也不是 a request has NO side effects

普通的 <a> 标签中的 href 都是 GET 请求。
<form> 属性中如果没有 method=“POST” 属性,默认为 GET 请求。这种情况下,很可能因为 servlet 端没有重写 doGET() 方法而造成错误。为了避免请求失败,可以如下书写代码:

public void doPost(...)throws ... {doGet(request, response);
}

一个 form 里,可以有多个参数(几个 select),一个参数里可以有多个值(如checkbox)

<form method="GET" action="SelectBeer.do"><input type="checkbox" name="sizes" value="12oz">12 oz.<br><input type="checkbox" name="sizes" value="16oz">16 oz.<br><input type="checkbox" name="sizes" value="22oz">22 oz.<br><input type="submit" value="ni ">你
</form>

勾选✔后发出去的效果
SelectBeer.do?sizes=12oz&sizes=16oz&sizes=22oz
代码中这样写:

String one = request.getParameterValues("sizes")[0];
String [] sizes = request.getParameterValues("sizes");
// for testing
String [] sizes = reqeust.getParameterValues("sizes");
for(int x=0; x < sizes.lenght ; x++) {out.println("<br>sizes: " + sizes[x]);// assume that "out" is a PrintWriter you got from the response
}

除了参数,还能从 Request 里面得到什么?

//要查看全部 API 看如下两个类
javax.servlet.ServletRequest
java.servlet.ServletResponse

需要关注的常用的方法有(常用的可能15%都不到)

// To client's platform and browser info
String client = request.getHeader("User-Agent");
// The cookies associated with this request
Cookie[] cookies = request.getCookies();
// The session associated with this client
HttpSession session = request.getSession();
// The HTTP Method of the request
String theMethod = request.getMethod();
// An input stream from the request
InputStream input = request.getInputStream();

Header 有name 和value,如 “User-Agent":"http://t.cn/EUC9o12?m=4317179900218395&u=3921730119"getHeader() 得value字符串。但对于有一些值本来就是数字的header,如"Content-Length"(指定message-body的字节数)、“Max-Forward”(指定通过路由的跳数),要直接获取数值,可以方便地用 getIntHeader() 方法。如下所示:

String forwards = request.getHeader("Max-Forwards");
int forwardsNum = Integer.parseInt(forwards);
// 等效于
int forwardsNum = request.getIntHeader("Max-Forwards");

区分:

  • getRemotePort() :get the client’s port,服务器的 remote 自然是 client。
  • getServerPort():to which port was the request originally SENT? 请求最初发送到哪个端口
  • getLocalPort():on which port was did the request END UP? 请求是在哪个端口上完成的

because although the requests are sent to a single port (where the server is listening), the server turns around and finds a different local port for each thread so that the app can handle multiple clients at the same time.
因为虽然请求被发送到单个端口(服务器正在侦听),但服务器转向并为每个线程找到不同的本地端口,以便应用程序可以同时处理多个客户端。

HttpServletResponse-设置响应-获取流

说完了 Request 来说 Response

大多数时候,你只是用 Response 返回数据给客户端。
使用两个方法:setContentType()getWriter(),利用I/O直接写进stream里。
但是有时候会用 Response 设置其他的 headers,发送errors,以及 add cookies。

前文提到过,不会直接把HTML写进Stream,而用 JSPs. 但不是说绝对不直接往 Response 里写东西,有如下原因:

  1. hosting provider 不支持 JSPs,有些旧的服务器或容器支持 servlet 但不支持 JSPs。
  2. 没有使用 JSPs 的选项,如系统管理员拒绝。
  3. 不写HTML,可以写其他东西,如:a JAR。

发送 JAR 到客户端。
例如创建一个下载页面让客户端能够通过JAR文件下载代码,而不是发送 HTML 网页。读取 JAR 的字节,然后写进 response 的 output stream 里面。

import javax.servlet.ServletRequest;
import java.io.InputStream;
import java.servlet.ServletResponse;public class CodeRetrun extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletExcetion {response.setContentType("application/jar");// "/" 表示web app 的根目录ServletContext ctx = getServletContext();InputStream is = ctx.getResourceAsSteam("/bookCode.jar");int read = 0;byte[] bytes = new byte[1024];OutputStream os = response.getOutputStream();while ((read = is.read(bytes)) != -1) {os.wirte(bytes, 0, read);}os.flush();os.close();}}

说 Content Type 就是说 MIME type。Content Type 是 HTTP response 中必须包含的 HTTP header . 浏览器接收到后,方能进行正确的操作:launch a “helper” app like a PDF viewer or video player, render the HTML, save the bytes of the response as a downloaded file, etc.

Common MIME types:

  • text/html
  • application/pdf
  • video/quicktime
  • application/java
  • image/jpeg
  • application/jar
  • application/octet-stream
  • application/x-zip

不用记住 content types,但是要知道 setContentType() 是干什么的,怎么用。谨记,call setContentType() first, BEFORE you call the method that gives you your output stream (getWriter() or getOutputStream()).

Apache 可以配置映射文件后缀content type,从而不必手动设置 content type.但是当没有文件时,需手动。
当Servlet读文件时,Container 不知道我们在干嘛,只知道我们正在从一种类型的东西里读,往 response 里的另一种完全的不同的东西里写。

以发送 JAR 为例,实际上,可以让用户点击链接,直接在服务器下载JAR文件而不必经由 servlet,就像下载 JPEG 一样。但是,例子是假设你想在发送前对文件做点什么(动态),而并非是直接发送(静态),如动态发送某一个文件,动态创建并发送。换句话说,要发送的文件在发送前并非是保存在服务器上的,而是运行时构造出来的。

输出:characters or bytes

ServetResponse interface 给了两个选择:ServletOutputStream for bytes, or a PrintWriter for character data.

// printing text data to a character stream
PrintWriter writer = response.getWriter();
writer.println("some text and HTML");
// write anything alse!
ServletOutputStream out = response.getOutputStream();
out.write(aByteArray);

注意 write() to an ServletOutputStream ; printIn() to a PrintWriter
getOutputStream()getWriter() 也要记住。

区分并熟记:

  • response.setHeader(“foo”,“bar”); // 如果同名已经存在则替换,否则添加
  • response.setIntHeader(“foo”,“bar”);// 如果同名已经存在则替换,否则添加
  • response.addHeader(“foo”,“bar”);// 新增 header 及其 value,或为已经存在的header增加额外的 value

setHeader() overwrites the existing value.
addHeader() adds an additional value.

setContentType(“text/html”) equels to setHeader(“content-type”,“text/html”),后者如果"content-type"拼错了,将会添加进一个新的不应该存在的header,造成错误。

HttpServletResponse-转发和重定向

有些时候并不想自己来处理 response

要么 redirect 到一个全新的 URL,要么 dispatch the request 给 web app 的另一个组件(典型的是一个 JSP)。

Servlet redirect makes the browser do the work.
if (workForMe) {//handle the request
} else {response.sendRedirect("http://www.oreilly.com");
}

Using relative URLs in sendRedirect()
可以用相对路径,也可以用绝对路径。使用相对地址时,容器会自动构造完成的URL。如:
用户访问:http://www.wickedlysmart.com/myApp/cool/bar.do
重定向:sendRedirect("foo/stuff.html")
容器构造完整URL(HTTP response 的 “location” header 要用):http://www.wickedlysmart.com/myApp/cool/foo/stuff.html (有 /cool)

注:the container knows the original request URL started from the “myApp/cool” path, so if you don’t use a forward slash, that part of the path is prepended to the front of “foo/stuff.html”.
容器知道从“myApp / cool”路径开始的原始请求URL,因此如果您不使用正斜杠,则路径的该部分将被添加到“foo / stuff.html”的前面。

但重定向相对路径开头如果加了正斜杠:sendRedirect("/foo/stuff.html")
容器构造相对于 web app 本身,而非相对于请求原来的URL的完整URL:http://www.wickedlysmart.com/myApp/foo/stuff.html (没有 /cool)

注:The forward slash at the beginning means “relative to the root of this web app”(in this case: “myApp”) 开头的正斜杠表示“相对于此Web应用程序的根目录”(在本例中为“myApp”)

sendRedirect() takes a String NOT a URL object!
典型错误:

sendRedirect(new URL("http://www.oreilly.com"));

如果字符串不能正确构造,会 sendRedirect() 会扔出 IllegalStateException.

不可能在 response 已经 commit 之后调用 sendRedirect(aStringURL),即如果已经开始往流里写东西,重定向就迟了。

A request dispatch does the work on the server side

redirect = client,(URL 改变)
request dispatch = server.(URL 不变)

P144 测试
1.B
2.C
3.D
4.B
5.B
6.B
7.B
8.A/B/D/E B
9.A/B/C/D A/B/C
10.D

正确率80%

8 题错误原因:审题不清
9题错误愿意:as opposed to 与之相反与之对应,审题不清。知识漏洞,流 并非HTTP 独有。

Hea First ServletJSP 4.request And response相关推荐

  1. SpringMvc4中获取request、response对象的方法

    springMVC4中获取request和response对象有以下两种简单易用的方法: 1.在control层获取 在control层中获取HttpServletRequest和HttpServle ...

  2. 简单了解request与response

    本文对 request. response 简单描述,未涉及到具体的浏览器缓存.重定向.请求转发等代码部分. 一.Web服务器,浏览器,代理服务器 在看 response.request 对象之前,先 ...

  3. request 和response

    当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, JSP,Perl, AJAX 等等. 无论Web技术在未来如何发展,理解Web程序之间通信的基本协议相当重要, 因为它让我们理解了We ...

  4. Struts2中action获取request、response、session的方式

    2019独角兽企业重金招聘Python工程师标准>>> 第一种方式,非IoC(Spring中的控制反转)方式: package com.action; import java.uti ...

  5. request和response一览

    1.HTTP SERVLETRESPONSE简介 set heade set int head set data head add haed add int head add int head 字节流 ...

  6. Spring MVC中处理Request和Response的策略

    前沿技术早知道,弯道超车有希望 积累超车资本,从关注DD开始 作者:码农小胖哥, 图文编辑:xj 来源:https://mp.weixin.qq.com/s/3eFygsiVl8dC2nRy8_8n5 ...

  7. request、response 中文乱码问题与解决方式

    request.response 中文乱码问题与解决方式 request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码: response乱码指的是:服务器向 ...

  8. ASP.NET之Request和Response对象

    经过了牛腩新闻公布系统和html的学习对B/S开发的流程有了些理解.前面尽管用到了非常多知识.但对制作网页仅仅能说知其然.当学到asp.net视频中的解说才干够说開始知其所以然了. 今天来说说clie ...

  9. error response from daemon_Scrapy 框架-模拟登录-Request、Response

    1. Scrapy-Request和Response(请求和响应) Scrapy的Request和Response对象用于爬网网站. 通常,Request对象在爬虫程序中生成并传递到系统,直到它们到达 ...

最新文章

  1. 【Java源码分析】Vector源码分析
  2. 元宇宙iwemeta: 北交所开创,资本市场服务创新型中小企业掀开新篇章,上市企业小盘点
  3. linux rar工具
  4. Linux下让进程在后台可靠运行的几种方法
  5. 声学漫谈之五:音腔是怎么影响声音效果的
  6. vue 安装php,vue中使用openinstall
  7. java游戏猿人时代_学习java编程就业前景如何
  8. 深度学习中的数据增强方法
  9. 计算机图形学上机(一)改进的DDA算法
  10. C#中使用ribbon界面
  11. matlab(1):画图像修改曲线形状
  12. Ribbon负载均衡原理,源码解读
  13. 一种将pkl转成excel的弯道[可以实现有点奇怪,以防excel显示不全]
  14. 锂电池充放电曲线、设置充电电流、检测TP4054的3种充电状态
  15. vue html 原始 模板,vue系列3--模板语法(示例代码)
  16. 巧用 Prometheus 监控 Kubernetes 集群所有组件的证书
  17. 纯js实现鼠标拖尾效果(好玩又简单,一学就会)
  18. Matlab中conj函数用法
  19. 隐藏U盘文件的病毒解决办法
  20. 蓝桥杯- 历届试题 填字母游戏

热门文章

  1. 球半足球分析,巴西甲:布拉干RB VS 博塔弗戈 7月5日
  2. 笔试题-武汉珞珈德毅笔试题
  3. android模拟器拍照图,android模拟器无法使用camera拍照
  4. 处理器博通还是高通比较好_苹果手机基带高通还是Intel好?iPhone查看基带生产商厂家方法...
  5. 输出月份英文名java_输出月份英文名 (30 分)
  6. windows installer服务坏了修复方法
  7. 基于MSP432控制的红外循迹爬坡小车设计报告
  8. PMO到底是做什么的
  9. Java项目:教师资格证报名系统(java+SpringBoot+vue+maven+mysql+elementui)
  10. Python数据分析和django建站一般使用工具