admin 管理员组

文章数量: 887021

【JSON

文章目录

  • 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, 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. 页面局部刷新,

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

2.3 Ajax-数据通信方式

2.4 Ajax文档使用






2.5 Ajax快速入门

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

2.5.2 新建java项目

新建java项目, 可以参考👉

  1. 新建lib目录,并引入jar包

  2. 成功启动

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路径/scrpit下引入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判断

$.post("/ajax/checkUserServlet2",{username: $("#username").val(),date: new Date() //built-in},function (data, status, xhr) {//成功后的回调函数console.log("$.post()请求成功");console.log("data=", data);console.log("status=", status);console.log("xhr=", xhr);//data是json对象,如果要显示-转成字符串$("#div").html(JSON.stringify(data));//对返回的结果进行处理if ("" == data.name) {$("#message").val("该用户名可用");} else {$("#message").val("该用户名不可用");}},"json"
)


3.6 jQuery.getJSON快速入门

四种格式

     var usernameValue = $(this).val();$.getJSON(//这里尽量准确, 一把确定[复制粘贴]"memberServlet", "action=isExistByName&username=" + usernameValue, function (data) {alert(data.isExist);console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()}
/*========================================================================================*/"memberServlet?action=isExistByName&username=" + usernameValue, function (data) {alert(data.isExist);console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()}
/*========================================================================================*/"memberServlet",{action: "isExistByName",username: usernameValue},function (data) {alert(data.isExist);console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()}
/*========================================================================================*/"memberServlet",{"action": "isExistByName","username": usernameValue},function (data) {alert(data.isExist);console.log("data= ", data);//显示json格式的数据: 1.要用逗号; 2.要用console.log()})

$.getJSON常用参数

  • url:请求发送的URL
  • data: 请求发送到服务器的数据
  • success: 请求成功时的回调函数
$.getJSON("/ajax/checkUserServlet2",{username: $("#username").val(),date: new Date() //built-in},function (data, status, xhr) {//成功后的回调函数console.log("$.getJSON()请求成功");console.log("data=", data);console.log("status=", status);console.log("xhr=", xhr);//data是json对象,如果要显示->转成字符串$("#div").html(JSON.stringify(data));//对返回的结果进行处理if ("" == data.name) {$("#message").val("该用户名可用");} else {$("#message").val("该用户名不可用");}},
);

如果你通过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. 文件上传下载需要使用两个包, 需要导入 文件上传下载需要的jar

jsp下的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👉参考

1.新建fileupdown项目

2.在com.zzw.servlet包 下配置 FileUploadServlet

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 doPost()...");}
}
<servlet><servlet-name>FileUploadServlet</servlet-name><servlet-class>com.zzw.servlet.FileUploadServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>FileUploadServlet</servlet-name><url-pattern>/fileUploadServlet</url-pattern>
</servlet-mapping>

3.web路径下新建upload.jsp
这段代码大部分是从家居购项目的furn_update.jsp来的

<%--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="<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();reader.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

遇到了一点小问题: temp\upload改成temp\upload

代码

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.如果将文件都上传到一个目录下, 当上传文件很多时, 会造成访问文件的速度变慢, 因此可以将文件上传到多个目录下.

2.比如: 一天上传的文件, 统一放到一个文件夹, 按照年月日格式, 比如👉20230513文件夹 日期类

●代码实现
1.在com.zzw.utils包下新建WebUtils工具类

public class WebUtils {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;}
}

2.修改FileUploadServlet

注意

3.测试效果

3.2 手动更改时间 再次测试


测试效果

5.7.2 文件覆盖问题

1.修改FileUploadServlet

2.测试

5.7.3 封装一下

把这部分代码摘出来封装进工具类里

5.8 文件上传其他注意事项

  1. 一个完美的文件上传, 要考虑的因素很多, 比如断点续传, 控制图片大小, 尺寸, 分片上传, 防止恶意上传等. 在项目中, 可以考虑使用WebUploader组件(百度开发👉.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 原理示意图

●响应头

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

●响应体

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

6.2 走通Servlet

1.在com.zzw.servlet包 下配置 FileDownloadServlet

<servlet><servlet-name>FileDownloadServlet</servlet-name><servlet-class>com.zzw.servlet.FileDownloadServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>FileDownloadServlet</servlet-name><url-pattern>/fileDownloadServlet</url-pattern>
</servlet-mapping>
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 doPost()被调用...");}
}

2.web路径下新建download.jsp

<head><title>文件下载</title><base href="<%=request.getContextPath()%>/">
</head>
<body>
<h1>文件下载</h1>
<a href="fileDownloadServlet?name=1.jpg">点击下载小狗图片</a><br/>
<a href="fileDownloadServlet?name=韩顺平零基础Java笔记.pdf">点击下载韩顺平零基础Java笔记.pdf</a><br/>
</body>

注意: 如果重启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. 对于不同的浏览器, 在把文件下载完毕后, 处理的方式不一样, 有的是直接打开文件, 有的是将文件下载到本地的下载目录

本文标签: Json