码迷,mamicode.com
首页 > Web开发 > 详细

Hibernate给表和字段设置前后缀及分隔符

时间:2017-06-30 23:56:23      阅读:283      评论:0      收藏:0      [点我收藏+]

标签:sdn   比较   eof   src   char   targe   dia   lib   增删改   

  在《一口一口吃掉Hibernate(一)——使用SchemaExport生成数据表》中介绍了如何生成数据表。但是这只是最基本的。hibernate在生成或者操作数据库时,会受一些限制。比如一开始设计表的时候,直接写成了user(id,name,password,createTime)  这种格式的。但是客户后来要求表名称要以“t_”开头,字段名要以“stu_”开头,可以是一些数据库的关键字,单词之间以“_”隔开,方便他们维护.例如:T_User(stu_Id,stu_Name,stu_Create_Time)。

 

      对于上面的问题,常规的方法就是去修改Hibernate_cfg.xml中的表,为每个表添加“t_”,或者写table属性,字段也重新使用column属性来修改。如果你有100张表,每个表平均有10个字段,你还会去一个一个修改么?还有可能漏掉或者改错。最“可恶”的是,如果客户再让你改成其他的呢,是不是还要全部修改一次?

 

      有没有一种方法,不修改原先的配置,添加并配置一下表和字段的前后缀及分隔符等等,既可以完成呢??经过尝试,终于被我拿下了,现在拿出来与大家分享。

 

      针对上述问题,我主要用的是NamingStrategy接口。这个接口很有意思,可以作为业务类规范和数据库表规范的桥梁,它可以表和列的映射关系的转变和处理。例如一个数据对象User,对应数据库表是T_USER,如果所有映射关系都是这样的情况,可以使用NamingStrategy做为一个桥梁衔接,而不用再hbm.xml映射文件中指定class对应的物理table。


      先说一下Hibernate读取映射文件的简要过程:循环读取class标签,判断class标签的table属性值是否为null,若为null,则调用NamingStrategy接口的classToTableName方法将class值转换并处理(按命名策略NamingStrategy处理)的表名。若不为null,则说明设置了table,那么调用NamingStrategy接口的tableName方法获取处理过的表名。循环遍历property,判断property标签的column属性值是否为null,若为null,则首先调用propertyToColumnName方法,将属性值转化为列名,再调用logicalColumnName方法。若不为null,则直接调用NamingStrategy接口的logicalColumnName方法,再调用columnName方法进行处理(按命名策略NamingStrategy处理)。

 

      了解了上面说的这个过程,只要我们实现NamingStrategy这个接口,就可以随心所欲的修改表映射了。不多说了,直接上代码吧:

    【MyNamingStrategy】自定义的命名策略,可对表、字段进行统一处理。

 

  1. package com.tgb.hibernate.neatlyDB;  
  2.   
  3. import org.hibernate.cfg.Configuration;  
  4. import org.hibernate.cfg.NamingStrategy;  
  5. import org.hibernate.util.StringHelper;  
  6.   
  7. /** 
  8.  * 数据库命名策略,可定制表、字段等的前后缀 
  9.  *  
  10.  * @author Longxuan 
  11.  *  
  12.  */  
  13. public class MyNamingStrategy implements NamingStrategy {  
  14.   
  15.     /** 
  16.      * 数据库命名策略单一实例 
  17.      */  
  18.     private static MyNamingStrategy instance = null;  
  19.   
  20.     /** 
  21.      * 数据库配置信息类 
  22.      */  
  23.     private static DatabaseConfiguration dbcfg = null;  
  24.   
  25.     /** 
  26.      * 私有化构造方法 
  27.      */  
  28.     private MyNamingStrategy() {  
  29.   
  30.     }  
  31.   
  32.     /** 
  33.      * 使用单利模式,获取数据库命名策略的唯一实例 
  34.      *  
  35.      * @return 
  36.      */  
  37.     public static synchronized MyNamingStrategy getInstance() {  
  38.         // 默认读取hibernate.cfg.xml文件  
  39.         Configuration cfg = new Configuration().configure();  
  40.         return getInstance(cfg);  
  41.     }  
  42.   
  43.     /** 
  44.      * 使用单利模式,获取数据库命名策略的唯一实例,同时使用默认Hibernate.cfg.xml更新命名策略信息 
  45.      *  
  46.      * @param cfg 
  47.      *            配置文件信息 
  48.      * @return 
  49.      */  
  50.     public static synchronized MyNamingStrategy getInstance(Configuration cfg) {  
  51.         if (instance == null) {  
  52.             instance = new MyNamingStrategy();  
  53.         }  
  54.         MyNamingStrategy.dbcfg = new DatabaseConfiguration(cfg);  
  55.         return instance;  
  56.     }  
  57.   
  58.     /** 
  59.      * 使用单利模式,获取数据库命名策略的唯一实例,同时更新命名策略信息 
  60.      *  
  61.      * @param cfg 
  62.      *            配置文件信息 
  63.      * @return 
  64.      */  
  65.     public static synchronized MyNamingStrategy getInstance(  
  66.             DatabaseConfiguration dbcfg) {  
  67.         if (instance == null) {  
  68.             instance = new MyNamingStrategy();  
  69.         }  
  70.         MyNamingStrategy.dbcfg = dbcfg;  
  71.         return instance;  
  72.     }  
  73.   
  74.     /** 
  75.      * 设置或更新数据库配置信息 
  76.      *  
  77.      * @param dbcfg 
  78.      */  
  79.     public void setDBConfig(DatabaseConfiguration dbcfg) {  
  80.         MyNamingStrategy.dbcfg = dbcfg;  
  81.     }  
  82.   
  83.     /** 
  84.      * 转化为物理表名 
  85.      *  
  86.      * @param className hbm.xml中的对应表的class值 
  87.      */  
  88.     @Override  
  89.     public String classToTableName(String className) {  
  90.           
  91.         if(className == null ) return null;  
  92.           
  93.         //改变大小写  
  94.         String str =UpdateStyle(className,dbcfg.getTableStyle().name());  
  95.               
  96.         //添加前后缀  
  97.         str = addPrefixORStuffix(str, dbcfg.getTablePrefix(),dbcfg.getTableSuffix());  
  98.           
  99.         //添加分隔符  
  100.         str = addSeparator(str,dbcfg.getTableSeparator());  
  101.           
  102.         return str;  
  103.     }  
  104.   
  105.     @Override  
  106.     public String collectionTableName(String ownerEntity,  
  107.             String ownerEntityTable, String associatedEntity,  
  108.             String associatedEntityTable, String propertyName) {  
  109.         return null;  
  110.     }  
  111.   
  112.       
  113.     /** 
  114.      * 将读取到的列名传递过来进行加工处理,变为物理表的字段名 
  115.      *  
  116.      * @param columnName logicalColumnName方法读取到的列名 
  117.      */  
  118.     @Override  
  119.     public String columnName(String columnName) {  
  120.         //先调用logicalColumnName方法,拿到处理过的值,  
  121.         //再传递到该方法中,所以可以在这两个方法中任一选择修改。         
  122.         //return columnName;  
  123.           
  124.         if(columnName == null ) return null;  
  125.           
  126.         //改变大小写  
  127.         String str =UpdateStyle(columnName,dbcfg.getColumnTyle().name());  
  128.               
  129.         //添加前后缀  
  130.         str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());  
  131.           
  132.         //添加分隔符  
  133.         str = addSeparator(str,dbcfg.getColumnSeparator());  
  134.           
  135.         return str;  
  136.           
  137.     }  
  138.   
  139.       
  140.     /** 
  141.      * 处理外键列名 
  142.      *  
  143.      */  
  144.     @Override  
  145.     public String foreignKeyColumnName(String propertyName,  
  146.             String propertyEntityName, String propertyTableName,  
  147.             String referencedColumnName) {  
  148.           
  149.         if(referencedColumnName == null ) return null;  
  150.           
  151.         //改变大小写  
  152.         String str =UpdateStyle(referencedColumnName,dbcfg.getColumnTyle().name());  
  153.               
  154.         //添加前后缀  
  155.         str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());  
  156.           
  157.         //添加分隔符  
  158.         str = addSeparator(str,dbcfg.getColumnSeparator());  
  159.           
  160.         return str;  
  161.     }  
  162.   
  163.     /** 
  164.      * 关联键的名称 
  165.      */  
  166.     @Override  
  167.     public String joinKeyColumnName(String joinedColumn, String joinedTable) {  
  168.           
  169.         if(joinedColumn == null ) return null;  
  170.           
  171.         //改变大小写  
  172.         String str =UpdateStyle(joinedColumn,dbcfg.getColumnTyle().name());  
  173.               
  174.         //添加前后缀  
  175.         str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());  
  176.           
  177.         //添加分隔符  
  178.         str = addSeparator(str,dbcfg.getColumnSeparator());  
  179.           
  180.         return str;  
  181.     }  
  182.   
  183.     @Override  
  184.     public String logicalCollectionColumnName(String columnName,  
  185.             String propertyName, String referencedColumn) {  
  186.         return null;  
  187.     }  
  188.   
  189.     @Override  
  190.     public String logicalCollectionTableName(String tableName,  
  191.             String ownerEntityTable, String associatedEntityTable,  
  192.             String propertyName) {  
  193.         return null;  
  194.     }  
  195.   
  196.     /** 
  197.      * 处理逻辑列名 
  198.      * <b>若设置了column属性,会直接调用调用该方法</b> 
  199.      *  
  200.      * @param columnName    列名 
  201.      * @param propertyName  实体列名 
  202.      */  
  203.     @Override  
  204.     public String logicalColumnName(String columnName, String propertyName) {  
  205.           
  206.         //name值对应propertyName,column值对应columnName  
  207.         //判断columnName是否设置,若设置了,则返回column值,否则返回propertyName值  
  208.         return columnName == null || columnName =="" ? propertyName:columnName;  
  209.           
  210.     }  
  211.   
  212.     /** 
  213.      * 处理逻辑列名 
  214.      * <b>若未设置column属性,则先调用该方法,再调用logicalColumnName方法</b> 
  215.      *  
  216.      * @param propertyName  实体列名 
  217.      */  
  218.     @Override  
  219.     public String propertyToColumnName(String propertyName) {  
  220.   
  221.         if(propertyName == null ) return null;  
  222.           
  223.         //改变大小写  
  224.         String str =UpdateStyle(propertyName,dbcfg.getColumnTyle().name());  
  225.               
  226.         //添加前后缀  
  227.         str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getColumnPrefix(),dbcfg.getColumnSuffix());  
  228.           
  229.         //添加分隔符  
  230.         str = addSeparator(str,dbcfg.getColumnSeparator());  
  231.           
  232.         return str;  
  233.     }  
  234.   
  235.       
  236.     /** 
  237.      * 处理表名 
  238.      * <b>若设置了table属性,才会调用该方法</b> 
  239.      */  
  240.     @Override  
  241.     public String tableName(String tableName) {  
  242.           
  243.         if(tableName == null ) return null;  
  244.           
  245.         //改变大小写  
  246.         String str =UpdateStyle(tableName,dbcfg.getTableStyle().name());  
  247.               
  248.         //添加前后缀  
  249.         str = addPrefixORStuffix(StringHelper.unqualify(str), dbcfg.getTablePrefix(),dbcfg.getTableSuffix());  
  250.           
  251.         //添加分隔符  
  252.         str = addSeparator(str,dbcfg.getTableSeparator());  
  253.           
  254.         return str;  
  255.     }  
  256.   
  257.     /** 
  258.      * 单词分隔符 
  259.      *  
  260.      * @param name 
  261.      * @return 
  262.      */  
  263.     private String addSeparator(String str, String flag) {  
  264.         StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));  
  265.         for (int i = 1; i < buf.length() - 1; i++) {  
  266.             if (‘_‘ != buf.charAt(i - 1)  
  267.                     && Character.isUpperCase(buf.charAt(i))  
  268.                     && !Character.isUpperCase(buf.charAt(i + 1))) {  
  269.                 // buf.insert(i++, ‘_‘);  
  270.                 buf.insert(i++, flag);  
  271.             }  
  272.         }  
  273.         return buf.toString();  
  274.     }  
  275.   
  276.     /** 
  277.      * 添加前后缀 
  278.      *  
  279.      * @param str 
  280.      *            字符串 
  281.      * @param prefix 
  282.      *            前缀 
  283.      * @param suffix 
  284.      *            后缀 
  285.      * @return 
  286.      */  
  287.     private String addPrefixORStuffix(String str, String prefix, String suffix) {  
  288.         StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));  
  289.         buf.insert(buf.length(), suffix).insert(0, prefix);  
  290.         return buf.toString();  
  291.     }  
  292.   
  293.     /** 
  294.      * 更新样式 
  295.      * @param str 
  296.      * @param style 
  297.      * @return 
  298.      */  
  299.     private String UpdateStyle(String str, String style) {        
  300.         if ("AU".equals(style)) {  
  301.             str = str.toUpperCase();  
  302.         } else if ("AL".equals(style)) {  
  303.             str = str.toLowerCase();  
  304.         } else if ("FU".equals(style)) {  
  305.             StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));  
  306.             String upper =buf.substring(0,1).toUpperCase();  
  307.             buf.delete(0, 1).insert(0, upper);  
  308.             str = buf.toString();  
  309.         } else if ("FL".equals(style)) {  
  310.             StringBuffer buf = new StringBuffer(str.substring(str.lastIndexOf(".")+1));  
  311.             String lower =buf.substring(0,1).toLowerCase();  
  312.             buf.delete(0, 1).insert(0, lower);  
  313.             str = buf.toString();  
  314.         }  else{  
  315.               
  316.         }         
  317.         return str;  
  318.     }  
  319.       
  320.       
  321. }  

 

【DatabaseConfiguration】数据库样式配置,包括前后缀、分隔符、大小写等

 

  1. package com.tgb.hibernate.neatlyDB;  
  2.   
  3. import org.hibernate.cfg.Configuration;  
  4.   
  5.   
  6. /** 
  7.  * 数据库模式配置 
  8.  * @author Longxuan 
  9.  * 
  10.  */  
  11. public final class DatabaseConfiguration {  
  12.   
  13.   
  14.     /** 
  15.      * 列名样式 
  16.      * AU-all upper case 
  17.      * AL-all lower case 
  18.      * FU-first upper case per word 
  19.      * FL-first lower case ,Other first letter upper case 
  20.      */  
  21.     public static enum ColumnTyle {  
  22.         AU,AL,FU,FL;          
  23.     }  
  24.       
  25.     /** 
  26.      * 表名称样式 
  27.      * AU-all upper case 
  28.      * AL-all lower case 
  29.      * FU-first upper case per word 
  30.      * FL-first lower case ,Other first letter upper case 
  31.      */  
  32.     public static enum TableStyle{  
  33.         AU,AL,FU,FL;  
  34.     }  
  35.   
  36.     /** 
  37.      * 列名样式 
  38.      * AU-all upper case 
  39.      * AL-all lower case 
  40.      * FU-first upper case per word 
  41.      * FL-first lower case ,Other first letter upper case 
  42.      */  
  43.     private ColumnTyle columnTyle = ColumnTyle.FL;  
  44.       
  45.     /** 
  46.      * 表名称样式 
  47.      * AU-all upper case 
  48.      * AL-all lower case 
  49.      * FU-first upper case per word 
  50.      * FL-first lower case ,Other first letter upper case 
  51.      */  
  52.     private TableStyle tableStyle = TableStyle.FU;  
  53.       
  54.     /** 
  55.      * 表名称前缀 
  56.      */  
  57.     private String tablePrefix = "";  
  58.       
  59.     /** 
  60.      * 表名称后缀 
  61.      */  
  62.     private String tableSuffix = "";  
  63.       
  64.     /** 
  65.      * 表名称分隔符 
  66.      */  
  67.     private String tableSeparator = "";  
  68.       
  69.     /** 
  70.      * 列名前缀 
  71.      */  
  72.     private String columnPrefix = "";  
  73.       
  74.     /** 
  75.      * 列名后缀 
  76.      */  
  77.     private String columnSuffix = "";  
  78.       
  79.     /** 
  80.      * 列名分隔符 
  81.      */  
  82.     private String columnSeparator = "";  
  83.       
  84.     public ColumnTyle getColumnTyle() {  
  85.         return columnTyle;  
  86.     }  
  87.   
  88.     public void setColumnTyle(ColumnTyle columnTyle) {  
  89.         this.columnTyle = columnTyle;  
  90.     }  
  91.   
  92.     public TableStyle getTableStyle() {  
  93.         return tableStyle;  
  94.     }  
  95.   
  96.     public void setTableStyle(TableStyle tableStyle) {  
  97.         this.tableStyle = tableStyle;  
  98.     }  
  99.   
  100.     public String getTablePrefix() {  
  101.         return tablePrefix;  
  102.     }  
  103.   
  104.     public void setTablePrefix(String tablePrefix) {  
  105.         this.tablePrefix = tablePrefix;  
  106.     }  
  107.   
  108.     public String getTableSuffix() {  
  109.         return tableSuffix;  
  110.     }  
  111.   
  112.     public void setTableSuffix(String tableSuffix) {  
  113.         this.tableSuffix = tableSuffix;  
  114.     }  
  115.   
  116.     public String getTableSeparator() {  
  117.         return tableSeparator;  
  118.     }  
  119.   
  120.     public void setTableSeparator(String tableSeparator) {  
  121.         this.tableSeparator = tableSeparator;  
  122.     }  
  123.   
  124.     public String getColumnPrefix() {  
  125.         return columnPrefix;  
  126.     }  
  127.   
  128.     public void setColumnPrefix(String columnPrefix) {  
  129.         this.columnPrefix = columnPrefix;  
  130.     }  
  131.   
  132.     public String getColumnSuffix() {  
  133.         return columnSuffix;  
  134.     }  
  135.   
  136.     public void setColumnSuffix(String columnSuffix) {  
  137.         this.columnSuffix = columnSuffix;  
  138.     }  
  139.   
  140.     public String getColumnSeparator() {  
  141.         return columnSeparator;  
  142.     }  
  143.   
  144.     public void setColumnSeparator(String columnSeparator) {  
  145.         this.columnSeparator = columnSeparator;  
  146.     }  
  147.       
  148.   
  149.     /** 
  150.      * 初始化,读取配置参数,默认读取Hibernate.cfg.xml 
  151.      * @param cfg 
  152.      */  
  153.     public DatabaseConfiguration(){  
  154.         ReadConfig(new Configuration().configure());   
  155.     }  
  156.       
  157.     /** 
  158.      * 初始化,读取配置文件 
  159.      * @param cfg 
  160.      */  
  161.     public DatabaseConfiguration(Configuration cfg){  
  162.         ReadConfig(cfg);   
  163.     }  
  164.       
  165.   
  166.     /** 
  167.      * 自动读取配置信息 
  168.      * @param cfg 
  169.      */  
  170.     private void ReadConfig(Configuration cfg){  
  171.         tableStyle = cfg.getProperty("tablestyle")==""?TableStyle.FU:TableStyle.valueOf(cfg.getProperty("tablestyle"));  
  172.         tablePrefix = cfg.getProperty("tablePrefix");  
  173.         tableSuffix = cfg.getProperty("tablesuffix");  
  174.         tableSeparator = cfg.getProperty("tableseparator");  
  175.           
  176.         columnTyle = cfg.getProperty("columntyle")==""?ColumnTyle.FL:ColumnTyle.valueOf(cfg.getProperty("columntyle"));  
  177.         columnPrefix = cfg.getProperty("columnPrefix");  
  178.         columnSuffix = cfg.getProperty("columnsuffix");  
  179.         columnSeparator = cfg.getProperty("columnseparator");  
  180.           
  181.     }  
  182.       
  183. }  



 

【hibernate.cfg.xml】设置数据库样式配置信息

 

  1. <!DOCTYPE hibernate-configuration PUBLIC  
  2.     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
  3.     "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
  4.   
  5. <hibernate-configuration>  
  6.     <session-factory name="foo">        
  7. <!--   
  8.     name:       配置的名称  
  9.     style:      类型 枚举AU-all upper case  
  10.                       AL-all lower case  
  11.                       FU-first letter upper case per word  
  12.                       FL-first letter lower case ,Other first letters upper case  
  13.       
  14.     befix:      前缀  
  15.     suffix:     后缀  
  16.     separator:  分隔符  
  17.  -->  
  18.         <property name="tablestyle">FU</property>  
  19.         <property name="tablePrefix" >T_</property>  
  20.         <property name="tablesuffix" ></property>  
  21.         <property name="tableseparator" >_</property>         
  22.         <property name="columntyle">FU</property>  
  23.         <property name="columnPrefix">[stu_</property>  
  24.         <property name="columnsuffix">]</property>  
  25.         <property name="columnseparator">_</property>  
  26.           
  27.           
  28.       
  29.         <property name="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</property>  
  30.         <property name="hibernate.show_sql">true</property><!-- 设置是否显示生成sql语句 -->  
  31.         <property name="hibernate.format_sql">false</property><!-- 设置是否格式化sql语句-->  
  32.           
  33.         <mapping resource="com/bjpowernode/hibernate/User.hbm.xml" />  
  34.           
  35.     </session-factory>  
  36.       
  37. </hibernate-configuration>  


【User.hbm.xml】映射文件可以比较随意的修改或者设定了

 

 

  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.bjpowernode.hibernate.User" table="Users">  
  7.         <id name="id" column="pid">  
  8.             <generator class="uuid" />  
  9.         </id>  
  10.         <property name="name" column="userName"></property>  
  11.         <property name="password" column="pwd"></property>  
  12.         <property name="createTime"></property>  
  13.         <property name="expireTime"></property>  
  14.           
  15.     </class>  
  16. </hibernate-mapping>  


最后修改一下【ExportDB】,主要是修改必须先设置NamingStrategy,在调用configure方法

 

 

  1. package com.bjpowernode.hibernate;  
  2.   
  3. import org.hibernate.cfg.Configuration;  
  4. import org.hibernate.tool.hbm2ddl.SchemaExport;  
  5.   
  6. import com.tgb.hibernate.neatlyDB.DatabaseConfiguration;  
  7. import com.tgb.hibernate.neatlyDB.MyNamingStrategy;  
  8.   
  9.   
  10.   
  11. /** 
  12.  * 将hbm生成ddl 
  13.  * @author Longxuan 
  14.  * 
  15.  */  
  16. public class ExportDB {  
  17.   
  18.     /** 
  19.      * @param args 
  20.      */  
  21.     public static void main(String[] args) {  
  22.   
  23.         //默认读取hibernate.cfg.xml文件,并按照命名策略修改表、字段的名称  
  24.         //Configuration cfg = new Configuration().configure();   
  25.           
  26.         //注意,必须先设置NamingStrategy,在调用configure方法  
  27.         Configuration cfg = new Configuration().setNamingStrategy(MyNamingStrategy.getInstance()).configure();  
  28.                           
  29.         SchemaExport export = new SchemaExport(cfg);  
  30.           
  31.         //true 在控制台打印ddl语句,true 导入ddl语句到数据库,即可执行  
  32.         export.create(true, true);  
  33.     }  
  34.   
  35. }  


      看一下结果图吧:表名,字段名都已经修改过了。

 

技术分享

 

      上面演示的是生成数据表。在对数据库的增删改查时,只要同样设置NamingStrategy即可。

      为了大家更为方便的使用,已经做成jar包分享给大家了,点这里下载。

Hibernate给表和字段设置前后缀及分隔符

标签:sdn   比较   eof   src   char   targe   dia   lib   增删改   

原文地址:http://www.cnblogs.com/KingIceMou/p/7100979.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!