• Java、servlet、Tomcat实现文件上传操作


    一、写在前面的话

    1.1、环境说明

    Tomcat:9.0.6
    Java:1.8.0_281
    lib:TomCat下的lib、commons-fileupload-1.2.2.jar、commons-io-2.4.jar

    1.2、观看基础推荐说明

    1. 需要掌握Java的继承、方法重写
    2. 需要掌握基础的Java语言逻辑
    3. 需要掌握基础的Java方法调用
    4. 需要掌握Java的类的引用
    5. 需要了解servlet的简单使用
    6. 需要掌握前后端交互的基本使用
    7. 需要掌握Tomcat的配置,及Java工程的创建、Java外部包的引用
    8. 需要掌握简单的Html页面书写
    9. 需要具备高中及以上数学知识水平
    10. 需要对文件编码格式有一定了解

    二、单一功能实现代码说明

    2.1、前端代码——使用简单的Html5页面

    注意事项
    1. 此方法采用form表单提交
    2. form表单的提交方式必须为post,说明:文件上传将会以IO流的方式,此时会对数据进行转换,get方式无法完整存储
    3. form必须添加enctype属性,并声明类型为数据传输(multipart/form-data
    4. required表示必填,即不进行文件上传无法点击上传按钮
    5. type="file"表示为文件上传,是HTML5自带属性
    6. action="upload.do"为文件上传地址的配置,upload.do是在servlet中设置,也可以在xml中配置
    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>文件上传title>
    head>
    <body>
    <h1>文件上传h1>
    <form method="post" action="upload.do" enctype="multipart/form-data">
      上传文件:
      <input type="file" name="file" required>
      <input type="submit" value="上传">
      <input type="reset" value="取消">
    form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.2、前后端连接servlet文件书写——使用语言Java

    注意事项
    1. package 后的内容需要根据自己项目自行修改
    2. 文件上传需要commons-fileupload-1.2.2.jar、commons-io-2.4.jar的架包
    3. 此方法中文件上传是直接书写在了servlet中,供做学习使用,耐心看完所有注释,此方法中对于文件上传出现的种种可能都做出了处理位置,可以自行添加,也可以不做处理
    4. 此方法form必须有enctype="multipart/form-data"的属性
    5. 此方法使用了文本标记语言@WebServlet(“/upload.do”),若已经在web.xml中进行了servlet的配置,请删除任意其中一个的配置,这两种方法等价
    package com.fileUpload.servlet;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    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.util.List;
    
    /**
     * 类说明:完成文件上传操作
     * 继承于HttpServlet类,并重写doPost(HttpServletRequest, HttpServletResponse)方法
     */
    @WebServlet("/upload.do")
    public class Upload extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 设置请求的编码格式为UTF-8(在此版本中Tomcat已经具备HttpServletRequest为UTF-8的编码格式,可以省略不写)
            request.setCharacterEncoding("UTF-8");
            // 设置响应的编码格式为UTF-8
            response.setContentType("text/html;charset=UTF-8");
    
            // 开始调用此类中包含的方法进行文件上传
            fileUpload(request, response);
        }
    
        /**
         * 文件上传——查看是否为文件上传类型
         * 如果不是则退出方法不再执行后续所有代码
         * 如果是文件上传类型,继续执行doUpload(HttpServletRequest, HttpServletResponse)方法
         * @param request 由前端页面传来的请求——来源于doPost(HttpServletRequest, HttpServletResponse)方法
         * @param response 由此处即后端,做出的响应——来源于doPost(HttpServletRequest, HttpServletResponse)方法
         */
        private void fileUpload(HttpServletRequest request, HttpServletResponse response) {
            // 是否为文件上传类型
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
            // 判断是否为文件上传类型
            if (isMultipart){
                // 是文件上传类型
                // 处理文件上传
                doUpload(request, response);
            }
            // 不是文件上传类型
            // return;
        }
    
        /**
         * 生成固定的系统路径,并创建这个目录
         * 路径创建完毕后,使用commons-fileupload-1.2.2.jar架包中的方法创建FileItemFactory、ServletFileUpload生成List对象
         * List对象将作为前端表单提交的所有信息的对象,其中包含了文件上传及非文件上传的所有信息
         * 遍历List对象,并判断是否为文件上传,即在前端中type=“file”,若不是则执行一般的表单提交方式,若是则执行文件上传操作
         * @param request 由前端页面传来的请求——来源于fileUpload(HttpServletRequest, HttpServletResponse)方法
         * @param response 由此处即后端,做出的响应——来源于fileUpload(HttpServletRequest, HttpServletResponse)方法
         */
        private void doUpload(HttpServletRequest request, HttpServletResponse response) {
        //文件路径设置部分
            // windows设置文件上传的路径(文件路径可自行设置,必须为绝对路径!!!)
                // 获取当前项目在windows中的路径
            String uploadPath = request.getServletContext().getRealPath("/");
                // 拼接路径,实现放在网站的部署目录下(File.separator就是一个右斜线"\")
            uploadPath = uploadPath + "upload" + File.separator;
    
            // 文件路径处理
            File uploadFile = new File(uploadPath);
            // 文件路径是否存在
            if (uploadFile.exists()){
                // 文件路径存在,不做处理(此处代码可做调整,作者为详细说明故如此书写)
            }else {
                // 文件路径不存在
                // 创建文件路径
                uploadFile.mkdir();
            }
    
        // 判断表单数据是否为文件上传部分
            // 创建文件上传所需API实例
            // 创建工厂
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 解析request请求,获取FileItem(commons-fileupload-1.2.2.jar架包内包含)对象集合
            List<FileItem> fileItemList = null;
            try {
                fileItemList = upload.parseRequest(request);
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
            // 遍历集合内的内容
            for (FileItem fileItem : fileItemList) {
                // 判断fileItem是否为普通的表单数据
                if (fileItem.isFormField()){
                    // 是普通表单数据,采用普通表单数据处理办法
                    doData(fileItem);
                }else {
                    // 非普通表单,而是文件数据,采用文件上传表单数据处理办法,根据返回值判定是否上传成功
                    boolean doFile = doFile(fileItem, uploadPath);
                    if (doFile){
                        // 文件上传成功!(此处自行处理,作者只是提供了一种可能和处理的位置)
                    }else {
                        // 文件上传失败!(此处自行处理,作者只是提供了一种可能和处理的位置)
                    }
                }
            }
        }
    
        /**
         * 普通表单处理,此处处理的为非文件上传的表单数据(在本次案例中对应前端无普通表单数据,故此方法不会被使用)
         * @param fileItem 在commons-fileupload-1.2.2.jar架包中包含的FileItem对象,由doUpload(HttpServletRequest, HttpServletResponse)方法创建并传递
         */
        private void doData(FileItem fileItem) {
            // 获取前端input中name属性名称,即中的user
            String filedName = fileItem.getFieldName();
            // 对结果进行UTF-8编码
            try {
                String value = fileItem.getString("UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            // 此处只是作者提供的一种最普通的处理方式,若只有文件上传的表单数据,此处可以直接省略
            switch (filedName){
                case "user":
                    // 暂时不做处理
                    break;
                case "fileType":
                    // 暂时不做处理
                    break;
                default:
                    System.out.println("数据上传input——name属性未找到!");
            }
        }
    
        /**
         * 对文件上传类型进行限制,限制方法为文件上传的后缀名是否符合(此处可添加对文件大小的限制)
         * 对文件进行重新命名,并保留原有后缀名
         * 执行文件上传
         * @param fileItem 在commons-fileupload-1.2.2.jar架包中包含的FileItem对象,由doUpload(HttpServletRequest, HttpServletResponse)方法创建并传递
         * @param uploadPath 文件上传路径,由doUpload(HttpServletRequest, HttpServletResponse)方法创建并传递
         * @return
         */
        private boolean doFile(FileItem fileItem, String uploadPath) {
            // 获取所上传文件的名称
            String fileName = fileItem.getName();
            // 判断是否真为文件上传,若无法获取文件上传名或文件上传名为空字符串,则认为为非文件上传类型
            if (fileName != null && !"".equals(fileName)){
                // 是真文件上传
                // 对上传文件进行限制,使用fileNewName(String)方法对文件进行限制,限制条件可自行书写
                boolean checkFile = checkFile(fileName);
                // 判断是否符合文件限制
                if (checkFile){
                    // 符合文件限制
                    // 设置文件新名字,使用checkFile(String)方法设置新的文件名称并返回,新文件名生成规则可自行设置(注意,名称如果重复将会覆盖原来的文件)
                    String fileNewName = fileNewName(fileName);
                    // 创建文件对象,根据文件路径及文件名称
                    File file = new File(uploadPath, fileNewName);
                    // 文件写入,此处将会产生Exception异常
                    try {
                        fileItem.write(file);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }else {
                    // 不符合文件限制
                }
            }else {
                // 不是真文件上传(此处自行处理,作者只是提供了一种可能和处理的位置)
            }
            return false;
        }
    
        /**
         * 产生新的文件名称,
         * 文件命名格式
         * 时间戳+随机数+原文件类型
         * 随机数范围[1000,10000)
         * @param fileName 原文件名称
         * @return 新的文件名称
         */
        private String fileNewName(String fileName) {
            // 获取最后一个“.”的位置,(作者提示:此处可以使用正则表达式进行限制)
            int index = fileName.lastIndexOf(".");
            // 通过最后一个“.”的位置,截取文件后缀名(.jpg)
            String fileType = fileName.substring(index);
            // 产生一个随机数作为新的文件名,随机数范围[1000,10000),大于等于1000小于10000
            int temp = (int)(Math.random() * 1000 + 9000);
            // 组成新的名字,时间戳+随机数+原文件类型
            String fileNewName = System.currentTimeMillis() + temp + fileType;
            return fileNewName;
        }
    
        /**
         * 判断是否符合此方法中限制的文件后缀
         * @param fileName 原文件名
         * @return true符合,false不符合
         */
        private boolean checkFile(String fileName){
            // 获取最后一个“.”的位置
            int index = fileName.lastIndexOf(".");
            // 通过最后一个“.”的位置,截取文件后缀名(jpg)
            String fileType = fileName.substring(index + 1);
            // 判断后缀名是否为png、jpg(equalsIgnoreCase不区分大小写)(可以自行添加,或采用switch的方式)
            if ("png".equalsIgnoreCase(fileType) ||
                    "jpg".equalsIgnoreCase(fileType)){
                // 文件后缀符合为png、jpg
                return true;
            }
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215

    三、整合为工具类使用代码说明——使用语言Java

    注意事项
    1. 此工具使用前请先观看本博客其他内容,以方便自己改写工具类的使用
    2. 此工具类为提供路径设置的方法,路径已在此工具中写死
    3. 再次强调,先观看前后端连接servlet文件书写——使用语言Java
    package com.community.utils;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.FileItemFactory;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    import javax.servlet.http.HttpServletRequest;
    import java.io.File;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 表单文件上传工具类
     * 使用说明:
     * 首先调用fileUpload()方法上传文件,如果不是文件上传类型返回null,是文件上传类型返回值中:Map<文件名,文件相对路径>,如果路径为null,则说明上传失败
     * fileUpload()方法获取到的路径,可以通过下标0、1、2、3......获取相应路径
     * 调用getMap()方法获取非文件上传类型的对象集合
     */
    public class FileUploads {
        /**
         * 非文件上传类型的参数返回,Map<文件名,value>
         */
        private Map<String,String> map = new HashMap<>();
        /**
         * 文件上传类型结果,Map<文件名,文件路径>
         */
        private Map<Integer,String> fileMap = new HashMap<>();
        /**
         * 文件上传路径
         */
        private String filePath = null;
        /**
         * 请求
         */
        private HttpServletRequest request = null;
    
        public Map<String, String> getMap() {
            return map;
        }
    
        /**
         * 文件路径设置
         */
        private void setFilePath() {
            // windows设置文件上传的路径
            String uploadPath = request.getServletContext().getRealPath("/") + "upload" + File.separator;
            System.out.println(request.getServletContext().getRealPath("/"));
            System.out.println(uploadPath);
            // 文件路径是否存在
            File uploadFile = new File(uploadPath);
            if (uploadFile.exists()){
                // 文件路径存在,不做处理
            }else {
                // 文件路径不存在
                // 创建文件路径
                uploadFile.mkdir();
            }
            this.filePath = uploadPath;
        }
    
        /**
         * 文件上传开始方法
         * @param request 请求
         * @throws Exception
         */
        public Map<Integer, String> fileUpload(HttpServletRequest request) throws Exception {
            // 设置请求对象
            this.request = request;
            // 文件上传,检测是否未文件上传类型
            boolean load = load();
            if (!load){
                return null;
            }
            // 设置路径
            setFilePath();
            // 执行上传操作
            doUpload();
            return fileMap;
        }
    
        /**
         * 文件上传,检测是否未文件上传类型
         * @return 是返回true,不是返回false
         */
        private boolean load() {
            // 是否为文件上传类型
            boolean isMultipart = ServletFileUpload.isMultipartContent(request);
            // 判断是否为文件上传类型
            if (isMultipart){
                // 是文件上传类型
                // 处理文件上传
                return true;
            }
            // 不是文件上传类型
            return false;
        }
    
        /**
         * 文件上传核心
         * @throws Exception
         */
        private void doUpload() throws Exception {
            // 创建文件上传所需API实例
            // 创建工厂
            FileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 解析request请求,获取FileItem(commons-fileupload-1.2.2.jar架包内包含)对象集合
            List<FileItem> fileItemList = null;
            fileItemList = upload.parseRequest(request);
    
    		int tempInt = 0;
            // 遍历集合内的内容
            for (FileItem fileItem : fileItemList) {
                // 判断fileItem是否为普通的表单数据
                if (fileItem.isFormField()){
                    // 是普通表单数据,并对数据进行编码
                    map.put(fileItem.getFieldName(),fileItem.getString("UTF-8"));
                }else {
                    // 非普通表单,而是文件数据
                    String fileNewName = doFile(fileItem);
                    if (fileNewName != null){
                        String tempStr = filePath + fileNewName;
                        fileMap.put(tempInt,tempStr);
                    }else {
                        fileMap.put(tempInt,null);
                    }
                    tempInt ++;
                }
            }
        }
    
        /**
         * 文件写入操作
         * @param fileItem FileItem实体类对象
         * @return 写入成功返回true,失败返回false
         * @throws Exception
         */
        private String doFile(FileItem fileItem) throws Exception {
            // 获取文件名称
            String fileName = fileItem.getName();
            // 判断是否真为文件上传
            if (fileName != null && !"".equals(fileName)){
                // 是真文件上传
                // 对上传文件进行限制
                boolean checkFile = checkFile(fileName);
                // 判断是否符合文件限制
                if (checkFile){
                    // 符合文件限制
                    // 设置文件新名字
                    String fileNewName = fileNewName(fileName);
                    // 创建文件对象,根据文件路径及文件名称
                    File file = new File(filePath, fileNewName);
                    // 文件写入
                    fileItem.write(file);
                    return fileNewName;
                }
            }
            return null;
        }
    
        /**
         * 文件名字限制操作
         * @param fileName 文件名
         * @return 符合返回true,不符合返回false
         */
        private boolean checkFile(String fileName){
            // 获取最后一个“.”的位置
            int index = fileName.lastIndexOf(".");
            // 通过最后一个“.”的位置,截取文件后缀名
            String fileType = fileName.substring(index + 1);
            // 判断后缀名是否为png、jpg(equalsIgnoreCase不区分大小写)
            if ("png".equalsIgnoreCase(fileType) ||
                    "jpg".equalsIgnoreCase(fileType)){
                // 文件后缀符合为png、jpg
                return true;
            }
            return false;
        }
    
        /**
         * 产生新的文件名称
         * @param fileName 文件名
         * @return 新的文件名
         */
        private String fileNewName(String fileName) {
            // 获取最后一个“.”的位置
            int index = fileName.lastIndexOf(".");
            // 通过最后一个“.”的位置,截取文件后缀名
            String fileType = fileName.substring(index);
            // 组成新的名字,时间戳+4位随机数+原文件类型
            String fileNewName = System.currentTimeMillis() + Integer.toString((int)(Math.random() * 1000 + 1000)) + fileType;
            return fileNewName;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
  • 相关阅读:
    websocket 初识
    win下的开发环境变量记录
    25期代码随想录算法训练营第二天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II
    跨时钟域问题(一)(建立时间保持时间和亚稳态)
    C#MessageBox的使用
    一种改进Harris算子的角点特征检测研究-含Matlab代码
    C#中通过LINQtoXML加载、创建、保存、遍历XML和修改XML树
    【NVMe2.0b 14-6】Format NVM、Keep Alive、Lockdown command
    SSM整合之Mybatis笔记(MyBatis的逆向工程(代码生成器))(P058—P059)
    【C++进阶之路】第十篇:C++的类型转换
  • 原文地址:https://blog.csdn.net/jule_zhou/article/details/128032819