项目实训12——解析建表的SQL语句

  管理员可以在管理员端新建存储用户信息的数据库并建表,也可以选定已有的用户数据库来建表。之前的界面是让管理员先确定有哪些列,然后为这些列填写中文名和中文描述以及选定类型。这里的创建表不是很灵活,不能随意选择字段长度而且不能建立多个主键和外键。新迭代的功能为允许管理员使用SQL语句建表。调用SQL语句并不难,但是系统数据库需要存储新建表的字段名、类型及介绍,难点在于如何分解SQL语句得到字段名和字段类型。
  SQL语句以String类型存在,建表语句中可能会有多个空格,所以用空格作为分割符不能成功拆分字段名和字段类型,而且可能还有类似“primary key”、“aoto_increment”、“not null”等补充属性扰乱第一列和第二列的分割。我想到最后还是需要工具包介入才能实现建表SQL的分解。网上几乎没有分解建表语句的教程,我根据一个分解select语句的教程编写了分解create语句的代码。项目需要引入druid包的依赖,使用这个包的类和方法分解SQL。依赖代码如下:

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>

项目的application.properties也需要更改:

server.port=8080
spring.datasource.name==druid
spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.url=jdbc:mysql://localhost:3306/databaseName?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=root
spring.datasource.druid.password=xxxxxxxx
spring.datasource.druid.filters=stat

  首先明确我想获得的是create table语句中的字段名和相应的字段类型以及字段描述。druid包中有对应不同类型SQL语句的类,比如新建数据库语句应使用SQLCreateDatabaseStatement类型,删除索引表语句应使用SQLDropIndexStatement类型,新建表应使用SQLCreateTableStatement类型,使用不对应的类型不会解析出正确的结果。我一开始就是按照解析select语句的教程使用错了对象,一直没有解析出字段名和类型。而且druid包也可以解析不同数据库的语句,这一点也要注意,不同数据库的SQL语句有些许的语法差异。解析的第一步要先声明一个SQLStatementParser类型的对象parser,我使用的是MySQL数据库,所以new出的子类型是MySqlStatementParser。第二步声明一个SQLCreateTableStatement对象sqlCreateTableStatement等于parser.parseCreateTable()。parser调用的方法也是对应create table类型的语句,其他操作要使用对应的parse方法。第三步声明一个SQLObject类型的List对象sqlObjects存储sqlCreateTableStatement的子对象,这些子对象就存储了每个字段的信息。然后使用一个for循环处理sqlObjects中每一个子对象。获取具体信息之前先判断sqlObjects实例化之后是否为SQLColumnDefinition类型,即列定义对象。如果是,则通过columnDefinition.getNameAsString()获得字段名,columnDefinition.getDataType().getName()获得字段类型,(String) ((SQLCharExpr) columnDefinition.getComment()).getValue()获得字段描述。注意这时的字段类型不包括括号内的字段长度。使用((SQLIntegerExpr) arguments.get(0)).getNumber().toString()获得字段的长度,再通过字符串拼接获得完整的字段类型。获得的信息存在一个meta对象,循环的一个meta类型的List对象。再循环执行插入DBID_CID_META表的操作。这样就完成了解析建表SQL语句的操作。具体代码如下:

    public void assembleMeta(List<Meta> metaList, String sql) {
        SQLStatementParser parser = new MySqlStatementParser(sql);
        SQLCreateTableStatement sqlCreateTableStatement=parser.parseCreateTable();
        List<SQLObject> sqlObjects = sqlCreateTableStatement.getChildren();

        for (SQLObject sqlObject : sqlObjects) {
            if (sqlObject instanceof SQLColumnDefinition) {
                SQLColumnDefinition columnDefinition = ((SQLColumnDefinition) sqlObject);
                Meta meta=new Meta();
                meta.setEN(columnDefinition.getNameAsString());
                System.out.println("从SQL中获得的字段名:"+meta.getEN());
                String metaType=columnDefinition.getDataType().getName();
                List<SQLExpr> arguments = columnDefinition.getDataType().getArguments();
                if (!CollectionUtils.isEmpty(arguments)) {
                    metaType=metaType+"("+((SQLIntegerExpr) arguments.get(0)).getNumber().toString()+")";
                }
                meta.setCN(metaType);
                System.out.println("从SQL中获得的字段类型:"+meta.getCN());
                if (columnDefinition.getComment() != null) {
                    meta.setDes((String) ((SQLCharExpr) columnDefinition.getComment()).getValue());
                    System.out.println("从SQL中获得的字段描述:"+meta.getDes());
                }else{
                    meta.setDes("暂无介绍!");
                    System.out.println("从SQL中获得的字段描述:"+meta.getDes());
                }
                meta.setZhengze("F");
                metaList.add(meta);
            }else{
                System.out.println("类型还是不对!");
            }
        }
    }

controller层的调用代码:

    @ResponseBody
    @RequestMapping(value = "/createSQL",method = RequestMethod.POST)
    public Map<String, Object> createSQL(HttpServletRequest req) throws SQLException {
        Map<String, Object> map = new HashMap<>();
        int DBid =Integer.parseInt(req.getParameter("DBid").trim());
        System.out.println("用户数据库编号:"+DBid);
        int Cid =Integer.parseInt(req.getParameter("Cid").trim());
        System.out.println("新建的表编号:"+Cid);
        String sql =req.getParameter("sql").trim();

        int ctsql=chartService.sqlCreateTable(DBid,sql);
        System.out.println("在用户数据库建表成功!");

        List<Meta> metaList=new ArrayList<>();
        getFromSQL g=new getFromSQL();
        g.assembleMeta(metaList,sql);
        int [] um=new int[metaList.size()];
        int judge=0;
        for(int i=0; i<metaList.size(); i++){
            um[i]=metaService.insertMeta(DBid,Cid,metaList.get(i).getEN(),metaList.get(i).getCN(),metaList.get(i).getDes());
            System.out.println("um["+i+"]="+um[i]);
            if(um[i]!=0)
                judge=1;
        }

        if (ctsql==0&&judge==0) {
            map.put("state", true);
            map.put("msg", "使用SQL建表成功!");
        } else {
            map.put("state", false);
            map.put("msg", "建表失败!请检查SQL语句语法问题!");
        }
        return map;
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值