Servlet
次要内容
—-IDEA 的装置与应用
IDEA 全称 IntelliJ IDEA,由 JetBrains 公司开发,是 java 编程语言开发的集成环境。在业界被公认为最好的 java 开发工具,尤其在智能代码助手、代码主动提醒、重构、J2EE 反对、各类版本工具(git、svn 等)、JUnit、CVS 整合、代码剖析、翻新的 GUI 设计等方面的性能能够说是超常的。
IDEA 的特色性能
- 智能选取
- 丰盛的导航模式
- 历史记录性能
- 编码辅助
- 灵便的排版性能
- 代码查看
- 完满的主动代码实现
- 版本控制的反对
…
IDEA 的下载
- 在浏览器中 IntelliJ IDEA 百度一下,关上如下官网
- 进入官网,单击 DOWNLOAD
- 抉择指定版本,点击 DOWNLOAD
- 点击保留,进行下载
- 下载之后的文件
IDEA 的装置
- 双击运行安装程序,点击“Next”下一步
- 批改装置门路(也可应用默认门路),点击 “Next”
- 依据本人电脑的操作系统,来进行相应的抉择
- 默认即可,间接抉择“Install”,进行装置
- 装置胜利,可抉择运行 IDEA,点击“Finish”实现装置
- 若之前装置过其余版本的 IDEA,会提醒是否导入原来的配置(抉择不导入即可)
- 抉择本人喜爱的主题,而后始终抉择“Next”。
- 抉择 “Activation code” 形式,输出激活码,点击“OK”
- 呈现如下画面,则示意激活胜利
IDEA 创立我的项目
创立 Java 我的项目
- 点击“Create New Project”
- 增加新的 JDK 版本(idea 默认应用自带的版本)
- 抉择 JDK 版本,而后“Next”
- 抉择“Next”
- 设置项目名称及工作空间
- 我的项目目录构造及提示信息(提示信息可抉择 ”Close”)
创立 Java 类
- 点击“src”—>“new”—>“package”,创立一个文件包
- 设置包名,与 Eclipse 的包相似
- 在包上面创立 Java 类文件,点击包名 —>“New”—>“Java Class”
- 抉择类型,并设置类的名称
- 在类中写一个 main 办法
执行 main 办法
- 形式一:代码左侧的绿色三角符号
- 形式二:在类中右键,抉择 Run 或 Debug
- 形式三:点击最上方菜单栏的 Run
呈现以下弹框,点击要运行的文件名,这里是 Hello
- 运行后果
IDEA 的根本设置
应用 IDEA 时,能够对它进行一些简略的设置,通过设置用户的偏好设置,可进步使用者的体验感。
进入设置页面
- 抉择右下角的“Configure”,抉择 ”Settings”(或在 IDEA 中,抉择左上角的“File”,抉择 ”Settings”)
- 进入设置页面
设置字体
- 在 Settings 窗口中,点击“Editor”—>“Color Scheme”
- 抉择“Color Scheme Font”,设置字体格调和字体大小,设置完之后抉择“Apply”利用
- 设置中文字体
Idea 更新 2019.2 后
中文字体的默认成果
批改字体之后的成果
解决方案:“Editor”—>“Font”—>“Fallback font”,抉择 SimHei
设置主动保留
抉择“Appearance & Behavior”,抉择“System Settings”
设置字体编码
抉择“Editor”,抉择“File Encoding”,设置编码为“UTF-8”
设置字体大小扭转
能够通过按住“Ctrl”,滚动鼠标滚轮扭转字体大小。
抉择“Editor”,抉择“General”
设置主动编译
抉择“Build,Execution,Deployment”,抉择“Compiler”
IDEA 罕用快捷键
快捷键
作用
Alt+Insert
生成代码(如 get,set 办法,构造函数等)
Alt+↑/ ↓
在办法间疾速定位
Alt+【F3】
查找雷同文本,并高亮显示
Ctrl+B
疾速关上光标处的类或办法
Ctrl+J
主动代码(main 办法)
Ctrl+N
查找类
Ctrl+Y
删除行
Ctrl+D
复制行
Ctrl+O
重写办法
Ctrl+E
最近关上的文件
Ctrl+F
查找文本
Ctrl+R
替换文本
Ctrl+P
办法参数提醒
Ctrl+/
单行正文 //
Ctrl+Shift+/
多行正文 / /
Ctrl+Shift+N
查找文件
Ctrl+Alt+L
格式化代码
Ctrl+Shift+↑/ ↓
代码向上 / 向下挪动
Shift+F6
重构 - 重命名
HTTP 协定
HTTP 协定(Hypertext Transfer Protocol, 超文本传输协定),是一个客户端申请和响应的标准协议,这个协定具体规定了浏览器和万维网服务器之间相互通信的规定。用户输出地址和端口号之后就能够从服务器上获得所须要的网页信息。
通信规定规定了客户端发送给服务器的内容格局,也规定了服务器发送给客户端的内容格局。客户端发送给服务器的格局叫 ”申请协定 “;服务器发送给客户端的格局叫 ” 响应协定“。
在浏览器中 F12 可查看
浏览器中的书写格局
服务器端资源须要通过浏览器进行,此时由浏览器将咱们给出的申请解析为满足 HTTP 协定的格局并收回。咱们收回的申请格局须要依照浏览器规定的格局来书写,在浏览器中书写格局如下:
当浏览器获取到信息当前,依照特定格局解析并发送即可。接管到服务器端给出的响应时,也依照 HTTP 协定进行解析获取到各个数据,最初依照特定格局展现给用户。
HTTP 协定的特点
- 反对客户 / 服务器模式。
- 简略疾速:客户向服务器申请服务时,只需传送申请办法和门路。申请办法罕用的 有 GET、POST。每种办法规定了客户与服务器分割的类型不同。因为 HTTP 协定简略,使得 HTTP 服务器的程序规模小,因此通信速度很快。
- 灵便:HTTP 容许传输任意类型的数据对象。传输的类型由 Content-Type 加以标记。
- 无连贯:无连贯是示意每次连贯只解决一个申请。服务器解决完客户的申请,并收到客户的应答后,即断开连接。采纳这种形式能够节俭传输工夫。
HTTP1.1 版本后反对可继续连贯。通过这种连贯, 就有可能在建设一个 TCP 连贯后, 发送申请并失去回应,而后发送更多的申请并失去更多的回应. 通过把建设和开释 TCP 连贯的开销摊派到多个申请上,则对于每个申请而言,因为 TCP 而造成的绝对开销被大大地升高了。而且,还能够发送流水线申请, 也就是说在发送申请 1 之后的回应到来之前就能够发送申请 2. 也能够认为,一次连贯发送多个申请,由客户机确认是否敞开连贯,而服务器会认为这些申请别离来自不同的客户端。
- 无状态:HTTP 协定是无状态协定。无状态是指协定对于事务处理没有记忆能力。短少状态意味着如果后续解决须要后面的信息,则它必须重传,这样可能导致每次连贯传送 的数据量增大。另一方面,在服务器不须要先前信息时它的应答就较快。
HTTP 之 URL
HTTP(超文本传输协定)是一个基于申请与响应模式的、应用层的协定,常基于 TCP 的连贯形式,绝大多数的 Web 开发,都是构建在 HTTP 协定之上的 Web 利用。
HTTP URL (URL 是一种非凡类型的 URI,蕴含了用于查找某个资源的足够的信息)的格局 如下:
http://host[:port]/[abc_path]
http://IP(主机名 / 域名): 端口 / 拜访的资源门路
- http 示意要通过 HTTP 协定来定位网络资源;
- host 示意非法的 Internet 主机域名或 者 IP 地址;
- port 指定一个端口号,为空则应用缺省端口 80;
- abs_path 指定申请资源的 URI;如果 URL 中没有给出 abs_path,那么当它作为申请 URI 时,必须以“/”的模式给出,通常 这个工作浏览器主动帮咱们实现。
HTTP 申请
HTTP 申请由三局部组成,别离是:申请行、申请头、申请注释。
通过 chrome 浏览器,F12 —> Network 查看。
- Get 申请(没有申请体)
-
Post 申请
格局
申请行 申请头 1 申请头 2 … 申请空行 申请体
申请行以一个办法符号结尾,以空格离开,前面跟着申请的 URI 和协定的版本。
格局如下:Method Request-URI HTTP-Version CRLF
Method 示意申请办法;
Request-URI 是一个对立资源标识符;
HTTP-Version 示意请 求的 HTTP 协定版本;
CRLF 示意回车和换行;
HTTP 响应
在接管和解释申请音讯后,服务器返回一个 HTTP 响应音讯。HTTP 响应也是由三个局部组成,别离是:状态行、消息报头、响应注释。
格局
状态行
响应头 1
响应头 2
…
响应空行
响应体
音讯头
HTTP 音讯由客户端到服务器的申请和服务器到客户端的响应组成。申请音讯和响应音讯都是由开始行(对于申请音讯,开始行就是申请行,对于响应音讯,开始行就是状态行),消息报头(可选),空行(只有 CRLF 的行),音讯注释(可选)组成。
每一个报头域都是由 名字 +”:”+ 空格 + 值 组成,消息报头域的名字是大小写无关的。
申请头
申请报头容许客户端向服务器端传递申请的附加信息以及客户端本身的信息。
- Referer:该申请头指明申请从哪里来。
如果是地址栏中输出地址拜访的都没有该申请头 地址栏输出地址,通过申请能够看到,此时多了一个 Referer 的申请头,并且前面的值 为该申请从哪里收回。比方:百度竞价,只能从百度来的才有成果,否则不算; 通常用来做统计工作、防盗链。
响应头
响应报头容许服务器传递不能放在状态行中的附加响应信息,以及对于服务器的信息和 对 Request-URI 所标识的资源进行下一步拜访的信息。
-
Location:Location 响应报头域用于重定向接受者到一个新的地位。
Location 响应报头域,罕用在更换域名的时候。
response.sendRedirect("http://www.baidu.com");
-
Refresh:主动跳转(单位是秒),能够在页面通过 meta 标签实现,也可在后盾实现。
<meta http-equiv="refresh" content="3;url=http://www.baidu.com">
Tomcat 服务器
什么是 Tomcat
Tomcat 是一个合乎 JavaEE WEB 规范的最小的 WEB 容器,所有的 JSP 程序肯定要有 WEB 容器的反对能力运行,而且在给定的 WEB 容器外面都会反对事务处理操作。
Tomcat 是由 Apache 提供的(www.apache.org)提供的能够用安装版和解压版,安装版能够在服务中呈现一个 Tomcat 的服务,免装置没有,开发中应用免安装版。Tomcat 简略的说就是一个运行 Java 的网络服务器,底层是 Socket 的一个程序,它也是 JSP 和 Servlet 的一个容器。Tomcat 是 Apache 软件基金会(Apache Software Foundation)的 Jakarta 我的项目中的一个外围我的项目,由 Apache、Sun 和其余一些公司及集体共同开发而成。
因为有了 Sun 的参加和反对,最新的 Servlet 和 JSP 标准总是能在 Tomcat 中失去体现。因为 Tomcat 技术先进、性能稳固,而且收费,因此深受 Java 爱好者的青睐并失去了局部软件开发商的认可,成为目前比拟风行的 Web 应用服务器。
Tomcat 服务器是一个收费的凋谢源代码的 Web 应用服务器,属于轻量级应用服务器,在中小型零碎和并发拜访用户不是很多的场合下被广泛应用,是开发和调试 JSP 程序的首选。对于一个初学者来说,能够这样认为,当在一台机器上配置好 Apache 服务器,可利用它响应 HTML(规范通用标记语言下的一个利用)页面的拜访申请。实际上 Tomcat 局部是 Apache 服务器的扩大,但它是独立运行的,所以当你运行 tomcat 时,它实际上作为一个与 Apache 独立的过程独自运行的。
当配置正确时,Apache 为 HTML 页面服务,而 Tomcat 实际上是在运行 JSP 页面和 Servlet。另外,Tomcat 和 IIS 等 Web 服务器一样,具备解决 HTML 页面的性能,另外它还是 一个 Servlet 和 JSP 容器,独立的 Servlet 容器是 Tomcat 的默认模式。不过,Tomcat 解决动态 HTML 的能力不如 Apache 服务器。目前 Tomcat 最新版本为 9.0。
装置 Tomcat
运行 Tomcat 须要 JDK 的反对【Tomcat 会通过 JAVA_HOME 找到所须要的 JDK】。装置就是解压缩过程。启动 Tomcat,能拜访则算装置好了
- 解压 Tomcat8 的压缩包
- 解压后目录构造
- 启动 Tomcat (在 tomcat 的装置目录下的 bin 目录 应用命令行启动 tomcat)
形式一:双击脚本文件启动
形式二:应用脚本命令启动
-
服务器启动胜利
注:
-
Tomcat 默认占用端口 8080。(留神端口抵触问题)
- 如果须要应用服务器,启动胜利后,该启动窗口不要敞开。
-
- 关上浏览器,输出 http://localhost:8080/ 拜访
- 调用 shutdown 命令敞开 Tomcat 服务器
Tomcat 目录构造
- bin:启动和敞开 tomcat 的 bat 文件
- conf:配置文件 server.xml 该文件用于配置 server 相干的信息,比方 tomcat 启动的端口号,配置主机(Host);web.xml 文件配置与 web 利用(web 利用相当于一个 web 站点);tomcat-user.xml 配置用户名明码和相干权限
- lib:该目录搁置运行 tomcat 运行须要的 jar 包
- logs:寄存日志,当咱们须要查看日志的时候,能够查问信息
- webapps:搁置咱们的 web 利用
- work 工作目录:该目录用于寄存 jsp 被拜访后生成对应的 server 文件和.class 文件
IDEA 配置 Tomcat
- 抉择“Appliction Servers”,点击右侧的“+”号,抉择“Tomcat Server”
- 设置 Tomcat 的装置目录(/idea_28.png)]
设置好之后
- 配置 Tomcat 服务器实现
Servlet 的实现
Servlet 是 Server 与 Applet 的缩写,是服务端小程序的意思。应用 Java 语言编写的服务器端程序,能够像生成动静的 WEB 页,Servlet 次要运行在服务器端,并由服务器调用执行,是一种依照 Servlet 规范来开发的类。是 SUN 公司提供的一门用于开发动静 Web 资源的技术。(话中有话:要实现 web 开发,须要实现 Servlet 规范)
Servlet 实质上也是 Java 类,但要遵循 Servlet 标准进行编写,没有 main()办法,它的创立、应用、销毁都由 Servlet 容器进行治理(如 Tomcat)。(话中有话:写本人的类,不必写 main 办法,他人主动调用)
Servlet 是和 HTTP 协定是紧密联系的,其能够解决 HTTP 协定相干的所有内容。这也是 Servlet 利用宽泛的起因之一。
提供了 Servlet 性能的服务器,叫做 Servlet 容器,其常见容器有很多,如 Tomcat, Jetty, WebLogic Server, WebSphere, JBoss 等等。
创立 Web 我的项目
- 抉择“File”—>“New”—>“Project”
- 设置我的项目的相干信息,抉择“Next”
- 设置项目名称及工作空间
- web 我的项目目录构造如下
Servlet 的实现
新建类
- 点击“src”—>“new”—>“package”,创立一个文件包
- 在包上面创立 Java 类文件,点击包名 —>“New”—>“Java Class”
- 创立一个一般的 Java 类
-
如下
package com.xxxx.servlet; public class Servlet01 {}
实现 Servlet 标准
实现 Servlet 标准,即继承 HttpServlet 类,并到如响应的包,该类中曾经实现了通信的规定,咱们只须要进行业务的实现即可。
package com.xxxx.servlet;
import javax.servlet.http.HttpServlet;
public class Servlet01 extends HttpServlet {}
重写 service 办法
满足 Servlet 标准只是让咱们的类可能满足接管申请的要求,接管到申请后须要对申请进行剖析,以及进行业务逻辑解决,计算出后果,则须要增加代码,在标准中有一个叫做 service 的办法,专门用来做申请解决的操作,业务代码则能够写在该办法中。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("Hello Servlet!");
resp.getWriter().write("Hello World");
}
}
设置注解
在实现好了所有代码的编写后,还须要向服务器阐明,特定申请对应特定资源。
开发 servlet 我的项目,应用 @WebServlet 将一个继承于 javax.servlet.http.HttpServlet 的类定义为 Servlet 组件。在 Servlet3.0 中,能够应用 @WebServlet 注解将一个继承于 javax.servlet.http.HttpServlet 的类标注为能够解决用户申请的 Servlet。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/ser01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("Hello Servlet!");
resp.getWriter().write("Hello World");
}
}
用注解配置 Servlet
@WebServlet(name="Servlet01",value="/ser01")
@WebServlet(name="Servlet01",urlPatterns = "/ser01")
也能够配置多个拜访门路
@WebServlet(name="Servlet01",value={"/ser01",'/ser001'})
@WebServlet(name="Servlet01",urlPatterns={"/ser01",'/ser001'})
公布我的项目并启动服务
到此,须要编写和配置的中央曾经实现,我的项目曾经残缺了,然而如果须要外界可能拜访,还须要将我的项目公布到服务器上并运行服务器。
- 设置我的项目的站点名(我的项目对外拜访门路)
- 设置我的项目的 Tomcat 配置
- 启动服务器
拜访并查看后果
在我的项目正确公布到服务器上之后,用户即可通过浏览器拜访该我的项目中的资源。留神 url 的 格局正确,tomcat 的端口为 8080。
浏览器拜访地址:http://localhost:8080/s01/ser01
页面成果
后盾后果
到这里咱们的第一个 Servlet 就实现了!
Servlet 的工作流程
- 通过申请头获知浏览器拜访的是哪个主机
- 再通过申请行获取拜访的是哪个一个 web 利用
- 再通过申请行中的申请门路获知拜访的是哪个资源
- 通过获取的资源门路在配置中匹配到实在的门路,
- 服务器会创立 servlet 对象,(如果是第一次拜访时,创立 servlet 实例,并调用 init 办法进行初始化操作)
- 调用 service(request,response)办法来解决申请和响应的操作
- 调用 service 结束后返回服务器 由服务器讲 response 缓冲区的数据取出,以 http 响应的格局发送给浏览器
Servlet 的生命周期
Servlet 没有 main()办法,不能独立运行,它的运行齐全由 Servlet 引擎来管制和调度。所谓生命周期,指的是 servlet 容器何时创立 servlet 实例、何时调用其办法进行申请的解决、何时并销毁其实例的整个过程。
- 实例和初始化机会
当申请达到容器时,容器查找该 servlet 对象是否存在,如果不存在,则会创立实例并进行初始化。
- 就绪 / 调用 / 服务阶段
有申请达到容器,容器调用 servlet 对象的 service()办法, 解决申请的办法在整个生命周期中能够被屡次调用;HttpServlet 的 service()办法,会根据申请形式来调用 doGet()或者 doPost()办法。然而,这两个 do 办法默认状况下,会抛出异样,须要子类去 override。
-
销毁机会
当容器敞开时(应用程序进行时),会将程序中的 Servlet 实例进行销毁。
上述的生命周期能够通过 Servlet 中的生命周期办法来察看。在 Servlet 中有三个生命周 期办法,不禁用户手动调用,而是在特定的机会有容器主动调用,察看这三个生命周期办法 即可察看到 Servlet 的生命周期。
init 办法,在 Servlet 实例创立之后执行(证实该 Servlet 有实例创立了)
public void init(ServletConfig config) throws ServletException {System.out.println("实例创立了..."); }
service 办法,每次有申请达到某个 Servlet 办法时执行,用来解决申请(证实该 Servlet 进行服务了)
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {System.out.println("服务调用了..."); }
destroy 办法,Servlet 实例销毁时执行(证实该 Servlet 的实例被销毁了)
public void destroy() {System.out.println("实例销毁了..."); }
Servlet 的生命周期,简略的概括这就分为四步:servlet 类加载–> 实例化–> 服务–> 销毁。
上面咱们形容一下 Tomcat 与 Servlet 是如何工作的, 看看上面的时序图:
1. Web Client 向 Servlet 容器(Tomcat)收回 Http 申请
2. Servlet 容器接管 Web Client 的申请
3. Servlet 容器创立一个 HttpServletRequest 对象,将 Web Client 申请的信息封装到这个对象 中
4. Servlet 容器创立一个 HttpServletResponse 对象
5. Servlet 容器调 HttpServlet 对象 service 办法,把 Request 与 Response 作为参数,传给 HttpServlet
6. HttpServlet 调用 HttpServletRequest 对象的无关办法,获取 Http 申请信息
7. HttpServlet 调用 HttpServletResponse 对象的无关办法,生成响应数据
8. Servlet 容器把 HttpServlet 的响应后果传给 Web Client
HttpServletRequest 对象
HttpServletRequest 对象:次要作用是用来接管客户端发送过去的申请信息,例如:申请的参数,发送的头信息等都属于客户端发来的信息,service()办法中形参接管的是 HttpServletRequest 接口的实例化对象,示意该对象次要利用在 HTTP 协定上,该对象是由 Tomcat 封装好传递过去。
HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一个子接口,就是 HttpServletRequest。既然只有一个子接口为什么不将两个接口合并为一个?
从久远上讲:当初次要用的协定是 HTTP 协定,但当前可能呈现更多新的协定。若当前想要反对这种新协定,只须要间接继承 ServletRequest 接口就行了。
在 HttpServletRequest 接口中,定义的办法很多,但都是围绕接管客户端参数的。然而怎么拿到该对象呢?不须要,间接在 Service 办法中由容器传入过去,而咱们须要做的就是取出对象中的数据,进行剖析、解决。
接管申请
罕用办法
- 办法
-
示例
// 获取客户端申请的残缺 URL(从 http 开始,到? 后面完结)String url = request.getRequestURL().toString(); System.out.println("获取客户端申请的残缺 URL:" + url); // 获取客户端申请的局部 URL(从站点名开始,到? 后面完结)String uri = request.getRequestURI(); System.out.println("获取客户端申请的局部 URL:" + uri); // 获取申请行中的参数局部 String queryString = request.getQueryString(); System.out.println("获取申请行中的参数局部:" + queryString); // 获取客户端的申请形式 String method = request.getMethod(); System.out.println("获取客户端的申请形式:" + method); // 获取 HTTP 版本号 String protocol = request.getProtocol(); System.out.println("获取 HTTP 版本号:" + protocol); // 获取 webapp 名字(站点名)String webapp = request.getContextPath(); System.out.println("获取 webapp 名字:" + webapp);
获取申请参数
- 办法
-
示例
// 获取指定名称的参数,返回字符串 String uname = request.getParameter("uname"); System.out.println("uname 的参数值:" + uname); // 获取指定名称参数的所有参数值,返回数组 String[] hobbys = request.getParameterValues("hobby"); System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
申请乱码问题
因为当初的 request 属于接管客户端的参数,所以必然有其默认的语言编码,次要是因为在解析过程中默认应用的编码方式为 ISO-8859-1(此编码不反对中文),所以解析时肯定会呈现乱码。要想解决这种乱码问题,须要设置 request 中的编码方式,通知服务器以何种形式来解析数据。或者在接管到乱码数据当前,再通过相应的编码格局还原。
形式一:
request.setCharacterEncoding("UTF-8");
这种形式只针对 POST 无效(必须在接管所有的数据之前设定)
形式二:
new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
借助了 String 对象的办法,该种形式对任何申请无效,是通用的。
Tomcat8 起,当前的 GET 形式申请是不会呈现乱码的。
申请转发
申请转发,是一种服务器的行为,当客户端申请达到后,服务器进行转发,此时会将申请对象进行保留,地址栏中的 URL 地址不会扭转,失去响应后,服务器端再将响应发送给客户端,从始至终只有一个申请收回。
实现形式如下,达到多个资源协同响应的成果。
request.getRequestDispatcher(url).forward(request,response);
request 作用域
通过该对象能够在一个申请中传递数据,作用范畴:在一次申请中无效,即服务器跳转无效。
// 设置域对象内容
request.setAttribute(String name, String value);
// 获取域对象内容
request.getAttribute(String name);
// 删除域对象内容
request.removeAttribute(String name);
request 域对象中的数据在一次申请中无效,则通过申请转发,request 域中的数据仍然存在,则在申请转发的过程中能够通过 request 来传输 / 共享数据。
HttpServletResponse 对象
Web 服务器收到客户端的 http 申请,会针对每一次申请,别离创立一个用于 代表申请 的 request 对象和 代表响应 的 response 对象。
request 和 response 对象代表申请和响应:获取客户端数据,须要通过 request 对象;向客户端输入数据,须要通过 response 对象。
HttpServletResponse 的次要性能用于服务器对客户端的申请进行响应,将 Web 服务器解决后的后果返回给客户端。service()办法中形参接管的是 HttpServletResponse 接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头,发送响应状态码的办法。
响应数据
接管到客户端申请后,能够通过 HttpServletResponse 对象间接进行响应,响应时须要获取输入流。
有两种模式:
getWriter() 获取字符流(只能响应回字符)
getOutputStream() 获取字节流(能响应所有数据)
响应回的数据到客户端被浏览器解析。
留神:两者不能同时应用。
// 字符输入流
PrintWriter writer = response.getWriter();
writer.write("Hello");
writer.write("<h2>Hello</h2>");
// 字节输入流
ServletOutputStream out = response.getOutputStream();
out.write("Hello".getBytes());
out.write("<h2>Hello</h2>".getBytes());
设置响应类型,默认是字符串
// 设置响应 MIME 类型
response.setHeader("content-type","text/html"); // html
响应乱码问题
在响应中,如果咱们响应的内容中含有中文,则有可能呈现乱码。这是因为服务器响应的数据也会通过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端应用的编码方式不同时则呈现乱码。
getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中文必然出乱码,因为服务器端在进行编码时默认会应用 ISO-8859-1 格局的编码,该编码方式并不反对中文。
要解决该种乱码只能在服务器端 告知服务器 应用一种可能反对中文的编码格局,比方咱们通常用的 ”UTF-8″。
response.setCharacterEncoding("UTF-8");
此时还只实现了一半的工作,要保证数据正确显示,还须要 指定客户端 的解码形式。
response.setHeader("content-type", "text/html;charset=UTF-8");
两端指定编码后,乱码就解决了。一句话:保障发送端和接收端的编码统一
// 设置服务端的编码
response.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
response.setHeader("content-type","text/html;charset=UTF-8");
// 失去字符输入流
PrintWriter writer = response.getWriter();
writer.write("<h2> 你好 </h2>");
以上两端编码的指定也能够应用一句代替,同时指定服务器和客户端
response.setContentType("text/html;charset=UTF-8");
getOutputStream()字节乱码
对于 getOutputStream()形式获取到的字节流,响应中文时,因为自身就是传输的字节,所以此时可能呈现乱码,也可能正确显示。当服务器端给的字节恰好和客户端应用的编码方式统一时则文本正确显示,否则呈现乱码。无论如何咱们都应该精确把握服务器和客户端应用的是那种编码格局,以确保数据正确显示。
指定客户端和服务器应用的编码方式统一。
response.setHeader("content-type","text/html;charset=UTF-8");
// 设置客户端的编码及响应类型
ServletOutputStream out = response.getOutputStream();
response.setHeader("content-type","text/html;charset=UTF-8");
out.write("<h2> 你好 </h2>".getBytes("UTF-8"));
同样也能够应用一句代替
// 设置客户端与服务端的编码
response.setContentType("text/html;charset=UTF-8");
总结:要想解决响应的乱码,只须要保障应用反对中文的编码格局。并且保障服务器端 和客户端应用雷同的编码方式即可。
重定向
重定向是一种服务器领导,客户端的行为。客户端收回第一个申请,被服务器接管解决后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次申请的地址 response.sendRedirect(url);),当客户端接管到响应后,会立即、马上、主动依据服务器给的新地址发动第二个申请,服务器接管申请并作出响应,重定向实现。
从形容中能够看出重定向当中有两个申请存在,并且属于客户端行为。
// 重定向跳转到 index.jsp
response.sendRedirect("index.jsp");
通过观察浏览器咱们发现第一次申请取得的响应码为 302,并且含有一个 location 头信息。并且地址栏最终看到的地址是和第一次申请地址不同的,地址栏曾经产生了变动。
申请转发与重定向的区别
申请转发和重定向比拟:
两者都可进行跳转,依据理论需要选取即可。
Cookie 对象
Cookie 是浏览器提供的一种技术,通过服务器的程序能将一些只须保留在客户端,或者在客户端进行解决的数据,放在本地的计算机上,不须要通过网络传输,因此进步网页解决的效率,并且可能缩小服务器的负载,然而因为 Cookie 是服务器端保留在客户端的信息,所以其安全性也是很差的。例如常见的记住明码则能够通过 Cookie 来实现。
有一个专门操作 Cookie 的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保留在浏览器。当下次再拜访服务器时把 Cookie 再带回服务器。
Cookie 的格局:键值对用“=”链接,多个键值对间通过“;”隔开。
Cookie 的创立和发送
通过 new Cookie(“key”,“value”); 来创立一个 Cookie 对象,要想将 Cookie 随响应发送到客户端,须要先增加到 response 对象中,response.addCookie(cookie); 此时该 cookie 对象则随着响应发送至了客户端。在浏览器上能够看见。
// 创立 Cookie 对象
Cookie cookie = new Cookie("uname","zhangsan");
// 发送 Cookie 对象
response.addCookie(cookie);
F12 查看
Cookie 的获取
在服务器端只提供了一个 getCookies()的办法用来获取客户端回传的所有 cookie 组成的一个数组,如果须要获取单个 cookie 则须要通过遍历,getName()获取 Cookie 的名称,getValue()获取 Cookie 的值。
// 获取 Cookie 数组
Cookie[] cookies = request.getCookies();
// 判断数组是否为空
if (cookies != null && cookies.length > 0) {
// 遍历 Cookie 数组
for (Cookie cookie : cookies){System.out.println(cookie.getName());
System.out.println(cookie.getValue());
}
}
Cookie 设置到期工夫
除了 Cookie 的名称和内容外,咱们还须要关怀一个信息,到期工夫,到期工夫用来指定该 cookie 何时生效。默认为以后浏览器敞开即生效。咱们能够手动设定 cookie 的无效工夫(通过到期工夫计算),通过 setMaxAge(int time); 办法设定 cookie 的最大无效工夫,以秒为单位。
到期工夫的取值
- 负整数
若为正数,示意不存储该 cookie。
cookie 的 maxAge 属性的默认值就是 -1,示意只在浏览器内存中存活,一旦敞开浏览器窗口,那么 cookie 就会隐没。
- 正整数
若大于 0 的整数,示意存储的秒数。
示意 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保留到硬盘上,就算敞开浏览器,就算重启客户端电脑,cookie 也会存活相应的工夫。
- 零
若为 0,示意删除该 cookie。
cookie 生命等于 0 是一个非凡的值,它示意 cookie 被作废!也就是说,如果原来浏览器曾经保留了这个 Cookie,那么能够通过 Cookie 的 setMaxAge(0)来删除这个 Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个 Cookie。
设置 Cookie 对象指定工夫后生效
// 创立 Cookie 对象
Cookie cookie = new Cookie("uname","zhangsan");
// 设置 Cookie 3 天后生效
cookie.setMaxAge(3 * 24 * 60 * 60);
// 发送 Cookie 对象
response.addCookie(cookie);
Cookie 的留神点
- Cookie 保留在以后浏览器中。
在个别的站点中经常有记住用户名这样一个操作,该操作只是将信息保留在本机上,换电脑当前这些信息就有效了。而且 cookie 还不能跨浏览器。
-
Cookie 存中文问题
Cookie 中不能呈现中文,如果有中文则通过 URLEncoder.encode()来进行编码,获取时通过 URLDecoder.decode()来进行解码。
String name = "姓名"; String value = "张三"; // 通过 URLEncoder.encode()来进行编码 name = URLEncoder.encode(name); value = URLEncoder.encode(value); // 创立 Cookie 对象 Cookie cookie = new Cookie(name,value); // 发送 Cookie 对象 response.addCookie(cookie);
// 获取时通过 URLDecoder.decode()来进行解码 URLDecoder.decode(cookie.getName()); URLDecoder.decode(cookie.getValue());
- 同名 Cookie 问题
如果服务器端发送反复的 Cookie 那么会笼罩原有的 Cookie。
- 浏览器寄存 Cookie 的数量
不同的浏览器对 Cookie 也有限定,Cookie 的存储有是下限的。Cookie 是存储在客户端(浏览器)的,而且个别是由服务器端创立和设定。前期联合 Session 来实现回话跟踪。
Cookie 的门路
Cookie 的 setPath 设置 cookie 的门路,这个门路间接决定服务器的申请是否会从浏览器中加载某些 cookie。
情景一:以后服务器下任何我的项目的任意资源都可获取 Cookie 对象
/* 以后我的项目门路为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置门路为 "/",示意在以后服务器下任何我的项目都可拜访到 Cookie 对象
cookie.setPath("/");
response.addCookie(cookie);
情景二:以后我的项目下的资源可获取 Cookie 对象(默认不设置 Cookie 的 path)
/* 以后我的项目门路为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置门路为 "/s01",示意在以后我的项目下任何我的项目都可拜访到 Cookie 对象
cookie.setPath("/s01"); // 默认状况,可不设置 path 的值
response.addCookie(cookie);
情景三:指定我的项目下的资源可获取 Cookie 对象
/* 以后我的项目门路为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置门路为 "/s02",示意在 s02 我的项目下才可拜访到 Cookie 对象
cookie.setPath("/s02"); // 只能在 s02 我的项目下获取 Cookie,就算 cookie 是 s01 产生的,s01 也不能获取它
response.addCookie(cookie);
情景四:指定目录下的资源可获取 Cookie 对象
/* 以后我的项目门路为:s01 */
Cookie cookie = new Cookie("xxx","XXX");
// 设置门路为 "/s01/cook",示意在 s02/cook 目录下才可拜访到 Cookie 对象
cookie.setPath("/s01/cook");
response.addCookie(cookie);
如果咱们设置 path,如果以后拜访的门路蕴含了 cookie 的门路(以后拜访门路在 cookie 门路根底上要比 cookie 的范畴小)cookie 就会加载到 request 对象之中。
cookie 的门路指的是能够拜访该 cookie 的顶层目录,该门路的子门路也能够拜访该 cookie。
总结:当拜访的门路蕴含了 cookie 的门路时,则该申请将带上该 cookie;如果拜访门路不蕴含 cookie 门路,则该申请不会携带该 cookie。
HttpSession 对象
HttpSession对象是 javax.servlet.http.HttpSession 的实例,该接口并不像 HttpServletRequest 或 HttpServletResponse 还存在一个父接口,该接口只是一个纯正的接口。这因为 session 自身就属于 HTTP 协定的领域。
对于服务器而言,每一个连贯到它的客户端都是一个 session,servlet 容器应用此接口创立 HTTP 客户端和 HTTP 服务器之间的会话。会话将保留指定的时间段,跨多个连贯或来自用户的页面申请。一个会话通常对应于一个用户,该用户可能屡次拜访一个站点。能够通过此接口查看和操作无关某个会话的信息,比方会话标识符、创立工夫和最初一次拜访工夫。在整个 session 中,最重要的就是属性的操作。
session 无论客户端还是服务器端都能够感知到,若从新关上一个新的浏览器,则无奈获得之前设置的 session,因为每一个 session 只保留在以后的浏览器当中,并在相干的页面获得。
Session 的作用就是为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的屡次申请)期间共享数据。咱们能够通过 request.getSession()办法,来获取以后会话的 session 对象。
// 如果 session 对象存在,则获取;如果 session 对象不存在,则创立
HttpSession session = request.getSession();
标识符 JSESSIONID
Session 既然是为了标识一次会话,那么此次会话就应该有一个惟一的标记,这个标记就是 sessionId。
每当一次申请达到服务器,如果开启了会话(拜访了 session),服务器第一步会查看是否从客户端回传一个名为 JSESSIONID 的 cookie,如果没有则认为这是一次新的会话,会创立 一个新的 session 对象,并用惟一的 sessionId 为此次会话做一个标记。如果有 JESSIONID 这 个 cookie 回传,服务器则会依据 JSESSIONID 这个值去查看是否含有 id 为 JSESSION 值的 session 对象,如果没有则认为是一个新的会话,从新创立一个新的 session 对象,并标记此次会话;如果找到了相应的 session 对象,则认为是之前标记过的一次会话,返回该 session 对象,数据达到共享。
这里提到一个叫做 JSESSIONID 的 cookie,这是一个比拟非凡的 cookie,当用户申请服务器时,如果拜访了 session,则服务器会创立一个名为 JSESSIONID,值为获取到的 session(无论是获取到的还是新创建的)的 sessionId 的 cookie 对象,并增加到 response 对象中,响应给客户端,无效工夫为敞开浏览器。
所以 Session 的底层依赖 Cookie 来实现。
session 域对象
Session 用来示意一次会话,在一次会话中数据是能够共享的,这时 session 作为域对象存在,能够通过 setAttribute(name,value) 办法向域对象中增加数据,通过 getAttribute(name) 从域对象中获取数据,通过 removeAttribute(name) 从域对象中移除数据。
// 获取 session 对象
HttpSession session = request.getSession();
// 设置 session 域对象
session.setAttribute("uname","admin");
// 获取指定名称的 session 域对象
String uname = (String) request.getAttribute("uname");
// 移除指定名称的 session 域对象
session.removeAttribute("uname");
数据存储在 session 域对象中,当 session 对象不存在了,或者是两个不同的 session 对象时,数据也就不能共享了。这就不得不谈到 session 的生命周期。
session 对象的销毁
默认工夫到期
当客户端第一次申请 servlet 并且操作 session 时,session 对象生成,Tomcat 中 session 默认的存活工夫为 30min,即你不操作界面的工夫,一旦有操作,session 会从新计时。
那么 session 的默认工夫能够改么?答案是必定的。
能够在 Tomcat 中的 conf 目录下的 web.xml 文件中进行批改。
<!-- session 默认的最大不流动工夫。单位:分钟。-->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
本人设定到期工夫
当然除了以上的批改形式外,咱们也能够在程序中本人设定 session 的生命周期,通过 session.setMaxInactiveInterval(int) 来设定 session 的最大不流动工夫,单位为秒。
// 获取 session 对象
HttpSession session = request.getSession();
// 设置 session 的最大不流动工夫
session.setMaxInactiveInterval(15); // 15 秒
当然咱们也能够通过 getMaxInactiveInterval() 办法来查看以后 Session 对象的最大不流动工夫。
// 获取 session 的最大不流动工夫
int time = session.getMaxInactiveInterval();
立即生效
或者咱们也能够通过 session.invalidate() 办法让 session 立即生效
// 销毁 session 对象
session.invalidate();
敞开浏览器
从后面的 JESSIONID 可晓得,session 的底层依赖 cookie 实现,并且该 cookie 的无效工夫为敞开浏览器,从而 session 在浏览器敞开时也相当于生效了(因为没有 JSESSION 再与之对应)。
敞开服务器
当敞开服务器时,session 销毁。
Session 生效则意味着此次会话完结,数据共享完结。
ServletContext 对象
每一个 web 利用都有且仅有一个 ServletContext 对象,又称 Application 对象,从名称中可知,该对象是与应用程序相干的。在 WEB 容器启动的时候,会为每一个 WEB 应用程序创立一个对应的 ServletContext 对象。
该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享;第二、该对象中保留了以后应用程序相干信息。例如能够通过 getServerInfo() 办法获取以后服务器信息,getRealPath(String path) 获取资源的实在门路等。
ServletContext 对象的获取
获取 ServletContext 对象的路径有很多。比方:
-
通过 request 对象获取
ServletContext servletContext = request.getServletContext();
-
通过 session 对象获取
ServletContext servletContext = request.getSession().getServletContext();
-
通过 servletConfig 对象获取,在 Servlet 规范中提供了 ServletConfig 办法
ServletConfig servletConfig = getServletConfig(); ServletContext servletContext = servletConfig.getServletContext();
-
间接获取,Servlet 类中提供了间接获取 ServletContext 对象的办法
ServletContext servletContext = getServletContext();
罕用办法
// 获取我的项目寄存的实在门路
String realPath = request.getServletContext().getRealPath("/");
// 获取以后服务器的版本信息
String serverInfo = request.getServletContext().getServerInfo();
ServletContext 域对象
ServletContext 也可当做域对象来应用,通过向 ServletContext 中存取数据,能够使得整个应用程序共享某些数据。当然不倡议寄存过多数据,因为 ServletContext 中的数据一旦存储进去没有手动移除将会始终保留。
// 获取 ServletContext 对象
ServletContext servletContext = request.getServletContext();
// 设置域对象
servletContext.setAttribute("name","zhangsan");
// 获取域对象
String name = (String) servletContext.getAttribute("name");
// 移除域对象
servletContext.removeAttribute("name");
Servlet 的三大域对象
- request 域对象
在一次申请中无效。申请转发无效,重定向生效。
- session 域对象
在一次会话中无效。申请转发和重定向都无效,session 销毁后生效。
- servletContext 域对象
在整个应用程序中无效。服务器敞开后生效。
文件上传和下载
在上网的时候咱们经常遇到文件上传的状况,例如上传头像、上传材料等;当然除了上传,遇见下载的状况也很多,接下来看看咱们 servlet 中怎么实现文件的上传和下载。
文件上传
文件上传波及到前台页面的编写和后盾服务器端代码的编写,前台发送文件,后盾接管并保留文件,这才是一个残缺的文件上传。
前台页面
在做文件上传的时候,会有一个上传文件的界面,首先咱们须要一个表单,并且表单的申请形式为 POST;其次咱们的 form 表单的 enctype 必须设为 ”multipart/form-data”,即 enctype=“multipart/form-data”,意思是设置表单的类型为文件上传表单。默认状况下这个表单类型是“application/x-www-form-urlencoded”, 不能用于文件上传。只有应用了 multipart/form-data 能力残缺地传递文件数据。
<!--
文件上传表单
1. 表单提交类型 method="post"
2. 表单类型 enctype="multipart/form-data"
3. 表单元素类型 文件域设置 name 属性值
-->
<form method="post" action="uploadServlet" enctype="multipart/form-data">
姓名:<input type="text" name="uname" > <br>
文件:<input type="file" name="myfile" > <br>
<button type="submit"> 提交 </button>
</form>
后盾实现
应用注解 @MultipartConfig 将一个 Servlet 标识为反对文件上传。Servlet 将 multipart/form-data 的 POST 申请封装成 Part,通过 Part 对上传的文件进行操作。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
@WebServlet("/uploadServlet")
@MultipartConfig // 如果是文件上传表单,肯定要加这个注解
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置申请的编码格局
request.setCharacterEncoding("UTF-8");
// 获取一般表单项(文本框)String uname = request.getParameter("uname"); // "uname" 代表的是文本框的 name 属性值
// 通过 getPart(name) 办法获取 Part 对象(name 代表的是页面中 file 文件域的 name 属性值)Part part = request.getPart("myfile");
// 通过 Part 对象,获取上传的文件名
String fileName = part.getSubmittedFileName();
// 获取上传文件须要寄存的门路(失去我的项目寄存的实在门路)String realPath = request.getServletContext().getRealPath("/");
// 将文件上传到指定地位
part.write(realPath + fileName);
}
}
文件下载
文件下载,行将服务器上的资源下载(拷贝)到本地,咱们能够通过两种形式下载。第一种是通过超链接自身的个性来下载;第二种是通过代码下载。
超链接下载
当咱们在 HTML 或 JSP 页面中应用 a 标签时,原意是心愿可能进行跳转,但当超链接遇到浏览器不辨认的资源时会主动下载;当遇见浏览器可能间接显示的资源,浏览器就会默认显示进去,比方 txt、png、jpg 等。当然咱们也能够通过 download 属性 规定浏览器进行下载。但有些浏览器并不反对。
默认下载
<!-- 当超链接遇到浏览器不辨认的资源时,会主动下载 -->
<a href="test.zip"> 超链接下载 </a>
指定 download 属性下载
<!-- 当超链接遇到浏览器辨认的资源时,默认不会下载。通过 download 属性可进行下载 -->
<a href="test.txt" download> 超链接下载 </a>
download 属性能够不写任何信息,会主动应用默认文件名。如果设置了 download 属性的值,则应用设置的值做为文件名。当用户关上浏览器点击链接的时候就会间接下载文件。
后盾实现下载
实现步骤
- 须要通过 response.setContentType 办法设置 Content-type 头字段的值,为浏览器无奈应用某种形式或激活某个程序来解决的 MIME 类型,例 如“application/octet-stream”或“application/x-msdownload”等。
- 须要通过 response.setHeader 办法设置 Content-Disposition 头的值 为“attachment;filename= 文件名”
- 读取下载文件,调用 response.getOutputStream 办法向客户端写入附件内容。
package com.xxxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class DownloadServlet extends HttpServlet {protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置申请的编码
request.setCharacterEncoding("UTF-8");
// 获取文件下载门路
String path = getServletContext().getRealPath("/");
// 获取要下载的文件名
String name = request.getParameter("fileName");
// 通过门路失去 file 对象
File file = new File(path + name);
// 判断 file 对象是否存在,且是否是一个标准文件
if (file.exists() && file.isFile()) {// 设置响应类型 (浏览器无奈应用某种形式或激活某个程序来解决的类型)
response.setContentType("application/x-msdownload");
// 设置头信息
response.setHeader("Content-Disposition", "attachment;filename=" + name);
// 失去输出流
InputStream is = new FileInputStream(file);
// 失去输入流
ServletOutputStream os = response.getOutputStream();
// 定义 byte 数组
byte[] car = new byte[1024];
// 定义长度
int len = 0;
// 循环 输入
while ((len = is.read(car)) != -1) {os.write(car, 0, len);
}
// 敞开流 开释资源
os.close();
is.close();} else {System.out.println("文件不存在,下载失败!");
}
}
}