文章目录
- 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?
2.示意图
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对象取出存放的数据
3.ThreadLocal源码解读
1.set方法
-
打断点,调试
-
跳入
-
下一步,跳入
-
跳出,下一步
-
下一步,跳入
-
跳入,下一步,下一步
-
下一步
-
下一步,下一步
-
跳出,跳出
2.set方法总结
简而言之,threadLocal.set(dog);
这句话,就是在当前线程下,存储了key为这个threadlocal,value为dog对象的Entry对象
3.get方法
- 打断点,调试
- 跳入
- 下一步,跳入
- 跳出,下一步
- 下一步,跳入
- 跳出,下一步
- 下一步,下一步
上传下载文件
1.基本介绍
1.基本说明
2.文件上传原理 分析
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
2.解决文件重名问题
为防止文件名重复,在前面加一个前缀,保证唯一
修改FileUploadServlet.java
3.创建目录问题
3.文件下载
1.原理示意图
2.文件下载案例
1.在本地创建文件夹,存放文件
- 存放完成后看看文件是否在target目录下
- 如果不在,则需要rebuild项目 + redeploy项目
- 在本地创建的文件,通过上下文路径+资源路径是可以定位到的
文件上传与下载创建目录的区别
- 文件上传:由于web应用已经启动,与其交互的就是target目录,所以如果需要下载到某个目录,必须获取真实路径
- 文件下载:文件下载是将本地的文件响应给浏览器,所以,在本地存放文件即可,只需要重新构建一下项目,把本地的文件同步到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);}
}