动手做一个文件服务器【简易版本 亦可作为私人网盘】
当我们在做项目时难免都要上传附件,这时我们会用到市面上开源的文件服务器,例如FastDFS
,ServU
,HDFS
等文件服务器,我想我可不可以做一个简易版本的小型文件服务器系统呢?
一,文件服务器的主要工作内容是什么?
- 向外界提供上传附件的接口
- 向外界提供附件在线预览地址的接口
- 服务器本身在硬盘上对所有的附件作统一管理
二,文件服务器的原理是什么?
文件服务器作为服务端,自然要接收客户端发送来的文件并将文件写入本地磁盘,然后做一些处理可以预览附件,那么这一句话就够用了,下面开始动手写一个简易的文件服务器。
三,动手写文件服务器
写这个服务器没有用到数据库,全都是文件流的操作,仅此而已!
1,服务端接收上传文件的接口
写对外开放的为客户端上传附件的接口,参数为MultipartFile
对象,客户端只需要直接将文件MultipartFile
参数传过来即可。
其中文件上传到了Tomcat/webapps/
中的一个文件夹,同时Tomcat
要开启状态,因为拼接上域名和文件路径以及文件名就可以直接下载了。
@Controller
@RequestMapping("/rest")
public class CreateFileController {
//硬盘文件地址(存储文件地址)
// private static final String dirPath="D:\\suibian\\test\\";
private static final String dirPath="/usr/local/share/apache-tomcat-8.5.40/webapps/files/";
//Tomcat域名,拼接上文件名可直接下载
private static final String tomcatUrl="https://www.tiger2.cn/files/";
//客户端向本服务端上传文件的开放接口
@PostMapping("createFile")
@ResponseBody
public Map<String, Object> createFile(MultipartFile uploadFile, String uploader) {
String message = "";
boolean success = true;
//构建新的文件名并进行存储,存储到云服务的文件夹中
String originalFilename = uploadFile.getOriginalFilename();
String suffix=originalFilename.substring(originalFilename.lastIndexOf("."));
long time=new Date().getTime();
String newFileName=originalFilename.substring(0,originalFilename.lastIndexOf("."))+String.valueOf(time)+suffix;
try {
//FileUtils.copyInputStreamToFile是commons-io包下的方法,可以直接将输入流转为一个新的文件(前提是指定好路径和要生成的文件名)
FileUtils.copyInputStreamToFile(uploadFile.getInputStream(),
new File(dirPath + newFileName));
} catch (Exception e) {
message = e.getMessage();
success = false;
}
Map<String, Object> result = new HashMap<>();
result.put("message", message);
result.put("success", success);
result.put("newFileName",newFileName); //返回一个新的文件名
result.put("downLoadUrl",tomcatUrl+newFileName);//返回文件下载地址
return result;
}
@Autowired
LoginController loginController;
//根据文件名创建在线预览地址
@GetMapping(value = "createPreviewUrl", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String createPreviewUrl(String fileName){
String previewUrl = loginController.createPreviewUrl(fileName);
return previewUrl;
}
}
2,服务端生成附件在线预览地址
上面生成附件在线预览地址的方法不用细看了,这里使用了永中云转换服务,只需要把下载地址作为参数给它们,它们会直接给你生成预览地址,不过免费的局限性很大。
3,服务端文件下载(将输入流 输出到浏览器进行下载)
获取到要下载的文件File
对象,得到输入流之后,将输入流写入到响应请求response
的输出流中,在浏览器端进行下载。
//根据文件名称下载文件输出到浏览器
@RequestMapping("/download")
@ResponseBody
public void download(String fileName, HttpServletResponse response) throws Exception{
//windows分隔符是\\ Linux分隔符是/
String fileName1=dirPath+"/"+fileName;
//获取要下载的文件输入流
FileInputStream is=new FileInputStream(new File(fileName1));
//设置content-disposition响应头控制浏览器以下载的形式打开文件
response.setHeader("content-disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
OutputStream out = response.getOutputStream();
byte[] bytes=new byte[1024];
int len;
while ((len=is.read(bytes))>0){
out.write(bytes,0,len);
}
//关闭输入流
is.close();
}
4,服务端上传附件到云服务器本身的硬盘中
FileUtils.copyInputStreamToFile
是commons-io
包下的方法,可以直接将输入流转为一个新的文件(前提是指定好路径和要生成的文件名)
//服务器本身上传图片到服务器本地硬盘
@RequestMapping("/upload")
public String upload(MultipartFile file,Model model) throws Exception{
boolean checkFileSize = checkFileSize(file, 5, "M");
if(true){
String originalFilename = file.getOriginalFilename();
long time=new Date().getTime();
String suffix=originalFilename.substring(originalFilename.lastIndexOf("."));
String name=originalFilename.substring(0,originalFilename.lastIndexOf("."));
FileUtils.copyInputStreamToFile(file.getInputStream(),new File(dirPath+"/"+name+String.valueOf(time)+suffix));
model.addAttribute("msg","The File Was Uploaded Successlly!");
return "forward:index";
}else{
model.addAttribute("msg","Sorry, The File Was Uploaded Error!The File Size Should Not Exceed 5MB!");
return "forward:index";
}
}
5,服务端判断文件大小
参数分别是文件,数字,单位(B,K,M,G)
public static boolean checkFileSize( MultipartFile multipartFile, int size, String unit) {
long len = multipartFile.getSize();//上传文件的大小, 单位为字节.
//准备接收换算后文件大小的容器
double fileSize = 0;
if ("B".equals(unit.toUpperCase())) {
fileSize = (double) len;
} else if ("K".equals(unit.toUpperCase())) {
fileSize = (double) len / 1024;
} else if ("M".equals(unit.toUpperCase())) {
fileSize = (double) len / 1048576;
} else if ("G".equals(unit.toUpperCase())) {
fileSize = (double) len / 1073741824;
}
//如果上传文件大于限定的容量
if (fileSize > size) {
return false;
}
return true;
}
6,服务端将文件列表按时间排序
//按时间排序
public static File[] orderByDate(String fliePath) {
File file = new File(fliePath);
File[] fs = file.listFiles();
Arrays.sort(fs, new Comparator<File>() {
public int compare(File f1, File f2) {
long diff = f1.lastModified() - f2.lastModified();
if (diff > 0)
return 1;
else if (diff == 0)
return 0;
else
return -1;
}
public boolean equals(Object obj) {
return true;
}
});
return fs;
}
public void index(){
File[] files = orderByDate(dirPath);
for (int i = files.length - 1; i > -1; i--) {
//对文件排序后的列表进行处理
}
}
7,客户端上传附件表单
准备一个表单,提交附件
<form action="/upload/tiger2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="uploadFile" />
<input type="submit" value="上传" />
</form>
8,客户端远程调用服务端上传附件
使用RestTemplate
把文件从客户端发送至服务端的接收文件的接口。
@RequestMapping("/tiger2")
@ResponseBody
public Map uploadFile(MultipartFile uploadFile){
FileServerManager fileServerManager=new FileServerManager();
Map result = fileServerManager.uploadFileToTiger2Server(uploadFile);
return result;
}
public Map uploadFileToTiger2Server(MultipartFile uploadFile) {
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap();
HttpHeaders header = new HttpHeaders();
header.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpHeaders fileHeader = new HttpHeaders();
fileHeader.setContentType(MediaType.parseMediaType(uploadFile.getContentType()));
fileHeader.setContentDispositionFormData("uploadFile", uploadFile.getOriginalFilename());
Map result = null;
try {
HttpEntity<ByteArrayResource> fileEntity = new HttpEntity(new ByteArrayResource(uploadFile.getBytes()), fileHeader);
multiValueMap.add("uploadFile", fileEntity);
String url = "http://fileserver.tiger2.cn/rest/createFile";
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity(multiValueMap, header);
ResponseEntity<Map> postForEntity = restTemplate.postForEntity(url, httpEntity, Map.class, new Object[0]);
result = (Map)postForEntity.getBody();
} catch (Exception var11) {
;
}
return result;
}
9,客户端远程调用服务端生成附件在线预览地址
都是RestTemplate
的基本操作,这个就不说了吧!
完美谢幕!