转载请注明:http://blog.csdn.net/weijonathan/article/details/9328509
最近这段时间在研究HttpClient,想实现一个基于Http上传文件的功能。通过网上的很多文章,做了一个HttpClient上传文件的例子。
客户端:
public class HttpUploadFile {
public static void main(String[] args) throws UnsupportedEncodingException {
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(
CoreProtocolPNames.HTTP_CONTENT_CHARSET,
Charset.forName("UTF-8"));
HttpPost post = new HttpPost("http://localhost:8082/httpclient/upload");
String name = new String("D:\\中文.txt".getBytes("UTF-8"), "UTF-8");
File file = new File(name);
MultipartEntity multipartEntity = new MultipartEntity();
FileBody cbFileBody = new FileBody(file);
multipartEntity.addPart("file", cbFileBody);
post.setEntity(multipartEntity);
HttpResponse response = null;
String content = null;
try {
response = client.execute(post);
content = EntityUtils.toString(response.getEntity());
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(content);
client.getConnectionManager().shutdown();
}
}
服务器端:
@Controller
@RequestMapping("/httpclient")
public class HttpClientWeb {
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public void uploadFile(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String name = request.getParameter("name");
DefaultMultipartHttpServletRequest req = (DefaultMultipartHttpServletRequest) request;
request.setCharacterEncoding("UTF-8");
Map<String, MultipartFile> files = req.getFileMap();
for (String key : files.keySet()) {
System.out.println(key);
MultipartFile file = files.get(key);
System.out.println(file.getName());
System.out.println(file.getSize());
System.out.println(file.getOriginalFilename());
System.out.println(file.getBytes());
FileOutputStream fileOutput;
try {
fileOutput = new FileOutputStream("d://hdytest//"
+ file.getOriginalFilename());
fileOutput.write(file.getBytes());
fileOutput.flush();
fileOutput.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
然后开始测试了,测试Test.txt,a.map都通过了,而且MP3文件可以播放。很开心
但是问题来了,当我上传中文.txt这个文件的时候,刷,一片红的。
DEBUG 07-15_09:29:40 DispatcherServlet.java 999 Null ModelAndView returned to DispatcherServlet with name 'Spring MVC Dispatcher Servlet': assuming HandlerAdapter completed request handling
DEBUG 07-15_09:29:40 CommonsFileUploadSupport.java 282 Cleaning up multipart file [file] with original filename [中文.txt], stored in memory
DEBUG 07-15_09:29:40 FrameworkServlet.java 966 Successfully completed request
DEBUG 07-15_10:36:14 DispatcherServlet.java 823 DispatcherServlet with name 'Spring MVC Dispatcher Servlet' processing POST request for [/httpclient/upload]
DEBUG 07-15_10:36:14 CommonsFileUploadSupport.java 259 Found multipart file [file] of size 16 bytes with original filename [??.txt], stored in memory
DEBUG 07-15_10:36:14 AbstractHandlerMethodMapping.java 226 Looking up handler method for path /httpclient/upload
DEBUG 07-15_10:36:14 AbstractHandlerMethodMapping.java 233 Returning handler method [public void com.zqgame.m.controllers.HttpClientWeb.uploadFile(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]
java.io.FileNotFoundException: d:\hdytest\??.txt (文件名、目录名或卷标语法不正确。)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:179)
at java.io.FileOutputStream.<init>(FileOutputStream.java:70)
at com.zqgame.m.controllers.HttpClientWeb.uploadFile(HttpClientWeb.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)DEBUG 07-15_10:36:14 AbstractBeanFactory.java 246 Returning cached instance of singleton bean 'httpClientWeb'
file
file
16
??.txt
[B@2b1682
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:838)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1221)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1212)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:399)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)DEBUG 07-15_10:36:14 DispatcherServlet.java 999 Null ModelAndView returned to DispatcherServlet with name 'Spring MVC Dispatcher Servlet': assuming HandlerAdapter completed request handling
DEBUG 07-15_10:36:14 CommonsFileUploadSupport.java 282 Cleaning up multipart file [file] with original filename [??.txt], stored in memory
DEBUG 07-15_10:36:14 FrameworkServlet.java 966 Successfully completed request
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
这下蒙了,在网上找了好多资料,都说要修改源码,那好,修改源码开始
按照网上说的,修改EncodingUtils,把默认的"US-ASCII"修改为UTF-8,重新编译,测试,不通过。
修改为GBK,编译,测试,不通过;
修改为ISO-8859-1,编译,测试,不通过;
我的心都凉了,为什么别人有用的方法我都没用。
想了下,还是自己看源码吧!
就一步步跟源码下去,思路是这样的,因为file是存放在FileBody里面,而FileBody却是放在MultipartEntity里面,
我从这里开始下手的,结果查看到MultipartEntity的构造函数里面是这样的。这里有三个构造函数
public MultipartEntity(
HttpMultipartMode mode,
String boundary,
Charset charset) {
super();
if (boundary == null) {
boundary = generateBoundary();
}
if (mode == null) {
mode = HttpMultipartMode.STRICT;
}
this.multipart = new HttpMultipart("form-data", charset, boundary, mode);
this.contentType = new BasicHeader(
HTTP.CONTENT_TYPE,
generateContentType(boundary, charset));
this.dirty = true;
}
/**
* Creates an instance using the specified {@link HttpMultipartMode} mode.
* Boundary and charset are set to {@code null}.
* @param mode the desired mode
*/
public MultipartEntity(final HttpMultipartMode mode) {
this(mode, null, null);
}
/**
* Creates an instance using mode {@link HttpMultipartMode#STRICT}
*/
public MultipartEntity() {
this(HttpMultipartMode.STRICT, null, null);
}
看到第一个构造函数public MultipartEntity( HttpMultipartMode mode,String boundary,
Charset charset)
Charset charset 感觉有点眉目了!接下来看到MultipartEntity把charset传给HttpMultipart,然后跟了进去
public HttpMultipart(final String subType, final Charset charset, final String boundary, HttpMultipartMode mode) {
super();
if (subType == null) {
throw new IllegalArgumentException("Multipart subtype may not be null");
}
if (boundary == null) {
throw new IllegalArgumentException("Multipart boundary may not be null");
}
this.subType = subType;
this.charset = charset != null ? charset : <span style="color:#ff0000;"><strong>MIME.DEFAULT_CHARSET;</strong></span>
this.boundary = boundary;
this.parts = new ArrayList<FormBodyPart>();
this.mode = mode;
}
大家注意MIME.DEFAULT_CHARSET这里,我们来看下这个类
/**
*
* @since 4.0
*/
public final class MIME {
public static final String CONTENT_TYPE = "Content-Type";
public static final String CONTENT_TRANSFER_ENC = "Content-Transfer-Encoding";
public static final String CONTENT_DISPOSITION = "Content-Disposition";
public static final String ENC_8BIT = "8bit";
public static final String ENC_BINARY = "binary";
/** The default character set to be used, i.e. "US-ASCII" */
public static final Charset DEFAULT_CHARSET = Charset.forName("US-ASCII");
}
默认为US-ASCII。原来是这样的。
我们看下我们之前的调用方法
MultipartEntity multipartEntity = new MultipartEntity();是这样调用的。
我们可以看到上面的MultipartEntity()构造方法调用
public MultipartEntity() {
this(HttpMultipartMode.STRICT, null, null);
}
就是说默认的charset给的值就是null,而到里面程序就会给它赋一个默认值US-ASCII。
那么现在我们修改下代码。只需要修改一个地方
将
MultipartEntity multipartEntity = new MultipartEntity();
修改为
MultipartEntity multipartEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE, null,
Charset.forName("UTF-8"));
将之前修改编译EncodingUtils的jar包去掉重新下载放入。测试
DEBUG 07-15_10:50:14 DispatcherServlet.java 823 DispatcherServlet with name 'Spring MVC Dispatcher Servlet' processing POST request for [/httpclient/upload]
DEBUG 07-15_10:50:14 CommonsFileUploadSupport.java 259 Found multipart file [file] of size 16 bytes with original filename [中文.txt], stored in memory
DEBUG 07-15_10:50:14 AbstractHandlerMethodMapping.java 226 Looking up handler method for path /httpclient/upload
DEBUG 07-15_10:50:14 AbstractHandlerMethodMapping.java 233 Returning handler method [public void com.zqgame.m.controllers.HttpClientWeb.uploadFile(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException]
DEBUG 07-15_10:50:14 AbstractBeanFactory.java 246 Returning cached instance of singleton bean 'httpClientWeb'
file
file
16
<strong><span style="color:#ff0000;">中文.txt</span></strong>
[B@cd2192
DEBUG 07-15_10:50:14 DispatcherServlet.java 999 Null ModelAndView returned to DispatcherServlet with name 'Spring MVC Dispatcher Servlet': assuming HandlerAdapter completed request handling
DEBUG 07-15_10:50:14 CommonsFileUploadSupport.java 282 Cleaning up multipart file [file] with original filename [中文.txt], stored in memory
DEBUG 07-15_10:50:14 FrameworkServlet.java 966 Successfully completed request