您的位置:首页 > 移动开发 > Android开发

Android仿QQ空间发说说实现上传图片到服务器(带缩略图的)

2016-11-25 13:36 633 查看
之前做别的项目的时候游泳到过,好久不用都生疏了。今天朋友问我这个问题我仔细看了一下,发现问题并改正了。下面是实现这个功能的全部代码(PS:界面很丑不用管,好看的我没传,大家自己写一下就好)

服务端:

需要两个jar包:(这两个是必须的)

commons-fileupload-1.2.jar

commons-io-2.0.1.jar

代码:

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;">import java.io.BufferedInputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.PrintWriter;

import java.util.List;

import javax.servlet.Servlet;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.FileItemFactory;

import org.apache.commons.fileupload.FileUploadException;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**

* 文件上传的Serlvet类

*

*/

public class FileImageUpload extends HttpServlet {

private static final long serialVersionUID = 1L;

private ServletFileUpload upload;

private final long MAXSize = 4194304*2L;//4*2MB

private String filedir;

/**

* @see HttpServlet#HttpServlet()

*/

public FileImageUpload() {

super();

// TODO Auto-generated constructor stub

}

/**

* 设置文件上传的初始化信息

* @see Servlet#init(ServletConfig)

*/

public void init(ServletConfig config) throws ServletException {

// Create a factory for disk-based file items

FileItemFactory factory = new DiskFileItemFactory();

// Create a new file upload handler

this.upload = new ServletFileUpload(factory);

// Set overall request size constraint 4194304

this.upload.setSizeMax(this.MAXSize);

// File file = new File(pathname);

filedir=config.getServletContext().getRealPath("images");

File file = new File(filedir);

if (!file.exists()) {

//创建临时目录

file.mkdir();

}

}

// @SuppressWarnings("unchecked")

@Override

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

// TODO Auto-generated method stub

PrintWriter out=response.getWriter();

try {

List<FileItem> items = this.upload.parseRequest(request);

if(items!=null && !items.isEmpty()){

for (FileItem fileItem : items) {

System.out.println(fileItem);

String filename=fileItem.getName();

String filepath=filedir+File.separator+filename;

System.out.println("文件保存路径为:"+filepath);

File file=new File(filepath);

InputStream inputSteam=fileItem.getInputStream();

BufferedInputStream fis=new BufferedInputStream(inputSteam);

FileOutputStream fos=new FileOutputStream(file);

int f;

while((f=fis.read())!=-1)

{

fos.write(f);

}

fos.flush();

fos.close();

fis.close();

inputSteam.close();

System.out.println("文件:"+filename+"上传成功!");

}

}

System.out.println("上传文件成功!");

out.write("上传文件成功!");

} catch (FileUploadException e) {

e.printStackTrace();

out.write("上传文件失败:"+e.getMessage());

}

}

}</span>

客户端:

布局代码:

activity_main.xml

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

tools:context="com.example.girdviewtest.MainActivity" >

<!-- 显示图片 -->

<!-- 网格显示图片 行列间距5dp 每列宽度90dp -->

<GridView

android:id="@+id/gridView1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="5dp"

android:layout_weight="111"

android:background="#EFDFDF"

android:columnWidth="90dp"

android:gravity="center"

android:horizontalSpacing="5dp"

android:numColumns="4"

android:stretchMode="columnWidth"

android:verticalSpacing="5dp" >

</GridView>

<!-- 底部按钮 -->

<LinearLayout

android:id="@+id/Layout_bottom"

android:layout_width="match_parent"

android:layout_height="50dp"

android:layout_alignParentBottom="true"

android:layout_weight="1"

android:orientation="horizontal" >

<Button

android:id="@+id/button1"

android:layout_width="wrap_content"

android:layout_height="fill_parent"

android:layout_weight="1"

android:onClick="button1"

android:text="上传"

android:textSize="20sp" />

</LinearLayout>

</LinearLayout></span>

griditem_addpic.xml

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center"

android:descendantFocusability="blocksDescendants"

android:orientation="vertical" >

<RelativeLayout

android:layout_gravity="center"

android:layout_width="85dp"

android:layout_height="85dp"

android:orientation="vertical" >

<ImageView

android:layout_marginTop="10dp"

android:layout_marginRight="10dp"

android:id="@+id/imageView1"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:scaleType="fitXY"

android:src="@drawable/gridview_addpic" />

</RelativeLayout>

</LinearLayout></span>

Java代码:

UploadUtils.Java

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.net.HttpURLConnection;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.UUID;

import android.util.Log;

/**

*

* 实现文件上传的工具类

*/

public class UploadUtils {

private static final String TAG = "uploadFile";

private static final int TIME_OUT = 10*10000000; //超时时间

private static final String CHARSET = "utf-8"; //设置编码

public static final String SUCCESS="1";

public static final String FAILURE="0";

/**

* android上传文件到服务器

* @param file 需要上传的文件

* @param RequestURL 请求的rul

* @return 返回响应的内容

*/

public static String uploadFile(File file,String RequestURL)

{

String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成

String PREFIX = "--" , LINE_END = "\r\n";

String CONTENT_TYPE = "multipart/form-data"; //内容类型

try {

URL url = new URL(RequestURL);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setReadTimeout(TIME_OUT);

conn.setConnectTimeout(TIME_OUT);

conn.setDoInput(true); //允许输入流

conn.setDoOutput(true); //允许输出流

conn.setUseCaches(false); //不允许使用缓存

conn.setRequestMethod("POST"); //请求方式

conn.setRequestProperty("Charset", CHARSET); //设置编码

conn.setRequestProperty("connection", "keep-alive");

conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);

if(file!=null)

{

/**

* 当文件不为空,把文件包装并且上传

*/

OutputStream outputSteam=conn.getOutputStream();

DataOutputStream dos = new DataOutputStream(outputSteam);

StringBuffer sb = new StringBuffer();

sb.append(PREFIX);

sb.append(BOUNDARY);

sb.append(LINE_END);

/**

* 这里重点注意:

* name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件

* filename是文件的名字,包含后缀名的 比如:abc.png

*/

sb.append("Content-Disposition: form-data; name=\"img\"; filename=\""+file.getName()+"\""+LINE_END);

sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END);

sb.append(LINE_END);

dos.write(sb.toString().getBytes());

InputStream is = new FileInputStream(file);

byte[] bytes = new byte[1024];

int len = 0;

while((len=is.read(bytes))!=-1)

{

dos.write(bytes, 0, len);

}

is.close();

dos.write(LINE_END.getBytes());

byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes();

dos.write(end_data);

dos.flush();

/**

* 获取响应码 200=成功

* 当响应成功,获取响应的流

*/

int res = conn.getResponseCode();

Log.e(TAG, "response code:"+res);

if(res==200)

{

return SUCCESS;

}

}

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return FAILURE;

}

}</span>

UploadFileTask.java

使用到了异步加载

AsyncTask的用法 在开发Android应用时必须遵守单线程模型的原则:

Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2.确保只在UI线程中访问Android UI工具包 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后, 是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员


android提供了几种在其他线程中访问UI线程的方法。 Activity.runOnUiThread( Runnable ) View.post(Runnable ) View.postDelayed( Runnable, long ) Hanlder这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。

为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。 AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。   Params 启动任务执行的输入参数,比如HTTP请求的URL。  

 Progress后台任务执行的百分比。   Result 后台执行任务最终返回的结果,比如String。

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。   

1)子类化AsyncTask   

2) 实现AsyncTask中定义的下面一个或几个方法   

onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。   

doInBackground(Params...), 将在onPreExecute方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。

可以调用publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。   

onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。    onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:   

1) Task的实例必须在UI thread中创建   

2)execute方法必须在UI thread中调用   

3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)这几个方法   

4) 该task只能被执行一次,否则多次调用时将会出现异常doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数 ,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;

import java.io.File;

import android.app.Activity;

import android.app.AlertDialog;

import android.app.ProgressDialog;

import android.content.DialogInterface;

import android.os.AsyncTask;

import android.widget.Toast;

public class UploadFileTask extends AsyncTask<String, Void, String> {

public static final String requestURL = "http://192.168.47.114:8080/UploadFileWeb/servlet/FileImageUpload";

/**

* 可变长的输入参数,与AsyncTask.exucute()对应

*/

private ProgressDialog pdialog;

private Activity context = null;

public UploadFileTask(Activity ctx) {

this.context = ctx;

pdialog = ProgressDialog.show(context, "正在加载...", "系统正在处理您的请求");

}

@Override

protected void onPostExecute(String result) {

// 返回HTML页面的内容

pdialog.dismiss();

if (UploadUtils.SUCCESS.equalsIgnoreCase(result)) {

Toast.makeText(context, "上传成功!", Toast.LENGTH_SHORT).show();

} else {

Toast.makeText(context, "上传失败!", Toast.LENGTH_SHORT).show();

}

}

@Override

protected void onPreExecute() {

}

@Override

protected void onCancelled() {

super.onCancelled();

}

@Override

protected String doInBackground(String... params) {

File file = new File(params[0]);

return UploadUtils.uploadFile(file, requestURL);

}

@Override

protected void onProgressUpdate(Void... values) {

}

}</span>

MainActivity.java

[java] view
plain copy

print?

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.example.androiduploadfile;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import android.app.Activity;

import android.app.AlertDialog;

import android.app.AlertDialog.Builder;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.pm.ActivityInfo;

import android.database.Cursor;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.net.Uri;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.provider.MediaStore;

import android.text.TextUtils;

import android.util.Log;

import android.view.View;

import android.view.WindowManager;

import android.widget.AdapterView;

import android.widget.AdapterView.OnItemClickListener;

import android.widget.Button;

import android.widget.GridView;

import android.widget.ImageView;

import android.widget.SimpleAdapter;

import android.widget.SimpleAdapter.ViewBinder;

import android.widget.Toast;

/**

*

* @author yu_longji

*

*/

public class MainActivity extends Activity {

private GridView gridView1; // 网格显示缩略图

private final int IMAGE_OPEN = 1; // 打开图片标记

private String pathImage; // 选择图片路径

private Bitmap bmp; // 导入临时图片

private ArrayList<HashMap<String, Object>> imageItem;

private SimpleAdapter simpleAdapter; // 适配器

private List<String> list;

String uploadFile = "";

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

// TODO Auto-generated method stub

super.handleMessage(msg);

switch (msg.what) {

case 1:

String b = (String) msg.obj;

Toast.makeText(MainActivity.this, b, Toast.LENGTH_SHORT).show();

break;

case 0:

String string = (String) msg.obj;

Toast.makeText(MainActivity.this, string, Toast.LENGTH_SHORT)

.show();

break;

default:

break;

}

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

/*

* 防止键盘挡住输入框 不希望遮挡设置activity属性 android:windowSoftInputMode="adjustPan"

* 希望动态调整高度 android:windowSoftInputMode="adjustResize"

*/

getWindow().setSoftInputMode(

WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

// 锁定屏幕

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

setContentView(R.layout.activity_main);

list = new ArrayList<>();

// 获取控件对象

gridView1 = (GridView) findViewById(R.id.gridView1);

/*

* 载入默认图片添加图片加号 通过适配器实现 SimpleAdapter参数imageItem为数据源

* R.layout.griditem_addpic为布局

*/

bmp = BitmapFactory.decodeResource(getResources(),

R.drawable.gridview_addpic); // 加号

imageItem = new ArrayList<HashMap<String, Object>>();

HashMap<String, Object> map = new HashMap<String, Object>();

map.put("itemImage", bmp);

imageItem.add(map);

simpleAdapter = new SimpleAdapter(this, imageItem,

R.layout.griditem_addpic, new String[] { "itemImage" },

new int[] { R.id.imageView1 });

/*

* HashMap载入bmp图片在GridView中不显示,但是如果载入资源ID能显示 如 map.put("itemImage",

* R.drawable.img); 解决方法: 1.自定义继承BaseAdapter实现 2.ViewBinder()接口实现

*/

simpleAdapter.setViewBinder(new ViewBinder() {

@Override

public boolean setViewValue(View view, Object data,

String textRepresentation) {

// TODO Auto-generated method stub

if (view instanceof ImageView && data instanceof Bitmap) {

ImageView i = (ImageView) view;

i.setImageBitmap((Bitmap) data);

return true;

}

return false;

}

});

gridView1.setAdapter(simpleAdapter);

/*

* 监听GridView点击事件 报错:该函数必须抽象方法 故需要手动导入import android.view.View;

*/

gridView1.setOnItemClickListener(new OnItemClickListener() {

@Override

public void onItemClick(AdapterView<?> parent, View v,

int position, long id) {

if (position == 0) { // 点击图片位置为+ 0对应0张图片

Toast.makeText(MainActivity.this, "添加图片",

Toast.LENGTH_SHORT).show();

// 选择图片

Intent intent = new Intent(

Intent.ACTION_PICK,

android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

startActivityForResult(intent, IMAGE_OPEN);

// 通过onResume()刷新数据

} else {

dialog(position);

Toast.makeText(MainActivity.this,

"点击第" + position + 1 + " 号图片", Toast.LENGTH_SHORT)

.show();

}

}

});

}

// 获取图片路径 响应startActivityForResult

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

// 打开图片

if (resultCode == RESULT_OK && requestCode == IMAGE_OPEN) {

Uri uri = data.getData();

if (!TextUtils.isEmpty(uri.getAuthority())) {

// 查询选择图片

Cursor cursor = getContentResolver().query(uri,

new String[] { MediaStore.Images.Media.DATA }, null,

null, null);

// 返回 没找到选择图片

if (null == cursor) {

return;

}

// 光标移动至开头 获取图片路径

cursor.moveToFirst();

pathImage = cursor.getString(cursor

.getColumnIndex(MediaStore.Images.Media.DATA));

list.add(pathImage);

}

} // end if 打开图片

}

// 提交发布

public void button1(View view) {

for (int i = 0; i < list.size(); i++) {

uploadFile = list.get(i);

System.out.println(uploadFile);

if (uploadFile != null && uploadFile.length() > 0) {

UploadFileTask uploadFileTask = new UploadFileTask(this);

uploadFileTask.execute(uploadFile);

}

}

}

// 刷新图片

@Override

protected void onResume() {

super.onResume();

if (!TextUtils.isEmpty(pathImage)) {

Bitmap addbmp = BitmapFactory.decodeFile(pathImage);

HashMap<String, Object> map = new HashMap<String, Object>();

map.put("itemImage", addbmp);

imageItem.add(map);

simpleAdapter = new SimpleAdapter(this, imageItem,

R.layout.griditem_addpic, new String[] { "itemImage" },

new int[] { R.id.imageView1 });

simpleAdapter.setViewBinder(new ViewBinder() {

@Override

public boolean setViewValue(View view, Object data,

String textRepresentation) {

// TODO Auto-generated method stub

if (view instanceof ImageView && data instanceof Bitmap) {

ImageView i = (ImageView) view;

i.setImageBitmap((Bitmap) data);

return true;

}

return false;

}

});

gridView1.setAdapter(simpleAdapter);

simpleAdapter.notifyDataSetChanged();

// 刷新后释放防止手机休眠后自动添加

pathImage = null;

}

}

/*

* Dialog对话框提示用户删除操作 position为删除图片位置

*/

protected void dialog(final int position) {

String string = "是否删除该图片";

AlertDialog.Builder builder = new Builder(MainActivity.this);

builder.setMessage(string);

builder.setTitle("提示");

builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

imageItem.remove(position);

list.remove(position - 1);

simpleAdapter.notifyDataSetChanged();

}

});

builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

dialog.dismiss();

}

});

builder.create().show();

}

}

</span>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: