Vue Implementation Click Button Download File Operation Code of Backend Java

  • 2021-11-13 00:23:36
  • OfStack

The last article introduced vue to realize the function of downloading files by clicking buttons. Today, we continue the topic of downloading files by clicking buttons by vue.

Recently, the project needs to realize the need to download files by clicking buttons. The front end uses vue, because files are of various types, such as pictures, pdf, word and so on. Here the back-end is able to return the address of the file to the front-end, but I looked at a variety of online 5 flower 8 door answers, feeling is not what I want.

Because we are not sure what type of file is, when we save the file to the database, we should store the Content-Type 1 of the file, so that when we take it out from the database and return it to the front end, we can take Content-Type to identify which type of file it is, and the front end can parse it.

1. Back-end code

Here I write the interface of the back end first, and consider what the back end needs under 1. Because the file information has been stored in the database in advance, we only need to pass in the primary key id to get the file information. After determining the parameters, you need to determine the return value type under 1. Here you can use ResponseEntity to return. ResponseEntity can return multiple information at one time, including status code, response header information, response content, etc.

Don't say much, look at the code.


/**
 *  Download attachments 
 * @param attachmentId
 * @return
 */
public ResponseEntity<byte[]> download(Long attachmentId) {
    //  Query if an attachment exists 
    SysAttachment sysAttachment = sysAttachmentMapper.selectSysAttachmentById(attachmentId);
    if (StringUtils.isNull(sysAttachment)) {
        return null;
    }

    ByteArrayOutputStream bos = null;
    InputStream ins = null;
    try {
        String fileName = sysAttachment.getOrgFileName();
        String ossFileName = sysAttachment.getUrl();
        bos = new ByteArrayOutputStream();
        ins = OssUtils.getInstance().getObject(ossFileName).getObjectContent();
        //  Fetch the data in the stream 
        int len = 0;
        byte[] buf = new byte[256];
        while ((len = ins.read(buf, 0, 256)) > -1) {
            bos.write(buf, 0, len);
        }

        //  Prevent Chinese garbled codes 
        fileName = URLEncoder.encode(fileName, "utf-8");
        //  Set the response header 
        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment;filename=" + fileName);
        headers.add("Content-Type", sysAttachment.getContentType());
        //  Set response 
        HttpStatus statusCode = HttpStatus.OK;
        ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(bos.toByteArray(), headers, statusCode);
        return response;
    } catch (Exception e) {
        throw new CustomException(" Download failed ");
    } finally {
        try {
            if (ins != null) {
                ins.close();
            }
            if (bos != null) {
                bos.close();
            }
        } catch (Exception e) {
            throw new CustomException(" Download failed ");
        }
    }
}

Here, after we take out the file url from the database, we get the input stream of the file through Alibaba Cloud oss, then output the file to binary, encapsulate it in ResponseEntity, and set the file type to Content-Type. At the same time, in order to prevent the file name from being garbled with Chinese name, we set utf-8 coding until the backend interface is completed.

Through the above information, when we save file information in the database, we should at least save the following fields: url of the file (1 will give you one after uploading to oss), file type, original file name, file size, etc.

2. Front-end code

With the back-end interface, the front-end is next. Here, the method of file download can be encapsulated into a general method for global mounting, and then the place where it needs to be used can be used directly.

We need to identify different files, so we need a key-value pair to represent different files.


const mimeMap = {
  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  xls: 'application/vnd.ms-excel',
  zip: 'application/zip',
  jpg: 'image/jpg',
  jpeg: 'image/jpeg',
  png: 'image/png',
  doc: 'application/msword',
  docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  ppt: 'application/vnd.ms-powerpoint',
  txt: 'text/plain',
  pdf: 'application/pdf'
}

If necessary, you can continue to supplement it. The next step is naturally to send a request. The return type here can be set to blob, and axios can be used to send it directly.


/**
 *  Download attachments 
 * @param path  Interface address 
 * @param param   Request parameter 
 */
export function downloadAttachment(path, param) {
  var url = baseUrl + path + param
  axios({
    method: 'get',
    url: url,
    responseType: 'blob',
    headers: { 'Authorization': getToken() }
  }).then(res => {
    resolveBlob(res, res.data.type)
  })
}

Interface address and request parameters are passed in from outside. At the same time, you need to carry token, otherwise it will be accessed across domains. After getting the data returned by the back end, we need to parse the binary file. Here, we define the resolveBlob method, which has two parameters, the type of the returned object and file, and the type of file. We have already put it into Content-Type at the back end, so we can take it directly here.


/**
 *  Analyse blob Respond to content and download 
 * @param {*} res blob Response content 
 * @param {String} mimeType MIME Type 
 */
export function resolveBlob(res, mimeType) {
  const aLink = document.createElement('a')
  var blob = new Blob([res.data], { type: mimeType })
  //  From response Adj. headers Get from filename,  Back end response.setHeader("Content-disposition", "attachment; filename=xxxx.docx")  File name set ;
  var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
  var contentDisposition = decodeURI(res.headers['content-disposition'])
  var result = patt.exec(contentDisposition)
  var fileName = result[1]
  fileName = fileName.replace(/\"/g, '')
  aLink.href = URL.createObjectURL(blob)
  aLink.setAttribute('download', fileName) //  Set the download file name 
  document.body.appendChild(aLink)
  aLink.click()
  document.body.removeChild(aLink);
}

There is no need to explain this code. The front-end bosses can understand it naturally. OK ah, here before and after the end of the code has been completed.

3. Use

It's easier to use. First mount to global


import { downloadAttachment } from "@/utils/download"
Vue.prototype.downloadAttac = downloadAttachment

You can call it directly where you use it


<el-button
    type="text"
    icon="el-icon-download"
    size="mini"
    @click="downloadAttachRow(scope.row.attachmentId)"
    ></el-button>

/**  Download attachments  */
downloadAttachRow(attachId) {
    this.$confirm(' Are you sure you want to download this file ?', " Warning ", {
        confirmButtonText: " Determine ",
        cancelButtonText: " Cancel ",
        type: "warning"
    }).then(() => {
        this.downloadAttac('/system/attachment/download/', attachId)
    }).then(() => {
        this.msgSuccess(" Download succeeded ")
    }).catch(() => {})
}

That's it.


Related articles: