文件存储微服务搭建
文件存储微服务
创建文件管理微服务changgou-service-file,该工程主要用于实现文件上传以及文件删除等功能。
pom.xml依赖
修改pom.xml,引入依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>changgou-service</artifactId> <groupId>com.changgou</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>changgou-service-file</artifactId> <description> 文件微服务(用户文件操作:图片上传) </description> <dependencies> <!-- fastDFS客户端程序包 --> <dependency> <groupId>net.oschina.zcx7878</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27.0.0</version> </dependency> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
FastDFS配置
在resources文件夹下创建fasfDFS的配置文件fdfs_client.conf
#连接超时的世界 s connect_timeout=60 #网络超时时间 network_timeout=60 #字符编码 charset=UTF-8 # tracker的http通信协议的端口 http.tracker_http_port=8080 # 22122 trackerserver的tcp 端口 tracker_server=192.168.211.132:22122
connect_timeout:连接超时时间,单位为秒。
network_timeout:通信超时时间,单位为秒。发送或接收数据时。假设在超时时间后还不能发送或接收数据,则本次网络通信失败
charset: 字符集
http.tracker_http_port :.tracker的http端口
tracker_server: tracker服务器IP和端口设置
application.yml配置
在resources文件夹下创建application.yml
spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB application: name: file server: port: 18082 eureka: client: service-url: defaultZone: http://127.0.0.1:7001/eureka instance: prefer-ip-address: true feign: hystrix: enabled: true
max-file-size是单个文件大小,max-request-size是设置总上传的数据大小
package com.changgou; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; //排除掉数据库类的自动配置 @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) @EnableEurekaClient public class FileApplication { public static void main(String[] args) { SpringApplication.run(FileApplication.class, args); } }
这里禁止了DataSource的加载创建。
文件上传
文件信息封装
文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性,代码如下:
创建com.changgou.file.FastDFSFile
代码如下:
package com.changgou.file; import java.io.Serializable; public class FastDFSFile implements Serializable { //文件名字 private String name; //文件内容 private byte[] content; //文件扩展名 private String ext; //文件MD5摘要值 private String md5; //文件创建作者 private String author; public FastDFSFile(String name, byte[] content, String ext, String md5, String author) { this.name = name; this.content = content; this.ext = ext; this.md5 = md5; this.author = author; } public FastDFSFile(String name, byte[] content, String ext) { this.name = name; this.content = content; this.ext = ext; } public FastDFSFile() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public byte[] getContent() { return content; } public void setContent(byte[] content) { this.content = content; } public String getExt() { return ext; } public void setExt(String ext) { this.ext = ext; } public String getMd5() { return md5; } public void setMd5(String md5) { this.md5 = md5; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
创建com/changgou/util/FastDFSClient类,该类中实现FastDFS信息获取以及文件的相关操作
package com.changgou.util; import com.changgou.file.FastDFSFile; import org.csource.common.MyException; import org.csource.common.NameValuePair; import org.csource.fastdfs.*; import org.springframework.core.io.ClassPathResource; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; public class FastDFSClient { static { //从classpath下获取文件对象获取路径 String path = new ClassPathResource("fdfs_client.conf").getPath(); try { ClientGlobal.init(path); } catch (Exception e) { e.printStackTrace(); } } //图片上传 public static String[] upload(FastDFSFile file) { try { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); StorageClient storageClient = new StorageClient(trackerServer, null); //参数1 字节数组 //参数2 扩展名(不带点) //参数3 元数据( 文件的大小,文件的作者,文件的创建时间戳) NameValuePair[] meta_list = new NameValuePair[]{new NameValuePair(file.getAuthor()), new NameValuePair(file.getName())}; String[] strings = storageClient.upload_file(file.getContent(), file.getExt(), meta_list); return strings;// strings[0]==group1 strings[1]=M00/00/00/wKjThF1aW9CAOUJGAAClQrJOYvs424.jpg } catch (Exception e) { e.printStackTrace(); } return null; } //图片下载 public static InputStream downFile(String groupName, String remoteFileName) { ByteArrayInputStream byteArrayInputStream = null; try { //3.创建trackerclient对象 TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); //5.创建stroageserver 对象 //6.创建storageclient 对象 StorageClient storageClient = new StorageClient(trackerServer, null); //7.根据组名 和 文件名 下载图片 //参数1:指定组名 //参数2 :指定远程的文件名 byte[] bytes = storageClient.download_file(groupName, remoteFileName); byteArrayInputStream = new ByteArrayInputStream(bytes); return byteArrayInputStream; } catch (Exception e) { e.printStackTrace(); } finally { try { if (byteArrayInputStream != null) { byteArrayInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return null; } //图片删除 public static void deleteFile(String groupName, String remoteFileName) { try { //3.创建trackerclient对象 TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); //5.创建stroageserver 对象 //6.创建storageclient 对象 StorageClient storageClient = new StorageClient(trackerServer, null); int i = storageClient.delete_file(groupName, remoteFileName); if (i == 0) { System.out.println("删除成功"); } else { System.out.println("删除失败"); } } catch (Exception e) { e.printStackTrace(); } } //根据组名获取组的信息 public static StorageServer getStorages(String groupName) { try { TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); //参数1 指定traqckerserver 对象 //参数2 指定组名 StorageServer group1 = trackerClient.getStoreStorage(trackerServer, groupName); return group1; } catch (IOException e) { e.printStackTrace(); } return null; } //根据文件名和组名获取文件的信息 public static FileInfo getFile(String groupName, String remoteFileName) { try { TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); StorageClient storageClient = new StorageClient(trackerServer, null); //参数1 指定组名 //参数2 指定文件的路径 FileInfo fileInfo = storageClient.get_file_info(groupName, remoteFileName); return fileInfo; } catch (Exception e) { e.printStackTrace(); } return null; } //根据文件名和组名 获取组信息的数组信息 public static ServerInfo[] getServerInfo(String groupName, String remoteFileName){ try { //3.创建trackerclient对象 TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); ServerInfo[] group1s = trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName); return group1s; } catch (IOException e) { e.printStackTrace(); } return null; } //获取tracker 的ip和端口的信息 //http://192.168.211.132:8080 public static String getTrackerUrl(){ try { //3.创建trackerclient对象 TrackerClient trackerClient = new TrackerClient(); //4.创建trackerserver 对象 TrackerServer trackerServer = trackerClient.getConnection(); //tracker 的ip的信息 String hostString = trackerServer.getInetSocketAddress().getHostString(); //http://192.168.211.132:8080/group1/M00/00/00/wKjThF1aW9CAOUJGAAClQrJOYvs424.jpg img int g_tracker_http_port = ClientGlobal.getG_tracker_http_port(); return "http://" + hostString + ":" + g_tracker_http_port; } catch (IOException e) { e.printStackTrace(); } return null; } }
创建文件上传的controller将文件上传后的访问地址返回给前端:
package com.changgou.file.controller; import com.changgou.file.FastDFSFile; import com.changgou.util.FastDFSClient; import entity.Result; import entity.StatusCode; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @RestController @CrossOrigin//支持跨域 //跨域: //不同的域名A 访问 域名B 的数据就是跨域 // 端口不同 也是跨域 loalhost:18081----->localhost:18082 // 协议不同 也是跨域 http://www.jd.com ---> https://www.jd.com // 域名不同 也是跨域 http://www.jd.com ---> http://www.taobao.com //协议一直,端口一致,域名一致就不是跨域 http://www.jd.com:80 --->http://www.jd.com:80 不是跨域 public class FileController { /** * 返回 图片的全路径 * * @param file 页面的文件对象 * @return */ @PostMapping("/upload") public Result<String> upload(@RequestParam(value = "file") MultipartFile file) { try { //1. 创建图片文件对象(封装) //2. 调用工具类实现图片上传 //String substring = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1); FastDFSFile fastdfsfile = new FastDFSFile( file.getOriginalFilename(),//原来的文件名 1234.jpg file.getBytes(),//文件本身的字节数组 StringUtils.getFilenameExtension(file.getOriginalFilename()) ); String[] upload = FastDFSClient.upload(fastdfsfile); // upload[0] group1 // upload[1] M00/00/00/wKjThF1aW9CAOUJGAAClQrJOYvs424.jpg //3. 拼接图片的全路径返回 // http://192.168.211.132:8080/group1/M00/00/00/wKjThF1aW9CAOUJGAAClQrJOYvs424.jpg // http://192.168.211.132:8080 + String filePath = FastDFSClient.getTrackerUrl()+"/"+upload[0]+"/"+upload[1]; return new Result<String>(true, StatusCode.OK,"上传成功!",filePath); } catch (IOException e) { e.printStackTrace(); } return null; } }
文件存储实际路径查看:
进入storage容器中
docker exec -it storage /bin/bash
查看storage的配置文件
vim storage.conf
所以可以根据此路径去/data/fast_data中查看自己上传的文件。
Postman测试文件上传
步骤:
1、选择post请求方式,输入请求地址 http://localhost:18082/upload
2、填写Headers
Key:Content-Type
Value:multipart/form-data
3、填写body
选择form-data 然后选择文件file 点击添加文件,最后发送即可。