第二阶段(day17)文件上传

1.文件上传

1.1介绍

1.在很多业务场景,用户都需要上传头像、证件照以及其他文件.

2.文件上传就是用户通过浏览器选择需要上传的文件并将文件传输至网站服务器上的一个过程

文件上传就是用浏览器把文件数据跟着请求报文一起发送到服务器。服务器把请求报文里的文件部分的内容取出来,并且还原成文件的过程。

1.2使用工具

文件上传需要对请求中传的的文件流进行解析,一般会选择工具来对文件流进行解析

文件上传相关的jar包:

commons-fileupload-1.3.3.jar

commons-io-2.5.jar

2.代码

新建项目day7_upload

新建web.myUpload.html

页面:

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--
上传文件,要有form,并且method必须是post
​
-->
    <form action="/day7/upload" method="post">
        <input type="text" name="username"><br>
        <input type="file" name="myfile"><br>
        <input type="submit">
    </form>
</body>
</html>

新建src.com.javasm.controller.UploadServlet

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String myfile = req.getParameter("myfile");
        System.out.println(username);
        System.out.println(myfile);
    }
}

测试,重新部署,运行:

访问:http://localhost:8080/day7/myUpload.html

点击选择文件,选择一张照片。点击提交

开发者工具network,看到username=&myfile=%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.png

只能当做一个普通键值对去传。后台只会接收到文件名。

发送数据,请求部分有:

Content-Type: application/x-www-form-urlencoded

是参数拼接的url格式。使用这种格式传文件数据时,传不过去。需要改变它。

<body>
<!--
上传文件,要有form,并且method必须是post
另外还要用enctype属性改变传输格式。它的默认值就是application/x-www-form-urlencoded
想要发送文件,就得改成multipart/form-data
-->
    <form action="/day7/upload" method="post" enctype="multipart/form-data">
        <input type="text" name="username"><br>
        <input type="file" name="myfile"><br>
        <input type="submit">
    </form>
</body>

修改以后,在network的Preview上看不到参数了,且后台输出两个null。

请求部分格式那块变成了:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryuajmTVXWf3eBBtJG

发送文件数据时,浏览器并没有区分是普通的键值对字段还是文件字段,若使用multipart/form-data之后,数据都会变成二进制数据,也就是流里要发送的字节数据。实际上发送的所有数据都打成了boundary=----WebKitFormBoundaryuajmTVXWf3eBBtJG这样一个包。

后台通过getParameter接收数据是因为Tomcat把发送过来的键值对格式的数据拆分,放到一个Map里,从Map里取值。现在改变传输格式,Tomcat默认的形式就读不出来了。

所有的文件都在流里,应该获取请求正文部分的输入流,根据输入流把里面上传的文件原封不动的拆出来。然后在本地建一些文件,把流里读出的文件放到本地建好的文件里。

所以,上传文件的过程中,浏览器只需要做一些设置。服务端这边则是一堆IO的读写,读请求里的输入流,本地再创建一个输出流,通过本地的输出流把内容写入到本地文件里。

作为发送文件来讲,浏览器不管发什么文件都是这个流程,服务器读请求,写入本地。上传不同文件,只是本地创建的文件不同(目录不同),文件名不同。这种模式化的东西有对应的工具,两个jar包:

commons-io-2.5.jar IO增强包

commons-fileupload-1.3.3.jar 上传文件,解析数据用的包

(第二个包基于第一个包,但主要使用第二个包,故第一个包也要用)

jar包还是放在web.WEB-INF.lib里,再给服务器配置一下。

通过这两个工具,服务端的1和3这两步都可以做到。

public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String myfile = req.getParameter("myfile");
        System.out.println(username);
        System.out.println(myfile);
​
        //commons-fileupload-1.3.3.jar下的方法,主要用到ServletFileUpload类
        //isMultipartContent()返回boolean值,主要检测这次请求的数据Content-Type是不是multipart/form-data
        //如果是该格式,才做文件的解析,不是就用普通字符串做接收。参数是请求对象
        boolean multipartContent = ServletFileUpload.isMultipartContent(req);
        System.out.println(multipartContent);
​
        //DiskFileItemFactory解析数据,并封装成一个个FileItem对象
        DiskFileItemFactory dff = new DiskFileItemFactory();
​
        //上传文件核心对象,包含对请求解析的方法
        ServletFileUpload servletFileUpload = new ServletFileUpload(dff);
​
        try {
            //解析请求,返回一个列表,列表里装的是FileItem对象
            List<FileItem> list = servletFileUpload.parseRequest(req);
            System.out.println(list);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }
}

以上就完成了第一步解析的工作。

重新部署,运行,访问:http://localhost:8080/day7/myUpload.html

后台控制台打印出的结果为:

null null true

[name=null, StoreLocation=D:\tomcat\apache-tomcat-8.5.34\temp\upload7b0117f0_180760fb0097fa4_00000000.tmp, size=0bytes, isFormField=true, FieldName=username,

name=文件上传.png, StoreLocation=D:\tomcat\apache-tomcat-8.5.34\temp\upload7b0117f0_180760fb0097fa4_00000001.tmp, size=26989bytes, isFormField=false, FieldName=myfile]

FieldName就是起的name属性。(文件上传时通常要给form里的表单元素起name属性,上传的键值对在英文里叫FormFiled.)

isFormField,如果是普通的上传文件字段就是true,如果是文件字段就是false

size,在第一条很小,因为是普通的字段。第二条比较大,故就是图片。

StoreLocation是Tomcat接收到文件,生成出来的临时文件。之前是什么文件也不会帮助还原出来,仅仅是把数据分成不同的临时文件存储,并且在这里写上了生成临时文件的地址。

name就是文件名。

第二步需要自己去做。创建的目录需要url能访问到。

1.只有自己的服务器,则存在当前服务器下

2.Tomcat作为服务器程序,可以启动多个,每次启动的时候换一个端口即可。如果可以启动不同的服务器,也可单独取一个服务器读取图片用。故也可存在其他服务器下。

能通过url访问必须在如下图片目录下,他是运行目录。在web下新建myupload目录,不过这里建的目录是源代码所在的目录,不是Tomcat运行目录,故建好目录一定要检查运行目录里有没有新建的目录。(右键,show in Explorer是源代码的目录)

但运行目录里没有。因为idea建立了空目录,不会打包过去。故在myupload目录下新建一个空文件,这里新建nouse.text

重新部署,再看运行目录。就会出现该目录。

之后,相应的代码:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String myfile = req.getParameter("myfile");
        System.out.println(username);
        System.out.println(myfile);
​
        boolean multipartContent = ServletFileUpload.isMultipartContent(req);
        System.out.println(multipartContent);
​
        String realPath = req.getServletContext().getRealPath("/");   //获得Tomcat运行代码的真实路径,也是通过url
        //可以访问到的真实根目录。也是本地IO存储的真实目录
        System.out.println(realPath);  //D:\workspace\two\javaEE\out\artifacts\day7_upload_war_exploded
        //windows系统,本地文件使用路径时用右斜杠,但url里使用左斜杠。    /通用性比较强,不管是url,linux系统,windows系统都可
        //识别出来     为了防止混乱,目录都用/
        String myFolderPath = "myupload/";       //要存的目录     目录和文件名中间也有/
​
        DiskFileItemFactory dff = new DiskFileItemFactory();
​
        ServletFileUpload servletFileUpload = new ServletFileUpload(dff);
​
        try {
            List<FileItem> list = servletFileUpload.parseRequest(req);
            System.out.println(list);
            for (FileItem item:list){
                if (!item.isFormField()){  //如果不是普通的文件字段
                    //创建文件,参数是路径。前两部分已有,还差文件名。
                    //生成文件名:1.使用uuid  2.使用原文件名(在name上)
                    File file = new File(realPath + myFolderPath + item.getName());
​
​
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
    }
}

第三步:

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String myfile = req.getParameter("myfile");
        System.out.println(username);
        System.out.println(myfile);
​
        boolean multipartContent = ServletFileUpload.isMultipartContent(req);
        System.out.println(multipartContent);
​
        String realPath = req.getServletContext().getRealPath("/");
        System.out.println(realPath);
        String myFolderPath = "myupload/";
​
        DiskFileItemFactory dff = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(dff);
​
        try {
            List<FileItem> list = servletFileUpload.parseRequest(req);
            System.out.println(list);
            for (FileItem item:list){
                if (!item.isFormField()){
                    File file = new File(realPath + myFolderPath + item.getName());
​
                   //把临时文件的内容,写入到指定的文件中
                    item.write(file);
​
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

重新部署,运行,访问:

http://localhost:8080/day7/myUpload.html

后台生成临时文件,打开运行目录:E:\workspace\two\javaEE\out\artifacts\day7_upload_war_exploded\myupload

会看到上传的图片。

再测试通过url访问: http://localhost:8080/day7/myupload/%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0.png (web目录下的myupload,后面是上传的文件名 上传文件.png)

3.文件上传注意点

1.分清java源代码目录和Tomcat运行代码目录

源代码目录:

运行目录:

上传文件最终会上传到myupload目录里。url访问的目录也是这个目录。

2.服务器每次重新部署或者重启时,idea会根据源码往服务器打包。

重新打包:Build,Build Atifacts,找到指定的服务器,可执行Rebuild。

3.普通字段部分怎么处理(假如要用到它)

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");      //告诉Tomcat解析时用utf-8解析
        String username = req.getParameter("username");
        String myfile = req.getParameter("myfile");
        System.out.println(username);
        System.out.println(myfile);
​
        boolean multipartContent = ServletFileUpload.isMultipartContent(req);
        System.out.println(multipartContent);
​
        String realPath = req.getServletContext().getRealPath("/");
        System.out.println(realPath);
        String myFolderPath = "myupload/";
​
        DiskFileItemFactory dff = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(dff);
​
        try {
            List<FileItem> list = servletFileUpload.parseRequest(req);
            System.out.println(list);
            for (FileItem item:list){
                if (!item.isFormField()){
                    File file = new File(realPath + myFolderPath + item.getName());
                    item.write(file);
                }else {
                    if ("username".equals(item.getFieldName())){   //找到对应的key
                        String string = item.getString();          //获得key对应的值的部分
                        //如果输入汉字,会出现乱码。因为现在是fileupload工具包解析的数据,和Tomcat没关系
                        //System.out.println(string);  该工具数据阿帕奇,默认ISO-8859-1编码,纯英文编码。
​
                        //string.getBytes("ISO-8859-1")先拆成Byte数组
                        System.out.println(new String(string.getBytes("ISO-8859-1"),"utf-8"));
                        //这套工具对中文支持比较差,故文件名是中文也要自己解析
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用工具之后,文件处理简单,但普通字段处理麻烦,因为使用了和文件处理相同的方式。

如果有个注册页面,上传头像和其他很多的字段,就很麻烦。

主流做法:使用Ajax把文件上传,将图片存的地址回传。注册时把地址写入数据库,访问时直接从数据库读地址。

4.Ajax上传文件(异步文件上传)

新建web.js,将jquery-3.6.0.js放入。

@WebServlet("/ajaxupload")
public class AjaxUploadServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
​
        String realPath = req.getServletContext().getRealPath("/");
        System.out.println(realPath);
        String myFolderPath = "myupload/";
​
        String retPath = "";
        DiskFileItemFactory dff = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(dff);
​
        try {
            List<FileItem> list = servletFileUpload.parseRequest(req);
            System.out.println(list);
            for (FileItem item:list){
                if (!item.isFormField()){
                    File file = new File(realPath + myFolderPath + item.getName());
                    item.write(file);
                    //要返回给页面的路径 存入数据库
                    retPath = myFolderPath + item.getName();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
​
        resp.setContentType("application/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        writer.print("{\"imgsrc\":\""+retPath+"\"}");
        writer.flush();
        writer.close();
    }
}

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/day7/js/jquery-3.6.0.js" type="text/javascript" charset="utf-8"></script>
    <style>
        .imgcls{
            width: 80px;
            height: 80px;
        }
    </style>
</head>
<body>
<form id="myform" >
    <input type="text" name="username"><br>
    <input type="text" name="userpwd"><br>
    <input type="text" name="userphone"><br>
    <input type="text" name="usermail"><br>
    <input type="text" name="useraddr"><br>
    <input type="hidden" id="imgsrc" name="imgsrc">
    <input id="myfile" type="file" name="myfile"><br/>
    <img id="mifileimg" class="imgcls" src="/day7/img/upready.png"/>
    <br>
    <!--<input id="testFileBtn" type="button" value="测试">-->
    <input id="mySubmitBtn" type="button" value="保存数据">
</form>
</body>
<script>
    //文件框 选择的文件改变了
    $("#myfile").change(function(){
        console.log($("#myfile")[0].files[0])
        //js取文件对象
​
        console.log(document.getElementById("myfile").files);
​
        //js创建form
        var myformdata = new FormData();
​
        //在form中创建键值对
        myformdata.append("myajaxfile",$("#myfile")[0].files[0]);
​
        $.ajax({
            url:"/day7/ajaxupload",       //请求地址
            type:"post",                  //请求方式
            data:myformdata,              //发送的数据 可以使用json格式 也可以使用url拼接格式
            contentType:false,            //使用formData的默认格式
            processData:false,            //是否把格式转为键值对拼接
            dataType:"json",              //返回的数据格式
            success:function(data){       //成功时的  回调函数
                console.log(data);
                //配合后续流程 把图片路径 写入隐藏框中
                $("#imgsrc").val(data.imgsrc);
                //展示上传数据预览
                $("#mifileimg").prop("src","/day7/"+data.imgsrc)
            }
        })
    })
​
    $("#mySubmitBtn").click(function(){
        var myData = $("#myform").serialize();
        console.log(myData);
        $.post("/day7/regist",myData,function(data){},"json");
    })
</script>
</html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 通达信是一款常用的股票分析软件,其保存的日线数据文件格式为day文件。而csv文件是一种常见的数据文件格式,可以在不同的软件和工具之间交换和共享数据。 将通达信的day文件转换为csv文件可以通过以下步骤完成: 1. 打开通达信软件,并选择要转换的股票或指数的日线数据。 2. 在通达信软件中找到“导出”或“另存为”等选项,选择将数据导出为文本文件。 3. 在弹出的保存对话框中,选择保存为txt格式,以便后续处理。 4. 使用文本编辑器(如记事本、Sublime Text等)打开保存的txt文件。 5. 检查txt文件的格式,通达信的day文件通常包含日期、开盘价、最高价、最低价、收盘价等信息,每个数据之间用制表符或空格分隔。 6. 检查并调整txt文件的编码,确保其与要求的csv文件编码一致(如UTF-8)。 7. 在文本编辑器中选择“另存为”选项,并将文件格式选择为csv格式。 8. 保存文件,并选择适当的文件名和存储位置。 转换完成后,您就可以使用支持csv文件格式的软件(如Microsoft Excel、Python pandas库等)进行进一步的数据分析、可视化或处理。 需要注意的是,转换过程中可能需要根据具体的数据格式和软件要求进行一些调整和处理,例如处理日期格式、缺失值等。此外,如需处理多只股票或指数的数据,需要对每一个day文件进行转换。 ### 回答2: 通达信day文件是一种历史股票数据文件格式,包含了股票的高、低、开、收、成交量等信息。而CSV文件是一种以逗号分隔值的文本文件,用于储存简单的表格数据。如果想将通达信day文件转换为CSV文件,可以按照以下步骤操作。 首先,需要打开通达信软件,并选择要导出的历史数据。通达信软件提供了数据导出的功能,可以通过菜单或快捷键找到导出选项。 接下来,选择导出文件的路径和名称。通常可以选择将导出的CSV文件保存在本地计算机的某个文件夹中。 然后,在导出选项中选择CSV文件作为导出的文件格式。通常可以在导出选项中看到支持的文件格式,选择CSV文件即可。 最后,点击导出按钮,等待一段时间,通达信软件将会自动将day文件转换为CSV文件,并保存在之前选择的路径中。 转换完成后,可以在保存的路径中找到生成的CSV文件。可以使用文本编辑器或者电子表格软件打开CSV文件,查看其中的股票历史数据,包括日期、开盘价、收盘价、最高价、最低价等。 需要注意的是,不同版本的通达信软件可能略有差异,具体的操作步骤可能会有所不同。如果对于软件操作不熟悉,可以参考软件的帮助文档或者寻求专业人士的帮助。 ### 回答3: 通达信day文件是一种常见的股票数据文件格式,而CSV文件是一种常用的数据存储格式。将通达信day文件转换为CSV文件可以方便地对股票数据进行处理和分析。 通达信day文件通常以“day”为后缀名,包含股票的每日交易数据,如开盘价、收盘价、最高价、最低价、成交量等。而CSV文件以逗号分隔不同的数值,并且可以直接在电子表格软件中打开和编辑。 要进行转换,首先需要打开通达信软件,选择相应的股票数据文件。然后在数据菜单中选择“导出数据”选项,并选择CSV格式。接下来,在弹出的导出设置窗口中,可以选择需要导出的数据类型、导出起止日期等,并点击“确认”按钮。 此时,通达信软件会自动生成相应的CSV文件,保存在指定的路径下。打开生成的CSV文件,可以使用电子表格软件(如Excel)打开和编辑,方便进行数据处理和分析。在CSV文件中,每一行代表一条股票交易数据,各个数据字段以逗号分隔。 总结而言,将通达信day文件转换为CSV文件,可以通过通达信软件进行操作,选择导出数据的格式为CSV,然后软件会自动生成对应的CSV文件,方便进行后续的数据处理和分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值