2021年4月Java WEB

Java WEB

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用


提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:
前言
Java Web 其实就是一个技术的总和,把Web看成一个容器。主要使用JavaEE技术来实现,再加上各种中间件。整个javaWeb阶段的内容通过实际的案例贯穿学习, 所涉及到的技术知识点会在案例中根据不同的需求引入。首先了解javaWEB的整个技术体系,掌握常用的技术知识点。
在这里插入图片描述
Web服务器

  1. Web服务器主要用来接收客户端发送的请求和响应客户端请求。
  2. Tomcat(Apache) ( 我们主要撸这只猫 ):当前应用最广的JavaWeb服务器;
  3. JBoss(Redhat红帽):支持JavaEE,应用比较广EJB容器 –> SSH轻量级的框架代替
  4. GlassFish(Orcale):Oracle开发JavaWeb服务器,应用不是很广;
  5. Resin(Caucho):支持JavaEE,应用越来越广;
  6. Weblogic(Orcale):要钱的!支持JavaEE,适合大型项目;
  7. Websphere(IBM):要钱的!支持JavaEE,适合大型项目。

提示:以下是本篇文章正文内容,下面案例可供参考

一、Tomcat

Tomcat7 的目录结构如图:

1、bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个exe文件:tomcat6.exe、tomcat6w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要先配置JAVA_HOME环境变量才能启动,shutdawn.bat用来停止Tomcat;
2、conf:这是一个非常非常重要的目录,这个目录下有四个最为重要的文件:
server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等;
tomcatusers.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面了;
web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗口才对。MIME就是用来说明文档的内容是什么类型的!
context.xml:对所有应用的统一配置,通常我们不会去配置它。
3、lib:**Tomcat的类库,里面是一大堆jar文件。**如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的Jar包放到这个目录下;
4、logs:这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件。
5、temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除!
6、webapps:存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的。项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。
7、work:运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。
8、LICENSE:许可证。
9、NOTICE:说明文件。

WEB资源静态和动态
在http协议当中,规定了请求和响应双方,客户端和服务器端。与web相关的资源。

有两种分类
静态资源html,js,css
动态资源servlet,jsp

1.静态资源和动态资源的概念
简单来说:
静态资源:一般客户端发送请求到web服务器,web服务器从内存在取到相应的文件,返回给客户端,客户端解析并渲染显示出来。
动态资源:一般客户端请求的动态资源,先将请求交于web容器,web容器连接数据库,数据库处理数据之后,将内容交给web服务器,web服务器返回给客户端解析渲染处理。

2.静态资源和动态资源的区别
a.静态资源一般都是设计好的html页面,而动态资源依靠设计好的程序来实现按照需求的动态响应;
b.静态资源的交互性差,动态资源可以根据需求自由实现;
c.在服务器的运行状态不同,静态资源不需要与数据库参于程序处理,动态可能需要多个数据库的参与运算。

动态WEB资源目录结构
website
|—根路径下放—静态页面(HTML、CSS、JS、图片)
|------JSP页面
|------WEB-INF
|-----web.xml (必须的,需要用的一些相关配置文件)
|-----classes (可选的,java类编写成class文件)
|-----lib (可选的,第三方的需要用的jar包,数据库的连接)

1.项目发布方式

方法一:
用eclipse集成的tomcat发布,或者将项目文件中的webroot中文件复制粘贴,放置在tomcat中webapps中新建的文件(将来路径名)里。使用eclipse时项目文件没有webroot只有webcontent的需要将webcontent在eclipse中修改设置为webroot,或者将webcontent中的除META-INF以及build文件中classes文件粘贴于新建文件,即可发布。

方法二:
用eclipse将项目导出war到webapps中,将conf中server.xml中host属性Appbase修改为webapps,unpackwar属性为true,autoDeploy="true"即可自动解压部署

方法三 :
将webroot或者webcontent和build中classes文件复制粘贴到一文件中,在server.xml文件中host节点下添加其中ROOT是虚拟路径(网址中一部分localhost:8080/ROOT),docbase是项目真实路径。

方法四:
在conf目录下创建Catalina目录,在此目录下新建localhost目录,
在localhost目录下新建bb.xml,内容为:

不需要写path, 虚拟目录就是文件名bb,path默认为/bb,添加bb.xml不需要重启tomcat服务器

Tomcat Server处理一个HTTP请求的过程
1、用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得。
2、Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应。
3、Engine获得请求localhost/test/index.jsp,匹配所有的虚拟主机Host。
4、Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机),名为localhost的Host获得请求/test/index.jsp,匹配它所拥有的所有的Context。Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为“ ”的Context去处理)。
5、path=“/test”的Context获得请求/index.jsp,在它的mapping table中寻找出对应的Servlet。Context匹配到URL PATTERN为*.jsp的Servlet,对应于JspServlet类。
6、构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet()或doPost().执行业务逻辑、数据存储等程序。
7、Context把执行完之后的HttpServletResponse对象返回给Host。
8、Host把HttpServletResponse对象返回给Engine。
9、Engine把HttpServletResponse对象返回Connector。
10、Connector把HttpServletResponse对象返回给客户Browser。

二、HTTP

1.HTTP1.0和HTTP1.1和HTTP2.0的区别

1.1 长连接(Persistent Connection)

   HTTP1.1支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启长连接keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。HTTP1.0需要使用keep-alive参数来告知服务器端要建立一个长连接。

1.2 节约带宽

   HTTP1.0中存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能。HTTP1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,客户端接收到100才开始把请求body发送到服务器;如果返回401,客户端就可以不用发送请求body了节约了带宽。

1.3 HOST域

   在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname),HTTP1.0没有host域。随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都支持host域,且请求消息中如果没有host域会报告一个错误(400 Bad Request)。

1.4缓存处理

   在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。

1.5错误通知的管理

   在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。

2 HTTP1.1和HTTP2.0的区别

2.1 多路复用

   HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。

2.2 头部数据压缩

   在HTTP1.1中,HTTP请求和响应都是由状态行、请求/响应头部、消息主体三部分组成。一般而言,消息主体都会经过gzip压缩,或者本身传输的就是压缩过后的二进制文件,但状态行和头部却没有经过任何压缩,直接以纯文本传输。随着Web功能越来越复杂,每个页面产生的请求数也越来越多,导致消耗在头部的流量越来越多,尤其是每次都要传输UserAgent、Cookie这类不会频繁变动的内容,完全是一种浪费。

   HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

2.3 服务器推送

   服务端推送是一种在客户端请求之前发送数据的机制。网页使用了许多资源:HTML、样式表、脚本、图片等等。在HTTP1.1中这些资源每一个都必须明确地请求。这是一个很慢的过程。浏览器从获取HTML开始,然后在它解析和评估页面的时候,增量地获取更多的资源。因为服务器必须等待浏览器做每一个请求,网络经常是空闲的和未充分使用的。

   为了改善延迟,HTTP2.0引入了server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前,免得客户端再次创建连接发送请求到服务器端获取。这样客户端可以直接从本地加载这些资源,不用再通过网络。

3. Http请求和Http响应

HTTP请求信息由3部分组成:

1、请求方法(GET/POST)、URI、协议/版本
2、请求头(Request Header)
3、请求正文

POST http://xg.mediportal.com.cn/health/sms/verify/telephone HTTP/1.1

User-Agent: DGroupPatient/1.052701.230/Dalvik/2.1.0 (Linux; U; Android 5.1.1; KIW-AL10 Build/HONORKIW-AL10)
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: xg.mediportal.com.cn
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 33

telephone=15527177736&userType=1&

(1)请求方法、URI、协议/版本
请求的第一行是“方法、URL、协议/版本”:
POST http://xg.mediportal.com.cn/health/sms/verify/telephone HTTP/1.1

以上代码中“POST”代表请求方法,“http://xg.mediportal.com.cn/health/sms/verify/telephone”表示URI,“HTTP/1.1代表协议和协议的版本。
根据HTTP标准,HTTP请求可以使用多种请求方法。例如:HTTP1.1目前支持7种请求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。

GET
请求获取由Request-URI所标识的资源

POST
在Request-URI所标识的资源后附加新的数据

HEAD
请求获取由Request-URI所标识的资源的响应消息报头

OPTIONS
请求查询服务器的性能,或查询与资源相关的选项和需求

PUT
请求服务器存储一个资源,并用Request-URI作为其标识

DELETE
请求服务器删除由Request-URI所标识的资源

TRACE
请求服务器回送收到的请求信息,主要用语测试或诊断
在Internet应用中,最常用的方法是GET和POST。最后,协议版本声明了通信过程中使用HTTP的版本。

(2)请求头(Request Header)
请求头包含许多有关的客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器所用的语言,请求正文的长度等。

User-Agent: DGroupPatient/1.052701.230/Dalvik/2.1.0 (Linux; U; Android 5.1.1; KIW-AL10 Build/HONORKIW-AL10) //用户发送请求的客户端环境
Content-Type: application/x-www-form-urlencoded; charset=UTF-8 //表单默认的提交数据的格式
Host: xg.mediportal.com.cn //请求资源的Intenet主机和端口号
Connection: Keep-Alive //持久连接
Accept-Encoding: gzip //浏览器能够进行解码的数据编码方式
Content-Length: 33 //请求正文的长度

Content-Type
是返回消息中非常重要的内容,表示后面的文档属于什么MIME类型。Content-Type: [type]/[subtype]; parameter。例如最常见的就是text/html,它的意思是说返回的内容是文本类型,这个文本又是HTML格式的。原则上浏览器会根据Content-Type来决定如何显示返回的消息体内容

Host
指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回

Accept
浏览器可接受的MIME类型

Accept-Charset
浏览器可接受的字符集

Accept-Encoding
浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间

Accept-Language
浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到

Authorization
授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中

Connection
表示是否需要持久连接。如果Servlet看到这里的值为“Keep- Alive”,或者看到请求使用的是HTTP1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入 ByteArrayOutputStream,然后在正式写出内容之前计算它的大小

Content-Length
表示请求消息正文的长度

Cookie
这是最重要的请求头信息之一

From
请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它

Host
初始URL中的主机和端口

If-Modified-Since
只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答

Pragma
指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝

Referer
包含一个URL,用户从该URL代表的页面出发访问当前请求的页面

User-Agent
浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用

UA-Pixels,UA-Color,UA-OS,UA-CPU
由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型

常见的MIME类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:

application/xhtml+xml :XHTML格式
application/xml : XML数据格式
application/atom+xml :Atom XML聚合格式
application/json : JSON数据格式
application/pdf :pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:

multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

(3)请求正文
请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的查询字符串信息:
telephone=15527177736&userType=1&

http响应格式

HTTP应答与HTTP请求相似,HTTP响应也由3个部分构成,分别是:

1、状态行
2、响应头(Response Header)
3、响应正文

HTTP/1.1 200 OK //状态行
Server: nginx
Date: Tue, 31 May 2016 02:09:24 GMT
Content-Type: application/json;charset=UTF-8
Connection: keep-alive
Vary: Accept-Encoding
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: X-Requested-With,access_token,access-token,content-type,multipart/form-data,application/x-www-form-urlencoded
Access-Control-Allow-Methods: GET,POST,OPTIONS
Content-Length: 49

{“resultCode”:1,“resultMsg”:“手机号未注册”} //正文

(1)状态行
由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
状态代码:
状态代码由3位数字组成,表示请求是否被理解或被满足。
状态描述:状态描述给出了关于状态代码的简短的文字描述。
状态代码的第一个数字定义了响应的类别,后面两位没有具体的分类。

第一个数字有五种可能的取值:

  • 1xx: 指示信息—表示请求已接收,继续处理。

  • 2xx: 成功—表示请求已经被成功接收、理解、接受。

  • 3xx: 重定向—要完成请求必须进行更进一步的操作。

  • 4xx: 客户端错误—请求有语法错误或请求无法实现。

  • 5xx: 服务器端错误—服务器未能实现合法的请求。
    状态代码 状态描述 说明

    200 OK 客户端请求成功
    304 需要查找本地缓存
    400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
    401 Unauthonzed 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
    403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
    404 Not Found 请求的资源不存在,例如,输入了错误的URL。
    500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
    503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常

(2)响应头
响应头可能包括:
Location:
Location响应报头域用于重定向接受者到一个新的位置。例如:客户端所请求的页面已不存在原先的位置,为了让客户端重定向到这个页面新的位置,服务 器端可以发回Location响应报头后使用重定向语句,让客户端去访问新的域名所对应的服务器上的资源。当我们在JSP中使用重定向语句的时候,服务器 端向客户端发回的响应报头中,就会有Location响应报头域。

Server:
Server响应报头域包含了服务器用来处理请求的软件信息。它和User-Agent请求报头域是相对应的,前者发送服务器端软件的信息,后者发送客户 端软件(浏览器)和操作系统的信息。下面是Server响应报头域的一个例子:Server: Apache-Coyote/1.1

WWW-Authenticate:
WWW-Authenticate响应报头域必须被包含在401(未授权的)响应消息中,这个报头域和前面讲到的Authorization请求报头域是 相关的,当客户端收到401响应消息,就要决定是否请求服务器对其进行验证。如果要求服务器对其进行验证,就可以发送一个包含了 Authorization报头域的请求,下面是WWW-Authenticate响应报头域的一个例子:WWW-Authenticate: Basic realm=“Basic Auth Test!”

从这个响应报头域,可以知道服务器端对我们所请求的资源采用的是基本验证机制。

Content-Encoding:
Content-Encoding实体报头域被使用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容编码,因而要获得Content- Type报头域中所引用的媒体类型,必须采用相应的解码机制。Content-Encoding主要用语记录文档的压缩方法,下面是它的一个例子: Content-Encoding: gzip。如果一个实体正文采用了编码方式存储,在使用之前就必须进行解码。

Content-Language:
Content-Language实体报头域描述了资源所用的自然语言。Content-Language允许用户遵照自身的首选语言来识别和区分实体。 如果这个实体内容仅仅打算提供给丹麦的阅读者,那么可以按照如下的方式设置这个实体报头域:Content-Language: da。

如果没有指定Content-Language报头域,那么实体内容将提供给所以语言的阅读者。

Content-Length:
Content-Length实体报头域用于指明正文的长度,以字节方式存储的十进制数字来表示,也就是一个数字字符占一个字节,用其对应的ASCII码存储传输。

   要注意的是:这个长度仅仅是表示实体正文的长度,没有包括实体报头的长度。

Content-Type :
Content-Type实体报头域用语指明发送给接收者的实体正文的媒体类型。例如:

Content-Type: text/html;charset=ISO-8859-1
Content-Type: text/html;charset=GB2312

Last-Modified :
Last-Modified实体报头域用于指示资源最后的修改日期及时间。

Expires :
Epires实体报头域给出响应过期的日期和时间。通常,代理服务器或浏览器会缓存一些页面。当用户再次访问这些页面时,直接从缓存中加载并显示给用 户,这样缩短了响应的时间,减少服务器的负载。为了让代理服务器或浏览器在一段时间后更新页面,我们可以使用Expires实体报头域指定页面过期的时 间。当用户又一次访问页面时,如果Expires报头域给出的日期和时间比Date普通报头域给出的日期和时间要早(或相同),那么代理服务器或浏览器就 不会再使用缓存的页面而是从服务器上请求更新的页面。不过要注意,即使页面过期了,也并不意味着服务器上的原始资源在此时间之前或之后发生了改变。
Expires实体报头域使用的日期和时间必须是RFC 1123中的日期格式,例如:

Expires: Thu, 15 Sep 2005 16:00:00 GMT
HTTP1.1的客户端和缓存必须将其他非法的日期格式(也包括0)看作已过期。例如,为了让浏览器不要缓存页面,我们也可以利用Expires实体报头 域,设置它的值为0,如下(JSP):response.setDateHeader(“Expires”,0);

4.servlet

会话范围(HttpSession)

何时创建和销毁的

创建:当第一次调用getSession()方法的时候。
销毁:三种情况
①Session过期,默认的过期时间30分钟(web.xml中配置)
②非正常关闭服务器。(正常关闭服务器session会被序列化)
③手动调用 session.invalidate()方法
如何存取数据

存数据:void setAttribute(String name, Object value);
取数据:Object getAttribute(String name);
作用范围

作用范围:一次会话(多次请求)

应用范围(ServletContext)
何时创建和销毁
创建:服务器启动时就创建,为每个web项目创建一个单独的ServletContext对象。
销毁:服务器关闭或者是项目从服务器移除的时候。
如何存取数据
存数据:void setAttribute(String name, Object value);
取数据:Object getAttribute(String name);
作用范围
作用范围:整个应用

Servlet的生命周期

servlet的生命周期就是从servlet出现到销毁的全过程。主要分为以下几个阶段:
加载类—>实例化(为对象分配空间)—>初始化(为对象的属性赋值)—>请求处理(服务阶段)—>销毁

服务器启动时(web.xml中配置load-on-startup=1,默认为0)或者第一次请求该servlet时,就会初始化一个Servlet对象,也就是会执行初始化方法init(ServletConfig conf),该servlet对象去处理所有客户端请求,service(ServletRequest req,ServletResponse res)方法中执行,最后服务器关闭时,才会销毁这个servlet对象,执行destroy()方法。其中加载阶段无法观察,但是初始化、服务、销毁阶段是可以观察到的。

总结:
Servlet的生命周期分为:加载阶段、实例化阶段、初始化阶段、服务阶段、销毁阶段。上面我们说了servlet默认是第一次被访问的时候初始化的,这种情况当用户要使用的时候才创建,也可以在服务器一启动的时候就创建好servlet(这种方式一般不用),要实现这样的操作需要进行配置,在web.xml中进行配置
什么是Servlet启动时加载
Servlet默认是在第一次访问的时候创建的对象。
Servlet启动时加载, 就是让(Tomcat)服务器启动的时候创建Servlet的对象

为什么需要启动时加载

Servlet对象是第一次被访问的时候会被创建的,init方法就会执行。

假设在init方法中做了一些比较耗时的操作(比如:加载了一些配置文件并且解析可能需要花费3秒钟)。那么,第一次访问这个Servlet的时候,需要等待3秒钟。我们通过配置Servlet启动时加载就可以避免第一次访问Servlet时,等待3秒了。

web.xm配置完成启动时加载
配置Servlet启动时加载,需要修改web.xml文件,格式如下,配置后,Tomcat服务器启动的时候会完成Servlet对象创建,在servlet的标签里面配置

<servlet>
    <servlet-name>life</servlet-name>
    <servlet-class>com.itheima.servlet.LifeServlet</servlet-class>
    <!--配置启动时加载 因为同时会有多个Servlet需要被启动时加载,然后配置的值用来设定这些Servlet的先后关系,里面的数字越小加载的优先级越高-->
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>life</servlet-name>
    <url-pattern>/life</url-pattern>
</servlet-mapping>

ServletContext

提两个问题:
1.大家在访问某个网站的时候,往往都会看到网站的首页面显示您是第几位浏览者(网站计数器),这是怎么实现的?
2.我们在访问某个bbs网站的时候,往往会显示有多少人在线,这是怎么实现的?

可能我们会想到的常规实现思路:数据库或者文件。这种做法比较简单,但是却会对数据库或者文件访问过于频繁,开销比较大。

解决之道是用ServletContext

一、获取web项目信息

(1) 如何得到ServletContext对象

this.getServletContext();
this.getServletConfig().getServletContext();

(2) 你可以把它想象成一张表,这个和Session非常相似:每一行就是一个属性,如下:
名字(String) 值(Object)
添加属性:setAttribute(String name, Object obj);
得到值:getAttribute(String name),这个方法返回Object
删除属性:removeAttribute(String name)
(3) 生命周期
ServletContext中的属性的生命周期从创建开始,到服务器关闭结束。

一个快速入门的案例:
我们创建Servlet1和Servlet2,Servlet1用于在ServletContext中创建属性,Servlet2用于从ServletContext读取属性:
Servlet1的doGet方法为:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    
    
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    // 获取ServletContext对象的引用
    // 第一种方法
    ServletContext servletContext = this.getServletContext();
    // 第二种方法
    // ServletContext servletContext2 = this.getServletConfig().getServletContext();
    servletContext.setAttribute("name", "小明");
    out.println("将 name=小明  写入了ServletContext");
}

Servlet2的doGet方法为:

public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    
    
    response.setContentType("text/html;charset=utf-8");
    PrintWriter out = response.getWriter();
    // 取出ServletContext的某个属性
    //1.首先获取到ServletContext
    ServletContext servletContext = this.getServletContext();
    //2.取出属性
    String name = (String)servletContext.getAttribute("name");
    out.println("name="+name);
}

二、读取web项目下的文件(路径不能使用相对路径)

利用ServletContext对象读取资源文件(比如properties文件)
读取资源文件要根据资源文件所在的位置分为两种情况:

(1)文件在WebRoot文件夹下,即我们的Web应用的根目录下。这时候我们可以使用ServletContext来读取该资源文件。

假设我们Web根目录下有一个配置数据库信息的dbinfo.properties文件,里面配置了name和password属性,这时候可以通过ServletContext去读取这个文件:

// 这种方法的默认读取路径就是Web应用的根目录
InputStream stream = this.getServletContext().getResourceAsStream("dbinfo.properties");
// 创建属性对象
Properties properties = new Properties();
properties.load(stream);
String name = properties.getProperty("name");
String password = properties.getProperty("password");
out.println("name="+name+";password="+password);

(2)但是如果这个文件放在了src目录下,通过ServletContext是读不到的,必须要使用类加载器去读取。

// 类加载器的默认读取路径是src根目录
InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("dbinfo.properties")

但是如果这个文件此时还没有直接在src目录下,而是在src目录下的某个包下,比如在com.gavin包下,此时类加载器要加上包的路径,如下:

InputStream stream = MyServlet.class.getClassLoader().getResourceAsStream("com/gavin/dbinfo.properties")

另外,补充一点,ServletContext可以获取文件的全路径,当然这个也是在Web应用根目录下的文件。比如我们在WebRoot文件夹下有一个images文件夹,images文件夹下有一个Servlet.jpg图片,为了得到这个图片的全路径,如下:

// 如何读取到一个文件的全路径,这里会得到在Tomcat的全路径
String path = this.getServletContext().getRealPath("/images/Servlet.jpg");

5.Response对象

响应行
设置响应状态码setStatus(302);
还有一种快捷的重定向方法,即使用response.sendRedirect()方法。比如上面例子中的两句可以使用response.sendRedirect(“http://www.baidu.com”)代替。
响应头
set开头针对一个key对应一个value
setHeader(“Content-Type”,”text/html;charset=utf-8”);
setContentType(”text/html;charset=utf-8”);
add开头针对一个key对应多个value
响应体
getWriter().write(String):响应字符串
getOutputStream().write(byte[]):响应二进制,(文件下载)

Response对象响应中文

使用字节流响应中文
getbyte
使用上述代码向页面输出中文是否会有乱码?
不一定,其实这个乱码的产生与中文转成字节数组及浏览器打开方式(打开的时候采用的默认字符集)有关
解决:将中文转成字节数组的时候和浏览器默认打开的时候采用的字符集一致即可。

使用字符流响应中文
使用上述代码向页面输出中文是否会产生乱码?
一定乱码
原因:字符流是有缓冲区的,response获得字符流,response设计默认的缓冲区编码是ISO-8859-1。这个字符集不支持中文的。
解决:设置response获得字符流缓冲区的编码和设置浏览器默认打开时候采用的字符集一致即可。

request—封装了客户端所有的请求数据

6.request

1、request概述

request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。

request的功能可以分为以下几种:
(1)封装了请求头数据;
(2)封装了请求正文数据,如果是GET请求,那么就没有正文;
(3)request是一个域对象,可以把它当成Map来添加获取数据;
(4)request提供了请求转发和请求包含功能。

2、request域方法

request是域对象!在JavaWeb中一共四个域对象,其中ServletContext就是域对象,它在整个应用中只创建一个ServletContext对象。request其中一个,request可以在一个请求中共享数据。

一个请求会创建一个request对象,如果在一个请求中经历了多个Servlet,那么多个Servlet就可以使用request来共享数据。现在我们还不知道如何在一个请求中经历几个Servlet。

下面是request的域方法:
(1)void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute(“xxx”, “XXX”),在request中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;
(2)Object getAttribute(String name):用来获取request中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)request.getAttribute(“xxx”);,获取名为xxx的域属性;
(3)void removeAttribute(String name):用来移除request中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;
(4)Enumeration getAttributeNames():获取所有域属性的名称;

3、request获取请求头数据

request与请求头相关的方法有:
String getHeader(String name):获取指定名称的请求头;
Enumeration getHeaderNames():获取所有请求头名称;
int getIntHeader(String name):获取值为int类型的请求头。

4 request获取请求相关的其它方法

request中还提供了与请求相关的其他方法,有些方法是为了我们更加便捷的方法请求头数据而设计,有些是与请求URL相关的方法。
 int getContentLength():获取请求体的字节数,GET请求没有请求体,没有请求体返回-1;
 String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x- www-form-urlencoded,表示请求体内容使用了URL编码;
 String getMethod():返回请求方法,例如:GET
 Locale getLocale():返回当前客户端浏览器的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;
 String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null,表示使用ISO-8859-1编码;
 void setCharacterEncoding(String code):设置请求编码,只对请求体有效!注意,对于GET而言,没有请求体!!!所以此方法只能对POST请求中的参数有效!
 String getContextPath():返回上下文路径,例如:/hello
 String getQueryString():返回请求URL中的参数,例如:name=zhangSan
 String getRequestURI():返回请求URI路径,例如:/hello/oneServlet
 StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;
 String getServletPath():返回Servlet路径,例如:/oneServlet
 String getRemoteAddr():返回当前客户端的IP地址;
 String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;
 String getScheme():返回请求协议,例如:http;
 String getServerName():返回主机名,例如:localhost
 int getServerPort():返回服务器端口号,例如:8080

5 request获取请求参数

最为常见的客户端传递参数方式有两种:
浏览器地址栏直接输入:一定是GET请求;
超链接:一定是GET请求;
表单:可以是GET,也可以是POST,这取决与的method属性值

GET请求和POST请求的区别:

GET请求:
请求参数会在浏览器的地址栏中显示,所以不安全;
请求参数长度限制长度在1K之内;
GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码;

POST请求:
请求参数不会显示浏览器的地址栏,相对安全;
请求参数长度没有限制;

下面是使用request获取请求参数的API:
l String getParameter(String name):通过指定名称获取参数值;
l String[] getParameterValues(String name):当多个参数名称相同时,可以使用方法来获取;
l Enumeration getParameterNames():获取所有参数的名字;
l Map getParameterMap():获取所有参数封装到Map中,其中key为参数名,value为参数值,因为一个参数名称可能有多个值,所以参数值是String[],而不是String。

6、请求转发和请求包含(重点

无论是请求转发还是请求包含,都表示由多个Servlet共同来处理一个请求。例如Servlet1来处理请求,然后Servlet1又转发给Servlet2来继续处理这个请求。

请求转发和请求包含
RequestDispatcher rd = request.getRequestDispatcher("/MyServlet"); 使用request获取RequestDispatcher对象,方法的参数是被转发或包含的Servlet的Servlet路径
请求转发:rd.forward(request,response);
请求包含:rd.include(request,response);

有时一个请求需要多个Servlet协作才能完成,所以需要在一个Servlet跳到另一个Servlet!
> 一个请求跨多个Servlet,需要使用转发和包含。
 > 请求转发:由下一个Servlet完成响应体!当前Servlet可以设置响应头!(留头不留体)

即当前Servlet设置的相应头有效,相应体无效。
> 请求包含:由两个Servlet共同未完成响应体!(留头又留体) 都有效。
> 无论是请求转发还是请求包含,都在一个请求范围内!使用同一个request和response!

请求转发与请求包含比较:
(1)如果在AServlet中请求转发到BServlet,那么在AServlet中就不允许再输出响应体,即不能再使用response.getWriter()和response.getOutputStream()向客户端输出,这一工作应该由BServlet来完成;如果是使用请求包含,那么没有这个限制;
(2)请求转发虽然不能输出响应体,但还是可以设置响应头的,例如:response.setContentType(”text/html;charset=utf-8”);
(3)请求包含大多是应用在JSP页面中,完成多页面的合并;
(4)请求转发大多是应用在Servlet中,转发目标大多是JSP页面;

请求转发与重定向比较
(1)请求转发是一个请求,而重定向是两个请求;
(2)请求转发后浏览器地址栏不会有变化,而重定向会有变化,因为重定向是两个请求;
(3)请求转发的目标只能是本应用中的资源,重定向的目标可以是其他应用;
(4)请求转发对AServlet和BServlet的请求方法是相同的,即要么都是GET,要么都是POST,因为请求转发是一个请求;
(5)重定向的第二个请求一定是GET;

POST方式接收中文(重点)因为表单一般都是用post来发送请求的

/**
* 产生乱码的原因:
* post方式提交的数据是在请求体中,request对象接收到数据之后,放入request的缓冲区中。缓冲区就有编码(默认ISO-8859-1:不支持中文).
* 解决方案:
* * 将request的缓冲区的编码修改了即可。
* request.setCharacterEncoding("UTF-8");
*/
 接收数据:
// request.setCharacterEncoding("UTF-8");

GET方式接收中文

/**
 * 产生乱码原因:
 * * get方式提交的数据在请求行的url后面,地址栏上其实就已经进行一次URL的编码了。
 * 解决方案:
 * 将存入到request缓冲区中的值以ISO-8859-1的方式获取到,以UTF-8的方式进行解码。
 */   

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

猜你喜欢

转载自blog.csdn.net/weixin_44177643/article/details/115081778