Feigin默認是不支持文件上傳和表單提交的,須要作一些配置才能支持。java
一、feign依賴web
圖中紅色爲form支持必須的jar。spring
二、添加自定義Encoder類:api
import static java.util.Collections.singletonMap; 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; /** * @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 (((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裏統一處理。app
三、feign接口類:ide
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: tomfang * @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進行單獨的配置:post
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(); } } }
四、服務實現類ui
@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 }
五、EmailDto屬性spa
private String from; private String to; private String subject; private String bodyText; private String bodyHtml;