通用的上传文件

目录

方式一:基于传统IO的方式

方式二:基于NIO

改进通用的上传文件服务


内容:其实就是将前端上传过来的文件保存到我们指定的服务器目录下

案例:添加信息时,我们一般还需要上传商品的图片或者其他文件!

先创建两张数据库表item和appendix

create table item(
	id int(11) not null auto_increment,
    name varchar(255) default null comment "商品名",
    code varchar(255) default null comment "商品编号",
    is_active int(11) default 1 comment "是否有效(1=是:0=否)",
    create_time datetime default null,
    primary key(id)
)engine=InnoDB default charset=utf8 comment="商品表";

create table appendix(
	id int(11) not null auto_increment,
    module_id int(11) default null comment "所属模块记录主键id",
    module_code varchar(255) character set utf8mb4 default null comment "所属模块编码",
    module_name varchar(255) character set utf8mb4 default null comment "所属模块名称",
    name varchar(100) character set utf8mb4 default null comment "文件名称",
    size varchar(255) character set utf8mb4 default null comment "文件大小",
    suffix varchar(50) character set utf8mb4 default null comment "文件后缀名",
    file_url varchar(500) character set utf8mb4 default null comment "文件访问的磁盘目录",
    is_active tinyint(4) default 1 comment "是否有效(1=是:0=否)",
    create_time datetime default current_timestamp comment "创建时间",
    primary key(id)
)engine=InnoDB default charset=utf8 comment"附件(文件)上传记录";

使用逆向工程生成相应的entity、mapper和mapper.xml

方式一:基于传统IO的方式

ItemController

@RestController
@RequestMapping("item")
public class ItemController extends  AbstractController{

    @Autowired
    private ItemService itemService;

    //添加商品-上传文件
    @RequestMapping(value="add/upload/v1",method = RequestMethod.POST)
    public BaseResponse upload(MultipartHttpServletRequest request){
        BaseResponse response = new BaseResponse(StatusCode.Success);
        try{
            log.info("--添加商品-上传文件");
            itemService.addAndUpload(request);
        }catch (Exception e){
            response = new BaseResponse(StatusCode.Fail);
        }
        return response;
    }
}

ItemService

@Service
public class ItemService {
    private static final Logger log = LoggerFactory.getLogger(ItemService.class);
    @Autowired
    private ItemMapper itemMapper;

    @Autowired
    private CommonService commonService;

    //添加商品和上传文件
    @Transactional(rollbackFor = Exception.class)
    public void addAndUpload(MultipartHttpServletRequest request) throws Exception{

        MultipartFile multipartFile = request.getFile("appendix");

        String itemName = request.getParameter("itemName");
        String itemCode = request.getParameter("itemCode");
        if(StringUtils.isBlank(itemName) || StringUtils.isBlank(itemCode)){
            throw  new RuntimeException("商品编码或者商品名称不能为空!");
        }

        Item item = new Item(itemName,itemCode);
        itemMapper.insertSelective(item);

        commonService.uploadV1(multipartFile, item.getId());
    }
}
CommonService(处理商品的附件)
@Service
public class CommonService {

    private static final Logger log = LoggerFactory.getLogger(ItemService.class);

    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private Environment env;
    @Autowired
    private AppendixMapper appendixMapper;
    public void uploadV1(MultipartFile multipartFile, final Integer moduleId) throws Exception{

       //TODO:将前端上传过来的文件保存到指定的服务器目录下
        String fileName = multipartFile.getOriginalFilename();
        Long size = multipartFile.getSize();

        String suffix = StringUtils.substring(fileName, StringUtils.indexOf(fileName, "."));

        String rootPath =  env.getProperty("file.upload.location.root.url") + DATE_FORMAT.format(new Date()) + File.separator+ moduleId;

        String newFileName = System.nanoTime() + suffix;//雪花算法 snowflake
        //上传之后的文件名
        String newFile = rootPath + File.separator + newFileName;

        File file = new File(newFile);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        multipartFile.transferTo(file);

        //TO:保存成功后将可以被访问的url拿出来,然后添加到数据库中-用于记录:上传历史

        log.info("====insertSelective before====");
        Appendix entity = new Appendix(moduleId, "item","商品", fileName, size.toString(), suffix, newFile);
        log.info(entity.toString());
        appendixMapper.insertSelective(entity);
        log.info("====insertSelective after====");
    }
}

结果:

方式二:基于NIO

(Non-blocking I/O, 在Java领域,也称为New I/O)的方式!其实主要是利用Files、Path组件相关API来实现(也有两种形式的覆盖)

public void uploadV2(MultipartFile multipartFile, final Integer moduleId) throws Exception{

        //TODO:将前端上传过来的文件保存到指定的服务器目录下
        String fileName = multipartFile.getOriginalFilename();
        Long size = multipartFile.getSize();

        String suffix = StringUtils.substring(fileName, StringUtils.indexOf(fileName, "."));

        String rootPath =  env.getProperty("file.upload.location.root.url") + DATE_FORMAT.format(new Date()) + File.separator+ moduleId;

        String newFileName = System.nanoTime() + suffix;
        //上传之后的文件名
        String newFile = rootPath + File.separator + newFileName;

        File file = new File(newFile);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }

        Path path = Paths.get(newFile);

        //TODO:方式一
        Files.write(path,multipartFile.getBytes());

        //方式二(如果文件名相同,则覆盖)
        Files.copy(multipartFile.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);

        //TO:保存成功后将可以被访问的url拿出来,然后添加到数据库中-用于记录:上传历史
        Appendix entity = new Appendix(moduleId, "item","商品", fileName, size.toString(), suffix, newFile);
        appendixMapper.insertSelective(entity);


    }

改进通用的上传文件服务

问题:既然要通用,那就肯定不只是给 "商品Item"模块使用

改进:因此我们不能硬编码,需要将动态配置起来!另外,FileUrl应当只存储“除去域名/根目录"剩下的路径!

如:file_url为E:\srv\middleware\appendix\20201026\2\123.jpg的只需要存储为\20201026\2\123.jpg,好处是:当发生迁移时,无需太多的修改。而且还能较少存储空间。

Appendix entity = new Appendix(moduleId, "item","商品", fileName, size.toString(), suffix, newFile);

因为这里给写死了,如果用户模块,订单模块等都需要上传文件的话,这里不够灵活。

创建一个枚举类

//系统/项目-模块的枚举类型
public enum SysModule {
    ModuleItem("item", "商品模块"),
    ModuleUser("user", "用户模块"),
    ModuleOrder("order","订单模块")
    ;
    private String code;
    private String name;

    SysModule(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

ItemService中调用的时候传递一个SysModule的类


commonService.uploadV1(multipartFile, item.getId(), SysModule.ModuleItem);

CommonService中-构造Appendix 的entity对象时发生了变化-数据库中存储的去掉了根目录

    public void uploadV1(MultipartFile multipartFile, final Integer moduleId, final SysModule sysModule) throws Exception{

       //TODO:将前端上传过来的文件保存到指定的服务器目录下
        String fileName = multipartFile.getOriginalFilename();
        Long size = multipartFile.getSize();
        String suffix = StringUtils.substring(fileName, StringUtils.indexOf(fileName, "."));

        String newFileName = System.nanoTime() + suffix;
        String filePath = DATE_FORMAT.format(new Date()) + File.separator + sysModule.getCode() + File.separator + moduleId  + File.separator + newFileName;
        //上传之后的文件名
        String newFile = env.getProperty("file.upload.location.root.url") + filePath + File.separator + newFileName;

        File file = new File(newFile);
        if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();
        }
        multipartFile.transferTo(file);

        //TO:保存成功后将可以被访问的url拿出来,然后添加到数据库中-用于记录:上传历史

        Appendix entity = new Appendix(moduleId, sysModule.getCode(),sysModule.getName(), fileName, size.toString(), suffix, filePath);
        log.info(entity.toString());
        appendixMapper.insertSelective(entity);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值