开发者

springboot项目配置多数据库连接的示例详解

目录
  • 前言
  • 创建springboot项目
    • 1.点击创建新maven项目,然后下一步
    • 2.输入项目名称,创建项目
    • 3.创建完成之后,初始默认结构如下:
  • 需要创建的文件夹结构分类
    • 导入pom依赖
      • 编写配置XML(yml)
        • 编写resource的mapper查询
          • 编写mapper接口
            • 编写多数据库配置
              • 启动类
                • 异常处理
                  • 结语

                    前言

                    之前编写了一篇maven项目创建多数据库的方法,现在对springboot更了解之后,将把springboot项目配置多数据库的方法贴出来。

                    从项目开始创建到调用数据库依次写出来。

                    PS:本项目使用的是IDEA进行创建

                    创建springboot项目

                    1.点击创建新maven项目,然后下一步

                    springboot项目配置多数据库连接的示例详解

                    2.输入项目名称,创建项目

                    springboot项目配置多数据库连接的示例详解

                    3.创建完成之后,初始默认结构如下:

                    springboot项目配置多数据库连接的示例详解

                    springboot项目配置多数据库连接的示例详解

                    需要创建的文件夹结构分类

                    以下截图为进行不同功能分类进行创建的文件夹

                    springboot项目配置多数据库连接的示例详解

                    文件说明:

                    Java文件都应该在java文件夹下
                    资源文件都应该放在resources下
                    bean: 存放实体对象
                    controller:存放控制层
                    service: 存放service层
                    db: 多数据库配置
                    mapper:数据库连接接口
                    tools:工具类
                    resources/mapper数据库的增删改查文件

                    以下为为配置多数据库应创建的文件,文件截图和说明如下:http://www.devze.com

                    springboot项目配置多数据库连接的示例详解

                    java文件都应该在java文件夹下
                    资源文件都应该放在resources下
                    db: db文件夹下的文件为多数据库配置代码
                    mapper:com.mapper下的文件为编写数据库的增删改查方法
                    MultipleDataApplication.java:启动类
                    resources/mapper下的文件数据库的增删改查`语句`文件
                    其中
                    resources/mapper下的MyDb1为对应数据库MyDb1的编写数据库语句文件
                    resources/mapper下的MyDB2为对应数据库MyDb2的编写数据库语句文件
                    applition.yml:springboot项目配置文件
                    pom.xml:依赖配置文件

                    导入pom依赖

                    初始pom.xml配置文件代码为:

                    springboot项目配置多数据库连接的示例详解

                    要完成多数据库配置,需要至少导入以下依赖:

                    第一个:springboot依赖

                    第二个:myBATis

                    第三个:数据库驱动依赖

                    第四个: 阿里巴巴数据库连接池

                    pom.xml代码如下:

                    <?xml version="1.0" encoding="UTF-8"?>
                    <project xmlns="http://maven.apache.org/POM/4.0.0"
                             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
                        <modelVersion>4.0.0</modelVersion>
                        <groupId>org.example</groupId>
                        <artifactId>multipleDataConnection</artifactId>
                        <version>1.0-SNAPSHOT</version>
                    <!--    springboot管理配置-->
                        <parent>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-starter-parent</artifactId>
                            <version>2.4.5</version>
                            <relativePath/>
                        </parent>
                        <dependencies>
                            <!-- springboot依赖 -->
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter</artifactId>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-test</artifactId>
                                <scope>test</scope>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-web</artifactId>
                            </dependency>
                            <!-- mybatis-->
                            <dependency>
                                <groupId>com.baomidou</groupId>
                                <artifactId>mybatis-plus-boot-starter</artifactId>
                                <version>3.4.3</version>
                            </dependency>
                            <dependency>
                                <groupId>org.mybatis</groupId>
                                <artifactId>mybatis</artifactId>
                                <version>3.5.5</version>
                            </dependency>
                            <!-- mysql数据库驱动 -->
                            <dependency>
                                <groupId>mysql</groupId>
                                <artifactId>mysql-connector-java</artifactId>
                            </dependency>
                            <!-- 数据库连接池 -->
                            <dependency>
                                <groupId>com.alibaba</groupId>
                                <artifactId>druid</artifactId>
                                <version>1.2.9</version>
                            </dependency>
                        </dependencies>
                        <properties>
                            <maven.compiler.source>8</maven.compiler.source>
                            <maven.compiler.target>8</maven.compiler.target>
                        </properties>
                    </project>

                    编写配置xml(yml)

                    在项目配置信息,需要编写启动端口,数据库连接以及连接池和mybatis的配置信息

                    具体配置信息如下:

                    以下为application.yml格式配置文件代码

                    server:
                      port: 9021
                      servlet:
                        context-path: /启动路径
                    #    数据库
                    spring:
                      datasource:
                        MyDb1:
                          type: com.alibaba.druid.pool.DruidDataSource
                          driver-class-name: com.mysql.jdbc.Driver
                          url: jdbc:mysql://数据库ip:3306/数据库名
                          username: 用户名
                          password: 密码
                        MyDb2:
                          type: com.alibaba.druid.pool.DruidDataSource
                          driver-class-name: com.mysql.jdbc.Driver
                          url: jdbc:mysql://数据库ip:3306/数据库名
                          username: 用户名
                          password: 密码
                        druid:
                          #最大活跃数
                          maxActive: 20
                          #初始化数量
                          initialSize: 1
                          #最大连接等待超时时间
                          maxWait: 60000
                          #打开PSCache,并且指定每个连接PSCache的大小
                          poolPreparedStatements: true
                          maxPoolPreparedStatementPerConnectionSize: 20
                          #通过connectionProperties属性来打开mergeSql功能;慢SQL记录
                          connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
                          minIdle: 1
                          timeBetweenEvictionRunsMillis: 60000
                          minEvictableIdleTimeMillis: 300000
                          validationQuery: select 1 from dual
                          validationQuery1: select 1
                          # 注意 有的数据库不支持select 1 from dual 在配置处需要修改为下方的select 1
                          testWhileIdle: true
                          testOnBorrow: false
                          testOnReturn: false
                          #配置监控统计拦截的filters,去掉后监控界面sql将无法统计,'wall'用于防火墙
                          filters: stat, wall, log4j
                          # 合并多个DruidDataSource的监控数据
                          use-global-data-source-stat: true
                    mybatis:
                      configuration:
                        map-underscore-to-camel-case: true
                        # 全局的sql执行超时时间(单位s) 当sql执行时间超过1s,就会断开操作了,起到保护数据库服务的作用
                        default-statement-timeout: 5
                        # 流式
                        default-fetch-size: 100
                        # 配置查询返回最大数量
                      max_row: 10000

                    注意: spring下的datasource,为编写多个数据库的连接信息,ip账号密码等。

                    其中作为演示,我把两个数据库名称分别标注命名为MyDb1和MyDb2

                    validationQuery:为验证不同的数据库连接的语句,不同数据库的验证语句不同

                    不同数据库验证语句如下:

                    数据库validationQuery验证语句
                    hsqldbselect 1 from INFORMATION_SCHEMA.SYSTEM_USERS
                    oracleselect 1 from dual
                    DB2select 1 from sysibm.sysdummy1
                    MySqlselect 1
                    Microsoft SqlServerselect 1
                    PostgreSQLselect version()
                    ingresselect 1
                    derbyselect 1
                    H2select 1

                    这个验证连接语句需要根据自己连的数据库进行更改配置语句

                    编写resource的mapper查询

                    在resource/mapper里,我创建了两个文件MyDb1Mapper.xmlMyDb2Mapper.xml,用来标识两个不同数据库的连接的文件.

                    其中MyDb1Mapper.xml文件代码如下(不包括增删改查功能:)

                    <?xml version="1.0" encoding="UTF-8" ?>
                    <!DOCTYPE mapper
                            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
                    <mapper namespace="com.mapper.MyDb1.MyDb1Mapper">
                    </mapper>

                    其中MyDb2Mapper.xml文件代码如下(不包括功能)

                    <?xml version="1.0" encoding="UTF-8" ?>
                    <!DOCTYPE mapperSiLmM
                            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
                    <mapper namespace="com.mapper.MyDb2.MyDb2Mapper">
                    </mapper>

                    注意:此处`namespace`路径为数据库接口文件路径

                    编写mapper接口

                    在com.demo.mapper下有两个文件夹,分别标识不同的数据库接口文件,

                    其中mapper/MyDb1Mapper.java文件代码如下(不包含功能):

                    package com.mapper.MyDb1;
                    import org.apache.ibatis.annotations.Mapper;
                    @Mapper
                    public interface MyDb1Mapper {
                    }

                    其中mapper/MyDb2Mapper.java文件代码如下(不包含功能):

                    package com.mapper.MyDb2;
                    import org.apache.ibatis.annotations.Mapper;
                    @Mapper
                    public interface MyDb2Mapper {
                    }

                    名称随便命名,自己容易区别就行

                    编写多数据库配置

                    如你所见,在上方截图中我编写了四个文件作为数据库配置,如你需要根据它去删除或添加多个数据库,把里面的DbMyDb1ConfigDbMyDb2Config换成你自己的数据库配置即可(根据yml里,你数据库的配置修改)

                    同时,在DataSourceConfig里增减需要的数据库配置代码,复制修改名称即可

                    MybatisInterceptor不需要修改。

                    如果有更多的数据库需要连接进来,只需要在`DataSourceConfig`里添加新数据库的配置代码,复制

                    `DbMyDb1Config`和`DbMyDb2Config`其中一个文件进行修改DataSourceConfig对应名称配置即可

                    其中,DataSourceConfig代码如下:

                    package com.db;
                    import com.alibaba.druid.pool.DruidDataSource;
                    import org.springframework.beans.factory.annotation.Qualifier;
                    import org.springframework.beans.factory.annotation.Value;
                    import org.springframework.context.annotation.Bean;
                    import org.springframework.context.annotation.Configuration;
                    import javax.sql.DataSource;
                    import java.sql.SQLException;
                    @Configuration
                    public class DataSourceConfig {
                        @Value("${spring.datasource.MyDb1.driver-class-name}")
                        private String MyDb1Driver;
                        @Value("${spring.datasource.MyDb1.url}")
                        private String MyDb1Url;
                        @Value("${spring.datasource.MyDb1.username}")
                        private String MyDb1Username;
                        @Value("${spring.datasource.MyDb1.password}")
                        private String MyDb1Password;
                        @Value("${spring.datasource.MyDb2.driver-class-name}")
                        private String MyDb2Driver;
                        @Value("${spring.datasource.MyDb2.url}")
                        private String MyDb2Url;
                        @Value("${spring.datasource.MyDb2.username}")
                        private String MyDb2Username;
                        @Value("${spring.datasource.MyDb2.password}")
                        private String MyDb2Password;
                        @Value("${spring.datasource.druid.maxActive}")
                        private Integer maxActive;
                        @Value("${spring.datasource.druid.initialSize}")
                        private Integer initialSize;
                        @Value("${spring.datasource.druid.maxWait}")
                        private Integer maxWait;
                        @Value("${spring.datasource.druid.poolPreparedStatements}")
                        private boolean poolPreparedStatements;
                        @Value("${spring.datasource.druid.maxPoolPreparedStatementPerConnectionSize}")
                        private Integer maxPoolPreparedStatementPerConnectionSize;
                        @Value("${spring.datasource.druid.minIdle}")
                        private Integer minIdle;
                        @Value("${spring.datasource.druid.connectionProperties}")
                        private String connectionProperties;
                        @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
                        private Integer timeBetweenEvictionRunsMillis;
                        @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
                        private Integer minEvictableIdleTimeMillis;
                        @Value("${spring.datasource.druid.validationQuery}")
                        private String validationQuery;
                        @Value("${spring.datasource.druid.validationQuery1}")
                        private String validationQuery1;
                        @Value("${spring.datasource.druid.testWhileIdle}")
                        private boolean testWhileIdle;
                        @Value("${spring.datasource.druid.testOnBorrow}")
                        private boolean testOnBorrow;
                        @Value("${spring.datasource.druid.testOnReturn}")
                        private boolean testOnReturn;
                        @Value("${spring.datasource.druid.filters}")
                        private String filters;
                        @Value("${spring.datasource.druid.use-global-data-source-stat}")
                        private boolean useGlobalDataSourceStat;
                        @Bean(name = "dsMyDb1")
                        @Qualifier("dsMyDb1")
                        public DataSource dataSourceMyDb1() {
                            DruidDataSource datasource = new DruidDataSource();
                            datasource.setUrl(MyDb1Url);
                            datasource.setUsername(MyDb1Username);
                            datasource.setPassword(MyDb1Password);
                            datasource.setDriverClassName(MyDb1Driver);
                            datasource.setInitialSize(initialSize);
                            datasource.setMinIdle(minIdle);
                            datasource.setMaxActive(maxActive);
                            datasource.setMaxWait(maxWait);
                            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
                            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
                            datasource.setValidationQuery(validationQuery);
                            datasource.setTestWhileIdle(testWhileIdle);
                            datasource.setTestOnBorrow(testOnBorrow);
                            datasource.setTestOnReturn(testOnReturn);
                            datasource.setPoolPreparedStatements(poolPreparedStatements);
                            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
                    //        try {
                    //            datasource.setFilters(filters);
                    //        } catch (SQLException e) {
                    //            System.err.println("druid configuration initialization filter: " + e);
                    //        }
                            datasource.setConnectionProperties(connectionProperties);
                            datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
                            return datasource;
                        }
                        @Bean(name = "dsMyDb2")
                        @Qualifier("dsMyDb2")
                        public DataSource dataSourceMyDb2() {
                            DruidDataSource datasource = new DruidDataSource();
                            datasource.setUrl(MyDb2Url);
                            datasource.setUsername(MyDb2Username);
                            datasource.setPassword(MyDb2Password);
                            datasource.setDriverClassName(MyDb2Driver);
                            datasource.setInitialSize(initialSize);
                            datasource.setMinIdle(minIdle);
                            datasource.setMaxActive(maxActive);
                            datasource.setMaxWait(maxWait);
                            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
                            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
                            datasource.setValidationQuery(validationQuery);
                            datasource.setTestWhileIdle(testWhileIdle);
                            datasource.setTestOnBorrow(testOnBorrow);
                            datasource.setTestOnReturn(testOnReturn);
                            datasource.setPoolPreparedStatements(poolPreparedStatements);
                            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
                    //        try {
                    //            datasource.setFilters(filters);
                    //        } catch (SQLException e) {
                    //            System.err.println("druid configuration initialization filter: " + e);
                    //        }
                            datasource.setConnectionProperties(connectionProperties);
                            datasource.setUseGlobalDataSourceStat(useGlobalDataSourceStat);
                            return datasource;
                        }
                    }

                    其中MybatisInterceptor代码如下:

                    package com.db;
                    import org.apache.ibatis.executor.Executor;
                    import org.apache.ibatis.mapping.MappedStatement;
                    import org.apache.ibatis.plugin.*;
                    import org.apache.ibatis.session.ResultHandler;
                    import org.apache.ibatis.session.RowBounds;
                    import org.springframework.beans.factory.annotation.Value;
                    import org.springframework.stereotype.Component;
                    import java.util.Properties;
                    @Component
                    @Intercepts({@Signature(type = Executor.class, method = "query",
                            args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
                    public class MybatisInterceptor implements Interceptor {
                        @Value("${mybatis.max_row}")
                        private Integer max_row;
                        @Override
                        public Object intercept(Invocation invocation) throws Throwable {
                            invocation.getArgs()[2] = new RowBounds(0, (null == max_row || 0 == max_row) ? 10000 : max_row);
                            return invocation.proceed();
                        }
                        @Override
                        public Object plugin(Object o) {
                            return Plugin.wrap(o, this);
                        }
                        @Override
                        public void setProperties(Properties properties) {
                        }
                    }

                    其中DbMyDb1Config 代码如下:

                    package com.db;
                    import org.apache.ibatis.plugin.Interceptor;
                    import org.apache.ibatis.session.SqlSessionFactory;
                    import org.mybatis.spring.SqlSessionFactoryBean;
                    import org.mybatis.spring.SqlSessionTemplate;
                    import org.mybatis.spring.annotation.MapperScan;
                    import org.springframework.beans.factory.annotation.Autowired;
                    import org.springframework.beans.factory.annotation.Qualifier;
                    import org.springframework.context.annotation.Bean;
                    import org.springframework.context.annotation.Configuration;
                    import org.springframework.context.annotation.Primary;
                    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
                    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
                    import javax.annotation.Resource;
                    import javax.sql.DataSource;
                    @Configuration
                    @MapperScan(basePackages = {"com.mapper.MyDb1"}, sqlSessionFactoryRef = "SqlSessionFactoryMyDb1")
                    public class DbMyDb1Config {
                        @Autowired
                        private MybatisInterceptor mybatisInterceptor;
                        @Resource
                        @Qualifier("dsMyDb1")
                        private DataSource dsMyDb1;
                        /**
                         * 创建sqlsessionfacpythontory
                         */
                        @Bean(name = {"SqlSessionFactoryMyDb1"})
                        @Primary
                        public SqlSessionFactory sqlSessionFactoryMyDb1() throws Exception {
                            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
                            sessionFactoryBean.setDataSource(dsMyDb1);
                            org.springframework.core.io.Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/MyDb1/*.xml");
                            sessionFactoryBean.setMapperlocations(resources);
                            sessionFactoryBean.setPlugins(new Interceptor[]{mybatisInterceptor});
                            return sessionFactoryBean.getObject();
                        }
                        @Bean(name = {"dbMyDb1TransactionManager"})
                        @Primary
                        public DataSourceTransactionManager dbMyDb1TransactionManager(@Qualifier("dsMyDb1") DataSource dataSource) {
                            return new DataSourceTransactionManager(dataSource);
                        }
                        @Bean
                        @Primary
                        public SqlSessionTemplate dbMyDb1SqlSessionTemplate() throws Exception {
                            return new SqlSessionTemplate(sqlSessionFactoryMyDb1());
                        }
                    }

                    其中DbMyDb2Config代码如下

                    package com.db;
                    import org.apache.ibatis.plugin.Interceptor;
                    import org.apache.ibatis.session.SqlSessionFactory;
                    import org.mybatis.spring.SqlSessionFactoryBean;
                    import org.mybatis.spring.SqlSessionTemplate;
                    import org.mybatis.spring.annotation.MapperScan;
                    import org.springframework.beans.factory.annotation.Autowired;
                    import org.springframework.beans.factory.annotation.Qualifier;
                    import org.springframework.context.annotation.Bean;
                    import org.springframework.context.annotation.Configuration;
                    import org.springframework.context.annotation.Primary;
                    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
                    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
                    import javax.annotation.Resource;
                    import javax.sql.DataSource;
                    @Configuration
                    @MapperScan(basePackages = {"com.Invoice.mapper.MyDb2"}, sqlSessionFactoryRef = "SqlSessionFactoryMyDb2")
                    public class DbMyDb2Config {
                        @Autowired
                        private MybatisInterceptor mybatisInterceptor;
                        @Resource
                        @Qualifier("dsMyDb2")
                        private DataSource dsMyDb2;
                        /**
                         * 创建sqlsessionfactory
                         */
                        @Bean(name = {"SqlSessionFactoryMyDb2"})
                        public SqlSessionFactory sqlSessionFactoryMyDb2() throws Exception {
                            SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
                            sessionFactoryBean.setDataSource(dsMyDb2);
                            org.springframework.core.io.Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/MyDb2/*.xml");
                            sessionFactoryBean.setMapperLocations(resources);
                            sessionFactoryBean.setPlugins(new Interceptor[]{mybatisInterceptor});
                            return sessionFactoryBean.getObject();
                        }
                        @Bean(name = {"dbMyDb2TransactionManager"})
                        public DataSourceTransactionManager dbMyDb2TransactionManager(@Qualifier("dsMyDb2") DataSource dataSource) {
                            return new DataSourceTransactionManager(dataSource);
                        }
                        @Bean
                        public SqlSessionTemplate dbMyDb2SqlSessionTemplate() throws Exception {
                            return new SqlSessionTemplate(sqlSessionFactoryMyDb2());
                        }
                    }

                    注意:

                    MyDb1Config和MyDb2Config的代码有一个很重要的区别,必须有且只有一个数据库作为主数据库。

                    用注解@primary标注

                    可以仔细看MyDb1Config和MyDb2Config的这个区别,他们的区别就在于@primary

                    启动类

                    Application.androidjava启动类代码如下:

                    package com;
                    import org.mybatis.spring.annotation.MapperScan;
                    import org.springframework.boot.SpringApplication;
                    import org.springframework.boot.autoconfigure.SpringBootApplication;
                    /**
                     * description: 启动类
                     * */
                    @SpringBootApplication
                    @MapperScan("com.mapper")
                    public class MultipleDataApplication {
                        public static void main(String[] args) {
                            SpringApplication.run(MultipleDataApplication.class,args);
                        }
                    }

                    运行成功截图

                    springboot项目配置多数据库连接的示例详解

                    springboot项目配置多数据库连接的示例详解

                    异常处理

                    在连接某些数据库,可能会出现一些异常,如写了接口方法找不到、但确实有写;如hana的时候遇到一个找不到对应的表,但是确实是有这个表在数据库,可以尝试简化DataSourceConfig的各个数据库配置

                    以下代码为最原始简单的连接数据库的配置,加上阿里巴巴连接池的目的是为了优化数据库连接

                    所有的数据库连接配置都可以用以下的代码配置

                        @Bean(name = "dsDemo")
                        @Qualifier("dsDemo")
                        public DataSource dataSourceErp() {
                            return DataSourceBuilder.create()
                                    .type(DruidDataSource.class)
                                    .driverClassName(DemoDriver)
                                    .url(DemopUrl)
                                    .username(DemoUsername)
                          python          .password(DemoPassword)
                                    .build();
                        }

                    结语

                    以上基于springboot多数据库连接的项目我是重新新建项目后一步步验证后发出来的。测试有效。

                    如果后续有更完善的内容,将会在这边进行更新出来。

                    希望能帮助到大家。

                    到此这篇关于springboot项目配置多数据库连接的文章就介绍到这了,更多相关springboot配置多数据库连接内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

                    0

                    上一篇:

                    下一篇:

                    精彩评论

                    暂无评论...
                    验证码 换一张
                    取 消

                    最新开发

                    开发排行榜