zoukankan      html  css  js  c++  java
  • Springboot文件上传下载

    Springboot文件上传下载

    文件的上传操作

    前端代码

    <form action="http://localhost:8091/file" method="post" 
          enctype="multipart/form-data">
        <input name="fileImage" type="file" />
        <input type="submit" value="提交"/>
    </form>
    

    服务端controller

    @RequestMapping("/upload")
    public String file(MultipartFile fileImage) {
        String fileDirPath = "D:/images"; // 存放位置
        File dirFile = new File(fileDirPath); 
        // 判断文件目录是否存在
        if (!dirFile.exists()) {
            // 如果目录没有, 则应该新建目录
            dirFile.mkdir();
        }
        // 准备文件上传路径, 路径 + 文件名称
        String fileName = fileImage.getOriginalFilename(); // 获取文件名
        File realFile = new File(fileDirPath + "/" + fileName); // 保存磁盘路径 + 文件名拼接
        // 将字节信息输出到文件中
        try {
            fileImage.transferTo(realFile); // 保存到指定的路径
            return "文件上传成功";
        } catch (IOException e) {
            e.printStackTrace();
            return "文件上传失败";
        }
    }
    

    文件下载操作

    下载操作也是非常的简单, 我们只需要用流的形式返回到客户端即可

    别看长, 其实没多少代码

    @RequestMapping("/download")
    @ResponseBody
    public String downloadFile(HttpServletResponse response) {
        String fileName = "aaa.txt";// 设置文件名,即用户下载得到文件的名字(可以和磁盘中的文件名不同)
        if (fileName != null) {
            //设置文件路径
            String filePath = "D:/file/001.txt"; // 要下载的文件位置
            File file = new File(filePath);
            if (file.exists()) {
                // 关于: application/octet-stream
                // 1、只能提交二进制,而且只能提交一个二进制,如果提交文件的话,只能提交一个文件,后台接收参数只能有一个,而且只能是流(或者字节数组)
                // 2、属于HTTP规范中Content-Type的一种
                // 3、很少使用
                response.setContentType("application/octet-stream");
                // response.setHeader("content-type", "application/octet-stream"); // 也可以这样写
                response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
                byte[] buffer = new byte[1024];
                FileInputStream fis = null;
                BufferedInputStream bis = null;
                try {
                    fis = new FileInputStream(file);
                    bis = new BufferedInputStream(fis);
                    OutputStream os = response.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1) {
                        os.write(buffer, 0, i);
                        i = bis.read(buffer);
                    }
                    System.out.println("success"); // 下载成功返回信息
                } catch (Exception e) {
                    e.printStackTrace();
                } finally { // 关闭流
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (fis != null) {
                        try {
                            fis.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return null; // 下载失败返回信息
    }
    

    扩展: 上传图片并校验

    上传图片是经常有的操作, 所以在上传图片的时候也要对文件进行校验, 防止不符合规范的文件或者伪装的木马病毒等, 例如:

    1. 校验文件的有效性
    2. 校验文件是否为恶意程序
    3. 提高用户简餐图片的效率 分目录存储
    4. 为了防止重名图片的提交 自定义文件名
    5. 实现图片的物理上传
    6. 准备一个访问的虚拟路径

    Controller编写

    @Autowarld
    private FileService fileService;
    
    @RequestMapping("/pic/upload")
    public ImageVO upload(MultipartFile uploadFile) {
        return fileService.upload(uploadFile); // 调用service进行保存图片
    }
    

    Service编写(接口略)

    service类-结构

    @Service
    public class FileServiceImpl implements FileService {
    	@Override
        public ImageVO upload(MultipartFile uploadFile) {
            
        }
    }
    

    1.校验文件后缀

    service中定义一个localDirPath静态变量, 用于存储支持的图片你后缀, 例如:

    private static Set<String> imageTypeSet = new HashSet<>();
    static {
        imageTypeSet.add(".jps");
        imageTypeSet.add(".png");
        imageTypeSet.add(".gif");
        imageTypeSet.add("/bmp");
        //.....其他省略
    }
    

    upload方法中

    // 1. 图片的类型 (1) 利用正则表达式   (2) 利用集合的方式进行校验Set 数据是否存在即可
    String fileName = uploadFile.getOriginalFilename();
    // 获取后缀 并转为全小写
    String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
    if (!imageTypeSet.contains(fileType)) { // 如果后缀没在集合中, 则上传失败
        return ImageVO.fail();
    }
    

    2.检验是否为图片

    upload方法中

    //  2. 如何判断文件是否为恶意程序, 是否有图片的属性
    // 2.1 将上传文件类型利用图片API进行转化
    try {
        BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
        // 2.2 校验是否有图片的特有属性 高度, 宽度
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();
        // 2.3 校验宽度和高度是否有值
        if (width == 0 || height == 0) {
            return ImageVO.fail();
        }
    } catch (IOException e) {
        e.printStackTrace();
        return ImageVO.fail();
    }
    

    3.分目录存储

    service中定义属性, 表示文件存储的位置根路径

    private String localDirPath = "D:/images"; // 定义本地磁盘目录
    

    upload方法中

    // 3. 实现分目录存储:
    // 方案1: 利用hash之后每隔2-3位截取之后拼接
    // 方案2: 以时间为单位进行分割   /yyyy/MM/dd/ 这里使用方案2, 方案1自行脑补
    // 3.1 利用工具的API将时间转化为执行的格式
    String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
    // 3.2 动态生成文件目录 2部分=根目录+时间目录
    String localDir = localDirPath + datePath;
    // 3.3 判断目录是否存在, 如果不存在则新建目录
    File dirFile = new File(localDir);
    if (!dirFile.exists()) {
        dirFile.mkdirs(); // 如果不存在, 则新建目录
    }
    

    4.自定义文件名称

    使用UUID自定义名称

    //4. 防止文件重名, 需要自定义文件名称 UUID
    //4.1 生成uuid
    String uuid = UUID.randomUUID().toString().replace("-", "");
    //4.2动态生成文件名称
    String uuidFileName = uuid + fileType;
    

    5.保存上传的文件

    // 5. 实现文件的上传
    String realFilePath = localDir + uuidFileName;
    // 5.1 封装文件的真实对象
    File imageFile = new File(realFilePath);
    // 5.1 实现文件的保存
    try {
        uploadFile.transferTo(imageFile);
    } catch (IOException e) {
        e.printStackTrace();
        return ImageVO.fail();
    }
    

    6.返回虚拟url路径

    // 6.暂时使用京东的路径代替
    // 检查文件上传业务调用是否正确
    // [http://image.jt.com] + [/yyyy/MM/dd/] + [文件名]
    String url =  urlPath + datePath + uuidFileName;
    return ImageVO.succcess(url);
    

    完整文件如下

    @Service
    @PropertySource("classpath:/properties/image.properties")
    public class FileServiceImpl implements FileService {
    
        private static Set<String> imageTypeSet = new HashSet<>();
        @Value("${image.localDirPath}")
        private String localDirPath; // 定义本地磁盘目录
        static {
            imageTypeSet.add(".jps");
            imageTypeSet.add(".png");
            imageTypeSet.add(".gif");
            imageTypeSet.add("." +
                    "bmp");
            //.....其他省略
        }
    
        @Value("${image.urlPath}")
        private String urlPath;
    
    
        /**
         * 1. 校验文件的有效性   .jsp|.png|.bmp|.gif
         * 2. 校验文件是否为恶意程序
         * 3. 提高用户简餐图片的效率  分目录存储
         * 4. 为了防止重名图片的提交  自定义文件名
         * 5. 实现图片的物理上传
         * 6. 准备一个访问的虚拟路径
         */
        @Override
        public ImageVO upload(MultipartFile uploadFile) {
            // 1. 图片的类型 (1) 利用正则表达式   (2) 利用集合的方式进行校验Set 数据是否存在即可
            String fileName = uploadFile.getOriginalFilename();
            // 获取后缀 并转为全小写
            String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
            if (!imageTypeSet.contains(fileType)) {
                return ImageVO.fail();
            }
    
            //  2. 如何判断文件是否为恶意程序, 是否有图片的属性
            // 2.1 将上传文件类型利用图片API进行转化
            try {
                BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
                // 2.2 校验是否有图片的特有属性 高度, 宽度
                int width = bufferedImage.getWidth();
                int height = bufferedImage.getHeight();
                // 2.3 校验宽度和高度是否有值
                if (width == 0 || height == 0) {
                    return ImageVO.fail();
                }
            } catch (IOException e) {
                e.printStackTrace();
                return ImageVO.fail();
            }
    
            // 3. 实现分目录存储:
            // 方案1: 利用hash之后每隔2-3位截取之后拼接
            // 方案2: 以时间为单位进行分割   /yyyy/MM/dd/
            // 3.1 利用工具的API将时间转化为执行的格式
            String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
            // 3.2 动态生成文件目录 2部分=根目录+时间目录
            String localDir = localDirPath + datePath;
            // 3.3 判断目录是否存在, 如果不存在则新建目录
            File dirFile = new File(localDir);
            if (!dirFile.exists()) {
                dirFile.mkdirs(); // 如果不存在, 则新建目录
            }
    
            //4. 防止文件重名, 需要自定义文件名称 UUID
            //4.1 生成uuid
            String uuid = UUID.randomUUID().toString().replace("-", "");
            //4.2动态生成文件名称
            String uuidFileName = uuid + fileType;
    
            // 5. 实现文件的上传
            String realFilePath = localDir + uuidFileName;
            // 5.1 封装文件的真实对象
            File imageFile = new File(realFilePath);
            // 5.1 实现文件的保存
            try {
                uploadFile.transferTo(imageFile);
            } catch (IOException e) {
                e.printStackTrace();
                return ImageVO.fail();
            }
    
            // 6.暂时使用京东的路径代替
            // 检查文件上传业务调用是否正确
            // [http://image.jt.com] + [/yyyy/MM/dd/] + [文件名]
            String url =  urlPath + datePath + uuidFileName;
            return ImageVO.succcess(url);
        }
    }
    

    页面显示图片

    可参考nginx中的图片服务器配置 [点击跳转到nginx图片服务器配置]

  • 相关阅读:
    5,pandas高级数据处理
    4,根据美国各州人口,土地面积进行数据分析
    3,Python常用库之三:Matplotlib
    2,Python常用库之二:Pandas
    1,Python常用库之一:Numpy
    18,增量式爬虫
    17,基于scrapy-redis两种形式的分布式爬虫
    http超文本传输协议,get与post区别
    优化css,增加性能
    bootstrap常用知识点总结
  • 原文地址:https://www.cnblogs.com/zpKang/p/13446948.html
Copyright © 2011-2022 走看看