线程数据共享和安全 -ThreadLocal

线程数据共享和安全 -ThreadLocal-----Java web文件上传下载应该注意什么

ThreadLocal

  1. ThreadLocal 可以实现在同一个线程数据共享, 从而解决多线程数据安全问题。

  2. ThreadLocal 可以给当前线程关联一个数据(普通变量、对象、数组)set 方法设置 关联数据。

public void set(T value) {
//获取当前线程
* Thread t = Thread.currentThread();
* //获取当前线程的 ThreadLocal.ThreadLocalMap 属性 threadLocals , 类型是 ThreadLocal 的静态内部类
* //threadLocals 有 一 个 属 性 Entry[], 类 型
ThreadLocal.ThreadLocalMap.Entry
* //k-> ThreadLocal 对象 v-> 值
* ThreadLocalMap map = getMap(t);
* if (map != null)
* map.set(this, value);//存放这里的 this 就是 ThreadLocal, 可以 debug 源码,一目了然
* else
* createMap(t, value);//创建
}
threadLocal.set(dog);
  1. ThreadLocal 可以像 Map 一样存取数据,key 为当前线程, get 方法获取当前线程的共享数据。

    public T get() {
             *          //1. 先得到当前的线程对象
             *         Thread t = Thread.currentThread();
             *         //2.通过线程获取到对应的ThrealLocalMap
             *         ThreadLocalMap map = getMap(t);
             *         if (map != null) {
             *              //3. 如果map不为空, 根据当前的 threadlocal对象,得到对应的Entry
             *             ThreadLocalMap.Entry e = map.getEntry(this);
             *             //4. 如果e 不为null
             *             if (e != null) {
             *                 @SuppressWarnings("unchecked")
             *                 //返回当前threadlocal关联的数据value
             *                 T result = (T)e.value;
             *                 return result;
             *             }
             *         }
             *         return setInitialValue();
             *     }
             //获取ThrealLocalMap对象的Entry[] table里的当前线程对象的信息Entry(k,v)线程名和关联数据
              Object o = T1.threadLocal1.get();
    
  2. 每一个 ThreadLocal 对象,只能为当前线程关联一个数据,如果不重新创建ThreadLocal对象实例,后面关联的对象会替换前面的对象。如果希望在当前线程共享多个数 据,就需要使用多个 ThreadLocal 对象实例。

    threadLocal.set(dog);
    //threadLocal.set(pig);//会替换 dog
    //如果希望在同一个线程共享多个对象/数据,就在创建一个 ThreadLocal 对象
    threadLocal2.set(pig);
    
  3. 每个 ThreadLocal 对象实例定义的时候,一般为 static 类型

  4. ThreadLocal 中保存数据,在线程销毁后,会自动释放。

    web 应用常用功能 -文件上传下载

    1.文件的上传和下载,是常见的功能。

    2.如果是传输大文件,一般有专门工具或者插件 。

    3.文件上传下载需要使用到两个包 , 需要导入
    文件上传需要的两个jar包

文件上传

1.使用表单提交。

//判断是不是文件表单(enctype="multipart/form-data")
	if (ServletFileUpload.isMultipartContent(request)) {
//是文件表单就构建创建解析上传数据的工具对象
//2. 创建 DiskFileItemFactory 对象, 用于构建一个解析上传数据的工具对象
	DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//3. 创建一个解析上传数据的工具对象
	ServletFileUpload servletFileUpload =new ServletFileUpload(diskFileItemFactory);}

2.action提交页面路径和之前一样,浏览器会自己解析前面的斜杠。

3.请求method指定为post。

4.enctype:encodetype编码类型默认是application/x-www-urlencodede即url编码,这种编码一般适用于文本。编码不正确会出现乱码。

5.进行二进制文件提交enctype要指定multipart/form-data 表示表单提交的数据有多个部分组成,可以提交二进制数据和文本数据。文件使用io技术进行处理。

文件上传注意事项和细节
  1. 如果文件上传会保存到一个目录下,当上传文件很多时,会造成访问文件速度变慢,因此 可以将文件上传到不同目录 比如 一天上传的文件,统一放到一个文件夹 年月日, 比如21001010 /文件名文件夹
  2. 一个完美的文件上传,要考虑的因素很多,比如断点续传、控制图片大小,尺寸,分片 上传,防止恶意上传等,在项目中,可以考虑使用 WebUploader 组件(百度开发) http://fex.baidu.com/webuploader/doc/index.html
  3. 文件上传功能,在项目中建议有限制的使用,一般用在头像、证明、合同、产品展示等, 如果不加限制,会造成服务器空间被大量占用 [比如 b 站评论,就不能传图片,微信发 1 次朋友圈最多 9 张图等…]
  4. 文件上传,创建 web/upload 的文件夹,在 tomcat 启动时,没有在 out 目录下 创建 对 应的 upload 文件夹, 原因是 tomcat 对应空目录是不会在 out 下创建相应目录的,所以,只 需在 upload 目录下,放一个文件即可, 这个是 Idea + Tomcat 的问题, 实际开发不会存 在.

文件下载

读取下载的文件数据,返回给客户端/浏览器

	     //(1) 创建一个和要下载的文件,关联的输入流
        InputStream resourceAsStream =
                servletContext.getResourceAsStream(downLoadFileFullPath);
        //(2) 得到返回数据的输出流 [因为返回文件大多数是二进制(字节), IO java基础]
        ServletOutputStream outputStream = response.getOutputStream();

        //(3) 使用工具类,将输入流关联的文件,对拷到输出流,并返回给客户端/浏览器
        IOUtils.copy(resourceAsStream, outputStream);

文件下载注意事项和细节

  1. 文件下载,比较麻烦的就是文件名中有中文,需要进行处理。如果不处理编码就会出现乱码。设置编码后,浏览器得到文件名会使用相应方法进行解码,中文文件名就不会出现乱码。

    // 获取到要下载的文件的名字
    request.setCharacterEncoding("utf-8");
    String downLoadFileName =request.getParameter("name");
    
  2. 不同的浏览器写法不一样,因此在代码中,我们要针对不同浏览器进行编码处理。

    		//(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"));
            }
    
  3. 对于网站的文件,很多文件使用另存为即可下载,对于大文件(文档,视频),会使用专 业的下载工具(迅雷、百度,腾讯,华为网盘等)。

  4. 对于不同的浏览器, 在把文件下载完毕后,处理的方式不一样, 有些是直接打开文件,有些是将文件下载到 本地/下载目录。

你可能感兴趣的:(安全,java,jvm)