JSON+AJAX+ThreadLocal+文件上传下载

news/2024/12/5 2:36:34/

文章目录

  • 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介绍

  1. JSON指的是JavaScript对象表示法(JavaScript Object Notation)
  2. JSON是轻量级的文本数据交换格式
    在这里插入图片描述
  3. 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转字符串

  1. JSON.stringify(json): 将一个json对象转换为json字符串
  2. JSON.parse(jsonString): 将一个json字符串转化为json对象
    在这里插入图片描述

1.2.2 字符串转JSON

在这里插入图片描述

1.2.3 JSON和字符串转换细节

  1. JSON.stringify(json对象)会返回json对象对应的String, 并不会影响原来的json对象
  2. JSON.parse(String)函数会返回对应的json的对象, 并不会影响原来的String
    在这里插入图片描述
  3. 在定义json对象时, 可以使用双引号表示字符串, 也可以使用单引号表示字符串. key可以不用引号.
 var personJson = {"name": "赵志伟","age": 23}var personJson = {'name': '赵志伟','age': 23}var personJson = {name: '赵志伟',age: 23}
  1. 但是在把原生字符串转成json对象时, 必须使用双引号"", 其他情况会报错

比如
var dogStr = “{‘name’:‘喵喵’, ‘age’:1}”;
➡JSON.parse(dogStr); 会报错
在这里插入图片描述
正确写法:
在这里插入图片描述

  1. JSON.stringify(json对象)返回的字符串(json对象->String), 都是双引号括起来的字符串, 所以在语法格式正确的情况下, 是可以重新转成json对象的(String->json对象)
    在这里插入图片描述

1.3 JSON在java中使用

  1. 在java中使用json, 需要引入到第三方的包gson.jar
  2. Gson是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库
    在这里插入图片描述
  1. 新建
    在这里插入图片描述
  2. 引入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);}
}
  1. 二说TypeToken
    在这里插入图片描述
    在这里插入图片描述
  2. 三说TypeToken
    )

1.3.3 Map对象和JSON字符串转换

在这里插入图片描述

2. Ajax介绍

  1. AJAX即Asynchronous Javascript And XML(异步 JavaScript 和 XML)
  2. AJAX是一种浏览器异步发起请求(可以指定发送哪些数据), 局部更新页面的技术

2.1 Ajax应用场景

  1. 搜索引擎根据用户输入的关键字, 自动提示检索关键字
  2. 动态加载数据, 按需取得数据 [树形菜单, 联动菜单…]
  3. 改善用户体验 [输入内容前提示, 带进度条文件上传…]
  4. 电子商务应用 [购物车, 邮件订阅…]
  5. 访问第三方服务 [访问搜索服务, rss阅读器]
  6. 页面局部刷新, https://piaofang.maoyan.com/dashboard

2.2 传统的web应用-数据通信方式

在这里插入图片描述

2.3 Ajax-数据通信方式

在这里插入图片描述

2.4 Ajax文档使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5 Ajax快速入门

2.5.1 验证用户是否存在-思路框架图

在这里插入图片描述

2.5.2 新建java项目

  1. 新建java项目
    在这里插入图片描述
  2. 引入web框架
    在这里插入图片描述
    在这里插入图片描述
  3. 新建lib目录,并引入jar包
    在这里插入图片描述
    在这里插入图片描述
  4. 配置Tomcat在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  5. 成功启动
    在这里插入图片描述

2.5.3 实现

  1. 搭建框架
    在这里插入图片描述
  2. 发送ajax请求[http请求]
    在这里插入图片描述
  3. 后台接收并返回json格式的数据
    在这里插入图片描述
  4. 前端得到数据, 通过dom操作, 进行页面局部刷新
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  5. 测试
    在这里插入图片描述
    在这里插入图片描述

2.6 接入数据库

引入数据库进行验证

项目结构 粘贴自满汉楼项目
在这里插入图片描述

  1. 思维框架图
    在这里插入图片描述
    在这里插入图片描述
  2. User实体类-无参构造器
    在这里插入图片描述
  3. UserDAO
    在这里插入图片描述
  4. UserService
    在这里插入图片描述
  5. CheckUserServlet
    在这里插入图片描述
    在这里插入图片描述
  6. 发现错误
    在这里插入图片描述
    解决方案
    src是se方式下的路径, javaweb要用到类加载器
    在这里插入图片描述
  7. 测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3. jQuery操作Ajax

  1. 编写原生的Ajax要写很多的代码, 要考虑浏览器兼容的问题
  2. 在实际工作中, 一般使用JavaScript的库(比如Jquery)发送Ajax请求

3.1 jQuery操作Ajax文档

  1. 在线文档
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 离线文档在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3.2 jQuery.ajax()函数

  1. $.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()快速入门

  1. 在web目录下引入jquery后, Rebuild Project一下
    在这里插入图片描述
  2. 发送ajax请求[http请求]
    在这里插入图片描述
  3. 后台接收并返回json格式的数据
    在这里插入图片描述
  4. 测试
    在这里插入图片描述
    解决方案
    在这里插入图片描述
    在这里插入图片描述
  1. 后台接收并返回数据
    在这里插入图片描述
  2. 前端获取
    在这里插入图片描述
    在这里插入图片描述
  3. 前端判断
    在这里插入图片描述
    测试
    在这里插入图片描述
    在这里插入图片描述
  4. 在div中显示内容
    在这里插入图片描述
    测试
    在这里插入图片描述
    在这里插入图片描述

3.4 jQuery.get()快速入门

  1. $.get()默认是get请求, 不需要再指定请求方式
  2. 不需要指定参数名
  3. 填写的实参, 是顺序的: url—data—success回调函数—dataType
  4. 没有提供error接口, 可以在success回调函数里根据status判断
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述

3.5 jQuery.post()快速入门

操作: 只需把$.get改成$.post

$.post和$.get的方式一样, 只是这时, 是按照post方法发送ajax请求[本质是http请求]

  1. $.post()默认是post请求, 不需要再指定请求方式
  2. 不需要指定参数名
  3. 填写的实参, 是顺序的: url—data—success回调函数—dataType
  4. 没有提供error接口, 可以在success回调函数里根据status判断
    在这里插入图片描述
    在这里插入图片描述

3.6 jQuery.getJSON快速入门

$.getJSON常用参数

  • url:请求发送的URL
  • data: 请求发送到服务器的数据
  • success: 请求成功时的回调函数

如果你通过jQuery发送的ajax请求[本质是http请求]是get请求, 并且返回的数据格式是JSON, 可以直接使用$.getJSON(). 简洁.
在这里插入图片描述
在这里插入图片描述

3.7 接入数据库

  1. 接入数据库在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 前端测试 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

4. ThreadLocal

4.1 什么是ThreadLocal?

  1. ThreadLocal的作用: 可以实现在同一个线程数据共享, 从而解决多线程数据安全问题.
  2. ThreadLocal可以给当前线程关联一个数据(普通变量, 对象, 数据) - set方法
  3. ThreadLocal可以像Map一样存取数据, key为当前线程 - get方法
  4. 每一个ThreadLocal对象, 只能为当前线程关联一个数据. 如果要为当前线程关联多个数据, 就需要使用多个ThreadLocal对象实例
  5. 每个ThreadLocal对象实例定义的时候, 一般为static类型
  6. ThreadLocal中保存的数据. 在线程销毁时. 会自动释放

4.2 ThreadLocal环境搭建

现象->分析原理->看源码进一步理解

  1. 创建java项目
    在这里插入图片描述
  2. ThreadLocal类图
    在这里插入图片描述
  3. 开启线程
    在这里插入图片描述
    在这里插入图片描述

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. 文件上传基本介绍

  1. 文件的上传和下载, 是常见的功能
  2. 后面项目就使用了文件上传下载
  3. 如果是传输大文件, 一般用专门的工具或插件
  4. 文件上传下载需要使用两个包, 需要导入
    commons-fileupload-1.2.1.jar
    commons-io-1.4.jar
    在这里插入图片描述
    在这里插入图片描述

5.1 文件上传-原理示意图

文件上传的解读

  1. 还是使用表单来提交
  2. action依然是按照以前的规定来确认
  3. method需指定为post
  4. enctype: 全称encodetype, 即编码类型. 默认是 application/x-www-form-urlencoded, 即url编码, 这种编码不适合于二进制文件的提交.
    enctype要指定为 multipart/form-data, 即表示表单提交的数据有多个部分组成, 也就是说即可以提交二进制数据, 也可以提交文本数据

服务端要完成的工作 FileUploadServlet.java

  1. 判断是不是一个文件表单
  2. 判断表单提交的各个表单项是什么类型
  3. 如果是一个普通的表单项, 就按照文本的方式来处理
  4. 如果是一个文件表单项(二进制数据), 使用IO技术来处理
  5. 把表单提交的文件数据, 保存到你指定的服务端的某个目录

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 按照年月日目录存放

  1. 如果将文件都上传到一个目录下, 当上传文件很多时, 会造成访问文件的速度变慢, 因此可以将文件上传到多个目录下.
    比如: 一天上传的文件, 统一放到一个文件夹, 按照年月日格式, 比如👉20230513文件夹
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    手动更改时间 再次测试
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    工具类WebUtils
public 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 文件上传其他注意事项

  1. 一个完美的文件上传, 要考虑的因素很多, 比如断点续传, 控制图片大小, 尺寸, 分片上传, 防止恶意上传等. 在项目中, 可以考虑使用WebUploader组件(百度开发👉https://fex.baidu.com/webuploader/doc/index.html).
  2. 文件上传功能, 在项目中建议有限制的使用, 一般用在头像, 证明, 合同, 产品展示等, 如果不加限制, 就会造成服务器空间被大量占用[比如微信发1次朋友圈最多9张图等].

5.8.1 upload文件夹为何要在out目录下直接创建

文件上传, 创建web/upload的文件夹. 在tomcat启动时, 没有在out目录下创建对应的upload文件夹. 其原因是tomcat对应空目录是不会在out下创建相应目录的. 所以, 只需在upload目录下放一个文件即可

  1. 这是web路径一个空文件夹, Tomcat启动后, 是不会在out/artifacts下创建相应目录的
    在这里插入图片描述
    在这里插入图片描述
  2. 如图, upload100文件夹下是有文件的, 那么在Tomcat启动后, out/artifacts下就会创建upload100目录
    在这里插入图片描述
    在这里插入图片描述

6. 文件下载基本介绍

6.1 原理示意图

响应头

  1. Content-Disposition: 表示下载的数据的展示方式. 比如内联形式(网页形式或者网页一部分), 或者是文件下载方式 attachment
  2. Content-type: 指定返回数据的类型MIME

响应体

  1. 在网络传输时是图片的原生数据(按照浏览器下载的编码)

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 文件下载注意事项

  1. 文件下载, 比较麻烦的就是文件名中文处理
    在这里插入图片描述
  2. 对于网站的文件, 很多文件使用另存为即可下载, 对于大文件(文档, 视频), 会使用专业的下载工具(迅雷, 华为网盘, 腾讯, 百度等).
  3. 对于不同的浏览器, 在把文件下载完毕后, 处理的方式不一样, 有的是直接打开文件, 有的是将文件下载到本地的下载目录

http://www.ppmy.cn/news/70360.html

相关文章

leetcode-二叉树专题

1. 判断相同 100. 相同的树 class Solution { public:bool isSameTree(TreeNode* p, TreeNode* q) {if(!p&&!q) return true;if(!p||!q) return false;if(p->val!q->val) return false;return isSameTree(p->left,q->left)&&isSameTree(p->ri…

gl-opendrive插件(车俩3D仿真模拟自动驾驶)

简介 本插件基于免费opendrive开源插件、Threejs和Webgl三维技术、vue前端框架&#xff0c;blender开源建模工具等进行二次开发。该插件由本人独立开发以及负责&#xff0c;目前处于demo阶段&#xff0c;功能还需待完善&#xff0c;由于开发仓促代码还需优化。 因此&#xff…

基于卷积的图像分类识别(七):SENet

系列文章目录 本专栏介绍基于深度学习进行图像识别的经典和前沿模型&#xff0c;将持续更新&#xff0c;包括不仅限于&#xff1a;AlexNet&#xff0c; ZFNet&#xff0c;VGG&#xff0c;GoogLeNet&#xff0c;ResNet&#xff0c;DenseNet&#xff0c;SENet&#xff0c;MobileN…

Redis的日常使用小结

一、数据类型 五大数据类型String型&#xff1a;String 是redis中最基本的数据类型,二进制安全的,即它可以包含任何数据,如序列化的对象、jpg图片,大小上限是512M。Hash型(存储消耗高于字符串): 键值对集合,适合存储对象&#xff0c;类似 Java的Map<String,Object>。Lis…

简单实现小程序授权登录功能

本人给大家带来了关于微信小程序的相关知识&#xff0c;其中主要介绍了怎么实现小程序授权登录功能的相关内容&#xff0c;下面一起来看一下&#xff0c;希望对大家有帮助。 在我们平时工作、学习、生活中&#xff0c;微信小程序已成为我们密不可分的一部分&#xff0c;我们仔细…

成都欢蓬信息:抖音电商去年GMV增速超80%

在今年的抖音电商生态大会上&#xff0c;抖音电商交出了年度“成绩单”。 5月16日&#xff0c;抖音电商总裁魏雯雯披露&#xff0c;近一年抖音电商GMV&#xff08;成交额&#xff09;增幅超80%。其中&#xff0c;商城GMV同比增长277%&#xff0c;电商搜索GMV同比增长159%&#…

Vue生成唯一id

精简版 安装nanoid库&#xff08;实际上就是一个函数&#xff09; &#xff0c;是简化版的uuid。 npm i nanoid 使用方式&#xff1a; <script> import {nanoid} from "nanoid";export default {name: "MyHeader",methods: {add(event) {const…

C++之构造函数与虚析构函数

文章目录 构造函数为什么不能被设置为虚函数析构函数为什么可以被设置为虚函数在什么情况下析构函数必须为虚函数构造函数为什么不能被设置为虚函数 1.虚函数调用只需要“部分的信息”,即只需要知道函数的接口(函数返回类型,函数名,参数列表),而不需要对象的具体类型,但…