springcloud feign前后端分离实现文件上传下载

文件上传

一、服务消费者Controller

package com.biddingportal.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.biddingportal.model.annextem.query.AnnexItemQuery;
import com.biddingportal.model.attachme.query.AttachmeQuery;
import com.biddingportal.model.commons.Result;
import com.biddingportal.service.AttachmeFeignClinent;
import feign.Response;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;

@RestController
@CrossOrigin(origins = "*",maxAge = 3600) //解决跨域
@RequestMapping("/attachmeController")
public class AttachmeController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AttachmeFeignClinent attachmeFeignClinent;

    /*附件文件上传
    *
    * */
    @PostMapping(value = "/multifileUpload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result upload(@RequestParam("file") MultipartFile file ,
                         @RequestParam("projectId") String projectId,
                         @RequestParam("user" ) String user) throws Throwable {

            //通过远程访问,访问bidding系统
            String result = attachmeFeignClinent.upload(file,projectId,user);
            //把json字符串转化成javabean对象
            Result resultObj = JSONObject.parseObject(result,Result.class);
            //输入日志
            logger.info("上传附件成功");
            //返回结果
            return resultObj;

    }


 /*
    * 附件文件下载,这里需要返回ResponseEntity对象,而feignClient是通过Response
      来接收服务提供者方返回的文件
    * */
    @PostMapping("/downloadAttachem")
    public ResponseEntity downloadAttachme(@RequestBody AttachmeQuery attachmeQuery) throws Throwable {
        //获取附件文件id
        String attachmeId = attachmeQuery.getAttachmeId();
        //获取附件文件名
        String filename = attachmeQuery.getFileName();
       logger.info("使用feign调用服务 文件下载");
        ResponseEntity result = null;
        InputStream inputStream = null;
        try {
            // feign文件下载
            Response response = attachmeFeignClinent.downloadAttachme(attachmeId);
            Response.Body body = response.body();
            inputStream = body.asInputStream();
            //创建字节数组,由于存放附件
            byte[] b = new byte[inputStream.available()];
            //输入流读取字节数组
            inputStream.read(b);
            /*设置响应头
            1.设置CONTENT_DISPOSITION
            2.设置CONTENT_TYPE
            * */
            HttpHeaders heads = new HttpHeaders();
            heads.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="+filename);
            heads.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            result = new ResponseEntity(b, heads, HttpStatus.OK);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        logger.info("附件文件下载成功");
        return result;
    }



}

feginClient端

package com.biddingportal.service;
import com.biddingportal.service.impl.AttachmeFeignClinentImpl;
import feign.Response;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;



@FeignClient(name = "bidding",fallback = AttachmeFeignClinentImpl.class)
public interface AttachmeFeignClinent {

    /*
     * 附件上传保存
     * */
    @PostMapping(value = "/attachmeController/multifileUpload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String upload(@RequestPart("file") MultipartFile file,
                  @RequestParam("projectId") String projectId,
                  @RequestParam("user" ) String user)throws Throwable;

    /*
    * 附件下载
    * 通过Response来接收文件流
    * */
    @PostMapping("/attachmeController/downloadAttachem")
    Response downloadAttachme(@RequestBody String attachemId) throws Throwable;
}

//FeignClinentImpl类

package com.biddingportal.service.impl;

import com.biddingportal.service.AttachmeFeignClinent;
import feign.Response;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;



@Component
public class AttachmeFeignClinentImpl implements AttachmeFeignClinent {

    @Override
    public String upload(MultipartFile file, String projectId,String user) throws Throwable {
        return "请求超时";
    }

    @Override
    public Response downloadAttachme(String attachemId) throws Throwable {
        return null;
    }
}

在文件上传时FeignClient调用接口时不支持上传文件,需要设置文件编码,之前用的@Configuration 可以实现,但对于全局的请求都会影响

package com.biddingportal.config;


import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.cloud.netflix.feign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;


/**
 * feign多媒体文件传输
 */

@Configuration
public class FeignMultipartSupportConfig {

    @Autowired
    private ObjectFactory messageConverters;

    @Bean
    @Primary//自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
    @Scope("prototype")//使用多例每次获得bean都会生成一个新的对象
    public Encoder multipartFormEncoder() {
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    @Bean
    public feign.Logger.Level multipartLoggerLevel() {
        return feign.Logger.Level.FULL;
    }


}

 

公共类Result.统一用于返回结果

package com.biddingportal.model.commons;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.List;

/**
 * 自定义响应结构
 */
public class Result {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    // 响应业务状态 200-成功  500-失败   404-找不到资源等.
    private Integer status;

    // 响应消息
    private String msg;

    // 响应中的数据
    private Object data;

    public static Result build(Integer status, String msg, Object data) {
        return new Result(status, msg, data);
    }

    public static Result ok(Object data) {
        return new Result(data);
    }

    public static Result ok() {
        return new Result(null);
    }

    public Result() {

    }

    public static Result build(Integer status, String msg) {
        return new Result(status, msg, null);
    }

    public Result(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public Result(Object data) {
        this.status = 200;
        this.msg = "OK";
        this.data = data;
    }

//    public Boolean isOK() {
//        return this.status == 200;
//    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    /**
     * 将json结果集转化为Result对象
     * 
     * @param jsonData json数据
     * @param clazz Result中的object类型
     * @return
     */
    public static Result formatToPojo(String jsonData, Class clazz) {
        try {
            if (clazz == null) {
                return MAPPER.readValue(jsonData, Result.class);
            }
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            JsonNode data = jsonNode.get("data");
            Object obj = null;
            if (clazz != null) {
                if (data.isObject()) {
                    obj = MAPPER.readValue(data.traverse(), clazz);
                } else if (data.isTextual()) {
                    obj = MAPPER.readValue(data.asText(), clazz);
                }
            }
            return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 没有object对象的转化
     * 
     * @param json
     * @return
     */
    public static Result format(String json) {
        try {
            return MAPPER.readValue(json, Result.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Object是集合转化
     * 
     * @param jsonData json数据
     * @param clazz 集合中的类型
     * @return
     */
    public static Result formatToList(String jsonData, Class clazz) {
        try {
            JsonNode jsonNode = MAPPER.readTree(jsonData);
            JsonNode data = jsonNode.get("data");
            Object obj = null;
            if (data.isArray() && data.size() > 0) {
                obj = MAPPER.readValue(data.traverse(),
                        MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
            }
            return build(jsonNode.get("status").intValue(), jsonNode.get("msg").asText(), obj);
        } catch (Exception e) {
            return null;
        }
    }

}

二、服务提供者Controller,并将文件信息保存到数据库中

package com.bidding.controller;


import com.bidding.model.annextem.query.AnnexItemQuery;
import com.bidding.model.annextem.vo.AnnexItemVo;
import com.bidding.model.attachme.query.AttachmeQuery;
import com.bidding.model.attachme.vo.AttachmeVo;
import com.bidding.model.commons.Result;
import com.bidding.service.AnnexItemService;
import com.bidding.service.AttachmeService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@RestController
@CrossOrigin(origins = "*",maxAge = 3600) //解决跨域
@RequestMapping("/attachmeController")
public class AttachmeController {
    private  Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private AttachmeService attachmeService;
    @Autowired
    private AnnexItemService annexItemService;

    /**
     * @param file
     * @param projectId
     * @return
     * @throws
     */
    @PostMapping(value = "/multifileUpload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Result upload(@RequestPart("file") MultipartFile file,
                         @RequestParam("projectId") String projectId,
                         @RequestParam("user" ) String user) throws Throwable {

        AttachmeQuery attachmeQuery = new AttachmeQuery();
        //获取项目根目录
        File genPath = null;
        {
            try {
                genPath = new File(ResourceUtils.getURL("classpath:").getPath());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
        Result result = new Result();
        //设置附件文件保存目录
        String uploadPath =genPath + "/static/file/"+projectId +"/";
        logger.info(uploadPath);
        //判断附件文件是否为空
        if (Objects.isNull(file) || file.isEmpty()) {
            logger.error("文件为空");
            return result.build(500,"对象为空");
        }

        try {
            byte[] bytes = file.getBytes();
            Path path = Paths.get(uploadPath + file.getOriginalFilename());
            //如果没有files文件夹,则创建
            if (!Files.isWritable(path)) {
                Files.createDirectories(Paths.get(uploadPath));
            }
            //文件写入指定路径
            Files.write(path, bytes);
            logger.debug("文件写入成功");
        } catch (IOException e) {
            e.printStackTrace();
            return result.build(500,"后端异常");
        }

        //附件文件id
        String attachmeId = UUID.randomUUID().toString().replaceAll("-", "");
        //附件文件保存路径
        String path = uploadPath;
        String fileName = file.getOriginalFilename();
        ///附件大小计算转换
        String fsize = null;
        int size = (int) file.getSize();
        if(size>1048576){
            fsize = String.valueOf(size/1048576)+"M";
        }else if (size<1024){
            fsize = String.valueOf(size)+"B";
        }else {
            fsize = String.valueOf(size/1024)+"KB";
        }
        logger.info(fileName + "-->" + size);
        String fileType = file.getContentType(); //获取文件类型
        attachmeQuery.setAttachmeId(attachmeId);
        attachmeQuery.setFileUrl(path);
        attachmeQuery.setFileName(fileName);
        attachmeQuery.setFileType(fileType);
        attachmeQuery.setFileSize(fsize);
        attachmeQuery.setUploadingPeople(user);
        attachmeQuery.setUploadTime(new Date());

        //保存附件文件数据库记录
        Result r = attachmeService.saveAttachme(attachmeQuery);
        logger.info("附件文件记录已保存到数据库");
        Result result1 = new Result();
        if(r.getStatus() == 200){
            AnnexItemQuery annexItemQuery = new AnnexItemQuery();
            annexItemQuery.setRelevanceCorrelationId(projectId);
            annexItemQuery.setAttachmeId(attachmeId);
             result1 =  annexItemService.saveAnnexItem(annexItemQuery);
             logger.info("附件文件关联记录已保存");
        }

        return result1.build(200,"添加成功");

    }
}

参考的博客链接:

文件上传:https://blog.csdn.net/jasnet_u/article/details/82805073

文件下载:https://www.2cto.com/kf/201902/797188.html

 

你可能感兴趣的:(学习整理)