ThreadLocal上传下载文件

文章目录

  • ThreadLocal
    • 1.基本介绍
        • 1.什么是ThreadLocal?
        • 2.示意图
    • 2.快速入门
        • 1.创建普通java项目
        • 2.编写代码
          • 1.T1.java
          • 2.T1Service.java
          • 3.T2Dao.java
          • 4.Dog.java
        • 3.结果
    • 3.ThreadLocal源码解读
        • 1.set方法
        • 2.set方法总结
        • 3.get方法
  • 上传下载文件
    • 1.基本介绍
        • 1.基本说明
        • 2.文件上传原理 分析
    • 2.文件上传案例
        • 1.创建maven项目,导入依赖
        • 2.基本功能实现
          • 1.upload.jsp
          • 2.FileUploadServlet.java
        • 3.注意事项以及细节处理
          • 1.分目录存放
            • 1.工具类获取年月日
            • 2.修改FileUploadServlet.java
          • 2.解决文件重名问题
          • 修改FileUploadServlet.java
          • 3.创建目录问题
    • 3.文件下载
        • 1.原理示意图
        • 2.文件下载案例
          • 1.在本地创建文件夹,存放文件
            • 文件上传与下载创建目录的区别
          • 2.download.jsp
          • 3.FileDownLoad.java

ThreadLocal

1.基本介绍

1.什么是ThreadLocal?

image-20240203151643660

2.示意图

image-20240203152833479

2.快速入门

1.创建普通java项目
2.编写代码
1.T1.java

创建线程放入dog对象,调用T1Service的update()

package threadlocal;


/**
 * @author 孙显圣
 * @version 1.0
 */
public class T1 {
    //创建ThreadLocal对象
    public static ThreadLocal<Object> threadLocal = new ThreadLocal<>();
    //静态内部类,也是一个线程类
    public static class Task implements Runnable {

        @Override
        public void run() {
            Dog dog = new Dog();
            Pig pig = new Pig();
            //把dog放到当前线程里
            threadLocal.set(dog);
            System.out.println("在run方法中线程=" + Thread.currentThread().getName());
            new T1Service().update();
        }
    }
    public static void main(String[] args) {
        new Thread(new Task()).start(); //主线程中启动一个线程
    }
}

2.T1Service.java

取出dog,调用T2Dao的update()

package threadlocal;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class T1Service {
    public void update(){
        //取出dog
        Object o = T1.threadLocal.get();
        String name = Thread.currentThread().getName();
        System.out.println("在T1Service里面的update线程=" + name);
        System.out.println("T1Service取出 " + o.getClass());
        new T2Dao().update();
    }
}

3.T2Dao.java

取出dog,调用T2Dao的update()

package threadlocal;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class T2Dao {
    public void update(){
        Object o = T1.threadLocal.get();
        String name = Thread.currentThread().getName();
        System.out.println("在T2Dao的update的线程=" + name);
        System.out.println("T2Dao取出 " + o.getClass());
    }
}

4.Dog.java
package threadlocal;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class Dog {
}

3.结果

可以理解为,一个ThreadLocal对象可以将一个数据存放在当前线程的Entry对象里,只要在当前线程中就可以使用ThreadLocal对象取出存放的数据

image-20240203155654453

3.ThreadLocal源码解读

1.set方法
  1. 打断点,调试image-20240203172023830

  2. 跳入image-20240203172110735

  3. 下一步,跳入image-20240203172234818

  4. 跳出,下一步image-20240203172335848

  5. 下一步,跳入image-20240203172655853

  6. 跳入,下一步,下一步image-20240203172912494

  7. 下一步image-20240203173108413

  8. 下一步,下一步image-20240203173856273

  9. 跳出,跳出

    image-20240203173752389

2.set方法总结

简而言之,threadLocal.set(dog);这句话,就是在当前线程下,存储了key为这个threadlocal,value为dog对象的Entry对象

3.get方法
  1. 打断点,调试image-20240203174245982
  2. 跳入image-20240203174323617
  3. 下一步,跳入image-20240203174656300
  4. 跳出,下一步image-20240203174900179
  5. 下一步,跳入image-20240203175104594
  6. 跳出,下一步image-20240203175256047
  7. 下一步,下一步image-20240203175426078

上传下载文件

1.基本介绍

1.基本说明

image-20240203183032646

2.文件上传原理 分析

image-20240203183709370

image-20240203183803798

image-20240203183818824

image-20240203184113278

2.文件上传案例

1.创建maven项目,导入依赖
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.2.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.4</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-impl</artifactId>
      <version>1.2.5</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-spec</artifactId>
      <version>1.2.5</version>
    </dependency>
2.基本功能实现
1.upload.jsp
<%@ 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("prevView");
            //获取文件对象
            var file = event.files[0];
            //获取文件阅读器: Js的一个类,直接使用即可
            var reader = new FileReader();
            reader.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.jpeg" alt="" width="200" height="200" id="prevView">

    <input type="file" name="pic" id="" value="" onchange="prev(this)"/>

    家居名: <input type="text" name="name"><br/>

    <input type="submit" value="上传"/>
</form>
</body>
</html>

2.FileUploadServlet.java
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

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.File;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.util.List;

/**
 * @author 孙显圣
 * @version 1.0
 */
@WebServlet("/fileUploadServlet")
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.判断是否为文件表单enctype="multipart/form-data"
        if (ServletFileUpload.isMultipartContent(req)) {
            //2.构建一个解析上传数据的工具对象
            DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
            //3.将工具对象传入ServletFileUpload
            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
            //解决文件名乱码问题
            servletFileUpload.setHeaderEncoding("utf-8");
            try {
                //4.servletFileUpload可以把表单提交的数据text/文件封装到FileItem文件项中
                List<FileItem> list = servletFileUpload.parseRequest(req);
                /*
                下面两个就是数据,他已经把文件上传到了StoreLocation的位置
                name=1.png, StoreLocation=D:\apache-tomcat-8.5.81\temp\upload_7e78ef67_18d6e981444__7f40_00000000.tmp, size=57722bytes, isFormField=false, FieldName=pic
                name=null, StoreLocation=D:\apache-tomcat-8.5.81\temp\upload_7e78ef67_18d6e981444__7f40_00000001.tmp, size=0bytes, isFormField=true, FieldName=name
                 */
                for (FileItem fileItem : list) {
                    //4.遍历数据,判断是一个文件还是普通表单字段,进行处理
                    if (fileItem.isFormField()) {
                        String string = fileItem.getString("utf-8"); //以value形式传的信息需要使用getString
                        System.out.println(string);
                    } else { //是一个文件
                        //获取上传的文件的名字
                        String name = fileItem.getName();
                        //创建将来要存放文件的目录
                        String filePath = "/upload/";
                        //获取真实路径,javase和javaweb是不同的,javaweb的真实目录是在target文件夹下
                        String realPath = super.getServletContext().getRealPath(filePath);
                        //判断是否有这个目录,如果没有再创建
                        File file = new File(realPath);
                        if (!file.exists()) {
                            file.mkdirs();
                        }
                        //将文件拷贝到刚才创建的目录下
                        String fileFullPath = realPath + name;
                        System.out.println("路径为" + fileFullPath);
                        fileItem.write(new File(fileFullPath));
                        //提示信息
                        resp.setContentType("text/html;charset=utf-8");
                        resp.getWriter().print("上传成功!");

                    }
                }
            } catch (FileUploadException e) {
                throw new RuntimeException(e);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            System.out.println("no");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.注意事项以及细节处理
1.分目录存放

将每天的信息存放到一个目录里

1.工具类获取年月日
import java.time.LocalDateTime;

/**
 * @author 孙显圣
 * @version 1.0
 */
public class WebUtils {
    /**
     * 获取年月日
     * @return
     */
    public static String getYearMonthDay() {
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int month = now.getMonthValue();
        int day = now.getDayOfMonth();
        return year + "/" + month + "/" + day + "/";
    }
}

2.修改FileUploadServlet.java

image-20240203202128597

2.解决文件重名问题

为防止文件名重复,在前面加一个前缀,保证唯一

修改FileUploadServlet.java

image-20240204085847188

3.创建目录问题

image-20240204090405183

3.文件下载

1.原理示意图

image-20240204090952590

image-20240204091024083

image-20240204091028767

2.文件下载案例
1.在本地创建文件夹,存放文件

image-20240204100026149

  1. 存放完成后看看文件是否在target目录下image-20240204100208181
  2. 如果不在,则需要rebuild项目 + redeploy项目
  3. 在本地创建的文件,通过上下文路径+资源路径是可以定位到的
文件上传与下载创建目录的区别
  1. 文件上传:由于web应用已经启动,与其交互的就是target目录,所以如果需要下载到某个目录,必须获取真实路径
  2. 文件下载:文件下载是将本地的文件响应给浏览器,所以,在本地存放文件即可,只需要重新构建一下项目,把本地的文件同步到target目录下。当web服务启动的时候,通过上下文路径+资源路径是可以定位到本地映射到target目录下的文件的
2.download.jsp
<%--
  Date: 2024/2/4
  Time: 9:11
  User: 孙显圣
  Version:1.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/fileupdown/downLoad?name=1.png">点击下载小狗图片</a><br><br>
<a href="/fileupdown/downLoad?name=java基础笔记.pdf">点击下载java基础笔记</a>
</body>
</html>

3.FileDownLoad.java
import org.apache.commons.io.IOUtils;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletContext;
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.InputStream;
import java.net.URLEncoder;

/**
 * @author 孙显圣
 * @version 1.0
 */
@WebServlet(urlPatterns = "/downLoad")
public class FileDownLoad extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String downLoadFileName = req.getParameter("name");

        //给http响应,设置响应头Content-Type就是文件的MINE
        ServletContext servletContext = req.getServletContext();
        //在本地的文件夹可以直接定位
        String downLoadPath = "/download/";
        String downLoadFileFullPath = downLoadPath + downLoadFileName;
        //找到该文件的MINE类型
        String mimeType = servletContext.getMimeType(downLoadFileFullPath);
        resp.setContentType(mimeType);

        //给http响应,设置响应头 Content-Disposition
        //   这里考虑的细节比较多,比如不同的浏览器写法不一样,考虑编码
        //   ff 是 文件名中文需要 base64, 而 ie/chrome 是 URL编码
        //(1)如果是Firefox 则中文编码需要 base64
        //(2)Content-Disposition 是指定下载的数据的展示形式 , 如果attachment 则使用文件下载方式
        //(3)如果是其他(主流ie/chrome) 中文编码使用URL编码
        if (req.getHeader("User-Agent").contains("Firefox")) {
            // 火狐 Base64编码
            resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?" +
                    new BASE64Encoder().encode(downLoadFileName.getBytes("UTF-8")) + "?=");
        } else {
            // 其他(主流ie/chrome)使用URL编码操作
            resp.setHeader("Content-Disposition", "attachment; filename=" +
                    URLEncoder.encode(downLoadFileName, "UTF-8"));
        }

        //读取要下载到浏览器的文件并返回给浏览器
        //创建与要下载文件相关的输入流
        InputStream resourceAsStream = servletContext.getResourceAsStream(downLoadFileFullPath);
        //创建返回数据的输出流
        ServletOutputStream outputStream = resp.getOutputStream();
        //使用工具类从本地读取文件并且发送到浏览器
        IOUtils.copy(resourceAsStream, outputStream);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud介绍

一、SpringCloud总体概述 Cloud Foundry Service Broker&#xff1a;通用service集成进入Cloud Foundry Cluster&#xff1a;服务集群 Consul&#xff1a;注册中心 Security&#xff1a;安全认证 Stream&#xff1a;消息队列 Stream App Starters&#xff1a;Spring Cloud Stre…

Redis 客户端

Redis 客户端 客户端-服务器结构 Redis 同 Mysql 一样&#xff0c;也是一个客户端-服务器结构的程序&#xff0c;结构如下图&#xff1a; 注&#xff1a;Redis 客户端和服务器可以在同一个主机上&#xff0c;也可以在不同主机上 Redis 客户端的多种形态 自带的命令行客户端&…

【Qt 学习笔记】详解Qt中的信号和槽

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 详解Qt中的信号与槽 文章编号&#xff1a;Qt 学习笔记 / 12 文章目录…

【Node.js】短链接

原文链接&#xff1a;Nodejs 第六十二章&#xff08;短链接&#xff09; - 掘金 (juejin.cn) 短链接是一种缩短长网址的方法&#xff0c;将原始的长网址转换为更短的形式。短链接的主要用途之一是在社交媒体平台进行链接分享。由于这些平台对字符数量有限制&#xff0c;长网址可…

旋转花键有哪些优缺点?

旋转花键是在花键外筒的外径上装上专用的轴承外套&#xff0c;使之运转动作&#xff0c;适用于水平多关节机械手臂&#xff08;SCARA&#xff09;、产业用机器人、自动装载机、镭射加工机、搬送装置、机械加工中心的ATC装置等各项设备。 目前&#xff0c;旋转花键的应用越来越普…

redis 哨兵

文章目录 前言主从复制的问题怎么人工恢复故障主节点 Redis Setinel 架构使用 docker 来配置哨兵结构安装 docker编排 redis 主从节点编排 redis 哨兵节点 观察哨兵模式的作用主从切换的具体流程小结 前言 redis 主从复制模式下, 一旦主节点出现故障, 不能提供服务的时候, 就需…

刷题之Leetcode283题(超级详细)

283.移动零 283. 移动零https://leetcode.cn/problems/move-zeroes/ 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nu…

第十讲 Query Execution Part 1

1 处理模型【Processing Model】 DBMS 的处理模型【Processing Model】定义了系统如何执行【execute】查询计划【Query Plan】。 针对不同的工作负载进行不同的权衡。 方法1&#xff1a;迭代器模型【Iterator Model】 方法2&#xff1a;物化模型【Materialization Model】 方…

创建和启动线程

概述 Java语言的JVM允许程序运行多个线程&#xff0c;使用java.lang.Thread类代表线程&#xff0c;所有的线程对象都必须是Thread类或其子类的实例。 Thread类的特性 每个线程都是通过某个特定Thread对象的run()方法来完成操作的&#xff0c;因此把run()方法体称为线程执行体。…

数据结构之堆底层实现的循序渐进

题外话 把没写的都补回来! 正题 堆 概念 堆是一棵完全二叉树&#xff0c;因此可以层序的规则采用顺序的方式来高效存储&#xff0c; 大根堆:指根结点比左右孩子都大的堆 小根堆:指根结点比左右孩子都小的堆 性质 1.堆中某个节点的值总是不大于或不小于其父节点的值 2…

CCIE-14-MPLS_and_BGP

目录 实验条件网络拓朴 环境配置开始配置配置MPLSR1访问R6检测结果R6访问R1检测结果 实验条件 网络拓朴 环境配置 在我的资源里可以下载&#xff08;就在这篇文章的开头也可以下载&#xff09; 开始配置 R1<->R2&#xff1a;EBGP R2<->R5&#xff1a;IBGP&…

蓝桥杯备考3

P8196 [传智杯 #4 决赛] 三元组 题目描述 给定一个长度为 n 的数列 a&#xff0c;对于一个有序整数三元组 (i,j,k)&#xff0c;若其满足 1≤i≤j≤k≤n 并且&#xff0c;则我们称这个三元组是「传智的」。 现在请你计算&#xff0c;有多少有序整数三元组是传智的。 输入格式…

小米手机澎湃OS,不Root查看电池健康

首先&#xff0c;在键盘拨号界面&#xff0c;输入*#*#284#*#*&#xff0c;会调用问题反馈APP来生成当前系统的故障日志&#xff0c;如果提示你需要授权什么就点确认 稍等几分钟&#xff0c;会得到一个压缩包&#xff0c;保存在目录MIUI/debug_log下 这里为了方便&#xff0c;我…

肖恩带你学C语言·文件操作(上)

1. 为什么使用文件 如果没有文件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运行程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进行持久化的保存&…

打造自然资源“一张图”管理平台,推动生态文明建设新篇章

在信息化时代的浪潮下&#xff0c;自然资源管理正面临着前所未有的挑战与机遇。传统的资源管理模式已经难以满足当前生态环境保护与经济发展的双重需求&#xff0c;我们需要一个全新的平台&#xff0c;一个集信息集成、智能分析、决策支持于一体的自然资源“一张图”管理平台。…

数据可视化-地图可视化-Python

师从黑马程序员 基础地图使用 基础地图演示 视觉映射器 具体颜色对应的代码可以在http://www.ab173.com/中查询RGB颜色查询对照表 from pyecharts.charts import Map from pyecharts.options import VisualMapOpts#准备地图对象 mapMap() #准备数据 data[("北京",…

c语言结构体变量和结构体数组的练习(自用版)

结构体变量注释和结构体数组练习&#xff08;已注释&#xff09;代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> struct Student {char name[20];int age;char sex;float score;char addr[30]; };int main() {//练习结构体变量struct Student s…

SSL/TLS:网络安全中的基石

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

c# wpf LiveCharts 简单试验2

1.概要 1.1 说明 1.2 要点 1.2.1 添加命名控件 xmlns:lvc"clr-namespace:LiveCharts.Wpf;assemblyLiveCharts.Wpf" 1.2.2 图片控件 <lvc:CartesianChart Name"chart" LegendLocation"Right"/> 1.3 代码文件引用 using LiveCharts…

YOLOv5实战记录05 Pyside6可视化界面

个人打卡&#xff0c;慎看。 指路大佬&#xff1a;【手把手带你实战YOLOv5-入门篇】YOLOv5 Pyside6可视化界面_哔哩哔哩_bilibili 零、虚拟环境迁移路径后pip报错解决 yolov5-master文件夹我换位置后&#xff0c;无法pip install了。解决如下&#xff1a; activate.bat中修改…