0
0

More than 3 years have passed since last update.

TERASOLUNAのJdbcCodeListの読み込みが遅いので一度に複数登録出来るようにしてみた

Last updated at Posted at 2020-02-01

TERASOLUNAのJdbcCodeListはデータベースからSQLで検索した結果をコードリストとして登録する機能で、よく使われていると思います。
1つや2つのコードリストなら大したことはないのですが、コードリストの数が数百のクラスになってくると起動にかかる時間が耐えがたいレベルにまでなってきます。

そこで下記のようにUNION ALLで複数のコードリストを1度に登録できないものかと。

SELECT code_bean_name, code_id, code_name FROM t_sample_codes WHERE code_bean_name = 'CL_ORDERSTATUS'
UNION ALL
SELECT code_bean_name, code_id, code_name FROM t_sample_codes WHERE code_bean_name = 'CL_HOGE'
ORDER BY code_bean_name, code_id

コードリストは1コードリスト1Bean定義となっているので、複数のコードリストを登録するには、動的にBean定義を追加してやる必要があります。
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor インタフェースの実装クラスを作ってあげれば、どうやら動的にBeanを追加できそうです。
このBeanDefinitionRegistryPostProcessorの実装クラスからDBアクセスしてコードリストのBeanを登録してやれば、思った物ができそうです。

ところが実際動かしてみると、DBアクセスがうまいこといきません。
どうやらBeanDefinitionRegistryPostProcessorが動くタイミングでは、Bean定義の ${hogehoge} みたいなプレースホルダが解決される前のようで、DBの接続文字列などがプロパティから設定される前の文字列(${hogehoge}自体)が取れてきてしまっていて、うまく接続できないようです。
DataSourceの定義にプレースホルダを使用せず、Bean定義に直に接続文字列などを記述すれば、DB接続はできるのですがXMLに直書きはどうにもイマイチです。

そこでBeanDefinitionRegistryPostProcessorの実装クラスのみで完結させるのは諦め、2段階に分けました。
BeanDefinitionRegistryPostProcessorの実装クラスでは、必要なコードリストのBean定義のみを定義します。(ただしコードリストの中身は空っぽ)
別のクラスの@PostConstructでDBアクセスし、空っぽのコードリストに値のマップを設定します。
実装イメージは下記の通り。

CustomBeanDefinitionRegistryPostProcessor.java
/**
 *
 */
package xxxxxx.yyyyyy.zzzzzz.app.welcome;

import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.terasoluna.gfw.common.codelist.SimpleMapCodeList;

/**
 * @author toshio
 *
 */
public class CustomBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    private List<String> codeListNames;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        if (codeListNames != null) {
            for (String codeBeanName : codeListNames) {
                BeanDefinition beanDefinition = new RootBeanDefinition(SimpleMapCodeList.class);
                registry.registerBeanDefinition(codeBeanName, beanDefinition);
            }
        }
    }

    /**
     * @param codeListNames セットする codeListNames
     */
    public void setCodeListNames(List<String> codeListNames) {
        this.codeListNames = codeListNames;
    }

}
CustomCodeListLoader.java
/**
 *
 */
package xxxxxx.yyyyyy.zzzzzz.app.welcome;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.terasoluna.gfw.common.codelist.SimpleMapCodeList;

/**
 * @author toshio
 *
 */
public class CustomCodeListLoader {
    /**
     * Database access information
     */
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * SQL Query to access the database
     */
    private String querySql;

    private List<String> codeListNames;

    /**
     *
     */
    private String codeNameColumn;

    /**
     * property that holds the name of the column of the database holding the value part of the codelist
     */
    private String valueColumn;

    /**
     * property that holds the name of the column of the database holding the label part of the codelist
     */
    private String labelColumn;

    @PostConstruct
    public void afterPropertiesSet() {

        Map<String, Map<String, String>> allMap = new HashMap<String, Map<String, String>>();
        for (String codeName : codeListNames) {
            allMap.put(codeName, new LinkedHashMap<String, String>());
        }

        List<Map<String, Object>> rows = jdbcTemplate.queryForList(querySql);
        for (Map<String, Object> row : rows) {
            Object codeName = row.get(codeNameColumn);
            Object key = row.get(valueColumn);
            Object value = row.get(labelColumn);
            if (codeName != null && key != null && value != null) {
                Map<String, String> map = allMap.get(codeName.toString());
                if (map == null) {
                    map = new LinkedHashMap<String, String>();
                }
                map.put(key.toString(), value.toString());
                allMap.put(codeName.toString(), map);
            }
        }

        for (Entry<String, Map<String, String>> codeEnt : allMap.entrySet()) {
            Object codeBean = applicationContext.getBean(codeEnt.getKey());
            if (codeBean instanceof SimpleMapCodeList) {
                SimpleMapCodeList smc = (SimpleMapCodeList) codeBean;
                smc.setMap(codeEnt.getValue());
            }
        }
    }

    /**
     * Sets JdbcTemplate
     * @param jdbcTemplate JdbcTemplate instance for fetching code list records
     */
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * Setter method for labelColumn
     * @param labelColumn column name for fetch a code label
     */
    public void setLabelColumn(String labelColumn) {
        this.labelColumn = labelColumn;
    }

    /**
     * Setter method for valueColumn
     * @param valueColumn column name for fetch code value
     */
    public void setValueColumn(String valueColumn) {
        this.valueColumn = valueColumn;
    }

    /**
     * Setter method for querySql
     * @param querySql sql for fetching code list records from database
     */
    public void setQuerySql(String querySql) {
        this.querySql = querySql;
    }

    public void setCodeNameColumn(String codeNameColumn) {
        this.codeNameColumn = codeNameColumn;
    }

    /**
     * @param codeListNames セットする codeListNames
     */
    public void setCodeListNames(List<String> codeListNames) {
        this.codeListNames = codeListNames;
    }

}
projectName-codelist.xml
    <bean class="xxxxxx.yyyyyy.zzzzzz.app.welcome.CustomBeanDefinitionRegistryPostProcessor">
        <property name="codeListNames">
            <list>
                <value>CL_ORDERSTATUS</value>
                <value>CL_HOGE</value>
            </list>
        </property>
    </bean>

    <bean class="xxxxxx.yyyyyy.zzzzzz.app.welcome.CustomCodeListLoader">
        <property name="querySql">
            <value>
                SELECT code_bean_name, code_id, code_name FROM t_sample_codes WHERE code_bean_name = 'CL_ORDERSTATUS'
                UNION ALL
                SELECT code_bean_name, code_id, code_name FROM t_sample_codes WHERE code_bean_name = 'CL_HOGE'
                ORDER BY code_bean_name, code_id
            </value>
        </property>
        <property name="codeNameColumn" value="code_bean_name"/>
        <property name="valueColumn" value="code_id" />
        <property name="labelColumn" value="code_name" />
        <property name="jdbcTemplate" ref="jdbcTemplateForCodeList" />
        <property name="codeListNames">
            <list>
                <value>CL_ORDERSTATUS</value>
                <value>CL_HOGE</value>
            </list>
        </property>
    </bean>

CREATE TABLE t_sample_codes (
                                code_bean_name varchar(32) not null,
                                code_id        varchar(32) not null,
                                code_name      varchar(256) not null,
                                primary key (code_bean_name, code_id)
                            );

INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_ORDERSTATUS', '1', 'Received');
INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_ORDERSTATUS', '2', 'Sent');
INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_ORDERSTATUS', '3', 'Cancelled');

INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_HOGE', '1', 'hoge');
INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_HOGE', '2', 'hogehoge');
INSERT INTO t_sample_codes(code_bean_name, code_id, code_name) VALUES ('CL_HOGE', '3', 'hogehogehoge');

commit;
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0