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

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

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

【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. <hibernate-configuration>
  5. <session-factory name="foo">
  6. <!--
  7. name:       配置的名称
  8. style:      类型 枚举AU-all upper case
  9. AL-all lower case
  10. FU-first letter upper case per word
  11. FL-first letter lower case ,Other first letters upper case
  12. befix:      前缀
  13. suffix:     后缀
  14. separator:  分隔符
  15. -->
  16. <property name="tablestyle">FU</property>
  17. <property name="tablePrefix" >T_</property>
  18. <property name="tablesuffix" ></property>
  19. <property name="tableseparator" >_</property>
  20. <property name="columntyle">FU</property>
  21. <property name="columnPrefix">[stu_</property>
  22. <property name="columnsuffix">]</property>
  23. <property name="columnseparator">_</property>
  24. <property name="hibernate.dialect" >org.hibernate.dialect.MySQLDialect</property>
  25. <property name="hibernate.show_sql">true</property><!-- 设置是否显示生成sql语句 -->
  26. <property name="hibernate.format_sql">false</property><!-- 设置是否格式化sql语句-->
  27. <mapping resource="com/bjpowernode/hibernate/User.hbm.xml" />
  28. </session-factory>
  29. </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. </class>
  15. </hibernate-mapping>

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

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

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

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

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

Hibernate给表和字段设置前后缀及分隔符的更多相关文章

  1. django 重写User表增加字段设置

    models中: from django.contrib.auth.models import AbstractUser lass User(AbstractUser): mobile = model ...

  2. mysql表时间戳字段设置

    创建时间 修改时间  

  3. Hibernate 3中如何获得库表所有字段的名称

    15问:Hibernate 3中如何获得库表所有字段的名称 答:可以使用以下的程序获得. Configuration conf = new Configuration(); conf.configur ...

  4. 在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?

    在高并发.高负载的情况下,如何给表添加字段并设置DEFAULT值? 在Oracle 12c之前,当Oracle表数据量上亿时,对表执行“ALTER TABLE XXX ADD COLUMN_XX VA ...

  5. MySQL 创建表时,设置时间字段自己主动插入当前时间

    MySQL 创建表时,设置时间字段自己主动插入当前时间 DROP TABLE IF EXISTS `CONTENT`; CREATE TABLE `CONTENT` ( `ID` char(20) N ...

  6. 如何更精准地设置 C# / .NET Core 项目的输出路径?(包括添加和删除各种前后缀)

    原文:如何更精准地设置 C# / .NET Core 项目的输出路径?(包括添加和删除各种前后缀) 我们都知道可以通过在 Visual Studio 中设置输出路径(OutputPath)来更改项目输 ...

  7. OneThink学习笔记02----数据字典(即OneThink项目数据库里的表及其字段)

    action 字段 类型 注释 id int(11) unsigned 自增主键 name char(30) 行为唯一标识 title char(80) 行为说明 remark char(140) 行 ...

  8. Hibernate学习笔记(三)Hibernate生成表单ID主键生成策略

    一. Xml方式 <id>标签必须配置在<class>标签内第一个位置.由一个字段构成主键,如果是复杂主键<composite-id>标签 被映射的类必须定义对应数 ...

  9. Ecshop 表结构 字段说明

    ecs_account_log 用户帐号情况记录表,包括资金和积分等 log_id mediumint 自增ID号user_id mediumint 用户登录后保存在session中的id号,跟use ...

随机推荐

  1. Let's Encrypt,站点加密之旅

    HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.即HTTP下加入 ...

  2. Apollo单向SSL认证(1)

    参考链接:https://www.cnblogs.com/benwu/articles/4891758.html keytool -genkey -alias mybroker -keyalg RSA ...

  3. api-gateway实践(13)新服务网关 - 断路保护/熔断机制

    参考链接:SpringCloud的Hystrix(五) Hystrix机制 新需求列表 1.在线测试 根据定义,生成输入界面, 点击测试, 验证参数,发起调用,返回执行结果 2.熔断保护 两个实现类: ...

  4. Linux之Shell命令

    开始接触Linux命令行,学习Linux文件系统导航以及创建.删除.处理文件所需的命令.  注:文末有福利! 几个快捷键: Linux发行版通常使用Ctrl+Alt组合键配合F1~F7进入要使用的控制 ...

  5. JS for循环小题2

    ********** for(var a = 1; a<=4;a++){ //外循环定义循环4次,4行 for(var i= 1;i<=a;i++){ //内循环控制*的打印次数,循环一次 ...

  6. 2018年html5入门到精通教程电子书百度云盘下载共22本

    名称 查看 <HTML5启动和运行>(HTML5.Up.and.Running)扫描版[PDF] 下载 <Pro HTML5 Performance>(Pro HTML5 Pe ...

  7. 【Vue中的swiper轮播组件】

    <template> <swiper :options="swiperOption" ref="mySwiper"> <!-- s ...

  8. Struts(十四):通用标签-form表单

    form标签是struts2标签中一个重要标签: 可以生成html标签,使用起来和html的form标签差不多: Strut2的form标签会生成一个table,进行自动布局: 可以对表单提交的值进行 ...

  9. WPF中自定义GridLengthAnimation

    需求 我们想在编辑一个列表中某一个条目时,将编辑的详情内容也放置当前面,比如右侧. 可以通过将一个Grid,分成两个Cloumn,动态调整两个Cloumn的Width,就可以实现这个需求. 我们知道, ...

  10. ionic新入坑-环境搭建+新建项目+打开低版本项目处理

    是的.我又双叒叕入新坑了.想我大学的时候web-app刚火起来.还帮忙做了我们学校医务室系统的web-app页面部分呢.时间太紧最后也没出个完整的版本.那时候只是用H5简单做了web部分.是想着用ph ...