• mybatisAOP多数据源配置(使用阿里数据库连接池)


    由于项目中需要使用数据源,用的网上开源的项目,之前使用网上通用的多数据源配置,没有切换成功,于是采用了AOP来切换数据源。

    (此处只贴出关于多数据源和其他部分的一些配置)

    spring-context.xml

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <beans xmlns="http://www.springframework.org/schema/beans" 
      3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      4     xmlns:context="http://www.springframework.org/schema/context" 
      5     xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
      6     xmlns:aop="http://www.springframework.org/schema/aop" 
      7     xmlns:jee="http://www.springframework.org/schema/jee" 
      8     xmlns:tx="http://www.springframework.org/schema/tx"
      9     xmlns:util="http://www.springframework.org/schema/util"
     10     xmlns:task="http://www.springframework.org/schema/task" 
     11     xsi:schemaLocation="
     12         http://www.springframework.org/schema/beans 
     13         http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 
     14         http://www.springframework.org/schema/context 
     15         http://www.springframework.org/schema/context/spring-context-4.1.xsd 
     16         http://www.springframework.org/schema/jdbc 
     17         http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd 
     18         http://www.springframework.org/schema/aop 
     19          http://www.springframework.org/schema/aop/spring-aop.xsd 
     20         http://www.springframework.org/schema/jee 
     21         http://www.springframework.org/schema/jee/spring-jee-4.1.xsd 
     22         http://www.springframework.org/schema/lang 
     23          http://www.springframework.org/schema/lang/spring-lang.xsd 
     24         http://www.springframework.org/schema/tx 
     25         http://www.springframework.org/schema/tx/spring-tx-4.1.xsd 
     26         http://www.springframework.org/schema/util 
     27         http://www.springframework.org/schema/util/spring-util-4.1.xsd 
     28         http://www.springframework.org/schema/task 
     29         http://www.springframework.org/schema/task/spring-task-4.1.xsd"
     30     default-lazy-init="true">
     31 
     32     <description>Spring Configuration</description>
     33     
     34     <!-- 加载配置属性文件 -->
     35     <context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" />
     36     
     37     <!-- 加载应用属性实例,可通过  @Value("#{APP_PROP['jdbc.driver']}") String jdbcDriver 方式引用 -->
     38     <util:properties id="APP_PROP" location="classpath:jeesite.properties" local-override="true"/>
     39     
     40     <!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。  -->
     41     <context:component-scan base-package="com.vcard"><!-- base-package 如果多个,用“,”分隔 -->
     42         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     43     </context:component-scan>
     44     
     45     <bean id="jedisUtil" class="h2o.common.thirdparty.redis.JedisUtil">
     46         <constructor-arg>
     47             <list>
     48                 <value>localhost:6379</value>
     49                 <value>localhost:6379</value>
     50             </list>
     51         </constructor-arg>
     52     </bean>
     53     
     54      <!-- MyBatis begin -->
     55     <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
     56         <!-- <property name="dataSource" ref="dataSource"/> -->
     57         <property name="dataSource" ref="dynamicDataSource"/>
     58         <property name="typeAliasesPackage" value="com.vcard"/>
     59         <property name="typeAliasesSuperType" value="com.vcard.common.persistence.BaseEntity"/>
     60         <property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>
     61         <property name="configLocation" value="classpath:/mybatis-config.xml"></property>
     62     </bean>
     63     
     64     <!-- 扫描basePackage下所有以@MyBatisDao注解的接口 -->
     65     <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
     66         <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
     67         <property name="basePackage" value="com.vcard"/>
     68         <property name="annotationClass" value="com.vcard.common.persistence.annotation.MyBatisDao"/>
     69     </bean>
     70     
     71     <!-- 动态数据源 -->
     72     <bean id="dynamicDataSource" class="com.vcard.common.db.DynamicDataSource">
     73          <property name="defaultTargetDataSource" ref="dataSource"/>
     74          <property name="targetDataSources">
     75              <map key-type="java.lang.String">
     76                  <!-- <entry key="dataSource" value-ref="dataSource"/> -->
     77                  <entry key="dataSource2" value-ref="dataSource2"/>
     78              </map>
     79          </property>
     80     </bean>
     81     
     82      <!-- 定义事务 -->
     83     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     84         <property name="dataSource" ref="dynamicDataSource" />
     85     </bean>
     86     
     87     <!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务  -->
     88     <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
     89     
     90     <!-- 拦截器方式配置事务 -->
     91     <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
     92         <tx:attributes>
     93             <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
     94             <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
     95             <tx:method name="list*" propagation="REQUIRED" read-only="true"/>
     96             <tx:method name="insert*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
     97             <tx:method name="create*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
     98             <tx:method name="update*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
     99             <tx:method name="save*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
    100             <tx:method name="delete*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
    101             <tx:method name="upd*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/>
    102         </tx:attributes>
    103     </tx:advice>
    104     
    105     <bean id="transactionAdvice" class="com.vcard.common.db.DataSourceAspect"></bean>
    106     
    107     <aop:config>
    108         <aop:pointcut id="transactionPointcut" expression="execution(* com.vcard.second.modules.order.web.*.*(..))" />
    109         <aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/>
    110     </aop:config>
    111     
    112     <!-- 定义事务 -->
    113     <!-- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    114         <property name="dataSource" ref="dataSource" />
    115     </bean> -->
    116     <!-- MyBatis end -->
    117     
    118     <!-- 配置 JSR303 Bean Validator 定义 -->
    119     <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
    120 
    121     <!-- 缓存配置 -->
    122     <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
    123         <property name="configLocation" value="classpath:${ehcache.configFile}" />
    124     </bean>
    125     
    126     <!-- 计划任务配置,用 @Service @Lazy(false)标注类,用@Scheduled(cron = "0 0 2 * * ?")标注方法 -->
    127     <task:executor id="executor" pool-size="10"/> <task:scheduler id="scheduler" pool-size="10"/>
    128     <task:annotation-driven scheduler="scheduler" executor="executor" proxy-target-class="true"/>
    129     
    130     <!-- 数据源配置, 使用 BoneCP 数据库连接池 -->
    131     <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
    132         <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
    133         <property name="driverClassName" value="${jdbc.driver}" />
    134         
    135         <!-- 基本属性 url、user、password -->
    136         <property name="url" value="${jdbc.url}" />
    137         <property name="username" value="${jdbc.username}" />
    138         <property name="password" value="${jdbc.password}" />
    139         
    140         <!-- 配置初始化大小、最小、最大 -->
    141         <property name="initialSize" value="${jdbc.pool.init}" />
    142         <property name="minIdle" value="${jdbc.pool.minIdle}" /> 
    143         <property name="maxActive" value="${jdbc.pool.maxActive}" />
    144         
    145         <!-- 配置获取连接等待超时的时间 -->
    146         <property name="maxWait" value="60000" />
    147         
    148         <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    149         <property name="timeBetweenEvictionRunsMillis" value="60000" />
    150         
    151         <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    152         <property name="minEvictableIdleTimeMillis" value="300000" />
    153         
    154         <property name="validationQuery" value="${jdbc.testSql}" />
    155         <property name="testWhileIdle" value="true" />
    156         <property name="testOnBorrow" value="false" />
    157         <property name="testOnReturn" value="false" />
    158         
    159         <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
    160         <property name="poolPreparedStatements" value="true" />
    161         <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->
    162         
    163         <!-- 配置监控统计拦截的filters -->
    164         <property name="filters" value="stat" /> 
    165     </bean>
    166     
    167     <!-- 数据源配置, 使用 BoneCP 数据库连接池 -->
    168     <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
    169         <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
    170         <property name="driverClassName" value="${jdbc2.driver}" />
    171         
    172         <!-- 基本属性 url、user、password -->
    173         <property name="url" value="${jdbc2.url}" />
    174         <property name="username" value="${jdbc2.username}" />
    175         <property name="password" value="${jdbc2.password}" />
    176         
    177         <!-- 配置初始化大小、最小、最大 -->
    178         <property name="initialSize" value="${jdbc2.pool.init}" />
    179         <property name="minIdle" value="${jdbc2.pool.minIdle}" /> 
    180         <property name="maxActive" value="${jdbc2.pool.maxActive}" />
    181         
    182         <!-- 配置获取连接等待超时的时间 -->
    183         <property name="maxWait" value="60000" />
    184         
    185         <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    186         <property name="timeBetweenEvictionRunsMillis" value="60000" />
    187         
    188         <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    189         <property name="minEvictableIdleTimeMillis" value="300000" />
    190         
    191         <property name="validationQuery" value="${jdbc.testSql}" />
    192         <property name="testWhileIdle" value="true" />
    193         <property name="testOnBorrow" value="false" />
    194         <property name="testOnReturn" value="false" />
    195         
    196         <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)
    197         <property name="poolPreparedStatements" value="true" />
    198         <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->
    199         
    200         <!-- 配置监控统计拦截的filters -->
    201         <property name="filters" value="stat" /> 
    202     </bean>
    203 
    204     <!-- 数据源配置, 使用应用服务器的数据库连接池 
    205     <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/jeesite" />-->
    206 
    207     <!-- 数据源配置, 不使用连接池 
    208     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    209         <property name="driverClassName" value="${jdbc.driver}" />
    210         <property name="url" value="${jdbc.url}" />
    211         <property name="username" value="${jdbc.username}"/>
    212         <property name="password" value="${jdbc.password}"/>
    213     </bean>-->
    214     
    215 </beans>

    jeesite.properties

      1 #============================#
      2 #===== Database sttings =====#
      3 #============================#
      4 
      5 #oracle database settings
      6 #jdbc.type=oracle
      7 #jdbc.driver=oracle.jdbc.driver.OracleDriver
      8 #jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
      9 #jdbc.username=jeesite
     10 #jdbc.password=123456
     11 
     12 #mysql database setting
     13 jdbc.type=mysql
     14 jdbc.driver=com.mysql.jdbc.Driver
     15 #jdbc.url=jdbc:mysql://localhost:3306/vcardjeesite?useUnicode=true&characterEncoding=utf-8
     16 #jdbc.username=root
     17 #jdbc.password=123456
     18 jdbc.url=jdbc:mysql://localhost:3306/vcardjeesite?useUnicode=true&characterEncoding=utf-8
     19 jdbc.username=changyue
     20 jdbc.password=cykjdev164123
     21 
     22 jdbc2.type=mysql
     23 jdbc2.driver=com.mysql.jdbc.Driver
     24 jdbc2.url=jdbc:mysql://localhost:3306/newmall?useUnicode=true&characterEncoding=utf-8
     25 jdbc2.username=changyue
     26 jdbc2.password=cykjdev164123
     27 #jdbc2.url=jdbc:mysql://localhost:3306/newmalljeesite?useUnicode=true&characterEncoding=utf-8
     28 #jdbc2.username=root
     29 #jdbc2.password=123456
     30 
     31 #mssql database settings
     32 #jdbc.type=mssql
     33 #jdbc.driver=net.sourceforge.jtds.jdbc.Driver
     34 #jdbc.url=jdbc:jtds:sqlserver://localhost:1433/jeesite
     35 #jdbc.username=sa
     36 #jdbc.password=sa
     37 
     38 #pool settings
     39 jdbc.pool.init=1
     40 jdbc.pool.minIdle=3
     41 jdbc.pool.maxActive=20
     42 
     43 jdbc2.pool.init=1
     44 jdbc2.pool.minIdle=3
     45 jdbc2.pool.maxActive=20
     46 
     47 #jdbc.testSql=SELECT 'x'
     48 jdbc.testSql=SELECT 'x' FROM DUAL
     49 
     50 #redis settings
     51 redis.keyPrefix=vcard
     52 redis.host=localhost
     53 redis.port=6379
     54 
     55 #============================#
     56 #===== System settings ======#
     57 #============================#
     58 
     59 #u4ea7u54c1u4fe1u606fu8bbeu7f6e
     60 productName=u5546u6237u5F00u653Eu5E73u53F0
     61 copyrightYear=2017
     62 version=V1.2.7
     63 
     64 #u6f14u793au6a21u5f0f: u4e0du80fdu64cdu4f5cu548cu4fddu5b58u7684u6a21u5757uff1a sys: area/office/user/role/menu/dict, cms: site/category
     65 demoMode=false
     66 
     67 #u7ba1u7406u57fau7840u8defu5f84, u9700u540cu6b65u4feeu6539uff1aweb.xml
     68 adminPath=/a
     69 
     70 #u524du7aefu57fau7840u8defu5f84
     71 frontPath=/f
     72 
     73 #u7f51u7ad9URLu540eu7f00
     74 urlSuffix=.html
     75 
     76 #u662fu5426u4e0du5141u8bb8u5237u65b0u4e3bu9875uff0cu4e0du5141u8bb8u60c5u51b5u4e0buff0cu5237u65b0u4e3bu9875u4f1au5bfcu81f4u91cdu65b0u767bu5f55
     77 notAllowRefreshIndex=false
     78 
     79 #u662fu5426u5141u8bb8u591au8d26u53f7u540cu65f6u767bu5f55
     80 user.multiAccountLogin=true
     81 
     82 #u5206u9875u914du7f6e
     83 page.pageSize=10
     84 
     85 #u7855u6b63u7ec4u4ef6u662fu5426u4f7fu7528u7f13u5b58
     86 supcan.useCache=false
     87 
     88 #u901au77e5u95f4u9694u65f6u95f4u8bbeu7f6e, u5355u4f4duff1au6bebu79d2, 30s=30000ms, 60s=60000ms
     89 oa.notify.remind.interval=60000
     90 
     91 #============================#
     92 #==== Framework settings ====#
     93 #============================#
     94 
     95 #u4f1au8bddu8d85u65f6uff0c u5355u4f4duff1au6bebu79d2uff0c 20m=1200000ms, 30m=1800000ms, 60m=3600000ms
     96 session.sessionTimeout=1800000
     97 #u4f1au8bddu6e05u7406u95f4u9694u65f6u95f4uff0c u5355u4f4duff1au6bebu79d2uff0c2m=120000msu3002
     98 session.sessionTimeoutClean=120000
     99 
    100 #u7f13u5b58u8bbeu7f6e
    101 ehcache.configFile=cache/ehcache-local.xml
    102 #ehcache.configFile=cache/ehcache-rmi.xml
    103 
    104 #u7d22u5f15u9875u8defu5f84
    105 web.view.index=/a
    106 
    107 #u89c6u56feu6587u4ef6u5b58u653eu8defu5f84
    108 web.view.prefix=/WEB-INF/views/
    109 web.view.suffix=.jsp
    110 
    111 #u6700u5927u6587u4ef6u4e0au4f20u9650u5236uff0cu5355u4f4du5b57u8282. 10M=10*1024*1024(B)=10485760 bytesuff0cu9700u540cu6b65u4feeu6539uff1ackfinder.xml
    112 web.maxUploadSize=10485760
    113 
    114 #u65e5u5fd7u62e6u622au8bbeu7f6euff0cu6392u9664u7684URIuff1bu5305u542b @RequestMappingu6ce8u89e3u7684valueu3002uff08u5df2u4f5cu5e9fuff09
    115 #web.logInterceptExcludeUri=/, /login, /sys/menu/tree, /sys/menu/treeData, /oa/oaNotify/self/count
    116 #web.logInterceptIncludeRequestMapping=save, delete, import, updateSort
    117 
    118 #u9759u6001u6587u4ef6u540eu7f00
    119 web.staticFile=.css,.js,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.htm,.html,.crx,.xpi,.exe,.ipa,.apk
    120 
    121 #u5355u70b9u767bu5f55CASu8bbeu7f6e
    122 cas.server.url=http://127.0.0.1:8080/cas
    123 cas.project.url=http://127.0.0.1:8080/vcard
    124 
    125 #u5de5u4f5cu6d41u8bbeu7f6e
    126 activiti.isSynActivitiIndetity=false
    127 activiti.export.diagram.path=c:/activiti_diagram
    128 #activiti font (windows font: u5b8bu4f53  linux font: simsun)
    129 activiti.diagram.activityFontName=u5b8bu4f53
    130 activiti.diagram.labelFontName=u5b8bu4f53
    131 #5.21.0 u65b0u589eu53c2u6570 ,2016.06.23 u8f66u6811u708e add
    132 activiti.diagram.annotationFontName=u5b8bu4f53
    133 #activitiu5916u90e8u8868u5355u6839u5730u5740u914du7f6e
    134 activiti.form.server.url=
    135 
    136 #u4e0au4f20u6587u4ef6u7eddu5bf9u8defu5f84, u8defu5f84u4e2du4e0du5141u8bb8u5305u542bu201cuserfilesu201d
    137 #userfiles.basedir=D:/jeesite
    138 
    139 #u5de5u7a0bu8defu5f84uff0cu5728u4ee3u7801u751fu6210u65f6u83b7u53d6u4e0du5230u5de5u7a0bu8defu5f84u65f6uff0cu53efu518du6b64u6307u5b9au7eddu5bf9u8defu5f84u3002
    140 #projectPath=D:\workspace\jeesite

    DynamicDataSource.java

     1 import org.aspectj.lang.annotation.Aspect;
     2 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
     3 import org.springframework.stereotype.Component;
     4 
     5 /**
     6  * 多数据源配置
     7  */
     8 @Component
     9 @Aspect
    10 public class DynamicDataSource extends AbstractRoutingDataSource {
    11 
    12     public DynamicDataSource() {
    13     }
    14     
    15     @Override
    16     protected Object determineCurrentLookupKey() {
    17         return DBContextHolder.getDbType();
    18     }
    19     
    20     public java.util.logging.Logger getParentLogger() {
    21         return null;
    22     }
    23 }

    DBContextHolder.java

     1 public class DBContextHolder {
     2     private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
     3     public static String Master = "dataSource";
     4     public static String Slave = "dataSource2";
     5     
     6     public DBContextHolder() {
     7     }
     8 
     9     public static String getDbType() {
    10         String db = contextHolder.get();
    11         if (db == null) {
    12             db = Master;
    13         }
    14         return db;
    15     }
    16     
    17     public static void setDbType(String str) {
    18         contextHolder.set(str);
    19     }
    20     
    21     public static void setMater() {
    22         contextHolder.set(Master);
    23     }
    24     
    25     public static void serSlave() {
    26         contextHolder.set(Slave);
    27     }
    28     
    29     public static void clearDBType() {
    30         contextHolder.remove();
    31     }
    32 }

    DataSourceAspect.java

     1 import java.lang.reflect.Method;
     2 
     3 import org.apache.logging.log4j.LogManager;
     4 import org.apache.logging.log4j.Logger;
     5 import org.aspectj.lang.JoinPoint;
     6 import org.springframework.aop.AfterReturningAdvice;
     7 import org.springframework.aop.MethodBeforeAdvice;
     8 import org.springframework.aop.ThrowsAdvice;
     9 
    10 public class DataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
    11     private static final Logger log = LogManager.getLogger(DataSourceAspect.class);
    12 
    13     public DataSourceAspect() {
    14     }
    15 
    16     public void before(Method m, Object[] args, Object target) throws Throwable {
    17         try {
    18             if (m != null) {
    19                 // 拦截ImsShopOrderController中的方法,切换数据源
    20                 if ((m.getName().equals("listImsShopOrder") 
    21                         || m.getName().equals("sendGoods") 
    22                         || m.getName().equals("cancleSend")) 
    23                         && !m.getName().contains("FromMaster")) {
    24                     DBContextHolder.setDbType(DBContextHolder.Slave);
    25                 } else {
    26                     DBContextHolder.setDbType(DBContextHolder.Master);
    27                 }
    28             }
    29         } catch (Exception var5) {
    30             log.error("data source aspect error.", var5);
    31         }
    32 
    33     }
    34 
    35     public void after(JoinPoint point) {
    36         log.info("clear db type after method.current id {}",
    37                 new Object[] { Long.valueOf(Thread.currentThread().getId()) });
    38         DBContextHolder.clearDBType();
    39     }
    40 
    41     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    42     }
    43 
    44     public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
    45         log.info("current db type {} when exception", new Object[] { DBContextHolder.getDbType() });
    46         DBContextHolder.setDbType(DBContextHolder.Master);
    47     }
    48 }
  • 相关阅读:
    Tree 点分治
    [LUOGU4149][IOI2011]Race
    [BZOJ2152] 聪聪可可
    [LUOGU3413] SAC#1
    [JZOJ5776]【NOIP2008模拟】小x游世界树
    [JZOJ5775]【NOIP2008模拟】农夫约的假期
    [JZOJ5781]【NOIP提高A组模拟2018.8.8】秘密通道
    [JZOJ5778]【NOIP提高A组模拟2018.8.8】没有硝烟的战争
    [JZOJ5773]【NOIP2008模拟】简单数学题
    [JZOJ5459]【NOIP2017提高A组冲刺11.7】密室
  • 原文地址:https://www.cnblogs.com/wdpnodecodes/p/8328054.html
Copyright © 2020-2023  润新知