古老的榕树

移动终端和 Java 服务端数据传输封装类

潘军杰 发表于 2017-03-05 17:55 阅读(3889) 评论(0) 赞(2)
移动互联时代,常常碰到的是移动终端和服务端数据交互。终端把某种形式的数据传递给服务端,服务端收到数据后,需要根据双方约定的数据格式,取值再做处理。

传递的数据有哪些形式?一般分成三种形式
1:JSON 的流形式
2:纯粹的键值对形式
3:键值对和文件流并存的形式

其实 2-3 可以合并成一种形式来处理,以下将以 Java 服务端情况说明一下,因为终端每次传递数据给服务端,都需要把数据转成约定好的数据结构,每次收到请求都用到,干脆封装了一个独立的工具类,Servlet 控制层把 HttpServletRequest 传递给封装好的方法,方法再解析成 JSON 字符串给逻辑层,(Java 有 fastJSON,jackSON 工具类在,很爽)逻辑层再按需取数据处理等等。

Java 代码:


import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSONObject;

public class RequestUtil {
	/**
     * 把 request 参数转成 JSON 字符串格式的参数
     * 
     * @param request
     * @return
     */
	public static String getReqJSON(HttpServletRequest request) {
		String contectType = StringUtils.isBlank(request.getContentType()) ? "": request.getContentType().toLowerCase();
		if (StringUtils.contains(contectType, "application/x-www-form-urlencoded")) {
			return form2JSON(request);
		} else if (StringUtils.contains(contectType, "multipart/form-data")) {
			return formData2JSON(request);
		} else if (StringUtils.contains(contectType, "multipart/json")) {
			return stream2Json(request);
		} else {
			return formData2JSON(request);
		}
	}

	/**
     * 只传递 JSON 流的时候,把它们转成 JSON 字符串
     * 
     * @param request
     * @return
     */
	private static String stream2Json(HttpServletRequest request) {
		try {
			StringBuilder sb = new StringBuilder();
			InputStream is = request.getInputStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			String line;
			while (null != (line = reader.readLine())) {
				sb.append(line);
			}
			reader.close();
			is.close();
			return sb.toString();
		} catch(Exception e) {
			e.printStackTrace();
			return "";
		}
	}

	/**
     * 只传递键值对的时候,把它们转成 JSON 字符串
     * 
     * @param request
     * @return
     */
	private static String form2JSON(HttpServletRequest request) {
		JSONObject obj = new JSONObject();
		Map < String,
		String[] > map = request.getParameterMap();
		Iterator < String > itReq = map.keySet().iterator();
		while (itReq.hasNext()) {
			String key = itReq.next();
			String val = map.get(key).length > 0 ? map.get(key)[0] : "";
			obj.put(key, val);
		}
		return obj.toJSONString();
	}

	/**
     * 同时传递键值对和文件流的时候,把它们转成 JSON 字符串
     * 
     * @param request
     * @return
     */
	private static String formData2JSON(HttpServletRequest request) {
		// 键值参数和文件字节流方式
		try {
			JSONObject obj = new JSONObject();
			DiskFileItemFactory factory = new DiskFileItemFactory();
			ServletFileUpload upload = new ServletFileUpload(factory);@SuppressWarnings("unchecked") List < FileItem > items = upload.parseRequest(request);
			// 解析request请求
			if (!items.isEmpty()) {
				Iterator < FileItem > iter = items.iterator();
				while (iter.hasNext()) {
					FileItem item = iter.next();
					if (item.isFormField()) { // 如果是表单域 ,就是非文件上传元素
						String name = item.getFieldName(); // 获取name属性的值
						String value = item.getString(); // 获取value属性的值
						obj.put(name, value);
					} else {
						String fieldName = item.getFieldName(); // 文件域中name属性的值
						String fileName = item.getName(); // 文件的全路径,绝对路径名加文件名
						if (fileName != "" && fileName != null) {
							String tempPath = request.getServletContext().getRealPath("") + File.separator + "temp" + File.separator;
							File savefolder = new File(tempPath);
							if (!savefolder.exists()) {
								savefolder.mkdirs();
							}

							File saveFile = new File(tempPath + fileName); // 定义一个file指向一个具体的文件
							item.write(saveFile); // 把上传的内容写到一个文件中
							obj.put(fieldName, tempPath + fileName);
						}
					}
				}
				items.clear();
			}
			return obj.toJSONString();
		} catch(Exception e) {
			e.printStackTrace();
			return "";
		}
	}
}





终端给服务端传递采用 POST 的方式,根据 HttpServletRequest 的 ContentType 区分终端 POST 过来什么形式的数据,比如 :
1:application/x-www-form-urlencoded 就是纯粹的键值对
2:multipart/form-data 就是键值对和文件流并存
3:application/json 就是 JSON 流


实际项目中,传递数据形式我们更倾向 JSON 流,但如果终端除了传递数据,还会有图片、文件的时候,JSON 流数据形式,怎么处理呢?这个问题当初自己也很纠结,当时就觉得第二种方式比较好,但本人并不喜欢混杂用,接口既接收 JSON 流,又接收 键值对和文件流,显然很混乱;让终端开发的兄弟无所适从,所以后来想到了一个办法, 使用 JSON 的某个值承载文件的字节数组,问题得到解决了。

比如以下的 JSON :
{"name":"photo1.jpg","file":file} 

其中 file 是一个字节数组,把一个文件转成字节数组,Java 如:
byte[] file = FileUtil.file2Bytes("/home/path/photo1.jpg");

iOS 也会有相应的办法,把文件转成字节数组,代码就不贴出来了。

(完)

0 条网友评论

哇~~~ 竟然还没有评论!

称呼*
邮箱*
内容*
验证码*
验证码 看不清换张