Kubo 是 IPFS的官方核心实现,由 Go 语言编写,是目前最成熟、应用最广泛的 IPFS 节点软件。 我们可以在此下载kubo并安装,具体教程可参见我的另一篇博客:
一、ipfs启动
以上是安装完成后的界面,我们直接在此处打开cmd,分别运行以下命令对kubo进行启动部署。
# 初始化ipfs
ipfs init
# 启动ipfs服务
ipfs daemon
首次运行需要进行初始化,如果已经配置过会进行提示。
如上图所示,ipfs启动成功后,我们可以访问http://127.0.0.1:5001/webui ,进入ipfs的页面。
二、实现ipfs上传
在实现上传下载功能前,我们要把ipfs的依赖引入到项目工程中
<dependency>
<groupId>com.github.ipfs</groupId>
<artifactId>java-ipfs-http-client</artifactId>
<version>1.3.3</version>
</dependency>
并且注意在项目配置文件中,对ipfs进行配置
ipfs:
config:
multi-addr: /ip4/127.0.0.1/tcp/5001 # ipfs的服务器地址和端口
接下来,我们编写控制类,写出上传接口
@Autowired
IpfsService ipfsService;
/**
* 文件上传到ipfs
*
* @param file 待上传文件
* @return Result
*/
@PostMapping("/upload")
public Result uploadIpfs(MultipartFile file) {
String fileCID = ipfsService.uploadIpfs(file);
Map<String, Object> map = new HashMap<>();
map.put("msg","上传成功");
map.put("data",fileCID);
return Result.ok().data("info",map);
}
对uploadIipfs方法实现
@Value("${server.port:8080}")
private String port;
@Value("${ip:localhost}")
private String ip;
@Value("${ipfs.config.multi-addr}")
private String ipfsAddress;
private static final String filePath = System.getProperty("user.dir") + "/files/";
public String uploadIpfs(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new RuntimeException("上传文件为空");
}
String flag;
synchronized (IpfsController.class) {
flag = System.currentTimeMillis() + "";
ThreadUtil.sleep(1L);
}
String fileName = file.getOriginalFilename();
String fileCID;
try {
if (!FileUtil.isDirectory(filePath)) {
FileUtil.mkdir(filePath);
}
IPFS ipfs = new IPFS(ipfsAddress);
File uploadFile = FileUtils.MultipartFileToFile(file);
NamedStreamable.FileWrapper saveFile = new NamedStreamable.FileWrapper(uploadFile);
MerkleNode result = ipfs.add(saveFile).get(0);
fileCID = result.hash.toBase58();
System.out.println(fileCID);
// 文件存储形式:时间戳-文件名
FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName);
System.out.println(fileName + "--上传成功");
FileUtils.deleteTempFile(uploadFile);
System.out.println("文件上传地址" + filePath);
return fileCID;
} catch (Exception e) {
System.err.println(fileName + "--文件上传失败");
throw new RuntimeException("上传文件失败");
}
}
现在进行测试
提示 上传成功,并且返回了该文件的CID,我们可以复制此CID在ipfs的主页导入,检测图片是否一致。
三、实现ipfs下载
类似上传,不过是另一种处理方式,我们接收文件的CID,这里称为hash
/**
* ipfs下载指定文件
*
* @param hash 待上传文件
*/
@PostMapping("/download/{hash}")
public void downloadIpfs(@PathVariable String hash, HttpServletResponse response) {
try {
ipfsService.downFromIpfs(response, hash);
} catch (Exception e) {
try {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
对downFromIpfs实现
public void downFromIpfs(HttpServletResponse response, String hash) {
IPFS ipfs = new IPFS(ipfsAddress);
try {
byte[] data = ipfs.cat(Multihash.fromBase58(hash));
if (data == null || data.length == 0) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
return;
}
// 设置响应头
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(hash + ".jpg", "UTF-8") + "\"");
response.setContentLength(data.length);
// 直接写入响应流
response.getOutputStream().write(data);
response.flushBuffer();
} catch (IOException e) {
try {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "文件下载失败");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
进行测试,为了直观展示,我写了一个简单的html页面,测试下载功能在浏览器中的实际效果,如下
我们在此输入之前的CID,可以发现接口识别后进行了下载,浏览器弹出下载窗口
至此,java实现ipfs的上传下载功能结束,不过在下载部分,我这里仅对文件进行了统一的.jpg命名,如何实现自动识别文件类型从而添加对应的文件后缀,还请各位大佬进行指点!(抱拳)