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 {@Overridepublic 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(){//取出dogObject 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设置图片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.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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.判断是否为文件表单enctype="multipart/form-data"if (ServletFileUpload.isMultipartContent(req)) {//2.构建一个解析上传数据的工具对象DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();//3.将工具对象传入ServletFileUploadServletFileUpload 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=picname=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形式传的信息需要使用getStringSystem.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");}}@Overrideprotected 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/4Time: 9:11User: 孙显圣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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf-8");String downLoadFileName = req.getParameter("name");//给http响应,设置响应头Content-Type就是文件的MINEServletContext 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);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mybatis——一对多关联映射

一对多关联映射 一对多关联映射有两种方式&#xff0c;都用到了collection元素 以购物网站中用户和订单之间的一对多关系为例 collection集合的嵌套结果映射 创建两个实体类和映射接口 package org.example.demo;import lombok.Data;import java.util.List;Data public cla…

手动实现Tomcat底层机制+自己设计Servlet

文章目录 1.Tomcat整体架构分析自己理解 2.第一阶段1.实现功能2.代码1.TomcatV1.java 3.调试阶段1.阻塞在readLine导致无法返回结果 4.结果演示 3.第二阶段1.实现功能2.代码1.RequestHander.java2.TomcatV2.java 3.调试阶段1.发现每次按回车会接受到两次请求 4.结果演示 4.第三…

Redis常见数据类型(2)

String字符串 字符串是Redis最基础的数据类型, 关于字符串需要特别注意: (1)首先Redis中所有的键的类型都是字符串类型, 而且其它几种数据结构也是在字符串类型的基础上构建的, 例如列表和集合的元素都是字符串类型, 所以字符串类型能为其它4种数据结构的学习奠定基础. (2)其次…

基于Unet的BraTS 3d 脑肿瘤医学图像分割,从nii.gz文件中切分出2D图片数据

1、前言 3D图像分割一直是医疗领域的难题&#xff0c;在这方面nnunet已经成为了标杆&#xff0c;不过nnunet教程较少&#xff0c;本人之前跑了好久&#xff0c;一直目录报错、格式报错&#xff0c;反正哪里都是报错等等。并且&#xff0c;nnunet对于硬件的要求很高&#xff0c…

Java23种设计模式

本文主要是对Java中一些常用的设计模式进行讲解 后期会进行不断的更新&#xff0c;欢迎浏览 23种设计模式 创建型模式&#xff0c;共五种&#xff1a;工厂方法模式、抽象工厂模式、建造者模式、原型模式、单例模式。结构型模式&#xff0c;共七种&#xff1a;适配器模式、桥接…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…

彩虹易支付接口配置

支付通道配置 基本概念 彩虹易支付系统有强大的支付接口扩展能力&#xff0c;首先需要明白以下几个概念。 支付方式&#xff1a; 支付方式用于定义发起支付的调用值&#xff08;在前台开发文档里面显示&#xff09;与支付方式名称。目前系统自带6种支付方式&#xff0c;它们的…

【C++】map set 底层刨析

文章目录 1. 红黑树的迭代器2. 改造红黑树3. map 的模拟实现4. set 的模拟实现 在 C STL 库中&#xff0c;map 与 set 的底层为红黑树&#xff0c;那么在不写冗余代码的情况下使用红黑树同时实现 map 与 set 便是本文的重点。 1. 红黑树的迭代器 迭代器的好处是可以方便遍历&…

openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警

文章目录 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 openGauss学习笔记-255 openGauss性能调优-使用Plan Hint进行调优-Hint的错误、冲突及告警 Plan Hint的结果会体现在计划的变化上&#xff0c;可以通过explain来查看变化。 …

Flutter Don‘t use ‘BuildContext‘s across async gaps.

Flutter提示Don‘t use ‘BuildContext‘s across async gaps.的解决办法—flutter里state的mounted属性

JAVAEE之Spring Boot日志

1. 日志概述 1.1 学习日志的原因 ⽇志对我们来说并不陌生, 从JavaSE部分, 我们就在使用 System.out.print 来打印日志了. 通过打印日志来发现和定位问题, 或者根据日志来分析程序的运行过程. 在Spring的学习中, 也经常根据控制台的日志来分析和定位问题. 随着项⽬的复杂…

【图论】【分类讨论】LeetCode3017按距离统计房屋对数目

本文涉及的知识点 图论 分类讨论 本题同解 【差分数组】【图论】【分类讨论】【整除以2】3017按距离统计房屋对数目 LeetCode3017按距离统计房屋对数目 给你三个 正整数 n 、x 和 y 。 在城市中&#xff0c;存在编号从 1 到 n 的房屋&#xff0c;由 n 条街道相连。对所有 …

Python 基于列表实现的通讯录管理系统(有完整源码)

目录 通讯录管理系统 PersonInformation类 ContactList类 menu函数 main函数 程序的运行流程 完整代码 运行示例 通讯录管理系统 这是一个基于文本的界面程序&#xff0c;用户可以通过命令行与之交互&#xff0c;它使用了CSV文件来存储和读取联系人信息&#xff0c;这…

Docker实战教程 第1章 Linux快速入门

2-1 Linux介绍 为什么要学Linux 三个不得不学习 课程需要&#xff1a;Docker开发最好在Linux环境下。 开发需要&#xff1a;作为一个后端程序员&#xff0c;是必须要掌握Linux的&#xff0c;这是找工作的基础门槛。 运维需要&#xff1a;在服务器端&#xff0c;主流的大型服…

Java栈和队列的实现

目录 一.栈(Stack) 1.1栈的概念 1.2栈的实现及模拟 二.队列(Queue) 2.1队列的概念 2.2队列的实现及模拟 2.3循环队列 2.4双端队列&#xff08;Deque&#xff09; 一.栈(Stack) 1.1栈的概念 栈:一种特殊的线性表&#xff0c;其 只允许在固定的一端进行插入和删除元素操作…

element-ui result 组件源码分享

今日简单分享 result 组件的源码实现&#xff0c;主要从以下三个方面&#xff1a; 1、result 组件页面结构 2、result 组件属性 3、result 组件 slot 一、result 组件页面结构 二、result 组件属性 2.1 title 属性&#xff0c;标题&#xff0c;类型 string&#xff0c;无默…

11-1(2)-CSS 背景+CSS 精灵图

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 一、CSS 背景1 背景颜色2 背景色半透明3 背景图片4 背景平铺5 背景图片位置6 …

linux操作系统安装及命令初识,上岸蚂蚁金服

310 包&#xff09; desktop 1800个包左右 内容必须大于 768M 系统设置 分区设置 挂载点 /boot / swap 交换分区–占用磁盘容量 网络配置 网卡配置 设置为ON 主机名配置 Begin installation 设置 root 用户密码 命令初识 命令 选项 参数&#xff1a; 命令选项参数…

JavaEE 初阶篇-生产者与消费者模型(线程通信)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 生产者与消费者模型概述 2.0 在生产者与消费者模型中涉及的关键概念 2.1 缓冲区 2.2 生产者 2.3 消费者 2.4 同步机制 2.5 线程间通信 3.0 实现生产者与消费者模…

iOS开发进阶(十三):脚手架创建iOS项目

文章目录 一、前言二、xcode-select 命令三、拓展阅读 一、前言 项目初期&#xff0c;需要搭建项目基本框架&#xff0c;为此离不开辅助工具&#xff0c;即脚手架。当然&#xff0c;IDE也可以实现新建空白项目&#xff0c;但是其新建后的项目结构可能不符合预期设计&#xff0…