文章目录
- JSON和AJAX文档介绍
- 1. JSON介绍
- 1.1 JSON快速入门
- 1.2 JSON和字符串转换
- 1.2.1 JSON转字符串
- 1.2.2 字符串转JSON
- 1.2.3 JSON和字符串转换细节
- 1.3 JSON在java中使用
- 1.3.1 Java对象和JSON字符串转换
- 1.3.2 List对象和JSON字符串转换
- 1.3.3 Map对象和JSON字符串转换
- 2. Ajax介绍
- 2.1 Ajax应用场景
- 2.2 传统的web应用-数据通信方式
- 2.3 Ajax-数据通信方式
- 2.4 Ajax文档使用
- 2.5 Ajax快速入门
- 2.5.1 验证用户是否存在-思路框架图
- 2.5.2 新建java项目
- 2.5.3 实现
- 2.6 接入数据库
- 3. jQuery操作Ajax
- 3.1 jQuery操作Ajax文档
- 3.2 jQuery.ajax()函数
- 3.3 $.get 和 $.post常用参数
- 3.4 jQuery.ajax()快速入门
- 3.4 jQuery.get()快速入门
- 3.5 jQuery.post()快速入门
- 3.6 jQuery.getJSON快速入门
- 3.7 接入数据库
- 4. ThreadLocal
- 4.1 什么是ThreadLocal?
- 4.2 ThreadLocal环境搭建
- 4.3 ThreadLocal快速入门
- 4.4 ThreadLocal源码阅读
- threadLocal.set()源码
- threadLocal.get()源码
- 5. 文件上传基本介绍
- 5.1 文件上传-原理示意图
- 5.2 文件上传页面
- 5.3 走通Servlet
- 5.4 表单项区别处理
- 5.5 创建目录-保存文件
- 5.6 中文编码问题
- 5.7 文件上传注意事项和细节
- 5.7.1 按照年月日目录存放
- 5.7.2 文件覆盖问题
- 5.7.3 封装一下
- 5.8 文件上传其他注意事项
- 5.8.1 upload文件夹为何要在out目录下直接创建
- 6. 文件下载基本介绍
- 6.1 原理示意图
- 6.2 走通Servlet
- 6.3 设置下载响应头
- 6.4 文件下载注意事项
JSON和AJAX文档介绍
在线文档
离线文档
1. JSON介绍
- JSON指的是JavaScript对象表示法(JavaScript Object Notation)
- JSON是轻量级的文本数据交换格式
- JSON独立于语言[即java, php, asp.net, go等都可以使用JSON]
1.1 JSON快速入门
JSON的定义格式
var 变量名 = {"k1" : value, //Number类型"k2" : "value", //字符串类型"k3" : [], // 数组类型"k4" : {}, //json对象类型"k5" : [{},{}] //json数组
};
var myJson = {"key1":"赵志伟", //字符串"key2":23, //Number"key3":[1,"hello",3.2], //数组"key4":{"age":23, "name":"赵志伟"}, //json对象"key5":[{"亚丝娜":"我的老婆", "桐谷和人":"我"},{"k1":23, "k2":"zzw"}]
};
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>json 快速入门案例</title><script type="text/javascript">/*1.myJson就是一个json对象2.演示如何获取到json对象的属性/key*/var myJson = {"key1": "赵志伟",//字符串"key2": 123,//Number"key3": [1, "hello", 2.3],//数组"key4": {"age": 12, "name": "jack"},//json对象"key5": [//json数组{"k1": 10, "k2": "apple"},{"k3": 30, "k4": "john"}]};//1.取出key1console.log("key1 = " + myJson.key1);//2.取出key3console.log("key3 = " + myJson.key3)// 可以对key3取出的值(Array)进行遍历for (var i = 0; i < myJson.key3.length; i++) {console.log("第%i个元素的值 = ", i, myJson.key3[i]);}//3.取出key4console.log("key4 = ", myJson.key4, "key4.name = " + myJson.key4.name);//4.取出key5console.log("key5 = ", myJson.key5, "k4 = " + myJson.key5[1].k4)</script>
</head>
<body>
</body>
</html>
1.2 JSON和字符串转换
1.2.1 JSON转字符串
- JSON.stringify(json): 将一个json对象转换为json字符串
- JSON.parse(jsonString): 将一个json字符串转化为json对象
1.2.2 字符串转JSON
1.2.3 JSON和字符串转换细节
- JSON.stringify(json对象)会返回json对象对应的String, 并不会影响原来的json对象
- JSON.parse(String)函数会返回对应的json的对象, 并不会影响原来的String
- 在定义json对象时, 可以使用双引号表示字符串, 也可以使用单引号表示字符串. key可以不用引号.
var personJson = {"name": "赵志伟","age": 23}var personJson = {'name': '赵志伟','age': 23}var personJson = {name: '赵志伟',age: 23}
- 但是在把原生字符串转成json对象时, 必须使用双引号"", 其他情况会报错
比如
var dogStr = “{‘name’:‘喵喵’, ‘age’:1}”;
➡JSON.parse(dogStr); 会报错
正确写法:
- JSON.stringify(json对象)返回的字符串(json对象->String), 都是双引号括起来的字符串, 所以在语法格式正确的情况下, 是可以重新转成json对象的(String->json对象)
1.3 JSON在java中使用
- 在java中使用json, 需要引入到第三方的包gson.jar
- Gson是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库
- 新建
- 引入gson.jar包
1.3.1 Java对象和JSON字符串转换
1.3.2 List对象和JSON字符串转换
public class JavaBean {public static void main(String[] args) {//创建一个gson对象, 作为一个工具对象使用Gson gson = new Gson();//3.演示把 List对象 -> json字符串List<Book> bookList = new ArrayList<>();bookList.add(new Book(2, "林北星"));bookList.add(new Book(3, "张万森"));//解读: 因为把一个 对象/集合 转成字符串, 相对比较简单//底层只需要遍历, 按照json格式拼接返回即可String bookListStr = gson.toJson(bookList);System.out.println("bookListStr= " + bookListStr);//4.演示把 json字符串 -> List对象//解读// (1)如果需要把json字符串 转成 集合这样复杂的类型, 需要使用gson提供的一个类// (2)TypeToken, 是一个自定义泛型类, 然后通过TypeToken来指定我们需要转换成的类型/*package com.google.gson.reflect;public class TypeToken<T> {final Class<? super T> rawType;final Type type;final int hashCode;protected TypeToken() {this.type = getSuperclassTypeParameter(this.getClass());this.rawType = Types.getRawType(this.type);this.hashCode = this.type.hashCode();}*///(1)返回的是类型的完整路径: java.util.List<com.zzw.json.Book>//(2)gson的设计者, 需要得到类型的完整路径, 然后在底层进行反射//(3)所以json设计者就提供了TypeToken来搞定//二说TypeToken [为什么要添加{} 涉及到内部类..]Type type = new TypeToken<List<Book>>() {}.getType();List<Book> bookList2 = gson.fromJson(bookListStr, type);System.out.println("bookList2 = " + bookList2);}
}
- 二说TypeToken
- 三说TypeToken
1.3.3 Map对象和JSON字符串转换
2. Ajax介绍
- AJAX即Asynchronous Javascript And XML(异步 JavaScript 和 XML)
- AJAX是一种浏览器异步发起请求(可以指定发送哪些数据), 局部更新页面的技术
2.1 Ajax应用场景
- 搜索引擎根据用户输入的关键字, 自动提示检索关键字
- 动态加载数据, 按需取得数据 [树形菜单, 联动菜单…]
- 改善用户体验 [输入内容前提示, 带进度条文件上传…]
- 电子商务应用 [购物车, 邮件订阅…]
- 访问第三方服务 [访问搜索服务, rss阅读器]
- 页面局部刷新, https://piaofang.maoyan.com/dashboard
2.2 传统的web应用-数据通信方式
2.3 Ajax-数据通信方式
2.4 Ajax文档使用
2.5 Ajax快速入门
2.5.1 验证用户是否存在-思路框架图
2.5.2 新建java项目
- 新建java项目
- 引入web框架
- 新建lib目录,并引入jar包
- 配置Tomcat
- 成功启动
2.5.3 实现
- 搭建框架
- 发送ajax请求[http请求]
- 后台接收并返回json格式的数据
- 前端得到数据, 通过dom操作, 进行页面局部刷新
- 测试
2.6 接入数据库
引入数据库进行验证
项目结构 粘贴自满汉楼项目
- 思维框架图
- User实体类-无参构造器
- UserDAO
- UserService
- CheckUserServlet
- 发现错误
解决方案
src是se方式下的路径, javaweb要用到类加载器
- 测试
3. jQuery操作Ajax
- 编写原生的Ajax要写很多的代码, 要考虑浏览器兼容的问题
- 在实际工作中, 一般使用JavaScript的库(比如Jquery)发送Ajax请求
3.1 jQuery操作Ajax文档
- 在线文档
- 离线文档
3.2 jQuery.ajax()函数
- $.ajax常用函数
$.ajax常用函数的位置
- url: 请求的地址
- type: 请求的方式get或post
- data: 发送到服务器的数据, 将自动转换为请求字符串格式
- success: 成功的回调函数
- error: 失败的回调函数
- dataType: 返回的数据类型 常用json和text
3.3 $.get 和 $.post常用参数
- url: 请求的URL地址
- data: 请求发送到服务器的数据
- success: 成功时回调函数
- type: 返回内容格式, xml.html.script.json.text
说明: $.get和$.post底层还是使用$.ajax()方法来实现异步请求
3.4 jQuery.ajax()快速入门
- 在web目录下引入jquery后, Rebuild Project一下
- 发送ajax请求[http请求]
- 后台接收并返回json格式的数据
- 测试
解决方案
- 后台接收并返回数据
- 前端获取
- 前端判断
测试
- 在div中显示内容
测试
3.4 jQuery.get()快速入门
- $.get()默认是get请求, 不需要再指定请求方式
- 不需要指定参数名
- 填写的实参, 是顺序的: url—data—success回调函数—dataType
- 没有提供error接口, 可以在success回调函数里根据status判断
3.5 jQuery.post()快速入门
操作: 只需把$.get改成$.post
$.post和$.get的方式一样, 只是这时, 是按照post方法发送ajax请求[本质是http请求]
- $.post()默认是post请求, 不需要再指定请求方式
- 不需要指定参数名
- 填写的实参, 是顺序的: url—data—success回调函数—dataType
- 没有提供error接口, 可以在success回调函数里根据status判断
3.6 jQuery.getJSON快速入门
$.getJSON常用参数
- url:请求发送的URL
- data: 请求发送到服务器的数据
- success: 请求成功时的回调函数
如果你通过jQuery发送的ajax请求[本质是http请求]是get请求, 并且返回的数据格式是JSON, 可以直接使用$.getJSON(). 简洁.
3.7 接入数据库
- 接入数据库
- 前端测试
4. ThreadLocal
4.1 什么是ThreadLocal?
- ThreadLocal的作用: 可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.
- ThreadLocal可以给当前线程关联一个数据(普通变量, 对象, 数据) - set方法
- ThreadLocal可以像Map一样存取数据, key为当前线程 - get方法
- 每一个ThreadLocal对象, 只能为当前线程关联一个数据. 如果要为当前线程关联多个数据, 就需要使用多个ThreadLocal对象实例
- 每个ThreadLocal对象实例定义的时候, 一般为static类型
- ThreadLocal中保存的数据. 在线程销毁时. 会自动释放
4.2 ThreadLocal环境搭建
现象->分析原理->看源码进一步理解
- 创建java项目
- ThreadLocal类图
- 开启线程
4.3 ThreadLocal快速入门
4.4 ThreadLocal源码阅读
threadLocal.set()源码
解读set源码
public void set (T value){//1.获取当前线程,关联到当前线程Thread t = Thread.currentThread();//2.通过线程对象, 获取到ThreadLocalMap, 是ThreadLocal的静态内部类// ThreadLocalMap的类型是: ThreadLocal.ThreadLocalMapThreadLocalMap map = getMap(t);//3.如果map不为空, 将数据(dog,pig...)放入map中, key:threadLocal, value:存放的数据// 从这个源码我们已然看出一个threadLocal只能关联一个数据, 如果再次set(), 就会替换//4. 如果map为空, 就创建一个和当前线程关联的ThreadLocalMap, 并且将该数据放入if (map != null) {map.set(this, value);} else {createMap(t, value);} }
debug1 存储
debug2 替换
debug3
threadLocal.get()源码
解读get源码
public T get() {//1.得到当前的线程对象Thread t = Thread.currentThread();//2.得到线程的threadLocals属性, 即ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null) {//3.如果线程的threadLocals不为空, 根据当前的threadLocal对象, 得到对应的EntryThreadLocalMap.Entry e = map.getEntry(this);//如果Entry不为空if (e != null) {@SuppressWarnings("unchecked")//返回当前的threadLocal关联的数据T result = (T)e.value;return result;}}return setInitialValue(); }
5. 文件上传基本介绍
- 文件的上传和下载, 是常见的功能
- 后面项目就使用了文件上传下载
- 如果是传输大文件, 一般用专门的工具或插件
- 文件上传下载需要使用两个包, 需要导入
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
5.1 文件上传-原理示意图
文件上传的解读
- 还是使用表单来提交
- action依然是按照以前的规定来确认
- method需指定为post
- enctype: 全称encodetype, 即编码类型. 默认是 application/x-www-form-urlencoded, 即url编码, 这种编码不适合于二进制文件的提交.
enctype要指定为 multipart/form-data, 即表示表单提交的数据有多个部分组成, 也就是说即可以提交二进制数据, 也可以提交文本数据
服务端要完成的工作 FileUploadServlet.java
- 判断是不是一个文件表单
- 判断表单提交的各个表单项是什么类型
- 如果是一个普通的表单项, 就按照文本的方式来处理
- 如果是一个文件表单项(二进制数据), 使用IO技术来处理
- 把表单提交的文件数据, 保存到你指定的服务端的某个目录
5.2 文件上传页面
新建项目, 导入web框架, 引入jar包, 配置Tomcat, 配置FileUploadServlet👉参考
<%--Created by IntelliJ IDEA.User: 赵志伟Version: 1.0--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!-- 指定了base标签 --><base href="<%=request.getContextPath()+"/"%>>"><style type="text/css">input[type="submit"] {outline: none;border-radius: 5px;cursor: pointer;background-color: #31B0D5;border: none;width: 70px;height: 35px;font-size: 20px;}img {border-radius: 50%;}form {position: relative;width: 200px;height: 200px;}input[type="file"] {position: absolute;left: 0;top: 0;height: 200px;opacity: 0;cursor: pointer;}</style><script type="text/javascript">function prev(event) {//获取展示图片的区域var img = document.getElementById("preView");//获取文件对象var file = event.files[0];//获取文件阅读器: Js的一个类, 直接使用即可var reader = new FileReader();read.readAsDataURL(file);reader.onload = function () {//给img的src设置图片urlimg.setAttribute("src", this.result)}}</script>
</head>
<body>
<%--表单的enctype属性要设置为multipart/form-dataenctype="multipart/form-data" 表示提交的数据是多个部分构成的. 有文件和文本--%>
<form action="fileUploadServlet" method="post" enctype="multipart/form-data">家居图: <img src="2.jpg" alt="" width="200" height="200" id="preView"><%--img是单标签, 后面不能加斜杠--%><input type="file" name="pic" id="" value="" onchange="prev(this)"/>家居名: <input type="text" name="name"><br/><input type="submit" value="上传"/>
</form>
</body>
</html>
5.3 走通Servlet
public class FileUploadServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("FileUpLoadServlet 被调用...");//1.判断是不是文件表单(enctype="multipart/form-data")if (ServletFileUpload.isMultipartContent(request)) {System.out.println("OK");//2.创建 DiskFileItemFactory 对象, 用于构建一个解析上传数据的工具对象DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();//3.创建一个解析上传数据的工具对象/*** <input type="file" name="pic" id="" value="" οnchange="prev(this)"/>* 家居名: <input type="text" name="name"><br/>* <input type="submit" value="上传"/>*/ServletFileUpload servletFileUpload =new ServletFileUpload(diskFileItemFactory);//4.关键代码, servletFileUpload 对象可以把表单提交的数据text/文件.// 将其封装到 FileItem 文件项中try {/**输出* list==>* [name=winner-autumn-2022 - 鍓湰.png,* StoreLocation=D:\Program Files\apache-tomcat-8.5.82\temp\\upload_62628cc5_1881341bf4c__7f85_00000000.tmp,* size=598521bytes, isFormField=false, FieldName=pic, name=null,* StoreLocation=D:\Program Files\apache-tomcat-8.5.82\temp\\upload_62628cc5_1881341bf4c__7f85_00000001.tmp,* size=6bytes, isFormField=true, FieldName=name]*/List<FileItem> list = servletFileUpload.parseRequest(request);System.out.println("list==>" + list);} catch (FileUploadException e) {throw new RuntimeException(e);}} else {System.out.println("不是文件表单...");}}
}
5.4 表单项区别处理
//4.关键代码, servletFileUpload 对象可以把表单提交的数据text/文件.
// 将其封装到 FileItem 文件项中
try {/**输出* list==>* [name=winner-autumn-2022 - 鍓湰.png,StoreLocation=D:\Program Files\apache-tomcat-8.5.82\temp\\upload_62628cc5_1881341bf4c__7f85_00000000.tmp,size=598521bytes, isFormField=false, FieldName=pic,* name=null,StoreLocation=D:\Program Files\apache-tomcat-8.5.82\temp\\upload_62628cc5_1881341bf4c__7f85_00000001.tmp, size=6bytes, isFormField=true, FieldName=name]*/List<FileItem> list = servletFileUpload.parseRequest(request);//System.out.println("list==>" + list);//遍历, 并分别处理for (FileItem fileItem : list) {//不知道是什么, 就输出看一下//System.out.println(fileItem);//判断是不是一个文件==>OOP程序员if (fileItem.isFormField()) {//如果为真,就是文本 input type="text"String name = fileItem.getString("utf-8");System.out.println("家居名= " + name);} else {//是一个文件//获取上传的文件的名字String name = fileItem.getName();System.out.println("上传的文件名= " + name);}}
} catch (FileUploadException e) {throw new RuntimeException(e);
}
} else {
System.out.println("不是文件表单...");
}
5.5 创建目录-保存文件
if (fileItem.isFormField()) {//如果为真,就是文本 input type="text"String name = fileItem.getString("utf-8");System.out.println("家居名= " + name);
} else {//是一个文件//获取上传的文件的名字String name = fileItem.getName();System.out.println("上传的文件名= " + name);//把上传到服务器 temp目录 下的文件保存到你指定的目录👉upload// 1.指定一个目录, 我们网站的工作目录下String filePath = "/upload/";// 2.获取完整的目录[io/servlet基础]// 这个目录是合你的web项目运行环境绑定的, 是动态的// fileRealPath= D:\idea_project\zzw_javaweb\fileupdown\out\artifacts\fileupdown_war_exploded\\upload\String fileRealPath =request.getServletContext().getRealPath(filePath);System.out.println("fileRealPath= " + fileRealPath);//3.创建这个上传的目录=>File fileRealPathDirectory = new File(fileRealPath);if (!fileRealPathDirectory.exists()) {//如果目录不存在, 就创建fileRealPathDirectory.mkdirs();//创建}//4.将文件拷贝到fileRealPathDirectory目录下// 构建了一个上传的文件的完整路径[目录+文件名], 这个路径由 目录+该文件的文件名 组成String fileFullPath = fileRealPathDirectory + "\\" + name;//这里必须加斜杠System.out.println("fileFullPath= " + fileFullPath);fileItem.write(new File(fileFullPath));//5.提示信息response.setContentType("text/html;charset=utf-8");PrintWriter writer = response.getWriter();writer.print("<h3>文件上传成功</h3>");
}
5.6 中文编码问题
5.7 文件上传注意事项和细节
5.7.1 按照年月日目录存放
- 如果将文件都上传到一个目录下, 当上传文件很多时, 会造成访问文件的速度变慢, 因此可以将文件上传到多个目录下.
比如: 一天上传的文件, 统一放到一个文件夹, 按照年月日格式, 比如👉20230513文件夹
手动更改时间 再次测试
工具类WebUtilspublic class WebUtils {public static void main(String[] args) {//测试代码System.out.println(getYearMonthDay());}public static String getYearMonthDay() {//第二代日期类CalendarCalendar calendar = Calendar.getInstance();int year = calendar.get(calendar.YEAR);int month = calendar.get(calendar.MONTH) + 1;//月份从0开始计算int day = calendar.get(calendar.DAY_OF_MONTH);String format = year + "/" + month + "/" + day + "/";// 2023/5/13///第三代日期类LocalDateTimeLocalDate now = LocalDate.now();year = now.getYear();month = now.getMonthValue();day = now.getDayOfMonth();format = year + "/" + month + "/" + day + "/";// 2023/5/13/return format;} }
5.7.2 文件覆盖问题
5.7.3 封装一下
把这部分代码摘出来封装进工具类里
5.8 文件上传其他注意事项
- 一个完美的文件上传, 要考虑的因素很多, 比如断点续传, 控制图片大小, 尺寸, 分片上传, 防止恶意上传等. 在项目中, 可以考虑使用WebUploader组件(百度开发👉https://fex.baidu.com/webuploader/doc/index.html).
- 文件上传功能, 在项目中建议有限制的使用, 一般用在头像, 证明, 合同, 产品展示等, 如果不加限制, 就会造成服务器空间被大量占用[比如微信发1次朋友圈最多9张图等].
5.8.1 upload文件夹为何要在out目录下直接创建
文件上传, 创建web/upload的文件夹. 在tomcat启动时, 没有在out目录下创建对应的upload文件夹. 其原因是tomcat对应空目录是不会在out下创建相应目录的. 所以, 只需在upload目录下放一个文件即可
- 这是web路径一个空文件夹, Tomcat启动后, 是不会在out/artifacts下创建相应目录的
- 如图, upload100文件夹下是有文件的, 那么在Tomcat启动后, out/artifacts下就会创建upload100目录
6. 文件下载基本介绍
6.1 原理示意图
响应头
- Content-Disposition: 表示下载的数据的展示方式. 比如内联形式(网页形式或者网页一部分), 或者是文件下载方式 attachment
- Content-type: 指定返回数据的类型MIME
响应体
- 在网络传输时是图片的原生数据(按照浏览器下载的编码)
6.2 走通Servlet
download.jsp->FileDownloadServlet
如果重启Tomcat后, 在out目录下你没有看到你创建的download文件夹, rebuild project -> 再次重启Tomcat(不能是重新发布)
公共资源为什么不直接放在工作路径下?👉因为Tomcat重启之后out目录就会清空
6.3 设置下载响应头
public class FileDownloadServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("fileDownloadServlet 被调用...");//1.准备要下载的文件, 放在web路径下的download目录, 然后重启Tomcat, 让程序把download文件夹加载到项目工作路径下// 如果实在不行, rebuild project -> 重启Tomcat(不是重新发布, 是重启)//2.获取要下载的文件的名字request.setCharacterEncoding("utf-8");String downloadFileName = request.getParameter("name");System.out.println("downloadFileName= " + downloadFileName);//3.给http响应,设置响应头Content-Type, 就是文件的MIME类型// 通过servletContext来获取ServletContext servletContext = request.getServletContext();String downloadPath = "/download/";//下载目录 从web工程根目录计算String downloadFileFullPath = downloadPath + downloadFileName;//拼接后->/download/1.jpgString mimeType = servletContext.getMimeType(downloadFileFullPath);System.out.println("mimeType= " + mimeType);response.setContentType(mimeType);//4.给http响应,设置Content-Disposition// 这里考虑的细节比较多, 比如不同的浏览器写法不一样, 要考虑编码// ff: 文件名中文需要base64, 而ie/chrome是URL编码//(1)如果是Firefox 中文编码需要base64//(2)Content-Disposition 指定下载的数据的展示形式(如果是attachment, 则使用文件下载方式;如果没有指定, 一般是以网页形式展示)//(3)如果是其它(主流ie/chrome), 中文编码使用URL编码if (request.getHeader("User-Agent").contains("Firefox")) {// 火狐 Base64编码response.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" +new BASE64Encoder().encode(downloadFileName.getBytes("UTF-8")) + "?=");} else {// 其他(主流ie/chrome)使用URL编码操作response.setHeader("Content-Disposition", "attachment; filename=" +URLEncoder.encode(downloadFileName, "UTF-8"));}//5.读取下载的文件数据, 返回给客户端/浏览器//(1)创建一个和要下载的文件 关联的输入流InputStream resourceAsStream = servletContext.getResourceAsStream(downloadFileFullPath);//(2)得到返回数据的输出流[因为返回的文件大多数是二进制(不管是文本还是二进制都可以按字节处理),IO]ServletOutputStream outputStream = response.getOutputStream();//(3)使用工具类, 将输入流关联的文件, 对拷到输出流, 并返回给IOUtilsIOUtils.copy(resourceAsStream, outputStream);}
}
6.4 文件下载注意事项
- 文件下载, 比较麻烦的就是文件名中文处理
- 对于网站的文件, 很多文件使用另存为即可下载, 对于大文件(文档, 视频), 会使用专业的下载工具(迅雷, 华为网盘, 腾讯, 百度等).
- 对于不同的浏览器, 在把文件下载完毕后, 处理的方式不一样, 有的是直接打开文件, 有的是将文件下载到本地的下载目录