Feign進行文件上傳+表單調用


Feigin默認是不支持文件上傳和表單提交的,需要做一些配置才能支持。

1、feign依賴

 圖中紅色為form支持必須的jar。

 

2、添加自定義Encoder類:

 

import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.web.multipart.MultipartFile;

import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.form.spring.SpringFormEncoder;
import lombok.val;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import static java.util.Collections.singletonMap;

/**
 * @author roger yang
 * @date 10/22/2019
 */
public class MultipartEncoder extends SpringFormEncoder {
    
    @SuppressWarnings("unchecked")
    @Override
    public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
        if (bodyType.getClass().equals(ParameterizedTypeImpl.class) && ((ParameterizedTypeImpl) bodyType).getRawType().equals(Map.class)) {
            val data = (Map<String, Object>) object;
            Set<String> nullSet = new HashSet<>();
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                if (entry.getValue() == null) {
                    nullSet.add(entry.getKey());
                }
            }
            for (String s : nullSet) {
                data.remove(s);
            }
            super.encode(data, MAP_STRING_WILDCARD, template);
            return;
        } else if (bodyType.equals(MultipartFile.class)) {
            val file = (MultipartFile) object;
            val data = singletonMap(file.getName(), object);
            super.encode(data, MAP_STRING_WILDCARD, template);
            return;
        } else if (bodyType.equals(MultipartFile[].class)) {
            val file = (MultipartFile[]) object;
            if (file != null) {
                val data = singletonMap(file.length == 0 ? "" : file[0].getName(), object);
                super.encode(data, MAP_STRING_WILDCARD, template);
                return;
            }
        }
        super.encode(object, bodyType, template);
    }
}

 

為什么要自定義呢?因為SpringFormEncoder這個類的源碼里只對MultipartFile做了特殊處理,並未對MultipartFile[]數組進行處理,在傳遞多個文件時會報錯。

  @Override
  public void encode (Object object, Type bodyType, RequestTemplate template) throws EncodeException {
    if (!bodyType.equals(MultipartFile.class)) {
      super.encode(object, bodyType, template);
      return;
    }

    val file = (MultipartFile) object;
    val data = singletonMap(file.getName(), object);
    super.encode(data, MAP_STRING_WILDCARD, template);
  }

另外,我們為了讓文件和表單一起在http的body里一起傳輸,所有我們將他們都封裝到map里統一處理。

 

3、feign接口類:

import java.util.Map;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.longge.common.GlobalResponse;

/**
 * @author: yangzhilong
 * @description: Notification api
 * post with MULTIPART_FORM_DATA_VALUE
 * you client feign config:
 * -------------------------------------------------------------------
 *  import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.context.annotation.Bean;
    
    import com.longge.api.NotificationService;
    
    import feign.codec.Encoder;
    import com.longge.config.MultipartEncoder;
    
    @FeignClient(value = "notification-service", configuration = NotificationServiceFeign.FeignSimpleEncoderConfig.class)
    public interface NotificationServiceFeign extends NotificationMultipartService {
        class FeignSimpleEncoderConfig {
            
            @Bean
            public Encoder encoder(){
                return new MultipartEncoder();
            }
        }
    }
 * ---------------------------------------------------------------------
 * @date: 17:24 2019/7/3
 **/
@RequestMapping(value = "/v1/api")
public interface NotificationMultipartService {

    /**
     * common email channel ,use to send common email
     *
     * @param data
     *     map key have: 
     *          attachfile       -->          MultipartFile[]
     *          com.longge.dto.EmailDto.FieldName --- >   value
     *          
     * eg:
     *  Map<String, Object> data = new HashMap<>();
        data.put("attachfile", new MultipartFile[] {file});
        data.put("from", emailDto.getFrom());
        data.put("to", emailDto.getTo());
        data.put("bodyText", emailDto.getBodyText());
        data.put("subject", emailDto.getSubject());
     * @return GlobalResponse<Long>  email id
     */
    @RequestMapping(value = "/send_mail", method = RequestMethod.POST, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE}, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    GlobalResponse<String> sendMail(Map<String, Object> data);
}

其中為了支持 form請求,需要對此feign進行單獨的配置:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;

import com.longge.api.NotificationMultipartService;

import feign.codec.Encoder;

@FeignClient(value = "notification-service", configuration = NotificationServiceFeign.FeignSimpleEncoderConfig.class)
public interface NotificationServiceFeign extends NotificationMultipartService {
    class FeignSimpleEncoderConfig {
        @Bean
        public Encoder encoder() {
            return new MyEncoder();
        }
    }
}

 

4、服務實現類

@RequestMapping(value = "/v1/api/send_mail", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = {MediaType.APPLICATION_JSON_VALUE})
public GlobalResponse<String> sendMail(@RequestParam(value = "attachfile", required = false) MultipartFile[] attachfile, EmailDto emailDto) {
    // TODO
}

 

5、EmailDto屬性

private String from;
private String to;
private String subject;
private String bodyText;
private String bodyHtml;

 

感謝:https://blog.csdn.net/ytzzh0726/article/details/79731343 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM