JavaWeb的Servlet实现文件上传功能

JavaWeb的Servlet实现文件上传功能

1. maven需要导入的jar

除了servlet的包之外还需要引入文件上传的jar以及返回json的jar

 <!-- 导入文件流 -->
    <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

    <!-- FastJson库 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.47</version>
    </dependency>

2. servlet的实现

package com.jzq.servlet.user;

import com.alibaba.fastjson.JSON;
import com.jzq.util.responseUtil.Result;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.ProgressListener;
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.*;
import java.util.*;

@WebServlet(name = "upload", value = "/upload")
public class FileServlet extends HttpServlet{
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 判断上传的文件是普通表单还是带文件的表单
        if (!ServletFileUpload.isMultipartContent(req)) {
            return; // 终止方法的运行,说明这是一个普通的表单,直接返回
        }

        // 创建上传文件的保存路径,建议在WEB-INF路径下,用户无法之际访问上传的文件
        String uploadPath = "F:/JavawebProject/fzfbwpClient/src/main/webapp/userResources/upload";
        File uploadFile = new File(uploadPath);
        if(!uploadFile.exists()) {
            uploadFile.mkdir(); // 创建这个路径
        }

        // 缓存,临时文件
        // 假如文件超过某种限制,我们就将它放到一个临时文件中,过几天自动删除
        //String tmpPath = this.getServletContext().getRealPath("/WEB-INF/tmpUpload");
        String tmpPath = "F:/JavawebProject/fzfbwpClient/src/main/webapp/userResources/tempUpload";
        File tmpUploadFile = new File(tmpPath);
        if(!tmpUploadFile.exists()) {
            tmpUploadFile.mkdir(); // 创建这个临时目录
        }

        // 处理上传的文件,一把需要通过流来获取,我们可以使用request.getInputStream(), 原生态的文件上传流获取,十分麻烦。
        // 建议使用 Apache的文件上传组件来实现, common-fileupload, 他需要依赖commons-io组件

        try {
            // 1. 创建DiskFileItemFactory对象,处理文件上传路径或者大小大小限制的;
            DiskFileItemFactory factory = getDiskFileItemFactory(tmpUploadFile);
            // 2. 获取ServletFileUpload
            ServletFileUpload upload = getServletFileUpload(factory);
            // 3. 处理上传的文件
            // 接收处理好的数据
            String jsonData = JSON.toJSONString(uploadParseRequest(upload, req, uploadPath));
            PrintWriter printWriter = resp.getWriter();
            printWriter.write(jsonData);

            // 显示提示消息
            //req.setAttribute("msg", msg);
            //req.getRequestDispatcher("/jsp/user/infoMsg.jsp").forward(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static DiskFileItemFactory getDiskFileItemFactory(File file) {
        // 1. 创建DiskFileItemFactory对象,处理文件上传路径或者大小限制
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 通过这个工厂设置一个缓冲区,当上传的文件大于这个缓冲区的时候,将它放到临时文件;
        factory.setSizeThreshold(1024 * 1024); // 缓存区大小为1M
        factory.setRepository(file);  // 临时目录的保存目录,需要一个file
        return factory;
    }

    public static ServletFileUpload getServletFileUpload(DiskFileItemFactory factory) {
        // 2. 获取ServletFileUpload
        ServletFileUpload upload = new ServletFileUpload(factory);

        // 监听文件的上传进度
        upload.setProgressListener(new ProgressListener() {
            @Override
            // pBytesRead: 已经读取到的文件大小
            // pContentLength:文件大小
            public void update(long pBytesRead, long pContentLength, int pTtems) {
                //System.out.println("总大小:" + pContentLength + "已上传" + pBytesRead);
            }
        });

        // 处理乱码问题
        upload.setHeaderEncoding("UTF-8");
        // 设置单个文件的最大值
        upload.setFileSizeMax(1021 * 1024 * 100);
        // 设置总共能上传文件的大小
        // 1024 - 1kb * 1024 = 1M * 10 = 10M
        upload.setSizeMax(1024 * 1024 *1000);

        return upload;
    }

    // 封装为结果类, 方便返回json
    public static Result uploadParseRequest(ServletFileUpload upload, HttpServletRequest request, String uploadPath) throws FileUploadException, IOException {
        // 3. 处理上传的文件
        // 把前端请求解析,封装成一个 FileItem对象,需要从ServletFileUpload对象中获取
            List<FileItem> fileItemList = upload.parseRequest(request);
            // 返回提示
            //String msg = "初始提示";
            // 返回保存
            Map<String, String> dataMap = new HashMap<>();
            // fileItem 是每一个表单对象
            System.out.println(fileItemList.size());
            for (FileItem fileItem : fileItemList
            ) {

                // 判断上传的文件是普通的表单还是带文件的表单
                if (fileItem.isFormField()) {
                    // getFieldName 指的是前端表单控件的name
                    String name = fileItem.getFieldName();
                    String value = fileItem.getString("UTF-8"); // 处理乱码
                } else {// 文件
                    // ============================  处理文件数据  ==============================


                    String uploadFileName = fileItem.getName();
                    // 可能存在文件名不合法,验证sql注入文件
                    if (uploadFileName.trim().equals("") || uploadFileName == null) {
                        continue;
                    }
                    // 获得上传的文件名 /images/xxx/xx.png
                    String fileName = uploadFileName.substring(uploadFileName.lastIndexOf("/") + 1);
                    // 获取文件的后缀名
                    String fileExtName = uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1);

                    // 检测文件名(防止文件注入)
                    List<String> fileExts = new LinkedList<String>() {{
                        add("jpeg");
                        add("png");
                        add("jpg");
                        add("mp4");
                        add("mp3");
                    }};
                    if (!fileExts.contains(fileExtName)) {
                        return Result.failure("kobe08", "文件后缀不安全!");
                    }

                    /*
                        如果文件后缀不合法,我们要直接return,告诉用户文件不合法
                     */

                    // ============================  存放地址  ==============================
                    // 存到什么地方? uploadPath
                    // 文件真实存在的路径 realPath
                    String realPath = uploadPath + "/";
                    String realExtPath = "";
                    if ("mp4".equals(fileExtName)) {
                        realExtPath = "mv/";
                    } else {
                        realExtPath = "img/";
                    }
                    // 拼接真正路径
                    realPath = realPath + realExtPath;
                    fileName = UUID.randomUUID().toString() + fileName;
                    // 给每个文件创建一个对应的文件夹
                    File realPathFile = new File(realPath);
                    if(!realPathFile.exists()) {
                        realPathFile.mkdir();
                    }
                    // ============================  文件传输  ==============================
                    // 获得文件上传的流
                    InputStream inputStream = fileItem.getInputStream();

                    // 创建一个文件输出流
                    // realPath = 真实文件路径
                    // 差了一个文件; 加上输出文件的名字 + "/" + 文件名
                    FileOutputStream fileOutputStream = new FileOutputStream(realPath + fileName);
                    // 创建一个缓冲区
                    byte[] buffer = new byte[1024 * 1024];

                    // 判断是否读取完毕
                    int len = 0;
                    // 如果大于0说明还存在数据
                    while ((len = inputStream.read(buffer))>0) {
                        fileOutputStream.write(buffer, 0, len);
                    }

                    // 关闭流
                    fileOutputStream.close();
                    inputStream.close();

                    dataMap.put("url", "http://127.0.0.1:7777/userResources/upload/"+realExtPath+fileName);
                    fileItem.delete(); // 上传成功后清除临时文件
                }
            }
        return Result.success(dataMap, "上传成功!");
    }
}

3.封装的结果类

3.1 结果类

package com.jzq.util.responseUtil;

import java.io.Serializable;

public class Result implements Serializable {

    private static final long serialVersionUID = -3948389268046368059L;

    private String code;

    private String msg;

    private Object data;

    public Result() {}

    public Result(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public static Result success() {
        Result result = new Result();
        result.setCode(ResponseCode.SUCCESS);
        return result;
    }

    public static Result success(Object data) {
        Result result = new Result();
        result.setCode(ResponseCode.SUCCESS);
        result.setData(data);
        return result;
    }

    public static Result success(Object data, String msg) {
        Result result = new Result();
        result.setCode(ResponseCode.SUCCESS);
        result.setData(data);
        result.setMsg(msg);
        return result;
    }

    public static Result failure(String code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

    public static Result failure(String code, String msg, Object data) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }

    public String getCode() {
        return this.code;
    }

    public void setCode(final String code) {
        this.code = code;
    }

    public String getMsg() {
        return this.msg;
    }

    public void setMsg(final String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return this.data;
    }

    public void setData(final Object data) {
        this.data = data;
    }
}

3.2 响应码

package com.jzq.util.responseUtil;

public final class ResponseCode {
    public static final String SUCCESS = "kobe24";   //成功
    public static final String ERROR_08 = "kobe08";// 系统异常

    public static final String ERROR_PARAMS_VALIDATOR="kobe5"; //参数验证错误

    public static final String ERROR_SERVICE_VALIDATOR="kobe9"; //业务验证错误

    public static final String ERROR_DATA_VALIDATOR="kobe7";  //系统数据错误

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值