1. 主要内容
2. IDEA的安装与使用
IDEA 全称 IntelliJ IDEA,由JetBrains公司开发,是java编程语⾔开发的集成环境。在业界被公认为最
好的java开发⼯具,尤其在智能代码助⼿、代码⾃动提示、重构、J2EE⽀持、各类版本⼯具(git、svn
等)、JUnit、CVS整合、代码分析、 创新的GUI设计等⽅⾯的功能可以说是超常的。
(i)IDEA创建项目
1.点击 “Create New Project”
2.添加新的 JDK 版本 (idea默认使⽤⾃带的版本)
3.选择JDK版本,然后 “Next”
4.选择 “Next”
5.设置项⽬名称及⼯作空间
6.项⽬⽬录结构及提示信息 (提示信息可选择"Close")
(ii) 创建Java类
1.点击 “src” —> “new” —> “package”,创建⼀个⽂件包
7.设置包名,与Eclipse的包类似
3.在包下⾯创建 Java 类⽂件,点击包名 —> “New” —> “Java Class”
8.选择类型,并设置类的名称
9.在类中写⼀个main⽅法
执⾏main⽅法
10.⽅式⼀:代码左侧的绿⾊三⻆符号
11.⽅式⼆:在类中右键,选择Run或Debug
3.⽅式三:点击最上⽅菜单栏的Run
出现以下弹框,点击要运⾏的⽂件名,这⾥是 Hello
12.运⾏结果
IDEA的基本设置
使⽤IDEA时,可以对它进⾏⼀些简单的设置,通过设置⽤户的偏好设置,可提⾼使⽤者的体验感。
进⼊设置页面
1.选择右下⻆的 “Configure”,选择"Settings" (或在IDEA中,选择左上⻆的 “File”,选
择"Settings"
2.进⼊设置⻚⾯
设置字体
3.在Settings窗⼝中,点击 “Editor” —> “Color Scheme”
4.选择 “Color Scheme Font”,设置字体⻛格和字体⼤⼩,设置完之后选择 “Apply” 应⽤
5.设置中⽂字体
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 重构-重命名
3. HTTP协议
HTTP 协议(Hypertext Transfer Protocol, 超⽂本传输协议),是⼀个客户端请求和响应的标准协
议,这个协议详细规定了浏览器和万维⽹服务器之间互相通信的规则。⽤户输⼊地址和端⼝号之后就可
以从服务器上取得所需要的⽹⻚信息。
通信规则规定了客户端发送给服务器的内容格式,也规定了服务器发送给客户端的内容格式。客户端
发送给服务器的格式叫"请求协议";服务器发送给客户端的格式叫"响应协议"。
在浏览器中 F12可查看
3.1浏览器中的书写格式
服务器端资源需要通过浏览器进⾏,此时由浏览器将我们给出的请求解析为满⾜ HTTP 协议的格式并
发出。我们发出的请求格式需要按照浏览器规定的格式来书写,在浏览器中书写格式如下:
当浏览器获取到信息以后,按照特定格式解析并发送即可。接收到服务器端给出的响应时,也按照
HTTP 协议进⾏解析获取到各个数据,最后按照特定格式展示给⽤户。
3.2. HTTP协议的特点
1.⽀持客户/服务器模式。
2.简单快速:客户向服务器请求服务时,只需传送请求⽅法和路径。请求⽅法常⽤的 有 GET、
POST。每种⽅法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,使得HTTP服务器的
程序规模⼩,因⽽通信速度很快。
3.灵活:HTTP 允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.⽆连接:⽆连接是表示每次连接只处理⼀个请求。服务器处理完客户的请求,并收到客户的应答
后,即断开连接。采⽤这种⽅式可以节省传输时间。
HTTP1.1 版本后⽀持可持续连接。通过这种连接,就有可能在建⽴⼀个 TCP 连接后,发送请求并得到
回应,然后发送更多的请求并得到更多的回应.通过把建⽴和释放 TCP 连接的开销分摊到多个请求
上,则对于每个请求⽽⾔,由于 TCP ⽽造成的相对开销被⼤⼤地降低了。⽽且, 还可以发送流⽔
线请求,也就是说在发送请求 1 之后的回应到来之前就可以发送请求 2.也可以认为,⼀次连接发送
多个请求,由客户机确认是否关闭连接,⽽服务器会认为这些请求分别来⾃不同的客户端。
5.⽆状态:HTTP 协议是⽆状态协议。⽆状态是指协议对于事务处理没有记忆能⼒。缺少状态意味着
如果后续处理需要前⾯的信息,则它必须重传,这样可能导致每次连接传送 的数据量增⼤。另⼀
⽅⾯,在服务器不需要先前信息时它的应答就较快。
3.3. 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 时,必
须以“/”的形式给出,通常 这个⼯作浏览器⾃动帮我们完成。
3.4. HTTP 请求
HTTP 请求由三部分组成,分别是:请求⾏、请求头、请求正⽂。
通过chrome浏览器, F12 —> Network查看。
1.Get 请求(没有请求体)
- Post 请求
格式
请求⾏
请求头1
请求头2 …
请求空⾏
请求体
请求⾏以⼀个⽅法符号开头,以空格分开,后⾯跟着请求的 URI 和协议的版本。
格式如下:Method Request-URI HTTP-Version CRLF
Method 表示请求⽅法;
Request-URI 是⼀个统⼀资源标识符;
HTTP-Version 表示请 求的 HTTP 协议版本;
CRLF 表示回⻋和换⾏;
3.5. HTTP 响应
在接收和解释请求消息后,服务器返回⼀个 HTTP 响应消息。HTTP 响应也是由三个部分组成,分别
是:状态⾏、消息报头、响应正⽂。
格式
状态⾏
响应头1
响应头2 …
响应空⾏
响应体
3.6. 消息头
HTTP 消息由客户端到服务器的请求和服务器到客户端的响应组成。请求消息和响应消息都是由开始
⾏(对于请求消息,开始⾏就是请求⾏,对于响应消息,开始⾏就是状态⾏), 消息报头(可选),空
⾏(只有 CRLF 的⾏),消息正⽂(可选)组成。
每⼀个报头域都是由 名字+":"+空格+值 组成,消息报头域的名字是⼤⼩写⽆关的。
请求头
请求报头允许客户端向服务器端传递请求的附加信息以及客户端⾃身的信息。
Referer:该请求头指明请求从哪⾥来 。
如果是地址栏中输⼊地址访问的都没有该请求头 地址栏输⼊地址,通过请求可以看到,此时多
了⼀个 Referer 的请求头,并且后⾯的值 为该请求从哪⾥发出。⽐如:百度竞价,只能从百度来
的才有效果,否则不算;通常⽤来做统计⼯作、 防盗链。
响应头
响应报头允许服务器传递不能放在状态⾏中的附加响应信息,以及关于服务器的信息和 对 RequestURI 所标识的资源进⾏下⼀步访问的信息。
Location:Location响应报头域⽤于重定向接受者到⼀个新的位置。
Location响应报头域,常⽤在更换域名的时候。
response.sendRedirect("http://www.baidu.com");
Refresh:⾃动跳转(单位是秒),可以在⻚⾯通过meta标签实现,也可在后台实现。
<meta http-equiv="refresh" content="3;url=http://www.baidu.com">
4. 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,能访问则算安装好了
IDEA配置Tomcat
1.选择 “Appliction Servers”,点击右侧的 “+” 号,选择 “Tomcat Server”
2.设置 Tomcat 的安装⽬录
3.配置Tomcat服务器完成
5. 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项⽬
1.选择 “File” —> “New” —> “Project”
2.设置项⽬的相关信息,选择 “Next”
3.设置项⽬名称及⼯作空间
4.web项⽬⽬录结构如下
Servlet的实现
新建类
1.点击 “src” —> “new” —> “package”,创建⼀个⽂件包
2.在包下⾯创建 Java 类⽂件,点击包名 —> “New” —> “Java Class”
3.创建⼀个普通的 Java 类
4.如下
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’})
发布项⽬并启动服务
到此,需要编写和配置的地⽅已经完成,项⽬已经完整了,但是如果需要外界能够访问, 还需要将项
⽬发布到服务器上并运⾏服务器。
1.设置项⽬的站点名(项⽬对外访问路径)
2.设置项⽬的Tomcat配置
3.启动服务器
Servlet的⼯作流程
4.通过请求头获知浏览器访问的是哪个主机
5.再通过请求⾏获取访问的是哪个⼀个web应⽤
6.再通过请求⾏中的请求路径获知访问的是哪个资源
7.通过获取的资源路径在配置中匹配到真实的路径,
8.服务器会创建servlet对象,(如果是第⼀次访问时,创建servlet实例,并调⽤init⽅法进⾏初始化
操作)
9.调⽤service(request, response)⽅法来处理请求和响应的操作
10调⽤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
6. HttpServletRequest对象
HttpServletRequest 对象:主要作⽤是⽤来接收客户端发送过来的请求信息,例如:请求的参数,发
送的头信息等都属于客户端发来的信息,service()⽅法中形参接收的是 HttpServletRequest 接⼝的实
例化对象,表示该对象主要应⽤在 HTTP 协议上,该对象是由 Tomcat 封装好传递过来。
HttpServletRequest 是 ServletRequest 的⼦接⼝,ServletRequest 只有⼀个⼦接⼝,就是
HttpServletRequest。既然只有⼀个⼦接⼝为什么不将两个接⼝合并为⼀个?
从⻓远上讲:现在主要⽤的协议是 HTTP 协议,但以后可能出现更多新的协议。若以后想要⽀持这种
新协议,只需要直接继承 ServletRequest 接⼝就⾏了。
在 HttpServletRequest 接⼝中,定义的⽅法很多,但都是围绕接收客户端参数的。但是怎么拿到该
对象呢?不需要,直接在 Service ⽅法中由容器传⼊过来,⽽我们需要做的就是取出对象中的数据,进
⾏分析、处理。
接收请求
常⽤⽅法
1.⽅法
示例
// 获取客户端请求的完整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);
获取请求参数
1.⽅法
- 示例
// 获取指定名称的参数,返回字符串
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⽅式请求是不会出现乱码的。
6.3. 请求转发
请求转发,是⼀种服务器的⾏为,当客户端请求到达后,服务器进⾏转发,此时会将请求对象进⾏保
存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始⾄终只有⼀
个请求发出。
实现⽅式如下,达到多个资源协同响应的效果。
request.getRequestDispatcher(url).forward(request,response);
6.4. request作⽤域
通过该对象可以在⼀个请求中传递数据,作⽤范围:在⼀次请求中有效,即服务器跳转有效。
// 设置域对象内容
request.setAttribute(String name, String value);
// 获取域对象内容
request.getAttribute(String name);
// 删除域对象内容
request.removeAttribute(String name);
request 域对象中的数据在⼀次请求中有效,则经过请求转发,request 域中的数据依然存在,则在
请求转发的过程中可以通过 request 来传输/共享数据。
7. HttpServletResponse对象
Web服务器收到客户端的http请求,会针对每⼀次请求,分别创建⼀个⽤于代表请求的 request 对象
和代表响应的 response 对象。
request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向客户端输
出数据,需要通过 response 对象。
HttpServletResponse 的主要功能⽤于服务器对客户端的请求进⾏响应,将 Web 服务器处理后的结
果返回给客户端。service()⽅法中形参接收的是 HttpServletResponse 接⼝的实例化对象,这个对象中
封装了向客户端发送数据、发送响应头,发送响应状态码的⽅法。
7.1. 响应数据
接收到客户端请求后,可以通过 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
7.2. 响应乱码问题
在响应中,如果我们响应的内容中含有中⽂,则有可能出现乱码。这是因为服务器响应的数据也会经
过⽹络传输,服务器端有⼀种编码⽅式,在客户端也存在⼀种编码⽅式,当两端使⽤的编码⽅式不同时
则出现乱码。
getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中⽂必定出乱码,由于服务器端在进⾏编码时默认会使⽤
ISO-8859-1 格式的编码,该编码⽅式并不⽀持中⽂。
要解决该种乱码只能在服务器端告知服务器使⽤⼀种能够⽀持中⽂的编码格式,⽐如我们通常⽤
的"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(“ 你好 ”.getBytes(“UTF-8”));
同样也可以使⽤⼀句替代
// 设置客户端与服务端的编码
response.setContentType(“text/html;charset=UTF-8”);
7.3. 重定向
重定向是⼀种服务器指导,客户端的⾏为。客户端发出第⼀个请求,被服务器接收处理后,服务器会
进⾏响应,在响应的同时,服务器会给客户端⼀个新的地址(下次请求的地址
response.sendRedirect(url);),当客户端接收到响应后,会⽴刻、⻢上、⾃动根据服务器给的新地址
发起第⼆个请求,服务器接收请求并作出响应,重定向完成。
从描述中可以看出重定向当中有两个请求存在,并且属于客户端⾏为。
// 重定向跳转到index.jsp
response.sendRedirect(“index.jsp”);
通过观察浏览器我们发现第⼀次请求获得的响应码为 302,并且含有⼀个 location 头信息。并且地址
栏最终看到的地址是和第⼀次请求地址不同的,地址栏已经发⽣了变化。
7.4. 请求转发与重定向的区别
请求转发和重定向⽐较:
8. Cookie对象
Cookie是浏览器提供的⼀种技术,通过服务器的程序能将⼀些只须保存在客户端,或者在客户端进⾏
处理的数据,放在本地的计算机上,不需要通过⽹络传输,因⽽提⾼⽹⻚处理的效率,并且能够减少服
务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的。例如常⻅
的记住密码则可以通过 Cookie 来实现。
有⼀个专⻔操作Cookie的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存
在浏览器。当下次再访问服务器时把Cookie再带回服务器。
Cookie 的格式:键值对⽤“=”链接,多个键值对间通过“;”隔开。
8.1. Cookie的创建和发送
通过 new Cookie(“key”,“value”);来创建⼀个 Cookie 对象,要想将 Cookie 随响应发送到客户端,需
要先添加到 response 对象中,response.addCookie(cookie);此时该 cookie 对象则随着响应发送⾄了
客户端。在浏览器上可以看⻅。
8.2. Cookie的获取
在服务器端只提供了⼀个 getCookies()的⽅法⽤来获取客户端回传的所有 cookie 组成的⼀个数组,
如果需要获取单个 cookie 则需要通过遍历,getName()获取 Cookie 的名称,getValue()获取 Cookie
的值。
8.3. 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);
8.4. Cookie的注意点
1.Cookie保存在当前浏览器中。
在⼀般的站点中常常有记住⽤户名这样⼀个操作,该操作只是将信息保存在本机上,换电脑以后这
些信息就⽆效了。⽽且 cookie 还不能跨浏览器。
2.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());
3.同名Cookie问题
如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。
4.浏览器存放Cookie的数量
不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)
的,⽽且⼀般是由服务器端创建和设定。后期结合Session来实现回话跟踪。
8.5. Cookie的路径
Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些
cookie。
情景⼀:当前服务器下任何项⽬的任意资源都可获取Cookie对象
情景⼆:当前项⽬下的资源可获取Cookie对象 (默认不设置Cookie的path)
情景三:指定项⽬下的资源可获取Cookie对象
情景四:指定⽬录下的资源可获取Cookie对象
如果我们设置path,如果当前访问的路径包含了cookie的路径(当前访问路径在cookie路径基础上要
⽐cookie的范围⼩)cookie就会加载到request对象之中。
cookie的路径指的是可以访问该cookie的顶层⽬录,该路径的⼦路径也可以访问该cookie。
总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含
cookie路径,则该请求不会携带该cookie
9. 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();
9.1. 标识符 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 来实现。
9.2. 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 的⽣命周期。
9.3. session对象的销毁
默认时间到期
当客户端第⼀次请求 servlet 并且操作 session 时,session 对象⽣成,Tomcat 中 session 默认的存
活时间为 30min,即你不操作界⾯的时间,⼀旦有操作,session 会重新计时。
那么 session 的默认时间可以改么?答案是肯定的。
可以在 Tomcat 中的 conf ⽬录下的 web.xml ⽂件中进⾏修改。
⾃⼰设定到期时间
当然除了以上的修改⽅式外,我们也可以在程序中⾃⼰设定 session 的⽣命周期,通过
session.setMaxInactiveInterval(int) 来设定 session 的最⼤不活动时间,单位为秒。
⽴刻失效
或者我们也可以通过 session.invalidate() ⽅法让 session ⽴刻失效
关闭浏览器
从前⾯的 JESSIONID 可知道,session 的底层依赖 cookie 实现,并且该 cookie 的有效时间为关闭浏
览器,从⽽ session 在浏览器关闭时也相当于失效了(因为没有 JSESSION 再与之对应)。
关闭服务器
当关闭服务器时,session 销毁。
Session 失效则意味着此次会话结束,数据共享结束。
10. ServletContext对象
每⼀个 web 应⽤都有且仅有⼀个ServletContext 对象,⼜称 Application 对象,从名称中可知,该对
象是与应⽤程序相关的。在 WEB 容器启动的时候,会为每⼀个 WEB 应⽤程序创建⼀个对应的
ServletContext 对象。
该对象有两⼤作⽤,第⼀、作为域对象⽤来共享数据,此时数据在整个应⽤程序中共享; 第⼆、该对
象中保存了当前应⽤程序相关信息。例如可以通过 getServerInfo() ⽅法获取当前服务器信息 ,
getRealPath(String path) 获取资源的真实路径等。
ServletContext对象的获取
获取 ServletContext 对象的途径有很多。⽐如:
1.通过 request 对象获取
ServletContext servletContext = request.getServletContext();
2.通过 session 对象获取
ServletContext servletContext =request.getSession().getServletContext();
3.通过 servletConfig 对象获取,在 Servlet 标准中提供了 ServletConfig ⽅法
ServletConfig servletConfig = getServletConfig();
ServletContext servletContext = servletConfig.getServletContext();
4.直接获取,Servlet 类中提供了直接获取 ServletContext 对象的⽅法
ServletContext servletContext = getServletContext();
10.2. ServletContext域对象
ServletContext 也可当做域对象来使⽤,通过向 ServletContext 中存取数据,可以使得整个应⽤程
序共享某些数据。当然不建议存放过多数据,因为 ServletContext 中的数据⼀旦存储进去没有⼿动移除
将会⼀直保存。
// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();
// 设置域对象
servletContext.setAttribute("name","zhangsan");
// 获取域对象
String name = (String) servletContext.getAttribute("name");
// 移除域对象
servletContext.removeAttribute("name");
Servlet的三⼤域对象
1.request域对象
在⼀次请求中有效。请求转发有效,重定向失效。
2.session域对象
在⼀次会话中有效。请求转发和重定向都有效,session销毁后失效。
3.servletContext域对象
在整个应⽤程序中有效。服务器关闭后失效。
11. ⽂件上传和下载
在上⽹的时候我们常常遇到⽂件上传的情况,例如上传头像、上传资料等;当然除了上传,遇⻅下载
的情况也很多,接下来看看我们 servlet 中怎么实现⽂件的上传和下载。
⽂件上传
⽂件上传涉及到前台⻚⾯的编写和后台服务器端代码的编写,前台发送⽂件,后台接收并保存⽂件,
这才是⼀个完整的⽂件上传
前台⻚⾯
在做⽂件上传的时候,会有⼀个上传⽂件的界⾯,⾸先我们需要⼀个表单,并且表单的请求⽅式为
POST;其次我们的 form 表单的 enctype 必须设为"multipart/form-data",即
enctype=“multipart/form-data”,意思是设置表单的类型为⽂件上传表单。默认情况下这个表单类
型是 “application/x-www-form-urlencoded”, 不能⽤于⽂件上传。只有使⽤了multipart/form-data 才
能完整地传递⽂件数据。
<!--
⽂件上传表单
表单提交类型 method="post"
表单类型 enctype="multipart/form-data"
表单元素类型 ⽂件域设置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/formdata 的 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属性的值,则使
⽤设置的值做为⽂件名。当⽤户打开浏览器点击链接的时候就会直接下载⽂件。
后台实现下载
实现步骤
1.需要通过 response.setContentType ⽅法设置 Content-type 头字段的值, 为浏览器⽆法使⽤某
种⽅式或激活某个程序来处理的 MIME 类型,例 如 “application/octet-stream” 或"application/x-msdownload" 等。
2.需要通过 response.setHeader ⽅法设置 Content-Disposition 头的值 为 “attachment;filename=
⽂件名”
3.读取下载⽂件,调⽤ 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("⽂件不存在,下载失败!");
}
}
}