1.HTTP协议
HTTP协议(Hypertext Transfer Protocol, 超文本传输协议),是一个客户端请求和响应的标准协议,这个协议详细规定了浏览器和万维网服务器之间互相通信的规则。
通信规则规定了客户端发送给服务器的内容格式,也规定了服务器发送给客户端的内容格式。客户端发送给服务器的格式叫"请求协议";服务器发送给客户端的格式叫"响应协议"。
1.2书写格式
告诉我规则 给我想要的内容
HTTP:// 127.0.0.1:8080 / myweb/servlet01 ? name=zhangsan
1.3HTTP协议的特点
1.支持客户/服务器模式
2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的 有 GET、POST。
3.灵活:HTTP 允许传输任意类型的数据对象。传输的类型由Content-Type加以标记。
4.无连接:无连接是表示每次连接只处理一个请求。
5.无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。
1.4HTTP请求
HTTP请求由三部分组成,分别是:请求行、请求头、请求正文。
通过Chrome浏览器,F12——>Network查看。
1.Get请求(没有请求体)。
2.Post请求
格式:
method 表示请求方法;
Request-URL是一个统一资源标识符;
HTTP-Version表示请求的HTTP协议版本;
CRLF表示回车和换行;
1.5HTTP响应
格式:
状态行
响应头1
响应头2
...
响应空行
响应体
1.6消息头
HTTP 消息由客户端到服务器的请求和服务器到客户端的响应组成。
每一个报头域都是由 名字+":"+空格+值 组成,消息报头域的名字是大小写无关的。
请求头
请求报头允许客户端向服务器端传递请求的附加信息以及客户端自身的信息。
- Referer:该请求头指明请求从哪里来 。
响应头
响应报头允许服务器传递不能放在状态行中的附加响应信息,以及关于服务器的信息和 对 RequestURI 所标识的资源进行下一步访问的信息。
- Location:Location响应报头域用于重定向接受者到一个新的位置。
Location响应报头域,常用在更换域名的时候。
response.sendRedirect("http://www.baidu.com");
- Refresh:自动跳转(单位是秒),可以在页面通过meta标签实现,也可在后台实现。
<meta http-equiv="refresh" content="3;url=http://www.baidu.com">
2.Tomcat服务器
2.1什么是Tomcat
Tomcat 是一个符合 JavaEE WEB 标准的最小的 WEB 容器,所有的 JSP 程序一定要有 WEB 容器的支持才能运行,而且在给定的 WEB 容器里面都会支持事务处理操作。
Tomcat 简单的说就是一个运行 Java 的网络服务器,底层是 Socket 的一个程序,它也是 JSP 和 Servlet 的一个容器。是目前比较流行的 Web 应用服务器。
2.2安装Tomcat
运行 Tomcat 需要 JDK 的支持【Tomcat 会通过 JAVA_HOME 找到所需要的 JDK】。 安装就是解压缩过程。启动 Tomcat,能访问则算安装好了
1.解压Tomcat8的压缩包
2.解压后目录结构物
3.启动 Tomcat (在 tomcat 的安装目录下的 bin 目录 使用命令行启动 tomcat)
方式一:双击脚本文件启动
方式二:使用脚本命令启动
-
服务器启动成功
1. Tomcat默认占用端口8080。(注意端口冲突问题) 2. 如果需要使用服务器,启动成功后,该启动窗口不要关闭。
-
打开浏览器,输入http://localhost:8080/ 访问
-
调用 shutdown 命令关闭Tomcat服务器
2.3Tomcat目录结构
- bin:启动和关闭 tomcat 的 bat 文件
- conf:配置文件server.xml 该文件用于配置 server 相关的信息,比如 tomcat 启动的端口号,配置主机(Host) ;web.xml 文件配置与 web 应用(web 应用相当于一个 web站点);tomcatuser.xml 配置用户名密码和相关权限
- lib:该目录放置运行 tomcat 运行需要的 jar
- logs:存放日志,当我们需要查看日志的时候,可以查询信息
- webapps:放置我们的 web 应用
- work 工作目录:该目录用于存放 jsp 被访问后生成对应的 server 文件和.class 文件
3.Servlet
Servlet是Sever与Applet的缩写,是服务端小程序的意思。使用Java语言编写的服务器端程序,可以生成动态的WEB页,Servlet主要运行在服务端,并由服务器调用执行,是一种按照Servlet标准来开发的类。
3.1实现Servlet
3.1.1实现Servlet规范
实现 Servlet 规范,即继承 HttpServlet 类,并到如响应的包,该类中已经完成了通信的规则,我们只需要进行业务的实现即可。
package com.xxxx.servlet;
import javax.servlet.http.HttpServlet;
public class Servlet01 extends HttpServlet {
}
3.1.2重写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");
}
}
3.1.3设置注解
在完成好了一切代码的编写后,还需要向服务器说明,特定请求对应特定资源。 开发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'})
3.2Servlet的工作流程
- 通过请求头获知浏览器访问的是哪个主机
- 再通过请求行获取访问的是哪个一个web应用
- 再通过请求行中的请求路径获知访问的是哪个资源
- 通过获取的资源路径在配置中匹配到真实的路径,
- 服务器会创建servlet对象,(如果是第一次访问时,创建servlet实例,并调用init方法进行初始化操作)
- 调用service(request, response)方法来处理请求和响应的操作
- 调用service完毕后返回服务器 由服务器讲response缓冲区的数据取出,以http响应的格式发送给浏览器
3.4Servlet的生命周期
Servlet没有 main()方法,不能独立运行,它的运行完全由 Servlet 引擎来控制和调度。 所谓生命周期,指的是 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 类加载–>实例化–>服务–>销毁。
4.HttppServletRequest对象
HttpServletRequest 对象:主要作用是用来接收客户端发送过来的请求信息。
HttpServletRequest 是 ServletRequest 的子接口,ServletRequest 只有一个子接口,就是 HttpServletRequest。
4.1.接受请求
4.1.1常用方法
1.方法
getRequestURL() | 获取客户端发出请求时的完整URL |
---|---|
getRequestURL() | 获取请求行中的资源名称部分(项目名称开始) |
getQueryString() | 获取请求航中的参数部分 |
getMethod() | 获取客户端请求方式 |
getProtocol() | 获取HTTP版本号 |
getContextPath() | 获取webapp名字 |
2.示例
// 获取客户端请求的完整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);
4.1.2. 获取请求参数
1.方法
getParameter(name)() | 获取指定名称的参数 |
---|---|
getParameterValues(String name) | 获取指定名称参数的所有值 |
2.示例
// 获取指定名称的参数,返回字符串
String uname = request.getParameter("uname");
System.out.println("uname的参数值:" + uname);
// 获取指定名称参数的所有参数值,返回数组
String[] hobbys = request.getParameterValues("hobby");
System.out.println("获取指定名称参数的所有参数值:" + Arrays.toString(hobbys));
4.2.请求乱码问题
要想解决这种乱码问题,需要设置 request 中的编码方式,告诉服务器以何种方式来解析数据。
方式一:
request.setCharacterEncoding("UTF-8");
这种方式只针对 POST 有效(必须在接收所有的数据之前设定)
方式二:
new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
借助了String 对象的方法,该种方式对任何请求有效,是通用的。
Tomcat8起,以后的GET方式请求是不会出现乱码的。
4.3.请求转发
请求转发,是一种服务器的行为,当客户端请求到达后,服务器进行转发,此时会将请求对象进行保存,地址栏中的 URL 地址不会改变,得到响应后,服务器端再将响应发送给客户端,从始至终只有一个请求发出。
request.getRequestDispatcher(url).forward(request,response);
4.4.request作用域
通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,即服务器跳转有效。
// 设置域对象内容
request.setAttribute(String name, String value);
// 获取域对象内容
request.getAttribute(String name);
// 删除域对象内容
request.removeAttribute(String name);
5.HttpServletResponse对象
Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。向客户端输出数据,需要通过 response 对象。
5.1响应数据
有两种形式:
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
5.2. 响应乱码问题
getWriter()的字符乱码
对于 getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO8859-1 格式的编码,该编码方式并不支持中文。
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");
5.3. 重定向
重定向是一种服务器指导,客户端的行为。客户端发出第一个请求,被服务器接收处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址 response.sendRedirect(url);),当客户端接收到响应后,会立刻、马上、自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。
// 重定向跳转到
index.jspresponse.sendRedirect("index.jsp");
5.4请求转发与重定向的区别
请求转发 | 重定向 |
---|---|
请求一次 | 请求两次 |
服务器端行为 | 客户端行为 |
转发地址栏不变 | 重定向地址栏改变 |
转发不可跨域 | 重定向可跨域 |
6.Cookie对象
Cookie是浏览器提供的一种技术,作用是回话跟踪。
Cookie 的格式:键值对用“=”链接,多个键值对间通过“;”隔开。
6.1. Cookie的创建和发送
// 创建Cookie对象
Cookie cookie = new Cookie("uname","zhangsan");
// 发送Cookie对象
response.addCookie(cookie);
F12查看
6.2. 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());
}
}
6.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);
6.4. 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());
3.同名Cookie问题如果服务器端发送重复的Cookie那么会覆盖原有的Cookie。
4.浏览器存放Cookie的数量不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合Session来实现回话跟踪。
7.文件上传和下载
在上网的时候我们常常遇到文件上传的情况,例如上传头像、上传资料等;当然除了上传,遇见下载的情况也很多,接下来看看我们 servlet 中怎么实现文件的上传和下载。
7.1. 文件上传
文件上传涉及到前台页面的编写和后台服务器端代码的编写,前台发送文件,后台接收并保存文件,这才是一个完整的文件上传。
7.1.1. 前台页面
在做文件上传的时候,会有一个上传文件的界面,首先我们需要一个表单,并且表单的请求方式为 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>
7.1.2. 后台实现
使用注解 @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.HttpSeletResponse;
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);
}
}
7.2. 文件下载
文件下载,即将服务器上的资源下载(拷贝)到本地,我们可以通过两种方式下载。第一种是通过超链接本身的特性来下载;第二种是通过代码下载。
7.2.1. 超链接下载
当我们在 HTML 或 JSP 页面中使用a标签时,原意是希望能够进行跳转,但当超链接遇到浏览器不识别的资源时会自动下载;当遇见浏览器能够直接显示的资源,浏览器就会默认显示出来,比如 txt、png、jpg 等。当然我们也可以通过 download 属性规定浏览器进行下载。但有些浏览器并不支持。
默认下载
<!-- 当超链接遇到浏览器不识别的资源时,会自动下载 -->
<a href="test.zip">超链接下载</a>
指定 download 属性下载
<!-- 当超链接遇到浏览器识别的资源时,默认不会下载。通过download属性可进行下载 -->
<a href="test.txt" download>超链接下载</a>
11.2.2. 后台实现下载
实现步骤
- 需要通过 response.setContentType 方法设置 Content-type 头字段的值, 为浏览器无法使用某种方式或激活某个程序来处理的 MIME 类型,例 如 “application/octet-stream” 或 “application/xmsdownload” 等。
- 需要通过 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("文件不存在,下载失败!");
}
}
}