springboot 文件上传及浏览设置

本文介绍了如何在SpringMVC应用中配置静态资源路径,并通过@PostMapping处理文件上传,涉及MultipartFile接口的使用。

配置:

spring.mvc.static-path-pattern: /static/**
spring.resources.static-locations=file:D:/dev/java/ltdemo/upload/

上传:

@PostMapping(value = "/a")
public String a(@RequestParam(required=false) MultipartFile material) throws Exception{}
<think>在Spring Boot项目中下载文件设置文件名,主要涉及以下关键点: 1. 使用HttpServletResponse设置响应头 2. 处理文件名编码以支持中文和特殊字符 3. 文件资源的读取与传输 以下是具体实现示例: ```java import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.MalformedURLException; import java.nio.file.Path; import java.nio.file.Paths; @RestController public class FileDownloadController { // 方法1:使用ResponseEntity(推荐,更简洁) @GetMapping("/download1/{fileName:.+}") public ResponseEntity<Resource> downloadFile1(@PathVariable String fileName, HttpServletRequest request) throws MalformedURLException { // 假设文件存储在项目的downloads目录下 Path filePath = Paths.get("downloads").resolve(fileName).normalize(); Resource resource = new UrlResource(filePath.toUri()); // 检查文件是否存在且可读 if (!resource.exists() || !resource.isReadable()) { throw new RuntimeException("文件不存在或无法读取"); } // 设置Content-Disposition头,指定下载的文件名(处理中文编码) String encodedFileName = encodeFileName(request, fileName); return ResponseEntity.ok() .contentType(MediaType.APPLICATION_OCTET_STREAM) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\"") .body(resource); } // 方法2:使用HttpServletResponse(传统方式) @GetMapping("/download2/{fileName:.+}") public void downloadFile2(@PathVariable String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException { Path filePath = Paths.get("downloads").resolve(fileName).normalize(); Resource resource = new UrlResource(filePath.toUri()); if (!resource.exists() || !resource.isReadable()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } // 设置响应内容类型 response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 设置Content-Disposition头,处理中文文件名 String encodedFileName = encodeFileName(request, fileName); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\""); // 将文件流写入响应 try (InputStream inputStream = resource.getInputStream(); OutputStream outputStream = response.getOutputStream()) { IOUtils.copy(inputStream, outputStream); outputStream.flush(); } } // 编码文件名,解决中文乱码问题 private String encodeFileName(HttpServletRequest request, String fileName) { String userAgent = request.getHeader("User-Agent"); try { if (userAgent != null && userAgent.contains("MSIE")) { // IE浏览器 return URLEncoder.encode(fileName, "UTF-8"); } else { // 其他浏览器(Firefox, Chrome, Safari等) return new String(fileName.getBytes("UTF-8"), "ISO-8859-1"); } } catch (UnsupportedEncodingException e) { return fileName; // 回退到原始文件名 } } } ``` ### 关键说明: 1. **文件名编码处理**: - 使用`encodeFileName`方法根据不同的浏览器(User-Agent)对文件名进行编码,避免中文乱码。 - IE浏览器使用`URLEncoder.encode`,其他浏览器使用ISO-8859-1编码。 2. **两种实现方式**: - **ResponseEntity方式**:更现代,利用Spring的响应构建器,代码简洁,推荐使用。 - **HttpServletResponse方式**:传统方式,直接操作响应流,更底层。 3. **安全注意**: - 使用`Paths.get().normalize()`防止路径遍历攻击(如文件名包含`../`)。 4. **依赖**: - 如果使用`IOUtils.copy`,需要Apache Commons IO依赖,也可以使用Java原生方式复制流。 ### 依赖添加(pom.xml): ```xml <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.11.0</version> </dependency> ``` ### 测试: - 访问 `http://localhost:8080/download1/测试文件.txt` 或 `http://localhost:8080/download2/测试文件.txt` 即可下载。 §§相关问题§§ 1. 如何在Spring Boot中处理文件上传? 2. 使用ResponseEntity和HttpServletResponse进行文件下载有何优缺点? 3. 如何防止文件下载接口被恶意利用(如下载系统文件)? 4. 除了浏览器兼容性,还有哪些情况会导致下载的文件名乱码? 5. 如何实现文件下载的进度显示?</think>在 Spring Boot 项目中实现文件下载并设置文件名,以下是完整解决方案: ### 核心实现代码 ```java import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.net.MalformedURLException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; @RestController public class FileDownloadController { // 文件存储目录(示例路径) private static final String FILE_DIRECTORY = "/var/www/files/"; /** * 文件下载接口 * @param filename 原始文件名 * @return ResponseEntity 包含文件内容和响应头 */ @GetMapping("/download/{filename:.+}") public ResponseEntity<Resource> downloadFile( @PathVariable String filename) throws MalformedURLException { // 1. 构建文件路径(安全处理) Path filePath = Paths.get(FILE_DIRECTORY).resolve(filename).normalize(); Resource resource = new UrlResource(filePath.toUri()); // 2. 验证文件存在且可读 if (!resource.exists() || !resource.isReadable()) { throw new RuntimeException("文件不存在或无法读取: " + filename); } // 3. 设置下载文件名(处理中文和特殊字符) String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8) .replace("+", "%20"); // 处理空格兼容性 // 4. 构建响应头 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFilename + "\""); headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); headers.add(HttpHeaders.PRAGMA, "no-cache"); headers.add(HttpHeaders.EXPIRES, "0"); // 5. 返回响应实体 return ResponseEntity.ok() .headers(headers) .contentLength(resource.contentLength()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(resource); } } ``` ### 关键要点说明 1. **文件名编码处理**: ```java String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8) .replace("+", "%20"); ``` - 使用 `URLEncoder` 处理中文和特殊字符 - 替换 `+` 为 `%20` 确保空格兼容所有浏览器 2. **安全防护措施**: - 使用 `normalize()` 防止路径遍历攻击 - 验证文件存在性:`resource.exists() && resource.isReadable()` - 设置安全响应头(禁用缓存) 3. **响应头关键参数**: ```http Content-Disposition: attachment; filename="encoded_filename.ext" Content-Type: application/octet-stream Content-Length: [文件大小] ``` ### 前端调用示例(JavaScript) ```javascript // 直接打开下载链接 window.location.href = `/download/${encodeURIComponent(fileName)}`; // 或通过隐藏 iframe 下载 const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = `/download/${encodeURIComponent(fileName)}`; document.body.appendChild(iframe); ``` ### 常见问题解决方案 1. **中文文件名乱码**: - 确保使用 `URLEncoder.encode(filename, "UTF-8")` - 添加 `filename*=UTF-8''` 备用方案: ```java headers.add("Content-Disposition", "attachment; filename=\"" + encodedName + "\"; " + "filename*=UTF-8''" + encodedName); ``` 2. **大文件下载优化**: ```java // 使用 StreamingResponseBody 分块传输 return ResponseEntity.ok() .headers(headers) .body(outputStream -> { try (InputStream is = resource.getInputStream()) { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } }); ``` 3. **浏览器兼容性**: | 浏览器 | 编码方案 | 特殊处理 | |-------------|----------------------------|-----------------------| | Chrome/Firefox | UTF-8 URL编码 | 无需额外处理 | | IE11 | ISO-8859-1 | 需转换编码 | | Safari | RFC 5987标准 (filename*) | 添加filename*参数 |
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值