SpringBoot 接口怎么传数据库中的 BLOB 图片给前端

2020-09-25 09:18:08 +08:00
 sandman511

单张或者多张的 求大佬讲个方案 现在是能传 但想要个最佳方案。。虽然数据库存图片就离谱。。。。

3707 次点击
所在节点    程序员
26 条回复
hejingyuan199
2020-09-25 15:27:58 +08:00
虽然我不知道如何回答。
但我想附和一下,我也是把图片存数据库的。

我现在的项目是个测试性项目,不是正规使用。
我们的数据库供所有开发人员同时使用的。

不同的开发人员有不同的功能,功能互不干涉,但是共用一个数据库和表。
如果图片存在服务器本地,数据库只存图片名称,那大家各自在测试时都拿不到图片。
所以我把图片转成 Base64 字符串存进数据库了。
还有的表里存着 Blob 类型的用户上传的附件(文件或图片)。

一直看到大家说大文件不应该存数据库,
也许未来转为生产环境时候再改吧。

如果数据库存着 Base64 字符串,往前端发送应该比较简单了吧。
Blob 我看到我们的这边用的是,
(代码风格很渣,随便接受 Critics )

/***** Student Chose One Application*****/
@RequestMapping(value="/history/{ticketNum}", method=RequestMethod.GET)
public String historyApplication(@PathVariable String ticketNum, Model model, HttpServletRequest request) {
String search = (String) request.getSession().getAttribute("searchTicketNum");
Optional<Application> app = applicationService.findApplication(ticketNum);
if (app.isPresent()) {
model.addAttribute("applicationObj", app.get());
Optional<User> user = AIBTuserdetailsService.findByUserName(app.get().getCreatedBy());
model.addAttribute("userObj",user.get());
model.addAttribute("urlTicketNum", ticketNum);

model.addAttribute("documents", applicationService.getDocumentUrl(ticketNum, app.get().getId()));
--------------------------------------------------------------------------------------------------
//调用 blob 类型的文件

model.addAttribute("logs", applicationService.getAuditLog(app.get().getId()));
//Optional<Course> course = courseService.findByCourseid(user.get().getCurrentCourseCode());
//if(course.isPresent()) {
// model.addAttribute("course", course.get().getCourseName());}
//else {
// model.addAttribute("course", "Not found");
//}
}
model.addAttribute("applicationList", applicationService.findApplications(search));
return "student/history";
}

In ApplicationService.java

public Map<String, String> getDocumentUrl(String ticketNum, int applicationId) {
Map<String, String> result = new HashMap<>();
for (String fileName : documentRepository.findAllFileNameByApplicationId(applicationId)) {
---------------------------------------------------------------------------------
//get document out from Database

if (!fileName.isEmpty()) {
try {
result.put(fileName, ticketNum + "/" + URLEncoder.encode(fileName, String.valueOf(StandardCharsets.UTF_8)));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
if (result.isEmpty()) {
return null;
} else {
return result;
}
}

In DocumentRepository.java

public interface DocumentRepository extends JpaRepository<Document, Integer> {
Optional<Document> findByFileNameAndApplicationId(String fileName, int applicationId);
@Query(value="select file_name from document where application_id =:application_id", nativeQuery=true)
List<String> findAllFileNameByApplicationId(@Param("application_id") int applicationId);
}


//This is parts of Class Document

@Entity
@Table(name = "Document")
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private int applicationId;
private String fileName;
private String fileType;
@Lob
private byte[] data;
...
}

仅供参考
这个流程似乎就是前面一些 V 友说的以文件下载方式传到前端的。

前端是这样的:
<div class="three">
<p>
<b>Attachment:</b>
</p>
<div class="links">
<a target="_blank" th:each="element : ${documents}"
th:href="@{/student/downloadFile/{url}(url=${element.value})}"><img th:src="@{/image/qubiezhen.png}">[[${element.key}]]</a>
</div>
</div>
hejingyuan199
2020-09-25 15:33:30 +08:00
@hejingyuan199

补上最关键的数据传输

@RequestMapping(value="/downloadFile/{ticketNum}/{fileName}", method=RequestMethod.GET)
public ResponseEntity<Resource> downloadFile(@PathVariable String ticketNum, @PathVariable String fileName) {
// Load file from database
Optional<Document> doc = applicationService.getDocument(ticketNum, fileName, Boolean.FALSE);

if (doc.isPresent()) {
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType(doc.get().getFileType()))
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + doc.get().getFileName() + "\"")
.body(new ByteArrayResource(doc.get().getData()));
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
bxd5812127
2020-09-25 16:15:34 +08:00
后端给前端提供两个接口,一个拿所有图片的 id,一个根据 id 拿一个图片,前端根据 id 排队拿图片有没有搞头,拿完一个在拿一个。
THESDZ
2020-09-25 16:34:35 +08:00
后端应该提供的能力是 <img src="url"/> 的这个 url,内部实现可以直接通过 resp 传输流
hyperbin
2020-09-26 11:56:53 +08:00
@charten 怎么保证图片里没有 0x3b ?
charten
2020-09-26 21:00:11 +08:00
@hyperbin 不用保证呀,又不是拿 0x3b 去当分割符,0x3b 只是一个标识符,标识符一个块的开始,这个标识符可以 0x00 到 0xff 的任意一个字符,关键是紧跟着的后四位字节,代表了这个块的长度,你真正要拿图片要通过这个长度去拿,就是 slice 方法。当然也可以根据这个长度跳过去拿下一张图片。psd 文件的二进制格式基本上都是这样的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/710288

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX