JSON, AJAX

news2024/11/23 16:46:46

文章目录

  • 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.取出key1
      console.log("key1 = " + myJson.key1);
      //2.取出key3
      console.log("key3 = " + myJson.key3)
      //  可以对key3取出的值(Array)进行遍历
      for (var i = 0; i < myJson.key3.length; i++) {
          console.log("第%i个元素的值 = ", i, myJson.key3[i]);
      }
      //3.取出key4
      console.log("key4 = ", myJson.key4, "key4.name = " + myJson.key4.name);
      //4.取出key5
      console.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.ThreadLocalMap
   ThreadLocalMap 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属性, 即ThreadLocalMap
   ThreadLocalMap map = getMap(t);
   if (map != null) {
       //3.如果线程的threadLocals不为空, 根据当前的threadLocal对象, 得到对应的Entry
       ThreadLocalMap.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设置图片url
                img.setAttribute("src", this.result)
            }
        }
    </script>
</head>
<body>
<%--表单的enctype属性要设置为multipart/form-data
    enctype="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 {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected 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() {
       //第二代日期类Calendar
       Calendar 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/

       //第三代日期类LocalDateTime
       LocalDate 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 {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected 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.jpg
        String 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)使用工具类, 将输入流关联的文件, 对拷到输出流, 并返回给IOUtils
        IOUtils.copy(resourceAsStream, outputStream);
    }
}

6.4 文件下载注意事项

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python实现SMS-Activate接口调用,获取手机号和验证码

前言 本文是该专栏的第27篇,后面会持续分享python的各种干货知识,值得关注。 对于SMS-Activate平台及其注册操作方法,这里就不过多详述了。尤其随着chatgpt的火爆,让sms-activate的热度也随之上涨。可能多数同学,是通过网页操作来获取手机号。而本文主要来介绍使用python…

Lua脚本语言快速上手(针对redis)

目录 基本介绍 设计目的 Lua 特性 lua基本语法 变量 流程控制 redis执行lua脚本 - EVAL指令 案例1&#xff1a;基本案例 案例2&#xff1a;动态传参 案例3&#xff1a;执行redis类库方法 案例4&#xff1a;给redis类库方法动态传参 案例5&#xff1a;pcall函数的使…

linux学习[10]磁盘与文件系统(1):查看磁盘容量指令df 评估文件系统的磁盘使用量指令 du

文章目录 前言1. df指令2. du指令 前言 TF卡制作的过程中涉及到了磁盘分区格式化等问题&#xff0c;当时对具体的指令理解不是特别深刻&#xff1b;由此引申到我对linux中的整个磁盘与文件系统没有一个全面的认识&#xff0c;这个磁盘与文件系统的系列博客章节就对这些进行记录…

电脑技巧:分享六个有趣好玩的网站,值得收藏

目录 1、Weavesilk 2、一键抠图 3、狗屁不通文章生成器 4、小霸王在线小游戏 5、世界名画在线拼图 6、寻找不动的emoji 今天小编给大家分享六个有趣好玩的网站&#xff0c;值得收藏&#xff01; 1、Weavesilk Weavesilk是一个光线绘画网站&#xff0c;它不需要有任何绘画…

基于python计算生态的第三方库总结与介绍

摘要&#xff1a;Python语言有超过12万个第三方库&#xff0c;覆盖信息技术几乎所有领域。即使在每个方向&#xff0c;也会有大量的专业人员开发多个第三方库来给出具体设计。正是因为python有了这么多“隐形的翅膀”&#xff0c;所以python的功能才足够庞大。本文主要针对pyth…

浏览器指纹

目录 下载安装与运行 软件目前可以随机的指纹 指纹随机化的好处 什么时候不需要指纹随机化 如何在软件上设置指纹 进入指纹设置的两个入口 指纹设置的两个步骤 如何获取随机指纹 设置过程&#xff08;动画演示&#xff09; 常见问题 浏览器指纹的有效期 同一个电脑…

【网站搭建】想搭建属于自己的网站吗,教你用ECS免费搭建网站

文章目录 前言ECS尾声 前言 Hello小伙伴们好久不见啦&#xff0c;博主一直忙得不可开交&#xff01; 久别重逢&#xff0c;博主最近发现了一个搭建网站的好方法&#xff0c;想要搭建网站的小伙伴们快来试试看吧&#xff01; ECS 用ECS搭建网站&#xff0c;可以说真的太爽啦…

CMS搭建篇:内容模型配置-题库管理模型

微信小程序云开发实战-答题积分赛小程序 CMS搭建篇:内容模型配置-题库管理模型 内容模型 内容模型是对数据库中存储的数据结构的描述,包含了内容的属性定义。通过内容模型,内容管理可以自动生成内容管理界面。 这里,我们需要建立一个内容模型,描述题库所具有的属性,如:题…

用友BIP成功入围工信部《2022年信息技术应用创新解决方案》

近日&#xff0c;由工业和信息化部网络安全产业发展中心&#xff08;工业和信息化部信息中心&#xff09;发布了2022年&#xff08;第四届&#xff09;信息技术应用创新解决方案征集工作成果&#xff0c;用友网络科技有限公司&#xff08;以下简称“用友”&#xff09;申报的“…

html实现一个一闪一闪的按钮,CSS实现一个一闪一闪的按钮,Css闪烁点标

效果 实现 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><style>#app {margin: auto 38%;margin-top: 10%;}/** 关键*/.lay-btn-box {position: relative;}.lay-btn {background: #59b0fb;border-r…

【C++项目设计】tcmalloc高并发内存池

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录 一、项目介绍二、池化技术与内存池池化技术内存池内存池需要解决的问题 三、malloc四、定长内存池&#xff08;了解内存池&&后面的…

51单片机(十一)蜂鸣器

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

使用ntpd同步服务端时间

安装ntpd 服务服务&#xff1a;yum install ntp -y ps&#xff1a;离线安装 1. 下载rpm离线包&#xff1a;autogen-libopts-5.18-5.el7.x86_64.rpm、ntp-4.2.6p5-29.el7.centos.2.x86_64.rpm、ntpdate-4.2.6p5-29.el7.centos.2.x86_64.rpm 2. 安装&#xff1a;rpm -Uvh --force…

logback按天归档日志

效果图 logback.xml文件配置 <configuration debug"false"><!--日志输出到文件--><appender name"BaseLogFile" class"ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/logback.log</file><…

计算机网络 | 五种I/O模型

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

用《文心一言》1分钟写一篇博客简直yyds

文章目录 前言文心一言是什么文心一言可以做什么文心一言写博客申请体验写在最后 前言 当今社会&#xff0c;博客已成为了许多人分享观点、知识和经验的重要平台。用文心一言写博客是将自己的思考、想法和经验以文字的形式呈现出来&#xff0c;让更多人了解自己。通过写博客&a…

SpringBoot——整合Junit测试

简单介绍&#xff1a; 其实Spring Boot的测试在之前我们就已经使用过了&#xff0c;只不过当时我们只是使用&#xff0c;并不知道他具体是怎么实现的&#xff0c;我们稍微介绍一下他在做测试的时候是怎么实现的&#xff1a; SpringBoot的测试&#xff1a; 在test文件夹下面&a…

C语言CRC-16 CCITT格式校验函数

C语言CRC-16 CCITT格式校验函数 CRC-16校验产生2个字节长度的数据校验码&#xff0c;通过计算得到的校验码和获得的校验码比较&#xff0c;用于验证获得的数据的正确性。基本的CRC-16校验算法实现&#xff0c;参考&#xff1a; C语言标准CRC-16校验函数。 不同同应用规范通过…

国产数据采集虚拟仪器板卡结合labview的应用

众所周知&#xff0c;虚拟仪器技术是根据用户的需求由软件定义通用测试硬件功能的系统。 通过将可重复配置的硬件应用到一个虚拟仪器系统&#xff0c;工程师可以使用软件来开发算法并把它们应用到一个嵌入式芯片&#xff0c;从而把虚拟仪器软件的可配置能力扩展至硬件。 以前只…

MySQL 主从复制与分离

基本概念 什么是读写分离 读写分离&#xff0c;基本的原理是让主数据库处理事务性增、改、删操作&#xff08;INSERT、UPDATE、DELETE&#xff09;&#xff0c;而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。 为什么要读写分…