SpringCloud+Feign环境下文件上传与form-data同时存在的解决办法
本文内容纲要:
最近项目转型使用SpringCloud框架下的微服务架构,各微服务之间使用Feign进行调用。期间,发现若被调用方法涉及到文件上传且仅存在单个文件时,一切正常,代码片段如下:
1@RequestMapping(value="/if/****/add",method=RequestMethod.POST,consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
2JSONObjectadd(@RequestPart(value="file")MultipartFilefile);
但若同时需要传递其他form-data数据时,则一直报错。
1@RequestMapping(value="/if/****",method=RequestMethod.POST,consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
2Objectadd(@RequestParam(name="objectCode")StringobjectCode,@RequestPart(name="file")MultipartFilefile);
报错信息为:
1org.springframework.web.multipart.support.MissingServletRequestPartException:Requiredrequestpart'file'isnotpresent
2atorg.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)
3atorg.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)
4atorg.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
5atorg.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
6atorg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
7atorg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
8atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
9atorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
10atorg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
11atorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
12atorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
13atorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
14atorg.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
15atjavax.servlet.http.HttpServlet.service(HttpServlet.java:661)
16atorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
17atjavax.servlet.http.HttpServlet.service(HttpServlet.java:742)
18atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
19atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
20atorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
21atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
22atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
23atorg.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
24atorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
25atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
26atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
此时,feign日志为:
12018-12-2203:42:37.591DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]--->POSThttp://assembly-uiif/if/test1/public/t1?objectCode=test%3ASat+Dec+22+03%3A42%3A31+CST+2018HTTP/1.1
22018-12-2203:42:37.593DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]Content-Type:multipart/form-data;charset=UTF-8;boundary=167d24a8200
32018-12-2203:42:37.594DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]Content-Length:161
42018-12-2203:42:37.595DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]
52018-12-2203:42:37.596DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]Binarydata
62018-12-2203:42:37.599DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]--->ENDHTTP(161-bytebody)
72018-12-2203:42:37.618INFO66057---[io-31023-exec-2]s.c.a.AnnotationConfigApplicationContext:Refreshingorg.springframework.context.annotation.AnnotationConfigApplicationContext@65669249:startupdate[SatDec2203:42:37CST2018];parent:org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@47df5041
82018-12-2203:42:37.777INFO66057---[io-31023-exec-2]f.a.AutowiredAnnotationBeanPostProcessor:JSR-330'javax.inject.Inject'annotationfoundandsupportedforautowiring
92018-12-2203:42:38.615INFO66057---[io-31023-exec-2]c.netflix.config.ChainedDynamicProperty:Flippingproperty:assembly-uiif.ribbon.ActiveConnectionsLimittouseNEXTproperty:niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit=2147483647
102018-12-2203:42:38.677INFO66057---[io-31023-exec-2]c.n.u.concurrent.ShutdownEnabledTimer:Shutdownhookinstalledfor:NFLoadBalancer-PingTimer-assembly-uiif
112018-12-2203:42:38.786INFO66057---[io-31023-exec-2]c.netflix.loadbalancer.BaseLoadBalancer:Client:assembly-uiifinstantiatedaLoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=assembly-uiif,currentlistofServers=[],Loadbalancerstats=Zonestats:{},Serverstats:[]}ServerList:null
122018-12-2203:42:38.796INFO66057---[io-31023-exec-2]c.n.l.DynamicServerListLoadBalancer:UsingserverListUpdaterPollingServerListUpdater
132018-12-2203:42:38.860INFO66057---[io-31023-exec-2]c.netflix.config.ChainedDynamicProperty:Flippingproperty:assembly-uiif.ribbon.ActiveConnectionsLimittouseNEXTproperty:niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit=2147483647
142018-12-2203:42:38.863INFO66057---[io-31023-exec-2]c.n.l.DynamicServerListLoadBalancer:DynamicServerListLoadBalancerforclientassembly-epsic-uiifinitialized:DynamicServerListLoadBalancer:{NFLoadBalancer:name=assembly-uiif,currentlistofServers=[192.168.43.31:20008],Loadbalancerstats=Zonestats:{defaultzone=[Zone:defaultzone;Instancecount:1;Activeconnectionscount:0;Circuitbreakertrippedcount:0;Activeconnectionsperserver:0.0;]
15},Serverstats:[[Server:192.168.43.31:20008;Zone:defaultZone;TotalRequests:0;Successiveconnectionfailure:0;Totalblackoutseconds:0;Lastconnectionmade:ThuJan0108:00:00CST1970;Firstconnectionmade:ThuJan0108:00:00CST1970;ActiveConnections:0;totalfailurecountinlast(1000)msecs:0;averageresptime:0.0;90percentileresptime:0.0;95percentileresptime:0.0;minresptime:0.0;maxresptime:0.0;stddevresptime:0.0]
16]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@114d8fc3
172018-12-2203:42:39.606DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]<---HTTP/1.1200(2006ms)
182018-12-2203:42:39.607DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]cache-control:no-cache,no-store,max-age=0,must-revalidate
192018-12-2203:42:39.608DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]content-type:application/json;charset=UTF-8
202018-12-2203:42:39.608DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]date:Fri,21Dec201819:42:39GMT
212018-12-2203:42:39.609DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]expires:0
222018-12-2203:42:39.610DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]pragma:no-cache
232018-12-2203:42:39.610DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]transfer-encoding:chunked
242018-12-2203:42:39.610DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]x-application-context:assembly-uiif:develop:20008
252018-12-2203:42:39.610DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]x-content-type-options:nosniff
262018-12-2203:42:39.613DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]x-frame-options:SAMEORIGIN
272018-12-2203:42:39.613DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]x-xss-protection:1;mode=block
282018-12-2203:42:39.613DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]
292018-12-2203:42:39.615DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]{"head":{"orgId":0,"orgCode":"","vers":null,"reqId":null,"errorCode":1,"errorCodeI18n":"i18n.errorCode.1","errorMessage":"Requiredrequestpart'file'isnotpresent","errorStack":"org.springframework.web.multipart.support.MissingServletRequestPartException:Requiredrequestpart'file'isnotpresent\n\tatorg.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:193)\n\tatorg.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)\n\tatorg.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tatorg.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)\n\tatorg.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)\n\tatorg.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)\n\tatorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)\n\tatorg.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)\n\tatorg.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)\n\tatorg.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)\n\tatorg.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)\n\tatorg.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)\n\tatorg.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)\n\tatjavax.servlet.http.HttpServlet.service(HttpServlet.java:661)\n\tatorg.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\n\tatjavax.servlet.http.HttpServlet.service(HttpServlet.java:742)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatcom.egoonet.devtools.springstarter.iam.sso.config.web.MyFilterSecurityInterceptor.invoke(MyFilterSecurityInterceptor.java:61)\n\tatcom.egoonet.devtools.springstarter.iam.sso.config.web.MyFilterSecurityInterceptor.doFilter(MyFilterSecurityInterceptor.java:31)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:317)\n\tatorg.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)\n\tatorg.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatcom.***.web.MyFilterSecurityInterceptor.invoke(MyFilterSecurityInterceptor.java:61)\n\tatcom.***.web.MyFilterSecurityInterceptor.doFilter(MyFilterSecurityInterceptor.java:31)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:150)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:331)\n\tatorg.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:214)\n\tatorg.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:177)\n\tatorg.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:347)\n\tatorg.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:263)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)\n\tatorg.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\n\tatorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tatorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tatorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)\n\tatorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\n\tatorg.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)\n\tatorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)\n\tatorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)\n\tatorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)\n\tatorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)\n\tatorg.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)\n\tatorg.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\n\tatorg.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\n\tatorg.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)\n\tatorg.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tatjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tatjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tatorg.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tatjava.lang.Thread.run(Thread.java:748)\n","userId":0,"appId":108},"info":{"now":"SatDec2203:42:39CST2018"}}
302018-12-2203:42:39.615DEBUG66057---[io-31023-exec-2]c.e.l.c.m.t.f.TestFileFeignController:[TestFileFeignController#t1]<---ENDHTTP(12082-bytebody)
很显然,feign发送的报文不对,正常的报文应该是:
1POST/if/test1/public/t1HTTP/1.1
2Host:localhost:20008
3cache-control:no-cache
4Postman-Token:1c879cba-fdf3-4b9a-b1ef-e3d5af7be37e
5Content-Type:multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
6
7Content-Disposition:form-data;name="objectCode"
8
9abcd
10
11Content-Disposition:form-data;name="file";filename="/Users/***/Downloads/03.jpg
12
13
14------WebKitFormBoundary7MA4YWxkTrZu0gW--
ok,到此可知,问题出在feign发送报文时发送错误。
查阅feign源码,参考网络资料,实现一个自定义注解:
1/**
2*Feign代理方法上,与RequestPart一起组成多参数模式的注解
3*/
4@Target(ElementType.PARAMETER)
5@Retention(RetentionPolicy.RUNTIME)
6@Documented
7public@interfaceRequestPartParam{
8
9Stringname()default"";
10
11booleanrequired()defaulttrue;
12
13}
实现自定义注解处理器:
1importfeign.MethodMetadata;
2importorg.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
3
4importjava.lang.annotation.Annotation;
5importjava.lang.reflect.Method;
6importjava.util.Map;
7
8importstaticfeign.Util.checkState;
9importstaticfeign.Util.emptyToNull;
10
11/**
12*
13*/
14publicclassRequestPartParamParameterProcessorimplementsAnnotatedParameterProcessor{
15
16privatestaticfinalClass<RequestPartParam>ANNOTATION=RequestPartParam.class;
17
18@Override
19publicClass<?extendsAnnotation>getAnnotationType(){
20returnANNOTATION;
21}
22
23@Override
24publicbooleanprocessArgument(AnnotatedParameterContextcontext,Annotationannotation,Methodmethod){
25intparameterIndex=context.getParameterIndex();
26Class<?>parameterType=method.getParameterTypes()[parameterIndex];
27MethodMetadatadata=context.getMethodMetadata();
28
29if(Map.class.isAssignableFrom(parameterType)){
30checkState(data.queryMapIndex()==null,"Querymapcanonlybepresentonce.");
31data.queryMapIndex(parameterIndex);
32
33returntrue;
34}
35
36RequestPartParamrequestPartParam=ANNOTATION.cast(annotation);
37Stringname=requestPartParam.name();
38checkState(emptyToNull(name)!=null,
39"RequestPartParam.name()wasemptyonparameter%s",
40parameterIndex);
41context.setParameterName(name);
42
43data.formParams().add(name);
44
45returntrue;
46}
47
48}
实现自定义的编码器:
1importfeign.RequestTemplate;
2importfeign.codec.EncodeException;
3importfeign.codec.Encoder;
4importfeign.form.FormEncoder;
5importfeign.form.MultipartFormContentProcessor;
6importfeign.form.spring.SpringManyMultipartFilesWriter;
7importfeign.form.spring.SpringSingleMultipartFileWriter;
8importlombok.val;
9importorg.springframework.web.multipart.MultipartFile;
10
11importjava.lang.reflect.ParameterizedType;
12importjava.lang.reflect.Type;
13importjava.util.HashSet;
14importjava.util.Map;
15importjava.util.Set;
16
17importstaticfeign.form.ContentType.MULTIPART;
18importstaticjava.util.Collections.singletonMap;
19
20/**
21*
22*/
23publicclassFeignSpringFormEncoderextendsFormEncoder{
24
25publicFeignSpringFormEncoder(){
26this(newEncoder.Default());
27}
28
29publicFeignSpringFormEncoder(Encoderdelegate){
30super(delegate);
31
32valprocessor=(MultipartFormContentProcessor)getContentProcessor(MULTIPART);
33processor.addWriter(newSpringSingleMultipartFileWriter());
34processor.addWriter(newSpringManyMultipartFilesWriter());
35}
36
37@Override
38publicvoidencode(Objectobject,TypebodyType,RequestTemplatetemplate)throwsEncodeException{
39if((bodyTypeinstanceofParameterizedType)&&((ParameterizedType)bodyType).getRawType().equals(Map.class)){
40valdata=(Map<String,Object>)object;
41Set<String>nullSet=newHashSet<>();
42for(Map.Entry<String,Object>entry:data.entrySet()){
43if(entry.getValue()==null){
44nullSet.add(entry.getKey());
45}
46}
47for(Strings:nullSet){
48data.remove(s);
49}
50super.encode(data,MAP_STRING_WILDCARD,template);
51return;
52}elseif(bodyType.equals(MultipartFile.class)){
53valfile=(MultipartFile)object;
54valdata=singletonMap(file.getName(),object);
55super.encode(data,MAP_STRING_WILDCARD,template);
56return;
57}elseif(bodyType.equals(MultipartFile[].class)){
58valfile=(MultipartFile[])object;
59if(file!=null){
60valdata=singletonMap(file.length==0?"":file[0].getName(),object);
61super.encode(data,MAP_STRING_WILDCARD,template);
62return;
63}
64}
65super.encode(object,bodyType,template);
66}
67
68}
定义bean:
1@Bean
2publicRequestPartParamParameterProcessorrequestPartParamParameterProcessor(){
3returnnewRequestPartParamParameterProcessor();
4}
5
6@Bean
7publicPathVariableParameterProcessorpathVariableParameterProcessor(){
8returnnewPathVariableParameterProcessor();
9}
10
11@Bean
12publicRequestParamParameterProcessorrequestParamParameterProcessor(){
13returnnewRequestParamParameterProcessor();
14}
15
16@Bean
17publicRequestHeaderParameterProcessorrequestHeaderParameterProcessor(){
18returnnewRequestHeaderParameterProcessor();
19}
注意,参阅org.springframework.cloud.netflix.feign.support.SpringMvcContract中的代码可知,使用自定义注解处理器时,必须自行处理另外3个系统默认注解处理器。
至此,重新编译,运行,工作正常。问题解决。
本文内容总结:
原文链接:https://www.cnblogs.com/oilamp/p/10159741.html