Android 通过form表单上传文字,图片,视频等(通过key值)以及问题分析
最近做到上传的时候,弄了一段时间,也遇到了一些问题和解决方案,在这里就和大家分享一下,希望对你们有用,谢谢。
好了,思想+代码
上传类Java代码:
/**
* Created by aierJun on 2017/3/9.
*/
public class UploadUtils {
private static String BOUNDARY = UUID.randomUUID().toString(); //边界标识 随机生成
private static String PREFIX = "--", LINE_END = "\r\n";
private static String CONTENT_TYPE = "multipart/form-data"; //内容类型
private static final String TAG = "uploadFile";
private static final int TIME_OUT = 10 * 1000; //超时时间
private static final String CHARSET = "utf-8"; //设置编码
private static int state;
/**
* @category 上传文件至Server的方法
* @param uploadUrl 上传路径参数
* @author ylbf_dev
*/
public static boolean uploadFile(final ArrayList<File> imagefiles,final ArrayList<File> videofiles, final String uploadUrl,final ArrayList<String> name,final ArrayList<Object> values) {
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(uploadUrl);
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);
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
StringBuffer sb = new StringBuffer();
sb.append(PREFIX);
sb.append(BOUNDARY);
sb.append(LINE_END);
/**
* 这里重点注意:
* name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
* filename是文件的名字,包含后缀名的 比如:abc.png
*/
if (name!=null&&name.size()>0)
for (int i=0;i<name.size();i++){
addText(name.get(i),values.get(i)+"",dos);
}
addImage(imagefiles,dos);
addVedio(videofiles,dos);
// 读取服务器返回结果
InputStream isBack = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(isBack, "utf-8");
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
Log.d("Jun",result);
dos.close();
JSONObject jsonObject =new JSONObject(result);
state=jsonObject.optInt("State");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
if (state==1){
return true;
}else{
return false;
}
}
private static void addText(String name,Object value,DataOutputStream output) {
StringBuilder sb = new StringBuilder();
sb.append(PREFIX + BOUNDARY + LINE_END);
sb.append("Content-Disposition: form-data; name=\""+name+"\"" + LINE_END);
sb.append(LINE_END);
sb.append(value + LINE_END);
sb.append(PREFIX + BOUNDARY + LINE_END);
try {
output.writeBytes(sb.toString());// 发送表单字段数据
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void addImage(ArrayList<File> files, DataOutputStream output) {
if (files.size()<1||files==null) return;
try {
StringBuilder sb = new StringBuilder();
sb.append(PREFIX + BOUNDARY + LINE_END);
sb.append("Content-Disposition: form-data; name=\"image\"; filename=\"" + files.get(0).getName() + "\"" + LINE_END);
sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END);
sb.append(LINE_END);
output.write(sb.toString().getBytes());
InputStream is = new FileInputStream(files.get(0));
byte[] bytes = new byte[1024];
int len = 0;
Log.d("Jun","开始上传");
while ((len = is.read(bytes)) != -1) {
output.write(bytes, 0, len);
}
is.close();
output.write(LINE_END.getBytes());
byte[] end_data = (PREFIX + BOUNDARY + LINE_END).getBytes();
output.write(end_data);
}catch (Exception e){
throw new RuntimeException(e);
}
}
private static void addVedio(ArrayList<File> files, DataOutputStream output) {
if (files==null||files.size()<1) return;
try {
StringBuilder sb = new StringBuilder();
sb.append(PREFIX + BOUNDARY + LINE_END);
sb.append("Content-Disposition: form-data; name=\"video\"; filename=\"" + files.get(0).getName() + "\"" + LINE_END);
sb.append("Content-Type: application/octet-stream; charset=" + CHARSET + LINE_END);
sb.append(LINE_END);
output.write(sb.toString().getBytes());
InputStream is = new FileInputStream(files.get(0));
byte[] bytes = new byte[1024];
int len = 0;
final int headerSize = sb.length();
Log.d("Jun","开始上传");
while ((len = is.read(bytes)) != -1) {
output.write(bytes, 0, len);
}
is.close();
output.write(LINE_END.getBytes());
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
output.write(end_data);
Log.d("Jun",output+"");
}catch (Exception e){
throw new RuntimeException(e);
}
}
}注意:上面的为封装方法。有text,Image,video。
对上面的分析在下面的问题里会有说明。
java调用方法:
public ArrayList<File> files=new ArrayList<>();
private ArrayList<String> names=new ArrayList<>();
private ArrayList<Object> values=new ArrayList<>();
//添加数据
boolean state=UploadUtils.uploadFile(files,null, APIManger.PUSH_STORY, names, values);注意这里的添加数据name和values是一一对应的关系,小心数据乱了name.add()后values.add();或者再用Arraylist,保证对应就行。
遇到的问题分析:
一.text可以上传,image可以上传,但video不能上传
1.起初,我调试的时候发现视频总是服务器端接收不到,但后,我把image的添加给注销掉了,用video直接上传,发现视频是可以上传的,但就是一起不能实现,然后debug
2.
3.
4.
5.
6,最后问题找到了,开始标签和结束标签的问题。修改为上面的图4和图5,好了。一般的开始–xxx,结束–xxx,最后一次的开始–xxx,结束–xxx–,注意换行我省略了。
二,视频选取和视频路径不是绝对的问题
1,image解决方法
Uri uri = data.getData();
Cursor cursor = PushVedioActivity.this.getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
String imgNo = cursor.getString(0); // 图片编号
String imgPath = cursor.getString(1); // 图片文件路径
filesImage.add(new File(imgPath));
String imgSize = cursor.getString(2); // 图片大小
String imgName = cursor.getString(3); // 图片文件名
cursor.close();2,最终完美解决方案
/**
* Created by aierJun on 2017/3/13.
*/
public class UriAllUriUtils {
/**
* 专为Android4.4设计的从Uri获取文件绝对路径,以前的方法已不好使
*/
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] { split[1] };
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context
* The context.
* @param uri
* The Uri to query.
* @param selection
* (Optional) Filter used in the query.
* @param selectionArgs
* (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = { column };
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri
* The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}注意:封装方法
三,文字text编码格式问题
/**
* Created by aierJun on 2017/3/13.
*/
public class GetFormStringUTF8Utils {
public static String getUTF8String(String string){
String s=null;
try {
s= new String(string.getBytes("UTF-8"),"ISO8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return s;
}
}注意:封装方法
以上,为个人上传的总结,希望对你们有用,如有错误和误解请指教,谢谢。
如需转载,请注明出处http://blog.csdn.net/aierJun/article/details/61916699,谢谢
版权声明:本文为aierJun原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。