AngularJS + Spring MVC 多文件 本地 上传和下载

文章目录

需求:可以选择多文件,并展示出来,可以进行前端删除,选择需要的进行上传和下载附件

<h1>多文件选择上传</h1>
    <input id="selectInputFile" name="selectInputFiles" multiple="multiple" type="file" style="display:none"/>
    <ol>
        <li ng-repeat="file in repeatFiles track by $index">
            <span>{{file.name}}</span>
            <a href="javascript:void(0);" ng-click="deleteRepeatFile($index)">删除</a>
        </li>
    </ol>
<button class="btn" type="submit" ng-click="selectFile()">选择文件</button>
<button class="btn" type="submit" ng-click="fileUpload()">上传</button>

隐藏一个input type=“file” 去选择文件,当点击“选择文件”的时候,去触发 input type="file"的点击事件

//选择文件按钮触发 input type='file' 选择文件
$scope.selectFile = function(){
    $("#selectInputFile").click();
};

再监听选择文件的change事件,获取当前选择的文件push到已有的里面,更新

两种方式都可以获取文件的数组,一般情况下,currentTarget 和 this 是一样的。

添加后面选择的文件时,循环push的话,把一个个file加到 newRepeatFile 里面;如果是concat,直接添加一个数组,就会有一个 fileList在数组里,页面 ng-repeat 的时候,会有一个空的显示在页面。

//监听 input type='file' 的change事件
$("#selectInputFile").on("change",function (e) {
    var selectFiles = document.querySelector('input[name="selectInputFiles"]').files;
    //或 e.currentTarget获取文件
    //var selectFiles2 = e.currentTarget.files;

    //使用concat直接添加数组,最后会加一个数组进去,页面循环会有问题
    var newRepeatFile = $scope.repeatFiles;
    for (var i=0; i<selectFiles.length; i++) {
        newRepeatFile.push(selectFiles[i]);
    }

    $scope.$apply(function () {
        $scope.repeatFiles = newRepeatFile;
    });
});

删除的点击事件

$scope.deleteRepeatFile = function(index){
    $scope.repeatFiles.splice(index,1);
};

1. 上传

上传按钮点击事件

FormData为序列化表以及创建与表单格式相同的数据(当然是用于XHR传输)提供便利。

直接append,同样的key,后面的value会变成一个数组

Angular 默认的transformRequest方法会尝试序列化我们的FormData对象,因此此处我们使用angular.identity函数来覆盖它;另外,angular 在发送 POST 请求的时候使用的默认Content-Type是application/json,因此此处需要调整为undefined,这时浏览器会自动的帮我们设置成 multipart/form-data的编码方式,同时还会生成一个合适的boundary,如果手动设置成 multipart/form-data 的话就不会生成 boundary 字段了。

$scope.fileUpload = function () {
    var form = new FormData();
    var selectFiles = $scope.repeatFiles;
     for (var i=0; i<selectFiles.length; i++) {
        form.append("file", selectFiles[i]);
      }

    var url = 'file/upload';
    $http({
        method: 'POST',
        url: Config.getApiRemoteUrl() + url,
        data: form,
        headers: {
            'Content-Type':undefined
        },
        transformRequest: angular.identity
    }).then(function successCallback(response) {
        if(response.status === 200){
            layer.msg("success");
        }else{
            layer.msg("fail");
        }
    }, function errorCallback(response) {
        layer.msg("error");
    });
};

后端上传接口,写到本地路径,localUploadDir 定义了一个本地文件夹,根据年月日时分秒新建文件夹存储文件

private static String localUploadDir;

@Value("${local.fileserver.dir:''}")
public void setLocalUploadDir(String uploadDir) {
    localUploadDir = uploadDir;
}

@PostMapping("/upload")
public void uploadFile(@RequestParam(value = "file") MultipartFile[]  files){
    if(files != null && files.length > 0){
        for(MultipartFile file : files){
            System.out.println("保存完成 : " + saveUploadFile(file));
        }
    }
}

private String saveUploadFile(MultipartFile multipartFile) {
    Calendar now = Calendar.getInstance();
    String fileName = multipartFile.getOriginalFilename();
    // 设定文件保存的目录,按年月日时分秒创建文件夹
    String path = localUploadDir +
        now.get(Calendar.YEAR) + "/" +
        (now.get(Calendar.MONTH) + 1) + "/" +
        now.get(Calendar.DAY_OF_MONTH) + "/" +
        now.get(Calendar.HOUR_OF_DAY) + "/" +
        now.get(Calendar.MINUTE) + "/" +
        now.get(Calendar.SECOND) + "/";
    File file = new File(path);
    if (!file.exists()){
        file.mkdirs();
    }
    try (
            FileOutputStream fileOutputStream = new FileOutputStream(path + fileName);
            InputStream inputStream = multipartFile.getInputStream();
            ) {
        if (!multipartFile.isEmpty()) {
            int len;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) > 0){
                fileOutputStream.write(buffer,0, len);
            }
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return path + fileName;
}

效果
文件上传

2. 下载

文件下载使用a标签,直接把url写在里面

<h1>a标签 文件下载</h1>
<a target="_self" id="download" ng-click="fileDownload()">下载</a>

后端下载接口

在服务器设置响应头,告诉浏览器以 utf-8 的编码显示数据,如果不写会出现中文乱码

设置内容类型为 application/octet-stream 即 .* 代表二进制流,不知道下载文件类型

Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。Content-disposition其实可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,文件直接在浏览器上显示或者在访问时弹出文件下载对话框。

文件名为 new String(fileName.getBytes(“GB2312”), “ISO8859-1”)

ISO8859-1是页面上数据传输的格式

GB2312是你java项目格式(根据实际项目变更),目的是为了将中文文件名正确显示在页面上。防止中文乱码

@GetMapping("/download")
public void downloadFile(HttpServletResponse response) {
    String filePath = localUploadDir + "2019/6/6/11/2/28/测试上传1.txt";
    String fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
    response.setCharacterEncoding ("utf-8");
    //二进制流
    response.setContentType("application/octet-stream");
    try (
        FileInputStream fileInputStream = new FileInputStream(filePath);
        ServletOutputStream servletOutputStream = response.getOutputStream();
        ){
        //附件
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("GB2312"), "ISO8859-1"));
        int len;
        byte[] buffer = new byte[1024];
        while ((len = fileInputStream.read(buffer)) > 0){
            servletOutputStream.write(buffer,0, len);
        }
    }catch (IOException e){
        e.printStackTrace();
    }
}

替换a标签的超链接url

$scope.fileDownload = function () {
    $('#download').attr('href', './api/file/download');
};

效果
文件下载
application.yml 配置文件

server:
  servlet:
    context-path: /file
  port: 8123

spring:
  thymeleaf:
    cache: false
    encoding: UTF-8
  servlet:
    multipart:
      #上传文件最大大小
      max-file-size: 100MB
      max-request-size: 1000MB

debug: true

local:
  fileserver:
    dir: D:/uploadfile/
    path: /uploadfile/**

参考:
百度知道
header中Content-Disposition的作用与使用方法
文件上传与 Angular

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值