MyBatis 自动生成代码

最近做一个项目是MyBatis的数据持久层,需要生成大量的实体类和配置文件。

特做分享。

操作

生产实体类:

只需配置tablename属性即可

private String tablename = "bid_clarify";//表名
private String[] colnames; // 列名数组
private String[] colTypes; //列名类型数组
private int[] colSizes; //列名大小数组
private boolean f_util = true; // 是否需要导入包java.util.*
private boolean f_sql = true; // 是否需要导入包java.sql.*

//数据库连接  
private static final String URL ="jdbc:oracle:thin:@192.168.0.160:1521:ORCL";  
private static final String NAME = "jdbc.username";  
private static final String PASS = "jdbc.password";  
private static final String DRIVER ="oracle.jdbc.driver.OracleDriver";
 

package work;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;

/**
 *  Product
 *  根据数据库生成mybatis的配置文件(包含增删改查SQL) 
 * 
 * @author qliu 日期:2016-10-10
 */
public class GenSQLXMLOracle {

	private String tablename = "bid_clarify";// 表名
	private String domianDao = "cn.com.aostarit.ecp.bid.dao.BidClarifyDao";
	private String domain = "BidClarify";
	private String domainAttr = "bidClarify";

	private String[] colnames; // 列名数组
	private String[] colTypes; // 列名类型数组
	private int[] colSizes; // 列名大小数组

	// 数据库连接
	private static final String URL = "jdbc:oracle:thin:@192.168.0.160:1521:ORCL";
	private static final String NAME = "ecp_dev";
	private static final String PASS = "ecp2016";
	private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";

	/*
	 * 构造函数
	 */
	public GenSQLXMLOracle() {
		// 创建连接
		Connection con;
		// 查要生成实体类的表
		String sql = "select * from " + tablename;
		PreparedStatement pStemt = null;
		try {
			try {
				Class.forName(DRIVER);
			} catch (ClassNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			con = DriverManager.getConnection(URL, NAME, PASS);
			pStemt = con.prepareStatement(sql);
			ResultSetMetaData rsmd = pStemt.getMetaData();
			int size = rsmd.getColumnCount(); // 统计列
			colnames = new String[size];
			colTypes = new String[size];
			colSizes = new int[size];
			for (int i = 0; i < size; i++) {
				colnames[i] = rsmd.getColumnName(i + 1);
				colTypes[i] = rsmd.getColumnTypeName(i + 1);
			}
				String content = parse(colnames, colTypes, colSizes);

				try {
					File directory = new File("");

					String fileName = directory.getAbsolutePath() + "/src/" + domain
							+ "Dao.xml";
					System.out.println(fileName);
					FileWriter fw = new FileWriter(fileName);
					PrintWriter pw = new PrintWriter(fw);
					pw.println(content);
					pw.flush();
					pw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			// try {
			// con.close();
			// } catch (SQLException e) {
			// // TODO Auto-generated catch block
			// e.printStackTrace();
			// }
		}
	}

	/**
	 * 功能:生成实体类Dao的主要Mapper文件
	 * 
	 * @param colnames
	 * @param colTypes
	 * @param colSizes
	 * @return
	 */
	private String parse(String[] colnames, String[] colTypes, int[] colSizes) {
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
		sb.append(
				" <!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");

		sb.append("<mapper namespace=\"" + domianDao + "\">\n");
		sqlColumns(sb);
		getSQL(sb);
		findById(sb);
		findbySQL(sb);
		whereCondition(sb);
		insertSQL(sb);
		updateSQL(sb);
		delSQL(sb);
		sb.append("	 	</update>\n");
		sb.append("	 </mapper>\n");
		return sb.toString();
	}

	private void sqlColumns(StringBuffer sb) {
		sb.append("<sql id=\"" + domainAttr + "Columns\">\n");
		String column=processAllColumn().trim();
		column=	column.substring(0,column.length()-1);
		sb.append(column);
		sb.append("</sql>\n");
	}

	private void getSQL(StringBuffer sb) {
		sb.append("<select id=\"get\" resultType=\""+domain+"\">\n");
		sb.append("SELECT \n");
		sb.append("<include refid=\"" + domainAttr + "Columns\" />\n");
		sb.append("		FROM " + tablename + "   a\n");
		sb.append("		WHERE a.id = #{id,jdbcType=BIGINT}\n");
		sb.append("			</select>\n");
	}

	private void findById(StringBuffer sb) {
		sb.append("						 	<select id=\"findById\" resultType=\"" + domain
				+ "\" parameterType=\"java.lang.Long\">\n");
		sb.append("	SELECT\n");
		sb.append("	<include refid=\"" + domainAttr + "Columns\" />\n");
		sb.append("		FROM " + tablename + " a\n");
		sb.append("		WHERE a.id = #{id,jdbcType=BIGINT}\n");
		sb.append("	 	</select>\n");
	}

	private void findbySQL(StringBuffer sb) {
		sb.append("	 <select id=\"findBy\" resultType=\"Role\" parameterType=\"Role\">\n");
		sb.append("	 SELECT\n");
		sb.append("	 	<include refid=\"roleColumns\" />\n");
		sb.append("	 FROM ecp_sys_role a\n");
		sb.append("	 	<include refid=\"whereCondition\" />\n");
		sb.append("		ORDER BY ID DESC\n");
		sb.append("	</select>\n\n");
	}

	private void whereCondition(StringBuffer sb) {
		sb.append("	<sql id=\"whereCondition\"> \n");
		sb.append("	<where>\n");
		
		for (int i = 0; i < colnames.length; i++) {
			String attri = initAttrcap(colnames[i].toLowerCase());	
			if(colTypes[i].equals("VARCHAR2") ){
				sb.append("	 	<if test=\""+attri+" != null and "+attri+" != ''\">\n");				
				sb.append("	 "+colnames[i]+" = #{"+attri+",jdbcType=VARCHAR}\n");				
				sb.append("	 </if>\n");
			}else if(colTypes[i].equals("CHAR")) {
				sb.append("	 	<if test=\""+attri+" != null \">\n");				
				sb.append("	 "+colnames[i]+" = #{"+attri+",jdbcType=CHAR} \n");				
				sb.append("	 </if>\n");
			}else if(colTypes[i].equals("TIMESTAMP")) {
				sb.append("	 	<if test=\""+attri+" != null \">\n");				
				sb.append("	"+colnames[i]+" = #{"+attri+",jdbcType=TIMESTAMP}\n");				
				sb.append("	 </if>\n");
			}else if(colTypes[i].equals("NUMBER")) {
				if(colnames[i].toLowerCase().contains("id")){
					sb.append("	 	<if test=\""+attri+" != null \">\n");				
					sb.append("	 "+colnames[i]+" = #{"+attri+",jdbcType=BIGINT}\n");				
					sb.append("	 </if>\n");
				}else {
					sb.append("	 	<if test=\""+attri+" != null \">\n");				
					sb.append("	 "+colnames[i]+" = #{"+attri+",jdbcType=NUMBER}\n");				
					sb.append("	 </if>\n");
				}
			}
			boolean timeAndBy = attri.equals("createBy")||attri.equals("createDate")||attri.equals("updateBy")||attri.equals("updateDate");
			if(timeAndBy){
				continue;
			}
		}
		sb.append("<if test=\"createBy != null and createBy != ''\">\n");
		sb.append("		AND CREATE_BY = #{createBy,jdbcType=VARCHAR}\n");
		sb.append("</if>\n");
		sb.append("	<if test=\"createDate != null\">\n");
		sb.append("		AND TO_CHAR(CREATE_DATE, 'yyyy-mm-dd') =\n");
		sb.append("		TO_CHAR(#{createDate,jdbcType=TIMESTAMP}, 'yyyy-mm-dd')\n");
		sb.append("	</if>\n");
		sb.append("<if test=\"updateBy != null and updateBy != ''\">\n");
		sb.append("	AND UPDATE_BY = #{updateBy,jdbcType=VARCHAR}\n");
		sb.append("	</if>\n");
		sb.append("<if test=\"updateDate != null\">\n");
		sb.append("	AND UPDATE_DATE = #{updateDate,jdbcType=TIMESTAMP}\n");
		sb.append("</if>\n");
		sb.append("	</where>\n");
		sb.append("	</sql>\n\n");
	}

	private void insertSQL(StringBuffer sb) {
		sb.append("	<insert id=\"save\" parameterType=\""+domain+"\">\n");
		sb.append("		<selectKey resultType=\"java.lang.Long\" order=\"BEFORE\"\n");
		sb.append("		keyProperty=\"id\">\n");
		sb.append("		SELECT ECP_MENU_ID_SEQ.nextval AS id FROM dual\n");
		sb.append("	</selectKey>\n");
		sb.append("		INSERT INTO " + tablename + "(\n");		
		sb.append(getAllColumn());	
		sb.append("			) VALUES (\n");
		sb.append(getAllColumnValue());
		sb.append("			)\n");
		sb.append("		 	</insert>\n");
	}

	private void delSQL(StringBuffer sb) {
		sb.append("	 	<update id=\"deleteById\" parameterType=\"java.lang.Long\">\n");
		sb.append("			delete from " + tablename + "\n");
		sb.append("			WHERE id = #{id,jdbcType=BIGINT}\n");
	}

	private void updateSQL(StringBuffer sb) {
		sb.append("	<update id=\"update\">\n");
		sb.append("	UPDATE " + tablename + " SET\n");
		sb.append(getAllColumnSetValue());
		sb.append("			WHERE id = #{id,jdbcType=BIGINT}\n");
		sb.append("		</update>\n");
		
		sb.append("		<update id=\"updateById\" parameterType=\"" + domain + "\">\n");
		sb.append("			UPDATE  " + tablename + " SET\n");
		sb.append(getAllColumnSetValue());
		sb.append("			WHERE id = #{id,jdbcType=BIGINT}\n");
		sb.append("		</update>\n");
	}

	/**
	 * 功能:生成所有属性
	 * 
	 * @param sb
	 */
	private void processAllAttrs(StringBuffer sb) {
		for (int i = 0; i < colnames.length; i++) {
			sb.append("\t  " + sqlType2JavaType(colTypes[i]) + " " + initAttrcap(colnames[i].toLowerCase()) + ";\r\n");
		}

	}

/**
 * 获取查询列
 * @return
 */
	private String processAllColumn() {
        StringBuilder sb = new StringBuilder();
		for (int i = 0; i < colnames.length; i++) {
			String attri = initAttrcap(colnames[i].toLowerCase());
			if (!colnames[i].toLowerCase().equals(attri)) {
				sb.append("\t  a." + colnames[i] + " AS "+  attri + ",\r\n");
			} else {
				sb.append("\t  a." + colnames[i] + ",\r\n");
			}
		}
		return sb.toString();
	}
	
	private String getAllColumnValue() {
        StringBuilder sb = new StringBuilder();
		for (int i = 0; i < colnames.length; i++) {		
			String attri = initAttrcap(colnames[i].toLowerCase());
				sb.append("#{" +attri + ",jdbcType="+colTypes[i]+"},\r\n");
		}
		String columns=sb.toString();
		columns=	columns.substring(0,columns.lastIndexOf(","));
		return columns;
	}
	
	private String getAllColumnSetValue() {
        StringBuilder sb = new StringBuilder();
		for (int i = 0; i < colnames.length; i++) {
			if(colnames[i].toLowerCase().equals("id")){
				continue;
			}
			String attri = initAttrcap(colnames[i].toLowerCase());
				sb.append(colnames[i]+" = #{" +attri + ",jdbcType="+sqlType2JDBCType(colTypes[i])+"},\r\n");
		}
		String columns=sb.toString();
		columns=	columns.substring(0,columns.lastIndexOf(","));
		return columns;
	}
	
	private String getAllColumn() {
        StringBuilder sb = new StringBuilder();
		for (int i = 0; i < colnames.length; i++) {			
				sb.append( colnames[i] + ",");
		}
		String columns=sb.toString();
		columns=	columns.substring(0,columns.length()-1);
		return columns;
	}



	/**
	 * 功能:将输入字符串的首字母改成大写,驼峰,命名
	 * 
	 * @param str
	 * @return
	 */
	private String initcap(String str) {
		String rename = str;
		if (rename.contains("_")) {
			StringBuilder sbBuilder = new StringBuilder();
			for (String stri : rename.split("_")) {
				sbBuilder.append(firstBig(stri));
			}
			;
			return firstBig(sbBuilder.toString());
		}
		return firstBig(rename.toLowerCase());
	}

	private String initAttrcap(String str) {
		String rename = str;
		if (rename.contains("_")) {
			StringBuilder sbBuilder = new StringBuilder();
			int i = 0;
			String[] splits = rename.split("_");
			for (String stri : splits) {
				if (i > 0) {
					sbBuilder.append(firstBig(stri));
				}
				i++;
			}
			return splits[0] + sbBuilder.toString();
		}
		return rename.toLowerCase();
	}

	private String firstBig(String rename) {
		char[] ch = rename.toCharArray();
		if (ch[0] >= 'a' && ch[0] <= 'z') {
			ch[0] = (char) (ch[0] - 32);
		}

		return new String(ch);
	}

	/**
	 * 功能:获得列的数据类型
	 * 
	 * @param sqlType
	 * @return
	 */
	private String sqlType2JavaType(String sqlType) {

		if (sqlType.equalsIgnoreCase("binary_double")) {
			return "double";
		} else if (sqlType.equalsIgnoreCase("binary_float")) {
			return "float";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "byte[]";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "byte[]";
		} else if (sqlType.equalsIgnoreCase("char") || sqlType.equalsIgnoreCase("nvarchar2")
				|| sqlType.equalsIgnoreCase("varchar2")) {
			return "String";
		} else if (sqlType.equalsIgnoreCase("date") || sqlType.equalsIgnoreCase("timestamp")
				|| sqlType.equalsIgnoreCase("timestamp with local time zone")
				|| sqlType.equalsIgnoreCase("timestamp with time zone")) {
			return "Date";
		} else if (sqlType.equalsIgnoreCase("number")) {
			return "Long";
		}
		return "String";
	}
	
	
	
	private String sqlType2JDBCType(String sqlType) {

		if (sqlType.equalsIgnoreCase("binary_double")) {
			return "NUMBER";
		} else if (sqlType.equalsIgnoreCase("binary_float")) {
			return "NUMBER";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "BLOB";
		} else if (sqlType.equalsIgnoreCase("clob")) {
			return "CLOB";
		} else if (sqlType.equalsIgnoreCase("char") || sqlType.equalsIgnoreCase("nvarchar2")
				|| sqlType.equalsIgnoreCase("varchar2")) {
			return "VARCHAR";
		} else if (sqlType.equalsIgnoreCase("date") || sqlType.equalsIgnoreCase("timestamp")
				|| sqlType.equalsIgnoreCase("timestamp with local time zone")
				|| sqlType.equalsIgnoreCase("timestamp with time zone")) {
			return "TIMESTAMP";
		} else if (sqlType.equalsIgnoreCase("number")) {
			return "NUMBER";
		}
		return "VARCHAR";
	}

	/**
	 * 出口 TODO
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		new GenSQLXMLOracle();

	}

}

生成MyBatis配置文件:需要截止红色属性值

public class GenSQLXMLOracle {

    private String tablename = "bid_clarify";// 表名
    private String domianDao = "cn.com.aostarit.ecp.bid.dao.BidClarifyDao";
    private String domain = "BidClarify";
    private String domainAttr = "bidClarify";

    private String[] colnames; // 列名数组
    private String[] colTypes; // 列名类型数组
    private int[] colSizes; // 列名大小数组

    // 数据库连接
    private static final String URL = "jdbc:oracle:thin:@192.168.0.160:1521:ORCL";
    private static final String NAME = "jdbc._dev";
    private static final String PASS = "jdbc.2016";
    private static final String DRIVER = "oracle.jdbc.driver.OracleDriver";

package work;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Date;

/**
* 生成实体类
* @author  qliu
* 日期:2016-10-10
*/
public class GenEntityOracle {

private String tablename = "bid_clarify";//表名
private String[] colnames; // 列名数组
private String[] colTypes; //列名类型数组
private int[] colSizes; //列名大小数组
private boolean f_util = true; // 是否需要导入包java.util.*
private boolean f_sql = true; // 是否需要导入包java.sql.*

//数据库连接  
private static final String URL ="jdbc:oracle:thin:@192.168.0.160:1521:ORCL";  
private static final String NAME = "ecp_dev";  
private static final String PASS = "ecp2016";  
private static final String DRIVER ="oracle.jdbc.driver.OracleDriver";  
/*
 * 构造函数
 */
public GenEntityOracle(){
    //创建连接
    Connection con;
 //查要生成实体类的表
    String sql = "select * from " + tablename;
    PreparedStatement pStemt = null;
    try {
     try {
   Class.forName(DRIVER);
  } catch (ClassNotFoundException e1) {
   // TODO Auto-generated catch block
   e1.printStackTrace();
  }
     con = DriverManager.getConnection(URL,NAME,PASS);
  pStemt = con.prepareStatement(sql);
  ResultSetMetaData rsmd = pStemt.getMetaData();
  int size = rsmd.getColumnCount(); //统计列
  colnames = new String[size];
  colTypes = new String[size];
  colSizes = new int[size];
  for (int i = 0; i < size; i++) {
   colnames[i] = rsmd.getColumnName(i + 1);
   colTypes[i] = rsmd.getColumnTypeName(i + 1);
   
   if(colTypes[i].equalsIgnoreCase("datetime")){
    f_util = true;
   }
   if(colTypes[i].equalsIgnoreCase("image") || colTypes[i].equalsIgnoreCase("text")){
    f_sql = true;
   }
   colSizes[i] = rsmd.getColumnDisplaySize(i + 1);
  }
  
  String content = parse(colnames,colTypes,colSizes);
  
  try {
   File directory = new File("");
   String path=this.getClass().getResource("").getPath();
   
   String fileName = directory.getAbsolutePath()+ "/src/"+initcap(tablename.toLowerCase()) + ".java";
   System.out.println(fileName);
FileWriter fw = new FileWriter(fileName);
   PrintWriter pw = new PrintWriter(fw);
   pw.println(content);
   pw.flush();
   pw.close();
  } catch (IOException e) {
   e.printStackTrace();
  }
  
 } catch (SQLException e) {
  e.printStackTrace();
 } finally{
//  try {
//   con.close();
//  } catch (SQLException e) {
//   // TODO Auto-generated catch block
//   e.printStackTrace();
//  }
 }
   }

/**
 * 功能:生成实体类主体代码
 * @param colnames
 * @param colTypes
 * @param colSizes
 * @return
 */
private String parse(String[] colnames, String[] colTypes, int[] colSizes) {
 StringBuffer sb = new StringBuffer();
 
 //判断是否导入工具包
 if(f_util){
  sb.append("import java.util.Date;\r\n");
 }
 if(f_sql){
  sb.append("import java.sql.*;\r\n");
 }
 sb.append("package com.share.barter.tool;\r\n");
 sb.append("\r\n");
 //注释部分
 sb.append("   /**\r\n");
 sb.append("    * "+tablename+" 实体类\r\n");
 sb.append("    * "+new Date()+"  qliu\r\n");
 sb.append("    */ \r\n");
 //实体部分
 sb.append("\r\n\r\npublic class " + initcap(tablename.toLowerCase()) + "{\r\n");
 processAllAttrs(sb);//属性
 processAllMethod(sb);//get set方法
 sb.append("}\r\n");
 
    //System.out.println(sb.toString());
 return sb.toString();
}

/**
 * 功能:生成所有属性
 * @param sb
 */
private void processAllAttrs(StringBuffer sb) {
 
 for (int i = 0; i < colnames.length; i++) {
  sb.append("\tprivate " + sqlType2JavaType(colTypes[i]) + " " + initAttrcap(colnames[i].toLowerCase()) + ";\r\n");
 }
 
}

/**
 * 功能:生成所有方法
 * @param sb
 */
private void processAllMethod(StringBuffer sb) {
 
 for (int i = 0; i < colnames.length; i++) {
  sb.append("\tpublic void set" + initcap(colnames[i]) + "(" + sqlType2JavaType(colTypes[i]) + " " +
		  initAttrcap(colnames[i].toLowerCase()) + "){\r\n");
  sb.append("\tthis." + initAttrcap(colnames[i].toLowerCase()) + "=" + initAttrcap(colnames[i].toLowerCase()) + ";\r\n");
  sb.append("\t}\r\n");
  sb.append("\tpublic " + sqlType2JavaType(colTypes[i]) + " get" + initcap(colnames[i].toLowerCase()) + "(){\r\n");
  sb.append("\t\treturn " + initAttrcap(colnames[i].toLowerCase()) + ";\r\n");
  sb.append("\t}\r\n");
 }
 
}

/**
 * 功能:将输入字符串的首字母改成大写,驼峰,命名
 * @param str
 * @return
 */
private String initcap(String str) {
	String rename=str;
	if(rename.contains("_")){
		StringBuilder sbBuilder = new StringBuilder();
		for(String stri:rename.split("_")){
			sbBuilder.append(firstBig(stri));
		};
		return firstBig(sbBuilder.toString());
	} 
 return firstBig(rename.toLowerCase());
}

private String initAttrcap(String str) {
	String rename=str;
	if(rename.contains("_")){
		StringBuilder sbBuilder = new StringBuilder();
		int i=0;
		String[] splits = rename.split("_");
		for(String stri:splits){
			if(i>0){
				sbBuilder.append(firstBig(stri));
			}
			i++;
		}
		return splits[0]+sbBuilder.toString();
	} 
 return rename.toLowerCase();
}

private String firstBig(String rename) {
	char[] ch = rename.toCharArray();
	 if(ch[0] >= 'a' && ch[0] <= 'z'){
	  ch[0] = (char)(ch[0] - 32);
	 }
	 
	 return new String(ch);
}

/**
 * 功能:获得列的数据类型
 * @param sqlType
 * @return
 */
	private String sqlType2JavaType(String sqlType) {

		if (sqlType.equalsIgnoreCase("binary_double")) {
			return "double";
		} else if (sqlType.equalsIgnoreCase("binary_float")) {
			return "float";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "byte[]";
		} else if (sqlType.equalsIgnoreCase("blob")) {
			return "byte[]";
		} else if (sqlType.equalsIgnoreCase("char") || sqlType.equalsIgnoreCase("nvarchar2")
				|| sqlType.equalsIgnoreCase("varchar2")) {
			return "String";
		} else if (sqlType.equalsIgnoreCase("date") || sqlType.equalsIgnoreCase("timestamp")
				|| sqlType.equalsIgnoreCase("timestamp with local time zone")
				|| sqlType.equalsIgnoreCase("timestamp with time zone")) {
			return "Date";
		} else if (sqlType.equalsIgnoreCase("number")) {
			return "Long";
		}
		return "String";
	}

/**
 * 出口
 * TODO
 * @param args
 */
public static void main(String[] args) {
 
 new GenEntityOracle();
 
}

} 

 

转载于:https://my.oschina.net/kerlais/blog/756502

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值