如何在Hilla中创建动态生成文件的下载按钮?
在Hilla中实现动态文件下载按钮
Hilla前端基于React(默认)/Vue生态,没有Vaadin Web Components中的<Anchor>组件,但可以通过两种实用方式实现动态文件下载功能:
方法一:Spring Boot控制器+前端按钮触发
这是你已验证过有响应的方案,直接通过后端接口返回文件流,前端处理下载逻辑:
后端(Spring Boot)
创建控制器方法,返回带文件流的响应:
@RestController @RequestMapping("/api/download") public class DownloadController { @GetMapping("/dynamic-file") public ResponseEntity<Resource> downloadDynamicFile() { // 动态生成文件内容(示例为CSV格式) String content = "姓名,年龄\n张三,25\n李四,30"; ByteArrayResource resource = new ByteArrayResource(content.getBytes(StandardCharsets.UTF_8)); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"dynamic-data.csv\"") .contentType(MediaType.parseMediaType("text/csv")) .body(resource); } }
前端(Hilla React视图)
用普通按钮触发请求,将响应转为Blob后触发浏览器下载:
import { Button } from '@hilla/react-components/Button'; export default function DownloadView() { const handleDownload = async () => { const response = await fetch('/api/download/dynamic-file'); if (!response.ok) throw new Error('下载失败'); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; // 从响应头解析文件名,或直接指定 const disposition = response.headers.get('Content-Disposition'); const filename = disposition?.match(/filename="?([^"]+)"?/)?.[1] || 'dynamic-file.csv'; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }; return ( <div> <Button onClick={handleDownload}>下载动态生成文件</Button> </div> ); }
方法二:Hilla类型安全服务端调用
如果想通过Hilla的类型安全服务调用(而非直接REST接口)实现,可在服务类返回StreamResource,前端处理Blob:
后端(Hilla服务类)
@AnonymousAllowed @Service public class DownloadService { public StreamResource generateDynamicFile() { String content = "动态生成的文件内容示例"; return new StreamResource("dynamic-file.txt", () -> new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))); } }
前端(Hilla React视图)
调用服务端方法,获取资源信息后完成下载:
import { Button } from '@hilla/react-components/Button'; import { downloadService } from 'Frontend/generated/endpoints'; export default function DownloadView() { const handleDownload = async () => { const resource = await downloadService.generateDynamicFile(); const response = await fetch(resource.url); const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = resource.name; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }; return ( <div> <Button onClick={handleDownload}>下载动态文件(服务端调用)</Button> </div> ); }
注:第二种方法中,StreamResource会生成临时URL,Hilla自动处理权限控制,适合需要鉴权的场景。
内容的提问来源于stack exchange,提问作者David Marko
相关产品推荐
相关产品推荐

