码迷,mamicode.com
首页 > 移动开发 > 详细

android-----基于XUtils照片上传客户端以及服务器端实现

时间:2016-06-12 02:39:39      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:

        想必大家都在android中或多或少的使用过XUtils框架了吧,今天我们通过他来实现一个照片上传的Demo,希望能够对大家有帮助,下一篇再从源码角度来分析下XUtils的HttpUtils是怎么一个执行流程的;

        先上执行效果图:

 技术分享技术分享技术分享技术分享

        客户端实现:

        首先来看布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <LinearLayout
        android:id="@+id/top"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    <Button
        android:id="@+id/upload_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="上传图片" />
     
        </LinearLayout>
    <ImageView
        android:id="@+id/imageView"
        android:layout_below="@id/top"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    
</RelativeLayout>
        很简单吧,就是一个按钮和一个用于显示图片的ImageView;

        接下来是MainActivity,直接看onCreate方法:

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		httpUtils = new HttpUtils(100000);
		httpUtils.configCurrentHttpCacheExpiry(5000);
	}
        这个方法首先会调用initView来初始化界面,接着创建了一个HttpUtils对象,并且设置他的连接超时时间是100s,设置他的缓存有效时间是5s,来看看initView方法:

/**
	 * 初始化view控件
	 */
	public void initView()
	{
		uploadImageBt = (Button) findViewById(R.id.upload_image);
		imageView = (ImageView)findViewById(R.id.imageView);
		uploadImageBt.setOnClickListener(this);
		progressDialog = getProgressDialog();//获得进度条
		dialogListener = new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				case 0:
					tempFile = new File(Environment.getExternalStorageDirectory(),getPhotoFileName());
					//调用系统拍照
					startCamera(dialog);
					break;
				case 1:
					//打开系统图库
					startWall(dialog);
					break;
				default:
					break;
				}
			}
		};
		mHandler = new Handler(){
			@Override
			public void handleMessage(Message msg) {
				if(msg.arg1 > 0)
					progressDialog.setProgress(msg.arg1);//更新进度条
			}
		};
	}

        首先第9行获得一个ProgressDialog对象,第10行为选择对话框绑定点击监听事件,用来提示用户是通过拍照获得照片还是从图库获得,这个对象的定义如下:

/**
	 * 显示选择图片来源的dialog(来自拍照还是本地图库)
	 * @param title
	 * @param items
	 */
	public void showDialog(String title,String[] items)
	{
		AlertDialog.Builder dialog = new AlertDialog.Builder(this).setTitle(title).setItems(items, dialogListener);
		//显示dialog
		dialog.show();
	}
        如果选择拍照,则通过startCamera方法来调用系统照相机:

/**
	 * 调用相机来照相
	 * @param dialog
	 */
	public void startCamera(DialogInterface dialog)
	{
		dialog.dismiss();//首先隐藏选择照片来源的dialog
		//调用系统的拍照功能
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		intent.putExtra("camerasensortype", 2);//调用前置摄像头
		intent.putExtra("autofocus", true);//进行自动对焦操作
		intent.putExtra("fullScreen", false);//设置全屏
		intent.putExtra("showActionIcons", false);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile));//指定调用相机之后所拍照存储到的位置
		startActivityForResult(intent, PHOTO_CAMERA);
	}
        该方法首先会将选择对话框隐藏,接着开启系统摄像头并且进行相应的设置,并且指定保存照片的位置,最后在返回上一个Activity之前将照片结果封装在intent中返回,并且设置返回标志是PHOTO_CAMERA;

        如果选择的是相册的话,则通过调用startWall方法来获得SD上面照片:

/**
	 * 打开系统图库
	 * @param dialog
	 */
	public void startWall(DialogInterface dialog)
	{
		dialog.dismiss();//设置隐藏dialog
		Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
		intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
		startActivityForResult(intent, PHOTO_WALL);
	}
        该方法同样首先将选择对话框隐藏,接着调用系统服务显示出SD卡中所有存在的图片,并且通过intent返回图片信息,同时设置返回标志为PHOTO_WALL;

        接下来我们看看不同的返回标志各自所执行的到底是什么内容呢?

@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		switch (requestCode) {
		case PHOTO_CAMERA:
			//表示从相机获得的照片,需要进行裁剪
			startPhotoCut(Uri.fromFile(tempFile), 300,true);
			break;
		case PHOTO_WALL:
			if(null != data)
				startPhotoCut(data.getData(),300,false);
			break;
		case PHOTO_STORE:
			if(null != data)
			{
				setPictureToImageView(data,true);
			}
			break;
		case PHOTO_NOT_STORE:
			if(null != data)
			{
				setPictureToImageView(data,false);
			}
			break;
		default:
			break;
		}
	}
        该方法是在调用startActivityForResult之后由系统调用的,看到了我们刚刚见到的PHOTO_CAMREA以及PHOTO_WALL标志,首选来看看PHOTO_CAMREA,他会调用startPhotoCut对照片进行裁剪,来看看startPhotoCut方法:

/**
	 * 将图片裁剪到指定大小
	 * @param uri
	 * @param size
	 * @param flag
	 */
	public void startPhotoCut(Uri uri,int size,boolean flag)
	{
		Intent intent = new Intent("com.android.camera.action.CROP");
		intent.setDataAndType(uri, "image/*");
		intent.putExtra("crop", true);//设置Intent中的view是可以裁剪的
		//设置宽高比
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		//设置裁剪图片的宽高
		intent.putExtra("outputX", size);
		intent.putExtra("outputY", size);
		//设置是否返回数据
		intent.putExtra("return-data", true);
		if(flag == true)
			startActivityForResult(intent, PHOTO_STORE);
		else
		{
			tempIntent = intent;
			try {
				startActivityForResult(tempIntent, PHOTO_NOT_STORE);
				System.out.println("haha");
			} catch (Exception e) {
				System.out.println(e.toString());
			}
		}
	}
        这个方法前面的几行都是对照片进行裁剪的一些设置,接着通过flag标志来判断是否将照片存储到SD卡上面,因为如果flag为false的话,表示这张照片是我们通过图库获取的,他来自于SD卡,因此没什么必要再存一次了,因而返回标志PHOTO_NOT_STORE,如果flag为true的话,才需要存储一遍,返回标志PHOTO_STORE,同样的调用的是startActivityForResult方法,那么他也会执行onActivityResult方法;

        那么对于PHOTO_WALL标志,如果选择的图片不为空的话,则执行startPhotoCut方法,同样也进行裁剪;

        对于PHOTO_NOT_STORE和PHOTO_STORE标志,他们都会执行setPictureToImageView方法,所以我们直接看他的代码就可以了:

/**
	 * 将图片显示到ImageView上面
	 * @param data
	 * @param flag 表示如果是拍照获得的照片的话则是true,如果是从系统选择的照片的话就是false
	 */
	public void setPictureToImageView(Intent data,boolean flag)
	{
		Bundle bundle = data.getExtras();
		if(null != bundle)
		{
			Bitmap bitmap = bundle.getParcelable("data");
			imageView.setImageBitmap(bitmap);//将图片显示到ImageView上面
			//上传图片到服务器
			if(flag == false)
			{
				//需要首先修改tempFile的值
				String path = getSelectPhotoPath(tempIntent);
				System.out.println("path:  "+path);
				tempFile = new File(path);
				//uploadPicture();
				//上传图片
				UploadThread thread = new UploadThread();
				thread.start();
			}else
			{
				//uploadPicture();
				//上传图片
				UploadThread thread = new UploadThread();
				thread.start();
			}
			if(flag == true)
				savePictureToSD(bitmap);//保存图片到sd卡上面
		}
	}
        这个方法做的事比较多,首先呢,他会从intent中获取到获取到图片并且显示到ImageView上面,接着会调用UploadThread线程将图片上传到服务器上面,最如果flag为true的话表示需要将图片存储到本地,那么我们需要调用savePictureToSD来存储图片,先来看看UploadThread线程:

class UploadThread extends Thread
	{
		@Override
		public void run() {
			uploadPicture();
		}
	}
        很简单,就只有一个uploadPicture方法了,自然我们需要查看uploadPicture的代码:

/**
	 * 上传图片到数据库
	 */
	public void uploadPicture()
	{
		RequestParams params = new RequestParams();
		params.addBodyParameter("msg",tempFile.getAbsolutePath());
		params.addBodyParameter(tempFile.getPath().replace("/", ""), tempFile);
		httpUtils.send(HttpMethod.POST, url,params,new RequestCallBack<String>() {
			
			@Override
			public void onStart() {
				progressDialog.show();//显示进度条
			}
			@Override
			public void onFailure(HttpException arg0, String arg1) {
				System.out.println("上传失败");
				System.out.println(arg0.toString());
				//上传失败之后隐藏进度条
				progressDialog.dismiss();
			}
			@Override
			public void onLoading(long total, long current, boolean isUploading) {
				System.out.println("current/total:  "+current+"/"+total);
				int process = 0;
				if(total != 0)
				{
					process = (int)(current/(total/100));
				}
				Message message = new Message();
				message.arg1 = process;
				mHandler.sendMessage(message);
				super.onLoading(total, current, isUploading); 
			}
			@Override
			public void onSuccess(ResponseInfo<String> arg0) {
				System.out.println("上传成功");
				//上传成功之后隐藏进度条
				progressDialog.dismiss();
			}
		});
	}
        这部分就是用到XUtils的HttpUtils的部分啦,首先设置一些请求参数,接着调用HttpUtils的send方法进行请求,为了能够对上传结果更加直观,我们添加了进度条,onStart方法是上传执行开始调用的方法,我们在此显示出进度条,onLoading是上传过程中执行的方法,大约每一秒钟会执行一次,我们在此通过Handler的消息机制将进度封装成Message对象将其发送给Handler处理,具体的更新进度条的代码是在我们上面的initView方法出现的,因为他只能在主线程中更新,最后在电泳失败或者成功之后都要调用ProgressDialog的dismiss方法来隐藏进度条;

        最后就只剩下保存图片到SD卡的操作了,这个比较简单,就只是简单的文件存储操作了,只不过路径是SD卡而已:

/**
	 * 将图片保存到SD卡上面
	 * @param bitmap
	 */
	public void savePictureToSD(Bitmap bitmap)
	{
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		FileOutputStream fos = null;
		bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//第2个参数表示压缩率,100表示不压缩
		try {
			fos = new FileOutputStream(tempFile);
			fos.write(baos.toByteArray());
			fos.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(null != baos)
				{
				    baos.close();
				    baos = null;
				}
				if(null != fos)
				{
					fos.close();
					fos = null;
				}
			} catch (Exception e2) {
				
			}
		}
	}
        至此,客户端代码讲解完毕,接下来是服务器端代码:

        服务器端:

        代码比较少,直接copy出来了:

public class UploadServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		response.setContentType("text/html,charset=utf-8");
		SmartUpload smartUpload = new SmartUpload();
		String msg= null;
        try {  
            smartUpload.initialize(this.getServletConfig(), request, response); 
            smartUpload.upload();  
            msg = smartUpload.getRequest().getParameter("msg");
            System.out.println(smartUpload.getFiles().getCount());
            com.jspsmart.upload.File smartFile = smartUpload.getFiles().getFile(0);  
            if (!smartFile.isMissing()) {  
                String saveFileName = getServletContext().getRealPath("/")+"images\\" + smartFile.getFileName();  
                System.out.println(saveFileName);
                smartFile.saveAs(saveFileName, SmartUpload.SAVE_PHYSICAL);  
            }
        } catch (Exception e) {  
        	e.printStackTrace();
        } 
	}
}

        最主要是doPost方法了,本实例采用的是SmartUpload的方式来实现文件上传操作的,当然你也可以采用别的方法,至于jar包等会源码下载链接的工程里面就有啦,第18行首先对SmartUpload进行初始化,接着调用upload方法准备上传,第22行获得客户端上传文件的第一个文件,从这里我们也可以看出来SmartUpload是支持多文件上传的,接着第23行判断这个文件是否存在,24行生成存放文件的路径,26行进行文件的存储操作,注意SmartUpload.SAVE_PHYSICAL的意思指的是绝对路径,因此你的文件存储路径必须是全路径,这样服务器端代码讲解结束,是不是很简单呀,提醒一下web.xml的配置,我的配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
	<servlet>
		<servlet-name>UploadServlet</servlet-name>
        <servlet-class>com.hzw.servlet.UploadServlet</servlet-class>
	</servlet>
	<servlet-mapping>
    	<servlet-name>UploadServlet</servlet-name>
        <url-pattern>/upload</url-pattern>
    </servlet-mapping>
</web-app>
        基本上讲解结束啦,记得在客户端里面别忘记添加网络访问和SD卡访问权限哈:

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
点击这里下载源码!!!!!
















android-----基于XUtils照片上传客户端以及服务器端实现

标签:

原文地址:http://blog.csdn.net/hzw19920329/article/details/51610683

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!