大话设计模式-代理模式

代理模式

​ **案例:**根据文件类型,将文件存储到不同服务

​ 代理模式:给一个对象创建一个代理对象,通过代理对象可以使用该对象的功能。

​ CGLib和JDK 是代理模式实现的技术方案。

​ **场景:**在大的项目中,文件上传功能,因为大项目文件比较多,所以不可能存储到部署代码的服务 器中,所以可能要把文件上传到其他服务器中(或者云服务器),现在我们就把.mp4,.avi 类型文件放到阿里云服务器,把jpg,png 放到FastDFS 服务器(分布式文件系统)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BlI4EwbL-1606802064839)(C:\Users\EDZ\AppData\Roaming\Typora\typora-user-images\image-20201201102435013.png)]

实现分析: 基于代理模式,我们实现文件上传分别路由到aliyunOSS 和FastDFS,用例图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lqdrrxDH-1606802064841)(C:\Users\EDZ\AppData\Roaming\Typora\typora-user-images\image-20201201102816695.png)]

前端首先要访问FileController,FileController 注入FileUploadProxy 代理对象,然后调用FileUploadProxy 代理对象的方法。然后写阿里云服务器的文件上传接口,FastDFS 服务器的文件上传接口,或者华为云的文件上传功能,我们要遵循开闭原则,**开放扩展,关闭修改,**所以尽量(一定不要,因为是有技术实现不修改代码的,可能是自己技术没那么强,暂时想不出办法来)不要修改代码,现在就是写一个接口,定义一个upload 方法,所有的文件上传功能都实现这个接口,然后通过FileController 得到文件的后缀名称,通过文件的后缀名判断调用哪个对象的方法。

FileController:是控制器,用于接收用户提交的文件,并调用代理FileUploadProxy实现文件上传。

@RestController
@RequestMapping(value = "/file")
public class FileController {

    @Autowired
    private FileUploadProxy fileUploadProxy;

    /***
     * 文件上传
     * @param file
     * @return
     * @throws IOException
     */
    @PostMapping(value = "/upload")
    public String upload(MultipartFile file) throws Exception {
        return fileUploadProxy.upload(file);
    }
}

FileUploadProxy:是代理对象,供用户访问,调用了FileUpload的文件上传方法,为用户提供不同文件上传调用。


@ConfigurationProperties(prefix = "upload")
@Component(value = "fileUploadProxy")
public class FileUploadProxy {

    @Autowired
    private ApplicationContext act;

    private Map<String,List<String>> filemap;

    /****
     * 文件上传
     * @param file
     * @return
     */
    public String upload(MultipartFile file) throws Exception{
        //1.文件的字节数组
        byte[] buffers = file.getBytes();

        //2.文件的扩展名   1.jpg
        String fileName = file.getOriginalFilename();
        String extName = StringUtils.getFilenameExtension(fileName);    //jpg|mp4|png

        /***
         * 3.1 aliyunOSSFileUpload----->mp4,avi
         * 3.2 fastdfsFileUpoad----->png,jpg,gif
         */
        for (Map.Entry<String, List<String>> entry : filemap.entrySet()) {
            //获取后缀集合
            for (String suffix : entry.getValue()) {
                //循环迭代匹配后缀
                if(suffix.equalsIgnoreCase(extName)){
                    return act.getBean(entry.getKey(),FileUpload.class).upload(buffers,extName);
                }
            }
        }
        return null;
    }

    /****
     * 文件上传
     * @param file
     * @return
     */
    public String upload_backup(MultipartFile file) throws Exception{
        //1.文件的字节数组
        byte[] buffers = file.getBytes();

        //2.文件的扩展名   1.jpg
        String fileName = file.getOriginalFilename();
        String extName = StringUtils.getFilenameExtension(fileName);    //jpg|mp4|png

        /***
         * 3.1 aliyunOSSFileUpload----->mp4,avi
         * 3.2 fastdfsFileUpoad----->png,jpg,gif
         */
        //1.判断文件后缀
        if(extName.equalsIgnoreCase("mp4") || extName.equalsIgnoreCase("avi")){
            //2.根据文件后缀获取指定对象的实例----->ApplicationContext获取实例
            return act.getBean("aliyunOSSFileUpload",FileUpload.class).upload(buffers,extName);
        }else if(extName.equalsIgnoreCase("png") || extName.equalsIgnoreCase("jpg")){
            return act.getBean("fastdfsFileUpoad",FileUpload.class).upload(buffers,extName);
        }
        return null;
    }

    //依赖注入
    public void setFilemap(Map<String, List<String>> filemap) {
        this.filemap = filemap;
    }
}

FileUpload: 抽象接口,定义了文件上传方法,分别给它写了2种实现。

public interface FileUpload {


    /****
     * 文件上传方法
     * 返回值:上传的文件访问路径
     */
    String upload(byte[] buffers,String extName);
}

FastdfsFileUpload:是将文件上传到FastDFS,主要上传png和jpg的图片小文件。


@Component(value = "fastdfsFileUpoad")
public class FastdfsFileUpoad implements FileUpload{

    @Value("${fastdfs.url}")
    private String url;

    /***
     * 文件上传
     * @param buffers:文件字节数组
     * @param extName:后缀名
     * @return
     */
    @Override
    public String upload(byte[] buffers, String extName) {
        /***
         * 文件上传后的返回值
         * uploadResults[0]:文件上传所存储的组名,例如:group1
         * uploadResults[1]:文件存储路径,例如:M00/00/00/wKjThF0DBzaAP23MAAXz2mMp9oM26.jpeg
         */
        String[] uploadResults = null;
        try {
            //获取StorageClient对象
            StorageClient storageClient = getStorageClient();
            //执行文件上传
            uploadResults = storageClient.upload_file(buffers, extName, null);
            return url+uploadResults[0]+"/"+uploadResults[1];
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /***
     * 初始化tracker信息
     */
    static {
        try {
            //获取tracker的配置文件fdfs_client.conf的位置
            String filePath = new ClassPathResource("fdfs_client.conf").getPath();
            //加载tracker配置信息
            ClientGlobal.init(filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 获取StorageClient
     * @return
     * @throws Exception
     */
    public static StorageClient getStorageClient() throws Exception{
        //创建TrackerClient对象
        TrackerClient trackerClient = new TrackerClient();
        //通过TrackerClient获取TrackerServer对象
        TrackerServer trackerServer = trackerClient.getConnection();
        //通过TrackerServer创建StorageClient
        StorageClient storageClient = new StorageClient(trackerServer,null);
        return storageClient;
    }
}

AliyunOSSFileUpload:是将文件上传到aliyunOSS,主要上传mp4和avi 的视频大文件


@Component(value = "aliyunOSSFileUpload")
public class AliyunOSSFileUpload implements FileUpload{

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${aliyun.oss.accessKey}")
    private String accessKey;
    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;
    @Value("${aliyun.oss.key}")
    private String key;
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;
    @Value("${aliyun.oss.backurl}")
    private String backurl;

    /****
     * 文件上传
     *  文件类型如果是图片,则上传到本地FastDFS
     *  文件类型如果是视频,则上传到aliyun OSS
     */
    @Override
    public String upload(byte[] buffers,String extName) {
        String realName = UUID.randomUUID().toString()+"."+extName ;
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, accessKeySecret);
        // <yourObjectName>表示上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key+realName, new ByteArrayInputStream(buffers));
        // 上传字符串。
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(FileUtil.getContentType("."+extName));
        putObjectRequest.setMetadata(objectMetadata);
        ossClient.putObject(putObjectRequest);

        // 关闭OSSClient。
        ossClient.shutdown();
        return backurl+realName;
    }
}

application.yml 配置:这里配置的是aliyun ,FastDFS的连接信息

upload 这块配置的是一个map,key,value 形式的,我们在FileController 中获取这段配置,然后获取用户上传文件的后缀名,和这个配置比较,上传到指定服务器中。

server:
	port: 18081
#指定服务处理指定的文件类型
upload:
	filemap:
		aliyunOSSFileUpload: mp4,avi
		fastdfsFileUpload: png,jpg
#FastDFS配置
fastdfs:
	url: http://192.168.211.137:28181/
#aliyun
aliyun:
	oss:
		FileUpload接口定义:
		AliyunOSSFileUpload实现:
		endpoint: oss-cn-beijing.aliyuncs.com
		accessKey: a7i6rVEjbtaJdYX2
		accessKeySecret: MeSZPybPHfJtsYCRlEaUbfRtdH8gl4
		bucketName: sklll
		key: video/
		backurl: https://sklll.oss-cn-beijing.aliyuncs.com/video/ #访问地址配置
spring:
	servlet:
		multipart:
			max-file-size: 100MB #上传文件大小配置

g.aliyuncs.com
accessKey: a7i6rVEjbtaJdYX2
accessKeySecret: MeSZPybPHfJtsYCRlEaUbfRtdH8gl4
bucketName: sklll
key: video/
backurl: https://sklll.oss-cn-beijing.aliyuncs.com/video/ #访问地址配置
spring:
servlet:
multipart:
max-file-size: 100MB #上传文件大小配置


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

vegetari

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值