元数据项目使用的设计模式

业务需求

用户输入语句后,点击“生成字段”按钮,自动生成字段。

1、用户点击DDL建表,2、在谈出的框输入创建语句,3、点击生成字段后字段列表展示对应的字段。

 

实现思路-策略模式+工厂模式

通过策略者模式+工厂模式实现

不同数据库解析对应的ddl后得到的对象都不同,获取的字段方式也不同,通过策略者模式将对应的获取方式封装在对应的数据库类内部处理。然后通过工厂类获取对应的实现。

实现方式

DDLColumnHandle接口,supports方法返回不同的数据库类型,getColumns方法通过数据库类型获取不同的处理方法。
AbstractDDLColumnHandle抽象方法,实现DDLColumnHandle。内部提供三个抽象方法。
    getCreateTableStatement()每一种数据库如何获取解析ddl得到的对象
    doGetColumns()获取解析得到的对象,转换系统定义的对象
    setTableInfo()获取表信息的每个数据库类型也不同
HiveDDLColumnHandle、MysqlDDLColumnHandle、OracleDDLColumnHandle实现去处理具体的逻辑

DDLColumnHandleFactory通过数据库类型获取不同的数据库实现方式,spring初始化后获取接口的所有实现类,放入map中supports方法返回值当做map的key,map的value则是对应的实现类。

public interface DDLColumnHandle {

    /**
     * 数据库类型类型
     * @return
     */
    DatabaseTypeEnum supports();

    /**
     * 获取ddl解析对象
     * @param sql
     * @param dbType
     * @param dwLevel
     * @return
     * @throws MetadataException
     */
    DDLRsp getColumns(String sql, String dbType, String dwLevel) throws MetadataException;
}
public enum DatabaseTypeEnum {
    /** . */
    TYPE_HIVE("hive", "hive数据库"),
    /** . */
    TYPE_MYSQL("mysql", "mysql数据库"),
}

 

@Component
public abstract class AbstractDDLColumnHandle<T> implements DDLColumnHandle{

    private static final String CHECK_COLUMN_ERROR_MSG = "字段不存在,字段类型不准确,请检查代码!";


    @Override
    public DDLRsp getColumns(String sql, String dbType, String dwLevel) throws MetadataException {
        SQLStatement stmt = getSQLStatement( dbType,  sql);

        DDLRsp rsp = new DDLRsp();
        List<MetaColumn> columns = doGetColumns(stmt, dwLevel);
        rsp.setColumns(columns);
        setTableInfo(stmt,rsp);
        return rsp;
    }

    /**
     * 获取解析得到的对象,转换系统定义的对象
     * @param stmt
     * @param dwLevel
     * @return
     * @throws MetadataException
     */
    abstract List<MetaColumn> doGetColumns(SQLStatement stmt, String dwLevel) throws MetadataException;


    /**
     * 转换不同数据库类型处理器,获取解析ddl得到的对象
     * @param stmt
     * @return
     * @throws MetadataException
     */
    abstract T getCreateTableStatement(SQLStatement stmt) throws MetadataException;


    /**
     * set关于表配置信息
     * @param stmt
     * @param rsp
     * @throws MetadataException
     */
    abstract void setTableInfo(SQLStatement stmt,DDLRsp rsp) throws MetadataException;




    protected MetaColumn getColumn(ColumnReq req,String isPartCol) throws MetadataException {
        ColumnDao columnDao = SpringUtil.getBean(ColumnDao.class);
        List<MetaColumn> metaColumns = Optional.ofNullable(columnDao.selectList(req)).orElse(Collections.emptyList());
        if (CollectionUtils.isEmpty(metaColumns)){
            //ods层字段允许字段库不存在对应字段
            if(StringUtils.equals(StandardTypeEnum.TYPE_ODS.geteCode(),req.getStandardType())){
                MetaColumn mc = new MetaColumn();
                mc.setColumnName(req.getColumnName());
                mc.setTypeName(req.getTypeName());
                mc.setComment(req.getComment());
                return mc;
            }else{
                throw new MetadataException(req.getColumnName()+"-"+req.getTypeName()+"-"+(req.getComment() == null ? "" : req.getComment()) +","+ CHECK_COLUMN_ERROR_MSG);
            }
        }
        if (metaColumns.size() >= 2){
            Optional<MetaColumn> optMc = metaColumns.stream().filter(v -> StringUtils.equals(v.getIsPartCol(),isPartCol)).findAny();
            if (optMc.isPresent()){
                return optMc.get();
            }
        }

        return metaColumns.get(0);
    }

    protected ColumnReq getColumnReq(SQLColumnDefinition sd,String dwLevel){
        String standardType = StringUtils.equals(StandardTypeEnum.TYPE_ODS.geteCode(),dwLevel) ?  dwLevel : StandardTypeEnum.TYPE_STANDARD.geteCode();
        ColumnReq req = new ColumnReq();
        req.setColumnName(sd.getName().getSimpleName());
        req.setTypeName(sd.getDataType().getName());
        req.setStandardType(standardType);
        SQLCharExpr sqlCharExpr = (SQLCharExpr) sd.getComment();
        if (sqlCharExpr != null){
            req.setComment(sqlCharExpr.getText());
        }
        return req;
    }


    private SQLStatement getSQLStatement(String dbType, String sql) throws MetadataException {
        List<SQLStatement> stmtList =  null;
        try {
            SQLUtils.format(sql, dbType);
            stmtList = SQLUtils.parseStatements(sql, dbType);
        }catch (ParserException e){
            throw new MetadataException("解析DDL异常!",e);
        }

        return stmtList.get(0);
    }
}
@Component
public class HiveDDLColumnHandle extends AbstractDDLColumnHandle{

    @Override
    public DatabaseTypeEnum supports() {
        return DatabaseTypeEnum.TYPE_HIVE;
    }


    @Override
    List<MetaColumn> doGetColumns(SQLStatement stmt,String dwLevel) throws MetadataException {
        List<MetaColumn> columns = Lists.newArrayList();
        for (SQLTableElement ste : getCreateTableStatement(stmt).getTableElementList()){
            SQLColumnDefinition sd = (SQLColumnDefinition)ste;
            MetaColumn column = getColumn(getColumnReq(sd,dwLevel),FlagEnum.FLAG_N.geteCode());
            column.setIsPartCol(FlagEnum.FLAG_N.geteCode());
            columns.add(column);
        }

        //分区列表查询
        List<SQLColumnDefinition> partitionColumns = getCreateTableStatement(stmt).getPartitionColumns();
        for (SQLColumnDefinition pc : partitionColumns){
            MetaColumn column = getColumn(getColumnReq(pc,dwLevel),FlagEnum.FLAG_Y.geteCode());
            column.setIsPartCol(FlagEnum.FLAG_Y.geteCode());
            columns.add(column);
        }
        return columns;
    }

    @Override
    public HiveCreateTableStatement getCreateTableStatement(SQLStatement stmt) throws MetadataException {
        return ((HiveCreateTableStatement) stmt);
    }

    @Override
    public  void setTableInfo(SQLStatement stmt,DDLRsp rsp) throws MetadataException {
        HiveCreateTableStatement statement = getCreateTableStatement( stmt) ;
        SQLExprTableSource source = ((HiveCreateTableStatement) stmt).getTableSource();
        rsp.setTableName(source.getName().getSimpleName());
        SQLCharExpr sqlExpr = (SQLCharExpr) statement.getComment();
        rsp.setCnName(sqlExpr.getText() != null ? sqlExpr.getText() : "");
    }

}
@Component
public class MysqlDDLColumnHandle extends AbstractDDLColumnHandle{

    @Override
    public DatabaseTypeEnum supports() {
        return DatabaseTypeEnum.TYPE_MYSQL;
    }


    @Override
    List<MetaColumn> doGetColumns(SQLStatement stmt,String dwLevel) throws MetadataException {
        List<MetaColumn> columns = Lists.newArrayList();
        for (SQLTableElement ste : getCreateTableStatement(stmt).getTableElementList()){
            SQLColumnDefinition sd = (SQLColumnDefinition)ste;
            MetaColumn column = getColumn(getColumnReq(sd,dwLevel),FlagEnum.FLAG_N.geteCode());
            column.setIsPartCol(FlagEnum.FLAG_N.geteCode());
            columns.add(column);
        }

        return columns;
    }

    @Override
    public MySqlCreateTableStatement getCreateTableStatement(SQLStatement stmt) throws MetadataException {
        return ((MySqlCreateTableStatement) stmt);
    }

    @Override
    public  void setTableInfo(SQLStatement stmt,DDLRsp rsp) throws MetadataException {
        MySqlCreateTableStatement statement = getCreateTableStatement( stmt) ;
        SQLExprTableSource source = statement.getTableSource();
        rsp.setTableName(source.getName().getSimpleName());
        SQLCharExpr sqlExpr = (SQLCharExpr) statement.getComment();
        rsp.setCnName(sqlExpr.getText() != null ? sqlExpr.getText() : "");
    }

}

 

@Component
public class DDLColumnHandleFactory implements InitializingBean, ApplicationContextAware {


    private static ApplicationContext applicationContext;

    private static Map<String, DDLColumnHandle> handleMap = Maps.newConcurrentMap();

    @Override
    public void afterPropertiesSet() throws Exception {

        Collection<DDLColumnHandle> th = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, DDLColumnHandle.class).values();
        th.forEach(v -> handleMap.put(v.supports().geteCode(), v));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        setAppContext(applicationContext);
    }

    private static void setAppContext(ApplicationContext applicationContext) {
        DDLColumnHandleFactory.applicationContext = applicationContext;
    }

    public static DDLColumnHandle getHandle(DatabaseTypeEnum type) throws MetadataException {
        DDLColumnHandle typeHandler = handleMap.get(type.geteCode());
        if (typeHandler == null) {
            throw new MetadataException("未找到处理器!");
        }
        return typeHandler;
    }

    public static DDLColumnHandle getHandle(String type) throws MetadataException {
        DDLColumnHandle typeHandler = handleMap.get(type);
        if (typeHandler == null) {
            throw new MetadataException("未找到处理器!");
        }
        return typeHandler;
    }

}
public class TableServiceImpl implements TableService {
   
    @Override
    public DDLRsp ddl(String sql, String dbType, String dwLevel) throws MetadataException{
        DDLRsp rsp = DDLColumnHandleFactory.getHandle(dbType).getColumns(sql,dbType,dwLevel);
        return rsp;
    }
}

==========================================================================================

业务需求

用户配置表信息,在业务数据库执行插入表且在对应的数据库创建对应的表

实现思路-迭代器模式+代理模式+观察者模式+模板模式

用户提交到后台,通过代理切面模式对应的保存方法,内部通过迭代器模式校验参数业务限制逻辑,观察者模式通知对应的监听者处理对应的业务逻辑,模板模式去拼接ddl创建语句。

 迭代器模式,提供工厂工具类获取所有实现。

观察者模式,执行创建表通知对应的监听者执行对应的业务逻辑

 模板模式,拼接ddl创建sql语句

实现方式

代理切面逻辑

@Aspect
@Component
public class EditTableAspect {

    @Pointcut("execution(public * cn.evun.geely.metadata.manage.service.TableService.edit(*,*))")
    public void aopEnter(){}

    @Before("aopEnter()")
    public void doBefore(JoinPoint joinPoint) throws MetadataException {

        //获取请求报文头部元数据
        ServletRequestAttributes requestAttributes= (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        //获取请求对象
        String tableStr = (String) joinPoint.getArgs()[0];
        String tcpsStr = (String) joinPoint.getArgs()[1];
        MetaTable table;
        List<TableColumnParam> tcps;
        try {
            table = JSONObject.parseObject(tableStr,MetaTable.class);
            tcps = JSONObject.parseArray(tcpsStr,TableColumnParam.class);
        }catch (JSONException e){
            throw new MetadataException("请求参数格式传入有误!",e);
        }

        List<EditTableFitler> fitlers = FitlerFactory.getEditTableFitler();

        for (EditTableFitler f : fitlers){
            f.fitler(table,tcps);
        }
    }

    @AfterReturning(returning = "ret",pointcut = "aopEnter()")
    public void doAfter(Object ret){
    }
}

代理切面方式切入对应的方法执行前置过滤校验

过滤器逻辑

public interface EditTableFitler {

    Integer sorted();

    void fitler(MetaTable table, List<TableColumnParam> tcps) throws MetadataException;
}
/**
 * Created by Jiyang.Zheng on 2019/9/9 13:31.
 * 验证某个字段是否已经被更新为码表值,如果已经被更新,如果在传入则提示,已经被更新
 */
@Component
public class IsDimUpdateTableFitler implements EditTableFitler {
    @Autowired
    private ColumnService columnService;

    @Override
    public Integer sorted() {
        return 4;
    }

    @Override
    public void fitler(MetaTable table, List<TableColumnParam> tcps)throws MetadataException {
        if (StringUtils.equals(table.getIsDim(),FlagEnum.FLAG_Y.geteCode())){
            boolean flag = tcps.stream().anyMatch(v -> StringUtils.equals(v.getIsDimCol(),FlagEnum.FLAG_Y.geteCode()));
            if (!flag){
                throw new MetadataException("码表必需要存在一个码值!");
            }
        }
        for (TableColumnParam t : tcps){

            MetaColumn column = columnService.selectColumn(t.getColId());

            //如果是码表字段,且此字段已经被别的码表更新
            if (StringUtils.equals(table.getIsDim(),FlagEnum.FLAG_Y.geteCode()) &&
                    StringUtils.equals(t.getIsDimCol(),FlagEnum.FLAG_Y.geteCode())
                    && (column.getRelId() != null && ObjectUtils.notEqual(column.getRelId(),table.getId()))){
                throw new MetadataException(column.getColumnName()+"字段已被标记过码值,不可重复标记!");
            }
        }

    }
}
@Component
public class ParamEditTableFitler implements EditTableFitler {
    @Autowired
    private ColumnDao columnDao;

    @Override
    public Integer sorted() {
        return 1;
    }

    @Override
    public void fitler(MetaTable table, List<TableColumnParam> tcps) throws MetadataException {

        if (table.getDbId() == null){
            throw new MetadataException("必须归属某个数据库!");
        }
        if (table.getId() == null && CollectionUtils.isEmpty(tcps)){
            throw new MetadataException("字段不允许为空!");
        }

        if (CollectionUtils.isNotEmpty(tcps)){
            boolean flag = tcps.stream().anyMatch(v -> StringUtils.equals(v.getIsPartCol(),FlagEnum.FLAG_N.geteCode()));
//            List<TableColumnParam> ts = tcps.stream().filter(v -> StringUtils.equals(v.getIsPartCol(),FlagEnum.FLAG_N.geteCode())).collect(Collectors.toList());
            if (!flag){
                throw new MetadataException("必须包含非分区字段!");
            }

            ColumnReq req = new ColumnReq();
            List<Integer> colIds = tcps.stream().filter(v -> v.getColId() != null).map(v -> v.getColId()).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(colIds)){
                return;
            }
            req.setIds(colIds);
            List<MetaColumn> list = columnDao.selectList(req);
            Map<String,String> ukCol = Maps.newHashMap();
            for (MetaColumn v: list){
                String col = ukCol.get(v.getColumnName());
                if (StringUtils.isNotEmpty(col)){
                    throw new MetadataException("字段不允许重复!");
                }else {
                    ukCol.put(v.getColumnName(),FlagEnum.FLAG_Y.geteCode());
                }
            }

        }

    }
}
@Component
public class TableNameUkEditTableFitler implements EditTableFitler {
    @Autowired
    private TableService tableService;

    @Override
    public Integer sorted() {
        return 2;
    }

    @Override
    public void fitler(MetaTable table, List<TableColumnParam> tcps)throws MetadataException {

        if (table.getId() != null){
            return;
        }
        MetaTable t = tableService.selectByTableName(table.getTableName(),table.getDbId());
        if (t != null){
            throw new MetadataException("数据库表名称已存在!");
        }
    }
}
@Component
public class FitlerFactory implements InitializingBean, ApplicationContextAware {


    private static ApplicationContext applicationContext;

    private static List<EditTableFitler> editTableFitler;

    @Override
    public void afterPropertiesSet() throws Exception {
        Collection<EditTableFitler> th = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, EditTableFitler.class).values();
        setEditTableFitler(th.stream().sorted(Comparator.comparing(EditTableFitler::sorted)).collect(Collectors.toList()));
    }

    private static void setEditTableFitler(List<EditTableFitler> editTableFitlers) {
        FitlerFactory.editTableFitler = editTableFitlers;
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        setAppContext(applicationContext);
    }

    private static void setAppContext(ApplicationContext applicationContext) {
        FitlerFactory.applicationContext = applicationContext;
    }

    public static List<EditTableFitler> getEditTableFitler() {
        return editTableFitler;
    }

}

观察者模式实现逻辑

public interface TableEditSubject {

    void registerObserver(TableEditObserver ovserver);
    void removeObserver(TableEditObserver ovserver);
    void notifyObservers(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException;
}
public interface TableEditObserver {
    void tableEdit(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException;
}
@Service
public class TableEditHandle implements TableEditSubject {

    private List<TableEditObserver> observers;

    public TableEditHandle() {
        observers = Lists.newCopyOnWriteArrayList();
    }

    @Override
    public void registerObserver(TableEditObserver ovserver) {
        observers.add(ovserver);
    }

    @Override
    public void removeObserver(TableEditObserver ovserver) {
        if(observers.indexOf(ovserver)>0){
            observers.remove(observers.indexOf(ovserver));
        }
    }

    @Override
    public void notifyObservers(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException {
        for(TableEditObserver o :observers){
            o.tableEdit(table,tcps,isAdd);
        }
    }

}
/**
 * Created by jiyang.zheng on 2019/9/6 10:01.
 * 表关联字段业务处理
 */
public class TableColumnSortObserver implements TableEditObserver {

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException {
        TableDao tableDao = SpringUtil.getBean(TableDao.class);
        if (StringUtils.equals(FlagEnum.FLAG_N.geteCode(),isAdd) && CollectionUtils.isNotEmpty(tcps)){
            tableDao.deleteTblsColumns(table.getId(),null);
        }

        tcps.stream().forEach(v ->{
            ColumnSort columnSort = new ColumnSort();
            columnSort.setTblId(table.getId());
            columnSort.setColId(v.getColId());
            columnSort.setIdx(v.getIdx());
            tableDao.insertTblsColumns(columnSort);
        });

    }
}
/**
 * ods表新增表,如果字段不存在数据库则新建字段
 * Created by Jiyang.Zheng on 2019/9/9 13:30.
 */
public class OdsColumnIsNullObserver implements TableEditObserver {

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps, String isAdd) throws MetadataException {
        //必须是ods 表
        if (!StringUtils.equals(table.getDwLevel(),DwLevelEnum.TYPE_ODS.geteCode())){
            return;
        }
        ColumnService columnService = SpringUtil.getBean(ColumnService.class);

        for (TableColumnParam tcp : tcps){
            if (tcp.getColId() != null){
                continue;
            }
            MetaColumn mc = new MetaColumn();
            BeanUtils.copyProperties(tcp,mc);
            mc.setColAttr(ColumnAttrEnum.ATTR_N.geteCode());
            mc.setDbType(table.getDbType());
            mc.setStandardType(StandardTypeEnum.TYPE_ODS.geteCode());
            mc.setIsDimCol(FlagEnum.FLAG_N.geteCode());
            Integer columnId = columnService.addMetaColumn(mc);
            tcp.setColId(columnId);
        }

    }
}
/**
 * Created by jiyang.zheng on 2019/9/6 10:01.
 * 表关联字段修改处理
 */
public class MetaColumnObserver implements TableEditObserver {


    /**
     * 相同的字段允许存在2条数据,一条非分区、一条分区记录
     * 新建立一个字段,默认是非分区字段,在新建立表,验证用户是否设置某个字段是分区字段,且数据库是否存在
     * 对应的分区数据,如果没有则新建一条分区数据,且将插入的那条字段数据,替换掉 tcps对应的某条记录
     *
     * @param table
     * @param tcps
     * @param isAdd
     * @throws MetadataException
     */

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps, String isAdd) throws MetadataException {
        ColumnService columnService = SpringUtil.getBean(ColumnService.class);
        ColumnDao columnDao = SpringUtil.getBean(ColumnDao.class);
        for (TableColumnParam v : tcps) {

            MetaColumn mc = setMetaColumn(table, v);
            columnService.updateColumn(mc);

        }

        //过滤出分区字段
        List<TableColumnParam> partCols = tcps.stream().filter(v -> StringUtils.equals(FlagEnum.FLAG_Y.geteCode(), v.getIsPartCol())).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(partCols)) {
            return;
        }
        //验证是否需重新插入
        Map<Integer, Integer> editColumnIds = Maps.newHashMap();
        for (TableColumnParam p : partCols) {
            MetaColumn metaColumn = columnService.selectColumn(p.getColId());
            List<MetaColumn> list = columnDao.selectList(MetadataUtil.getColumnReq(metaColumn));
            //存在分区和非分区2条记录
            if (list.size() >= 2) {
            } else {
                //只存在1条,且是非分区数据,则插入一条分区数据
                //如果当前记录是非分区记录,则插入一条是分区的记录
                if (metaColumn != null && StringUtils.equals(FlagEnum.FLAG_N.geteCode(), metaColumn.getIsPartCol())) {
                    Integer metaColumnId = metaColumn.getId();
                    metaColumn.setId(null);
                    metaColumn.setIsPartCol(FlagEnum.FLAG_Y.geteCode());
                    metaColumn.setCreateUser(null);
                    metaColumn.setModifyUser(null);
                    columnDao.insertColumn(metaColumn);
                    editColumnIds.put(metaColumnId, metaColumn.getId());
                }
            }
        }
        replaceTableColumnParams(editColumnIds, tcps);
    }

    private void replaceTableColumnParams(Map<Integer, Integer> editColumnIds, List<TableColumnParam> tcps) {
        //替换tcps 某条数据
        if (MapUtils.isNotEmpty(editColumnIds)) {
            tcps.forEach(v -> {
                Integer changeColumnId = editColumnIds.get(v.getColId());
                if (changeColumnId != null) {
                    v.setColId(changeColumnId);
                }
            });
        }
    }

    private MetaColumn setMetaColumn(MetaTable table, TableColumnParam v) {
        MetaColumn mc = null;
       
        mc = new MetaColumn();
        mc.setId(v.getColId());
        //是码表,且是码值
        if (StringUtils.equals(table.getIsDim(), FlagEnum.FLAG_Y.geteCode()) && StringUtils.equals(v.getIsDimCol(), FlagEnum.FLAG_Y.geteCode())) {
            mc.setColAttr(ColumnAttrEnum.ATTR_D.geteCode());
            mc.setRelId(table.getId());
        }else {
            mc.setColAttr(StringUtils.isEmpty(v.getColAttr()) ? ColumnAttrEnum.ATTR_N.geteCode() : v.getColAttr());
            mc.setRelId(v.getRelId());
        }
        mc.setIsDimCol(v.getIsDimCol());
        mc.setRelInfo(v.getRelInfo());

        return mc;
    }
}
/**
 * Created by jiyang.zheng on 2019/9/6 10:01.
 * 执行ddl语句
 */
public class ExeSqlObserver implements TableEditObserver {

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException {
        JDBCDao jdbcDao = SpringUtil.getBean(JDBCDao.class);
        String ddlSql;
        DDLJointTemplate template =  DDLJointTemplateUtil.getDDLJointTemplate(table.getDbType());

        if (StringUtils.equals(isAdd,FlagEnum.FLAG_Y.geteCode())){
            ddlSql = template.getCreateDDl(table);
            jdbcDao.exeTable(ddlSql,table);
        }else {
            List<String> list = DDLJointTemplateUtil.executeAlertDDL(table,tcps);
            for (String v : list){
                jdbcDao.exeTable(v,table);
            }
        }

    }

}
/**
 * Created by jiyang.zheng on 2019/9/6 10:01.
 * 元数据表处理
 */
public class EditMetaTableObserver implements TableEditObserver {

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException {
        TableDao tableDao = SpringUtil.getBean(TableDao.class);
        DatabaseDao databaseDao = SpringUtil.getBean(DatabaseDao.class);
        MetaDatabase metaDatabase = databaseDao.selectDbById(table.getDbId()+"");
        table.setDbName(metaDatabase.getDbName());
        if (StringUtils.equals(isAdd,FlagEnum.FLAG_Y.geteCode())){
            tableDao.insert(table);
        }else {
            tableDao.update(table);
        }

        TableServiceImpl.tableId.set(table.getId());

    }
}
/**
 * Created by jiyang.zheng on 2019/9/6 10:01.
 * 执行ddl语句处理
 */
public class DDLLogObserver implements TableEditObserver {

    @Override
    public void tableEdit(MetaTable table, List<TableColumnParam> tcps,String isAdd) throws MetadataException {
        TableDao tableDao = SpringUtil.getBean(TableDao.class);
        String ddlSql="";
        MetaTableLog log = new MetaTableLog();
        DDLJointTemplate template =  DDLJointTemplateUtil.getDDLJointTemplate(table.getDbType());
        if (StringUtils.equals(isAdd,FlagEnum.FLAG_Y.geteCode())){
            ddlSql = template.getCreateDDl(table);
            log.setDdl(ddlSql);
        }else {
            List<String> ddlSqls = DDLJointTemplateUtil.executeAlertDDL(table,tcps);
            ddlSql = ddlSqls.toString();
            log.setDdl(ddlSqls.stream().collect(Collectors.joining(",")));
        }
        log.setCreateUser(UserUtil.getEmpNameAndEmpNo(""));
        log.setTblId(table.getId());
        if (StringUtils.isNotEmpty(ddlSql)){
            tableDao.insertTableLog(log);
        }


    }
}
public class SpringUtil implements InitializingBean, ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void afterPropertiesSet() {
        //注册修改表事件处理
        registerEditTableObserver();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        setAppContext(applicationContext);
    }

    private static void setAppContext(ApplicationContext applicationContext) {
        SpringUtil.applicationContext = applicationContext;
    }


    private void registerEditTableObserver() {
        TableEditSubject subject = getBean(TableEditSubject.class);
        //主表
        subject.registerObserver(new EditMetaTableObserver());
        //扩展表
        subject.registerObserver(new TableInfoExtObserver());
        //ods表 字段库可能不存在对应字段,如果不存在则新建
        subject.registerObserver(new OdsColumnIsNullObserver());
        //字段表
        subject.registerObserver(new MetaColumnObserver());
        //表字段关联表
        subject.registerObserver(new TableColumnSortObserver());//依赖 MetaColumnObserver
        //ddl log表记录表
        subject.registerObserver(new DDLLogObserver());
        //执行 ddl 语句
        subject.registerObserver(new ExeSqlObserver());

    }


    
}

模板模式实现

/**
 * ddl 语句拼接
 * Created by Jiyang.Zheng on 2019/9/9 17:14.
 */
public abstract class DDLJointTemplate {

    public String getCreateDDl(MetaTable table) throws MetadataException {
        StringBuilder sb = new StringBuilder();
        sb.append(appendCreateSqlStartToken(table));
        sb.append(appendSqlColumn(table));
        sb.append(appendSqlEndToken(table));
        return sb.toString();
    }

    /**
     * 拼接前缀sql
     * @param table
     * @return
     */
    abstract String appendCreateSqlStartToken(MetaTable table);

    /**
     * 拼接字段内容sql
     * @param table
     * @return
     * @throws MetadataException
     */
    abstract String appendSqlColumn(MetaTable table) throws MetadataException;

    /**
     * 拼接后缀sql
     * @param table
     * @return
     */
    abstract String appendSqlEndToken(MetaTable table);

}
public class HiveDDLJointTemplate extends DDLJointTemplate {

    private final String comment = " comment ";

    @Override
    String appendCreateSqlStartToken(MetaTable table) {
        return getSqlStartToken(table);
    }


    @Override
    String appendSqlColumn(MetaTable table) throws MetadataException {

        StringBuilder sb = new StringBuilder(" ( ");
        ColumnService columnService = SpringUtil.getBean(ColumnService.class);
        List<MetaColumn> mcs = columnService.selectTableColumnList(table.getId());
        //分区字段列表
        List<MetaColumn> isPartCol = mcs.stream().filter(v -> StringUtils.equals(v.getIsPartCol(), FlagEnum.FLAG_Y.geteCode())).sorted(Comparator.comparing(MetaColumn::getIdx)).collect(Collectors.toList());
        //非分区字段列表
        List<MetaColumn> notPartCol = mcs.stream().filter(v -> StringUtils.equals(v.getIsPartCol(), FlagEnum.FLAG_N.geteCode())).sorted(Comparator.comparing(MetaColumn::getIdx)).collect(Collectors.toList());

        //拼接非分区字段
        notPartCol.stream().forEach(v -> {
            sb.append(v.getColumnName() + " " + v.getTypeName() + comment + "'" + (StringUtils.isEmpty(v.getComment()) ? "" : v.getComment()) + "',");
        });
        sb.deleteCharAt(sb.length() - 1);

        //拼接字段结束符
        sb.append(" ) ");

        //拼接表注释
        sb.append(" comment '" + table.getTableDesc() + "' ");

        if (CollectionUtils.isNotEmpty(isPartCol)) {
            //拼接分区字段
            sb.append(" partitioned by ( ");
            isPartCol.stream().forEach(v -> {
                sb.append(v.getColumnName() + " " + v.getTypeName() + comment + "'" + (StringUtils.isEmpty(v.getComment()) ? "" : v.getComment()) + "',");
            });
            sb.deleteCharAt(sb.length() - 1);

            //拼接分区结束符
            sb.append(" ) ");
        }


        return sb.toString();
    }

    @Override
    String appendSqlEndToken(MetaTable table) {
        if (StringUtils.isNotEmpty(table.getTableDdlExt())) {
            return table.getTableDdlExt();
        }
        return "";
    }

    private String getSqlStartToken(MetaTable table) {
        String tableName = table.getDbName()+"." + table.getTableName();
        String sql;
        if (StringUtils.equals(TableTypeEnum.TYPE_EXT.geteCode(), table.getTblType())) {
            sql = "create external  table " + tableName;
        } else {
            sql = "create table " + tableName;
        }

        return sql;
    }
}

业务代码调用

@Service
public class TableServiceImpl implements TableService {
    
    @Autowired
    private TableEditSubject tableEditSubject;

    public static ThreadLocal<Integer> tableId = new ThreadLocal<>();


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer edit(String tableStr, String tcpsStr) throws MetadataException {

        MetaTable table = JSONObject.parseObject(tableStr,MetaTable.class);
        List<TableColumnParam> tcps = JSONObject.parseArray(tcpsStr,TableColumnParam.class);
        String isAdd = table.getId() == null ? FlagEnum.FLAG_Y.geteCode() : FlagEnum.FLAG_N.geteCode();
        tableEditSubject.notifyObservers(table,tcps,isAdd);
        return tableId.get();
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值