详解Spring框架入门

目录

一、什么是Spring 

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。 
 ◆目的:解决企业应用开发的复杂性

 ◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

 ◆范围:任何Java应用

 

二、什么是IOC

控制反转(Inversion of Control,英文缩写为IoC)把创建对象的权利交给框架,是框架的重要特征,并非面向对象编程的专用术语。它包括依赖注入和依赖查找。传统的业务层,当需要资源时就在该业务层new资源,这样耦合性(程序之间相互依赖关联)较高。现在将new的部分交给spring,做到高内聚低耦合。简而言之:原先是每当调用dao层或service层方法时,由app来new,现在是将new的权利交给spring,要什么资源从spring中获取!

 

三、快速搭建框架环境

1.下载框架所需的依赖jar包

 spring官网为:http://spring.io/

下载jar包:   http://repo.springsource.org/libs-release-local/org/springframework/spring

2.导入基本jar包

其实基本核心jar有beans;context;core;expression包,其他是依赖log4j日志。当然spring的jar不止这些,后期慢慢加上。

3.配置log4j配置文件

日志文件定义在src目录下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

### direct log messages to stdout ###

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.Target=System.err

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

 

### direct messages to file mylog.log ###

log4j.appender.file=org.apache.log4j.FileAppender

log4j.appender.file.File=c\:mylog.log

log4j.appender.file.layout=org.apache.log4j.PatternLayout

log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

 

### set log levels - for more verbose logging change 'info' to 'debug' ###

 

log4j.rootLogger=info, stdout

4.测试日志文件是否部署成功

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo1;

 

import org.apache.log4j.Logger;

import org.junit.Test;

 

/**

 * 演示日志用法

 * @author Administrator

 *

 */

public class Demo1 {

 //创建日志类

 private Logger log=Logger.getLogger(Demo1.class);

 @Test

 public void run1(){

  //可以将log4j.rootLogger属性中的info改为off则不会再控制台显示

  log.info("执行了");

 }

}

5.定义一个接口和实现类

接口:

?

1

2

3

4

5

package com.clj.demo2;

 

public interface UserService {

 public void sayHello();

}

实现类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

package com.clj.demo2;

 

public class UserServiceImpl implements UserService{

 private String name;

  

 public String getName() {

  return name;

 }

 public void setName(String name) {

  this.name = name;

 }

 public void init(){

  System.out.println("初始化。。");

 }

 public void sayHello() {

  System.out.println("Hello Spring"+"\t"+name);

 }

 public void destory(){

  System.out.println("销毁。。");

 }

 

}

6.定义spring专属的配置文件

定义名为applicationContext.xml,位置为src下,与日志文件同目录,导入相对应的约束,并将实现类注入到配置文件中,刚开始入门,使用bean约束

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<?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:p="http://www.springframework.org/schema/p"

 xsi:schemaLocation="

  http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd">

  <!-- 使用bean标签

   1.id值唯一(必写)

  2.注意:class为实现类路径,不是接口(必写)

  3.init-method核心方法执行之前初始化工作(选写)

  4.destroy-method核心方法执行之后初始化工作(选写)-->

  <bean id="userService" class="com.clj.demo2.UserServiceImpl" init-method="init" destroy-method="destory">

   <property name="name" value="佳先森"></property>

  </bean>

</beans>

7.测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

public class Demo1 {

 /**

  * 原始方式

  */

 @Test

 public void run(){

  //创建实现类

  UserServiceImpl s=new UserServiceImpl();

  s.setName("佳先森");

  s.sayHello();

 }

 /**

  * 老的工厂版本BeanFactory

  * 旧的工厂不会创建配置文件对象

  */

 @Test

 public void run2(){

  BeanFactory factory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));

  UserService us=(UserService)factory.getBean("userService");

  us.sayHello();

 }

 /**

  * 使用spring框架IOC方式

  * 新版本factory创建启动服务器会创建配置文件对象,再次调用时无需加载工厂

  */

 @Test

 public void run3(){

  //创建工厂,加载核心配置文件(ClassPathXmlApplicationContext从src下找)

  ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

  //从工厂中获取到对象(配置文件中的id值,这里用了多态)

  UserService usi=(UserService) ac.getBean("userService");

  //调用对象的方法执行

  usi.sayHello();

 }

 /**

  * 演示destroy-method方法

  * bean摧毁方法不会自动执行

  * 除非scope= singleton或者web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContext的close()方法)

  */

 @Test

 public void run4(){

  //创建工厂,加载核心配置文件(ClassPathXmlApplicationContext从src下找)

  ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

  //从工厂中获取到对象(配置文件中的id值,这里用了多态)

  UserService usi=(UserService) ac.getBean("userService");

  //调用对象的方法执行

  usi.sayHello();

  //ApplicationContext实现类提供close方法,将工厂关闭就可执行destory-method方法

  ac.close();

 }

}

其中旧工厂与新工厂的区别

* BeanFactory和ApplicationContext的区别

* BeanFactory               -- BeanFactory采取延迟加载,第一次getBean时才会初始化Bean

* ApplicationContext      -- 在加载applicationContext.xml时候就会创建具体的Bean对象的实例,还提供了一些其他的功能

 * 事件传递

 * Bean自动装配

* 各种不同应用层的Context实现

总结:这是个最基本的demo,是将实现类配置到了spring配置文件中,每次启动服务器时,就会加载配置文件,从而实例化了实现类

 

四、spring之依赖注入

1、什么是依赖注入?

Spring 能有效地组织J2EE应用各层的对象。不管是控制层的Action对象,还是业务层的Service对象,还是持久层的DAO对象,都可在Spring的 管理下有机地协调、运行。Spring将各层的对象以松耦合的方式组织在一起,Action对象无须关心Service对象的具体实现,Service对 象无须关心持久层对象的具体实现,各层对象的调用完全面向接口。当系统需要重构时,代码的改写量将大大减少。依赖注入让bean与bean之间以配置文件组织在一起,而不是以硬编码的方式耦合在一起。理解依赖注入

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。

不管是依赖注入,还是控制反转,都说明Spring采用动态、灵活的方式来管理各种对象。对象与对象之间的具体实现互相透明。  

2. IOC和DI的概念

* IOC -- Inverse of Control,控制反转,将对象的创建权反转给Spring!!

* DI -- Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!

3.演示

对于类成员变量,常用的注入方式有两种

属性set方法注入和构造方法注入

先演示第一种:属性set方法注入

1)持久层

?

1

2

3

4

5

6

7

package com.clj.demo3;

 

public class CustomerDaoImpl {

  public void save(){

    System.out.println("我是持久层的Dao");

  }

}

2)业务层

注意:此时是想将持久层注入到业务层,将创建持久层实例权利交给框架,条件是业务层必须提供持久层的成员属性和set方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

package com.clj.demo3;

/**

 * 依赖注入之将dao 层注入到service层

 * @author Administrator

 *

 */

public class CustomerServiceImpl{

  //提供成员属相,提供set方法

  private CustomerDaoImpl customerDao;

   

  public void setCustomerDao(CustomerDaoImpl customerDao) {

    this.customerDao = customerDao;

  }

 

  public void save(){

    System.out.println("我是业务层的service...");

    //1.原始方式

    //new CustomerDaoImpl().save();

     

    //2.spring 之IOC方式

    customerDao.save();

  }

}

 3)配置文件配置

?

1

2

3

4

5

6

<!-- 演示依赖注入 -->

   <bean id="customerDao" class="com.clj.demo3.CustomerDaoImpl"/>

   <bean id="customerService" class="com.clj.demo3.CustomerServiceImpl">

       <!-- 将Dao注入到service层 -->

      <property name="customerDao" ref="customerDao"></property>

   </bean>

4)测试

?

1

2

3

4

5

6

7

8

9

10

11

/**

   * spring 依赖注入方式

   * 将dao层注入到service层

   */

  @Test

  public void run2(){

    //创建工厂,加载配置文件,customerService被创建,从而也创建了customerDao

    ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");

    CustomerServiceImpl csi=(CustomerServiceImpl) context.getBean("customerService");

    csi.save();

  }

第二种:构造方法注入

1)pojo类并提供构造方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.clj.demo4;

/**

 * 演示的构造方法的注入方式

 * @author Administrator

 *

 */

public class Car1 {

  private String cname;

  private Double price;

  public Car1(String cname, Double price) {

    super();

    this.cname = cname;

    this.price = price;

  }

  @Override

  public String toString() {

    return "Car1 [cname=" + cname + ", price=" + price + "]";

  }

   

}

2)配置文件配置

?

1

2

3

4

5

6

7

8

<!-- 演示构造方法注入方式 -->

  <bean id="car1" class="com.clj.demo4.Car1">

    <!-- 写法一<constructor-arg name="cname" value="宝马"/>

    <constructor-arg name="price" value="400000"/> -->

    <!--写法二 -->

    <constructor-arg index="0" value="宝马"/>

    <constructor-arg index="1" value="400000"/>

   </bean>

3)测试

?

1

2

3

4

5

6

@Test

  public void run1(){

    ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

    Car1 car=(Car1) ac.getBean("car1");

    System.out.println(car);

  }

拓展:构造方法之将一个对象注入到另一个对象中

1)pojo类:目的:将上列中的车注入到人类,使之成为其中一个属性,则必须在此类中提供车的成员属性,并提供有参构造方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

package com.clj.demo4;

 

public class Person {

  private String name;

  private Car1 car1;

  public Person(String name, Car1 car1) {

    super();

    this.name = name;

    this.car1 = car1;

  }

  @Override

  public String toString() {

    return "Person [name=" + name + ", car1=" + car1 + "]";

  }

}

2)配置文件

?

1

2

3

4

5

<!-- 构造方法之将一个对象注入到另一个对象-->

  <bean id="person" class="com.clj.demo4.Person">

    <constructor-arg name="name" value="佳先森"/>

    <constructor-arg name="car1" ref="car1"/>

  </bean>

4.如何注入集合数组

1)定义pojo类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

package com.clj.demo4;

 

import java.util.Arrays;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

 

/**

 * 演示集合注入的方式

 * @author Administrator

 *

 */

public class User {

  private String[] arrs;

  private List<String> list;

  private Set<String> sets;

  private Map<String,String> map;

  private Properties pro;

   

  public void setPro(Properties pro) {

    this.pro = pro;

  }

 

  public void setSets(Set<String> sets) {

    this.sets = sets;

  }

 

  public void setMap(Map<String, String> map) {

    this.map = map;

  }

 

  public void setList(List<String> list) {

    this.list = list;

  }

 

  public void setArrs(String[] arrs) {

    this.arrs = arrs;

  }

 

  @Override

  public String toString() {

    return "User [arrs=" + Arrays.toString(arrs) + ", list=" + list

        + ", sets=" + sets + ", map=" + map + ", pro=" + pro + "]";

  }

}

2)配置文件

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

<!-- 注入集合 -->

  <bean id="user" class="com.clj.demo4.User">

    <!-- 数组 -->

    <property name="arrs">

      <list>

        <value>数字1</value>

        <value>数字2</value>

        <value>数字3</value>

      </list>

    </property>

    <!-- list集合 -->

    <property name="list">

      <list>

        <value>金在中</value>

        <value>王杰</value>

      </list>

    </property>

    <!-- set集合 -->

    <property name="sets">

      <set>

        <value>哈哈</value>

        <value>呵呵</value>

      </set>

    </property>

    <!-- map集合 -->

    <property name="map">

      <map>

        <entry key="aa" value="rainbow"/>

        <entry key="bb" value="hellowvenus"/>

      </map>

    </property>

    <!-- 属性文件 -->

    <property name="pro">

      <props>

        <prop key="username">root</prop>

        <prop key="password">123</prop>

      </props>

    </property>

  </bean>

3)测试

?

1

2

3

4

5

6

7

8

9

/**

  * 测试注入集合

  */

 @Test

 public void run3(){

   ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

   User user= (User) ac.getBean("user");

   System.out.println(user);

 }

5.怎么分模块开发

在主配置文件加入<import>标签(假如此时在com.clj.test包下定义了一个配置文件applicationContext2.xml)

?

1

2

<!-- 分模块开发之引入其他配置文件 -->

   <import resource="com/clj/test/applicationContext2.xml"/>

 

五、详解Spring框架的IOC之注解方式

1、入门

1).导入jar包

除了先前6个包,玩注解还需一个spring-aop包

  

2).持久层和实现层(这里忽略接口)

持久层

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo1;

 

import org.springframework.context.annotation.Scope;

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Repository;

/**

 * UserDaoImpl交给IOC的容器管理

 * @author Administrator

 *

 */

public class UserDaoImpl implements UserDao{

 

  @Override

  public void save() {

    System.out.println("保存客户。。");

     

  }

 

}

业务层

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

package com.clj.demo1;

 

import javax.annotation.PostConstruct;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;

 

public class UserServiceImpl implements UserService{

 

 

  @Override

  public void sayHello() {

    System.out.println("Hello spring");

  }

}

3).定义配置文件

此时约束条件需添加context约束,并添加组件扫描

?

1

2

3

4

5

6

7

8

9

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

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->

  <!-- 开启注解扫面 :base-package指定扫面对 包-->

  <context:component-scan base-package="com.clj.demo1"/>

</beans>

4)在实现类中添加注解

?

1

2

3

4

5

6

7

8

9

/**

 * 组件注解,可以用来标记当前的类

 * 类似<bean id="userService" class="com.clj.demo1.UserServiceImpl">

 * value表示给该类起个别名

 */

@Component(value="userService")

public class UserServiceImpl implements UserService{

      //省略

}

5)编写测试

?

1

2

3

4

5

6

7

8

9

/**

 * 注解方式

 */

@Test

public void run2(){

  ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");

  UserService us=(UserService) ac.getBean("userService");

  us.sayHello();

}

2.关于bean管理常用属性

1. @Component:组件.(作用在类上)  最原始的注解,所有需要注解的类都写这个没问题,他是通用的

2. Spring中提供@Component的三个衍生注解:(功能目前来讲是一致的)
    * @Controller       -- 作用在WEB层
    * @Service          -- 作用在业务层
    * @Repository       -- 作用在持久层
    * 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

3. 属性注入的注解(说明:使用注解注入的方式,可以不用提供set方法)
    * 如果是注入的普通类型,可以使用value注解
    * @Value             -- 用于注入普通类型
    * 如果注入的是对象类型,使用如下注解
        * @Autowired        -- 默认按类型进行自动装配   匹配的是类型,与注入类的类名无关
            * 如果想按名称注入
            * @Qualifier    -- 强制使用名称注入            必须与Autowired一起用,指定类名,与注入的类名有关
        * @Resource         -- 相当于@Autowired和@Qualifier一起使用
        * 强调:Java提供的注解
        * 属性使用name属性

4. Bean的作用范围注解

    * 注解为@Scope(value="prototype"),作用在类上。值如下:

        * singleton     -- 单例,默认值

        * prototype     -- 多例

5. Bean的生命周期的配置(了解)

    * 注解如下:

        * @PostConstruct    -- 相当于init-method

        * @PreDestroy       -- 相当于destroy-method

1.演示属性对象注解

条件:采用扫描的方式将属性(name)和对象(userDaoImpl)注入到业务层中

1)持久层开启注解扫描Repository

?

1

2

3

4

5

6

7

8

//@Component(value="userDao")通用类注解

@Repository(value="ud")

public class UserDaoImpl implements UserDao{

  @Override

  public void save() {

    System.out.println("保存客户。。"); 

  }

}

2)业务层针对属性和对象提供注解

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

package com.clj.demo1;

 

import javax.annotation.PostConstruct;

 

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Qualifier;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Component;

/**

 * 组件注解,可以用来标记当前的类

 * 类似<bean id="userService" class="com.clj.demo1.UserServiceImpl">

 * value表示给该类起个别名

 */

//@Scope(value="grototype")多列的(singletype为单列)

@Component(value="userService")

public class UserServiceImpl implements UserService{

  //属性注解:相当于给name属性注入指定的字符串,setName方法可以省略不写

  @Value(value="佳先森")

  private String name;

   

  /**

   * 引用注入方式一:Autowired()

   * 引用注入方式二:Autowired()+Qualifier

   * 引用注入方式三:@Resource(name="userDao") java方式,按名称识别注入

   */

  //Autowired()按类型自动装配注入(缺点:因为是按类型匹配,所以不是很准确)

  @Autowired()

  @Qualifier(value="ud") //按名称注入,得与Autowired一起用,两者一起能指定类

  private UserDao userDao;

  //注意Qualifier中的value是指定UserDaoImpl类名顶上的注解名,也可以指定配置文件中bean的id名

   

   

  /*public void setName(String name) {

    this.name = name;

  }*/

 

  @Override

  public void sayHello() {

    System.out.println("Hello spring"+name);

    userDao.save();

  }

  //@PostConstruct标签用于action生命周期中初始化的注解

  @PostConstruct

  public void init(){

    System.out.println("初始化...");

  }

}

3)配置文件只需要开启全部扫描即可

?

1

2

3

4

5

6

7

8

9

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

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->

  <!-- 开启注解扫面 :base-package指定扫面对 包-->

  <context:component-scan base-package="com.clj.demo1"/>

</beans>

注意:至于集合还是推荐使用配置文件方式

2.Spring框架整合JUnit单元测试

1)添加单元测试所需依赖包spring-test.jar

  

注意:基于myeclipes自带Junit环境,但是有时因为版本问题,可能需要比较新的Junit环境,这里我在网上下了一个教新的 Junit-4.9的jar包,如果myeclipes较新的话无须考虑

2)编写测试类,添加相对应的注解

@RunWith与@ContextConfiguration(此是用于加载配置文件,因为默认从WebRoot路径为一级目录,加上此是认定src为一级目录)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.clj.demo2;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

import com.clj.demo1.UserService;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo2 {

  @Resource(name="userService")

  private UserService userService;

  @Test

  public void run1(){

    userService.sayHello();

  }

}

六.spring框架之AOP

1.什么是AOP

        * 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,功能模块化

        * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构

        * AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范

        * 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术

        * AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型

        * 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

      AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)

2. 为什么要学习AOP

        * 可以在不修改源代码的前提下,对程序进行增强!!(为固定的方法生成一个代理,在访问该方法之前,先进入代理,在代理中,可以编写更多的功能,使之方法的功能更强,使得程序进行增        强)

Aop:面向切面编程,将一切事模块化,每个模块比较独立,模块可以共用(相同的),不同的格外自定义。用此替代传统的面向纵向编程,提高程序的可重用性

3.AOP的实现(实现原理)

Aop的实现包含两种代理方式<1>实现类接口:采用JDK动态代理<2>未实现类接口:采用CGLIB动态代理

   1.实现JDK动态代理

      1)定义持久层接口实现类

?

1

2

3

4

5

6

package com.clj.demo3;

 

public interface UserDao {

  public void save();

  public void update();

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

package com.clj.demo3;

 

public class UserDaoImpl implements UserDao {

 

  @Override

  public void save() {

    System.out.println("保存用户");

  }

  @Override

  public void update() {

    System.out.println("修改用户");

  }

}

   2)定义JDK动态代理工具类

此工具类是在执行持久层save方法时增加一些功能,在开发中做到在不更改源码情况下增强某方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

package com.clj.demo3;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

 

/**

 * 使用JDK的方式生成代理对象(演示AOP原理)

 * @author Administrator

 *

 */

public class MyProxyUtils {

  public static UserDao getProxy(final UserDao dao){

    //使用Proxy类生成代理对象

    UserDao proxy=(UserDao)Proxy.newProxyInstance(dao.getClass().getClassLoader() , dao.getClass().getInterfaces(),new InvocationHandler() {

      //只要代理对象一执行,invoke方法就会执行一次

      public Object invoke(Object proxy, Method method, Object[] args)

          throws Throwable {

        //proxy代表当前代理对象

        //method当前对象执行的方法

        //args封装的参数

        //让到类的save或者update方法正常执行下去

        if("save".equals(method.getName())){

          System.out.println("执行了保存");

          //开启事务

        }

        return method.invoke(dao, args);

      }

    });

    return proxy;

  }

}

 3)测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.clj.demo3;

 

import org.junit.Test;

 

public class Demo1 {

  @Test

  public void run1(){

    //获取目标对象

    UserDao dao=new UserDaoImpl();

    dao.save();

    dao.update();

    System.out.println("===============");

    //使用工具类,获取到代理对象

    UserDao proxy=MyProxyUtils.getProxy(dao);

    //调用代理对象的方法

    proxy.save();

    proxy.update();

     

  }

}

 2.实现CGLIB技术

 1)定义持久层,此时没有接口

?

1

2

3

4

5

6

7

8

9

10

package com.clj.demo4;

 

public class BookDaoImpl {

  public void save(){

    System.out.println("保存图书");

  }

  public void update(){

    System.out.println("修改图书");

  }

}

  2)编写工具类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

package com.clj.demo4;

 

import java.lang.reflect.Method;

 

import org.springframework.cglib.proxy.Enhancer;

import org.springframework.cglib.proxy.MethodInterceptor;

import org.springframework.cglib.proxy.MethodProxy;

/**

 * Cglib代理方式实现原理

 * @author Administrator

 *

 */

public class MyCglibUtils {

  /**

   * 使用CGLIB方式生成代理对象

   * @return

   */

  public static BookDaoImpl getProxy(){

    Enhancer enhancer=new Enhancer();

    //设置父类

    enhancer.setSuperclass(BookDaoImpl.class);

    //设置回调函数

    enhancer.setCallback(new MethodInterceptor() {

       

      @Override

      public Object intercept(Object obj, Method method, Object[] objs,

          MethodProxy methodProxy) throws Throwable {

        if(method.getName().equals("save")){

        System.out.println("我保存了");

        System.out.println("代理对象执行了");

    }

        return methodProxy.invokeSuper(obj, objs);//是方法执行下去

      }

    });

    //生成代理对象

    BookDaoImpl proxy=(BookDaoImpl) enhancer.create();

    return proxy;

  }

}

  3)编写测试类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

package com.clj.demo4;

import org.junit.Test;

public class Demo1 {

  @Test

  public void run1(){

    //目标对象

    BookDaoImpl dao=new BookDaoImpl();

    dao.save();

    dao.update();

    System.out.println("==========");

    BookDaoImpl proxy=MyCglibUtils.getProxy();

    proxy.save();

    proxy.update();

  }

}

 3、Spring基于AspectJ的AOP的开发(配置文件方式)

  

  1)部署环境,导入相对应的jar包

  

 2)创建配置文件,并引入AOP约束

?

1

2

3

4

5

6

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:aop="http://www.springframework.org/schema/aop"

      xsi:schemaLocation="

      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

 3)创建接口和实现类

?

1

2

3

4

5

6

package com.clj.demo5;

 

public interface CustomerDao {

  public void save();

  public void update();

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

package com.clj.demo5;

/**

 * 采用配置文件的方式 诠释AOP

 * @author Administrator

 *

 */

public class CustomerDaoImpl implements CustomerDao {

 

  @Override

  public void save() {

    //模拟异常

    //int a=10/0;

    System.out.println("保存客户了啊");

  }

 

  @Override

  public void update() {

    // TODO Auto-generated method stub

    System.out.println("更新客户了啊");

  }

 

}

 4)定义切面类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

package com.clj.demo5;

 

import org.aspectj.lang.ProceedingJoinPoint;

 

/**

 * 切面类:切入点+通知

 * @author Administrator

 *

 */

public class MyAspectXml {

  /**

   * 通知(具体的增强)

   */

  public void log(){

    System.out.println("记录日志");

  }

  /**

   * 方法执行成功或者异常都会执行

   */

  public void after(){

    System.out.println("最终通知");

  }

  /**

   * 方法执行之后,执行后置通知,如果程序出现异常,后置通知不会执行

   */

  public void afterReturn(){

    System.out.println("后置通知");

  }

  /**

   * 方法执行之后,如果程序有异常,才会执行异常通知

   */

  public void afterThrowing(){

    System.out.println("异常通知");

  }

  /**

   * 环绕通知:方法执行之前和方法执行之后进行通知,

   * 默认情况下,目标对象的方法不能执行的,需要手动让目标对象执行

   */

  public void around(ProceedingJoinPoint joinPoint){

    System.out.println("环绕通知1");

    //手动让目标对象的方法执行

    try {

      joinPoint.proceed();

    } catch (Throwable e) {

      // TODO Auto-generated catch block

      e.printStackTrace();

    }

    System.out.println("环绕通知2");

  }

}

 5)注入实现类和切面类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="

    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

  <!-- 配置客户的dao -->

  <bean id="customerDao" class="com.clj.demo5.CustomerDaoImpl"/>

  <!-- 编写切面类配置好 -->

  <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>

  <!-- 配置AOP -->

  <aop:config>

    <!-- 配置切面类:切入点+通知 (类型)-->

    <aop:aspect ref="myAspectXml">

      <!-- 配置前置通知,save方法执行之前,增强方法会执行 -->

      <!-- 切入点表达式:execution(public void com.clj.demo5.CustomerDaoImpl.save()) -->

      <!-- 切入点表达式:

        1.execution()固定的,必写

        2.public可以省略不写

        3.返回值   必写,严格根据切入点方法而定,否则增强方法不会执行,可以用*代替,表示任意的返回值

        4.包名   必写,可以用*代替(如:*..*(默认所有包); com.clj.*)

        5.类名   必写,可以部分用*(如*DaoImpl表示以'DaoImpl'结尾的持久层实现类),但不建议用*代替整个类名

        6.方法   必写,可以部分用*(如save*表示以'save'开头的方法),但不建议用*代替整个类名

        7.方法参数 根据实际方法而定,可以用'..'表示有0或者多个参数

       -->

      <!-- <aop:before method="log" pointcut="execution(public void com.clj.*.CustomerDaoImpl.save(..))"/> -->

      <aop:before method="log" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>

    </aop:aspect>

  </aop:config>

</beans>

 6)测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo5;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo1 {

  @Resource(name="customerDao")

  private CustomerDao customerDao;

  @Test

  public void run(){

    customerDao.save();

    customerDao.update();

  }

}

扩展:切面类升级

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="

    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

  <bean id="myAspectXml" class="com.clj.demo5.MyAspectXml"/>

  <aop:config>

    <aop:aspect ref="myAspectXml">

      <!-- 配置最终通知

      <aop:after method="after" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->

      <!-- 配置后置通知

      <aop:after-returning method="afterReturn" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->

      <!-- 配置异常通知

      <aop:after-throwing method="afterThrowing" pointcut="execution(* *..*.*DaoImpl.save*(..))"/>-->

      <aop:around method="around" pointcut="execution(* *..*.*DaoImpl.update*(..))"/>

    </aop:aspect>

  </aop:config>

</beans>

4、Spring框架AOP之注解方式

 1)创建接口和实现类

?

1

2

3

4

5

6

package com.clj.demo1;

 

public interface CustomerDao {

  public void save();

  public void update();

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

package com.clj.demo1;

 

public class CustomerDaoImpl implements CustomerDao{

 

  @Override

  public void save() {

    // TODO Auto-generated method stub

    System.out.println("保存客户..");

  }

 

  @Override

  public void update() {

    // TODO Auto-generated method stub

    System.out.println("更新客户");

  }

 

}

2)定义切面类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

package com.clj.demo1;

 

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

 

/**

 * 注解方式的切面类

 * @Aspect表示定义为切面类

 */

@Aspect

public class MyAspectAnno {

  //通知类型:@Before前置通知(切入点的表达式)

  @Before(value="execution(public *   com.clj.demo1.CustomerDaoImpl.save())")

  public void log(){

    System.out.println("记录日志。。");

  }

  //引入切入点

  @After(value="MyAspectAnno.fun()")

  public void after(){

    System.out.println("执行之后");

  }

  @Around(value="MyAspectAnno.fun()")

  public void around(ProceedingJoinPoint joinPoint){

    System.out.println("环绕通知1");

    try {

      //让目标对象执行

      joinPoint.proceed();

    } catch (Throwable e) {

      // TODO Auto-generated catch block

      e.printStackTrace();

    }

    System.out.println("环绕通知2");

  }

  //自定义切入点

  @Pointcut(value="execution(public *   com.clj.demo1.CustomerDaoImpl.save())")

  public void fun(){

     

  }

}

3)配置切面类和实现类,并开启自动代理

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 开启自动注解代理-->

  <aop:aspectj-autoproxy/>

  <!-- 配置目标对象 -->

  <bean id="customerDao" class="com.clj.demo1.CustomerDaoImpl"/>

  <!-- 配置切面类 -->

  <bean id="myAspectAnno" class="com.clj.demo1.MyAspectAnno"/>

</beans>

 

七、Spring之JDBC

spring提供了JDBC模板:JdbcTemplate类

1.快速搭建

 1)部署环境

这里在原有的jar包基础上,还要添加关乎jdbc的jar包,这里使用的是mysql驱动

  

 2)配置内置连接池,将连接数据库程序交给框架管理,并配置Jdbc模板类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 先配置连接池(内置) -->

  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

    <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="username" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置JDBC的模板类-->

  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

    <property name="dataSource" ref="dataSource"/>

  </bean>

</beans>

 3)测试

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

package com.clj.demo2;

 

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.List;

 

import javax.annotation.Resource;

 

import org.apache.commons.dbcp.BasicDataSource;

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.cglib.beans.BeanMap;

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.RowMapper;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

 

/**

 * 测试JDBC的模板类,使用IOC的方式

 * @author Administrator

 *

 */

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo2 {

  @Resource(name="jdbcTemplate")

  private JdbcTemplate jdbcTemplate;

  /**

   * 插入

   */

  @Test

  public void run1(){

    String sql="insert into t_account values(null,?,?)";

    jdbcTemplate.update(sql,"李钇林",10000);

  }

  /**

   * 更新

   */

  @Test

  public void run2(){

    String sql="update t_account set name=? where id=?";

    jdbcTemplate.update(sql,"李钇林",1);

  }

  /**

   * 删除

   */

  @Test

  public void run3(){

    String sql="delete from t_account where id=?";

    jdbcTemplate.update(sql,4);

  }

  /**

   * 测试查询,通过主键来查询一条记录

   */

  @Test

  public void run4(){

    String sql="select * from t_account where id=?";

    Account ac=jdbcTemplate.queryForObject(sql, new BeanMapper(),1);

    System.out.println(ac);

  }

  /**

   * 查询所有

   */

  @Test

  public void run5(){

    String sql="select * from t_account";

    List<Account> ac=jdbcTemplate.query(sql,new BeanMapper());

    System.out.println(ac);

  }

}

/**

 * 定义内部类(手动封装数据(一行一行封装数据,用于查询所有)

 * @author Administrator

 *

 */

class BeanMapper implements RowMapper<Account>{

 

  @Override

  public Account mapRow(ResultSet rs, int rowNum) throws SQLException {

    Account ac=new Account();

    ac.setId(rs.getInt("id"));

    ac.setName(rs.getString("name"));

    ac.setMoney(rs.getDouble("money"));

    return ac;

  }

   

}

2、配置开源连接池

一般现在企业都是用一些主流的连接池,如c3p0和dbcp

首先配置dbcp

1)导入dbcp依赖jar包

  

2)编写配置文件

?

1

2

3

4

5

6

7

<!-- 配置DBCP开源连接池-->

  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>

    <property name="url" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="username" value="root"/>

    <property name="password" value="root"/>

  </bean>

将模板类中引入的内置类datasource改为开源连接池的

3)编写测试类

配置c3p0

 1)导入c3p0依赖jar包

  

2)配置c3p0

?

1

2

3

4

5

6

7

<!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

将模板类中引入的内置类datasource改为开源连接池的

3)编写测试类

 

八、Spring之事务

1、什么是事务

数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

2、怎么解决事务安全性问题

读问题解决,设置数据库隔离级别;写问题解决可以使用 悲观锁和乐观锁的方式解决

3、快速开发

方式一:调用模板类,将模板注入持久层

1)编写相对应的持久层和也外层,这里省略接口   

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

package com.clj.demo3;

 

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

 

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

  // 方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类

   private JdbcTemplate jdbcTemplate;

   public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

     this.jdbcTemplate = jdbcTemplate;

   }

 

   

  public void outMoney(String out, double money) {

    String sql="update t_account set money=money-? where name=?";

    jdbcTemplate().update(sql,money,out);

  }

 

   

  public void inMoney(String in, double money) {

    String sql="update t_account set money=money+? where name=?";

    jdbcTemplate().update(sql,money,in);

  }

   

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

package com.clj.demo4;

 

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

 

public class AccountServiceImpl implements AccountService{

  //采用的是配置文件注入方式,必须提供set方法

  private AccountDao accountDao;

  public void setAccountDao(AccountDao accountDao) {

    this.accountDao = accountDao;

  }

  @Override

  public void pay(String out, String in, double money) {

    // TODO Auto-generated method stub

    accountDao.outMoney(out, money);

    int a=10/0;

    accountDao.inMoney(in, money);

  }

}

2)配置相对应的配置文件

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

<!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

<!-- 配置JDBC的模板类 -->

  <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">

    <property name="dataSource" ref="dataSource"/>

  </bean>

<!-- 配置业务层和持久层 -->

  <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

  </bean>

<bean id="accountDao" class="com.clj.demo3.AccountDaoImpl">

    <!-- 注入模板类-->

    <property name="jdbcTemplate" ref="jdbcTemplate"/>  

    <property name="dataSource" ref="dataSource"/>

  </bean>

</beans>

3)测试类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo3;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class Demo1 {

  @Resource(name="accountService")

  private AccountService accountService;

  @Test

  public void Demo1(){

    //调用支付的方法

    accountService.pay("佳先森","李钇林",100);

  }

}

方式二:持久层继承JdbcDaoSupport接口,此接口封装了模板类jdbcTemplate

1)编写配置文件

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置业务层和持久层 -->

  <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

  </bean>

  <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl"

    <property name="dataSource" ref="dataSource"/>

  </bean>

</beans>

2)更改持久层

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.clj.demo3;

 

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

 

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

  //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类

//  private JdbcTemplate jdbcTemplate;

//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

//    this.jdbcTemplate = jdbcTemplate;

//  }

 

  //方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类

  public void outMoney(String out, double money) {

    //jdbcTemplate.update(psc);

    String sql="update t_account set money=money-? where name=?";

    this.getJdbcTemplate().update(sql,money,out);

  }

 

   

  public void inMoney(String in, double money) {

    String sql="update t_account set money=money+? where name=?";

    this.getJdbcTemplate().update(sql,money,in);

  }

   

}

3)更改业务层

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

package com.clj.demo4;

 

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

 

public class AccountServiceImpl implements AccountService{

  //采用的是配置文件注入方式,必须提供set方法

  private AccountDao accountDao;

  public void setAccountDao(AccountDao accountDao) {

    this.accountDao = accountDao;

  }

  @Override

  public void pay(String out, String in, double money) {

    // TODO Auto-generated method stub

    accountDao.outMoney(out, money);

    int a=10/0;

    accountDao.inMoney(in, money);

  }

   

 

}

4)测试类和上述一样

4、spring事务管理

Spring为了简化事务管理的代码:提供了模板类 TransactionTemplate,手动编程的方式来管理事务,只需要使用该模板类即可!!

 

九、Spring框架的事务管理之编程式的事务管理

1、手动编程方式事务(了解原理)

1)快速部署,搭建配置文件,配置事务管理和事务管理模板,并在持久层注入事务管理模板

配置事务管理器

?

1

2

3

4

<!-- 配置平台事务管理器 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

  <property name="dataSource" ref="dataSource"/>

</bean>

配置事务管理模板

?

1

2

3

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

    <property name="transactionManager" ref="transactionManager"/>

</bean>

将管理模板注入业务层

?

1

2

3

4

<bean id="accountService" class="com.clj.demo3.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

    <property name="transactionTemplate" ref="transactionTemplate"/>

</bean>

全部代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

   

  <!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置业务层和持久层 -->

  <bean id="accountService" class="com.clj.demo3.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

    <property name="transactionTemplate" ref="transactionTemplate"/>

  </bean>

  <bean id="accountDao" class="com.clj.demo3.AccountDaoImpl"

    <property name="dataSource" ref="dataSource"/>

  </bean>

  <!-- 配置平台事务管理器 -->

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

  </bean>

  <!-- 手动编码方式,提供了模板类,使用该类管理事务比较简单-->

  <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

    <property name="transactionManager" ref="transactionManager"/>

  </bean>

</beans>

2)在业务层使用模板事务管理

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

package com.clj.demo3;

 

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

 

public class AccountServiceImpl implements AccountService{

  //采用的是配置文件注入方式,必须提供set方法

  private AccountDao accountDao;

  //注入事务模板类

  private TransactionTemplate transactionTemplate;

  public void setAccountDao(AccountDao accountDao) {

    this.accountDao = accountDao;

  }

 

  public void setTransactionTemplate(TransactionTemplate transactionTemplate) {

    this.transactionTemplate = transactionTemplate;

  }

 

  /**

   * 转账的方法

   */

  public void pay(final String out,final String in, final double money) {

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {

      //事务的执行,如果没有问题,提交,如果楚翔异常,回滚

      protected void doInTransactionWithoutResult(TransactionStatus arg0) {

        // TODO Auto-generated method stub

        accountDao.outMoney(out, money);

        int a=10/0;

        accountDao.inMoney(in, money);

      }

    });

  }

 

}

3)测试类和上一致

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo4;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext2.xml")

public class Demo2 {

  @Resource(name="accountService")

  private AccountService accountService;

  @Test

  public void Demo1(){

    //调用支付的方法

    accountService.pay("佳先森","李钇林",100);

  }

}

 

十、Spring框架的事务管理之声明式事务管理,即通过配置文件来完成事务管理(AOP思想)

申明式事务有两种方式:基于AspectJ的XML方式;基于AspectJ的注解方式

1、XML方式

1)配置配置文件

需要配置平台事务管理

?

1

2

3

4

5

6

7

8

9

10

11

<!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置平台事务管理器 -->

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

  </bean>

配置事务增强

?

1

2

3

4

5

6

7

<tx:advice id="myAdvice" transaction-manager="transactionManager">

    <tx:attributes>

      <!-- 给方法设置数据库属性(隔离级别,传播行为) -->

      <!--propagation事务隔离级别:一般采用默认形式:tx:method可以设置多个 -->

      <tx:method name="pay" propagation="REQUIRED"/>

    </tx:attributes>

  </tx:advice>

aop切面类

?

1

2

3

4

<aop:config>

    <!-- aop:advisor,是spring框架提供的通知-->

    <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>

  </aop:config>

全部代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置平台事务管理器 -->

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

  </bean>

  <!-- 申明式事务(采用XML文件的方式) -->

  <!-- 先配置通知 -->

  <tx:advice id="myAdvice" transaction-manager="transactionManager">

    <tx:attributes>

      <!-- 给方法设置数据库属性(隔离级别,传播行为) -->

      <!--propagation事务隔离级别:一般采用默认形式:tx:method可以设置多个 -->

      <tx:method name="pay" propagation="REQUIRED"/>

    </tx:attributes>

  </tx:advice>

  <!-- 配置AOP:如果是自己编写的AOP,使用aop:aspect配置,使用的是Spring框架提供的通知 -->

  <aop:config>

    <!-- aop:advisor,是spring框架提供的通知-->

    <aop:advisor advice-ref="myAdvice" pointcut="execution(public * com.clj.demo4.AccountServiceImpl.pay(..))"/>

  </aop:config>

   

  <!-- 配置业务层和持久层 -->

  <bean id="accountService" class="com.clj.demo4.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

  </bean>

  <bean id="accountDao" class="com.clj.demo4.AccountDaoImpl">

    <property name="dataSource" ref="dataSource"/>

  </bean>

</beans>

2)编写持久层和业务层(省略接口)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.clj.demo5;

 

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

 

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

  //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类

//  private JdbcTemplate jdbcTemplate;

//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

//    this.jdbcTemplate = jdbcTemplate;

//  }

 

  //方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类

  public void outMoney(String out, double money) {

    //jdbcTemplate.update(psc);

    String sql="update t_account set money=money-? where name=?";

    this.getJdbcTemplate().update(sql,money,out);

  }

 

   

  public void inMoney(String in, double money) {

    String sql="update t_account set money=money+? where name=?";

    this.getJdbcTemplate().update(sql,money,in);

  }

   

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

package com.clj.demo5;

 

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.annotation.Transactional;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;public class AccountServiceImpl implements AccountService{

  //采用的是配置文件注入方式,必须提供set方法

  private AccountDao accountDao;

  public void setAccountDao(AccountDao accountDao) {

    this.accountDao = accountDao;

  }

  @Override

  public void pay(String out, String in, double money) {

    // TODO Auto-generated method stub

    accountDao.outMoney(out, money);

    int a=10/0;

    accountDao.inMoney(in, money);

  }

   

 

}

3)测试类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo4;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext2.xml")

public class Demo2 {

  @Resource(name="accountService")

  private AccountService accountService;

  @Test

  public void Demo1(){

    //调用支付的方法

    accountService.pay("佳先森","李钇林",100);

  }

}

2、注解方式

1)配置配置文件

配置事务管理

?

1

2

3

4

5

6

7

8

9

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

  </bean>

开启注释事务

?

1

2

<!-- 开启事务的注解 -->

<tx:annotation-driven transaction-manager="transactionManager"/>

全部代码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<?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"

  xmlns:tx="http://www.springframework.org/schema/tx"

  xsi:schemaLocation="http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans.xsd

  http://www.springframework.org/schema/context

  http://www.springframework.org/schema/context/spring-context.xsd

  http://www.springframework.org/schema/aop

  http://www.springframework.org/schema/aop/spring-aop.xsd

  http://www.springframework.org/schema/tx

  http://www.springframework.org/schema/tx/spring-tx.xsd">

  <!-- 配置C3P0开源连接池 -->

  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

    <property name="driverClass" value="com.mysql.jdbc.Driver"/>

    <property name="jdbcUrl" value="jdbc:mysql://192.168.174.130:3306/SSH"/>

    <property name="user" value="root"/>

    <property name="password" value="root"/>

  </bean>

  <!-- 配置平台事务管理器 -->

  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

    <property name="dataSource" ref="dataSource"/>

  </bean>

  <!-- 开启事务的注解 -->

  <tx:annotation-driven transaction-manager="transactionManager"/>

   

  <!-- 配置业务层和持久层 -->

  <bean id="accountService" class="com.clj.demo5.AccountServiceImpl">

    <property name="accountDao" ref="accountDao"/>

  </bean>

  <bean id="accountDao" class="com.clj.demo5.AccountDaoImpl">

    <property name="dataSource" ref="dataSource"/>

  </bean>

</beans>

2)业务层增加@Transactional

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

package com.clj.demo5;

 

import org.springframework.transaction.TransactionStatus;

import org.springframework.transaction.annotation.Transactional;

import org.springframework.transaction.support.TransactionCallbackWithoutResult;

import org.springframework.transaction.support.TransactionTemplate;

//在当前类加此注解表示当前类所有的全部都有事务

@Transactional

public class AccountServiceImpl implements AccountService{

  //采用的是配置文件注入方式,必须提供set方法

  private AccountDao accountDao;

  public void setAccountDao(AccountDao accountDao) {

    this.accountDao = accountDao;

  }

  @Override

  public void pay(String out, String in, double money) {

    // TODO Auto-generated method stub

    accountDao.outMoney(out, money);

    int a=10/0;

    accountDao.inMoney(in, money);

  }

   

 

}

3)持久层不变

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

package com.clj.demo5;

 

import org.springframework.jdbc.core.JdbcTemplate;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

 

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{

  //方式一:将jdbc模板类注入到配置文件中,直接在持久层写模板类

//  private JdbcTemplate jdbcTemplate;

//  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {

//    this.jdbcTemplate = jdbcTemplate;

//  }

 

  //方式二:持久层继承JdbcDaoSupport,它里面封转了模板类,配置文件持久层无需注入模板类,也不需要配置模板类

  public void outMoney(String out, double money) {

    //jdbcTemplate.update(psc);

    String sql="update t_account set money=money-? where name=?";

    this.getJdbcTemplate().update(sql,money,out);

  }

 

   

  public void inMoney(String in, double money) {

    String sql="update t_account set money=money+? where name=?";

    this.getJdbcTemplate().update(sql,money,in);

  }

   

}

4)测试类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

package com.clj.demo5;

 

import javax.annotation.Resource;

 

import org.junit.Test;

import org.junit.runner.RunWith;

import org.springframework.test.context.ContextConfiguration;

import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext3.xml")

public class Demo3 {

 @Resource(name="accountService")

 private AccountService accountService;

 @Test

 public void Demo1(){

  //调用支付的方法

  accountService.pay("佳先森","李钇林",100);

 }

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值