Servlet中的HttpRequest、HttpResponse、Cookie、Session对象
本文最后更新于:2 小时前
Request对象
常用方法
package cn.edu.neusoft;
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("/ServletRequest")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*常用方法*/
String url = request.getRequestURL() + "";
System.out.println("获取请求时的完整路径: " + url);
String uri = request.getRequestURI();
System.out.println("获取请求时的部分路径: " + uri);
String queryString = request.getQueryString();
System.out.println("获取请求时的参数字符串: " + queryString);
String method = request.getMethod();
System.out.println("获取请求时的请求方式: " + method);
String protocol = request.getProtocol();
System.out.println("获取当前协议版本: " + protocol);
String webapp = request.getContextPath();
System.out.println("获取请求时的项目站点名(项目对外访问路径): " + webapp);
/**
* getParameter(name) 获取指定名称的参数
* getParameterValues(name) 获取指定名称参数的所有值,用于复选框
*/
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
System.out.println("uname = " + uname);
System.out.println("upwd = " + upwd);
String[] languages = request.getParameterValues("languages");
if ( languages != null && languages.length > 1 ) {
for ( String language : languages ) {
System.out.println("language: " + language);
}
}
}
}
在浏览器传入参数后
http://localhost:8080/ServletRequest/ServletRequest?uname=admin&upwd=123&languages=Java&languages=JavaScript&languages=Rust
在IDEA中打印如下
请求乱码问题
乱码原因:在解析过程中默认使用的编码方式为 ISO-8859-1 这种不支持中文的编码方式,所以解析时一定会出现乱码
Tomcat8及以上版本 | Tomcat7及以下版本 | |
---|---|---|
GET请求 | 不会乱码 | 乱码 |
POST请求 | 乱码 | 乱码 |
乱码情况:POST请求不论什么版本的服务器,中文都会乱码
解决方式:
request.setCharacterEncoding("UTF-8");//这种方式只针对POST请求才有效
针对Tomcat7及以下版本的GET请求乱码解决方式:
用的很少,仅做了解
这种方式针对任意请求的乱码都有效,但设计编码格式转换的问题,如果本身不乱码,使用这种方式转换则会出现另外的乱码问题
String name = new String(request.getParameter("uname").getBytes("ISO-8859-1"), "UTF-8");
package cn.edu.neusoft;
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("/Servlet02")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");//这种方式只针对POST请求才有效
//获取客户端传递的参数
String uname = request.getParameter("uname");
String upwd = request.getParameter("upwd");
System.out.println("uname: " + uname);
System.out.println("upwd: " + upwd);
//解决Tomcat7及以下版本的GET请求乱码
String name = new String(request.getParameter("uname").getBytes("ISO-8859-1"), "utf-8");
System.out.println("name: " + name);
}
}
请求转发
可以让请求从服务端跳转到客户端,或者跳转到指定Servlet
request.getRequestDispatcher("url").forward(request, response);
特点:
- 服务端行为
- 地址栏不发生改变
- 从始至终只有一个请求
- request数据可以共享
package cn.edu.neusoft;
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("/s03")
public class Servlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收客户端参数
String uname = request.getParameter("uname");
System.out.println("Servlet03 uname: " + uname);
//请求转发跳转到Servlet04
// request.getRequestDispatcher("s04").forward(request, response);
//请求转发跳转到jsp页面
// request.getRequestDispatcher("login.jsp").forward(request, response);
//请求转发跳转到html页面
request.getRequestDispatcher("login.html").forward(request, response);
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>Hello</h2>
</body>
</html>
作用域
通过该对象可以在一个请求中传递数据,作用范围:在一次请求中有效,服务器跳转有效(请求转发跳转时有效)
Servlet05
package cn.edu.neusoft;
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;
import java.util.ArrayList;
import java.util.List;
/**
* request作用域
*/
@WebServlet("/s05")
public class Servlet05 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet05");
//设置域对象
request.setAttribute("name", "admin");
request.setAttribute("age", 18);
List<String> list = new ArrayList<>();
list.add("aaa");
list.add("bbb");
request.setAttribute("list", list);
//请求转发跳转到Servlet06
// request.getRequestDispatcher("s06").forward(request, response);
//请求转发跳转到jsp,并通过域对象传输数据
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
Servlet06
package cn.edu.neusoft;
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;
import java.util.ArrayList;
import java.util.List;
@WebServlet("/s06")
public class Servlet06 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Servlet06");
//获取域对象内容
String name = (String) request.getAttribute("name");
System.out.println("name: " + name);
Integer age = (Integer) request.getAttribute("age");
System.out.println("age: " + age);
List<String> list = (List<String>) request.getAttribute("list");
for ( String str : list ) {
System.out.println(str);
}
}
}
index.jsp
<%@ page import="java.util.List" %><%--
Created by IntelliJ IDEA.
User: QiuQian
Date: 2020/11/7
Time: 17:19
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h2>index页面</h2>
<%-- 如果要在jsp中写Java代码,需要卸载脚本段中--%>
<%
//获取对象
//获取域对象内容
String name = (String) request.getAttribute("name");
System.out.println("name: " + name);
Integer age = (Integer) request.getAttribute("age");
System.out.println("age: " + age);
List<String> list = (List<String>) request.getAttribute("list");
for ( String str : list ) {
System.out.println(str);
}
%>
</body>
</html>
Response对象
HttpServletResponse的主要功能用于服务器对客户端的请求进行响应,将Web服务器处理后的结果返回给客户端。service()方法中的形参接收的是HttpServletResponse接口的实例化对象,这个对象中封装了向客户端发送数据、发送响应头、发送响应状态码的方法。
响应数据
字符流/字节流只能使用其中一种,如果同时使用会报错
package cn.edu.neusoft;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 响应数据
* 字符流/字节流只能使用其中一种,如果同时使用会报错
*/
@WebServlet("/s01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取字符输出流
// PrintWriter printWriter = response.getWriter();
//输出数据
// printWriter.write("Hello");
//得到字节输出流
ServletOutputStream servletOutputStream = response.getOutputStream();
//输出数据
servletOutputStream.write("hi".getBytes());
}
}
响应乱码问题
在响应中,如果响应的内容含有中文,有可能出现乱码。因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,客户端也存在一种编码方式,当两端使用的编码方式不同,则会出现乱码。
字符流乱码
对于getWrite()获取到的字符流,响应中文一定会出现乱码,由于服务器端在进行编码时会默认使用 ISO-8859-1 格式的编码,该编码方式不支持中文。
要解决这种乱码,只能在服务器端告知服务器使用一种能够支持中文的编码格式,比如常用的”UTF-8”
response.setCharacterEncoding("UTF-8");
此时还只完成已一半的工作,要保证数据正确显示,还需要指定客户端的解码方式
response.setHeader("content-type", "text/html;charset=UTF-8");
两端指定编码后,乱码就解决了。
总结:保证发送端和接收端的编码保持一致!
Servlet02
package cn.edu.neusoft;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 字符流响应数据
*/
@WebServlet("/s02")
public class Servlet02 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//设置服务端的编码格式
response.setCharacterEncoding("UTF-8");
//设置客户端的解码格式和响应的MIME类型
response.setHeader("content-type", "text/html;charset=UTF-8");
//获取字符输出流
PrintWriter printWriter = response.getWriter();
//输出数据
printWriter.write("<h2>秋千</h2>");
}
}
Servlet03
package cn.edu.neusoft;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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("/s03")
public class Servlet03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//同时设置客户端和服务端的编码格式
response.setContentType("text/html;charset=UTF-8");
//得到字节输出流
ServletOutputStream servletOutputStream = response.getOutputStream();
//输出数据
servletOutputStream.write("<h2>你好</h2>".getBytes("UTF-8"));
}
}
还有一种方式可以同时设置客户端和服务端的编码格式
response.setContentType("text/html;charset=UTF-8");
字节流乱码
对于getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节,所以此时可能会出现乱码,也可能显示正确。当服务端给的字节恰好和客户端使用的编码格式一致时,文本显示正确,否则出现乱码。无论如果,我们都应该准确掌握服务器和客户端使用的是哪种编码格式,以确保数据显示正确
同时设置客户端和服务端的编码格式
不管服务器和客户端使用的是什么编码格式,全都自己指定!我命由我不由服务器和客户端!
response.setContentType("text/html;charset=UTF-8");
重定向
重定向是一种服务器指导客户端的行为。客户端发出第一个请求,被服务器接受处理后,服务器会进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址 response.sendRedirect(url); ),当客户端接收到响应后,会立刻自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。
从描述中可以看出重定向中有两个请求存在,并且属于客户端行为
///重定向跳转到index.jsp
response.sendRedirect("index.jsp");
通过观察浏览器我们发现第一次请求获得的响应码为302,并且含有一个location头信息。并且地址栏最终看到的地址是和第一次请求地址不同的,地址栏已经发生了变化。
Servlet04
package cn.edu.neusoft;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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("/s04")
public class Servlet04 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet04...");
//重定向跳转到Servlet05
response.sendRedirect("s05");
//接收参数
String uname = request.getParameter("uname");
System.out.println("S04_uname: " + uname);
}
}
Servlet05
package cn.edu.neusoft;
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("/s05")
public class Servlet05 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet05...");
//接收参数
String uname = request.getParameter("uname");
System.out.println("S05_uname: " + uname);
}
}
在浏览器传入参数
http://localhost:8080/Test2/s04?uname=admin
控制台打印结果
这个因为重定向存在两次请求!在Servlet04中,request对象是一个新的;Servlet05中也是一个新的
总结:重定向也是一种简单的跳转方式,只是这种跳转方式相对于请求转发而言,地址栏会发生变化,而且会有两次请求,数据无法共享
请求转发与重定向的区别
- 请求转发的地址栏不会发生改变,重定向的地址栏会发生改变
- 请求转发只有一次请求,重定向有两次
- 请求转发时request对象可共享,重定向是request对象不共享
- 请求转发是服务端行为,重定向是客户端行为
- 请求转发时的地址只能是当前站点下的资源,重定向可以是任何地址
Cookie对象
Cookie是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端进行处理的数据,放在本地的计算机上,不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于Cookie是服务器端保存在客户端的信息,所以其安全性也是很差的。例如常见的记住密码则可以通过Cookie来实现。
有一个专门操作Cookie的类javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存在浏览器。当下次再访问服务器时把Cookie再带回服务器。Cookie的格式:键值对用“=”链接,多个键值对间通过” ; “隔开。
Cookie的创建和发送
package com.xxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie的创建和发送
*/
@WebServlet("/coo01")
public class Cookie01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse resposne) throws ServletException, IOException {
//Cookie的创建
Cookie cookie = new Cookie("name", "admin");
//响应Cookie
resposne.addCookie(cookie);
}
}
Cookie获取
package com.xxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie的获取
* 返回的是Cookie数组
*/
@WebServlet("/coo02")
public class Cookie02 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse resposne) throws ServletException, IOException {
//获取Cookie数组
Cookie[] cookies = request.getCookies();
//判断Cookie是否为空
if ( cookies != null && cookies.length > 0 ) {
for ( Cookie cookie : cookies ) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println("名称: " + name + ", 值: " + value);
}
}
}
}
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。
package com.xxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie的到期时间
*/
@WebServlet("/coo03")
public class Cookie03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse resposne) throws ServletException, IOException {
//创建cookie
Cookie cookie = new Cookie("uname", "zhangsan");
//设置存活时间
cookie.setMaxAge(-1);//关闭浏览器失效
//响应cookie
resposne.addCookie(cookie);
//创建cookie
Cookie cookie2 = new Cookie("uname2", "lisi");
//设置存活时间
cookie2.setMaxAge(30);//存活30秒
//响应cookie
resposne.addCookie(cookie2);
//创建cookie
Cookie cookie3 = new Cookie("uname3", "wangwu");
//设置存活时间
cookie3.setMaxAge(0);//删除cookie
//响应cookie
resposne.addCookie(cookie3);
}
}
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对大小的限制在4kb左右
Cookie的路径
Cookie的setPath设置cookie的路径,这个路径直接决定服务器的请求是否会从浏览器中加载某些cookie。
package com.xxx.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie的路径
*/
@WebServlet("/coo05")
public class Cookie05 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse resposne) throws ServletException, IOException {
/* 当前服务器下任何项目的任意资源都可获取Cookie对象 */
Cookie cookie1 = new Cookie("cookie01", "cookie01");
cookie1.setPath("/");
resposne.addCookie(cookie1);
/* 当前项目下的资源可获取Cookie对象(默认不设置Cookie的path或设置为当前站点名) */
Cookie cookie2 = new Cookie("cookie02", "cookie02");
cookie2.setPath("/Cookie");//当前站点名
resposne.addCookie(cookie2);
/* 指定项目下的资源可获取Cookie对象 */
Cookie cookie3 = new Cookie("cookie03", "cookie03");
cookie3.setPath("/LoginServlet");//设置指定项目的站点名
resposne.addCookie(cookie3);
/* 指定目录下的资源可获取Cookie对象 */
Cookie cookie4 = new Cookie("cookie04", "cookie04");
cookie4.setPath("/Cookie/coo02");//设置指定项目的站点名
resposne.addCookie(cookie4);
}
}
在LoginServlet中访问的Cookie
如果我们设置path,如果当前访问的路径包含了cookie的路径(当前访问路径在cookie路径基础上要比cookie的范围小) cookie就会加载到request对象之中。
cookie的路径指的是可以访问该cookie的顶层目录,该路径的子路径也可以访问该cookie。
总结:当访问的路径包含了cookie的路径时,则该请求将带上该cookie;如果访问路径不包含cookie路径,则该请求不会携带该cookie
Session对象
HttpSession对象是javax.servlet.http.HttpSession的实例,该接口并不像HttpServletRequest或HttpServletResponse还存在一个父接口,该接口只是一个纯粹的接口。这因为session本身就属于HTTP协议的范畴。
对于服务器而言,每一个连接到它的客户端都是一个session,servlet容器使用此接口创建HTTP客户端和HTTP服务器之间的会话。会话将保留指定的时间段,跨多个连接或来自用户的页面请求。一个会话通常对应于一个用户,该用户可能多次访问一个站点。可以通过此接口查看和操作有关某个会话的信息,比如会话标识符、创建时间和最后一次访问时间。在整个session 中,最重要的就是属性的操作。
session无论客户端还是服务器端都可以感知到,若重新打开一个新的浏览器,则无法取得之前设置的session,因为每一个session只保存在当前的浏览器当中,并在相关的页面取得。
Session的作用就是为了标识一次会话,或者说确认一个用户;并且在一次会话(一个用户的多次请求)期间共享数据。我们可以通过request.getSession()方法,来获取当前会话的session对象。
标识符JSESSIONID
Session既然是为了标识一次会话,那么此次会话就应该有一个唯一的标志,这个标志就是sessionld。
每当一次请求到达服务器,如果开启了会话(访问了session),服务器第一步会查看是否从客户端回传一个名为JSESSIONID的cookie,如果没有则认为这是一次新的会话,会创建一个新的session对象,并用唯一的sessionld为此次会话做一个标志。如果有JESSIONID这个cookie回传,服务器则会根据JSESSIONID这个值去查看是否含有id为JSESSION值的session对象,如果没有则认为是一个新的会话,重新创建一个新的session对象,并标志此次会话;如果找到了相应的session对象,则认为是之前标志过的一次会话,返回该session对象,数据达到共享。
这里提到一个叫做JSESSIONID的cookie,这是一个比较特殊的cookie,当用户请求服务器时,如果访问了session,则服务器会创建一个名为JSESSIONID,值为获取到的session(无论是获取到的还是新创建的)的sessionld的cookie对象,并添加到response对象中,响应给客户端,有效时间为关闭浏览器。
所以Session的底层依赖Cookie来实现。
package com.xxx.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 javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Session对象
* session对象的获取
* request.getSession();
* 当获取Session对象时,会先判断是否存在
* 存在,获取
* 不存在,创建Session对象
* 常用方法
* 获取session的会话标识符 getId();
* 获取session创建时间 getCreationTime();
* 获取session最后一次访问时间 getLastAccessedTime();
* 判断是否是新的session isNew();
*/
@WebServlet("/ser01")
public class Session01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session对象
HttpSession session = request.getSession();
//获取session的会话标识符
String id = session.getId();
System.out.println(id);
//获取session创建时间
System.out.println(session.getCreationTime());
//获取session最后一次访问时间
System.out.println(session.getLastAccessedTime());
//判断是否是新的session
System.out.println(session.isNew());
}
}
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的生命周期。
package com.xxx.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 javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Session域对象
* 请求转发
* 一次请求
* request作用域有效
* session作用域有效
* 重定向
* 两次请求
* request作用域无效
* session作用域有效
*/
@WebServlet("/ser02")
public class Session02 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* session域对象 */
//获取session对象
HttpSession session = request.getSession();
//设置域对象
session.setAttribute("uname", "admin");
session.setAttribute("upwd", "123456");
//移除域对象
session.removeAttribute("upwd");
/* request域对象 */
request.setAttribute("name", "zhangsan");
//请求转发跳转到index.jsp页面
// request.getRequestDispatcher("index.jsp").forward(request, response);
//重定向跳转到index.jsp页面
response.sendRedirect("index.jsp");
}
}
session对象的销毁
package com.xxx.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 javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* Session对象的销毁
*/
@WebServlet("/ser03")
public class Session03 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* session域对象 */
//获取session对象
HttpSession session = request.getSession();
//设置域对象
session.setAttribute("uname", "admin");
// //获取session最大不活动时间
// System.out.println("session最大不活动时间: " + session.getMaxInactiveInterval());
// //修改session最大不活动时间
// session.setMaxInactiveInterval(15);//15秒不失效
// System.out.println("session最大不活动时间: " + session.getMaxInactiveInterval());
//立即销毁
session.invalidate();
}
}
默认到期时间
当客户端第一次请求servlet并且操作session时,session对象生成,Tomcat中 session默认的存活时间为30min,即不操作界面的时间,一旦有操作,session会重新计时。
那么session的默认时间可以改么?答案是肯定的。
可以在Tomcat中的conf目录下的web.xml文件中进行修改。
自己设置到期时间
除了以上的修改方式外,我们也可以在程序中自己设定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();
关闭浏览器销毁
Session底层依赖Cookie对象, Cookie对象默认只在浏览器中存活,关闭浏览器即失效。
从前面的JESSION可知道,session的底层依赖cookie 实现,并且该cookie的有效时间为关闭浏览器,从而session在浏览器关闭时也相当于失效了(因为没有JSESSION再与之对应)。
//不操作
关闭服务器销毁
当关闭服务器时,session销毁。
Session失效则意味着此次会话结束,数据共享结束。
//不操作
Context对象
每一个web应用都有且仅有一个ServletContext对象,又称Application对象,从名称中可知,该对象是与应用程序相关的。在WEB容器启动的时候,会为每一个WEB应用程序创建一个对应的ServletContext对象。
该对象有两大作用,第一、作为域对象用来共享数据,此时数据在整个应用程序中共享;第二、该对象中保存了当前应用程序相关信息。例如可以通过getServerInfo()方法获取当前服务器信息,getRealPath(String path)获取资源的真实路径等。
对象的获取和常用方法
package com.xxx.servlet;
import javax.servlet.ServletContext;
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;
/**
* 获取ServletContext对象
*
*/
@WebServlet("/s01")
public class Servlet01 extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//通过request对象获取
ServletContext servletContext = request.getServletContext();
//通过session对象获取
ServletContext servletContext1 = request.getSession().getServletContext();
//通过ServletConfig对象获取
ServletContext servletContext2 = getServletConfig().getServletContext();
//直接获取
ServletContext servletContext3 = getServletContext();
//常用方法
//1.获取当前服务器的版本信息
String serverInfo = request.getServletContext().getServerInfo();
System.out.println("serverinfo: " + serverInfo);
//2.获取当前项目真实路径
String realPath = request.getServletContext().getRealPath("/");
System.out.println("realPath: " + realPath);
}
}
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销毁后失效
servletSession域对象
在整个应用程序中有效,服务器关闭后失效
域对象的选择:域范围越大,所占内存越多。在能够满足需求的情况下,尽可能选择域范围最小的。
文件上传
文件上传涉及到前台页面的编写和后台服务器端代码的编写,前台发送文件,后台接收并保存文件,这才是一个完整的文件上传。
在做文件上传的时候,会有一个上传文件的界面,首先我们需要一个表单,并且表单的请求方式为POST;其次我们的form表单的enctype必须设为”multipart/form-data”,即enctype=”multipart/form-data”,意思是设置表单的类型为文件上传表单。默认情况下这个表单类型是”application/x-www-form-urlencoded”,不能用于文件上传。只有使用了multipart/form-data才能完整地传递文件数据。
前端代码
文件上传:
1. 准备表单
2. **设置表单的提交方式为POST请求 method="post"**
3. **设置表单类型为文件上传表单 enctype="multipart/form-data"**
4. **设置文件提交的地址 action="uploadServlet"**
5. 准备表单元素
1. 普通的表单项 type="text"
2. 文件项 type="file"
6. 设置元素的name属性值**表单提交一定要设置表单元素的name属性值,否则后台无法接受数据!**
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form method="post" enctype="multipart/form-data" action="uploadServlet">
姓名: <input type="text" name="uname"> <br>
文件: <input type="file" name="myfile" > <br>
<button>提交</button>
</form>
</body>
</html>
后端代码
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 {
System.out.println("文件上传");
//设置请求的编码格式
request.setCharacterEncoding("UTF-8");
//获取普通表单项(获取参数)
String uname = request.getParameter("uname"); // 表单中表单元素的name属性值
System.out.println("uname: " + uname);
//获取Part对象(Servlet将multipart/form-data的POST请求封装成Part对象)
Part part = request.getPart("myfile"); // 表单中file文件域的name属性值
//通过Part对象得到上传的文件名
String cd = part.getHeader("Content-Disposition");
String fileName = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
System.out.println("fileName: " + fileName);
//得到文件存放的路径
String filePath = request.getServletContext().getRealPath("/");
System.out.println("filePath: " + filePath);
//上传文件到指定目录
part.write(filePath + "/" + fileName);
}
}
需要注意的是,在tomcat7及以上的环境下就没有part.getSubmittedFileName()这一方法,无法直接获取文件名,所以我们需要使用如下方法获取文件名
//通过Part对象得到上传的文件名
String cd = part.getHeader("Content-Disposition");
String fileName = cd.substring(cd.lastIndexOf("=")+2, cd.length()-1);
文件下载
超链接下载
当我们在HTML或JSP页面中使用a标签时,原意是希望能够进行跳转,但当超链接遇到浏览器不识别的资源时会自动下载;当遇见浏览器能够直接显示的资源,浏览器就会默认显示出来,比如txt、png、jpg等。当然我们也可以通过download 属性规定浏览器进行下载。但有些浏览器并不支持。
默认下载
<!-- 当超链接遇到浏览器不识别的资源时,会自动下载 -->
<a href="test.zip">超链接下载</a>
指定download属性下载
<!-- 当超链接遇到浏览器识别的资源时,默认不会下载。通过download属性可进行下载 -->
<a href="test.zip" download>超链接下载</a>
download属性可以不写任何信息,会自动使用默认文件名。如果设置了download属性的值,则使用设置的值作为文件名。当用户打开浏览器点击链接的时候,就会直接下载文件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件下载</title>
</head>
<body>
<!--
超链接下载:
当使用超链接(a标签)时,如果遇到浏览器能识别的资源,则会显示内容。否则会进行下载
download属性
通过download属性规定浏览器进行下载
-->
<!-- 浏览器能够识别的资源 -->
<a href="download/SQL.txt">文本文件</a>
<a href="download/test.jpg">图片文件</a>
<!-- 浏览器不能识别的资源 -->
<a href="download/test.zip">压缩文件</a>
<hr>
<a href="download/SQL.txt" download>文本文件</a>
<a href="download/test.jpg" download="kcb.jpg">图片文件</a>
</body>
</html>
下载文件需要在IDEA中的服务器配置中添加资源路径,才能够访问到资源
后台实现下载
代码有点小问题还未修复
实现步骤:
- 需要通过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.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
/**
* 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 {
System.out.println("文件下载...");
//设置请求编码格式
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//获取参数(下载文件名)
String fileName = request.getParameter("fileName");
System.out.println("fileName: " + fileName);
//参数的非空判断trim():去除字符串前后空格
if ( fileName == null || "".equals(fileName.trim()) ) {
response.getWriter().write("请输入要下载的文件名");
response.getWriter().close();
return ;
}
//得到图片存放的路径
String path = request.getServletContext().getRealPath("/download/");
System.out.println("path: " + path);
//通过路径得到file对象
File file = new File(path + fileName);
System.out.println("file: " + file);
//判断文件对象是否存在并且是一个标准文件
System.out.println(file.exists());
System.out.println(file.isFile());
if ( file.exists() && file.isFile() ) {
//设置相应类型(浏览器无法使用某种方式或激活某个程序来处理的MIME类型)
response.setContentType("application/x-msdownload");
//设置响应头
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
//得到file文件输入流
InputStream in = new FileInputStream(file);
//得到字节输出流
ServletOutputStream out = response.getOutputStream();
//定义一个byte数组
byte[] bytes = new byte[1024];
//定义一个长度
int len = 0;
//循环输出
while ( (len = in.read(bytes)) != -1 ) {
//输出
out.write(bytes, 0, len);
}
//关闭资源
out.close();
in.close();
}
else {
response.getWriter().write("文件不存在,请重试");
response.getWriter().close();
}
}
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!