MultipartFile-使用策略模式实现可拓展文件分类上传

引子:
想起以前第一个项目的时候,常常使用apache的fileUploadutil,感觉效果很不好,又不容易实现一个上传的过程。
后来使用了spring提供的MultipartFile上传机制,将少了很多复杂的处理过程。但是随着业务逻辑的复杂,对于文件的分类那时候处理得比较困难,比如上传一个图片,还是pdf,还是doc,图片多大?pdf多大?分别存储的路径在哪?如果是图片要压缩怎么办?等等,直到后来学习了策略模式,这些问题通通变成了可拓展,可维护的,文件上传现在对我来说,就是一两句代码的事情了。
大概的逻辑是这样的:把multipartFile和一个检验的具体策略传送给一个fileUtil,fileUtil根据具体的上传策略对文件执行上传操作,上传策略定义了文件可被接受的类型,文件大小,图片是否支持图片压缩,文件的存储路径等。当我们想要上传图片的时候,我们就使用图片策略,如果过几天想要上传pdf,我们只需要新写一个pdf上传策略就可以完成拓展,不需要修改原来代码。

概念扫盲
MultipartFile:spring对二进制文件的封装之后得到的一个对象,拿到它之后我们可以使用这个方法对文件进行上传

FileUtils.writeByteArrayToFile()

进行文件上传操作,且调用对象本身我们可以拿到一些文件信息。

A representation of an uploaded file received in a multipart request.

The file contents are either stored in memory or temporarily on disk. In either case, the user is responsible for copying file contents to a session-level or persistent store as and if desired. The temporary storages will be cleared at the end of request processing.

如何实现可拓展上传组件的封装
现在我的包是这样的
这里写图片描述

首先看一下上传策略接口

/**
 * 
 */
package com.ruiyi.upload.component;

/**
 * @author jiangjintai
 *
 */
public interface UpdateLoadFileStrategy {
    /**
     * 定义上传文件类型:格式如:bmp.jpg.tiff.gif.pcx.tga.exif.fpx.svg.psd.cdr.pcd.dxf.ufo.eps.ai.raw.png(用点隔开)
     * "*"表示全部类型
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    String type();
    /**
     * 定义上传文件的路径
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    String path();
    /**
     * 定义文件的大小 单位为M
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    Long size();


}

可被压缩接口

/**
 * 
 */
package com.ruiyi.upload.component;

/**
 * @author jiangjintai
 *
 */
public interface Compressable {
    /**
     * 压缩后的图片宽
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    String pictureWidth();
    /**
     * 压缩后的图片长
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    String pictureLength();
    /**
     * 压缩后图片的存储路劲
     * jiangjintai
     * 2016年8月12日
     * @return
     */
    String changedPath();
}

图片压缩外观类

package com.ruiyi.upload.component;
import java.io.File;
import java.io.IOException;
import net.coobird.thumbnailator.Thumbnails;



/*
 * 通过像素的缩放技术,改变图片的大小
 * --等距采样法
 */
public class ImageChange {
    private File file=null;
    private File out=null;
    public ImageChange(String filePath,String newFilePath) throws IOException{

        this.file = new File(filePath);//原图片
        this.out= new File(newFilePath);//目的图片  
    }
    /**
     * @param uploadPrictureFile
     * @param changePrictureFile
     */
    public ImageChange(File uploadPrictureFile, File changePrictureFile) {
        this.file=uploadPrictureFile;
        this.out=changePrictureFile;
    }
    /**
     * 
     * @param width 改变后图片的宽
     * @param heigth 改变后图片的高
     * @throws IOException 
     * @throws SimpleImageException 
     */
    public void flex(int width,int height) throws IOException{
        /*
         * size(width,height) 若图片横比200小,高比300小,不变
         * 若图片横比200小,高比300大,高缩小到300,图片比例不变 若图片横比200大,高比300小,横缩小到200,图片比例不变
         * 若图片横比200大,高比300大,图片按比例缩小,横为200或高为300
         */
        Thumbnails.of(file).size(1024, 768).toFile(out);
        //开源框架
    }


}

再来看看我们的上传主类

package com.ruiyi.upload.component;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.web.multipart.MultipartFile;


public class FileUpLoadUtil {
    private static final Logger logger = Logger.getLogger(FileUpLoadUtil.class);
    private String[] type;//文件类型
    private String path;//文件存储路径
    private long size;//文件大小(单位M)
    private UpdateLoadFileStrategy strategy; //文件存储策略

    public FileUpLoadUtil(UpdateLoadFileStrategy strategy) {
            type = strategy.type().split("\\.");
            path = strategy.path();
            size = strategy.size()*1024*1024;   
    }
    /**
     * 返回-1,表示类型出现问题,返回-2,表示尺寸过大,文件名表示存入成功,0表示未知错误
     * jiangjintai
     * 2016年3月23日
     * @param multipartFile
     * @param realPath
     * @return
     */
    public String doUpload(MultipartFile multipartFile, String realPath) {
        logger.info("选择当前保存根路径:"+realPath);
        String fileName = multipartFile.getOriginalFilename();//返回文件在客户机的路径
        logger.info("文件原本路径:"+fileName);
        String fileUploadName = fileName
                .substring(fileName.lastIndexOf("\\") + 1);
        logger.info("文件名:"+fileUploadName);
        String typeName = fileUploadName.substring(fileUploadName
                .lastIndexOf(".") + 1);
        logger.info("文件类型:"+typeName);
        if (multipartFile.getSize() >= size) {
            return "-2";
        }

        int count = 0;
        if("*".equals(type[0]))//代表全部类型
            count=1;
        for (String aType : type) {
            if (aType.toLowerCase().equals(typeName.toLowerCase())) {
                count = count + 1;
            }
        }
        logger.info("该类型与策略类型匹配程度:"+count+"匹配");
        if (count == 1) {
            //命名策略
            // 往文件名里面加上时间戳
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            int random = (int) (Math.random()*1000000);
            String timeStamp = sdf.format(new Date());
            fileUploadName = timeStamp +random+  fileUploadName.substring(fileUploadName
                    .lastIndexOf("."));//重新命名
            //命名策略结束 这里还可以抽出一个部分

            try {
                String fileLocalPath = realPath+path;//本地图片存储路径
                File file = new File(realPath + path);
                if (!file.exists()) {
                    file.mkdirs();
                }

                //这里用这个方式进行存储
                FileUtils.writeByteArrayToFile(new File(fileLocalPath,fileUploadName), multipartFile.getBytes());
                //如果是一个图片就进行转化处理
                if(strategy instanceof Compressable){
                    logger.info("是一个图片,进行压缩");
                    Compressable compressable = (Compressable) this.strategy;
                    File changeFile = new File(realPath+compressable.changedPath());
                    if(!changeFile.exists()){
                        changeFile.mkdirs();
                    }
                    File uploadPrictureFile = new File(fileLocalPath,fileUploadName);
                    File changePrictureFile = new File(realPath + compressable.changedPath(),fileUploadName);
                    ImageChange ic = new ImageChange(uploadPrictureFile,changePrictureFile);//进行压缩
                    ic.flex(Integer.valueOf(compressable.pictureWidth()),Integer.valueOf(compressable.pictureLength()));
                    String afterCompressable = "/"+compressable.changedPath()+"/"+fileUploadName;
                    logger.info("压缩后的路径:"+afterCompressable);
                    return afterCompressable;
                }else{
                    String fileSavedPath = "/"+path+"/"+fileUploadName;
                    logger.info("文件保存路径");
                    return fileSavedPath;
                }
            } catch (Exception e) {
                e.printStackTrace();
                return "0";
            }
        } else {            
            return "-1";
        }
    }
}

最后你只需要根据你的需求定义一个具体的策略,如图片策略

/**
 * 
 */
package com.ruiyi.upload.component.strategy;

import com.ruiyi.upload.component.Compressable;
import com.ruiyi.upload.component.UpdateLoadFileStrategy;



/**
 * @author jiangjintai
 *
 */
public class PictureStrategy implements Compressable, UpdateLoadFileStrategy {
    private final String type = "bmp.jpg.tiff.gif.pcx.tga.exif.fpx.svg.psd.cdr.pcd.dxf.ufo.eps.ai.raw.png";
    private final String path = "picture";
    private final String pictureWidth = "1024";
    private final String pictureLength = "768";
    private final String changedPath = "changed";
    private final Long size = 10L;
    /* (非 Javadoc)
     * @see com.haizhi.upload.component.UpdateLoadFileStrategy#type()
     */
    @Override
    public String type() {
        // 
        return this.type;
    }

    /* (非 Javadoc)
     * @see com.haizhi.upload.component.UpdateLoadFileStrategy#path()
     */
    @Override
    public String path() {
        // 
        return path;
    }

    /* (非 Javadoc)
     * @see com.haizhi.upload.component.UpdateLoadFileStrategy#size()
     */
    @Override
    public Long size() {
        // 
        return size;
    }

    /* (非 Javadoc)
     * @see com.haizhi.upload.component.Compressable#pictureWidth()
     */
    @Override
    public String pictureWidth() {
        // 
        return pictureWidth;
    }

    /* (非 Javadoc)
     * @see com.haizhi.upload.component.Compressable#pictureLength()
     */
    @Override
    public String pictureLength() {
        // 
        return pictureLength;
    }

    /* (非 Javadoc)
     * @see com.haizhi.upload.component.Compressable#changedPath()
     */
    @Override
    public String changedPath() {
        // 
        return changedPath;
    }

}

使用事例:

FileUpLoadUtil ufuu = new FileUpLoadUtil(new PictureStrategy());//这里如果你需要也可以使用工厂模式
            String flag = ufuu.doUpload(productImage, request
                    .getServletContext().getRealPath("/"));
            switch (flag) {
            case "-1":
                return ResponseEntityUtil.buildErrorEntity(
                        ErrorCode.paramError, "类型出错");
            case "-2":
                return ResponseEntityUtil.buildErrorEntity(
                        ErrorCode.paramError, "尺寸要小于10M");
            case "0":
                return ResponseEntityUtil.buildErrorEntity(
                        ErrorCode.paramError, "未知错误");
            default:
                tbProduct.setProductImgUrl(flag);
                break;
            }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值