实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据。先来看看本文程序运行的动画:

这个SQL分页表格控件主要分为“表格区”和“分页栏”这两部分,这两部分都是基于GridView实现的。网上介绍Android上实现表格的DEMO一般都用ListView。ListView与GridView对比,ListView最大的优势是格单元的大小可以自定义,可以某单元长某单元短,但是难于实现自适应数据表的结构;而GridView最大的优势就是自适应数据表的结构,但是格单元统一大小。。。对于数据表结构多变的情况,建议使用GridView实现表格。
本文实现的SQL分页表格控件有以下特点:
1.自适应数据表结构,但是格单元统一大小;
2.支持分页;
3.“表格区”有按键事件回调处理,“分页栏”有分页切换事件回调处理。
本文程序代码较多,可以到这里下载整个工程的源码:http://www.rayfile.com/files/72e78b68-f2e5-11df-8469-0015c55db73d/items.xml
的代码如下,它是“表格区”和“分页栏”的格单元实现:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout android:id="@+id/LinearLayout01"
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. android:layout_width="fill_parent" android:background="#555555"
  5. android:layout_height="wrap_content">
  6. <TextView android:layout_below="@+id/ItemImage" android:text="TextView01"
  7. android:id="@+id/ItemText" android:bufferType="normal"
  8. android:singleLine="true" android:background="#000000"
  9. android:layout_width="fill_parent" android:gravity="center"
  10. android:layout_margin="1dip" android:layout_gravity="center"
  11. android:layout_height="wrap_content">
  12. </TextView>
  13. </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/LinearLayout01"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:background="#555555"
android:layout_height="wrap_content">
<TextView android:layout_below="@+id/ItemImage" android:text="TextView01"
android:id="@+id/ItemText" android:bufferType="normal"
android:singleLine="true" android:background="#000000"
android:layout_width="fill_parent" android:gravity="center"
android:layout_margin="1dip" android:layout_gravity="center"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>

main.xml的代码如下:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical" android:layout_width="fill_parent"
  4. android:layout_height="fill_parent" android:id="@+id/MainLinearLayout">
  5. <Button android:layout_height="wrap_content"
  6. android:layout_width="fill_parent" android:id="@+id/btnCreateDB"
  7. android:text="创建数据库"></Button>
  8. <Button android:layout_height="wrap_content"
  9. android:layout_width="fill_parent" android:text="插入一串实验数据" android:id="@+id/btnInsertRec"></Button>
  10. <Button android:layout_height="wrap_content" android:id="@+id/btnClose"
  11. android:text="关闭数据库" android:layout_width="fill_parent"></Button>
  12. </LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:id="@+id/MainLinearLayout">
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent" android:id="@+id/btnCreateDB"
android:text="创建数据库"></Button>
<Button android:layout_height="wrap_content"
android:layout_width="fill_parent" android:text="插入一串实验数据" android:id="@+id/btnInsertRec"></Button>
<Button android:layout_height="wrap_content" android:id="@+id/btnClose"
android:text="关闭数据库" android:layout_width="fill_parent"></Button>
</LinearLayout>

演示程序testSQLite.java的源码:

  1. package com.testSQLite;
  2. import android.app.Activity;
  3. import android.database.Cursor;
  4. import android.database.SQLException;
  5. import android.database.sqlite.SQLiteDatabase;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. import android.view.View;
  9. import android.widget.Button;
  10. import android.widget.LinearLayout;
  11. import android.widget.Toast;
  12. public class testSQLite extends Activity {
  13. GVTable table;
  14. Button btnCreateDB, btnInsert, btnClose;
  15. SQLiteDatabase db;
  16. int id;//添加记录时的id累加标记,必须全局
  17. private static final String TABLE_NAME = "stu";
  18. private static final String ID = "id";
  19. private static final String NAME = "name";
  20. private static final String PHONE = "phone";
  21. private static final String ADDRESS = "address";
  22. private static final String AGE = "age";
  23. @Override
  24. public void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.main);
  27. btnCreateDB = (Button) this.findViewById(R.id.btnCreateDB);
  28. btnCreateDB.setOnClickListener(new ClickEvent());
  29. btnInsert = (Button) this.findViewById(R.id.btnInsertRec);
  30. btnInsert.setOnClickListener(new ClickEvent());
  31. btnClose = (Button) this.findViewById(R.id.btnClose);
  32. btnClose.setOnClickListener(new ClickEvent());
  33. table=new GVTable(this);
  34. table.gvSetTableRowCount(8);//设置每个分页的ROW总数
  35. LinearLayout ly = (LinearLayout) findViewById(R.id.MainLinearLayout);
  36. table.setTableOnClickListener(new GVTable.OnTableClickListener() {
  37. @Override
  38. public void onTableClickListener(int x,int y,Cursor c) {
  39. c.moveToPosition(y);
  40. String str=c.getString(x)+" 位置:("+String.valueOf(x)+","+String.valueOf(y)+")";
  41. Toast.makeText(testSQLite.this, str, 1000).show();
  42. }
  43. });
  44. table.setOnPageSwitchListener(new GVTable.OnPageSwitchListener() {
  45. @Override
  46. public void onPageSwitchListener(int pageID,int pageCount) {
  47. String str="共有"+String.valueOf(pageCount)+
  48. " 当前第"+String.valueOf(pageID)+"页";
  49. Toast.makeText(testSQLite.this, str, 1000).show();
  50. }
  51. });
  52. ly.addView(table);
  53. }
  54. class ClickEvent implements View.OnClickListener {
  55. @Override
  56. public void onClick(View v) {
  57. if (v == btnCreateDB) {
  58. CreateDB();
  59. } else if (v == btnInsert) {
  60. InsertRecord(16);//插入16条记录
  61. table.gvUpdatePageBar("select count(*) from " + TABLE_NAME,db);
  62. table.gvReadyTable("select * from " + TABLE_NAME,db);
  63. }else if (v == btnClose) {
  64. table.gvRemoveAll();
  65. db.close();
  66. }
  67. }
  68. }
  69. /**
  70. * 在内存创建数据库和数据表
  71. */
  72. void CreateDB() {
  73. // 在内存创建数据库
  74. db = SQLiteDatabase.create(null);
  75. Log.e("DB Path", db.getPath());
  76. String amount = String.valueOf(databaseList().length);
  77. Log.e("DB amount", amount);
  78. // 创建数据表
  79. String sql = "CREATE TABLE " + TABLE_NAME + " (" +
  80. ID  + " text not null, " + NAME + " text not null," +
  81. ADDRESS + " text not null, " + PHONE + " text not null," +
  82. AGE + " text not null "+");";
  83. try {
  84. db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
  85. db.execSQL(sql);
  86. } catch (SQLException e) {}
  87. }
  88. /**
  89. * 插入N条数据
  90. */
  91. void InsertRecord(int n) {
  92. int total = id + n;
  93. for (; id < total; id++) {
  94. String sql = "insert into " + TABLE_NAME + " (" +
  95. ID + ", " + NAME+", " + ADDRESS+", " + PHONE+", "+AGE
  96. + ") values('" + String.valueOf(id) + "', 'man','address','123456789','18');";
  97. try {
  98. db.execSQL(sql);
  99. } catch (SQLException e) {
  100. }
  101. }
  102. }
  103. }
package com.testSQLite;
import android.app.Activity;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
public class testSQLite extends Activity {
GVTable table;
Button btnCreateDB, btnInsert, btnClose;
SQLiteDatabase db;
int id;//添加记录时的id累加标记,必须全局
private static final String TABLE_NAME = "stu";
private static final String ID = "id";
private static final String NAME = "name";
private static final String PHONE = "phone";
private static final String ADDRESS = "address";
private static final String AGE = "age"; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnCreateDB = (Button) this.findViewById(R.id.btnCreateDB);
btnCreateDB.setOnClickListener(new ClickEvent());
btnInsert = (Button) this.findViewById(R.id.btnInsertRec);
btnInsert.setOnClickListener(new ClickEvent());
btnClose = (Button) this.findViewById(R.id.btnClose);
btnClose.setOnClickListener(new ClickEvent());
table=new GVTable(this);
table.gvSetTableRowCount(8);//设置每个分页的ROW总数
LinearLayout ly = (LinearLayout) findViewById(R.id.MainLinearLayout);
table.setTableOnClickListener(new GVTable.OnTableClickListener() {
@Override
public void onTableClickListener(int x,int y,Cursor c) {
c.moveToPosition(y);
String str=c.getString(x)+" 位置:("+String.valueOf(x)+","+String.valueOf(y)+")";
Toast.makeText(testSQLite.this, str, 1000).show();
}
});
table.setOnPageSwitchListener(new GVTable.OnPageSwitchListener() { @Override
public void onPageSwitchListener(int pageID,int pageCount) {
String str="共有"+String.valueOf(pageCount)+
" 当前第"+String.valueOf(pageID)+"页";
Toast.makeText(testSQLite.this, str, 1000).show();
}
}); ly.addView(table);
}
class ClickEvent implements View.OnClickListener {
@Override
public void onClick(View v) {
if (v == btnCreateDB) {
CreateDB();
} else if (v == btnInsert) {
InsertRecord(16);//插入16条记录
table.gvUpdatePageBar("select count(*) from " + TABLE_NAME,db);
table.gvReadyTable("select * from " + TABLE_NAME,db);
}else if (v == btnClose) {
table.gvRemoveAll();
db.close(); }
}
} /**
* 在内存创建数据库和数据表
*/
void CreateDB() {
// 在内存创建数据库
db = SQLiteDatabase.create(null);
Log.e("DB Path", db.getPath());
String amount = String.valueOf(databaseList().length);
Log.e("DB amount", amount);
// 创建数据表
String sql = "CREATE TABLE " + TABLE_NAME + " (" +
ID + " text not null, " + NAME + " text not null," +
ADDRESS + " text not null, " + PHONE + " text not null," +
AGE + " text not null "+");";
try {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
db.execSQL(sql);
} catch (SQLException e) {}
}
/**
* 插入N条数据
*/
void InsertRecord(int n) {
int total = id + n;
for (; id < total; id++) {
String sql = "insert into " + TABLE_NAME + " (" +
ID + ", " + NAME+", " + ADDRESS+", " + PHONE+", "+AGE
+ ") values('" + String.valueOf(id) + "', 'man','address','123456789','18');";
try {
db.execSQL(sql);
} catch (SQLException e) {
}
}
} }

分页表格控件GVTable.java的源码:

  1. package com.testSQLite;
  2. import java.util.ArrayList;
  3. import java.util.HashMap;
  4. import android.content.Context;
  5. import android.database.Cursor;
  6. import android.database.sqlite.SQLiteDatabase;
  7. import android.view.View;
  8. import android.widget.AdapterView;
  9. import android.widget.GridView;
  10. import android.widget.LinearLayout;
  11. import android.widget.SimpleAdapter;
  12. import android.widget.AdapterView.OnItemClickListener;
  13. public class GVTable extends LinearLayout {
  14. protected GridView gvTable,gvPage;
  15. protected SimpleAdapter saPageID,saTable;// 适配器
  16. protected ArrayList<HashMap<String, String>> srcPageID,srcTable;// 数据源
  17. protected int TableRowCount=10;//分页时,每页的Row总数
  18. protected int TableColCount=0;//每页col的数量
  19. protected SQLiteDatabase db;
  20. protected String rawSQL="";
  21. protected Cursor curTable;//分页时使用的Cursor
  22. protected OnTableClickListener clickListener;//整个分页控件被点击时的回调函数
  23. protected OnPageSwitchListener switchListener;//分页切换时的回调函数
  24. public GVTable(Context context) {
  25. super(context);
  26. this.setOrientation(VERTICAL);//垂直
  27. //----------------------------------------
  28. gvTable=new GridView(context);
  29. addView(gvTable, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
  30. LayoutParams.WRAP_CONTENT));//宽长式样
  31. srcTable = new ArrayList<HashMap<String, String>>();
  32. saTable = new SimpleAdapter(context,
  33. srcTable,// 数据来源
  34. R.layout.items,//XML实现
  35. new String[] { "ItemText" },// 动态数组与ImageItem对应的子项
  36. new int[] { R.id.ItemText });
  37. // 添加并且显示
  38. gvTable.setAdapter(saTable);
  39. gvTable.setOnItemClickListener(new OnItemClickListener(){
  40. @Override
  41. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
  42. long arg3) {
  43. int y=arg2/curTable.getColumnCount()-1;//标题栏的不算
  44. int x=arg2 % curTable.getColumnCount();
  45. if (clickListener != null//分页数据被点击
  46. && y!=-1) {//点中的不是标题栏时
  47. clickListener.onTableClickListener(x,y,curTable);
  48. }
  49. }
  50. });
  51. //----------------------------------------
  52. gvPage=new GridView(context);
  53. gvPage.setColumnWidth(40);//设置每个分页按钮的宽度
  54. gvPage.setNumColumns(GridView.AUTO_FIT);//分页按钮数量自动设置
  55. addView(gvPage, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
  56. LayoutParams.WRAP_CONTENT));//宽长式样
  57. srcPageID = new ArrayList<HashMap<String, String>>();
  58. saPageID = new SimpleAdapter(context,
  59. srcPageID,// 数据来源
  60. R.layout.items,//XML实现
  61. new String[] { "ItemText" },// 动态数组与ImageItem对应的子项
  62. new int[] { R.id.ItemText });
  63. // 添加并且显示
  64. gvPage.setAdapter(saPageID);
  65. // 添加消息处理
  66. gvPage.setOnItemClickListener(new OnItemClickListener(){
  67. @Override
  68. public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
  69. long arg3) {
  70. LoadTable(arg2);//根据所选分页读取对应的数据
  71. if(switchListener!=null){//分页切换时
  72. switchListener.onPageSwitchListener(arg2,srcPageID.size());
  73. }
  74. }
  75. });
  76. }
  77. /**
  78. * 清除所有数据
  79. */
  80. public void gvRemoveAll()
  81. {
  82. if(this.curTable!=null)
  83. curTable.close();
  84. srcTable.clear();
  85. saTable.notifyDataSetChanged();
  86. srcPageID.clear();
  87. saPageID.notifyDataSetChanged();
  88. }
  89. /**
  90. * 读取指定ID的分页数据,返回当前页的总数据
  91. * SQL:Select * From TABLE_NAME Limit 9 Offset 10;
  92. * 表示从TABLE_NAME表获取数据,跳过10行,取9行
  93. * @param pageID 指定的分页ID
  94. */
  95. protected void LoadTable(int pageID)
  96. {
  97. if(curTable!=null)//释放上次的数据
  98. curTable.close();
  99. String sql= rawSQL+" Limit "+String.valueOf(TableRowCount)+ " Offset " +String.valueOf(pageID*TableRowCount);
  100. curTable = db.rawQuery(sql, null);
  101. gvTable.setNumColumns(curTable.getColumnCount());//表现为表格的关键点!
  102. TableColCount=curTable.getColumnCount();
  103. srcTable.clear();
  104. // 取得字段名称
  105. int colCount = curTable.getColumnCount();
  106. for (int i = 0; i < colCount; i++) {
  107. HashMap<String, String> map = new HashMap<String, String>();
  108. map.put("ItemText", curTable.getColumnName(i));
  109. srcTable.add(map);
  110. }
  111. // 列举出所有数据
  112. int recCount=curTable.getCount();
  113. for (int i = 0; i < recCount; i++) {//定位到一条数据
  114. curTable.moveToPosition(i);
  115. for(int ii=0;ii<colCount;ii++)//定位到一条数据中的每个字段
  116. {
  117. HashMap<String, String> map = new HashMap<String, String>();
  118. map.put("ItemText", curTable.getString(ii));
  119. srcTable.add(map);
  120. }
  121. }
  122. saTable.notifyDataSetChanged();
  123. }
  124. /**
  125. * 设置表格的最多显示的行数
  126. * @param row 表格的行数
  127. */
  128. public void gvSetTableRowCount(int row)
  129. {
  130. TableRowCount=row;
  131. }
  132. /**
  133. * 取得表格的最大行数
  134. * @return 行数
  135. */
  136. public int gvGetTableRowCount()
  137. {
  138. return TableRowCount;
  139. }
  140. /**
  141. * 取得当前分页的Cursor
  142. * @return 当前分页的Cursor
  143. */
  144. public Cursor gvGetCurrentTable()
  145. {
  146. return curTable;
  147. }
  148. /**
  149. * 准备分页显示数据
  150. * @param rawSQL sql语句
  151. * @param db 数据库
  152. */
  153. public void gvReadyTable(String rawSQL,SQLiteDatabase db)
  154. {
  155. this.rawSQL=rawSQL;
  156. this.db=db;
  157. }
  158. /**
  159. * 刷新分页栏,更新按钮数量
  160. * @param sql SQL语句
  161. * @param db 数据库
  162. */
  163. public void gvUpdatePageBar(String sql,SQLiteDatabase db)
  164. {
  165. Cursor rec = db.rawQuery(sql, null);
  166. rec.moveToLast();
  167. long recSize=rec.getLong(0);//取得总数
  168. rec.close();
  169. int pageNum=(int)(recSize/TableRowCount) + 1;//取得分页数
  170. srcPageID.clear();
  171. for (int i = 0; i < pageNum; i++) {
  172. HashMap<String, String> map = new HashMap<String, String>();
  173. map.put("ItemText", "No." + String.valueOf(i));// 添加图像资源的ID
  174. srcPageID.add(map);
  175. }
  176. saPageID.notifyDataSetChanged();
  177. }
  178. //---------------------------------------------------------
  179. /**
  180. * 表格被点击时的回调函数
  181. */
  182. public void setTableOnClickListener(OnTableClickListener click) {
  183. this.clickListener = click;
  184. }
  185. public interface OnTableClickListener {
  186. public void onTableClickListener(int x,int y,Cursor c);
  187. }
  188. //---------------------------------------------------------
  189. /**
  190. * 分页栏被点击时的回调函数
  191. */
  192. public void setOnPageSwitchListener(OnPageSwitchListener pageSwitch) {
  193. this.switchListener = pageSwitch;
  194. }
  195. public interface OnPageSwitchListener {
  196. public void onPageSwitchListener(int pageID,int pageCount);
  197. }
  198. }

Android提高第九篇之GridView和SQLite实现分页表格的更多相关文章

  1. Android提高21篇之二:SurfaceView的基本使用方法

    上次介绍MediaPlayer的时候稍微介绍了SurfaceView,SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,这次我就用两篇文章来介绍Su ...

  2. Android提高第二篇之SurfaceView的基本使用

    本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处! 上次介绍MediaPlayer的时候略微介绍了SurfaceView,SurfaceView因为能够直接从内存 ...

  3. Android提高21篇之一:MediaPlayer

    本文介绍MediaPlayer的使用.MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用Med ...

  4. android之存储篇——SQLite数据库

    转载:android之存储篇_SQLite数据库_让你彻底学会SQLite的使用 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么. 例如:可以在In ...

  5. 第九篇 :微信公众平台开发实战Java版之如何实现自定义分享内容

    第一部分:微信JS-SDK介绍 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统 ...

  6. 第九篇 SQL Server安全透明数据加密

    本篇文章是SQL Server安全系列的第九篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...

  7. Python之路【第九篇】:Python操作 RabbitMQ、Redis、Memcache、SQLAlchemy

    Python之路[第九篇]:Python操作 RabbitMQ.Redis.Memcache.SQLAlchemy   Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用 ...

  8. 【译】第九篇 SQL Server安全透明数据加密

    本篇文章是SQL Server安全系列的第九篇,详细内容请参考原文. Relational databases are used in an amazing variety of applicatio ...

  9. ElasticSearch入门 第九篇:实现正则表达式查询的思路

    这是ElasticSearch 2.4 版本系列的第九篇: ElasticSearch入门 第一篇:Windows下安装ElasticSearch ElasticSearch入门 第二篇:集群配置 E ...

随机推荐

  1. C语言头文件、库文件的查找路径

    在 程序设计中,文件包含是很有用的.一个大的程序可以分为多个模块,由多个程序员分别编程.有些公用的符号常量或宏定义等可单独组成一个文件,在其它文件的开头用包含命令包含该文件即可使用.这样,可避免在每个 ...

  2. 用liferay实现的增删改查例子-book管理系统

    liferay 这个框架是一个开源的项目,大家可以修改源代码,来实现自己的需求.但是关于liferay的开发资料中文的很少关于liferay的基础知识,大家可以百度学习一下,再来看下边的例子 首先需要 ...

  3. c# 获取某个进程的CPU使用百分百(类似任务管理器中显示CPU)

    using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using S ...

  4. zw版【转发·台湾nvp系列Delphi例程】HALCON ConvolImage

    zw版[转发·台湾nvp系列Delphi例程]HALCON ConvolImage procedure TForm1.Button1Click(Sender: TObject);begin img.D ...

  5. python进程join()函数理解

    Join()是主程序等我这个进程执行完毕了,程序才往下走  

  6. 异常和TCP通讯

    第七章 异常处理 * 异常处理机制中的try-catch * 语法: * try{ * 代码片段 * }catch(XXXException e){ * 当try中的代码片段出现了XXXExcepti ...

  7. MySQL Crash Course #16# Chapter 24. Using Cursors + mysql 循环

    mysql中游标的使用案例详解(学习笔记)这篇讲得相当直白好懂了. 索引: cursor 基础讲解 mysql 循环 书上的整合代码 cursor 基础讲解 cursor 有点类似于 JDBC 中的 ...

  8. SACD ISO镜像中提取DSDIFF(DFF)、DSF文件

                      听语音 | 浏览:5620 | 更新:2015-08-25 11:46 | 标签:硬件 1 2 3 4 5 分步阅读 现在有一种比较流行的无损音乐传输介质是SACD ...

  9. Window系统远程连接Linux服务器(非桌面系统)

    Window系统远程连接Linux服务器(非桌面系统) Window系统远程连接Linux服务器(非桌面系统),步骤: 第一步:下载Xshell远程登录软件:第二步:设置Linux服务器的IP.端口. ...

  10. SpringCloud请求响应数据转换(一)

    异常现象 近期做Spring Cloud项目,工程中对Controller添加ResponseBodyAdvice切面,在切片中将返回的结果封装到ResultMessage(自定义结构),但在Cont ...