Android - N级树形结构实现
生活随笔
收集整理的這篇文章主要介紹了
Android - N级树形结构实现
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ? 目前已經實現3級之內的任意級樹形結構展示(如果想增加更多級,需要擴展排序算法),并支持單選和多選(使用不同的適配器)。
? ? 實現使用的控件:ListView
? ? 首先,最重要的應該是數據源的格式,支持樹形結構的數據源,每條數據應該都要指明它的父級是誰,本文為parent_org,并把每條數據都存放在一個HashMap里面。這里使用的除了parent_org(父營業部),還有org_name(營業部名稱),org_code(營業部編號)。
? ? 其次,對數據進行排序。因為只使用ListView實現,所以需要實現層次結構的樹形結構,需要對數據按父級->2級->3級->父級->2級->父級->2級->父級->2級->3級這樣的順序排序。
? ? 接著,實現適配器,展現樹形結構。
? ? 最后,調用適配器,并調用適配器里的方法獲取選擇結果。
排序算法:
?
/*** 查詢操作員營業部列表類* * @author xinyan* */ public class QueryIntOrgListWork extends BaseWork implements Runnable {private static final String TAG = "QueryIntOrgListWork";HashMap<String, String> params;public QueryIntOrgListWork(Context context, Map args) {super(context, args);}public QueryIntOrgListWork(Context context, View layoutView, Map args) {super(context, layoutView, args);}@Overridepublic void work() {params = new HashMap<String, String>();AppState appState = AppState.getState();BrokerInfo brokerInfo = appState.getBrokerInfo();// params.put("uuid", brokerInfo.getUuid());Utils.putUuid(params);params.put("funcno", "20017");params.put("org_type", "0");params.put("right_flag", "1");try {HttpFactory httpFactory = new HttpFactory();byte[] bytes = httpFactory.send(Configuration.getString("system.http"), params,HttpFactory.POST);if (bytes == null) {return;}String result = new String(bytes,Configuration.getString("system.charSet"));JSONObject jsonObject = new JSONObject(result);// 增加登錄過期或賬號已在其他地方登錄的處理try {String strPrompt = jsonObject.getString("errorInfo");String strErrorNo = jsonObject.getString("errorNo");if (!StringHelper.isEmpty(strPrompt)) {if (strPrompt.contains("未登")|| strPrompt.contains("其它地方登陸")) {sendMessage(new LoginExpiredUiWork(null));return;}}// 如果訪問接口異常,提示信息if (!strErrorNo.equals("0")) {HashMap<String, String> param = new HashMap<String, String>();if (null != strPrompt) {param.put("errorInfo", "調用查詢操作員機構列表接口:" + strPrompt);} else {param.put("errorInfo", "");}sendMessage(new CallInterfaceExceptionUiWork(param));if ("-111".equals(strErrorNo) || "-110".equals(strErrorNo)|| "-2008000".equals(strErrorNo)) {return;}}} catch (Exception e) {}String errorNo = jsonObject.getString("errorNo");if (errorNo.equals("-1")) {String errorInfo = jsonObject.getString("errorInfo");Map<String, String> map = new HashMap<String, String>();map.put("errorNo", "-1");map.put("errorInfo", errorInfo);} else if (errorNo.equals("-999")) {Intent intent = new Intent("com.thinkive.action.MAIN");context.startActivity(intent);} else if (errorNo.equals("0")) {JSONArray array = jsonObject.getJSONArray("results");ArrayList<HashMap<String, Object>> dataList = new ArrayList<HashMap<String, Object>>();HashMap<String, Object> dataItem = null;for (int i = 0; i < array.length(); i++) {dataItem = new HashMap<String, Object>();JSONObject item = array.getJSONObject(i);String org_name = item.getString("org_name");// String area_addr = item.getString("area_addr");//// String org_type = item.getString("org_type");// String right_flag = item.getString("right_flag");// String zip_code = item.getString("zip_code");// String acct_len = item.getString("acct_len");String org_code = item.getString("org_code");// String acct_prefix = item.getString("acct_prefix");// String org_full_name = item.getString("org_full_name");String parent_org = item.getString("parent_org");// String area_no = item.getString("area_no");// String org_status = item.getString("org_status");// String org_cls = item.getString("org_cls");dataItem.put("org_name", org_name);dataItem.put("org_code", org_code);dataItem.put("parent_org", parent_org);dataList.add(dataItem);}AppState.getState().getBrokerInfo().setIntOrgs(regroupData(dataList));}} catch (Exception e) {e.printStackTrace();}}/*** 對數據根據子父級關系進行重組*/private List<HashMap<String, Object>> regroupData(List<HashMap<String, Object>> dataList) {HashMap<String, Object> item = null;ArrayList<HashMap<String, Object>> regroupedDataList = null;for (int i = 0; i < dataList.size(); i++) {item = dataList.get(i);String strOrg = item.get("org_code").toString();String strParentOrg = item.containsKey("parent_org") ? item.get("parent_org").toString() : "";// 如果沒有父營業部,遍歷列表是否存在子營業部if (StringHelper.isEmpty(strParentOrg)) {HashMap<String, Object> item2 = null;ArrayList<HashMap<String, Object>> childList = null;// 遍歷列表是否存在子營業部for (int j = 0; j < dataList.size(); j++) {if (i == j) {continue;}item2 = dataList.get(j);// 列表存在子營業部if (strOrg.equals(item2.get("parent_org"))) {childList = new ArrayList<HashMap<String, Object>>();if (null != item2.get("child")) {// 如果該營業部的子營業部還存在子營業部,那么此營業部是1級,最高級item2.put("org_level", "1");} else {// 如果該營業部的子營業部不存在子營業部,那么將此營業部暫定為2級item2.put("org_level", "2");}childList.add(item2);}// end if}// end foritem.put("child", childList);} else {// 如果有父營業部HashMap<String, Object> parentOrgItem = null;boolean isParentOrgExist = false;// 首先檢查列表是否存在父營業部for (int j = 0; j < dataList.size(); j++) {if (i == j) {continue;}parentOrgItem = dataList.get(j);// 列表存在父營業部if (strParentOrg.equals(parentOrgItem.get("org_code"))) {isParentOrgExist = true;// 加入當前營業部到該父營業部的子營業部列表,標記當前項為2級營業部item.put("org_level", "2");ArrayList<HashMap<String, Object>> childList = null;if (null != parentOrgItem.get("child")) {childList = (ArrayList<HashMap<String, Object>>) parentOrgItem.get("child");} else {childList = new ArrayList<HashMap<String, Object>>();}// 檢查子營業部列表是否已經存在該營業部boolean isOrgExist = false;if (childList.size() > 0) {HashMap<String, Object> childItem = null;for (int k = 0; k < childList.size(); k++) {childItem = (HashMap<String, Object>) childList.get(k);if (childItem.get("org_code").toString().equals(item.get("org_code"))) {isOrgExist = true;}}}if (!isOrgExist) {childList.add(item);parentOrgItem.put("child", childList);}break;}// end if}// end for// 檢查完了是否存在父營業部之后,再檢查列表是否存在該營業部的子營業部HashMap<String, Object> childOrgItem = null;ArrayList<HashMap<String, Object>> childList = new ArrayList<HashMap<String, Object>>();// 遍歷列表是否存在子營業部for (int k = 0; k < dataList.size(); k++) {if (i == k) {continue;}childOrgItem = dataList.get(k);// 列表存在子營業部if (strOrg.equals(childOrgItem.get("parent_org"))) {if (null != childOrgItem.get("child")) {// 如果該營業部的子營業部還存在子營業部,那么此營業部是1級,最高級childOrgItem.put("org_level", "1");} else {// 如果該營業部的子營業部不存在子營業部,那么將此營業部暫定為2級childOrgItem.put("org_level", "2");}childList.add(childOrgItem);}// end if}// end forif (childList.size() > 0) {item.put("child", childList);// 如果當前營業部存在父營業部和子營業部,那么就是2級if (isParentOrgExist) {item.put("org_level", "2");} else {// 不存在父營業部,那么是1級item.put("org_level", "1");}} else {// 不存在子營業部if (isParentOrgExist) {// 不存在子營業部,但存在父營業部,那么是2級item.put("org_level", "2");} else {// 不存在子營業部和父營業部,那么是1級item.put("org_level", "1");}}}// end else}// end for// 當數據按數學結構組織好之后,按順序排列為列表,以便在listview里顯示regroupedDataList = new ArrayList<HashMap<String, Object>>();HashMap<String, Object> tempItem = null;for (int i = 0; i < dataList.size(); i++) {tempItem = dataList.get(i);if ("1".equals(tempItem.get("org_level").toString())) {regroupedDataList.add(tempItem);// 把子營業部加入到重組后的列表if (tempItem.containsKey("child")) {ArrayList<HashMap<String, Object>> childList = (ArrayList<HashMap<String, Object>>) tempItem.get("child");HashMap<String, Object> childItem = null;if (childList.size() > 0) {for (int j = 0; j < childList.size(); j++) {childItem = (HashMap<String, Object>) childList.get(j);regroupedDataList.add(childItem);// 檢查子營業部是否還有子營業部if (childItem.containsKey("child")) {ArrayList<HashMap<String, Object>> childList2 = (ArrayList<HashMap<String, Object>>) childItem.get("child");HashMap<String, Object> childItem2 = null;if (childList2.size() > 0) {for (int k = 0; k < childList2.size(); k++) {childItem2 = (HashMap<String, Object>) childList2.get(k);regroupedDataList.add(childItem2);}// end for}// end if}// end if}// end for}// end if}// end if}// end if}// end forfor (int i = 0; i < regroupedDataList.size(); i++) {if (regroupedDataList.get(i).containsKey("child")) {regroupedDataList.get(i).remove("child");}}// 父級、子級都得排序Log.i(TAG, "重組前的營業部數據" + dataList);Log.i(TAG, "重組后的營業部數據" + regroupedDataList);return regroupedDataList;}@Overridepublic void run() {work();}}?
?
多選營業部樹形列表適配器:?
?
?
/*** 多選營業部樹形列表適配器* * @author xinyan* @date 2013-5-27*/ public class MultiCheckIntOrgListAdapter extends BaseAdapter {public static final String TAG = "MultiCheckIntOrgListAdapter";public static final String CHECKED_TRUE = "1";public static final String CHECKED_FALSE = "0";public static final String IS_CHECKED = "IS_CHECKED";private List<HashMap<String, Object>> mDataList;private LayoutInflater mInflater;public MultiCheckIntOrgListAdapter(Context context,List<HashMap<String, Object>> dataList) {this.mInflater = LayoutInflater.from(context);mDataList = dataList;setDefaultChecked();}@Overridepublic int getCount() {return mDataList.size();}@Overridepublic Object getItem(int position) {return mDataList.get(position);}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder = null;final HashMap<String, Object> dataItem = mDataList.get(position);if (null == convertView) {holder = new ViewHolder();convertView = mInflater.inflate(R.layout.lv_item_tree_structure,null);holder.cb = (CheckBox) convertView.findViewById(R.id.lv_item_tree_structure_cb);holder.text = (TextView) convertView.findViewById(R.id.lv_item_tree_structure_text);holder.joinBottom = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_join_bottom);holder.leaf = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_leaf);holder.joinBottom2 = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_join_bottom2);holder.leaf2 = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_leaf2);holder.tree = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_tree);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.tree.setVisibility(View.GONE);holder.joinBottom.setVisibility(View.GONE);holder.leaf.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);// 如果是父級if ("1".equals(dataItem.get("org_level"))) {holder.tree.setVisibility(View.VISIBLE);holder.joinBottom.setVisibility(View.GONE);holder.leaf.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);} else if ("2".equals(dataItem.get("org_level"))) {// 如果是子級holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);holder.tree.setVisibility(View.GONE);holder.joinBottom.setVisibility(View.VISIBLE);holder.leaf.setVisibility(View.VISIBLE);} else { // 3級holder.tree.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.VISIBLE);holder.leaf2.setVisibility(View.VISIBLE);holder.joinBottom.setVisibility(View.VISIBLE);holder.leaf.setVisibility(View.VISIBLE);}try {holder.text.setText(dataItem.get("org_code").toString() + " "+ dataItem.get("org_name").toString());} catch (Exception e) {}final CheckBox cb = holder.cb;if (CHECKED_TRUE.equals(dataItem.get(IS_CHECKED))) {cb.setChecked(true);} else {cb.setChecked(false);}convertView.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (MotionEvent.ACTION_DOWN == event.getAction()) {if (cb.isChecked()) {cb.setChecked(false);dataItem.put(IS_CHECKED, CHECKED_FALSE);} else {cb.setChecked(true);dataItem.put(IS_CHECKED, CHECKED_TRUE);}if ("1".equals(dataItem.get("org_level").toString())) {// 遍歷子營業部HashMap<String, Object> item = null;for (int i = position + 1; i < mDataList.size(); i++) {item = mDataList.get(i);if ("2".equals(item.get("org_level"))|| "3".equals(item.get("org_level"))) {if (cb.isChecked()) {item.put(IS_CHECKED, CHECKED_TRUE);} else {item.put(IS_CHECKED, CHECKED_FALSE);}} else if ("1".equals(item.get("org_level"))) {break;}// end else if}// end fornotifyDataSetChanged();}// end ifelse if ("2".equals(dataItem.get("org_level").toString())) {// 遍歷子營業部HashMap<String, Object> item = null;for (int i = position + 1; i < mDataList.size(); i++) {item = mDataList.get(i);if ("3".equals(item.get("org_level"))) {if (cb.isChecked()) {item.put(IS_CHECKED, CHECKED_TRUE);} else {item.put(IS_CHECKED, CHECKED_FALSE);}} else if ("1".equals(item.get("org_level"))) {break;}// end else if}// end fornotifyDataSetChanged();}// end else ifreturn true;}return false;}});return convertView;}/*** 拿到已選擇營業部的代碼字符串,代碼之間逗號分隔* * @return*/public String getSelectedOrgCodes() {StringBuilder sbOrgCodes = new StringBuilder();for (int i = 0; i < mDataList.size(); i++) {if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) {if (sbOrgCodes.length() <= 2) {sbOrgCodes.append(mDataList.get(i).get("org_code").toString());} else {sbOrgCodes.append(","+ mDataList.get(i).get("org_code").toString());}// end else}// end if}// end forLog.i(TAG, "getSelectedOrgCodes: " + sbOrgCodes.toString());return sbOrgCodes.toString();}/*** 拿到已選擇的營業部(org_code+org_name)* * @return*/public String getSelectedOrg() {StringBuilder sbOrg = new StringBuilder();for (int i = 0; i < mDataList.size(); i++) {if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) {String strText = mDataList.get(i).get("org_code").toString()+ " " + mDataList.get(i).get("org_name").toString();if (sbOrg.length() <= 2) {sbOrg.append(strText);} else {sbOrg.append("," + strText);}// end else}// end if}// end forLog.i(TAG, "getSelectedOrg: " + sbOrg.toString());return sbOrg.toString();}/*** 默認全部選中*/private void setDefaultChecked() {for (int i = 0; i < mDataList.size(); i++) {mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE);}}class ViewHolder {TextView text;CheckBox cb;ImageView tree;// 樹形圖ImageView joinBottom;// 連接線ImageView leaf;// 子節點圖ImageView joinBottom2;// 3級連接線ImageView leaf2;// 3級子節點圖}}?
?單選營業部樹形列表適配器
?
/*** 單選營業部樹形列表適配器* * @author xinyan* @date 2013-5-27*/ public class SingleChoiceIntOrgListAdapter extends BaseAdapter {public static final String TAG = "SingleChoiceIntOrgListAdapter";public static final String CHECKED_TRUE = "1";public static final String CHECKED_FALSE = "0";public static final String IS_CHECKED = "IS_CHECKED";private List<HashMap<String, Object>> mDataList;private LayoutInflater mInflater;public SingleChoiceIntOrgListAdapter(Context context,List<HashMap<String, Object>> dataList) {this.mInflater = LayoutInflater.from(context);mDataList = dataList;}@Overridepublic int getCount() {return mDataList.size();}@Overridepublic Object getItem(int position) {return mDataList.get(position);}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder = null;final HashMap<String, Object> dataItem = mDataList.get(position);if (null == convertView) {holder = new ViewHolder();convertView = mInflater.inflate(R.layout.lv_item_tree_structure_single_choice, null);holder.cb = (CheckBox) convertView.findViewById(R.id.lv_item_tree_structure_cb);holder.text = (TextView) convertView.findViewById(R.id.lv_item_tree_structure_text);holder.joinBottom = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_join_bottom);holder.leaf = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_leaf);holder.joinBottom2 = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_join_bottom2);holder.leaf2 = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_leaf2);holder.tree = (ImageView) convertView.findViewById(R.id.lv_item_tree_structure_tree);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.tree.setVisibility(View.GONE);holder.joinBottom.setVisibility(View.GONE);holder.leaf.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);// 如果是父級if ("1".equals(dataItem.get("org_level"))) {holder.tree.setVisibility(View.VISIBLE);holder.joinBottom.setVisibility(View.GONE);holder.leaf.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);} else if ("2".equals(dataItem.get("org_level"))) {// 如果是子級holder.joinBottom2.setVisibility(View.GONE);holder.leaf2.setVisibility(View.GONE);holder.tree.setVisibility(View.GONE);holder.joinBottom.setVisibility(View.VISIBLE);holder.leaf.setVisibility(View.VISIBLE);} else { // 3級holder.tree.setVisibility(View.GONE);holder.joinBottom2.setVisibility(View.VISIBLE);holder.leaf2.setVisibility(View.VISIBLE);holder.joinBottom.setVisibility(View.VISIBLE);holder.leaf.setVisibility(View.VISIBLE);}try {holder.text.setText(dataItem.get("org_code").toString() + " "+ dataItem.get("org_name").toString());} catch (Exception e) {}convertView.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (MotionEvent.ACTION_DOWN == event.getAction()) {dataItem.put(IS_CHECKED, CHECKED_TRUE);// 把其它的營業部設置為falsefor (int i = 0; i < mDataList.size(); i++) {if (i == position) {continue;} else {mDataList.get(i).put(IS_CHECKED, CHECKED_FALSE);}}}return false;}});return convertView;}/*** 拿到已選擇營業部的代碼字符串,代碼之間逗號分隔* * @return*/public String getSelectedOrgCodes() {StringBuilder sbOrgCodes = new StringBuilder();for (int i = 0; i < mDataList.size(); i++) {if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) {if (sbOrgCodes.length() <= 2) {sbOrgCodes.append(mDataList.get(i).get("org_code").toString());} else {sbOrgCodes.append(","+ mDataList.get(i).get("org_code").toString());}// end else}// end if}// end forLog.i(TAG, "getSelectedOrgCodes: " + sbOrgCodes.toString());return sbOrgCodes.toString();}/*** 拿到已選擇的營業部(org_code+org_name)* * @return*/public String getSelectedOrg() {StringBuilder sbOrg = new StringBuilder();for (int i = 0; i < mDataList.size(); i++) {if (mDataList.get(i).get(IS_CHECKED).equals(CHECKED_TRUE)) {String strText = mDataList.get(i).get("org_code").toString()+ " " + mDataList.get(i).get("org_name").toString();if (sbOrg.length() <= 2) {sbOrg.append(strText);} else {sbOrg.append("," + strText);}// end else}// end if}// end forLog.i(TAG, "getSelectedOrg: " + sbOrg.toString());return sbOrg.toString();}/*** 默認全部選中*/private void setDefaultChecked() {for (int i = 0; i < mDataList.size(); i++) {mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE);}}/*** 設置默認選中的營業部* * @param orgCode*/public void setDefaultChecked(String orgCode) {for (int i = 0; i < mDataList.size(); i++) {if (orgCode.contains(mDataList.get(i).get("org_code").toString())) {mDataList.get(i).put(IS_CHECKED, CHECKED_TRUE);} else {// 因為查詢框里使用的多選營業部框跟這里使用的一個數據源,// 為了避免其它地方對這造成的影響,所以全部初始化好mDataList.get(i).put(IS_CHECKED, CHECKED_FALSE);}}}class ViewHolder {TextView text;CheckBox cb;ImageView tree;// 樹形圖ImageView joinBottom;// 連接線ImageView leaf;// 子節點圖ImageView joinBottom2;// 3級連接線ImageView leaf2;// 3級子節點圖}}?
ListView的item布局
?
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal" ><ImageViewandroid:id="@+id/lv_item_tree_structure_tree"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center_vertical"android:scaleType="fitXY"android:src="@drawable/customer_account_mgr"android:visibility="gone" /><ImageViewandroid:id="@+id/lv_item_tree_structure_join_bottom"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center_vertical"android:scaleType="fitXY"android:src="@drawable/joinbottom"android:visibility="gone" /><ImageViewandroid:id="@+id/lv_item_tree_structure_leaf"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center_vertical"android:scaleType="fitXY"android:src="@drawable/leaf"android:visibility="gone" /><ImageViewandroid:id="@+id/lv_item_tree_structure_join_bottom2"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center_vertical"android:scaleType="fitXY"android:src="@drawable/joinbottom"android:visibility="gone" /><ImageViewandroid:id="@+id/lv_item_tree_structure_leaf2"android:layout_width="20dp"android:layout_height="20dp"android:layout_gravity="center_vertical"android:scaleType="fitXY"android:src="@drawable/leaf"android:visibility="gone" /><CheckBoxandroid:id="@+id/lv_item_tree_structure_cb"style="@style/custom_checkbox"android:layout_width="30dp"android:layout_height="30dp"android:layout_gravity="center_vertical"android:layout_marginLeft="5dp"android:clickable="false" /><TextViewandroid:id="@+id/lv_item_tree_structure_text"android:layout_width="400dp"android:layout_height="40dp"android:gravity="center_vertical"android:paddingLeft="10dp"android:textColor="@color/black"android:textSize="20sp" /> </LinearLayout>?
父級標志圖
子級標志圖
父級和子級的連接線
?
總結
以上是生活随笔為你收集整理的Android - N级树形结构实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tomcat请求数据的编码设置
- 下一篇: Python中metaclass解释