Code generator that point thing

Code generator that point thing

To talk about the code generator that point thing, some technical solutions, details

Interface List

Check the table

Home

Code structure

Code

Common code

Common code

aims

To simplify the code, generating template code, so there is a code generator.

premise

Premise code generator is already some templates, standardized code. For example, generic DAO layer, Service layer, even
Controller layer.

Technical means

The most basic function

  • Select a template engine familiar, such Freemark, reads the field information database, based on the template to generate the relevant code.
  • Provide a friendly interface, you can check the table needs to support search

Experience Optimization

  • Table support custom entity mapping
  • Support for external data sources
  • Online editing template files

Technical realization

I am here according to the company's technology stack, based on a spring boot and jetbrick template engine developed Java code generator.

stand by

  • Online preview table, select the required table
  • Specify the package prefix table automatically generate code prefixes, supporting custom entity name
  • Sqlite embedded database, no additional configuration, start the project directly.
  • Connecting an external data source (multi-source data automatic switching), generating template code
  • Use lombok simplify template code

Among them, there are relatively bright spot is embedded sqlite database, maintained source information. Read external data source, the data source automatically switched. Other features are more conventional, not further elaborated here.

External data source

First of all maintain connection information for an external data source, and to achieve more dwarfish if so, reads the external data source table structure information jdbcTemplate the like, according to the final rendering template.

However, this is not cool ah!

Data source switching

After the code reading can write the configuration information table, it automatically according to an automatic switch connected to the front end of a selected data source information?

Possible!

The spring jdbc org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSourcegave me inspiration. Familiar with its fellow should know how to operate, and did not know a whole lot online.

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

    @Nullable
    private Map<Object, Object> targetDataSources;

    @Nullable
    private Object defaultTargetDataSource;

    private boolean lenientFallback = true;

    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

    @Nullable
    private Map<Object, DataSource> resolvedDataSources;

    @Nullable
    private DataSource resolvedDefaultDataSource;

    // 省略掉其他代码
}

But there is a problem, you need to advance in the configuration file, or defined the various data sources on program na! Not enough dynamic, maintenance can not be configured on the interface. So, I define a dynamic data source:

/**
 * 动态数据源
 *
 * @author 奔波儿灞
 * @since 1.0
 */
@Slf4j
public class DynamicDataSource extends AbstractDataSource implements DataSourceManager {
    
    /**
     * 维护数据源ID与数据源对应关系
     */ 
    private final ConcurrentMap<Long, DataSource> dataSources;

    /**
     * 默认数据源,也就是内嵌的 sqlite 数据源
     */ 
    private DataSource defaultDataSource;

    public DynamicDataSource() {
        dataSources = new ConcurrentHashMap<>();
    }

    public void setDefaultTargetDataSource(DataSource defaultTargetDataSource) {
        this.defaultDataSource = defaultTargetDataSource;
    }

    @Override
    public Connection getConnection() throws SQLException {
        return determineTargetDataSource().getConnection();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return determineTargetDataSource().getConnection(username, password);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T unwrap(Class<T> iface) throws SQLException {
        if (iface.isInstance(this)) {
            return (T) this;
        }
        return determineTargetDataSource().unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
    }

    /**
     * 主要就是根据此方法,决定获取哪个数据源
     * 通过 ThreadLocal 放入数据源ID,再从 map 中获取到数据源
     */ 
    private DataSource determineTargetDataSource() {
        Long lookupKey = DataSourceContextHolder.getKey();
        DataSource dataSource = Optional.ofNullable(lookupKey)
                .map(dataSources::get)
                .orElse(defaultDataSource);
        if (dataSource == null) {
            throw new IllegalStateException("Cannot determine DataSource for lookup key [" + lookupKey + "]");
        }
        return dataSource;
    }

    /**
     * 界面更新或新增数据源时,更新内部 map 维护信息
     */ 
    @Override
    public void put(Long id, DataSource dataSource) {
        log.info("put datasource: {}", id);
        dataSources.put(id, dataSource);
    }

    @Override
    public DataSource get(Long id) {
        return dataSources.get(id);
    }

    /**
     * 界面删除数据源时,删除内部 map 维护信息
     */ 
    @Override
    public void remove(Long id) {
        log.warn("remove datasource: {}", id);
        dataSources.remove(id);
    }

}

See here, it should Huqu startled fellow, know how the dynamic.

/**
 * 数据源key上下文管理
 *
 * @author 奔波儿灞
 * @since 1.0
 */
public class DataSourceContextHolder {

    private static final ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();

    private DataSourceContextHolder() {
        throw new IllegalStateException("Utils");
    }

    public static synchronized void setKey(Long key) {
        THREAD_LOCAL.set(key);
    }

    public static Long getKey() {
        return THREAD_LOCAL.get();
    }

    public static void clearKey() {
        THREAD_LOCAL.remove();
    }

}

Here is the code, the switching Source:

@Override
public PageInfo<Table> getTables(Long dataSourceId, String database, String table, IPage page) {
    try {
        // 将页面上选取的数据源ID,设置到 ThreadLocal
        DataSourceContextHolder.setKey(dataSourceId);
        // 下面就是分页查询数据源的表信息了,这里使用的是 mybatis pagehelper
        PageHelper.startPage(page);
        return PageInfo.of(tableRepository.getTables(database, table));
    } finally {
        // 最后再将 ThreadLocal 释放,切记切记,防止影响默认数据源,哈哈
        DataSourceContextHolder.clearKey();
    }
}

Of course, write here show that, by way ThreadLocal AOP universal part of the code.

Thinking:

  • After the program starts, the data source defined in the database needs to be maintained to the map information

About Open Source

Feel no need to open source, why do not you own line and a fellow?

Guess you like

Origin www.cnblogs.com/bener/p/12157247.html