spring

1、Spring简介

官网: https://spring.io/

1.1 什么是框架

- 源自于建筑学,隶属土木工程,后发展到软件工程领域

- 软件工程框架:经过验证的,具有一定功能的,半成品软件

  - 经过验证

  - 具有一定功能

  - 半成品

1.2 框架的作用

在这里插入图片描述

1.3 Spring是什么

Spring是分层的JavaSE/EE应用full-stack轻量级开源框架
在这里插入图片描述

1.4 Spring的体系结构

在这里插入图片描述

2、IOC容器

  • IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源
  • Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器

在这里插入图片描述

2.1 spring入门

2.1.1依赖

buildscript {
    repositories {
        mavenLocal()
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
        mavenCentral()
    }
}

allprojects {
    group = 'com.xingyu'
    version = '0.0.1-SNAPSHOT'

    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'java-library'

    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17

    repositories {
        mavenLocal()
        maven {url 'https://maven.aliyun.com/repository/public'}
        mavenCentral()
    }
    dependencies {
        // 提供注解处理器
        annotationProcessor 'org.projectlombok:lombok:1.18.24'
        implementation 'org.projectlombok:lombok:1.18.24'
        testAnnotationProcessor 'org.projectlombok:lombok:1.18.24'
        testImplementation 'org.projectlombok:lombok:1.18.24'
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0'
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
        implementation 'org.springframework:spring-context:6.0.3'
        implementation 'org.springframework:spring-jdbc:6.0.3'
        runtimeOnly 'mysql:mysql-connector-java:8.0.31'
        implementation 'org.mybatis:mybatis:3.5.11'
        implementation 'com.alibaba:druid:1.2.15'
    }
    test {
        useJUnitPlatform()
    }
}

2.1.2 spring.xml及java代码

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/beans/spring-context.xsd">
    <bean id="dataSource" class="com.xingyu.pojo.JdbcConfig">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/db1"/>
        <property name="userName" value="root"/>
        <property name="passWord" value="root"/>
    </bean>

    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">

    </bean>
</beans>
@Data
public class JdbcConfig {
    private String driverClassName;
    private String url;
    private String userName;
    private String passWord;
}

public interface UserDao {
}

public class UserDaoImpl implements UserDao {
}


public interface UserService {
}

public class UserServiceImpl implements UserService {

    public void setUserDao(UserDao userDao) {
        System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
    }
}

2.1.3 BeanFactory入门

public class Application {

    public static void main(String[] args) {
         // 创建工厂对象
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 创建一个读取器
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // 读取器绑定工厂
        reader.loadBeanDefinitions("spring.xml");
        // 根据id获取实例对象
        JdbcConfig dataSource = (JdbcConfig) beanFactory.getBean("dataSource");
        System.out.println(dataSource);

        UserService userService = (UserService) beanFactory.getBean("userService");
        System.out.println(userService);

        UserDao userDao = (UserDao) beanFactory.getBean("userDao");
        System.out.println(userDao);
    }

}

2.1.4 ApplicationContext入门

public class Application {

    public static void main(String[] args) {
        // 创建工厂对象
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        // 根据id获取实例对象
        JdbcConfig dataSource = (JdbcConfig) applicationContext.getBean("dataSource");
        System.out.println(dataSource);

        UserService userService = (UserService) applicationContext.getBean("userService");
        System.out.println(userService);

        UserDao userDao = (UserDao) applicationContext.getBean("userDao");
        System.out.println(userDao);
    }

}

2.1.5 ApplicationContext和BeanFactory的关系

在这里插入图片描述

2.2 IOC的XML配置

  • bean

作用:定义spring中的资源,受此标签定义的资源将受到spring控制

  • bean属性scope

定义bean的作用范围
取值:

  • singleton:设定创建出的对象保存在spring容器中,是一个单例的对象
  • prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象
  • request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置
  • bean生命周期

定义bean对象在初始化或销毁时完成的工作
<bean init-method=“init” destroy-method="destroy>

  • bean对象创建方式
  • factory-bean
    定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作
  • factory-bean,factory-method
    定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作

2.2.1 Springbean的配置

在这里插入图片描述

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/beans/spring-context.xsd">
    <bean id="dataSource" class="com.xingyu.pojo.JdbcConfig">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/db1"/>
        <property name="userName" value="root"/>
        <property name="passWord" value="root"/>
    </bean>

    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>

    <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">

    </bean>
</beans>
2.2.1.1 beanName

不配置id的话,bean的名称默认为类的全限定名

2.2.1.2 别名 name属性
    <bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl">

    </bean>
2.2.1.3 作用域

在这里插入图片描述

 <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl" scope="singleton">
        <property name="userDao" ref="userDao"/>
    </bean>
2.2.1.4 延迟加载

在这里插入图片描述

    <bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl" lazy-init="true">

    </bean>
2.2.1.5 初始化
public class UserServiceImpl implements UserService {

    public void init(){
        System.out.println("初始化方法");
    }

    public void destroy(){
        System.out.println("销毁方法");
    }

    public void setUserDao(UserDao userDao) {
        System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
    }
}
    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl" init-method="init" destroy-method="destroy">
        <property name="userDao" ref="userDao"/>
    </bean>
2.2.1.6 InitializingBean

属性设置之后,beand的init方法之前

public class UserServiceImpl implements UserService, InitializingBean {

    public void init(){
        System.out.println("初始化方法");
    }

    public void destroy(){
        System.out.println("销毁方法");
    }

    public void setUserDao(UserDao userDao) {
        System.out.println("beanfactory去调用该方法获得userDao设置到此处:" + userDao);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }
}

2.2.2 Bean的实例化配置

a、构造方法实例化(无参、有参)
    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
        
    </bean>
     <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>

    <bean id="userDao" name="userDao2" class="com.xingyu.dao.impl.UserDaoImpl">

    </bean>
b、工厂方法实例化(静态工厂、实例工厂)
public class MyFactoryBean {
    public static UserDao userDao(){
        return new UserDaoImpl();
    }
}

    <bean id="userDao1" class="com.xingyu.pojo.MyFactoryBean" factory-method="userDao">

    </bean>
public class MyFactoryBean {
    public UserDao userDao(){
        return new UserDaoImpl();
    }
}

    <bean id="myFactoryBean" class="com.xingyu.pojo.MyFactoryBean">

    </bean>
    
    <bean id="userDao1" factory-bean="myFactoryBean" factory-method="userDao"/>
c、实现FactoryBean
public class MyFactoryBean implements FactoryBean<UserDao> {

    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        return UserDao.class;
    }
}


    <bean id="userDao1" class="com.xingyu.pojo.MyFactoryBean">

    </bean>

2.2.3 依赖注入

a、构造器注入
    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>
b、 set注入

在这里插入图片描述

     <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </list>
        </property>
    </bean>

    <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
        <property name="set">
            <set>
                <value>1</value>
                <value>2</value>
                <value>3</value>
            </set>
        </property>
    </bean>
    <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
        <property name="map">
            <map>
                <entry key="1" value="123"/>
                <entry key="2" value="345"/>
            </map>
        </property>
    </bean>
        <bean id="userDao" class="com.xingyu.dao.impl.UserDaoImpl">
        <property name="properties">
            <props>
               <prop key="1">123</prop>
               <prop key="2">345</prop>
            </props>
        </property>
    </bean>
c、自动装配

在这里插入图片描述

d、命名空间
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dataSource" class="com.xingyu.pojo.JdbcConfig" p:url="jdbc:mysql://localhost:3306/db1">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="userName" value="root"/>
        <property name="passWord" value="root"/>
    </bean>
</beans>

2.2.4 Bean实例化的基本流程

在这里插入图片描述

2.2.5 Spring的后处理器

在这里插入图片描述

  • BeanFactoryPostProcessor
public class MyFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyFactoryProcessor 执行了");
    }
}


<bean id="myFactoryProcessor" class="com.xingyu.processor.MyFactoryProcessor"></bean>
  • BeanPostProcessor
public class MyBeanProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization 执行了");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization 执行了");
        return bean;
    }
}

<bean id="myBeanProcessor" class="com.xingyu.processor.MyBeanProcessor"></bean>

2.2.6 Spring Bean的生命周期

在这里插入图片描述

a、bean的初始化
  • 属性注入
beanDefinition中封装有Bean实体的注入信息通过propertyValues进行存储

  • 循环依赖
    多个实体之间相互引用并形成闭环的情况叫做循环依赖

在这里插入图片描述

  • 三级缓存

解决循环依赖问题
在这里插入图片描述

2.3 注解开发

2.3.1 bean

@Component,@Repository,@Service,@Controller :创建bean

@Scope 作用域
 
@Lazy  懒加载

@Value 值注入

@Autowired 引用类型注入


@Configuration  // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import(JdbcConfig.class)  //导入配置类或者bean
public class MyConfig {
    @Bean
    public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
        dataSource.setUrl(jdbcConfig.getUrl());
        dataSource.setUsername(jdbcConfig.getUserName());
        dataSource.setPassword(jdbcConfig.getPassWord());
        return dataSource;
    }
}

2.3.2 属性注入

a. @Value
@PropertySource("classpath:application.properties") // 导入properties文件
@Data
public class JdbcConfig {
	
	// 值注入
    @Value("${jdbc.driverClassName}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.userName}")
    private String userName;
    @Value("${jdbc.passWord}")
    private String passWord;


	@Autowired // 引用类型注入
    private UserService userService;
}
b. @Autowired和@Resource

@Autowired // 根据类型注入,如果没有第二次根据name找,如果还没有则报错
@Resource // 不指定名称则根据type找,指定则根据name找,没找到就报错

c. 配置类替代spring.xml
@Configuration  // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import(JdbcConfig.class)  //导入配置类或者bean
public class MyConfig {
    @Bean
    public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
        dataSource.setUrl(jdbcConfig.getUrl());
        dataSource.setUsername(jdbcConfig.getUserName());
        dataSource.setPassword(jdbcConfig.getPassWord());
        return dataSource;
    }
}


        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);

2.3.3.4 Import,ImportSelector,ImportBeanDefinitionRegistrar整合第三方框架
@Configuration  // 声明为配置类,替代spring.xml
@ComponentScan("com.xingyu") // 扫包
@Import({JdbcConfig.class,JdbcConfigSelector.class,JdbcConfigBeanDefinitionRegistrar.class})  //导入配置类或者bean
public class MyConfig {
    @Bean
    public DruidDataSource dataSource(@Autowired JdbcConfig jdbcConfig){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(jdbcConfig.getDriverClassName());
        dataSource.setUrl(jdbcConfig.getUrl());
        dataSource.setUsername(jdbcConfig.getUserName());
        dataSource.setPassword(jdbcConfig.getPassWord());
        return dataSource;
    }
}
public class JdbcConfigSelector  implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{JdbcConfig.class.getName()};
    }
}
public class JdbcConfigBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClassName(JdbcConfig.class.getName());
        registry.registerBeanDefinition("jdbcConfig",beanDefinition);
        ImportBeanDefinitionRegistrar.super.registerBeanDefinitions(importingClassMetadata, registry);
    }
}

3、 AOP

3.1 简介

AOP,面向切面编程,是面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与方法、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。

3.1.1 相关概念

在这里插入图片描述

3.1.2 动态代理技术

@Service
public class UserServiceImpl implements UserService, InitializingBean {

    @Autowired
    private UserDao userDao;

    @PostConstruct
    public void init(){
        System.out.println("初始化方法");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("销毁方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }

    @Override
    public void show() {
        System.out.println("UserServiceImpl show");
    }
}

@Component
public class MyAdvice {

    public void before(){
        System.out.println("MyAdvice before");
    }

    public void after(){
        System.out.println("MyAdvice after");
    }
}


@Component
public class MyBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        String aPackage = bean.getClass().getPackage().getName();
        if(aPackage.equals("com.xingyu.service.impl")){
            Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);
                    myAdvice.before();
                    Object result = method.invoke(bean, args);
                    myAdvice.after();
                    return result;
                }
            });
            return beanProxy;
        }
        return bean;
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.applicationContext = context;
    }
}

3.1.3 cglb动态代理技术

3.2 xml开发

3.2.1 入门

  • 依赖
runtimeOnly 'org.aspectj:aspectjweaver:1.9.19'
  • 代码
public class MyAdvice {

    public void before(){
        System.out.println("MyAdvice before");
    }

    public void after(){
        System.out.println("MyAdvice after");
    }
}


  • 配置
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/beans/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标类-->
    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
    </bean>

    <!--配置切面类-->
    <bean id="myAdvice" class="com.xingyu.advices.MyAdvice"/>

    <!--aop配置-->
    <aop:config expose-proxy="true">
        <aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
        <aop:aspect id="myAdvice" ref="myAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

3.2.2 切点表达式

【权限修饰符】 返回值 包名.类型.方法名(参数)

<aop:config expose-proxy="true">
        <aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
        <aop:aspect id="myAdvice" ref="myAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

3.2.3 五种通知类型

在这里插入图片描述

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/beans/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--配置目标类-->
    <bean id="userService" class="com.xingyu.service.impl.UserServiceImpl">
    </bean>

    <!--配置切面类-->
    <bean id="myAdvice" class="com.xingyu.advices.MyAdvice"/>

    <!--aop配置-->
    <aop:config expose-proxy="true">
        <aop:pointcut id="pointcut" expression="execution(public * *.*(..))"/>
        <aop:aspect id="myAdvice" ref="myAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

3.3 注解开发

@EnableAspectJAutoProxy
@Component
public class MyAdvice {

    @Pointcut(value = "execution(public * com.xingyu.controller.*(..))")
    public void pointcut(){

    }

    @Before(value = "pointcut()")
    public void before(){
        System.out.println("MyAdvice before");
    }

    @After(value = "pointcut()")
    public void after(){
        System.out.println("MyAdvice after");
    }

    @Around(value = "pointcut()")
    public void around(){
        System.out.println("MyAdvice around");
    }

    @AfterReturning(value = "pointcut()")
    public void afterReturning(){
        System.out.println("MyAdvice afterReturning");
    }

    @AfterThrowing(value = "pointcut()")
    public void afterThrowing(){
        System.out.println("MyAdvice afterThrowing");
    }
}

3.4 AOP整合事务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值