除了文件下载外,文件上传也是项目开发中经常用到的功能。此时需要用HttpClient类库的扩展包HttpMime中的MultipartEntity类,此类同样实现了HttpEntity接口。需要注意的是HttpClient通过POST来上传文件,而不是通过流的形式。
示例:使用HttpClient实现文件上传功能。
第一步:要求在服务器端使用fileupload组件接收客户端提交内容。新建一个JSP项目zghc,首先在WEB-INF/lib目录下加入commons-fileupload-1.2.2.jar和commons-io-2.4.jar两个jar包,然后再提供一个对用户提交数据(文本、文件)进行处理的Servlet,具体代码如下所示:
@WebServlet("/uploadServlet") public class UploadServlet extends HttpServlet { // 使用fileupload组件 private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 检测是不是文件上传的请求 boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) {// 属于上传文件的请求 // 创建磁盘工厂,该类用来配置上传组件ServletFileUpload DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(10 * 1024 * 1024); factory.setRepository(new File("D:/")); // 设置存放临时文件的目录 // 使用磁盘工厂实例化上传组件 ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(10 * 1024 * 1024); // 设置允许的最大上传尺寸 upload.setHeaderEncoding("UTF-8");// 明确指定使用UTF-8编码 PrintWriter out = response.getWriter(); try { // 获取客户端提交过来的所有请求参数 List<FileItem> items = upload.parseRequest(request); // 解析 for (FileItem item : items) {//对用户上传的所有文件进行遍历 if (item.isFormField()) {// 如果是表单字段 System.out.println(item.getFieldName()+" "+ item.getString("UTF-8")); } else {// 如果是文件 String path = request.getSession().getServletContext() .getRealPath("/");// 站点根目录的路径 String name = item.getName().substring( item.getName().lastIndexOf("/") + 1); // ---② // 保存用户上传的文件到指定目录 item.write(new File(path, name)); System.out.println("上传完毕"); response.setCharacterEncoding("UTF-8"); out.println("上传完毕"); } } } catch (Exception e) { e.printStackTrace(); out.println("文件超过规定大小"); } } } }
FileItemFactory类的setSizeThreshold()方法用来设置上传文件时用于临时存放文件的内存的大小,超出的部分将临时存放在硬盘,可以使用FileItemFactory类的 setRepository()方法设置临时文件的目录。
在调用item.write()方法写入数据到文件中时,如果文件的名称是中文,有可能会出现乱码;另外需要注意的是Windows系统中item.getName()方法的返回的值是带路径的。
提示:
如果使用tomcat6,采用传统的在web.xml方式中配置Servlet,编号②处的代码需要改为:item.getName().lastIndexOf("\")
第二步:提供一个JSP文件upload.jsp,对上面的Servlet进行测试。注意在此JSP文件中需要设置form表单的enctype的值为multipart/form-data。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <form action="uploadServlet" method="post" enctype="multipart/form-data"> 标题:<input type="text" name="name"/> 文件:<input type="file" name="imgFile"/> <input type="submit" value="提交"/> </form> </body> </html>
为了能上传文件,必须将表单的method属性设置为POST、enctype属性设置为multipart/form-data,只有这样,浏览器才会把用户选择文件的二进制数据发送给服务器。
第四步:将上面的JSP项目部署到tomcat中,然后在打开的upload.jsp页面中输入文件名,选中要上传的文件,单击【提交】按钮,然后在tomcat下的webapps\zghc目录下确实发现上传的文件,表明文件上传成功。
第五步:新建一个Android项目,将httpmime_XXXX.jar文件添加到当前项目的classpath路径下面,然后在项目中添加一个实现上传功能的工具类,具体代码如下所示:
public class HttpClientUtil { public static HttpClient httpClient = new DefaultHttpClient(); public static String sendPost(String url,HashMap<String,String> map,File file){ String result = null; HttpPost post = new HttpPost(url);// 创建HttpPost对象 // 如果传递参数个数比较多的话可以对传递的参数进行封装 MultipartEntity entity = new MultipartEntity(); try { for (String key : map.keySet()) { // 封装请求参数 StringBody value = new StringBody(map .get(key), Charset.forName("UTF-8"));//避免传递汉字出现乱码 entity.addPart(new FormBodyPart(key,value)); } if(file != null) entity.addPart("myfile", new FileBody(file)); post.setEntity(entity);// 设置请求参数 synchronized (httpClient) { HttpResponse response = httpClient.execute(post);// 发送POST请求 if (response.getStatusLine().getStatusCode() == 200){ HttpEntity resEntity = response.getEntity(); result = EntityUtils.toString(resEntity, "UTF-8"); } } } catch (IOException e) { e.printStackTrace(); } return result; } }
第六步:为了提高用户体验,我们提供一个线程类来实现文件文件上传的功能,具体代码如下所示:
public class UploadThread extends Thread { private String url; private HashMap<String, String> map; private File file; private Handler handler; public UploadThread(String url, HashMap<String, String> map, File file, Handler handler) { this.url = url; this.map = map; this.file = file; this.handler = handler; } @Override public void run() { String result = HttpClientUtil.sendPost(url, map, file); //具体上传代码 System.out.println("aaaaa" + result); if ("上传完毕".equals(result.trim())) { handler.sendEmptyMessage(1); } else { handler.sendEmptyMessage(0); } } }
第七步:在主布局文件中提供一个onClick属性值为upload的Button,然后修改MainAcvitity类的代码如下所示:
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } private Handler handler = new Handler() { public void handleMessage(Message msg) { if (msg.what == 1) { Toast.makeText(MainActivity.this, "提交数据成功", 1).show(); } else { Toast.makeText(MainActivity.this, "提交数据失败", 1).show(); } } }; public void upload(View view) { HashMap<String, String> map = new HashMap<String, String>(); map.put("username", "music"); File sdPath = Environment.getExternalStorageDirectory(); File file = new File(sdPath + "/zbjbxf.mp3"); String url = "http://10.0.2.2:8080/zghc/uploadServlet"; UploadThread thread = new UploadThread(url, map, file, handler); thread.start(); } }
在保证第一步创建的JSP项目已经部署到tomcat中且tomcat已经启动的前提下,运行本程序,发现当点击客户端主界面中的Button按钮后,在tomcat下的webapps/zghc目录下确实看到了刚才上传的文件。
大家可以将前面章节中学到Android中制作文件管理器的知识和本示例程序结合起来,实现一个能够通过图形化方式选择文件的文件上传软件。