梳理

(一)梳理思路

搭建项目结构

搭建前端环境,技术准备,git

前后端分离的思想,开发的流程,mybatisplus的入门

商品品牌和分类,以及crud实现、高级查询。分页查询

redis项目实战、页面静态化

图片文件的统一处理

(二)图片的文件处理

单体项目处理图片思路:

用户注册时,上传头像,
将图片上传到本地的盘符,数据库内保存图片的路径

问题1:(资源占用空间)
		由于图片是存储在本地的,项目发布之后,图片和war包在同一个服务器,但是图片资源是非常占用资源的,因此占用了服务器的资源。随着图片占用空间的增加,服务器额资源越小。
	
问题2:(集群环境之下,资源可能访问呢不到)
		如果在微服务架构之下,图片存放在一个服务器,因为负载均衡的作用,导致用户访问的是另一个服务器,但是另一个服务器就没有这个资源,用户就获取不到图片资源。

因此需要将图片进行统一处理,

微服务架构下的,分布式模块处理图片上传的思路:

① 撘一个分布式的文件服务器,具有分布式的效果,因为分布式快,因为是集群,就避免了单点故障(有备用服务器)。

② 服务器上面存放很多的图片,通过唯一标识进行区分(比如我们DB中的id)
③ 之后服务器会将标识返回,再将标识存放到数据库中。
④ 这样处理之后,用户在登录时,获取唯一标识,就可以到图片服务器上面去获取图片资源。
⑤ 前台直接就是通过路径(http协议+IP+port+标识)展示用户的图片资源。
  1. 购买服务器
    阿里云、七牛云

  2. 搭建服务器
    使用FastDFS:免费。功能OK

(三)Hello FastDFS

FacstDFs是C写的开源的文件分布式系统

  1. FastDFs架构分为:(两大角色)
    Tracker server 跟踪或调度服务器(对外)
    实现集群,收集Stroage的信息
    Storage server 存储服务器(真正实现存储)
    分布很多组(group),每个组是不一样的,但是组内的数据时一致的,没有主从概念,都是公平的。

  2. 首先需要安装FastDFs服务器
    需要保证IP地址的分配处理,修改两个配置文件的ip地址
    启动服务,和基本的测试

  3. 通过java客户端,实现文件的上传和下载
    ① 导入 依赖

    maven打jar包:
    在当前源码包路径下,进入cmd,输入命令:mvn clean package install
    (注意需要在源码所在的文件夹内进行打包,否则会找不到文件异常)

    echo “%MAVEN_HOME%” 查看当前maven的环境变量

    引入本地打的jar包

(四)搭建文件上传微服务

关于搭建文件上传系统,我也会在博客中记录,具体搭建思路,后续整理
创建FastDFs的接口以及回调函数(因为其他服务也会有图片文件上传的业务,所以将文件系统服务抽取到公共的接口中,其他服务就可以进行一个调用)

  1. 创建公共接口,并注册到Eurka注册中心
package cn.lzj.aigou.client;

import cn.lzj.aigou.util.AjaxResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@FeignClient(value="COMMON-PROVIDER",fallback = FastDfsFallback.class)
public interface FastDfsClient {

    //上传
    @RequestMapping(value = "/common/upload",method = RequestMethod.POST)
    AjaxResult upload(@RequestBody MultipartFile file);

    //下载:页面直接使用http://ip/groupname/filename

    //删除:直接获取前台传入的路径即可(前台传入的是存放在文件服务系统内的组名+文件唯一标识符)
    @RequestMapping(value = "/common/delete",method = RequestMethod.GET)
    AjaxResult delete(@RequestParam("filePath") String filePath);

}
  1. 创建接口的托底函数(当服务器出现问题时,将托底函数的内容返回给用户)
package cn.lzj.aigou.client;

import cn.lzj.aigou.util.AjaxResult;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

@Component
public class FastDfsFallback implements  FastDfsClient{

    @Override
    public AjaxResult upload(MultipartFile file) {
        return AjaxResult.me().setSuccess(false).setMsg("抱歉,服务器正忙,请稍后再试~");
    }

    @Override
    public AjaxResult delete(String filePath) {
        return AjaxResult.me().setSuccess(false).setMsg("抱歉,服务器正忙,请稍后再试~");
    }
}
  1. 抽取文件上传工具类
package cn.lzj.aigou.common.util;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

/**
 * 微服务中文件上传的工具类
 */
public class FastDfsApiOpr {
    /**
     * fdfs_client.conf   为配置文件,内部配置的是文件上传系统所部署的位置(IP+port)
     */
    public static String CONF_FILENAME  = FastDfsApiOpr.class.getResource("/fdfs_client.conf").getFile();

    /**
     * 上传文件
     * @param file
     * @param extName
     * @return
     */
    public static  String upload(byte[] file,String extName) {
 
        try { 
            ClientGlobal.init(CONF_FILENAME); //加载配置文件
 
            TrackerClient tracker = new TrackerClient(); 
            TrackerServer trackerServer = tracker.getConnection(); 
            StorageServer storageServer = null;
 
            StorageClient storageClient = new StorageClient(trackerServer, storageServer); 
            NameValuePair nvp [] = new NameValuePair[]{
                    new NameValuePair("age", "18"), 
                    new NameValuePair("sex", "male") 
            }; 
            String fileIds[] = storageClient.upload_file(file,extName,nvp);
             
            System.out.println(fileIds.length); 
            System.out.println("组名:" + fileIds[0]); 
            System.out.println("路径: " + fileIds[1]);
            return  "/"+fileIds[0]+"/"+fileIds[1];
 
        } catch (Exception e) {
            e.printStackTrace();
            return  null;
        }
    }

    /**
     * 下载文件
     * @param groupName
     * @param fileName
     * @return
     */
    public static byte[] download(String groupName,String fileName) {
        try {
 
            ClientGlobal.init(CONF_FILENAME);
 
            TrackerClient tracker = new TrackerClient(); 
            TrackerServer trackerServer = tracker.getConnection(); 
            StorageServer storageServer = null;
 
            StorageClient storageClient = new StorageClient(trackerServer, storageServer); 
            byte[] b = storageClient.download_file(groupName, fileName);
            return  b;
        } catch (Exception e) {
            e.printStackTrace();
            return  null;
        } 
    }

    /**
     * 删除文件
     * @param groupName
     * @param fileName
     */
    public static int delete(String groupName,String fileName){
        try {
            ClientGlobal.init(CONF_FILENAME);

            TrackerClient tracker = new TrackerClient();
            TrackerServer trackerServer = tracker.getConnection();
            StorageServer storageServer = null;

            StorageClient storageClient = new StorageClient(trackerServer,
                    storageServer);
            int i = storageClient.delete_file(groupName,fileName);

            //因为底层源码使用的是0,作为判断数据是否正确删除
            System.out.println( i==0 ? "删除成功" : "删除失败:"+i);
            return i;
        } catch (Exception e) {
            e.printStackTrace();
            throw  new RuntimeException("删除异常,"+e.getMessage());
        }
    }
}
  1. 文件上传和下载访问的controller接口
package cn.lzj.aigou.common.controller;

import cn.lzj.aigou.client.FastDfsClient;
import cn.lzj.aigou.common.util.FastDfsApiOpr;
import cn.lzj.aigou.util.AjaxResult;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@RestController    //加上此注解才表示为一个controller层
@RequestMapping("/common")
public class FastDfsController implements FastDfsClient {

    /**
     * 文件上传
     * @param file   注意,此处有坑,当心~~~~~在微服务中,使用文件的上传,必须使用MultipartFile接受前台所传入的参数
     */
    @Override
    @RequestMapping(value = "/upload",method = RequestMethod.POST)
    public AjaxResult upload(@RequestBody MultipartFile file) {
        try {
            byte[] bytes = file.getBytes();
            //原始名
            String originalFilename = file.getOriginalFilename();
            //后缀名
            String extName = FilenameUtils.getExtension(originalFilename);
            // "/"+fileIds[0]+"/"+fileIds[1];
            String groupNameAndFileName = FastDfsApiOpr.upload(bytes, extName);
            return AjaxResult.me().setSuccess(true).setMsg("亲,文件上传成功!").setObject(groupNameAndFileName);
        } catch (IOException e) {
            e.printStackTrace();
            return AjaxResult.me().setSuccess(false).setMsg("亲,文件上传失败!"+e.getMessage());
        }
    }

    @Override
    @RequestMapping(value = "/delete",method = RequestMethod.GET)
    public AjaxResult delete(String filePath) {
        // filePath:   http://ip/groupName/fileName
        //    /groupName/fileName   groupName/fileName
        String filePath1  =filePath.substring(1);
        String  groupName= filePath1.substring(0, filePath1.indexOf("/"));
        String fileName=filePath1.substring(filePath1.indexOf("/")+1);
        int delete = FastDfsApiOpr.delete(groupName, fileName);
        if(delete==0){
            return AjaxResult.me().setSuccess(true).setMsg("删除成功!!");
        }else{
            return AjaxResult.me().setSuccess(false).setMsg("删除失败!!");
        }
    }
}

此时文件上传的服务就搭建完毕,其他服务有上传文件的业务需求,直接通过fegin进行调用即可。

以下我以产品分类的品牌,上传品牌logo为例,调用文件上传服务进行文件的上传。

直接在产品分类的服务的入口,添加@EnableFeignClients(“cn.lzj.aigou.client”) ,包的路径就是,抽取的公共的文件上传接口的路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值