精华内容
下载资源
问答
  • 非常合适新手,容易上手,动态加载数据,适配器很容易被小白看懂
  • 本文实现了运用bootstrap treeview实现动态加载数据,并且添加快捷搜索功能,需要的朋友参考下
  • 页面滚动动态加载数据,页面下拉自动加载内容 相信很多人都见过瀑布流图片布局,那些图片是动态加载出来的,效果很好,对服务器的压力相对来说也小了很多 有手机的相信都见过这样的效果:进入qq空间,向下拉动空间,...
  • 主要介绍了SpringBoot如何在运行时动态添加数据源,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 在使用bootstrap-select 动态加载数据的时候,refresh和render方法是必须使用的,不然就必须使用jquery往li对象里面填充数据,因为在bootstrap-select 中界面显示数据是通过li对象显示的,而select对象只是用于填充...
  • 动态添加加载数据。通过ul li里面的数据 利用append添加
  • 今天小编就为大家分享一篇解决Vue使用swiper动态加载数据,动态轮播数据显示白屏的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要介绍了javascript如何为下拉列表动态添加数据项,需要的朋友可以参考下
  • 下面小编就为大家分享一篇swiper 解决动态加载数据滑动失效的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • C# 动态添加数据到折线图 chart 动态折线图。 C#窗口程序chart控件实现动态将数据添加到折线图的功能,勾选框可指示数据是否显示 C# chart 动态折线图
  • 动态加载数据源关键一点:在系统运行时加载多一个数据源,加载此数据源的对象必须和系统启动时加载数据源的同一个,在我这里加载数据源的对象是类DynamicDataSource,可在这里添加一个加载数据源的方法: ...
  • 无刷新功能我们用到很多很多的,下面我就来给各位介绍一个实例,就是实现php+ajax实现无刷新滚屏加载数据,例子非常的简单大家只要按流程来操作就可以了哦。
  • 本文介绍一个treepanel动态加载数据的例子,需要了解的朋友可以参考下
  • JS EasyUI DataGrid动态加载数据
  • 本文实例讲述了Android开发中Listview动态加载数据的方法。分享给大家供大家参考,具体如下: 最近在研究网络数据加载的问题,比如我有几百,甚至上千条数据,这些数据如果一次性全部加载到arraylist,然后再加载到...
  • 主要介绍了PHP+jQuery实现滚屏无刷新动态加载数据功能,涉及php动态读取数据库及加载数据实现滚屏无刷新效果的具体操作技巧,需要的朋友可以参考下
  • 主要为大家详细介绍了jquery Ajax实现Select动态添加数据的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 分公司各自使用各自的业务数据库,用户登陆访问A数据库校验成功后将用户所属分公司的KEY保存session中(此文章以存放session为例,其他存放方式参考即可),当然本文重点在与还可以动态增加EFG。。。。分公司,无需...

    _**使用场景:
    假设需要做一个工具,由于保密需要只描述场景。 A下面有 B、C、D三家或者更多分公司,人员信息统一在总公司的A数据库,分公司各自使用各自的业务数据库,用户登陆访问A数据库校验成功后将用户所属分公司的KEY保存session中(此文章以存放session为例,其他存放方式参考即可),当然本文重点在与还可以动态增加EFG。。。。分公司,无需重启应用。
    _**设计思路:
    因为系统登录离不开A数据库,我成A为主数据库。
    B、C、D、E…..并非系统运行必须数据库,所以简称自定义数据库。
    B、C、D都为分公司,数据库结构完全一致,支持BCD与A库表结构不一致。案例以SpringBoot项目为例,Spring按照这个思路,更简单。

    新建项目依赖的主数据库A 配置主数据源,以及公共数据源属性,application.properties
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    spring.datasource.druid.url=
    spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.druid.username=root
    spring.datasource.druid.password=root
    spring.datasource.druid.maxWait=5000
    spring.datasource.druid.。。。。。。
    配置自定义数据源jdbc.properties(也可以不在配置文件中配置,项目有提供页面配置,保存数据库或者配置文件)
    *数据源的key–可以理解为分公司代码
    spring.datasource.keys=dev,stg,prd
    spring.datasource.names=开发,测试,生产
    *个数据源前缀为key
    dev.spring.datasource.druid.driver-class-name=
    dev.spring.datasource.druid.url=
    dev.spring.datasource.druid.username=
    dev.spring.datasource.druid.password=

    stg.spring.datasource.druid.driver-class-name=
    stg.spring.datasource.druid.url=
    stg.spring.datasource.druid.username=
    stg.spring.datasource.druid.password=
    支持动态切换数据源的思路
    包装一个DataSource 从当前线程中拿到需要访问的key,根据key得到需要使用哪个数据源,参考目前spring已经提供的AbstractRoutingDataSource,因此只需要自己写个类继承AbstractRoutingDataSource实现determineCurrentLookupKey()方法,这个方法就是获取当前线程中的key。
    如下:
    public class DynamicDataSource extends AbstractRoutingDataSource{

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
    
    /**
     * 动态更新自定义数据源
     * @param defaultDataSource
     * @param customDataSources
     */
    public void updateTargetDataSource(Map<String,DataSource> customDataSources){
        Map<Object,Object> customDS=new HashMap<Object, Object>();
        customDS.putAll(customDataSources);
        setTargetDataSources(customDS);
        afterPropertiesSet();
    }
    

    }
    由于要支持动态添加数据源所以又添加updateTargetDataSource()方法。

    现在配置主以及自定义DataSource,SpringBoot方式
    /**
    * @ClassName DynamicDataSourceRegister
    * @Description 动态数据源注册
    */
    public class DynamicDataSourceRegister implements EnvironmentAware {
    /**
    * 加载多数据源配置
    */
    @Override
    public void setEnvironment(Environment env) {
    DynamicDataSourceRegisterUtil.initAndRegisterDataSource(env);
    }
    }

    DynamicDataSourceRegisterUtil中的方法
    public static void initAndRegisterDataSource(Environment env){
    //将自定义的数据源的信息加载到spring 的Environment中
    try {
    initCustomEnvironment(env);
    } catch (IOException e) {
    logger.error(“初始化自定义数据库配置文件出错”,e);
    }
    //产生主数据源,默认数据源配置在application.properties中的数据源
    initDefaultDataSource(env);
    //产生主自定义的数据源,默认数据源配置在jdbc.properties中的数据源
    initCustomDataSources(env);
    //将主数据员,自定义数据源注入到动态数据源DynamicDataSource ,
    //再将DynamicDataSource 以名称“dataSource”注入到spring中
    registerDataSource(DATA_SOURCE);
    }
    DynamicDataSourceRegisterUtil具体代码如下(各个方法作用见注释):
    /**
    * @ClassName DynamicDataSourceRegister
    * @Description 动态数据源注册
    */
    public class DynamicDataSourceRegisterUtil{
    public final static String DATASOURCE_PARAM_PREF =”spring.datasource.”;
    public final static String DATASOURCE_PARAM_PRPO_KEY_DRIVER_CLASS_NAME =”driver-class-name”;
    public final static String DRUID_DATASOURCE_PARAM_PREF =”spring.datasource.druid.”;
    public final static String DATASOURCE_PARAM_TYPE =”druid.”;
    public final static String DATASOURCE_PARAM_SPLIT =”.”;

    public final static  String DEFAULT_TARGET_DATA_SOURCE ="defaultTargetDataSource";
    public final static  String TARGET_DATA_SOURCES  ="targetDataSources";
    public final static  String  DATA_SOURCE  ="dataSource";
    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegisterUtil.class);
    private static final ConversionService conversionService = new DefaultConversionService();
    private static final String JDBC_FILE_NAME="jdbc.properties";
    private static final String CUSTOM_DATA_SOURCES_MAP_NAME="customDataSourcesMap";
    
    private static PropertyValues dataSourcePropertyValues;
    // 数据源
    private static DataSource defaultDataSource;
    private static Map<String,DataSource> customDataSources = new HashMap<String,DataSource>();
    
    /**
     * 创建DataSource
     *
     * @param type
     * @param driverClassName
     * @param url
     * @param username
     * @param password
     * @return
     */
    private static DataSource buildDataSource(Map<String,Object> dsMap)  {
        DataSource dataSource=null;
        try {
            dataSource=DruidDataSourceFactory.createDataSource(dsMap);
            if(dataSource instanceof DruidDataSource){
                //注意:这一设置是为解决Druid 在获取连接时由于连接配置出错会一直等待获取连接,比较重要
                ((DruidDataSource) dataSource) .setBreakAfterAcquireFailure(true);
                //((DruidDataSource) dataSource).init();
            }
            return dataSource;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public  static void initAndRegisterDataSource(Environment env){
        //将自定义的数据源的信息加载到spring 的Environment中
        try {
            initCustomEnvironment(env);
        } catch (IOException e) {
            logger.error("初始化自定义数据库配置文件出错",e);
        }
        //产生主数据源,默认数据源配置在application.properties中的数据源
        initDefaultDataSource(env);
        //产生主自定义的数据源,默认数据源配置在jdbc.properties中的数据源
        initCustomDataSources(env);
        //将主数据员,自定义数据源注入到动态数据源DynamicDataSource ,再将DynamicDataSource 以名称“dataSource”注入到spring中
        registerDataSource(DATA_SOURCE);
    }
    
    /**
     * 更新配置文件,并热加载到Environment中
     * @param properties
     * @throws IOException
     */
    public synchronized static void refreshDataSoureProperties(Properties properties) throws IOException {
        //将属性持久化到配置文件
        OutputStream out=new FileOutputStream(URLEncoder.encode(DynamicDataSourceRegisterUtil.class.getClassLoader().getResource(JDBC_FILE_NAME).getPath(),"utf-8"));
        properties.store(out,"更新数据库");
        out.flush();
        out.close();
        //将属性热加载到环境中去
        Environment env =EnvironmentUtils.getEnvironment();
        PropertySource<?> source = new PropertiesPropertySource(CUSTOM_DATA_SOURCES_MAP_NAME, properties);
        ((StandardEnvironment) env).getPropertySources().addLast(source);
        refreshDataSource(env);
    }
    /**
     * 初始化主数据源
     */
    private static void initDefaultDataSource(Environment env) {
        // 读取主数据源
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, DATASOURCE_PARAM_PREF);
        Map<String,Object> dsMap = propertyResolver.getSubProperties(DATASOURCE_PARAM_TYPE);
        defaultDataSource = buildDataSource(dsMap);
        dataBinder(defaultDataSource,env);
    }
    
    /**
     * 关闭老的数据源
     */
    private static void closeOldCustomDataSources(){
        if(customDataSources!=null&&customDataSources.size()>0){
            for (String key:customDataSources.keySet()){
                DataSource dataSource =customDataSources.get(key);
                if(dataSource instanceof DruidDataSource){
                    ((DruidDataSource)dataSource).close();
                    logger.info("closed datasource "+key);
                }
            }
        }
        if(customDataSources!=null){
            customDataSources.clear();
        }
    }
    
    public synchronized static void initCustomEnvironment(Environment env) throws IOException {
        Properties properties = new Properties();
        InputStream in =null;
        try {
            in = new FileInputStream(URLEncoder.encode(DynamicDataSourceRegisterUtil.class.getClassLoader().getResource(JDBC_FILE_NAME).getPath(), "utf-8"));
            properties.load(in);
            PropertySource<?> source = new PropertiesPropertySource(CUSTOM_DATA_SOURCES_MAP_NAME, properties);
            ((StandardEnvironment) env).getPropertySources().addLast(source);
        }finally {
            in.close();
        }
    }
    /**
     * 初始化更多数据源
     *
     */
    private static void initCustomDataSources(Environment env) {
        //初始化之前要先将老的数据源关闭
        closeOldCustomDataSources();
        // 读取配置文件获取更多数据源,也可以通过defaultDataSource读取数据库获取更多数据源
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, DATASOURCE_PARAM_PREF);
        String dsPrefixs = propertyResolver.getProperty("keys");
        if(dsPrefixs==null){
            return;
        }
        for (String dsPrefix : dsPrefixs.split(",")) {// 多个数据源
            RelaxedPropertyResolver propertys = new RelaxedPropertyResolver(env, dsPrefix.trim()+DATASOURCE_PARAM_SPLIT+DATASOURCE_PARAM_PREF);
            Map<String,Object> dsMap = propertys.getSubProperties(DATASOURCE_PARAM_TYPE);
            DataSource dataSource= buildDataSource(dsMap);
            dataBinder(dataSource,env);
            customDataSources.put(dsPrefix, dataSource);
            try{
                //向库中插入信息
                String password = (String) dsMap.get(DruidDataSourceFactory.PROP_PASSWORD);
                String url = (String) dsMap.get(DruidDataSourceFactory.PROP_URL);
                String username = (String) dsMap.get(DruidDataSourceFactory.PROP_USERNAME);
                String strs[]=url.split(";");
                String dbName="";
                for(String s: strs){
                    if(s!=null&&s.trim()!=null){
                        if(s.toUpperCase().contains("DATABASENAME")){
                            dbName=s.split("=")[1];
                        }
                    }
                }
                //Data Source=192.168.5.92;Initial Catalog=MS_CUBE_TEST;User ID=sa;Password=root;
                String connectionStr="Data Source="+strs[0].replaceAll(".*(\\d{3}(\\.\\d{1,3}){3}).*","$1")
                        +";Initial Catalog="+dbName+";User ID="+username+";Password="+password+";";
    
                updateConnectionStr2Db(dsMap,connectionStr);
            } catch (Exception e) {
                logger.error("将数据源配置信息写入到数据库失败!",e);
            }
        }
    }
    
    private static void updateConnectionStr2Db(Map<String, Object> dataSource, String connectionStr) throws SQLException {
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        try {
            Class.forName((String)dataSource.get(DATASOURCE_PARAM_PRPO_KEY_DRIVER_CLASS_NAME));
            connection =DriverManager.getConnection((String)dataSource.get(DruidDataSourceFactory.PROP_URL),
                    (String)dataSource.get(DruidDataSourceFactory.PROP_USERNAME),
                    (String)dataSource.get(DruidDataSourceFactory.PROP_PASSWORD));
            preparedStatement=connection.prepareStatement("merge into ssas_base_config_prop p using(\n" +
                    "\tselect 'clrSSASConfigurationConnectionString' as  properties_key\n" +
                    ") t on (t.properties_key=p.properties_key)\n" +
                    "when matched then\n" +
                    "update set  properties_value=?\n" +
                    "when not matched then\n" +
                    "insert (properties_key,properties_value,properties_name,display_type)values('clrSSASConfigurationConnectionString',?,'当前环境数据库','text');\n");
            preparedStatement.setString(1,connectionStr);
            preparedStatement.setString(2,connectionStr);
            preparedStatement.executeUpdate();
            connection.commit();
        }catch (Exception e){
            logger.error("保存数据库连接信息失败",e);
        }finally {
            preparedStatement.close();
            connection.close();
        }
    }
    /**
     * 更新配置之后要更新DynamicDataSource
     * @param dataSourceName
     */
    private static void refreshDataSource(Environment environment) {
        initCustomDataSources(environment);
        DynamicDataSource dynamicDataSource =ApplicationContextUtil.getBean(DATA_SOURCE);
        dynamicDataSource.updateTargetDataSource(defaultDataSource,customDataSources);
        DynamicDataSourceContextHolder.dataSourceIds.clear();
        DynamicDataSourceContextHolder.dataSourceIds.addAll(customDataSources.keySet());
    }
    /**
     * 将动态数据源注册到spring中
     * @param dataSourceName
     */
    private static void registerDataSource(String dataSourceName) {
        Map<String,Object> targetDataSources = new HashMap<String,Object>();
        // 将主数据源添加到更多数据源中
        targetDataSources.put(DEFAULT_TARGET_DATA_SOURCE, defaultDataSource);
        // 添加更多数据源
        targetDataSources.putAll(customDataSources);
        DynamicDataSourceContextHolder.dataSourceIds.addAll(customDataSources.keySet());
        Map<String,Object> paramValues=new HashMap<String, Object>();
        paramValues.put(DEFAULT_TARGET_DATA_SOURCE, defaultDataSource);
        paramValues.put(TARGET_DATA_SOURCES, targetDataSources);
        ApplicationContextUtil.registerSingletonBean(dataSourceName,DynamicDataSource.class,paramValues);
        logger.info("Dynamic DataSource Registry");
    }
    /**
     * 为DataSource绑定更多数据
     * @param dataSource
     * @param env
     */
    private static void dataBinder(DataSource dataSource, Environment env) {
        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
        dataBinder.setConversionService(conversionService);
        dataBinder.setIgnoreNestedProperties(false);//false
        dataBinder.setIgnoreInvalidFields(false);//false
        dataBinder.setIgnoreUnknownFields(true);//true
        if (dataSourcePropertyValues == null) {
            Map<String, Object> rpr = new RelaxedPropertyResolver(env, DATASOURCE_PARAM_PREF).getSubProperties(DATASOURCE_PARAM_TYPE);
            Map<String, Object> values = new HashMap<>(rpr);
            // 排除已经设置的属性
            values.remove("type");
            values.remove(DATASOURCE_PARAM_PRPO_KEY_DRIVER_CLASS_NAME);
            values.remove("url");
            values.remove("username");
            values.remove("password");
            dataSourcePropertyValues = new MutablePropertyValues(values);
        }
        dataBinder.bind(dataSourcePropertyValues);
    }
    

    }
    相关工具类ApplicationContextUtil、EnvironmentUtil
    @Component
    public class ApplicationContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }
    
    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }
    
    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(String name) {
        checkApplicationContext();
        if (applicationContext.containsBean(name)) {
            return (T) applicationContext.getBean(name);
        }
        return null;
    }
    
    /**
     * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }
    
    private static void checkApplicationContext() {
        if (applicationContext == null)
            throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextUtil");
    }
    public synchronized static void registerSingletonBean(String beanName,Class clzz,Map<String,Object> original) {
        checkApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
        if(beanFactory.containsBean(beanName)){
            removeBean(beanName);
        }
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //类class
        definition.setBeanClass(clzz);
        //属性赋值
        definition.setPropertyValues(new MutablePropertyValues(original));
        //注册到spring上下文
        beanFactory.registerBeanDefinition(beanName, definition);
    }
    public synchronized static void registerSingletonBean(String beanName,Object obj,Map<String,Object> original) {
        checkApplicationContext();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ApplicationContextUtil.getApplicationContext().getAutowireCapableBeanFactory();
        if(beanFactory.containsBean(beanName)){
            removeBean(beanName);
        }
        GenericBeanDefinition definition = new GenericBeanDefinition();
        //类class
        definition.setBeanClass(obj.getClass());
        //属性赋值
        definition.setPropertyValues(new MutablePropertyValues(original));
        //注册到spring上下文
        beanFactory.registerBeanDefinition(beanName, definition);
    }
    public synchronized static void registerSingletonBean(String beanName,Object obj) {
        registerSingletonBean(beanName,obj,BeanUtils.transBean2Map(obj));
    }
    /**
     * 删除spring中管理的bean
     * @param beanName
     */
    public static void removeBean(String beanName){
        ApplicationContext ctx = ApplicationContextUtil.getApplicationContext();
        DefaultListableBeanFactory acf = (DefaultListableBeanFactory) ctx.getAutowireCapableBeanFactory();
        if(acf.containsBean(beanName)) {
            acf.removeBeanDefinition(beanName);
        }
    }
    

    }

    @Component
    public class EnvironmentUtils implements EnvironmentAware {
    private static Environment environment ;
    @Override
    public void setEnvironment(Environment environment) {
    EnvironmentUtils.environment=environment;
    }
    public static Environment getEnvironment(){
    return EnvironmentUtils.environment;
    }
    }

    动态数据源注入完成,配置事务之类的照旧 数据源一律使用DynamicDataSource。
    在springBoot启动类加上注解@Import(DynamicDataSourceRegister.class)
    这样数据源加载就完成。
    接下来配置切面实现动态切换数据源,原理:将要访问的数据源放到session中(不一定是session,可以根据自定义业务需要变化)。每次切面都从session中拿到数据源的key (dev、 stg、prd)将这个key设置到当前线程
    用ThreadLocal来实现(见DynamicDataSourceContextHolder)
    /**
    * @ClassName DynamicDataSourceContextHolder
    * @Description 判断当前数据源是否存在(上下文)
    */
    public class DynamicDataSourceContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal();
    public static List dataSourceIds = new ArrayList<>();
    //使用setDataSourceType设置当前的
    public static void setDataSourceType(String dataSourceType) {
    contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }
    
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
     //判断指定DataSrouce当前是否存在
    public static boolean containsDataSource(String dataSourceId){
        return dataSourceIds.contains(dataSourceId);
    }
    

    }
    这也是DynamicDataSource的方法determineCurrentLookupKey()中从当前线程中取数据源的key
    @Override
    protected Object determineCurrentLookupKey() {
    return DynamicDataSourceContextHolder.getDataSourceType();
    }

    因此接下来的切面要做的事就是在业务方法之前将数据源key设置到当前线程中,在访问结束后再清楚。理论上可以配置环绕切面,为避免很多不必要麻烦这里采用前置、和后置配合使用
    项目结构 Controller层 service层 dao(mapper)层
    所以切面直接切service层
    @Component
    @Aspect
    public class MultipleDataSourceAspectAdvice implements Ordered {
    private static final Logger logger = Logger.getLogger(MultipleDataSourceAspectAdvice.class);

    @Before("execution(* com..mapper..*.*(..))")
    public void changeDataSource(JoinPoint point) throws Throwable {
        String environmentCode = SessionUtil.getSessionAttr(SessionUtil.ENVIRONMENT_CODE,"dev").toString();
        logger.info("Use DataSource : "+ environmentCode+"-"+ point.getSignature());
        DynamicDataSourceContextHolder.setDataSourceType(environmentCode);
    }
    
    @After("execution(* com..service..*.*(..))")
    public void clearDataSource2(JoinPoint point) {
        //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
    @After("execution(* com..mapper..*.*(..))")
    public void clearDataSource(JoinPoint point) {
        //方法执行完毕之后,销毁当前数据源信息,进行垃圾回收。
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
    @Before("execution(* com..service..*.*(..))")
    public void switchDataSource(JoinPoint point) throws Throwable {
        String environmentCode = SessionUtil.getSessionAttr(SessionUtil.ENVIRONMENT_CODE,"dev").toString();
        logger.info("Use DataSource : "+ environmentCode+"-"+ point.getSignature());
        DynamicDataSourceContextHolder.setDataSourceType(environmentCode);
    }
    @Override
    public int getOrder() {
        return 1;
    }
    

    }
    但是如果只切service层会有问题存在,如果在service层调用service 就会导致里面的service调用完成之后将当前线程中的key清除了,最终导致接下来的dao获取不到key而走默认库
    因此这里又对dao层也切入一次做同样操作,就避免刚才情况。
    实际上到这里并不完美,因为如果事务切面先执行,即使现在切换了数据源也没有用了,事务会缓存数据源。所以必须要让切面在事务切面之前执行因此实现Ordered 接口的getOrder()方法。
    在启动类添加注解@EnableTransactionManagement(order = 2,proxyTargetClass=true)将事务切面的order设置为2或者更大。
    到此动态切换以及动态添加完成。

    这是动态添加数据源的接口的实现,非常简单
    @ResponseBody
    @RequestMapping(method = RequestMethod.POST,value=”submitEnvironmentConfig”)
    public ResponseData submitEnvironmentConfig(@RequestBody List environmentConfigs) throws Exception{
    if(environmentConfigs==null||environmentConfigs.size()==0){
    return new ResponseData.Builder().error(“没有数据!”);
    }
    //参数校验
    String codes=”“;
    String names=”“;
    //生成prop
    Properties properties=new Properties();
    for (EnvironmentConfig e:environmentConfigs){
    if(StringUtils.isEmpty(e.getCode())||
    StringUtils.isEmpty(e.getName())||
    StringUtils.isEmpty(e.getDriverClassName())||
    StringUtils.isEmpty(e.getPassword())||
    StringUtils.isEmpty(e.getUsername())||
    StringUtils.isEmpty(e.getUrl())){
    return new ResponseData.Builder().error(“所有参数不能为空!”);
    }
    codes=codes+”,”+e.getCode().trim();
    names=names+”,”+e.getName().trim();
    properties.setProperty(e.getCode().trim()+DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_SPLIT+DynamicDataSourceRegisterUtil.DRUID_DATASOURCE_PARAM_PREF+DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_PRPO_KEY_DRIVER_CLASS_NAME,e.getDriverClassName());
    properties.setProperty(e.getCode().trim()+DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_SPLIT+DynamicDataSourceRegisterUtil.DRUID_DATASOURCE_PARAM_PREF+DruidDataSourceFactory.PROP_URL,e.getUrl());
    properties.setProperty(e.getCode().trim()+DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_SPLIT+DynamicDataSourceRegisterUtil.DRUID_DATASOURCE_PARAM_PREF+DruidDataSourceFactory.PROP_USERNAME,e.getUsername());
    properties.setProperty(e.getCode().trim()+DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_SPLIT+DynamicDataSourceRegisterUtil.DRUID_DATASOURCE_PARAM_PREF+DruidDataSourceFactory.PROP_PASSWORD,e.getPassword());
    }
    codes=codes.substring(1);
    names=names.substring(1);
    properties.setProperty(DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_PREF+”keys”,codes);
    properties.setProperty(DynamicDataSourceRegisterUtil.DATASOURCE_PARAM_PREF+”names”,names);
    DynamicDataSourceRegisterUtil.refreshDataSoureProperties(properties);
    return new ResponseData.Builder(null).success();
    }

    谢谢大家,由于时间仓促可能比较混乱,希望给大家带来思路就可以了。欢迎交流。

    展开全文
  • 主要介绍了jQuery实现表单动态添加数据并提交的方法,结合实例形式总结分析了jQuery针对存在form表单的添加、提交,不存在form表单的添加、提交,ajax、非ajax形式提交等数据添加与表单提交操作技巧,需要的朋友可以参考...
  • 数据量高性能前端表格grid 动态加载数据 可以做到 一边滚动一边加载新的dom,并同时删除不可见的dom,防止因数据过大引起的dom卡顿
  • java swing 多选下拉框 支持动态加载数据 (优化了网上的下拉框代码)
  • 对bootstrap表格的自定义demo,js动态加载表格数据
  • 本篇文章主要介绍了bootstrap table动态加载数据示例代码,可以实现点击选择按钮,弹出模态框,加载出关键词列表,有兴趣的可以了解一下。
  • swiper 动态加载数据

    千次阅读 2018-11-09 09:41:00
    swiper 动态加载数据使用说明 进行动态数据加载,如果按照一般的静态文件方式进行设置则会发现无法正常滑动, 原因可能是swiper在初始化的时候会扫描swiper-wrapper内部swiper-slide的个数,从而完成初始化,...

    swiper 动态加载数据使用说明

    进行动态数据加载,如果按照一般的静态文件方式进行设置则会发现无法正常滑动,
    原因可能是swiper在初始化的时候会扫描swiper-wrapper内部swiper-slide的个数,从而完成初始化,但是由于动态加载是在初始化完成进行的操作,所以无法确定swiper-wrapper内部swiper-slide的个数,从而导致左右滑动失效

    如果是动态DOM添加初始化

    方式一

    initialSlide :0,		//轮播开始位置
    observer:true,			//轮播元素为内部动态添加必须加此 修改swiper自己或子元素时,自动初始化swiper
    observeParents:true,	//轮播元素为内部动态添加必须加此 修改swiper的父元素时,自动初始化swiper
    slidesPerView: 3,
    spaceBetween: 30,
    pagination: {
    	el: '.fenye04',
    	clickable: true,
    },
    autoplay: {
    	delay: 5000,
    	stopOnLastSlide: false,
    	disableOnInteraction: true,
    }

    方式二

    /** 添加DOM
    	var tdom=document.getElementById("xxx");
    	tdom.innerText='xxxxx';
    	然后重新初始化swoper
    	var swiper = new Swiper('.swiper-container', {
    		slidesPerView : 3
    	});
    
    	 */

    常用参数说明:

    var swiper = new Swiper(".news",{ //绑定置顶容器class
            pagination: ".news_lis",//分页clss(就是下面小圆点的容器)
            paginationClickable: true,//点击分页圆点是否切换
            slidesPerView: 4,//每页显示几个
            spaceBetween: 20,//每个间距是多少
            nextButton: ".news-next",//绑定下一个按钮容器的class
            prevButton: ".news-prev",//绑定上一个按钮容器的class
            autoplay: 3000,//设置多少毫秒会执行一次动画(可以理解为:翻页 / 切换)
          centeredSlides: false//值为【false】时左对齐,默认就是左对齐,值为【true】时居中对齐
            breakpoints: { //响应布局设置
                1200: {//如果屏幕宽度小于<1200
                    slidesPerView: 3,//每页显示3个
                    spaceBetween: 20//每个间距是20
                },
                1024: {
                    slidesPerView: 3,
                    spaceBetween: 20
                },
                768: {
                    slidesPerView: 2,
                    spaceBetween: 20
                },
                640: {//如果屏幕宽度小于<640
                    slidesPerView: 1,//每页显示1个
                    spaceBetween: 10//每个间距是10
                }
            }
        });
    

     

     

     

    转载于:https://my.oschina.net/qingqingdego/blog/2873941

    展开全文
  • swiper支持动态加载数据

    万次阅读 2018-01-24 20:39:43
    用swiper插件动态加载数据:动态获取完数据之后,在初始化swiper. 1、在标签里面加入swiper的css和js文件 2、html如下: 3、js如下: function handle

    用swiper插件动态加载数据:动态获取完数据之后,在初始化swiper.


    1、在<head>标签里面加入swiper的css和js文件

     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/css/swiper.min.css">

     <script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/3.4.2/js/swiper.min.js"></script>
    

    2、html如下:

        <div class="swiper-container"><!--swiper容器[可以随意更改该容器的样式-->  
            <div class="swiper-wrapper" id="swiperWrapper">  
              
                
            </div>    
            <div class="swiper-button-prev swiper-button-white"></div><!--前进按钮-->  
            <div class="swiper-button-next swiper-button-white"></div><!--后退按钮-->  
        </div> 

    3、js如下:

       function handlePascreenImg(datas){
    		var len = datas.length,
    			DOMObj = null,        //img
    			obj = null,           //保存当前对象
    			img_path = '',        //图片名
    			price = '',           //霸屏每秒的价钱
    			paScreenType = '',    //霸屏的type
    			name = '',            //霸屏图片的名字
    			src = '';             //图片路径
    
    		// 清除上次的数据
    		$('#swiperWrapper').empty();
    		for( var i=0;i<len;i++ ){
    			obj = datas[i],
    			img_path = obj.img_path,
    			price = obj.price,
    			paScreenType = obj.type,
    			name = obj.name,
    			src = globalConfig.pre_api_url + '/wxwall_api/good/img/' + img_path;
    
    			var imgList =  '<div class="swiper-slide">' +
    						   '<img id="img'+i+'"  src="'+src+'"    name="'+name+'"  paScreenType="'+paScreenType+'"  price="'+price+'" >' +
    						   '</div>';
    
    			$('#swiperWrapper').append(imgList);
    			if( i == len-1 ){
    				$('#paScreenTxt').text($('#img0').attr('name'));
    
    				// 在获取数据之后,在对swiper进行初始化,解决动态加载的问题
    		    	       mySwiper = new Swiper(".swiper-container",{  
    	            	                direction:"horizontal",/*横向滑动*/  
    	            	                // loop:true,/*形成环路(即:可以从最后一张图跳转到第一张图*/    
    	            	               prevButton:".swiper-button-prev",/*前进按钮*/  
    	            	               nextButton:".swiper-button-next",/*后退按钮*/
    	            	               onSlideChangeStart:function(swiper){
    	            		              // 监听swiper滑动事件,更换图片上方文字
    	            		             var index = swiper.activeIndex;
    	    		                     $('#paScreenTxt').text( $('#img'+index).attr('name') );
    	            	               }  
            		      });
    			}
    		}
    
    	}






    展开全文
  • layui 树 动态加载数据

    千次阅读 2020-07-13 15:57:14
    }, spread: function (obj) { if(obj.state=='open'){ setTimeout(function () { //懒加载,只有点击父节点的时候,才加载父节点下的子节点数据 tree.lazytree(inst1.config.id, obj.elem, getTreeJson...

    效果图:

    在这里插入图片描述

    前端样式代码:

     <div >
         <div id="trees" class="demo-tree demo-tree-box"></div>
    </div>
    

    前端js代码:

    //引入包
     layui.config({
            base: '/static/layui-v2.5.6/ext/',// 第三方模块所在目录
            version: 'v1.5.10' // 插件版本号
        }).extend({
            soulTable: 'soulTable/soulTable',
            tableChild: 'soulTable/tableChild',
            tableMerge: 'soulTable/tableMerge',
            tableFilter: 'soulTable/tableFilter',
            excel: 'soulTable/excel',
            treeGrid:'treegrid/treeGrid'
        });
    
     layui.use(['form','layer','tree'], function() {
            var form = layui.form;
            form.render();
            showhslist();//调用数据加载函数
        });
    
     function showhslist() {
          var postdata ={
              menu:$("#menu").val()//对树结构数据进行查询
          }
          //后台传入地址
           dLong.post("/sys/SysPermissionController/getTreeList",postdata,function(data){
               if (data.success) {
                   settreelist(data.treelist)//样式渲染函数
               }else
               {
                   dLong.layerMsg(data.msg)
               }
           },true);
        }
    
    	function settreelist(data) {
    	        layui.tree.render({
    	            elem: '#trees' //默认是点击节点可进行收缩
    	            ,data: data,//数据传递过来
    	            spread: true ,//展开
    	            // accordion: true,
    	            onlyIconControl:true,
    	            showLine: false ,  //是否开启连接线
    	            click: function(obj){//数据点击事件
    	                var data = obj.data;
    	                id=data.value;
    	                var postdata={
    	                    id:id
    	                }
    	                //查询赋值
    	                dLong.post("/sys/SysPermissionController/edit",postdata,function(data){
    	                    if (data.success) {
    	                        // dLong.layerMsg(data.msg)
    	                        $('#id').val(data.list.id);
    	                        $('#menuType').val(data.list.menuType);
    	                        $('#parentId').val(data.parentId);
    	                        parenid=data.parentId;
    	                        layui.form.render("select");
    	                    }else{
    	                        dLong.layerMsg(data.msg)
    	                    }
    	                },true);
    	                //选中样式
    	                obj.tr.addClass('layui-tree-click').siblings().removeClass('layui-tree-click');
    	            },
    	            spread: function (obj) {
    	                if(obj.state=='open'){
    	                    setTimeout(function () {
    	                    //懒加载,只有点击父节点的时候,才加载父节点下的子节点数据
    	                        tree.lazytree(inst1.config.id, obj.elem, getTreeJson(obj.data.id));
    	                    }, 2000);
    	                }
    	            }
    	        });
    	    }
    

    后端传递过来的数据结构:

    {
        "msg":"",
        "success":true,
        "treelist":[
            {
                "children":[
                    {
                        "children":[
                            {
                                "label":"数据权限",
                                "value":"9168256c82d943b39028d75239f87875",
                                "spread":true
                            },
                            {
                                "label":"菜单管理",
                                "value":"dabaa38e8dfd405c811e6a2a3920b71b",
                                "spread":true
                            },
                            {
                                "label":"用户维护",
                                "value":"ae582d7fa4634e93b1a6ba81ec3235a6",
                                "spread":true
                            },
                            {
                                "label":"角色维护",
                                "value":"c837d1205bb84f77b2f16234211cefdf",
                                "spread":true
                            }
                        ],
                        "label":"系统管理",
                        "value":"42ff266e99e34ba18398bfc09651ea95",
                        "spread":true
                    },
                    {
                        "children":[
                            {
                                "label":"业务层",
                                "value":"dbf9b2a6c1a14ccbafc0641679c5c67f",
                                "spread":true
                            },
                            {
                                "label":"报表权限",
                                "value":"8d5b3eed65904219b98b84c24db40305",
                                "spread":true
                            }
                        ],
                        "label":"报表配置",
                        "value":"56bf1bb00c1c40a0a27843cadd7c3448",
                        "spread":true
                    }
                ]
            },
            {
                "children":[],
                "label":"其他",
                "value":"32ff266e99e24ba18398bfc09651ea95",
                "spread":true
            }
        ]
    }
    
    展开全文
  • echarts饼图动态加载数据

    千次阅读 2020-03-13 10:53:20
    echarts饼图动态加载数据 前台页面展示 注意点:准备一个有大小设置的div,引用js,ajax加载数据。 <div id="container10" style="width: 100%;height: 90%"> </div> <script type='text/...
  • 主要为大家详细介绍了iscroll动态加载数据的完美解决方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,171,483
精华内容 468,593
关键字:

动态加载数据