一、HttpServletResponse对象
1.1 简介
Web服务器收到客户端的http请求,会针对每⼀次请求,分别创建⼀个⽤于代表请求的
request 对象和代表响应的 response 对象。
request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向
客户端输出数据,需要通过 response 对象。
1.2 响应数据
/**
* 响应数据
* getWriter() 获取字符流(只能响应回字符)
* getOutputStream() 获取字节流(能响应一切数据)
*
* 两种流不能同时使用!
*/
@WebServlet("/resp01")
public class Response01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/* // getWriter() 获取字符流(只能响应回字符)
//得到字符输出流
PrintWriter writer = resp.getWriter();
writer.write("你好");// 乱码 ??
writer.write("<h2>Hello<h2/>"); //原样输出 <h2>Hello<h2/>
//刷新
writer.flush();
//关闭
writer.close();*/
//getOutputStream() 获取字节流(能响应一切数据)
ServletOutputStream out = resp.getOutputStream();
out.write("你好".getBytes()); // 不乱吗 输出 你好
out.write("<h2>Hello<h2/>".getBytes());// <h2>Hello<h2/> 没有达到想要的效果 原本是想表示h2标签
out.flush();
out.close();
}
}
1.3 响应乱码问题
/**
* 响应乱码问题
* 这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。
*
* getWriter()
* 一定会乱码,因为服务器默认的解析编码是ISO-8859-1,该编码不支持中文
*
* getOutputStream()
* 可能乱码,当服务端的编码格式与客户端的编码不一致时,会出现乱码
*
* 解决方案:
* 1. 设置服务端的编码格式 response.setCharacterEncoding("UTF-8");
* 2. 设置客户端的编码格式 response.setHeader("content-type","text/html;charset=UTF-8");
*
* 3. 同时设置客户端和服务端的编码 resp.setContentType("text/html;charset=UTF-8");(重要)
*
* 总结:
* 设置客户端和服务端的编码格式保持一致,且支持中文。
* 响应json格式的数据时,设置响应类型为application/json
*
*/
@WebServlet("/resp02")
public class Response02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//同时设置客户端和服务端的编码 设置响应的数据类型是html格式
//resp.setContentType("text/html;charset=UTF-8");
/**
* 字符流
*/
/*//设置服务端的编码格式
resp.setCharacterEncoding("UTF-8");
//设置客户端的编码格式
resp.setHeader("content-type","text/html;charset=UTF-8");
// getWriter() 获取字符流(只能响应回字符)
// 得到字符输出流
PrintWriter writer = resp.getWriter();
writer.write("你好");//你好
writer.write("<h2>Hello</h2>");//Hello
writer.flush();
writer.close();*/
/**
* 字节流
*/
/* ServletOutputStream out = resp.getOutputStream();
out.write("你好".getBytes("UTF-8"));
out.write("<h2>Hello</h2>".getBytes());
out.flush();
out.close();*/
//设置响应的数据类型是json格式
resp.setContentType("application/json;charset=UTF-8");
ServletOutputStream out = resp.getOutputStream();
out.write("{\"userId\":1,\"uname\":\"admin\", \"upwd\":\"123456\"}".getBytes());
out.flush();
out.close();
}
}
1.4 重定向
重定向是⼀种服务器指导,客户端的⾏为。重定向当中有两个请求存在,并且属于客户端⾏为。
/**
* 重定向
*/
@WebServlet("/resp03")
public class Response03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 重定向跳转到index.jsp
//resp.sendRedirect("index.jsp");
// 重定向跳转到百度
resp.sendRedirect("https://www.baidu.com/");
}
}
1.5 请求转发与重定向的区别
二、Cookie对象
Cookie是浏览器提供的⼀种技术,通过服务器的程序能将⼀些只须保存在客户端,或者在
客户端进⾏处理的数据,放在本地的计算机上。
但是由于 Cookie 是服务器端保存在客户端的信息, 所以其安全性也是很差的。
Cookie 的格式:键值对⽤“=”链接,多个键值对间通过“;”隔开。
2.1 Cookie的创建和发送
通过 new Cookie(“key”,“value”);来创建⼀个 Cookie 对象,要想将 Cookie 随响应发送到
客户端,需要先添加到 response 对象中,response.addCookie(cookie);
此时该 cookie 对象则随着响应发送⾄了客户端。在浏览器上可以看⻅。
/**
* Cookie的创建与发送
* Cookie cookie = new Cookie("名称","值");
* response.addCookie(cookie对象);
*/
@WebServlet("/cook01")
public class Cookie01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("name","zhangsan");
//响应Cookie(发送cookie对象给客户端)
resp.addCookie(cookie);
Cookie cookie2 = new Cookie("name2","lisi");
resp.addCookie(cookie2);
}
}
2.2 Cookie的获取
在服务器端只提供了⼀个 getCookies()的⽅法⽤来获取客户端回传的所有 cookie 组成的
⼀个数组,如果需要获取单个 cookie 则需要通过遍历,getName()获取 Cookie 的名称,
getValue()获取 Cookie的值。
/**
* 获取COokie对象
* 通过request.getCookies()获取cookie对象,返回的是cookie数组
*
*/
@WebServlet("/cook02")
public class Cookie02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取cookie数组
Cookie[] cookies = req.getCookies();
//判断cookie是否存在
if(cookies != null && cookies.length > 0){
//遍历cookie数组
for(Cookie cookie : cookies){
if("name".equals(cookie.getName())){
System.out.println(cookie.getValue());
}
}
}
}
}
2.3 Cookie设置到期时间
/**
* Cookie的到期时间
* 到期时间,到期时间用来指定该 cookie 何时失效。默认为当前浏览器关闭即失效。
* 我们可以手动设定 cookie 的有效时间(通过到期时间计算),通过 setMaxAge(int time);方法设定 cookie 的最大有效时间,以秒为单位。
*
* maxAge的取值:
* 负整数,表示只在浏览器中存活
* 正整数,表示会存活指定秒数,关闭浏览器或关闭服务器都不影响
* 零,表示删除cookie
*
*/
@WebServlet("/cook03")
public class Cookie03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象
Cookie cookie = new Cookie("aa","AAA");
//负整数,表示浏览器关闭即失效
//cookie.setMaxAge(-1);
//正整数,表示会存活指定描数
//cookie.setMaxAge(15);
//零,表示删除cookie
cookie.setMaxAge(0);
//发送cookie对象
resp.addCookie(cookie);
//删除已有的cookie
Cookie cookie1 = new Cookie("bb","BBB");
cookie1.setMaxAge(0);
resp.addCookie(cookie1);
}
}
2.4 Cookie的注意点
1.Cookie保存在当前浏览器中。
在⼀般的站点中常常有记住⽤户名这样⼀个操作,该操作只是将信息保存在本机上,换电脑以后这些信息就⽆效了。⽽且 cookie 还不能跨浏览器。
2.Cookie存中⽂问题
/**
* Cookie存中文
* cookie不支持存中文
* 如果需要存中文,需要URLencoder.encode(name)进行编码;获取时URLdncoder.dncode(name)进行解码
*/
@WebServlet("/cook04")
public class Cookie04 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = "姓名";
String value = "张三";
//将中文通过URLencoder.encode(name)进行编码
name = URLEncoder.encode(name);
value = URLEncoder.encode(value);
//创建cookie对象
Cookie cookie = new Cookie(name,value);
//发送cookie对象
resp.addCookie(cookie);
// 获取时通过 URLDecoder.decode()来进行解码
//URLDecoder.decode(cookie.getName());
//URLDecoder.decode(cookie.getValue());
}
}
3.同名Cookie问题
/**
* Cookie同名问题
* 如果出现同名,后面的cookie会将前面的覆盖。(在domain和path相同的情况下)
*/
@WebServlet("/cook05")
public class Cookie05 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie对象(前面设置过同名的)
Cookie cookie = new Cookie("name2","wangwu");
//设置失效时间
cookie.setMaxAge(1000);
resp.addCookie(cookie);
}
}
4.浏览器存放Cookie的数量
不同的浏览器对Cookie也有限定,Cookie的存储有是上限的。Cookie是存储在客户端(浏览器)的,⽽且⼀般是由服务器端创建和设定。后期结合Session来实现回话跟踪。
2.5 Cookie的路径
Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中
加载某些cookie。
/**
* Cookie的路径
* 1. 在当前服务器中,任意资源都可访问
* 2. 当前项目下的资源可获取Cookie对象 (默认不设置Cookie的path)
* 3. 当前项目中指定目录下的资源可获取Cookie对象
* 4. 指定项目下的资源可获取Cookie对象
*
* 总结:只要请求的路径中包含Cookie的path值,才能获取到该cookie对象
*/
@WebServlet("/cook06")
public class Cookie06 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 当前项目下的资源可获取cookie对象(默认不设置cookie的path)
Cookie cookie01 = new Cookie("a1","A1");
resp.addCookie(cookie01);
// 在当前服务器中,任意资源都可访问
Cookie cookie02 = new Cookie("a2","A2");
cookie02.setPath("/");
resp.addCookie(cookie02);
// 指定目录下的资源可以获取Cookie对象
Cookie cookie03 = new Cookie("a3","A3");
cookie03.setPath("/s03/test/cook02");
resp.addCookie(cookie03);
// 指定项目下的资源可获取Cookie对象 (指定站点名)
Cookie cookie04 = new Cookie("a4","A4");
cookie04.setPath("/s04"); // 某一个项目的访问路径
resp.addCookie(cookie04);
}
}
三、HttpSession对象
session ⽆论客户端还是服务器端都可以感知到,若重新打开⼀个新的浏览器,则⽆法取
得之前设置的 session,因为每⼀个 session 只保存在当前的浏览器当中,并在相关的⻚⾯取得。
ssion 的作⽤就是为了标识⼀次会话,或者说确认⼀个⽤户;并且在⼀次会话(⼀个⽤户
的多次请求)期间共享数据。我们可以通过 request.getSession()⽅法,来获取当前会话的 session 对象。
@WebServlet("/se01")
public class Session01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session对象(如果session对象不存在,则新建session对象 如果session存在,则获取session对象)
HttpSession session = req.getSession();
//获取session的标识符
System.out.println(session.getId());
// 获取第一次访问时间
System.out.println(session.getCreationTime());
// 获取最后一次访问时间
System.out.println(session.getLastAccessedTime());
// 是否是新的session对象
System.out.println(session.isNew());
}
}
3.1 标识符 JSESSIONID
Session 既然是为了标识⼀次会话,那么此次会话就应该有⼀个唯⼀的标志,这个标志就
是sessionId。
所以 Session 的底层依赖 Cookie 来实现。
3.2 session域对象
Session ⽤来表示⼀次会话,在⼀次会话中数据是可以共享的,这时 session 作为域对象存在,可以通过 setAttribute(name,value) ⽅法向域对象中添加数据。
通过 getAttribute(name) 从域对象中获取数据,通过 removeAttribute(name) 从域对象中移除数据。
@WebServlet("/se02")
public class Session02 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取session对象 (如果session对象不存在,则新建session对象;如果session存在,则获取session对象
HttpSession session = req.getSession();
//设置session域对象(一次会话有效)
session.setAttribute("uname","admin");
//获取User对象
User user = new User(1,"张三","123456");
//将用户对象存到session作用域中
session.setAttribute("user",user);
//设置request作用域(一次请求有效)
req.setAttribute("name","zhangsan");
//请求转发(一次请求)
//req.getRequestDispatcher("se03").forward(req,resp);
//重定向(两次请求)
resp.sendRedirect("se03");
}
}
/**
* Session作用域
*/
@WebServlet("/se03")
public class Session03 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
//获取session作用域
String uname = (String)session.getAttribute("uname");
System.out.println("Session作用域:" + uname);
// 获取session作用域中的user对象
User user = (User) session.getAttribute("user");
System.out.println(user.toString());
// 获取request作用域
String name = (String) req.getAttribute("name");
System.out.println("request作用域:" + name);
}
}
3.3 session对象的销毁
/**
* Session的销毁
* 1. 默认到期时间
* Tomcat中默认到期时间是30分钟,单位分钟。可以在Tomcat的解压目录中的conf目录的web.xml中修改 session-config标签的值
* 2. 手动设置失效时间
* 单位是秒,通过 session.setMaxInactiveInterval(int) 来设定失效时间。通过getMaxInactiveInterval()获取当前失效时间。
* 3. 手动销毁
* session.invalidate();
* 4. 关闭浏览器
* session底层依赖cookie,cookie默认关闭浏览器失效。
* 5. 关闭服务器
*/
@WebServlet("/se04")
public class Session04 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取session对象
HttpSession session = req.getSession();
System.out.println(session.getId());
//1.默认到期时间
// 2. 手动设置失效时间
// 获取当前最大不活动时间
System.out.println("最大不活动时间:" + session.getMaxInactiveInterval());
//设置最大不活动时间
session.setMaxInactiveInterval(15);
System.out.println("修改后最大不活动时间:" + session.getMaxInactiveInterval());
// 3. 手动销毁
//session.invalidate();
// 4. 关闭浏览器
// 5. 关闭浏览器
}
}
四、ServletContext对象
每⼀个 web 应⽤都有且仅有⼀个ServletContext 对象,⼜称 Application 对象,从名称中
可知,该对象是与应⽤程序相关的。在 WEB 容器启动的时候,会为每⼀个 WEB 应⽤程
序创建⼀个对应的ServletContext 对象。
该对象有两⼤作⽤:
第⼀、作为域对象⽤来共享数据,此时数据在整个应⽤程序中共享。
第⼆、该对象中保存了当前应⽤程序相关信息。例如可以通过 getServerInfo() ⽅法获取当
前服务器信息 ,getRealPath(String path) 获取资源的真实路径等。
4.1 ServletContext对象的获取
@WebServlet("/con01")
public class Context01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过request获取对象
ServletContext servletContext = req.getServletContext();
//通过session获取
ServletContext servletContext1 = req.getSession().getServletContext();
//通过servletconfig对象获取
ServletContext servletContext2 = getServletConfig().getServletContext();
//常用方法
//获取服务器的版本信息
String serverInfo = servletContext.getServerInfo();
System.out.println("获取服务器的版本信息:" + serverInfo);
//获取项目的真实路径
String realPath = servletContext.getRealPath("/");
System.out.println("获取项目的真实路径:" + realPath);
}
4.2 ServletContext域对象
// 获取ServletContext对象
ServletContext servletContext = request.getServletContext();
// 设置域对象
servletContext.setAttribute("name","zhangsan");
// 获取域对象
String name = (String) servletContext.getAttribute("name");
// 移除域对象
servletContext.removeAttribute("name");
Servlet的三⼤域对象:
- request域对象
在⼀次请求中有效。请求转发有效,重定向失效。 - session域对象
在⼀次会话中有效。请求转发和重定向都有效,session销毁后失效。 - servletContext域对象
在整个应⽤程序中有效。服务器关闭后失效。
五、文件上传和下载
5.1 文件上传
前台⻚⾯:
<!--
通过表单实现文件上传的功能
1. 请求方式设置为POST method="post"
2. 文件上传表单要设置表单类型为二进制表单
普通表单 enctype="application/x-www-form-urlencoded"
二进制表单 enctype="multipart/form-data"
3. 设置文件上传的文件域,并设置name属性值
-->
<form action="uploadServlet" method="post" enctype="multipart/form-data">
文件:<input type="file" name="myfile"><br>
姓名:<input type="text" name="uname"><br>
<button>上传文件</button>
后台实现:
/**
* 文件上传
* 如果是文件上传表单(二进制表单),对应的Servlet需要添加注解 @MutlipartConfig
* 使用注解 @MultipartConfig 将一个 Servlet 标识为支持文件上传。
* Servlet 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。
*/
@WebServlet("/uploadServlet")
@MultipartConfig // 文件一定要加注解!!!
public class UploadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求的编码格式
req.setCharacterEncoding("UTF-8");
// 获取普通的表单项数据(获取参数)
String uname = req.getParameter("uname");
// 获取上传的文件
// 通过request.getPart(name)方法,获取Part对象; name代表的是表单中的file文件域的name属性值
Part part = req.getPart("myfile");
//获取上传文件的文件名
String fileName = part.getSubmittedFileName();
System.out.println("上传文件名:" + fileName);
//设置文件的存放路径(获取项目的真实路径)
String realPath = req.getServletContext().getRealPath("/upload/");
//上传文件
part.write(realPath + fileName);
}
}
5.2 文件下载
⽂件下载,即将服务器上的资源下载(拷⻉)到本地,我们可以通过两种⽅式下载。第⼀种是通过超链接本身的特性来下载;第⼆种是通过代码下载。
5.2.1 超链接下载
<!--
超链接下载
当浏览器遇到能够识别的资源,会进行跳转;
当浏览器遇到无法识别的资源,则会进行下载。
download属性
表示当前超链接的资源会被下载;
如果download属性没有设置属性值,则默认的下载名为为文件名;也可通过设置download属性的值来指定下载的文件名
-->
<!--浏览器能够识别的资源-->
<a href="index.jsp">JSP页面</a> <br>
<a href="upload.html">HTML页面</a> <br>
<a href="play.png">图片</a> <br>
<a href="test.txt">TXT文件</a> <br>
<!--浏览器不能够识别的资源-->
<hr>
<a href="红蜘蛛软件.lnk">快捷方式</a> <br>
<hr>
<!-- download属性-->
<a href="play.png" download>图片</a> <br>
<a href="test.txt" download="测试.txt">TXT文件</a> <br>
<hr>
<form action="downloadServlet">
要下载的文件名:<input type="text" name="fileName">
<button>下载</button>
</form>
</body>
</html>
5.2.2 后台实现下载
/**
* 文件下载
* 1. 需要通过 response.setContentType 方法设置 Content-type 头字段的值, 为浏览器无法使用某种方式或激活某个程序来处理的 MIME 类型,例 如 "application/octet-stream" 或 "application/x-msdownload" 等。
* 2. 需要通过 response.setHeader 方法设置 Content-Disposition 头的值 为 "attachment;filename=文件名"
* 3. 读取下载文件,调用 response.getOutputStream 方法向客户端写入附件内容。
*/
@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求的编码格式
request.setCharacterEncoding("UTF-8");
// 得到要下载的文件名
String fileName = request.getParameter("fileName");
// 得到文件所存放的路径(项目的存放路径)
String path = request.getServletContext().getRealPath("/");
// 通过路径得到file对象
File file = new File(path + "/" + fileName);
// 判断文件是否存在,且是一个标准文件
if (file.exists() && file.isFile()) {
// 如果文件存在,则下载
// 设置响应类型 (浏览器无法使用某种方式或激活某个程序来处理的类型)
response.setContentType("application/x-msdownload");
// 设置头信息
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
// 得到文件的输入流
InputStream inputStream = new FileInputStream(file);
// 得到字节输出流
ServletOutputStream outputStream = response.getOutputStream();
byte[] ch = new byte[1024];
int len = 0;
while((len = inputStream.read(ch)) != -1) {
outputStream.write(ch, 0 ,len);
}
outputStream.close();
inputStream.close();
} else {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("<h2>要下载的文件不存在,请重试!<a href='download.html'>返回下载</a></h2>");
response.getWriter().close();
}
}
}