更简单的方法
请看这个安卓端同时上传图片和文字,服务器接收并处理(二))
之前看了很多博客,找到的无非就是要么只上传json,要么只上传图片。碰了许多的壁,因此我这里写一下自己已经测试成功的代码。
Android端使用Post上传图片和json代码
注意事项:
- 根据前端表单上传可知,我们需要将form的enctype设置成为multipart/form-data才可以完成传文件和传值。
- 根据前端表单上传可知,前端的input标签是需要写一个name的,这样后台才能根据name获取值。
- 一般安卓端上传json或者文件不会向前端传值一样,安卓上传的时候一般没有name这个key的.因此,服务器后台就不可能根据参数名来获取相应的值了。只能通过request对象获取InputStream来进行相应的操作了(或者使用Spring的注解 @RequestPBody)。但是由于文字和图片同时上传,使用这种方式处理起来可能略显麻烦。
因此我才用的方式是,在安卓端直接构造http的报文的方式,模拟出前端向后台传值传文件的操作,然后再向服务器发送请求。
Android代码(非真正Android代码,仅仅用来测试,并未写成app):
其中Json的name是 data
图片流的name是 file
import net.sf.json.JSONObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class UploadTest {
/**
*
* @param args 此方法主要写上传的json数据以及图片文件的地址
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws UnsupportedEncodingException {
String url = "http://localhost:8080/upload";
JSONObject jsonObject = new JSONObject();
jsonObject.put("upload_name", "武汉光谷渍水");
jsonObject.put("upload_type", "公众");
jsonObject.put("longitude", 132.2);
jsonObject.put("latitude", 68.58);
jsonObject.put("upload_address", "武汉光谷");
jsonObject.put("upload_time", new Date().getTime());
jsonObject.put("upload_description", "描述");
jsonObject.put("approval_status", 2);
Map<String, String> params = new HashMap<>();
//设置编码类型为utf-8
params.put("data", String.valueOf(jsonObject));
String filePath = "/home/coder/workspace/baidu.png";
post(url, params, filePath);
}
/**
* @param actionUrl 上传的地址
* @param params 上传的键值对参数
* @param filePath 上传的图片路径
*/
static void post(String actionUrl, Map<String, String> params, String filePath) {
//前面设置报头不需要更改
try {
String BOUNDARY = "--------------et567z"; //数据分隔线
String MULTIPART_FORM_DATA = "Multipart/form-data";
URL url = new URL(actionUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);//允许输入
conn.setDoOutput(true);//允许输出
conn.setUseCaches(false);//不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA + ";boundary=" + BOUNDARY);
//获取map对象里面的数据,并转化为string
StringBuilder sb = new StringBuilder();
System.out.println("上传名称:"+params.get("data"));
//上传的表单参数部分,不需要更改
for (Map.Entry<String, String> entry : params.entrySet()) {//构建表单字段内容
sb.append("--");
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n");
sb.append(entry.getValue());
sb.append("\r\n");
}
System.out.println(sb.toString());
//上传图片部分
DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
outStream.write(sb.toString().getBytes());//发送表单字段数据
//调用自定义方法获取图片文件的byte数组
byte[] content = readFileImage(filePath);
//再次设置报头信息
StringBuilder split = new StringBuilder();
split.append("--");
split.append(BOUNDARY);
split.append("\r\n");
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!非常重要
//此处将图片的name设置为file ,filename不做限制,不需要管
split.append("Content-Disposition: form-data;name=\"file\";filename=\"temp.jpg\"\r\n");
//这里的Content-Type非常重要,一定要是图片的格式,例如image/jpeg或者image/jpg
//服务器端对根据图片结尾进行判断图片格式到底是什么,因此务必保证这里类型正确
split.append("Content-Type: image/png\r\n\r\n");
outStream.write(split.toString().getBytes());
outStream.write(content, 0, content.length);
outStream.write("\r\n".getBytes());
byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();//数据结束标志
outStream.write(end_data);
outStream.flush();
//返回状态判断
int cah = conn.getResponseCode();
// if (cah != 200) throw new RuntimeException("请求url失败:"+cah);
if (cah == 200)//如果发布成功则提示成功
{
System.out.println("上传成功");
} else if (cah == 400) {
System.out.println("400错误");
} else {
throw new RuntimeException("请求url失败:" + cah);
}
outStream.close();
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private static byte[] readFileImage(String filePath) throws IOException {
BufferedInputStream bufferedInputStream = new BufferedInputStream(
new FileInputStream(filePath));
int len = bufferedInputStream.available();
byte[] bytes = new byte[len];
int r = bufferedInputStream.read(bytes);
if (len != r) {
bytes = null;
throw new IOException("读取文件不正确");
}
bufferedInputStream.close();
return bytes;
}
}
服务器后台接受请求的处理代码
使用spring boot框架,采用注解形式获取参数
@PostMapping(value = "upload")
@ResponseBody
public String uploadAccident(@RequestParam(value = "data")String data,@RequestParam(value = "file")MultipartFile file) throws IOException {
System.out.println(data);
//解析数据
Upload upload = null;
logger.info("json为:"+data);
JSONObject jsonObject = JSONObject.fromObject(data);
String uploadName = jsonObject.getString("upload_name");
String uploadType = jsonObject.getString("upload_type");
float longitude = (float) jsonObject.getDouble("longitude");
float latitude = (float) jsonObject.getDouble("latitude");
String uploadAddress = jsonObject.getString("upload_address");
Date uploadTime = new Date(Long.parseLong(jsonObject.getString("upload_time")));
String uploadDescription = jsonObject.getString("upload_description");
int approvalStatus = jsonObject.getInt("approval_status");
logger.info("文件的大小:"+file.getSize());
logger.info("文件的类型:"+file.getContentType());
logger.info("文件的名称:"+file.getName());
String [] contentType = file.getContentType().split("/");
if (file.isEmpty()){
System.out.println("文件空");
}
//文件不空
if (!file.isEmpty()){
File dir = new File(UploadFileUtil.IMAGE_DIR);
//如果文件夹不存在,创建目录
if (!dir.exists()){
dir.mkdirs();
}
//设置上传的图片名称为日期+图片类型
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String fileName = sdf.format(date);
byte [] imageBytes = file.getBytes();
String filePath = UploadFileUtil.IMAGE_DIR + fileName +"." +contentType[1];
File imageFile = new File(filePath);
if (!imageFile.exists()){
imageFile.createNewFile();
}
FileImageOutputStream imageOutput = new FileImageOutputStream(imageFile);
//将bytes数组写成文件
imageOutput.write(imageBytes,0,imageBytes.length);
imageOutput.close();
//构造一个upload上传实体
upload = new Upload(uploadName,uploadType,filePath,longitude,latitude,uploadAddress,uploadTime,uploadDescription,approvalStatus);
}
try{
//将实体信息存入数据库
// uploadDao.save(upload);
} catch (Exception e){
e.printStackTrace();
return "{\"result\":\"false\",\"msg\":"+e.getMessage()+"}";
}
return "{\"result\":\"true\",\"msg\":\"success\"}";
}
这个接口写了很长时间,就卡在怎么接受参数的问题上了,如果有更好的方法,欢迎大家在下面回复。~