精华内容
下载资源
问答
  • 2019-10-20 21:21:58

    重要声明:本文章仅仅代表了作者个人对此观点的理解和表述。读者请查阅时持自己的意见进行讨论。

    本文更新不及时,请到原文地址浏览:《超详细的实现上传文件功能教程,文件上传实现。》。

    一、文件上传的方式

    在程序的世界里,没有什么功能的实现方式是单一的。上传文件也不例外,我们有很多种能够实现文件上传的方法。但我们最终要采用的,必然是最熟悉、最常用的方法。文件上传通常有下面的方法进行:

    1. 将内容进行base64,将base64字符串结果通过普通请求提交给后台。
    2. 直接使用浏览器的form表单进行文件上传。
    3. 使用java模拟表单(自己封装表单格式数据)进行文件上传。

    这些文件上传方式,都是基于HTTP协议的基础,它并没有强制限定了我们要如何去编码或处理数据,相反协议的存在使世界上所有的程序差异化不是那么太大。HTTP协议规定了,提交大量数据时,可以使用POST请求来进行提交。是的,大多数后台程序都只会在POST请求下去获取大量上传的数据,而不会在GET请求下去获取。你要知道,如果你不规范提交,当然也是可以不规范的从GET下获取到提交的数据。但极其不建议这样做。

    如果你对HTTP协议还不是很了解,你可以通过这篇文章来入门对HTTP协议的了解:《【HTTP,Java】认识HTTP协议,在互联网世界里翱翔》。

    二、base64 上传文件

    1、HTML网页内使用base64

    如果你要在网页中使用base64的方式将文件提交给后台,那么你不得不面临一个很严峻的问题就是:如何在网页中奖文件内容读取并转换成base64的数据。很幸运HTML5为我们提供了解决方案。

    FileReader提供了读取文件的能力。但它可不是你想象的提供一个文件路径就可以读取了。它能读取的文件需是来自下面的途径:

    1. 通过<input type="file">节点选择的文件。
    2. 通过拖放(DataTransfer)文件事件得到的文件。
    3. Canvas通过mozGetAsFile()方法返回的文件。

    下面以input选择的文件为例进行讲解。

    a、选择文件并转换为base64

    直接在html文件中写一个input并将其type设定为file即可立即实现一个文件选择功能。现在同时给出读取文件的示列代码:

    <body>
        <!-- 文件选择和上传按钮 -->
        <input type="file" id="fileSelecter"><button onclick="uploadFile()">上传</button>
    
        <!-- 上传逻辑 -->
        <script>
            function uploadFile() {
    
                // 找到文件文件选择框
                var fileInput = document.querySelector("#fileSelecter");
    
                // 获取选择的文件
                // (因为input是支持选择多个文件的,所以获取文件通过files字段,如果单个文件也是在这个files列表里。)
                var file = fileInput.files.item(0);
    
                // 判断一下
                if (file == null) {
                    // 没有选择文件。就什么都不处理。
                    return;
                }
    
                // 使用FileReader读取文件。
                var fileReader = new FileReader();
    
                fileReader.addEventListener("error", function (ev) {
                    // 文件读取出错时,执行此方法。
                    // 通过 fileReader.error 可以获取到错误信息。
                });
    
                fileReader.addEventListener("load", function (ev) {
                    // 文件读取成功后调用此方法。
                    // 通过 fileReader.result 即可获取到文件内容。
                });
    
                fileReader.addEventListener("loadstart", function (ev) {
                    // 读取开始时此方法被调用。
                });
    
                fileReader.addEventListener("loadend", function (ev) {
                    // 文件读取结束时执行此方法。
                    // 无论读取成功,还是读取失败。
                    // 总之,在结束读文件操作时,此方法都会调用。
                });
    
                fileReader.addEventListener("abort", function (ev) {
                    // 文件读取被中断时,此方法调用。
                    // 你可以通过 fileReader.abort() 方法随时中断文件的读取。
                });
    
                fileReader.addEventListener("progress", function (ev) {
                    // 读取文件过程不是一次性读完的,会进行多次读取。
                    // 没读取一次,本方法执行一次。
                });
    
                // 将文件内容读取为 base64 内容。通过 fileReader.result 即可返回base64的数据内容。
                fileReader.readAsDataURL(file);
            }
        </script>
    </body>
    

    上述代码中详细注释了使用FileReader如何读取文件的使用方式。通过监听load事件,即可获取到文件读取的结果数据。如果你将这个结果打印出来,你将看到类似下面的数据:

    data:image/jpeg;base64,/9j/4AAQSkZJergxawffwetcwgIKFUEGNiwgefnwkef...KCAcHCg0
    

    如果你看到了类似的数据。那么你就算是成功一半了。

    注意: 其中data:image/jpeg;base64,这一段属于对base64数据体的描述。文件真实base64内容只有逗号后面部分。如果后端接口明确告知你只需要传递后面的数据,那么你还需要自行将前面的描述去除。

    b、上传结果到接口

    现在建立请求将得到的结果提交到服务器即可。在load监听事件里我们可以成功的获取到base64的结果,因此只需要将提交数据代码写在监听里即可。这里我直接使用JQuerypost方法进行数据提交。代码如下:

    fileReader.addEventListener("load", function (ev) {
        // 文件读取成功后调用此方法。
        // 通过 fileReader.result 即可获取到文件内容。
        var result = fileReader.result;
        $.post("https://www.microanswer.cn/test/uploadBase64", {
            base64Data: result
        }, function (response) {
            // 服务器响应了我们的上传请求。
        });
    });
    

    如果你对JQuery的post方法不是很熟悉,请参考:【JQuery】JQuery常用方法总结、大全

    2、Java程序内使用base64

    在使用java作为后台程序的时候,有时候也经常通过http向其他服务器上传内容,那如果是使用base64方式,如何将数据以base64提交呢?其实非常简单,和上一小节里提到的BASE64Decoder有点类似,Java里还有一个类BASE64Encoder,他可以方便的将文件转为一个base64字符串,看下面的示列代码:

    // 将文件转为base64字符串
    public String file2Base64(String filePath) {
        // 建立文件对象
        File file = new File(filePath);
        BASE64Encoder base64Encoder = new BASE64Encoder();
        ByteArrayOutputStream out = null;
        FileInputStream fileInputStream = null;
        // 标准流读取代码模板。
        try {
            out = new ByteArrayOutputStream();
            fileInputStream = new FileInputStream(file);
            byte[] data = new byte[1024];
            int datasize = 0;
            while ((datasize = fileInputStream.read(data)) != -1) {
                out.write(data, 0, datasize);
            }
            out.flush();
        } finally {
            try {
                if (fileInputStream != null) {
                    fileInputStream.close();
                }
            }catch (Exception ignore) {}
        }
        return base64Encoder.encode(out.toByteArray());
    }
    

    有了base64字符串,就可以方便的进行上传了。相信后台程序一般都会有一个封装好了的网络请求工具类,下面示列一个典型的上传代码:

    String base64 = file2Base64("D:/temp/test.doc");
    HashMap<String, String> param = new HashMap<>();
    param.put("base64Data", base64);
    String response = HttpUtil.postFormUrlEncode("https://www.microanswer.cn/test/uploadBase64", param);
    

    此处使用的HttpUtil工具你可以通过下面的maven依赖获取:

    <dependency>
        <groupId>cn.microanswer</groupId>
        <artifactId>HttpUtil</artifactId>
        <version>1.0.1</version>
    </dependency>
    

    3、后台接口

    上述请求中,将数据以 base64Data 字段提交给了接口。现在只需要处理服务器响应后的事情了。先看看接口是如何获取数据的把:

    @RequestMapping("/uploadBase64")
    public Object uploadBase64Data(HttpServletRequest request) throws Exception {
        String base64Data = request.getParameter("base64Data");
    
        // 保存文件后缀名。
        String fileExtName = "";
        // 保存文件真实的base64数据
        String realBase64;
    
        // 判断是否有前缀
        if (base64Data.startsWith("data:") && base64Data.contains("base64,")) {
            String[] typeAndData = base64Data.split(",");
    
            // 截取 data:image/jpeg;base64, 为=>  jpeg;base64,
            String tempType = typeAndData[0].split("/")[1];
            // 拿到 ; 号前面的内容作为文件后缀。
            fileExtName = "." + tempType.substring(0, tempType.indexOf(";"));
    
            // 拿到真实base64数据。
            realBase64 = typeAndData[1];
        } else {
            // 没有前缀,则认为所有字符串都是base64实际内容。
            realBase64 = base64Data;
        }
    
        // 对 base64 字符串进行原数据读取
        byte[] bytes = new BASE64Decoder().decodeBuffer(realBase64);
    
        // 构建文件将数据保存
        File file = new File("D:/temp/" + UUID.randomUUID().toString() + fileExtName);
        FileOutputStream fo = new FileOutputStream(file);
    
        // 输出文件内容
        fo.write(bytes);
        fo.flush();
        fo.close();
    
        // 返回成功
        JSONObject object = new JSONObject();
        object.put("code", 200);
        object.put("msg", "上传成功");
        return object;
    }
    

    三、form表单上传文件

    对于前端来说,这种方式无疑是最简单的上传方式,因为甚至可以做到不写一点JavaScript代码就实现了。为了对前端上传文件有更深入了解,使用form表单上传时也有两种上传方案,一种是直接使用form节点的,另一种则是通过FromData对象来完成。

    1、使用html的form节点

    下面直接展示示列代码:

    <form method="post"
          action="https://www.microanswer.cn/test/uploadFile"
          enctype="multipart/form-data">
        请选择文件:<input type="file" name="fileData"><br>
        请输入文件描述:<input type="text" name="fileDescription"><br>
        <input type="submit" value="提交">
    </form>
    

    这样,前端就实现了文件上传了。提交给接口uploadFile要怎么去获取里面的文件,前端不用管了。

    2、使用 FormData 对象

    当使用FormData完成文件上传时,事情就变得稍微复杂一点了。但是有它的优势。直接在页面上使用form表单会造成页面的跳转,上传成功后就不会再停留在当前页面了。而使用 FormData 进行文件上传则可以完成异步上传,达到不跳页面的效果。

    首先要清除一点,FormData对象要提交数据时,其文件数据是来自于<input type="file">选择的文件。加入现在你已经选好了文件并且拿到了file对象,那么下面示列一个如何将此数据上传到服务端的代码:

    // 文件上传方法。 callback 是上传完成回调。
    function uploadFile(file, callback) {
        var formData = new FormData();
        formData.append("fileData", file); // 添加文件到 formData。
        formData.append("fileDescription", "文件上传描述信息。"); // 添加一个描述字段。
    
        // 进行上传
        $.ajax({
            url: "https://www.microanswer.cn/test/uploadFile",
            type: 'post',
            data: formData,
            contentType: false, // 不指定contentType,这样让JQuery主动识别
            processData: false, // 不让JQuery处理上传的数据,
            dataType: 'json',   // 预期返回数据格式。
            success: function (response) {
                callback(response);
            },
            error: function (xmlHttpRequest, statusStr, exception) {
                callback(undefined, exception);
            }
        });
    }
    

    代码中可以看到,首先使用 FormData 创建了一个实例,然后将文件和描述信息放入其中,最后通过 JQuery 的 ajax 方法将数据提交给后台接口。

    四、使用Java模拟表单

    java里没有类似formdata的上传文件辅助类,我们需要根据表单在上传文件时数据具体是如何进行提交的流程进行自己使用java来实现。摆在我们面前的首要任务就是要搞明白表单提交的数据结构,只有详细了解了其结构,才能使用Java进行完美的模拟。

    1、文件上传的数据内容格式

    通过表单上传文件显然是HTTP协议内的一部分内容,因此我们不妨直接翻开HTTP协议里针对表单上传文件相关的定义文档:RFC1867。下面是一些重点内容的截取部分(博主能力有限,翻译得不好还请将就凑合):

    multipart/form-data的定义

    数据格式内容举例

    ww

    2、Java代码实现表单

    通过上述HTTP协议定义文档中的描述,相信文件表单在数据提交过程中数据传输方式和格式已经有了大致的了解。现在是时候使用Java实现这样一个功能了。

    a、单个表单文件单元

    根据定义,一个input可以支持选择多个文件的,而在传输时,每个文件的传输需要提供一些基本信息。因此,直接为单个文件单元实现为一个类:

    /**
     * InputFile.java
     * 用于放在表单 Input 里的文件单元。
     */
    public class InputFile {
    
        // 保存当前需要传递的文件引用。
        private File file;
    
        // 如果要传递的数据直接是二进制数据了,这里也提供一个变量,使支持二进制数据直接传递。
        private byte[] byteData;
    
        // 在不清楚上传的数据是什么,但确切知道上传的内容是一个inputstream里的内容。这里也提供一个变量,使支持输入流直接传递。
        private InputStream inputStream;
    
        public InputFile(File file) { this.file = file; }
    
        // 对于数组,不要直接引用,而是取一份其拷贝的数据。
        public InputFile(byte[] byteData) {
            this.byteData = new byte[byteData.length];
            System.arraycopy(byteData, 0, this.byteData, 0, byteData.length);
        }
        public InputFile(InputStream inputStream) { this.inputStream = inputStream; }
    
    
        // 当进行提交时,使用此方法,此方法将会把当前单元持有的[文件\数据\流]进行上传。
        public void submit(OutputStream outputStream) throws Exception{
    
            // 输出是,首先建立基本信息输出。
            StringBuilder baseInfo = new StringBuilder();
    
            if (file != null) {
                // 有文件,则输出文件。
                baseInfo.append(" filename=\"").append(file.getName()).append("\"").append(Constant.LINE_SEPARATOR);
                baseInfo.append("Content-Type: ").append(new MimetypesFileTypeMap().getContentType(file)).append(Constant.LINE_SEPARATOR);
                baseInfo.append(Constant.LINE_SEPARATOR);
    
                inputStream = new FileInputStream(file);
    
            } else {
                // 输出数据 或 流,但因为不知道名称,因此填写一个随机名称。
                baseInfo.append(" filename=\"")
                        .append(UUID.randomUUID().toString().replaceAll("-", ""))
                        .append("\"")
                        .append(Constant.LINE_SEPARATOR)
                        .append("Content-Type: application/octet-stream").append(Constant.LINE_SEPARATOR)
                        .append(Constant.LINE_SEPARATOR);
            }
    
            outputStream.write(baseInfo.toString().getBytes(Constant.charset));
    
            // 将具备的流信息输出。
            if (inputStream != null) {
                byte[] datas = new byte[1024];
                int datasize = 0;
    
                while ((datasize = inputStream.read(datas))!= -1) {
                    outputStream.write(datas, 0, datasize);
                }
    
                if (file != null) {
                    inputStream.close();
                }
            } else if (byteData != null && byteData.length > 0) {
                // 将数据输出。
                outputStream.write(byteData);
            }
    
            outputStream.write(Constant.LINE_SEPARATOR.getBytes(Constant.charset));
        }
    }
    
    b、Input单元

    input单元里可以放置一个键值对,用来传递数据,同时,它还可以传递键和一系列文件,上一节的文件单元就可以放在这个Input单元中。则可以设计出 Input单元类如下:

    /**
     * Input.java
     * 表单里面的一条input输入单元。
     */
    public class Input {
        // 表单支持的类型枚举
        public enum Type { text,file }
    
        // 此 input 要提交的name值。
        private String name;
    
        // 此 input 要提交的value值。当type为text时才会提交此数据。
        private String value;
    
        // 此 input 要提交的文件。当type为file时才会提交此数据。
        private ArrayList<InputFile> inputFiles;
    
        // 此表单的类型,目前只有:text 和 file
        private Type type;
    
        // 允许直接使用键值对构造一个text的input。
        public Input(String name, String value) {
            this.name = name;
            this.value = value;
            this.type = Type.text;
        }
    
        // 允许使用name和文件列表构造一个file的input。
        public Input(String name, InputFile... inputFile) {
            this.name = name;
            this.inputFiles = new ArrayList<>();
            this.inputFiles.addAll(Arrays.asList(inputFile));
            this.type = Type.file;
        }
    
        // 在提交前,允许添加文件。
        public Input addFile(InputFile inputFile) {
            this.inputFiles.add(inputFile);
            return this;
        }
    
        // 在提交前,允许修改要提交的值。
        public Input setValue(String value) {
            this.value = value;
            return this;
        }
    
    
        // 将此input内的数据进行提交。
        public void submit(OutputStream outputStream) throws Exception {
            // 先构建基本信息输出。
            StringBuilder baseInfo = new StringBuilder();
            baseInfo.append("content-disposition: form-data; name=\"").append(name).append("\";");
    
            if (type == Type.text) {
                baseInfo.append(Constant.LINE_SEPARATOR);
                baseInfo.append(Constant.LINE_SEPARATOR);
                baseInfo.append(value);
                baseInfo.append(Constant.LINE_SEPARATOR);
    
                String s = baseInfo.toString();
                outputStream.write(s.getBytes(Constant.charset));
            } else {
    
                if (inputFiles != null && inputFiles.size() > 0) {
    
                    if (inputFiles.size()  == 1) {
    
                        outputStream.write(baseInfo.toString().getBytes(Constant.charset));
                        inputFiles.get(0).submit(outputStream);
                    } else {
                        String boundary = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6);
    
                        // 此input有多个文件。先输出内容体的基本信息。
                        baseInfo.append(Constant.LINE_SEPARATOR);
                        baseInfo.append("Content-Type: multipart/mixed, boundary=").append(boundary);
                        baseInfo.append(Constant.LINE_SEPARATOR);
                        baseInfo.append(Constant.LINE_SEPARATOR);
    
                        // 循环输出文件内容
                        for (InputFile infile: inputFiles) {
                            baseInfo.append("--").append(boundary).append(Constant.LINE_SEPARATOR);
                            baseInfo.append("content-disposition: attachment;");
                            outputStream.write(baseInfo.toString().getBytes(Constant.charset));
                            infile.submit(outputStream);
    
                            baseInfo = new StringBuilder();
                        }
    
                        // 追加上最后一个 boundary。
                        baseInfo.append("--").append(boundary).append("--").append(Constant.LINE_SEPARATOR);
                        outputStream.write(baseInfo.toString().getBytes(Constant.charset));
                    }
                }
            }
        }
    }
    
    
    c、 form 表单

    实现了 Input 之后,最后一个便是form实现了,form只需要实现其基本的数据组装即可完成:

    /**
     * Form.java
     * 模拟HTML页面表单行为。
     */
    public class Form {
    
        private ArrayList<Input> inputs;
    
        public Form() {
            this.inputs = new ArrayList<>();
        }
    
        // 往表单中添加一个input数据。
        public Form addInput(Input input) {
            this.inputs.add(input);
            return this;
        }
    
        // 提交这个表单。传入你要提交到的目标地址。
        // 此处代码比较简单,可以按需自己实现或修复其中存在的问题。
        public String submit(String url) throws Exception {
            if (inputs == null || inputs.size() == 0) {
                throw new NullPointerException("请至少添加一个要提交的表单数据。");
            }
    
            URL url1 = new URL(url);
            URLConnection urlConnection = url1.openConnection();
    
            HttpURLConnection c = (HttpURLConnection) urlConnection;
    
            // 设置请求方式、
            c.setRequestMethod("POST");
            c.setDoOutput(true);
            c.setDoInput(true);
    
            String boundary = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6);
    
            // 设置header
            c.setRequestProperty("Content-Type", "multipart/form-data, boundary=" + boundary);
    
            // 进行传输。
            OutputStream outputStream = c.getOutputStream();
            for (Input in : inputs) {
    
                outputStream.write(("--" + boundary + Constant.LINE_SEPARATOR).getBytes(Constant.charset));
                in.submit(outputStream);
            }
    
            outputStream.write(("--" + boundary + "--").getBytes(Constant.charset));
            outputStream.flush();
    
            // 获取结果
            InputStream inputStream = c.getInputStream();
    
            // 读取结果字符串。
            InputStreamReader reader = new InputStreamReader(inputStream, Constant.charset);
            char[] chars = new char[256];
            int charsize=  0;
    
            StringBuilder result = new StringBuilder();
            while ((charsize = reader.read(chars))!= -1) {
                result.append(chars, 0, charsize);
            }
            c.disconnect();
    
            return result.toString();
        }
    }
    
    d、测试结果

    现在InputFileInputForm 类都已完成开发,不妨进行一下测试:

    // 构建一个表单
    Form form = new Form();
    
    // 加入一个普通的键值对。
    form.addInput(new Input("name", "Jack"));
    
    // 加入一个包含多个文件的input。
    form.addInput(new Input("fileData",
            new InputFile(new File("C:\\Users\\Micro\\Desktop\\file1.jpg")),
            new InputFile(new File("C:\\Users\\Micro\\Desktop\\file2.jpg"))
    ));
    
    // 提交到指定地址。
    String result = form.submit("https://www.microanswer.cn/test/uploadFile");
    
    // 打印结果
    System.out.println("提交结果:" + result);
    
    // 输出:提交结果:{"msg":"success","code":200,"data":null}
    
    

    完美通过。

    e、附加类

    在上述几个类中,使用了一个常量类,其代码如下:

    public class Constant {
    
        /**
         * 表单中上传文件,使用的换行必须是 \r\n。
         */
        public static final String LINE_SEPARATOR = "\r\n";
    
        /**
         * 表单中字符串的编码。
         */
        public static final Charset charset = StandardCharsets.UTF_8;
    
    }
    

    五、后台接收表单文件

    本文主要讲了Java后台如何实现获取表单内的数据,下面将分别对spring后台和原生的servlet后台进行示例。

    1、Spring后台

    如果你的后台使用了Spring框架,那么你就幸运了,你可以十分方便的拿到表单上传上来的文件。只需要通过一些简单的注解就可以完成,下面示列了一个典型的Controller接口方法,用于获取表单上传上来的文件:

    @RequestMapping("/uploadFile")
    public Object uploadFileTest(
            @RequestParam(value = "fileData") MultipartFile multipartFile,
            HttpServletRequest request
    ) throws Exception {
        // 即可拿到已上传的文件内容。如果你不处理,这个文件就会在本次请求结束时被删除
        InputStream in = multipartFile.getInputStream();
    
        return Util.buildReturnJson(WebApplication.Code.SUCCESS, "success", null);
    }
    

    这个方法针对input里只有一个文件时非常方便。如果某个input里包含了多个文件,这个方法似乎没法获取到更多的文件。(如果这个方法能的法话,还请大佬评论指正。)

    当你希望获取到某个input下的所有上传的文件时。你可以用下面的方法:

    @RequestMapping("/uploadFile")
    public Object uploadFileTest(HttpServletRequest request) throws Exception {
    
        // 使用 spring 提供的内置工具
        StandardMultipartHttpServletRequest r = new StandardMultipartHttpServletRequest(request);
    
        // 可以直接获取到input里如果是text类型的值。
        String name = r.getParameter("name");
    
        // 可以通过这样的方式获取到某个input下的所有文件。
        // 这里就获取了input的name为files时,提交上来的所有文件。
        List<MultipartFile> files = r.getMultiFileMap().get("files");
    
        return Util.buildReturnJson(WebApplication.Code.SUCCESS, "success", null);
    }
    

    2、servlet 实现

    在servlet中获取表单上传的文件相对比spring里复杂,但其实spring只是把servlet的封装了一下。咱们java后台的表单解析功能是自带就有的。下面给出一个示例:

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 获取表单的所有 part 内容。
        // 一个 text 的input 是一个 part
        // 一个 file 的input 里可能有多个part(因为可以多选文件嘛),这些part的name都是 input的name。
        Collection<Part> parts = request.getParts();
        Iterator<Part> iterator = parts.iterator();
        while (iterator.hasNext()) {
            // 获取到表单里的每个part。
            Part part = iterator.next();
            part.getName(); // 对应了 input 的 name 属性。
            part.getSubmittedFileName(); // 对应了 input=file 时 提交的文件的真实名字。(当input不是file类型时此方法返回的null)
            part.getInputStream();  // 对应了 input=file 是文件时的文件输入流。input=text时,其value值也通过此流读取。
            // todo 实现自己的业务。
        }
    }
    

    六、总结

    无论使用什么方式进行文件上传,只要对HTTP协议有一定的了解,都可以轻松完成各种需求的开发。为什么要针对表单进行模拟来上传文件,因为这是大多数服务器的上传文件方式,许多服务端也都默认支持解析表单文件,因此客户端的上传也许迎合服务器所支持的使用表单进行文件上传。

    如果你还对HTTP协议不是很了解,可通过这篇文章进行入门:《【HTTP,Java】认识HTTP协议,在互联网世界里翱翔》。

    更多相关内容
  • SpringBoot上传文件实例下载

    热门讨论 2017-03-11 17:51:25
    SpringBoot 单文件上传、批量文件上传。SpringMVC 也可以用。
  • java web接收上传文件服务器端示例

    热门讨论 2015-03-15 13:58:37
    做毕业设计的时候Android端要求把相关文件传到服务器端保存,目前这个就是用来接收文件上传请求的简单项目,目前就是在传送参数的时候中文会乱码,但是传送的文件不会乱码
  • javaEE上传文件和参数

    千次下载 热门讨论 2012-11-22 20:17:44
    用于android图片上传的服务器端代码 相关文章:http://blog.csdn.net/vipa1888/article/details/8213898
  • http下载和上传文件 c++ 封装类

    热门讨论 2014-12-10 13:37:23
    用c++ 封装的 CHttpClient 类 能够实现http文件上传和下载
  • 上传文件资料并生成缩略图

    万次阅读 多人点赞 2021-12-13 20:15:25
    本文详细阐述了文件上传并生成缩略图的整个过程,其中包括图片上传,PDF上传,video上传都可以生成缩略图。

    目录

    一:需求

    二:如何实现需求,以及其中遇到的问题?

    需求分析时遇到的问题

    编码过程中遇到的问题

    三:流程图与UML图

    四:上传文件资料生成缩略图

    1.上传图片生成缩略图--FastDFS

    2.上传视频生成缩略图--javacv

    3.上传PDF生成缩略图--pdfbox

    4.封装好的方法

    五:总结


    一:需求

    用户有一个需求就是收藏的功能,单纯的收藏记录好做,但是想加点难度就是,生成缩略图。类似B站的收藏一样。


    二:如何实现需求,以及其中遇到的问题?

    需求分析时遇到的问题

    1.如何生成缩略图?

    2.收藏的时候生成缩略图还是文件上传的时候生成缩略图?

    3.生成的缩略图存在哪里?

    编码过程中遇到的问题

    1.文件截取比较慢,如何解决?

    方法:使用多线程

    2.通过new File()无法获取网络文件?

    File file = new File("http://d-godone.dmsd.tech/goDone/M00/00/0A/wKg8O2D2mnqEMg7wAAAAALbl5Ys275.pdf");

    方法:使用工具类FileUtils.copyURLToFile(url,file)

    3.文件上传需要MultipartFile类型,但是截取出来的类型为Frame和BufferedImage,怎么弄?

    方法:查阅资料封装出,文件转换的方法。


    三:流程图与UML图

    image.png

    image.png


    四:上传文件资料生成缩略图

    1.上传图片生成缩略图--FastDFS

    /**
     * @Author: Promsing(张有博)
     * @Date: 2021/9/18 - 0:25
     * @Description: 图片的处理类
     * @version: 1.0
     */
    @Slf4j
    @Component
    public class ImageProcessing extends TypeProcessing{
    
        @Autowired
        private FastFileStorageClient fastFileStorageClient;
    
        @Autowired
        private ThumbImageConfig thumbImageConfig;
    
        private  String group="http://192.168.y.y:8888/group1/";
    
        /**
         *
         * @param fileName 本地文件的位置
         * @return
         */
        @Override
        public String fileUpload(String fileName) {
    
            File file = new File(fileName);
    
    
            // 上传并且生成缩略图
            StorePath storePath = null;
            try {
                storePath = this.fastFileStorageClient.uploadImageAndCrtThumbImage(
                        new FileInputStream(file), file.length(), "png", null);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            //String path = thumbImageConfig.getThumbImagePath(storePath.getPath());
    
            String imageUrl=group+thumbImageConfig.getThumbImagePath(storePath.getPath());
    
            return imageUrl;
    
        }
    }

    2.上传视频生成缩略图--javacv

    /**
     * @Author: Promsing(张有博)
     * @Date: 2021/9/18 - 0:37
     * @Description: 视频的处理类
     * @version: 1.0
     */
    @Component
    @Slf4j
    public class VideoProcessing extends TypeProcessing {
    
        @Override
        public String fileUpload(String videoFileName) {
            //最后获取到的视频的图片的路径
            String videPicture="";
            //Frame对象
            Frame frame = null;
            //标识
            int flag = 0;
            try {
                 /*
                获取视频文件
                */
                // FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber(videoPath + "/" + videoFileName);
                FFmpegFrameGrabber fFmpegFrameGrabber = new FFmpegFrameGrabber( videoFileName);
                fFmpegFrameGrabber.start();
    
                //获取视频总帧数
                int ftp = fFmpegFrameGrabber.getLengthInFrames();
                log.info("时长 " + ftp / fFmpegFrameGrabber.getFrameRate() / 60);
    
    
                while (flag <= ftp) {
                    frame = fFmpegFrameGrabber.grabImage();
    
                    /*
                    对视频的第五帧进行处理
                     */
                    if (frame != null && flag==5) {
    
    //                    //文件转换
                        BufferedImage bufferedImage =FileCaseUtil.FrameToBufferedImage(frame);
    
                        MultipartFile multipartFile =FileCaseUtil. fileCase(bufferedImage);
                        log.info("开始文件上传:");
                        //文件上传
                        String fileLoad = FileUploadUtil.fileLoad(multipartFile);
    
                        videPicture=fileLoad;
                        log.info("文件上传成功{}",fileLoad);
                        break;
    
                    }
                    flag++;
                }
                fFmpegFrameGrabber.stop();
                fFmpegFrameGrabber.close();
            } catch (Exception E) {
                E.printStackTrace();
            }
            return videPicture;
    
        }
    
    }

    3.上传PDF生成缩略图--pdfbox

    /**
     * @Author: Promsing(张有博)
     * @Date: 2021/9/18 - 0:29
     * @Description: PDF的处理类
     * @version: 1.0
     */
    @Slf4j
    @Component
    public class PDFProcessing extends TypeProcessing{
        @Override
        public String fileUpload(String fileName) {
    
            String pdfUrl="";
            try
            {
                //将读取URL生成File
                File file = FileCaseUtil. URLToFile(fileName);
    
    
                // 打开来源 使用pdfbox中的方法
                PDDocument pdfDocument = PDDocument.load(file);
                PDFRenderer pdfRenderer = new PDFRenderer(pdfDocument);
    
                // 提取的页码
                int pageNumber = 0;
                // 以300 dpi 读取存入 BufferedImage 对象
                int dpi = 300;
                BufferedImage buffImage = pdfRenderer.renderImageWithDPI(pageNumber, dpi, ImageType.RGB);
                // 将 BufferedImage 写入到 png
                // ImageIOUtil.writeImage(buffImage, "c:/temp/xx.png", dpi);
    
                //这里使用文件BufferedImage上传
    
                // 文件上传
                MultipartFile multipartFile =FileCaseUtil. fileCase(buffImage);
                log.info("PDF开始上传:");
                 pdfUrl=FileUploadUtil. fileLoad(multipartFile);
                log.info("PDF上传成功:{}",pdfUrl);
    
    //            //文件储存对象
    //            File outPut = new File("C:\\Users\\Administrator\\Videos\\"+ UUID.randomUUID().toString()+".jpg");
    //            // ImageIO.write(FrameToBufferedImage(frame), "jpg", outPut);
    //            ImageIO.write(buffImage, "jpg",outPut);
    
                // 关闭文档
                pdfDocument.close();
    
                //注意关闭文档与删除文档的顺序
                //删除临时的file
                String s = FileCaseUtil.threadLocal.get();
                System.out.println(s);
    
                File f=new File(s);
                boolean delete = f.delete();
                System.out.println("文件的删除状态"+delete);
            }
            catch (InvalidPasswordException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
    
            return pdfUrl;
    
        }
    }

    4.封装好的方法

     public static File URLToFile(String url){
            log.info("读取FastDFS上的ppt");
            File file1 = new File("test.pdf");
            try {
    
                URL url1 = new URL(url);
                FileUtils.copyURLToFile(url1,file1);
    
            } catch (IOException e) {
                e.printStackTrace();
            }
            File absoluteFile = file1.getAbsoluteFile();
            threadLocal.set(absoluteFile.toString());
            log.info("ppt已经存储到本地"+absoluteFile.toString());
            return file1;
        }
    
    public static BufferedImage FrameToBufferedImage(Frame frame) {
            //创建BufferedImage对象
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage bufferedImage = converter.getBufferedImage(frame);
            return bufferedImage;
        }
    
     public static MultipartFile fileCase(BufferedImage image){
            //得到BufferedImage对象
           // BufferedImage bufferedImage = JoinTwoImage.testEncode(200, 200, url);
            MultipartFile multipartFile= null;
            try {
                //创建一个ByteArrayOutputStream
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                //把BufferedImage写入ByteArrayOutputStream
                ImageIO.write(image, "jpg", os);
                //ByteArrayOutputStream转成InputStream
                InputStream input = new ByteArrayInputStream(os.toByteArray());
                //InputStream转成MultipartFile
                multipartFile =new MockMultipartFile("file", "file.jpg", "text/plain", input);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return multipartFile;
    
        }
    
      public static String fileLoad(MultipartFile mf) throws IOException {
            //上传视频并返回视频地址
            StorePath storePath = fastFileStorageClient.uploadFile(group,mf.getInputStream(), mf.getSize(), mf.getOriginalFilename().substring(mf.getOriginalFilename().lastIndexOf(".")+1));
            //将视频地址和项目id存到项目资料表中
            String videoUrl = "http://d-godone.yyy.tech/goDone/"+storePath.getPath();
            return videoUrl;
        }

    五:总结

    1.收到需求先拆分业务、梳理逻辑,通过画图、伪代码的形式去熟悉业务,梳理逻辑

    2.将大的工作任务,拆分成小块。一点一点去实现,然后再去串起来。

    3.遇到困难,不要怕,总会有解决办法,好的办法要不断查找才能获得。

    如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏哦。

    展开全文
  • 当我们没有搭建单独的文件服务器时,我们需要将文件上传至项目目录下,今天我们就学习如何上传文件到项目的resources目录下 一、引入依赖 <dependency> <groupId>commons-fileupload</groupId> ...

    当我们没有搭建单独的文件服务器时,我们需要将文件上传至项目目录下,今天我们就学习如何上传文件到项目的resources目录下

    一、引入依赖

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    <dependency>
        <groupId>commons-net</groupId>
        <artifactId>commons-net</artifactId>
        <version>3.3</version>
    </dependency>
    

    文件上传,就会涉及到 IO 操作,我们需要引入以上依赖

    二、配置文件

    spring:
      # 上传文件
      servlet:
        multipart:
          max-file-size: 10MB
          max-request-size: 10MB
    

    配置上传文件的最大值:

    • spring.servlet.multipart.max-file-size,限制单个文件的最大值
    • spring.servlet.multipart.max-request-size,限制上传的多个文件的总大小

    三、上传工具类

    package com.asurplus.common.utils;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import org.springframework.util.ResourceUtils;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.File;
    import java.net.InetAddress;
    import java.util.UUID;
    
    /**
     * 文件上传
     *
     * @author YangXiuTeng
     * @date Jun 1, 2015
     */
    @Component
    public class UploadFileUtil {
    
    	/**
    	* 项目端口
    	*/
        @Value("${server.port}")
        public String port;
    
    	/**
    	* 项目路径
    	*/
        @Value("${server.servlet.context-path}")
        public String contextPath;
    
    	/**
         * 上传文件
         * 
         * @param multipartFile 文件对象
         * @param dir 上传目录
         * @return
         */
        public ResponseResult uploadFile(MultipartFile multipartFile, String dir) {
            try {
                if (multipartFile.isEmpty()) {
                    return ResponseResult.error("请选择文件");
                }
                // 获取文件的名称
                String originalFilename = multipartFile.getOriginalFilename();
                // 文件后缀 例如:.png
                String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
                // uuid 生成文件名
                String uuid = String.valueOf(UUID.randomUUID());
                // 根路径,在 resources/static/upload
                String basePath = ResourceUtils.getURL("classpath:").getPath() + "static/upload/" + (StringUtils.isNotBlank(dir) ? (dir + "/") : "");
                // 新的文件名,使用uuid生成文件名
                String fileName = uuid + fileSuffix;
                // 创建新的文件
                File fileExist = new File(basePath);
                // 文件夹不存在,则新建
                if (!fileExist.exists()) {
                    fileExist.mkdirs();
                }
                // 获取文件对象
                File file = new File(basePath, fileName);
                // 完成文件的上传
                multipartFile.transferTo(file);
                // 返回绝对路径
                return ResponseResult.success("上传成功", "http://" + InetAddress.getLocalHost().getHostAddress() + ":" + port + contextPath + "/upload/" + fileName);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return ResponseResult.error("上传失败");
        }
    }
    
    
    • 我们由于需要在工具类中获取项目端口及上下文路径,所以我们使用注解 @Component
    • 我们上传的根目录在:resources/static/upload
    • 文件名,我们使用了 uuid 作为新的文件名,保证文件不会被覆盖
    • 我们返回的路径是绝对路径,在实际的生成环境中,建议使用相对路径
    • ResponseResult 是我们自定义的统一返回对象,表示成功还是失败

    四、上传调用

    • 1、注入上传工具类
    @Autowired
    private UploadFileUtil uploadFileUtil;
    
    • 2、上传 API
    /**
     * 上传文件
     * <p>
     * Ajax方式上传文件
     *
     * @return
     */
    @PostMapping("uploadFileAjax")
    @ResponseBody
    public ResponseResult uploadFileAjax(HttpServletRequest request) {
        MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multiRequest.getFile("files");
        String dir = request.getHeader("Minio-dir");
        return uploadFileUtil.uploadFile(file, dir);
    }
    
    • 3、上传调用

    Html

    <p>ajax提交</p>
    <hr>
    <div style="height: 200px;width: 200px;position: relative;border: 1px #e2e2e2 solid">
        <input type="file" accept="image/*" id="imgUpload" style="position: absolute;left: 0;top: 0;opacity: 0;filter: alpha(opacity=0);height: 100%;width: 100%;z-index: 99">
        <img src="" alt="" id="picImg" style="height: 100%;width: 100%;position: absolute;left: 0;top: 0;">
    </div>
    

    JavaScript

    $('#imgUpload').change(function () {
        var formData = new FormData();
        formData.append("files", $("#imgUpload")[0].files[0]);
        var index = layer.load();
        $.ajax({
            type : "POST",
            cache: false,
            dataType: "json",
            data : formData,
            processData :  false,
            contentType :  false,
            url: baseUrl + 'uploadFileAjax',
            success:function(res){
                layer.close(index);
                layer.msg(res.msg);
                if(200 == res.code){
                    $('#picImg').attr('src',res.data);
                }
            },
            error:function() {
                layer.close(index);
                layer.msg("服务器异常!");
            }
        });
    });
    

    五、上传测试

    上传元素
    点击上传

    上传成功
    图片上传成功,转到上传目录:

    上传目录
    成功上传至项目的 resources/static/upload/ 目录下

    如您在阅读中发现不足,欢迎留言!!!

    展开全文
  • 写给大忙人看的 - Java中上传文件MinIO服务器(2)

    万次阅读 多人点赞 2020-05-10 18:25:48
    上一篇 写给大忙人看的 - 搭建文件服务器 MinIO(一),我们已经成功地搭建了 MinIO 文件服务器,这一篇讲解在 Java 中如何上传文件至 MinIO 一、开发前戏 1、项目中引入 maven 依赖 <!-- minio 相关依赖 --> ...

    上一篇 写给大忙人看的 - 搭建文件服务器 MinIO(一),我们已经成功地搭建了 MinIO 文件服务器,这一篇讲解在 Java 中如何上传文件至 MinIO

    一、开发前戏

    1、项目中引入 maven 依赖

    <!-- minio 相关依赖 -->
    <dependency>
        <groupId>io.minio</groupId>
        <artifactId>minio</artifactId>
        <version>3.0.10</version>
    </dependency>
    <!-- alibaba的fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.51</version>
    </dependency>
    <!-- thymeleaf模板引擎 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    

    这里除了 MinIO 的相关依赖,还添加了 fastjson,thymeleaf 的相关依赖,篇幅原因,其余依赖请自行添加

    2、添加配置信息

    在 application.yml 文件中加入 MinIO 服务器的相关信息

    # minio 文件存储配置信息
    minio:
      endpoint: http://127.0.0.1:9000
      accesskey: minioadmin
      secretKey: minioadmin
    

    3、创建实体类

    package com.zyxx.email.common.minio;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    /**
     * minio 属性值
     */
    @Data
    @Component
    @ConfigurationProperties(prefix = "minio")
    public class MinioProp {
        /**
         * 连接url
         */
        private String endpoint;
        /**
         * 用户名
         */
        private String accesskey;
        /**
         * 密码
         */
        private String secretKey;
    }
    
    

    这一步,我们将配置文件中 minio 的配置信息通过注解的方式注入到 MinioProp 这个实体中,方便后面我们使用

    4、创建核心配置类

    package com.zyxx.email.common.minio;
    
    import io.minio.MinioClient;
    import io.minio.errors.InvalidEndpointException;
    import io.minio.errors.InvalidPortException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * minio 核心配置类
     */
    @Configuration
    @EnableConfigurationProperties(MinioProp.class)
    public class MinioConfig {
    
        @Autowired
        private MinioProp minioProp;
    
        /**
         * 获取 MinioClient
         *
         * @return
         * @throws InvalidPortException
         * @throws InvalidEndpointException
         */
        @Bean
        public MinioClient minioClient() throws InvalidPortException, InvalidEndpointException {
            return new MinioClient(minioProp.getEndpoint(), minioProp.getAccesskey(), minioProp.getSecretKey());
        }
    }
    
    

    通过注入 MinIO 服务器的相关配置信息,得到 MinioClient 对象,我们上传文件依赖此对象

    5、上传工具类

    package com.zyxx.email.common.minio;
    
    import com.alibaba.fastjson.JSONObject;
    import com.zyxx.email.common.redis.RedisUtil;
    import com.zyxx.email.utils.DateUtils;
    import io.minio.MinioClient;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    
    @Slf4j
    @Component
    public class MinioUtils {
    
        @Autowired
        private MinioClient client;
        @Autowired
        private MinioProp minioProp;
    
        /**
         * 创建bucket
         *
         * @param bucketName bucket名称
         */
        @SneakyThrows
        public void createBucket(String bucketName) {
            if (!client.bucketExists(bucketName)) {
                client.makeBucket(bucketName);
            }
        }
    
        /**
         * 上传文件
         *
         * @param file       文件
         * @param bucketName 存储桶
         * @return
         */
        public JSONObject uploadFile(MultipartFile file, String bucketName) throws Exception {
            JSONObject res = new JSONObject();
            res.put("code", 0);
            // 判断上传文件是否为空
            if (null == file || 0 == file.getSize()) {
                res.put("msg", "上传文件不能为空");
                return res;
            }
            try {
    	       	// 判断存储桶是否存在
    	        createBucket(bucketName);
    	        // 文件名
    	        String originalFilename = file.getOriginalFilename();
    	        // 新的文件名 = 存储桶名称_时间戳.后缀名
    	        String fileName = bucketName + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
    	        // 开始上传
    	        client.putObject(bucketName, fileName, file.getInputStream(), file.getContentType());
    	        res.put("code", 1);
    	        res.put("msg", minioProp.getEndpoint() + "/" + bucketName + "/" + fileName);
    	        return res;
    		}  catch (Exception e) {
                log.error("上传文件失败:{}", e.getMessage());
            }
            res.put("msg", "上传失败");
            return res;
        }
    }
    
    

    二、开发进行中

    1、编写 Controller

    package com.zyxx.email.controller;
    
    import com.alibaba.fastjson.JSONObject;
    import com.zyxx.email.common.minio.MinioUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Controller
    public class MinioController {
    
        @Autowired
        private MinioUtils minioUtils;
    
        @GetMapping("init")
        public String init() {
            return "file";
        }
    
        /**
         * 上传
         *
         * @param file
         * @param request
         * @return
         */
        @PostMapping("/upload")
        @ResponseBody
        public String upload(@RequestParam(name = "file", required = false) MultipartFile file, HttpServletRequest request) {
            JSONObject res = null;
            try {
                res = minioUtils.uploadFile(file, "product");
            } catch (Exception e) {
                e.printStackTrace();
                res.put("code", 0);
                res.put("msg", "上传失败");
            }
            return res.toJSONString();
        }
    }
    
    

    2、上传页面

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
        <head>
            <meta charset="UTF-8">
            <title>首页</title>
        </head>
        <body>
            <form accept-charset="UTF-8" th:action="@{upload}" method="post" enctype="multipart/form-data" target="_blank">
                文件:<input type="file" name="file"/>
                <input type="submit" value="上传"/>
            </form>
        </body>
    </html>
    

    这里我用的 thymeleaf 模板引擎

    三、上传测试

    1、访问地址

    http://localhost:8080/init
    

    测试页面

    2、启动 MinIO 文件服务器

    3、响应信息

    {"msg":"http://127.0.0.1:9000/product/product_1589105654237.png","code":1}
    

    http://127.0.0.1:9000/product/product_1589105654237.png 就是我们上传之后得到的文件地址了

    4、访问文件

    MinIO 形式上传的文件也不支持直接访问,我们如果需要直接访问,还需要做如下操作:
    更改权限
    设置 bucket 的 policy 策略:
    设置策略
    设置该存储桶下面的文件为 Read and Write,这时我们就可以直接访问了
    在这里插入图片描述

    四、完整工具类代码

    package com.zyxx.email.common.minio;
    
    import com.alibaba.fastjson.JSONObject;
    import com.zyxx.email.utils.DateUtils;
    import io.minio.MinioClient;
    import io.minio.ObjectStat;
    import io.minio.messages.Bucket;
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.web.multipart.MultipartFile;
    
    import java.io.InputStream;
    import java.util.*;
    
    @Slf4j
    @Component
    public class MinioUtils {
    
        @Autowired
        private MinioClient client;
        @Autowired
        private MinioProp minioProp;
    
        /**
         * 创建bucket
         *
         * @param bucketName bucket名称
         */
        @SneakyThrows
        public void createBucket(String bucketName) {
            if (!client.bucketExists(bucketName)) {
                client.makeBucket(bucketName);
            }
        }
    
        /**
         * 获取全部bucket
         */
        @SneakyThrows
        public List<Bucket> getAllBuckets() {
            return client.listBuckets();
        }
    
        /**
         * 根据bucketName获取信息
         *
         * @param bucketName bucket名称
         */
        @SneakyThrows
        public Optional<Bucket> getBucket(String bucketName) {
            return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
        }
    
        /**
         * 根据bucketName删除信息
         *
         * @param bucketName bucket名称
         */
        @SneakyThrows
        public void removeBucket(String bucketName) {
            client.removeBucket(bucketName);
        }
    
        /**
         * 获取文件外链
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @param expires    过期时间 <=7
         * @return url
         */
        @SneakyThrows
        public String getObjectURL(String bucketName, String objectName, Integer expires) {
            return client.presignedGetObject(bucketName, objectName, expires);
        }
    
        /**
         * 获取文件
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @return 二进制流
         */
        @SneakyThrows
        public InputStream getObject(String bucketName, String objectName) {
            return client.getObject(bucketName, objectName);
        }
    
        /**
         * 上传文件
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @param stream     文件流
         * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
         */
        public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
            client.putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream");
        }
    
        /**
         * 上传文件
         *
         * @param bucketName  bucket名称
         * @param objectName  文件名称
         * @param stream      文件流
         * @param size        大小
         * @param contextType 类型
         * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
         */
        public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
            client.putObject(bucketName, objectName, stream, size, contextType);
        }
    
        /**
         * 获取文件信息
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
         */
        public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception {
            return client.statObject(bucketName, objectName);
        }
    
        /**
         * 删除文件
         *
         * @param bucketName bucket名称
         * @param objectName 文件名称
         * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
         */
        public void removeObject(String bucketName, String objectName) throws Exception {
            client.removeObject(bucketName, objectName);
        }
    
        /**
         * 上传文件
         *
         * @param file       文件
         * @param bucketName 存储桶
         * @return
         */
        public JSONObject uploadFile(MultipartFile file, String bucketName) throws Exception {
            JSONObject res = new JSONObject();
            res.put("code", 0);
            // 判断上传文件是否为空
            if (null == file || 0 == file.getSize()) {
                res.put("msg", "上传文件不能为空");
                return res;
            }
            try {
    	       	// 判断存储桶是否存在
    	        createBucket(bucketName);
    	        // 文件名
    	        String originalFilename = file.getOriginalFilename();
    	        // 新的文件名 = 存储桶名称_时间戳.后缀名
    	        String fileName = bucketName + "_" + System.currentTimeMillis() + originalFilename.substring(originalFilename.lastIndexOf("."));
    	        // 开始上传
    	        client.putObject(bucketName, fileName, file.getInputStream(), file.getContentType());
    	        res.put("code", 1);
    	        res.put("msg", minioProp.getEndpoint() + "/" + bucketName + "/" + fileName);
    	        return res;
    		}  catch (Exception e) {
                log.error("上传文件失败:{}", e.getMessage());
            }
            res.put("msg", "上传失败");
            return res;
        }
    }
    
    

    文件的下载功能代码,在后续的文章中会贴出

    Java Client 指南地址如下:

    https://docs.min.io/docs/java-client-quickstart-guide.html
    

    如您在阅读中发现不足,欢迎留言!!!

    展开全文
  • 【Servlet】servlet上传文件

    千次阅读 2021-06-10 11:00:54
    往lib目录下添加两个上传文件所需要的jar包。 2 编写上传文件的html页面 upload.html 添加meta标签,设置页面编码 form表单中action为uploadImg,表示对应的servlet。 method必须为post,才能上传文件。 还必须...
  • netty系列之:搭建HTTP上传文件服务器

    万次阅读 2021-09-06 12:56:02
    上一篇的文章中,我们讲到了如何从HTTP服务器中下载文件,和搭建下载文件服务器应该注意的问题,使用的GET方法。本文将会讨论一下常用的向服务器提交数据的POST方法和如何向服务器上传文件
  • Java上传文件到服务器端的方法

    千次阅读 2021-02-12 14:15:38
    Web文件上传采用POST的方式,与POST提交表单不同的是,上传文件需要设置FORM的enctype属性为multipart/form-data.由于上传的文件会比较大,因此需要设置该参数指定浏览器使用二进制上传。如果不设置,enctype属性...
  • 批量上传文件带进度条

    千次下载 热门讨论 2013-03-20 10:24:08
    批量上传文件带进度条批量上传文件带进度条批量上传文件带进度条批量上传文件带进度条
  • java实现上传文件

    千次阅读 2022-01-13 11:37:08
    /*使用SpringBoot实现简单文件上传(上传至本地)*/ @PostMapping("/upload") //MultipartFile 接收前端传过来的文件 public String upload(@RequestBody MultipartFile file) throws IOException { // 注意 前端...
  • secureCRT上传文件

    千次阅读 2022-01-29 10:31:12
    4.然后就可以使用get+put命令进行下载和上传了,注意传文件时加 -r sftp> put DoDocuments/相册/WechatIMG20.jpeg sftp> put -r DoDocuments/相册/壁纸 sftp> get DoDocuments/相册/WechatIMG.
  • HTML上传文件

    千次阅读 2021-02-15 01:28:05
    文件上传表单: <form action="/" method="post" enctype="multipart/form-data"> <div><input type="file" multiple="multiple" accept="image/*" name="image"></div> <div><...
  • Vue使用formData类型上传文件

    千次阅读 2021-09-01 09:43:11
    这篇文章五分钟教会你上传文件。 1.如图片上传,后端需要前端传formData类型数据的情况下 <el-button type="primary" v-if="imgUrl2 ==''" @click="uploadFile2()">点击上传</el-button> <input ...
  • java后台发起上传文件的post请求(http和https)

    万次阅读 多人点赞 2019-07-31 19:11:04
    对于文件上传,客户端通常就是页面,在页面里实现上传文件不是什么难事,写个form,加上enctype="multipart/form-data",在写个接收的就可以了,没什么难的。如: <!DOCTYPEhtml> <html> <head> ...
  • ftp无法上传文件的原因

    千次阅读 2021-08-06 08:22:37
    前段时间小编再上传ftp文件的时候,忽然发现有些文件编辑后无法上传,下方一直显示传输失败。这时就需要ftp客户端来设置文件夹权限。如下图所示,找到相应的文件,右击,找到属性然后找到文件和文件夹下的写入和执行...
  • 1.将headers配置中,Content-Type配置为multipart/form-data 2.根据接口的实际情况配置参数,我的是form-data 3.Body中的文件参数名称配置为file ,类型选择file,选择文件 运行结果
  • java上传文件大小限制

    千次阅读 2021-03-08 22:06:26
    win系统下解决ASP上传文件大小限制200K_电脑基础知识_IT/计算机_专业资料。win系统下解决ASP上传文件大小限制200K 解决ASP 上传文件大小限制 200K win2003 系统下的 ......介绍 上传 // 新建一个 SmartUpload 对象 ...
  • elementui upload 上传文件详解

    万次阅读 多人点赞 2019-07-21 23:09:52
    before-upload:是你上传文件之前触发的函数,记住这个函数是上传文件前,不是选择文件之前,很多人在 这里设置了预览图片功能,但是如果一旦 auto-upload 关闭,也就不会自动上传,这个钩子也就不会触发。 。。。。。。...
  • JAVA开发 OSS上传文件

    万次阅读 2021-06-18 14:16:57
    参考链接:OSS 上传压缩文件,并自动解压 相关依赖: <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>2.8.3</...
  • Hadoop通过WEB上传文件到HDFS失败

    千次阅读 2021-12-15 10:10:15
    那时候用WEB上传文件到HDFS是正常的。 最近又用了一下,发现WEB不能上传文件了,浏览器中报错: Couldn’t upload the file xxxx.yyy 大概如下图: (一)可能的原因:目录权限 如上图,HDFS中创建目录的时候,仅...
  • Selenium-如何上传文件

    千次阅读 2022-01-09 06:45:10
    在前端点击的按钮,会跳出让我们去选择文件的框,这个弹出框Selenium是无法识别的,所以它不是真正负责上传文件的控件。 真正负责上传文件的控件应该是:, 我们需要做的就是定位到这个真正的控件,然后对其send_...
  • web前端js上传文件

    千次阅读 2019-06-23 16:19:00
    前端用的js+easyui Demo: <html> <head> <meta charset="UTF-8"> <...XMLHttpRequest上传文件</title> <script type="text/javascript"> //图片上传 var xh...
  • TortoiseSVN如何上传文件

    千次阅读 2021-10-22 09:32:28
    含义:把本地文件上传到SVN,上传成功后即本地文件的增删改操作后,commit后,服务器文件对应更新,与本地文件保持一致。 操作: 1、新建文件夹,右键选择SVN checkout 2、选择上传的服务器地址,即上传显示在...
  • 如何上传文件及文件夹到IPFS

    万次阅读 2021-09-02 14:36:57
    上传时,文 件会被分块保存在当前节点上(也就是运行IPFS进程的主机),当有其他节点请求并下载 这个文件后,这个文件会被这些节点缓存。如果一份文件十分冷门,导致所有节点缓存的 数据块拼...
  • ajax如何上传文件

    千次阅读 2020-06-14 08:53:23
    怎么用ajax上传文件?2. FormData是什么?3. FormData+ajax上传文件的注意事项?二、文件的上传(表单上传和ajax文件异步上传)三、注意 一、总结 1. 怎么用ajax上传文件? 使用FormData,FormData+ajax即可异步...
  • Hadoop基础操作--上传文件到HDFS

    千次阅读 2021-10-21 13:52:29
    文件系统是对文件存储设备的空间进行组织和分配,负责文件存储并对存入的文件进行保护和检索的系统。即:为用户建立文件、存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时删除文件。 现在我们的...
  • 8.使用xshell上传文件

    千次阅读 2022-01-10 14:24:08
    上传文件 1.安装rz命令 输入rz命令,看是否已经安装了lrzsz 如果没有安装则执行下方命令进行安装 # yum -y install lrzsz 2.确认是否正确安装 安装成功后,输入rpm命令确认是否正确安装 # rpm -qa lrzsz 3.上传...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,522,008
精华内容 608,803
关键字:

上传文件