Java文件下载,提供前端页面下载、HttpClient接口下载

学习Java的文件上传/下载需要先明白一下几点:

1、下载的资源,有两种:

1)、本地文件:即项目运行时可访问的文件目录,比如,在本机Idea中运行一个 fileServer,那么 fileServer 可访问的你电脑目录下文件做为下载资源;或者 fileServer 在服务器上运行,就是服务器上可访问的目录下文件资源。

2)、远程文件:fileServer 运行的网络环境中 可访问的 Ftp/SFtp或其他服务接口中获取的文件字节码,I/O流等。

2、下载方式: 就是谁来获取这些“下载文件”,比如 :客户端的浏览器或这其他开发者通过接口获取你的文件。

总结:首先,以上两点,你需要知道, 第一,提供的接口中文件从哪里来,是本地文件还是远程文件 ;第二、文件提供给谁下载,你的返回类型是什么,是一个字节码、还是一个输出流。

一、提供“本地文件” ,给浏览器、前端Ajax或其他开发者接口来下载

1.1、controllert 类 

package com.appms.controller;

import com.appms.util.Util;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@CrossOrigin("*")
@RequestMapping("file")
public class FileController {

    @GetMapping("/download")
    public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
        Util.downloadFile(request, response);
    }
}

1.2、实现类 :Util.class


    public static void downloadFile(HttpServletRequest request, HttpServletResponse response)
            throws IOException {

        // 本地文件地址,文件名称,我是在本机运行,如果是服务器的话,地址可能是 ../fileServer/file/deploy2.sh
        String filePath = "/Users/jjshen/bysj/deploy2.sh";
        String fileName = "deploy2.sh";
        
        
        // 获取浏览器的信息
        String agent = request.getHeader("USER-AGENT");
        if (agent != null && agent.toLowerCase().indexOf(FIRE_FOX) > 0) {
            //火狐浏览器自己会对URL进行一次URL转码所以区别处理
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("GB2312"), "ISO-8859-1"));
        } else if (agent.toLowerCase().indexOf(SAFARI) > 0) {
            //苹果浏览器需要用ISO 而且文件名得用UTF-8
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
        } else {
            //其他的浏览器
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + java.net.URLEncoder.encode(fileName, "UTF-8"));
        }

        File file = new File(filePath);
        FileInputStream fileInputStream = new FileInputStream(file);

        byte[] fileByte = new byte[(int) file.length()];
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] bytes = new byte[1024];
        int len;
        while ((len = fileInputStream.read(bytes, 0, bytes.length)) != -1) {
            byteArrayOutputStream.write(bytes, 0, len);
        }
        byteArrayOutputStream.close();
        fileByte = byteArrayOutputStream.toByteArray();

        OutputStream outputStream = null;
        outputStream = response.getOutputStream();
        outputStream.write(fileByte);
        outputStream.flush();
        outputStream.close();

    }

代码解释:文件下载是将文件流写入 HttpServletResponse中,在header中添加 浏览器的解析方式,和文件名:

Content-Disposition, attachment ; fileName = ? 这样如果在浏览器中直接访问接口,就可以直接下载了。如:浏览直接访问:http://127.0.0.1:9080/file/download,就可以在浏览器下载了。

1.3、前端页面调用

定义 responseType的类型为 “blob” ,然后通过 document 创建一个 a 标签,然后将文件名称、文件流设置进去即可。

    // 初始化一个HTTP请求
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:9080/file/download');
    xhr.responseType = 'blob';
    xhr.send();
    // 回调函数
    xhr.onload = function () {
        if (this.status === 200) { // HTTP 状态码
            const blob = this.response;
            const reader = new FileReader();
            reader.readAsDataURL(blob); // 读取指定的 Blob 或 File 对象
            // 处理读取事件
            reader.onload = function (e) {
                // 响应头存在中文需要编码
                const headerName = decodeURIComponent(escape(xhr.getResponseHeader('Content-disposition')));
                const headerNameArr = headerName.split('=');
                const fileName = headerNameArr[headerNameArr.length - 1];

                let aLink = document.createElement('a');
                aLink.download = fileName;
                aLink.href = e.target.result;
                aLink.click();
                $(aLink).remove();// 移除元素,但未清理DOM元素引用
                aLink = null; // 解除引用,内存释放
                alert('下载成功!');
            };

        } else {
            tools.errorAlerts('下载失败!');
        }
    };

1.4、其他服务接口调用:

调用接口,然后,根据 header中文件名称和 在返回reponse中的 文件流 , 转换成BufferedInputStream写入本地文件或用作其他。

    public static void main(String[] args) {
        String result = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpGet HttpGet = new HttpGet("http://127.0.0.1:9080/file/download");
//        HttpServletResponse response = null;
        HttpResponse response = null;
        try {
            response = httpClient.execute(HttpGet);
            // 获取header中文件名称
            String fileName = "";
            try {
                fileName = response.getAllHeaders()[3].getValue().split(";")[1].split("=")[1].substring(1);
                System.out.println(fileName);
            } catch (Exception e) {
            }
             // 后去接口返回的文件流
            HttpEntity entity = response.getEntity();
            BufferedInputStream br = new BufferedInputStream(entity.getContent());
            byte[] buf = new byte[1024];
            int len = 0;
            // 要写入本地的文件
            FileOutputStream fileOutputStream = new FileOutputStream("/Users/jjshen/bysj/" + fileName);
            while ((len = br.read(buf)) != -1) {
                fileOutputStream.write(buf, 0, len);
            }
            fileOutputStream.close();
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                httpClient.close();
//                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

二、提供“远程文件” ,给浏览器、前端Ajax或其他开发者接口来下载。

其实和 “第一点” 一样, 就是获取文件源的地方稍作修改。在“第一”点中是 直接 new File(filePath); 一个文件出来,转换成字节 流,放入 response中。

2.1、从 Ftp/SFtp上获取的

其实就是 使用 FTPClient 登陆到文件所在目录 ,然后将文件转换成一个 输出流OutputStream或Byte[]。

首先文件名要知道。ftp/sft的地址 登陆用户名/密码等。


    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileName)
            throws IOException {

        // 本地文件地址,文件名称,我是在本机运行,如果是服务器的话,地址可能是 ../fileServer/file/deploy2.sh
        //String filePath = "/Users/jjshen/bysj/deploy2.sh";
       // String fileName = "deploy2.sh";

        int reply; 
        FTPClient ftp = new FTPClient();          
        // 获取浏览器的信息
        String agent = request.getHeader("USER-AGENT");
        if (agent != null && agent.toLowerCase().indexOf(FIRE_FOX) > 0) {
            //火狐浏览器自己会对URL进行一次URL转码所以区别处理
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("GB2312"), "ISO-8859-1"));
        } else if (agent.toLowerCase().indexOf(SAFARI) > 0) {
            //苹果浏览器需要用ISO 而且文件名得用UTF-8
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
        } else {
            //其他的浏览器
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + java.net.URLEncoder.encode(fileName, "UTF-8"));
        }

     ftp.connect("http://xxx.xxx.xxx", 22);
     //下面三行代码必须要,而且不能改变编码格式
     ftp.setControlEncoding("GBK");
     ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
     FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);  
     conf.setServerLanguageCode("zh");
     //如果采用默认端口,可以使用ftp.connect(url) 的方式直接连接FTP服务器  
     ftp.login("root", "123456");//登录  
     reply = ftp.getReplyCode();  
     if (!FTPReply.isPositiveCompletion(reply)) {  
         ftp.disconnect();  
         return success;  
     }  
     String remotePath = "/home/username/files/";
 
     ftp.changeWorkingDirectory(remotePath+"/");//转移到FTP服务器目录  
     FTPFile[] fs = ftp.listFiles(); 

     OutputStream outputStream = response.getOutputStream();
     for(int i = 0; i < fs.length; i++){
         FTPFile ff = fs[i];
         if(ff.getName().equals(fileName)){ 
//                   System.out.println("fileName"+fileName);
             String filename1 = URLEncoder.encode(fileName,"utf-8");
             response.setHeader("Content-disposition","attachment;filename="+URLEncoder.encode(fileName,"utf-8"));
             //将文件保存到输出流outputStream中
             ftp.retrieveFile(new String(ff.getName().getBytes("GBK"),"ISO-8859-1"), outputStream);
             outputStream.flush();
             outputStream.close();
             break;
         }  
     }                     
     ftp.logout();  
     success = true;  
     ftp.disconnect();

    }

上面是使用 FtpClient.retrieveFile 直接将Ftp上文件写入response 的outputStream中。其实 FtpClient.retrieveFile 的效率没有 ftpClient.retrieveFileStream方法快。 如果考虑效率这里可以将retrieveFile 方法修改成 retrieveFileStream,然后再将返回结果写入 outputStream 中去。


    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileName)
            throws IOException {

        // 本地文件地址,文件名称,我是在本机运行,如果是服务器的话,地址可能是 ../fileServer/file/deploy2.sh
        //String filePath = "/Users/jjshen/bysj/deploy2.sh";
       // String fileName = "deploy2.sh";

        int reply; 
        FTPClient ftp = new FTPClient();          
        // 获取浏览器的信息
        String agent = request.getHeader("USER-AGENT");
        if (agent != null && agent.toLowerCase().indexOf(FIRE_FOX) > 0) {
            //火狐浏览器自己会对URL进行一次URL转码所以区别处理
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("GB2312"), "ISO-8859-1"));
        } else if (agent.toLowerCase().indexOf(SAFARI) > 0) {
            //苹果浏览器需要用ISO 而且文件名得用UTF-8
            response.setHeader("Content-Disposition",
                    "attachment; filename=" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));
        } else {
            //其他的浏览器
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + java.net.URLEncoder.encode(fileName, "UTF-8"));
        }

     ftp.connect("http://xxx.xxx.xxx", 22);
     //下面三行代码必须要,而且不能改变编码格式
     ftp.setControlEncoding("GBK");
     ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
     FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);  
     conf.setServerLanguageCode("zh");
     //如果采用默认端口,可以使用ftp.connect(url) 的方式直接连接FTP服务器  
     ftp.login("root", "123456");//登录  
     reply = ftp.getReplyCode();  
     if (!FTPReply.isPositiveCompletion(reply)) {  
         ftp.disconnect();  
         return success;  
     }  
     String remotePath = "/home/username/files/";
 
     OutputStream outputStream= response.getOutputStream(); 
     ftp.changeWorkingDirectory(remotePath+"/");//转移到FTP服务器目录  
     InputStream   inputStream = ftpClient.retrieveFileStream(new String(fileName.getBytes("GBK"), "ISO-8859-1"));

    byte[] buf = new byte[1024];
    int len;
    while ((len = inputStream.read(buf, 0, buf.length)) > 0) {
        outputStream.write(buf, 0, len);
    }
    inputStream.close();

    outputStream.flush();
    outputStream.close();
                      
     ftp.logout();  
     ftp.disconnect();

    }

2.2、从接口中获取

其实就相当于 在1.4调用接口成功后,将文件流,在提供给返回给浏览器、前端页面、接口等。

------------------------------------------------------分割线---------------------------------------------------------------------------

博客只作为博主记录、复习用,如果有什么不足之处或更好的建议,都可以一起畅快的交流。对你有用或拿来参考的话,请自行完善,有任何不足或引发的事故概不负责。

### 回答1: 好的,下面是一个示例代码,它将从数据库中检索数据,将数据写入Excel表格,并将表格提供给用户进行下载。 ```java import java.io.FileOutputStream; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelWriter { public static void main(String[] args) throws SQLException, IOException { String jdbcURL = "jdbc:mysql://localhost:3306/sampledb"; String username = "root"; String password = "password"; Connection connection = DriverManager.getConnection(jdbcURL, username, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM users"); Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Users"); int rowCount = 0; while (resultSet.next()) { Row row = sheet.createRow(rowCount++); int columnCount = 0; Cell cell = row.createCell(columnCount++); cell.setCellValue(resultSet.getInt("id")); cell = row.createCell(columnCount++); cell.setCellValue(resultSet.getString("name")); cell = row.createCell(columnCount++); cell.setCellValue(resultSet.getString("email")); cell = row.createCell(columnCount++); cell.setCellValue(resultSet.getString("country")); } connection.close(); FileOutputStream outputStream = new FileOutputStream("users.xlsx"); workbook.write(outputStream); workbook.close(); outputStream.close(); System.out.println("Excel written successfully.."); } } ``` 该代码使用 Apache POI 库来创建 Excel 工作簿,并将从数据库中检索到的数据写入工作表中。您可以使用该代码作为起点,并将其修改为您的应用程序。 对于在前端页面提供下载按钮,您可以使用以下 HTML 和 JavaScript 代码: ```html <button onclick="downloadExcel()">Download Excel</button> <script> function downloadExcel() { window.location.href = "/path/to/your/excel/file.xlsx"; } </script> ``` 您需要将 "/path/to/your/excel/file.xlsx" 替换为实际的文件路径。 ### 回答2: 要使用Java帮助写一个Excel表并将数据库数据写入该表,并在前端页面上添加一个按钮以便用户能够下载这个Excel表,可以按照以下步骤进行操作: 1. 使用Java中的相关库(如apache poi)创建一个新的Excel表格。 2. 连接数据库,提取需要导出为Excel的数据。可以使用Java中的JDBC连接数据库,编写SQL查询语句来获取需要的数据。 3. 使用Apache POI库的API,将数据库中的数据逐行逐列地写入Excel表。 4. 将Excel表保存到本地或服务器上的指定路径。 5. 创建一个前端页面,添加一个按钮元素,并为该按钮添加一个点击事件。 6. 在按钮的点击事件中,使用Java和合适的库(如Apache HttpClient)向后端发送请求,请求获取Excel文件下载地址。 7. 后端接收到下载请求后,将之前保存的Excel文件读取为输入流,设置相关的HTTP响应头,使得浏览器能够正确地识别并下载Excel文件。 8. 将Excel文件的输入流通过HTTP响应输出流返回给前端,用户即可在浏览器中下载该Excel表。 需要注意以下事项: - 在编写Java代码时,要确保数据库连接和Excel表格的创建、数据导出等操作都在适当的异常处理块中,以保证程序的稳定性和安全性。 - 在前端页面上,要注意为按钮设置合适的样式和事件处理机制,以提供给用户明确的下载Excel表格的入口。 希望以上信息能够帮助到您,如有任何疑问,请随时追问。 ### 回答3: 首先,您可以使用Java中的Apache POI库来创建和操作Excel表格。这个库提供了丰富的功能,可以方便地创建和编辑Excel文件。 以下是一个简单的示例代码,展示如何使用Java编写一个Excel表格并将数据库数据写入该表格: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.FileOutputStream; import java.sql.*; public class ExcelGenerator { public static void main(String[] args) { String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase"; String username = "root"; String password = "password"; try (Connection connection = DriverManager.getConnection(jdbcUrl, username, password); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery("SELECT * FROM mytable")) { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); int rowNum = 0; // 创建表头 Row headerRow = sheet.createRow(rowNum++); ResultSetMetaData metaData = resultSet.getMetaData(); int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { Cell cell = headerRow.createCell(i - 1); cell.setCellValue(metaData.getColumnLabel(i)); } // 填充数据 while (resultSet.next()) { Row row = sheet.createRow(rowNum++); for (int i = 1; i <= columnCount; i++) { Cell cell = row.createCell(i - 1); cell.setCellValue(resultSet.getString(i)); } } // 保存Excel文件 try (FileOutputStream outputStream = new FileOutputStream("data.xlsx")) { workbook.write(outputStream); } } catch (SQLException | java.io.IOException e) { e.printStackTrace(); } } } ``` 在这个示例中,首先我们连接到数据库,然后执行一条查询语句来获取需要导出的数据。然后,我们使用POI库创建一个Excel表格,并将查询结果逐行写入该表格。 最后,我们使用Java文件输出流将该Excel文件保存到本地磁盘,文件名为"data.xlsx"。您可以根据需要更改文件名和保存路径。 在前端页面上,您可以使用HTML和JavaScript创建一个简单的按钮,并使用`<a>`和`download`属性来实现点击按钮下载这个Excel文件。例如: ```html <!DOCTYPE html> <html> <head> <title>Excel下载</title> </head> <body> <button onclick="downloadExcel()">点击下载Excel</button> <script> function downloadExcel() { // 替换为您的Java后端接口地址 var url = "/download-excel"; var link = document.createElement("a"); link.href = url; link.download = "data.xlsx"; document.body.appendChild(link); link.click(); document.body.removeChild(link); } </script> </body> </html> ``` 在这个例子中,当用户点击按钮时,`downloadExcel()`函数会创建一个`<a>`元素,并将其链接和下载属性设置为后端Java接口的地址和文件名。然后,`click()`方法会触发链接的点击事件,从而开始下载Excel文件。 请注意,您需要将Java后端的接口路径和文件名与上述示例代码中的地址对应起来。此外,还需要将数据库连接信息和查询语句适配到您的实际情况。 希望这个回答能对您有所帮助!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值