最近用到了MyBatis配置多数据源,原以为简单配置下就行了,实际操作后发现还是要费些事的,这里记录下,以作备忘

不多废话,直接上代码,后面会有简单的实现介绍
jdbc和log4j的配置
#定义输出格式
ConversionPattern=%d %-5p [%t] %c - %m%n
log4j.rootLogger=DEBUG,Console
log4j.logger.com.cnblogs.lzrabbit=DEBUG
log4j.logger.org.springframework=ERROR
log4j.logger.org.mybatis=ERROR
log4j.logger.org.apache.ibatis=ERROR
log4j.logger.org.quartz=ERROR
log4j.logger.org.apache.axis2=ERROR
log4j.logger.org.apache.axiom=ERROR
log4j.logger.org.apache=ERROR
log4j.logger.httpclient=ERROR
#log4j.additivity.org.springframework=false
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Threshold=DEBUG
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=${ConversionPattern}
#log4j.appender.Console.encoding=UTF-8
#org.apache.log4j.DailyRollingFileAppender
log4j.appender.DailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DailyFile.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.DailyFile.File=${myApp.root}/logs/daily.log
log4j.appender.DailyFile.Append=true
log4j.appender.DailyFile.Threshold=DEBUG
log4j.appender.DailyFile.layout=org.apache.log4j.PatternLayout
log4j.appender.DailyFile.layout.ConversionPattern=${ConversionPattern}
log4j.appender.DailyFile.encoding=UTF-8
# %c 输出日志信息所属的类的全名
# %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy-MM-dd HH:mm:ss},输出类似:2002-10-18- 22:10:28
# %f 输出日志信息所属的类的类名
# %l 输出日志事件的发生位置,即输出日志信息的语句处于它所在的类的第几行
# %m 输出代码中指定的信息,如log(message)中的message
# %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
# %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL。如果是调用debug()输出的,则为DEBUG,依此类推
# %r 输出自应用启动到输出该日志信息所耗费的毫秒数
# %t 输出产生该日志事件的线程名
#============================================================================ # MySQL #============================================================================ jdbc.mysql.driver=com.mysql.jdbc.Driver jdbc.mysql.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true jdbc.mysql.username=root jdbc.mysql.password=root #============================================================================ # MS SQL Server #============================================================================ #jdbc.sqlserver.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver #jdbc.sqlserver.url=jdbc:sqlserver://127.0.0.1:1433;database=test; #jdbc.sqlserver.username=sa #jdbc.sqlserver.password=sa #============================================================================ # MS SQL Server (JTDS) #============================================================================ jdbc.sqlserver.driver=net.sourceforge.jtds.jdbc.Driver jdbc.sqlserver.url=jdbc:jtds:sqlserver://127.0.0.1:1433/test jdbc.sqlserver.username=sa jdbc.sqlserver.password=sa #============================================================================ # 通用配置 #============================================================================ jdbc.initialSize=5 jdbc.minIdle=5 jdbc.maxIdle=20 jdbc.maxActive=100 jdbc.maxWait=100000 jdbc.defaultAutoCommit=false jdbc.removeAbandoned=true jdbc.removeAbandonedTimeout=600 jdbc.testWhileIdle=true jdbc.timeBetweenEvictionRunsMillis=60000 jdbc.numTestsPerEvictionRun=20 jdbc.minEvictableIdleTimeMillis=300000
单数据源时的Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.mysql.driver}"/>
<property name="url" value="${jdbc.mysql.url}"/>
<property name="username" value="${jdbc.mysql.username}"/>
<property name="password" value="${jdbc.mysql.password}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxIdle" value="${jdbc.maxIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<property name="maxWait" value="${jdbc.maxWait}"/>
<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- mybatis.spring自动映射 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cnblogs.lzrabbit"/>
</bean>
<!-- 自动扫描,多个包以 逗号分隔 -->
<context:component-scan base-package="com.cnblogs.lzrabbit"/>
<aop:aspectj-autoproxy/>
</beans>
多数据源时Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<bean id="sqlServerDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.sqlserver.driver}"/>
<property name="url" value="${jdbc.sqlserver.url}"/>
<property name="username" value="${jdbc.sqlserver.username}"/>
<property name="password" value="${jdbc.sqlserver.password}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxIdle" value="${jdbc.maxIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<property name="maxWait" value="${jdbc.maxWait}"/>
<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
</bean>
<bean id="mySqlDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.mysql.driver}"/>
<property name="url" value="${jdbc.mysql.url}"/>
<property name="username" value="${jdbc.mysql.username}"/>
<property name="password" value="${jdbc.mysql.password}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxIdle" value="${jdbc.maxIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<property name="maxWait" value="${jdbc.maxWait}"/>
<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
</bean>
<bean id="multipleDataSource" class="com.cnblogs.lzrabbit.MultipleDataSource">
<property name="defaultTargetDataSource" ref="mySqlDataSource"/>
<property name="targetDataSources">
<map>
<entry key="mySqlDataSource" value-ref="mySqlDataSource"/>
<entry key="sqlServerDataSource" value-ref="sqlServerDataSource"/>
</map>
</property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="multipleDataSource"/>
</bean>
<!-- mybatis.spring自动映射 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.cnblogs.lzrabbit"/>
</bean>
<!-- 自动扫描,多个包以 逗号分隔 -->
<context:component-scan base-package="com.cnblogs.lzrabbit"/>
<aop:aspectj-autoproxy/>
</beans>
MultipleDataSource实现
package com.cnblogs.lzrabbit;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* Created by rabbit on 14-5-25.
*/
public class MultipleDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static void setDataSourceKey(String dataSource) {
dataSourceKey.set(dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return dataSourceKey.get();
}
}
MyBatis接口Mapper定义,直接使用注解方式实现
public interface MySqlMapper {
@Select("select * from MyTable")
List<Map<String,Object>> getList();
}
public interface SqlServerMapper {
@Select("select * from MyTable")
List<Map<String,Object>> getList();
}
手动数据源切换调用
package com.cnblogs.lzrabbit;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Created by rabbit on 14-5-25.
*/
public class Main {
public static void main(String[] args) {
//初始化ApplicationContext
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
MySqlMapper mySqlMapper = applicationContext.getBean(MySqlMapper.class);
SqlServerMapper sqlServerMapper = applicationContext.getBean(SqlServerMapper.class);
//设置数据源为MySql,使用了AOP测试时请将下面这行注释
MultipleDataSource.setDataSourceKey("mySqlDataSource");
mySqlMapper.getList();
//设置数据源为SqlServer,使用AOP测试时请将下面这行注释
MultipleDataSource.setDataSourceKey("sqlServerDataSource");
sqlServerMapper.getList();
}
}
使用SpringAOP方式实现自动切换
package com.cnblogs.lzrabbit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class MultipleDataSourceAspectAdvice {
@Around("execution(* com.cnblogs.lzrabbit.*.*(..))")
public Object doAround(ProceedingJoinPoint jp) throws Throwable {
if (jp.getTarget() instanceof MySqlMapper) {
MultipleDataSource.setDataSourceKey("mySqlDataSource");
} else if (jp.getTarget() instanceof SqlServerMapper) {
MultipleDataSource.setDataSourceKey("sqlServerDataSource");
}
return jp.proceed();
}
}
调用日志
2014-05-25 20:02:04,319 DEBUG [main] com.jb51.lzrabbit.MySqlMapper.getList - ooo Using Connection [jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true, UserName=root@192.168.1.32, MySQL Connector Java] 2014-05-25 20:02:04,333 DEBUG [main] com.jb51.lzrabbit.MySqlMapper.getList - ==> Preparing: select * from MyTable 2014-05-25 20:02:04,371 DEBUG [main] com.jb51.lzrabbit.MySqlMapper.getList - ==> Parameters: 2014-05-25 20:02:04,396 DEBUG [main] com.jb51.lzrabbit.MySqlMapper.getList - <== Total: 8 2014-05-25 20:02:04,620 DEBUG [main] com.jb51.lzrabbit.SqlServerMapper.getList - ooo Using Connection [jdbc:jtds:sqlserver://127.0.0.1:1433/test, UserName=sa, jTDS Type 4 JDBC Driver for MS SQL Server and Sybase] 2014-05-25 20:02:04,620 DEBUG [main] com.jb51.lzrabbit.SqlServerMapper.getList - ==> Preparing: select * from TmallCityMap 2014-05-25 20:02:04,621 DEBUG [main] com.jb51.lzrabbit.SqlServerMapper.getList - ==> Parameters: 2014-05-25 20:02:04,681 DEBUG [main] com.jb51.lzrabbit.SqlServerMapper.getList - <== Total: 397
这里就上面的实现做个简单解释,在我们配置单数据源时可以看到数据源类型使用了org.apache.commons.dbcp.BasicDataSource,而这个代码实现了javax.sql.DataSource接口
配置sqlSessionFactory时org.mybatis.spring.SqlSessionFactoryBean注入参数dataSource类型就是javax.sql.DataSource
实现多数据源的方法就是我们自定义了一个MultipleDataSource,这个类继承自AbstractRoutingDataSource,而AbstractRoutingDataSource继承自AbstractDataSource ,AbstractDataSource 实现了javax.sql.DataSource接口,所以我们的MultipleDataSource也实现了javax.sql.DataSource接口,可以赋值给sqlSessionFactory的dataSource属性
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {}
public abstract class AbstractDataSource implements DataSource {}
再来说下MultipleDataSource的实现原理,MultipleDataSource实现AbstractRoutingDataSource抽象类,然后实现了determineCurrentLookupKey方法,这个方法用于选择具体使用targetDataSources中的哪一个数据源
<bean id="multipleDataSource" class="com.cnblogs.lzrabbit.MultipleDataSource">
<property name="defaultTargetDataSource" ref="mySqlDataSource"/>
<property name="targetDataSources">
<map>
<entry key="mySqlDataSource" value-ref="mySqlDataSource"/>
<entry key="sqlServerDataSource" value-ref="sqlServerDataSource"/>
</map>
</property>
</bean>
可以看到Spring配置中multipleDataSource设置了两个属性defaultTargetDataSource和targetDataSources,这两个属性定义在AbstractRoutingDataSource,当MyBatis执行查询时会先选择数据源,选择顺序时现根据determineCurrentLookupKey方法返回的值到targetDataSources中去找,若能找到怎返回对应的数据源,若找不到返回默认的数据源defaultTargetDataSource,具体参考AbstractRoutingDataSource的源码
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {
private Map<Object, Object> targetDataSources;
private Object defaultTargetDataSource;
/**
* Retrieve the current target DataSource. Determines the
* {@link #determineCurrentLookupKey() current lookup key}, performs
* a lookup in the {@link #setTargetDataSources targetDataSources} map,
* falls back to the specified
* {@link #setDefaultTargetDataSource default target DataSource} if necessary.
* @see #determineCurrentLookupKey()
*/
protected DataSource determineTargetDataSource() {
Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
Object lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.resolvedDataSources.get(lookupKey);
if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
dataSource = this.resolvedDefaultDataSource;
}
if (dataSource == null) {
throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
}
return dataSource;
}
/**
* Determine the current lookup key. This will typically be
* implemented to check a thread-bound transaction context.
* <p>Allows for arbitrary keys. The returned key needs
* to match the stored lookup key type, as resolved by the
* {@link #resolveSpecifiedLookupKey} method.
*/
protected abstract Object determineCurrentLookupKey();
.............
}
在动态切换数据源方法时选择了AOP方式实现,这里实现的简单粗暴,具体应用时根据实际需要灵活变通吧
题外话,这里提下SqlServer驱动选择的问题,目前SqlServer的驱动主要有微软的官方驱动和JTDS驱动两种,关于这两个驱动我做过测试,批量更新,在小数据量(100以下)时,JTDS相对微软驱动性能稍微高一点点,在数据量增大时几万到上百万时,微软驱动有着明显优势,所以若对性能比较敏感,建议使用微软驱动,否则随意
微软驱动在Maven库找不到,这点比较郁闷,若使用maven的话还得先安装到本地,这点很不爽
JTDS使用比较方便Maven直接引用即可
相关jar maven引用
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<org.springframework.version>3.2.7.RELEASE</org.springframework.version>
</properties>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.6</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jtds</groupId>
<artifactId>jtds</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
</dependencies>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
# sping
# mybatis数据源
# mybatis
# 多个数据源
# 多数据源配置
# 详解Spring Boot整合Mybatis实现 Druid多数据源配置
# Spring Boot 集成Mybatis实现主从(多数据源)分离方案示例
# Spring3 整合MyBatis3 配置多数据源动态选择SqlSessionFactory详细教程
# Spring Boot + Mybatis多数据源和动态数据源配置方法
# springboot + mybatis配置多数据源示例
# 详解SpringBoot和Mybatis配置多数据源
# Spring Boot+Mybatis+Druid+PageHelper实现多数据源并分页的方法
# Spring Boot 整合mybatis 使用多数据源的实现方法
# Spring与Mybatis相结合实现多数据源切换功能
# Spring AOP如何实现注解式的Mybatis多数据源切换详解
# 微软
# 实现了
# 多个
# 找不到
# 这两个
# 可以看到
# 时请
# 配置文件
# 这行
# 使用了
# 会有
# 依此类推
# 两种
# 不多
# 去找
# 再来
# 做过
# 做个
# 自定义
# 还得
相关文章:
如何在腾讯云服务器上快速搭建个人网站?
建站之星如何快速生成多端适配网站?
如何在腾讯云免费申请建站?
赚钱网站制作软件,建一个网站怎样才能赚钱?是如何盈利的?
免费视频制作网站,更新又快又好的免费电影网站?
深圳企业网站制作设计,在深圳如何网上全流程注册公司?
专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?
长沙企业网站制作哪家好,长沙水业集团官方网站?
php能控制zigbee模块吗_php通过串口与cc2530 zigbee通信【介绍】
如何选择高效便捷的WAP商城建站系统?
广州网站制作的公司,现在专门做网站的公司有没有哪几家是比较好的,性价比高,模板也多的?
详解ASP.NET 生成二维码实例(采用ThoughtWorks.QRCode和QrCode.Net两种方式)
怎么将XML数据可视化 D3.js加载XML
如何解决ASP生成WAP建站中文乱码问题?
网站制作员失业,怎样查看自己网站的注册者?
建站主机选购指南:核心配置与性价比推荐解析
网站海报制作教学视频教程,有什么免费的高清可商用图片网站,用于海报设计?
建站之星2.7模板:企业网站建设与h5定制设计专题
ppt制作免费网站有哪些,ppt模板免费下载网站?
建站之星伪静态规则如何正确配置?
c# 在ASP.NET Core中管理和取消后台任务
如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法
Android自定义控件实现温度旋转按钮效果
如何配置IIS站点权限与局域网访问?
,怎么在广州志愿者网站注册?
如何快速上传自定义模板至建站之星?
建站之星后台管理系统如何操作?
制作电商网页,电商供应链怎么做?
浙江网站制作公司有哪些,浙江栢塑信息技术有限公司定制网站做的怎么样?
Swift中swift中的switch 语句
官网自助建站系统:SEO优化+多语言支持,快速搭建专业网站
建站之星CMS五站合一模板配置与SEO优化指南
深入理解Android中的xmlns:tools属性
免费制作小说封面的网站有哪些,怎么接网站批量的封面单?
整人网站在线制作软件,整蛊网站退不出去必须要打我是白痴才能出去?
移民网站制作流程,怎么看加拿大移民官网?
如何快速配置高效服务器建站软件?
如何用虚拟主机快速搭建网站?详细步骤解析
如何选择香港主机高效搭建外贸独立站?
北京的网站制作公司有哪些,哪个视频网站最好?
如何获取上海专业网站定制建站电话?
建站主机如何安装配置?新手必看操作指南
学校免费自助建站系统:智能生成+拖拽设计+多端适配
建站之星后台管理:高效配置与模板优化提升用户体验
合肥做个网站多少钱,合肥本地有没有比较靠谱的交友平台?
平台云上自助建站如何快速打造专业网站?
如何在阿里云部署织梦网站?
红河网站制作公司,红河事业单位身份证如何上传?
简历在线制作网站免费版,如何创建个人简历?
建站之星代理如何获取技术支持?
*请认真填写需求信息,我们会在24小时内与您取得联系。