一起学Android之Xml与Json解析
概述
在网络中,数据交互通常是以XML和Json的格式进行,所以对这两种格式的数据进行解析,是Android开发中的必备功能,本文以一个简单的小例子,简述Android开发中Xml和Json解析的常用方式,仅供学习分享使用。
XML解析
Android 提供了三种解析XML的方式:SAX(Simple API XML), DOM(Document Object Model), PULL,本文主要讲解Pull的方式解析Xml。
PULL解析Xml优点:PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器,Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
涉及知识点
- XmlPullParser 是一个提供对XML进行Pull方式解析的基础功能的接口。
- xmlPullParser.getEventType() 返回当前节点的事件类型(如:START_TAG, END_TAG, TEXT, etc.)。
- xmlPullParser.getName() 获取当前节点对应的名称。
- xmlPullParser.getAttributeCount() 获取当前节点对应的属性个数。
- xmlPullParser.getText() 获取当前节点对应的文本内容。
- xmlPullParser.getAttributeName(0) 获取属性对应的名称。
- xmlPullParser.getAttributeValue(0) 获取属性对应的值。
- xmlPullParser.next() 移动到下一个事件。
Xml文件
Xml存放相对路径:DemoXml\app\src\main\res\xml\test.xml [xml文件夹]
- <bookstore>
- <book category="COOKING">
- <title lang="en">Everyday Italian</title>
- <author>Giada De Laurentiis</author>
- <year>2005</year>
- <price>30.00</price>
- </book>
- <book category="CHILDREN">
- <title lang="en">Harry Potter</title>
- <author>J K. Rowling</author>
- <year>2005</year>
- <price>29.99</price>
- </book>
- <book category="WEB">
- <title lang="en">Learning XML</title>
- <author>Erik T. Ray</author>
- <year>2003</year>
- <price>39.95</price>
- </book>
- </bookstore>
Xml解析源码
- /**
- * 获取Xml内容
- * @param resources
- * @param id
- * @return
- * @throws XmlPullParserException
- * @throws IOException
- */
- private List<String> xml_parser(Resources resources, int id) throws XmlPullParserException, IOException {
- XmlPullParser xmlPullParser = resources.getXml(id);
- List<String> lstContent=new ArrayList<String>();
- int eventType = xmlPullParser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
- switch (eventType) {
- case XmlPullParser.START_DOCUMENT://文档开始
- Log.i(TAG, "xml_parser: START_DOCUMENT");
- break;
- case XmlPullParser.END_DOCUMENT://文档结束
- Log.i(TAG, "xml_parser: END_DOCUMENT");
- break;
- case XmlPullParser.START_TAG://标记(元素,节点)开始
- Log.i(TAG, "xml_parser: START_TAG");
- String tagName = xmlPullParser.getName();
- //有些节点是没有属性值的,所以需要判断,否则会越界
- int count = xmlPullParser.getAttributeCount();//获取属性个个数
- String tagAttributeValue="";
- String tagAttributeName="";
- //String text =xmlPullParser.getText();//此处获取不到text
- String content="";
- if (count > 0) {
- tagAttributeName=xmlPullParser.getAttributeName(0);
- tagAttributeValue = xmlPullParser.getAttributeValue(0);
- content="标签="+tagName+"属性名="+tagAttributeName+"属性值="+tagAttributeValue;
- }else{
- content="标签="+tagName;
- }
- lstContent.add(content);
- break;
- case XmlPullParser.TEXT:
- String text =xmlPullParser.getText();
- lstContent.add("节点内容="+text);
- break;
- case XmlPullParser.END_TAG://标记结束
- Log.i(TAG, "xml_parser: END_TAG");
- break;
- }
- eventType = xmlPullParser.next();
- }
- return lstContent;
- }
如果Xml文件过大的话,则不适合在Activity主线程中执行,本文是在Worker线程中执行的,如下所示:
- private static final String TAG="TAG";
- private static final int MSG_FINISH=0x0001;
- private TextView tvMsg;
- private Handler handler=new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what){
- case MSG_FINISH:
- List<String> lstContent=(List<String>)msg.obj;
- for (String info :lstContent){
- tvMsg.append(info+"\r\n");
- }
- break;
- }
- }
- };
- public void bn_xml_parser_click(View view){
- tvMsg.setText("");
- new Thread(){
- @Override
- public void run() {
- try {
- List<String> lstContent=xml_parser(getResources(),R.xml.test);
- Message msg=handler.obtainMessage();
- msg.what=MSG_FINISH;
- msg.obj=lstContent;
- handler.sendMessage(msg);
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }.start();
- }
JSON解析
Json是一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。业内主流技术为其提供了完整的解决方案,从而可以在不同平台间进行数据交换。
涉及知识点
- JSONObject 表示一个Json格式的对象。
- jsonObject.getString("key"); 获取字符串格式的值。
- jsonObject.getInt("key"); 获取Int类型的值。
- jsonObject.getBoolean("key"); 获取bool类型的值。
- jsonObject.getDouble("key"); 获取浮点数类型的值。
- jsonObject.get("key"); 返回Object类型的对象。
- jsonObject.getJSONArray("key"); 返回数据类型的对象。
- InputStream 输入流。
Json文件
Json存放相对路径:DemoXml\app\src\main\res\raw\test2.json [raw文件夹]
- {
- "name": "小明",
- "age": 14,
- "gender": true,
- "height": 1.65,
- "grade": null,
- "middle_school": "\"W3C\" Middle School",
- "skills": [
- "JavaScript",
- "Java",
- "Python",
- "Lisp"
- ]
- }
Json解析源码
- /**
- * 解析到列表
- * @return
- * @throws IOException
- * @throws JSONException
- */
- private List<String> json_parser() throws IOException, JSONException {
- List<String> lstContent = new ArrayList<String>();
- String data = getContent(getResources(), R.raw.test2);
- JSONObject jsonObject = new JSONObject(data);
- String name = jsonObject.getString("name");
- int age = jsonObject.getInt("age");
- boolean gender = jsonObject.getBoolean("gender");
- double height = jsonObject.getDouble("height");
- Object grade = jsonObject.get("grade");
- String middleSchool = jsonObject.getString("middle_school");
- JSONArray jsonArray = jsonObject.getJSONArray("skills");
- lstContent.add("name=" + name);
- lstContent.add("age=" + age);
- lstContent.add("gender=" + gender);
- lstContent.add("height=" + height);
- lstContent.add("grade=" + grade);
- lstContent.add("middleSchool=" + middleSchool);
- for (int i = 0; i < jsonArray.length(); i++) {
- String skill = jsonArray.getString(i);
- lstContent.add("skill=" + skill);
- }
- return lstContent;
- }
- /**
- * 通过id获取Json文件对应的内容
- * @param resources
- * @param id
- * @return
- * @throws IOException
- */
- private String getContent(Resources resources, int id) throws IOException {
- StringBuilder stringBuilder = new StringBuilder();
- InputStream inputStream = null;
- try {
- inputStream = resources.openRawResource(id);
- byte[] bytes = new byte[1024];
- int length = inputStream.read(bytes, 0, 1024);
- while (length > -1) {
- stringBuilder.append(new String(bytes, 0, length));
- length = inputStream.read(bytes, 0, 1024);
- }
- } finally {
- if (inputStream != null) {
- inputStream.close();
- }
- }
- return stringBuilder.toString();
- }
同样,如果Json文件比较大,或者解析比较慢,则不能在Activity主线程中执行,需要新启动一个Worker线程,在后台执行,如下所示:
- private static final String TAG="TAG";
- private static final int MSG_FINISH=0x0001;
- private static final int MSG_SERIALIZE=0x0002;
- private TextView tvMsg;
- private Handler handler=new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what){
- case MSG_FINISH:
- List<String> lstContent=(List<String>)msg.obj;
- for (String info :lstContent){
- tvMsg.append(info+"\r\n");
- }
- break;
- }
- }
- };
- /**
- * 解析Json
- * @param view
- */
- public void bn_json_parser_click(View view) {
- tvMsg.setText("");
- new Thread() {
- @Override
- public void run() {
- try {
- List<String> lstContent = json_parser();
- Message msg = handler.obtainMessage();
- msg.what = MSG_FINISH;
- msg.obj = lstContent;
- handler.sendMessage(msg);
- } catch (IOException e) {
- e.printStackTrace();
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- }.start();
- }
如果需要将Json反序列化成类对象,或者将类对象序列化成Json格式文件,如下是一个帮助类:
- package com.hex.demoxml;
- import android.util.Log;
- import java.util.Collection;
- import java.lang.reflect.Array;
- import java.lang.reflect.Field;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import java.util.Collection;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import org.json.JSONStringer;
- /** JSON序列化辅助类 **/
- public class JsonHelper {
- private static final String TAG="TAG";
- /**
- * 将对象转换成Json字符串
- **/
- public static String toJSON(Object obj) {
- JSONStringer js = new JSONStringer();
- serialize(js, obj);
- return js.toString();
- }
- /**
- * 序列化为JSON
- **/
- private static void serialize(JSONStringer js, Object o) {
- if (isNull(o)) {
- try {
- js.value(null);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return;
- }
- Class<?> clazz = o.getClass();
- if (isObject(clazz)) { // 对象
- serializeObject(js, o);
- } else if (isArray(clazz)) { // 数组
- serializeArray(js, o);
- } else if (isCollection(clazz)) { // 集合
- Collection<?> collection = (Collection<?>) o;
- serializeCollect(js, collection);
- } else { // 单个值
- try {
- js.value(o);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 序列化数组
- **/
- private static void serializeArray(JSONStringer js, Object array) {
- try {
- js.array();
- for (int i = 0; i < Array.getLength(array); ++i) {
- Object o = Array.get(array, i);
- serialize(js, o);
- }
- js.endArray();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 序列化集合
- **/
- private static void serializeCollect(JSONStringer js, Collection<?> collection) {
- try {
- js.array();
- for (Object o : collection) {
- serialize(js, o);
- }
- js.endArray();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 序列化对象
- **/
- private static void serializeObject(JSONStringer js, Object obj) {
- try {
- js.object();
- for (Field f : obj.getClass().getFields()) {
- Object o = f.get(obj);
- js.key(f.getName());
- serialize(js, o);
- }
- js.endObject();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 反序列化简单对象
- *
- * @throws
- **/
- public static <T> T parseObject(JSONObject jo, Class<T> clazz) {
- Log.i(TAG, "parseObject: >>>>>>第二个开始");
- if (clazz == null || isNull(jo)) {
- Log.i(TAG, "parseObject: >>>>>>第二个parseObject");
- return null;
- }
- T obj = createInstance(clazz);
- if (obj == null) {
- Log.i(TAG, "parseObject: >>>>>>创建实例为空");
- return null;
- }
- Log.i(TAG, "parseObject: >>>>>>属性长度"+clazz.getFields().length);
- Log.i(TAG, "parseObject: >>>>>>属性长度2"+clazz.getClass());
- for (Field f : clazz.getFields()) {
- Log.i(TAG, "parseObject: >>>>>>"+f.getName());
- setField(obj, f, jo);
- //Log.i(TAG, "parseObject: >>>>>>"+obj.);
- }
- Log.i(TAG, "parseObject: >>>>>返回obj"+obj.getClass());
- return obj;
- }
- /**
- * 反序列化简单对象
- *
- * @throws
- **/
- public static <T> T parseObject(String jsonString, Class<T> clazz) {
- if (clazz == null || jsonString == null || jsonString.length() == 0) {
- Log.i(TAG, "parseObject: >>>>>>>null");
- return null;
- }
- Log.i(TAG, "parseObject: >>>>>>>not null");
- JSONObject jo = null;
- try {
- jo = new JSONObject(jsonString);
- } catch (JSONException e) {
- Log.i(TAG, "parseObject: >>>>>>转换json对象异常:"+e.getMessage());
- e.printStackTrace();
- }
- if (isNull(jo)) {
- Log.i(TAG, "parseObject: >>>>>转换后为null");
- return null;
- }
- Log.i(TAG, "parseObject: >>>>>>进入下一步");
- return parseObject(jo, clazz);
- }
- /**
- * 反序列化数组对象
- *
- * @throws
- **/
- public static <T> T[] parseArray(JSONArray ja, Class<T> clazz) {
- if (clazz == null || isNull(ja)) {
- return null;
- }
- int len = ja.length();
- Log.i(TAG, "parseArray: >>>>>"+len);
- Log.i(TAG, "parseArray: >>>>>"+clazz.getName());
- @SuppressWarnings("unchecked")
- T[] array = (T[]) Array.newInstance(clazz, len);
- for (int i = 0; i < len; ++i) {
- try {
- Object object=ja.get(i);
- if(isSingle(clazz)){
- Log.i(TAG, "parseArray: >>>>>:"+object.toString());
- array[i]=(T)object.toString();
- }else {
- JSONObject jo = ja.getJSONObject(i);
- Log.i(TAG, "parseArray: >>>>>jo:"+jo.toString());
- T o = parseObject(jo, clazz);
- Log.i(TAG, "parseArray: >>>>>o:" + o.toString());
- array[i] = o;
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- return array;
- }
- /**
- * 反序列化数组对象
- *
- * @throws
- **/
- public static <T> T[] parseArray(String jsonString, Class<T> clazz) {
- if (clazz == null || jsonString == null || jsonString.length() == 0) {
- return null;
- }
- JSONArray jo = null;
- try {
- jo = new JSONArray(jsonString);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- if (isNull(jo)) {
- return null;
- }
- return parseArray(jo, clazz);
- }
- /**
- * 反序列化泛型集合
- *
- * @throws
- **/
- @SuppressWarnings("unchecked")
- public static <T> Collection<T> parseCollection(JSONArray ja, Class<?> collectionClazz,
- Class<T> genericType) {
- if (collectionClazz == null || genericType == null || isNull(ja)) {
- return null;
- }
- Collection<T> collection = (Collection<T>) createInstance(collectionClazz);
- for (int i = 0; i < ja.length(); ++i) {
- try {
- JSONObject jo = ja.getJSONObject(i);
- T o = parseObject(jo, genericType);
- collection.add(o);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- return collection;
- }
- /**
- * 反序列化泛型集合
- *
- * @throws
- **/
- public static <T> Collection<T> parseCollection(String jsonString, Class<?> collectionClazz,
- Class<T> genericType) {
- if (collectionClazz == null || genericType == null || jsonString == null
- || jsonString.length() == 0) {
- return null;
- }
- JSONArray jo = null;
- try {
- jo = new JSONArray(jsonString);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- if (isNull(jo)) {
- return null;
- }
- return parseCollection(jo, collectionClazz, genericType);
- }
- /**
- * 根据类型创建对象
- **/
- private static <T> T createInstance(Class<T> clazz) {
- if (clazz == null)
- return null;
- T obj = null;
- try {
- obj = clazz.newInstance();
- } catch (Exception e) {
- Log.i(TAG, "createInstance: >>>>>>创建实例异常");
- e.printStackTrace();
- }
- return obj;
- }
- /**
- * 设定字段的值
- **/
- private static void setField(Object obj, Field f, JSONObject jo) {
- String name = f.getName();
- Class<?> clazz = f.getType();
- Log.i(TAG, "setField: >>>>>name:"+name);
- try {
- if (isArray(clazz)) { // 数组
- Log.i(TAG, "setField: >>>>>数组");
- Class<?> c = clazz.getComponentType();
- JSONArray ja = jo.optJSONArray(name);
- if (!isNull(ja)) {
- Log.i(TAG, "setField: >>>>>ja:"+ja.getString(0));
- Object array = parseArray(ja, c);
- f.set(obj, array);
- }else{
- Log.i(TAG, "setField: >>>>>数组为空");
- }
- } else if (isCollection(clazz)) { // 泛型集合
- Log.i(TAG, "setField: >>>>>泛型集合");
- // 获取定义的泛型类型
- Class<?> c = null;
- Type gType = f.getGenericType();
- if (gType instanceof ParameterizedType) {
- ParameterizedType ptype = (ParameterizedType) gType;
- Type[] targs = ptype.getActualTypeArguments();
- if (targs != null && targs.length > 0) {
- Type t = targs[0];
- c = (Class<?>) t;
- }
- }
- JSONArray ja = jo.optJSONArray(name);
- if (!isNull(ja)) {
- Object o = parseCollection(ja, clazz, c);
- f.set(obj, o);
- }
- } else if (isSingle(clazz)) { // 值类型
- Log.i(TAG, "setField: >>>>>Single值类型");
- Object o = jo.opt(name);
- if (o != null) {
- f.set(obj, o);
- }
- } else if (isObject(clazz)) { // 对象
- Log.i(TAG, "setField: >>>>>Object对象:"+clazz);
- JSONObject j = jo.optJSONObject(name);
- if (!isNull(j)) {
- Object o = parseObject(j, clazz);
- f.set(obj, o);
- }else{
- Log.i(TAG, "setField: >>>>>Object对象为null");
- }
- } else {
- Log.i(TAG, "setField: >>>>>未知类型:"+clazz);
- throw new Exception("unknow type!");
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * 判断对象是否为空
- **/
- private static boolean isNull(Object obj) {
- if (obj instanceof JSONObject) {
- return JSONObject.NULL.equals(obj);
- }
- return obj == null;
- }
- /**
- * 判断是否是值类型
- **/
- private static boolean isSingle(Class<?> clazz) {
- return isBoolean(clazz) || isNumber(clazz) || isString(clazz);
- }
- /**
- * 是否布尔值
- **/
- public static boolean isBoolean(Class<?> clazz) {
- return (clazz != null)
- && ((Boolean.TYPE.isAssignableFrom(clazz)) || (Boolean.class
- .isAssignableFrom(clazz)));
- }
- /**
- * 是否数值
- **/
- public static boolean isNumber(Class<?> clazz) {
- return (clazz != null)
- && ((Byte.TYPE.isAssignableFrom(clazz)) || (Short.TYPE.isAssignableFrom(clazz))
- || (Integer.TYPE.isAssignableFrom(clazz))
- || (Long.TYPE.isAssignableFrom(clazz))
- || (Float.TYPE.isAssignableFrom(clazz))
- || (Double.TYPE.isAssignableFrom(clazz)) || (Number.class
- .isAssignableFrom(clazz)));
- }
- /**
- * 判断是否是字符串
- **/
- public static boolean isString(Class<?> clazz) {
- return (clazz != null)
- && ((String.class.isAssignableFrom(clazz))
- || (Character.TYPE.isAssignableFrom(clazz)) || (Character.class
- .isAssignableFrom(clazz)));
- }
- /**
- * 判断是否是对象
- **/
- private static boolean isObject(Class<?> clazz) {
- return clazz != null && !isSingle(clazz) && !isArray(clazz) && !isCollection(clazz);
- }
- /**
- * 判断是否是数组
- **/
- public static boolean isArray(Class<?> clazz) {
- return clazz != null && clazz.isArray();
- }
- /**
- * 判断是否是集合
- **/
- public static boolean isCollection(Class<?> clazz) {
- return clazz != null && Collection.class.isAssignableFrom(clazz);
- }
- }
备注
沉舟侧畔千帆过,病树前头万木春。
一起学Android之Xml与Json解析的更多相关文章
- Android基础总结(12)——XML和JSON解析
XML和JSON解析 在网络上传输数据时最常用的格式有两种:XML和JSON.本文主要就是学习如何对这两种常用的数据格式进行解析. 1.XML和JSON的定义 XML:扩展标记语言 (Extensib ...
- android基础---->XMl数据的解析
在网络上传输数据时最常用的格式有两种,XML和JSON,下面首先学一下如何解析XML格式的数据,JSON的解析可以参见我的博客(android基础---->JSON数据的解析).解析XML 格式 ...
- Qt on Android: http下载与Json解析
百度提供有查询 ip 归属地的开放接口,当你在搜索框中输入一个 ip 地址进行搜索,就会打开由 ip138 提供的百度框应用,你能够在框内直接输入 ip 地址查询.我查看了页面请求,提取出查询 ip ...
- XML与JSON解析
[XML简介] XML在线校验工具: http://tool.oschina.net/codeformat/xml 可扩展标记语言(EXtensible Markup Language) 一种标记语言 ...
- Android之XML序列化和解析
XML文件是一种常用的文件格式,可以用来存储与传递数据 ,本文是XML文件序列化与解析的一个简单示例 写文件到本地,并用XML格式存储 /** * 写xml文件到本地 */ private void ...
- python入门(十):XML和JSON解析
一.python解析XML 1.xml.dom.*模块,它是W3C DOM API的实现,若需要处理DOM API则该模块很适合,注意xml.dom包里面有许多模块,须区分它们间的不同: 2.xml. ...
- golang的xml、json解析
xml golang的xml处理主要应用Unmarshal.Marshal方法实现,解析一个xml到struct如下,首先是xml文件: <?xml version="1.0" ...
- 【Android】XML文件的解析
1.首先我们可以在res包路径下创建一个raw包,然后在raw下创建一个email.xml 文件,并修改其内容如下: <?xml version="1.0" encoding ...
- android AndroidManifest.xml 属性详细解析
一.关于AndroidManifest.xml AndroidManifest.xml 是每个android程序中必须的文件.它位于整个项目的根目录,描述了package中暴露的组件(activiti ...
随机推荐
- 解决zabbix监控因php问题导致图形界面中文乱码方法
解决因编译php中添加了-enable-gd-jis-conv选项导致Zabbix监控系统图形界面中文乱码问题 现象: php编译参数: 说明: 如果PHP编译时启用–enable-gd-jis-co ...
- VMware kali虚拟机环境配置
编译内核 (1)执行命令uname -r以查看内核版本. (2)执行命令apt-cache search linux-headers查看是否安装内核头文件. (3) 如果uname -r出现的内容在 ...
- Shell—详解$( )、$(( ))、``与${ }的区别
https://www.jianshu.com/p/2237f029c385 https://www.cnblogs.com/chenpython123/p/11052276.html https:/ ...
- 集合系列 Map(十二):HashMap
HashMap 是 Map 基于哈希散列算法的实现,其在 JDK1.7 中采用了数组+链表的数据结构.在 JDK1.8 中为了提高查询效率,采用了数组+链表+红黑树的数据结构.本文所有讲解均基于 JD ...
- laravel .env文件的使用
umen 是 laravel 的衍生品,核心功能的使用和 laravel 都是一致的,但配置文件这一方面,lumen 在 laravel 的基础上增加了更简便的配置方式:lumen 采用了 DotEn ...
- 1、netty入门说明
netty中的例子,基本模式都是:server -> Initializer -> Handler . 在server中去启动线程,打开端口,设置initializer,和一些启动的参数配 ...
- "(error during evaluation)" computed
在vue-cli搭建的去哪网app项目中使用了 computed 计算属性 computed计算属性在chrome插件中的 vue devtools 插件中报错 应该显示出来 computed 属 ...
- MySQL数据库:多表连接查询
多表连接查询 注意:使用连接技术建议将表经行重命名! # explain 检索连接是否达标 # 内连接 # 语法1 from 表1 inner join 表2 on 主键字段=外键字段 [where ...
- Java8特性Lambda表达式
Lambda 表达式 简介: Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). (parame ...
- 《Web Development with Go》Mangodb插入struct数据
学习数据持久化. package main import ( "fmt" "log" "time" "gopkg.in/mgo.v ...