业务需求
用户输入语句后,点击“生成字段”按钮,自动生成字段。
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();
}