SpringMVC整合ActiveRecord 4.2

[背景]

jfinal使用ActiveRecord 进行数据库操作,非常好用,想在将activerecord移植到spring mvc中

[思路]

在spring mvc中添加一个spring监听器,在监听器中初始化activeRecord,初始化完成后使用Db.find方法查询数据库

我只需要使用Db类的系列方法,所以不需要添加类到model的映射


step1:添加jar包,需要添加的jar包有很多,这里仅列出必要的jar包

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.10</version>
</dependency>
<dependency>
  <groupId>com.jfinal</groupId>
  <artifactId>activerecord</artifactId>
  <version>4.2</version>
</dependency>

配置文件jdbc.properties

jdbc.driver=
jdbc.url=
jdbc.username=
jdbc.password=


PropertiesLoader.java读取配置文件 文件比较长,懒得简化了

import java.io.IOException;
import java.io.InputStream;
import java.util.NoSuchElementException;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
/**
 * Properties文件载入工具类. 可载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的值,但以System的Property优先.
 * @version 2013-05-15
 */
public class PropertiesLoader {
  private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class);
  private static ResourceLoader resourceLoader = new DefaultResourceLoader();
  private final Properties properties;
  public PropertiesLoader(String... resourcesPaths) {
    properties = loadProperties(resourcesPaths);
  }
  public Properties getProperties() {
    return properties;
  }
  /**
   * 取出Property,但以System的Property优先,取不到返回空字符串.
   */
  private String getValue(String key) {
    String systemProperty = System.getProperty(key);
    if (systemProperty != null) {
      return systemProperty;
    }
    if (properties.containsKey(key)) {
      return properties.getProperty(key);
    }
    return "";
  }
  /**
   * 取出String类型的Property,但以System的Property优先,如果都为Null则抛出异常.
   */
  public String getProperty(String key) {
    String value = getValue(key);
    if (value == null) {
      throw new NoSuchElementException();
    }
    return value;
  }
  /**
   * 取出String类型的Property,但以System的Property优先.如果都为Null则返回Default值.
   */
  public String getProperty(String key, String defaultValue) {
    String value = getValue(key);
    return value != null ? value : defaultValue;
  }
  /**
   * 取出Integer类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
   */
  public Integer getInteger(String key) {
    String value = getValue(key);
    if (value == null) {
      throw new NoSuchElementException();
    }
    return Integer.valueOf(value);
  }
  /**
   * 取出Integer类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
   */
  public Integer getInteger(String key, Integer defaultValue) {
    String value = getValue(key);
    return value != null ? Integer.valueOf(value) : defaultValue;
  }
  /**
   * 取出Double类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常.
   */
  public Double getDouble(String key) {
    String value = getValue(key);
    if (value == null) {
      throw new NoSuchElementException();
    }
    return Double.valueOf(value);
  }
  /**
   * 取出Double类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常
   */
  public Double getDouble(String key, Integer defaultValue) {
    String value = getValue(key);
    return value != null ? Double.valueOf(value) : defaultValue;
  }
  /**
   * 取出Boolean类型的Property,但以System的Property优先.如果都为Null抛出异常,如果内容不是true/false则返回false.
   */
  public Boolean getBoolean(String key) {
    String value = getValue(key);
    if (value == null) {
      throw new NoSuchElementException();
    }
    return Boolean.valueOf(value);
  }
  /**
   * 取出Boolean类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容不为true/false则返回false.
   */
  public Boolean getBoolean(String key, boolean defaultValue) {
    String value = getValue(key);
    return value != null ? Boolean.valueOf(value) : defaultValue;
  }
  /**
   * 载入多个文件, 文件路径使用Spring Resource格式.
   */
  private Properties loadProperties(String... resourcesPaths) {
    Properties props = new Properties();
    for (String location : resourcesPaths) {
      InputStream is = null;
      try {
        Resource resource = resourceLoader.getResource(location);
        is = resource.getInputStream();
        props.load(is);
      } catch (IOException ex) {
        logger.info("Could not load properties from path:" + location + ", " + ex.getMessage());
      } finally {
        IOUtils.closeQuietly(is);
      }
    }
    return props;
  }
}

ActiveRecord.java 启动对外提供启动和停止ActiveRedocrd 

import com.litong.util.PropertiesLoader;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
public class ActiveRecord {
  private static DruidPlugin dp = null;
  private static ActiveRecordPlugin arp = null;
  static {
    initArp();
  }
  private static void initArp() {
    PropertiesLoader loader = new PropertiesLoader("jdbc.properties");
    String url = loader.getProperty("jdbc.url");
    String username = loader.getProperty("jdbc.username");
    String password = loader.getProperty("jdbc.password");
    String driverClass = loader.getProperty("jdbc.driver");
    if(dp==null) {
      dp = new DruidPlugin(url, username, password, driverClass);
      arp = new ActiveRecordPlugin(dp);
      dp.start();
      arp.start();
    }        
    
  }
  public static void stop() {
    dp.stop();
    arp.stop();
  }
  public static ActiveRecordPlugin getArp() {
    return arp;
  }
}


SpingMVCStartListener 当springmvc 启动完成后,启动ActiveRecord

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class SpingMVCStartListener implements ApplicationListener<ContextRefreshedEvent> {
  @Override
  public void onApplicationEvent(ContextRefreshedEvent event) {
    ActiveRecordPlugin arp = ActiveRecord.getArp();
    if (arp != null) {
      log.info("arp启动成功:{}", arp);
    } else {
      log.info("arp启动失败:{}", arp);
    }
  }
}


配置spring-mvc.xml

<!-- 监听spring mvc启动 -->
<bean id="spingMVCStartListener" class="com.litongjava.jfinal.active.record.SpingMVCStartListener"></bean>

1.6.3.测试整合结果

String sql = selectFrom + " where time BETWEEN ? and ? and mobile_name=?";
List<Record> find = Db.find(sql, startTimestamp, endTimetamp, name);

测试成功,然后就可以愉快的使用active record,并并且不影响原有的数据库操作框架 还有1个优点是在测试类中操作数据库只需要启动activerecord

ActiveRecord.getArp();
#操作数据库
#xxxx

ActiveRecord.stop();


评论区

Code_Cat

2020-09-09 15:44

我前几天刚整理过,我的没有这么麻烦,只有这些
@Configuration
public class ActiveRecordPluginConfig {

@Resource
private DataSource dataSource;

@PostConstruct
public void initActiveRecordPlugin() {
ActiveRecordPlugin arp = new ActiveRecordPlugin(dataSource);
arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
arp.addSqlTemplate("sql/all.sql");

//添加映射
_MappingKit.mapping(arp);

arp.setShowSql(false);
arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
// 必须调用start
arp.start();
}

}

李通

2020-09-09 18:47

@Code_Cat 你的方案更好,谢谢分享

cpcp

2020-09-11 11:44

@Code_Cat 我的更简单

李通

2020-09-11 13:37

@cpcp 是的,直接从spring中的bean中获取datasource,你的方案个更好,我还有1给我问题没有解决,activerecord使用了druid创建了一个连接池, mybatis也使用druid创建了个连接池,怎样可以将这个2个连接池合并呢?