动手做一个文件服务器【简易版本 亦可作为私人网盘】

当我们在做项目时难免都要上传附件,这时我们会用到市面上开源的文件服务器,例如FastDFSServUHDFS等文件服务器,我想我可不可以做一个简易版本的小型文件服务器系统呢?

一,文件服务器的主要工作内容是什么?

  1. 向外界提供上传附件的接口
  2. 向外界提供附件在线预览地址的接口
  3. 服务器本身在硬盘上对所有的附件作统一管理

二,文件服务器的原理是什么?

文件服务器作为服务端,自然要接收客户端发送来的文件并将文件写入本地磁盘,然后做一些处理可以预览附件,那么这一句话就够用了,下面开始动手写一个简易的文件服务器。

三,动手写文件服务器

写这个服务器没有用到数据库,全都是文件流的操作,仅此而已!
在这里插入图片描述
在这里插入图片描述

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.copyInputStreamToFilecommons-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的基本操作,这个就不说了吧!

完美谢幕!

猜你喜欢

转载自blog.csdn.net/weixin_44001965/article/details/107106235