spring

spring 7大组成模块:

 1:spring core:提供了spring 的核心功能,BeanFactoryspring核心容器的主要组件,
    
它通过Ioc把程序的配置和依赖性与实际的代码分开,是整个spring的基础

 2:spring context:通过配置文件向spring提供上下文信息,
     
它构建在BeanFactory之上,另外增加了国际化和资源访问等功能

 3:spring dao:提供了一个简单有效的JDBC应用

 4:spring aop:提供了面向方面编程的功能
 
 5:spring orm
spring除了有自己的JDBC以外还提供了对其他ORM框架的支持,如Hibernate,都可以和spring进行良好的结合
 
 6:spring web
:提供了简化的处理多部分请求以及把请求参数绑定到域的任务。
 
 7:spring MVC
:提供了MVC2模式的实现,也可以和struts良好的集成在一起。

  这七大模块可以单独使用,不需要其他模块的支持
 
 --------------------------------------------------------
  spring
的特点:
 
  1
:设计良好的分层结构。
  2
:以IOC为核心,提倡面向接口编程。
  3
:良好的架构设计。
  4
:可以代替EJB
  5
:实现了MVC2
  6
:可以和其他框架良好的结合如:Hibernate ,struts
 
 
编写第一个HelloWorld程序:
  1
interface
   public interface IHelloWorld {
  public void sayHello();
 }
  2:
实现类:
  public class HelloWorld implements IHelloWorld{
  private String msg;
  public String getMsg() {
   return msg;
  }
  public void setMsg(String msg) {
   this.msg = msg;
  }
  public void sayHello(){
   System.out.println(msg);
  }
 }
  3
:编写spring配置文件:applicationContext.xml
   <beans>
  <bean  id="Hello" class="EnHelloWorld">
  <property name="msg">
  <value>Hello World!</value>
  </property>
  </bean>
    </beans>
   
  4:
编写测试类:
  public class TestHelloWorld {
   public static void main(String[] args) {
    ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
  IHelloWorld hw= (IHelloWorld)ac.getBean("Hello");
  hw.sayHello();
 }
}

---------------------------------------------------------------------
依赖注入的三种方式:
1
:接口注入
2
set注入
3
:构造注入
spring
支持set注入和构造注入
把上面的HelloWorld改为构造注入:
 1
:实现类:
  public class CHelloWorld implements IHelloWorld{
  public String msg;
  public CHelloWorld(String msg){
   this.msg = msg;
  }
  public void sayHello(){
   System.out.print(msg);
  }
 }
  2
:在spring配置文件:applicationContext.xml中:
   <bean  id="CHello" class="CHelloWorld">
  <constructor-arg index="0">
  <value>C Hello World!</value>
  </constructor-arg>
 </bean>
 constructor-arg
用来表示用构造方式注入参数
 index="0"
表示是构造方法中的第一个参数

  3:编写测试类:
  public class TestHelloWorld {
   public static void main(String[] args) {
    ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
  IHelloWorld hw= (IHelloWorld)ac.getBean("CHello");
  hw.sayHello();
 }
}

---------------------------------------------------------------------------
Spring
的核心容器:

spring中两个最基本最重要的包:
org.springframework.context
org.springframework.beansspringIOC提供了基础
在这两个最重要的类是BeanFactoryApplicationContextBeanFactory来管理各种beanApplicationContextBeanFactory之上
增加了其他功能如国际化,获取资源事件传递等。
1
bean的标志(id name)
  
每个bean都有一个id在管理beanBeanFactoryApplicationContext中必须是唯一标志。
   id
name都可以用来指定id这两者中至少有一个。区别是id的命名必须符合xml id中和合法字符。name则没有限制,而且可以使用name指定多个id

2bean的类

 class属性路径要完整,包名.类名

3:singleton的使用
  
spring bean可以定义为两种部署模式:singletonnon-singleton
 singleton
:只有一个共享的实例存在
 non-singleton
:每次请求都创建新的实例

4bean的属性: 
  
在定义bean的属性时除了直接指定bean的属性外还可以参考配置文件中定义的其他bean
    1:
 <bean  id="DateHello" class="DateHelloWorld">
 <property name="msg">
 <value>Hello World!</value>
 </property>
 <property name="date">
 <bean id="date" class="java.util.Date"/>
 </property>
 </bean>
    2:
 <bean  id="DateHello" class="DateHelloWorld">
 <property name="msg">
 <value>Hello World!</value>
 </property>
 <property name="date">
 <ref bean="date"/>
 </property>
 </bean>
   <bean id="date" class="java.util.Date"/>

5:null值的处理
   
把属性设为null值有两种方法:
 1
 
 <bean  id="DateHello" class="DateHelloWorld">
 <property name="msg">
 <value>null</value>
 </property>
 </bean>
 2:
 <bean  id="DateHello" class="DateHelloWorld">
 <property name="msg">
 <null/>
 </property>
 </bean>

6:使用depends-on

 beandepends-on可以用来在初始化这个bean前,强制执行一个或多个bean的初始化。
 
如:
 <bean  id="DateHello" class="DateHelloWorld" depends-on="date">

---------------------------------------------------------------------------------------

bean的生命周期:
 
1
bean的定义
 //
配置bean的开始,beans中包含一个或多个bean
 <beans>
  //
定义一个bean id是唯一标志,classbean的来源
      <bean  id="DateHello" class="DateHelloWorld">
  //
配置bean的开始
  <property name="msg">
  <null/>
  </property>
  //
定义bean的结束
  </bean>
 //
配置bean的结束
 </beans>
2
bean的初始化
 
初始化有两种方式:
 1
在配置文件中指定init-method属性来完成
   public class HelloWorld {
  private String msg;
  public void init(){
  msg="Hello World";
  }
  public String getMsg() {
   return msg;
  }
  public void setMsg(String msg) {
   this.msg = msg;
  }
  public void sayHello(){
   System.out.println(msg);
  }
  }

 applicationContext.xml文件中
 <bean  id="DateHello" class="HelloWorld" init-method="init">
  

 2实现org.springframework.beans.factory.InitialingBean接口
       
实现其中的afterPropertiesSet()方法

   public class HelloWorld implements InitializingBean{
  private String msg;
  public void afterPropertiesSet(){
  msg="Hello World";
  }
  public String getMsg() {
   return msg;
  }
  public void setMsg(String msg) {
   this.msg = msg;
  }
  public void sayHello(){
   System.out.println(msg);
  }
  }

 applicationContext.xml文件中
 <bean  id="DateHello" class="HelloWorld">
 </bean> 
 
 
3
bean的使用
 
有三种方式:
 1
:使用BeanWrapper
  HelloWorld helloWorld = new HelloWorld ();
  BeanWrapper bw = new BeanWrapperImpl(helloWorld);
     bw.setPropertyValue("msg","HelloWorld");
  System.out.println(bw.getPropertyValue("msg"));
 2:
使用BeanFactory
  InputStream is = new FileInputStream("applicationContext.xml");
  XmlBeanFactory factory = new XmlBeanFactory (is);
  HelloWorld helloWorld = (HelloWorld)factory.getBean ("HelloWorld");
  helloWorld.sayHello();

 3:使用ApplicationContext
  ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml"); 
  IHelloWorld hw= (IHelloWorld)ac.getBean("CHello");
  hw.sayHello();

4bean的销毁
 
销毁有两种方式:
 1
在配置文件中指定destory-method属性来完成
   public class HelloWorld {
  private String msg;
  public void init(){
  msg="Hello World";
  }
  public void cleanup(){
  msg="";
  }
  public String getMsg() {
   return msg;
  }
  public void setMsg(String msg) {
   this.msg = msg;
  }
  public void sayHello(){
   System.out.println(msg);
  }
  }

 applicationContext.xml文件中
 <bean  id="DateHello" class="HelloWorld" init-method="init" destory-method="cleanup">
  

 2实现org.springframework.beans.factory.DisposeableBean接口
       
实现其中的destory()方法

   public class HelloWorld implements InitializingBean,DisposeableBean{
  private String msg;
  public void afterPropertiesSet(){
  msg="Hello World";
  }
  public void destory(){
  msg="";
  }
  public String getMsg() {
   return msg;
  }
  public void setMsg(String msg) {
   this.msg = msg;
  }
  public void sayHello(){
   System.out.println(msg);
  }
  }

 applicationContext.xml文件中
 <bean  id="DateHello" class="HelloWorld">
 </bean> 
 ----------------------------------------------------------
 
ref属性指定依赖的三种方式
 1
:用local属性指定:local属性的值必须与被参考引用的beanid一致,如果在同一个xml文件里没有匹配的元素,xml解析将产生一个错误
  
如:
    <bean  id="DateHello" class="DateHelloWorld">
  <property name="msg">
  <value>Hello World!</value>
  </property>
  <property name="date">
  <ref local="date"/>
  </property>
  </bean>
    <bean id="date" class="java.util.Date"/>
    
   2:
bean属性指定
       
ref元素中的bean属性指定被参考引用的beanspring中最常见的形式,它允许指向的bean可以在同一xml文件中也可以不在同一个xml文件里
        bean
属性的值可以与被引用的beanid相同也可以与name相同。
    <bean  id="DateHello" class="DateHelloWorld">
  <property name="msg">
  <value>Hello World!</value>
  </property>
  <property name="date">
  <ref bean="date"/>
  </property>
  </bean>
    <bean id="date" class="java.util.Date"/>
   3
:用parent属性指定
    
ref元素中的parent属性指定被参考引用的bean时,允许引用当前BeanFactoryApplicationContext的父BeanFactoryApplicationContext
    bean
属性的值可以与被引用的beanid相同也可以与name相同。
     <bean  id="DateHello" class="DateHelloWorld">
  <property name="msg">
  <value>Hello World!</value>
  </property>
  <property name="date">
  <ref parent="date"/>
  </property>
  </bean>
   
local属性指定和用bean属性指定的比较
   
相同:都可以使用id来参考引用,可以对同一xml文件进行参考引用
   
不同:bean属性的值可以与被引用的beanid相同也可以与name相同。可以引用不在同一个xml文件里的bean
    
 ----------------------------------------------------------
 bean
自动装配的5种模式:
 
可以使用bean元素的autowire属性来指定bean的装配模式:
 1
byName
 2: byType
 3:constructor
 4:autodetect
 5:no
 
显示的指定依赖如:property constructor-arg元素总会覆盖自动装配。对与大型应用不鼓励使用自动装配
 
    --------------------------------------------------------------
    bean
依赖检查的4种模式:
   
依赖检查能够分别对每个bean应用或取消应用,默认的是不检查依赖关系,
   
可以使用bean元素的dependency-check属性来指定bean的依赖检查,共有4种:
    1
:使用simple模式
   
是指对基本类型、字符串和集合进行依赖检查
   
如:
    <bean  id="DateHello" class="DateHelloWorld" autowire="autodetect" dependency-check="simple">
  </bean>
    <bean id="date" class="java.util.Date"/>
    
只会对msg进行检查
 
    2
:使用object模式
   
是指对对象进行依赖检查
   
如:
    <bean  id="DateHello" class="DateHelloWorld" autowire="autodetect" dependency-check="object">
  </bean>
    <bean id="date" class="java.util.Date"/>
    
只会对date进行检查
    
    3
:使用all模式
   
是指对所有属性进行依赖检查
   
如:
    <bean  id="DateHello" class="DateHelloWorld" autowire="autodetect" dependency-check="all">
  </bean>
    <bean id="date" class="java.util.Date"/>
    
会对msg进行检查和date进行检查
     
   4
:使用none模式
   
是指对所有属性不进行依赖检查
   
如:
    <bean  id="DateHello" class="DateHelloWorld" autowire="autodetect" dependency-check="none">
  </bean>
    <bean id="date" class="java.util.Date"/>
    
不会对msg进行检查和date进行检查
    
    
总结:一般情况下依赖检查和自动装配结合使用,当bean属性都有默认值或不需要对bean的属性是否被设置到bean上检查时,依赖检查的作用就不大了
     
-----------------------------------------------------------------------
集合的注入方式
对于集合List Set Map Props元素则有不同的配置方式
1
List
     public class HelloWorld{
     //
定义一个List变量msg
     List msg=null;
     public void setMsg(List msg){
     this.msg = msg;
    }
     }
     xml
文件:
    <bean  id="Hello" class="HelloWorld">
  <property name="msg">
  <list>
  <value>Hello World!</value>
  <value>Hello World2!</value>
  </list>
  </property>
  </bean>

2:set

     public class HelloWorld{
     //
定义一个Set变量msg
        Set msg=null;
     public void setMsg(Set msg){
     this.msg = msg;
    }
     }
     xml
文件:
    <bean  id="Hello" class="HelloWorld">
  <property name="msg">
  <set>
  <value>Hello World!</value>
  <value>Hello World2!</value>
  </set>
  </property>
  </bean>
3:map
     public class HelloWorld{
     //
定义一个Map变量msg
        Map msg=null;
     public void setMsg(Map msg){
     this.msg = msg;
    }
     }
     xml
文件:
    <bean  id="Hello" class="HelloWorld">
  <property name="msg">
  <map>
  <entry key="h1">
  <value>Hello World!</value>
  </entry>
  <entry key="h2">
  <value>Hello World2!</value>
  </entry>
  </map>
  </property>
  </bean>

4:properties
  
     public class HelloWorld{
     //
定义一个properties变量msg
     Properties msg;
     public void setMsg(Properties msg){
     this.msg = msg;
    }
     }
     xml
文件:
    <bean  id="Hello" class="HelloWorld">
  <property name="msg">
  <props>
  <prop key ="h1">Hello World!</prop>
  <prop key ="h2">Hello World2!</prop>
  </props>
  </property>
  </bean>
  
  
  
  ---------------------------------------------------------------
  Spring AOP(Aspect Oriented Programming)
  
  
应用程序通常包含两种代码:一是核心业务代码,一是和业务关系不大的代码如日志、事物处理等。
  AOP
的思想就是使这两种代码分离,从而降低了两种代码的偶合性,达到了易于重用和维护的目的。
  AOP
OOP
  
AOP里,每个关注点的实现并不知道是否有其他关注点关注它,这是AOPOOP的主要区别,
  
AOP里组合的流向是从横切关注点到主关注点,在OOP中组合流向是从主关注点到横切关注点。
  AOP
OOP所关注的对象不同,AOPOOP有益的补充,不是对立面。
  
  AOP
3个关键概念:
  1
:切入点:(PiontCut)
    
连接点(Jion piont):是指程序运行中的某个阶段,如方法的调用、异常的抛出等。
    PiontCu
就是Jion piont点的集合,它是程序中需要注入的Advice的集合。指明Advice
    
在什么 条件下才被触发。
  2
:通知(Advice):
         
某个连接点采用的处理逻辑,也就是向连接点注入的代码。
  3
Advisor
     
PiontCutAdvice的配置器,它包含PiontCutAdvice,是把Advice注入到PiontCut位置的代码。
 
 
  Spring
3种切入点的实现:
  1
:静态切入点:
    
静态切入点只限于给定的方法和目标类。不考虑方法的参数。
  2
:动态切入点:
    
动态切入点不仅限于给定的方法和目标类,还可以指定方法的参数。
    
动态切入点有很大的性能损耗,一般很少使用。
  3
:自定义切入点:
   
正在发展
   
   
  Spring
的通知:
  1
Intercdption Around通知
  
   Intercdption Around
JiontPoint的前后执行。实现Intercdption Around通知要实现
   MethodInterceptor
接口,示例代码如下:
   public class LoginInterceptor implements MethodInterceptor{
    public Object invoke(MenthodInvocation invocation) throws Throwable{
     System.out.println("
开始审核数据");
     Object result = invocation.proceed();
     System.out.println("
审核数据结束");
     return result;
    }
   }
  2:Before
通知
  
      Before
通知在JiontPoint的前执行。实现Befored通知要实现
   MethodBeforeAdvice
接口,示例代码如下:
   public class LoginBeforeAdvice implements MethodBeforeAdvice{
    public void Beforee(Menthod m,Object [] atgs,Object target) throws Throwable{
     System.out.println("
开始审核数据");
    }
   }
   
   
  3:After Return
通知
  
    After Return
通知在JiontPoint后执行。实现After Returnd通知要实现
   AfterReturningAdvice
接口,示例代码如下:
   public class LoginAfterAdvice implements AfterReturningAdvice{
    public void AfterReturning(Menthod m,Object [] atgs,Object target) throws Throwable{
     System.out.println("
审核数据结束");
    }
   }
  
  4:Throw
通知
  
    Throw
通知在JiontPoint抛出异常时执行。实现Throw通知要实现
   ThrowAdvice
接口,示例代码如下:
   public class LoginThrowAdvice implements ThrowAdvice{
    public void AfterThrowing(RemoteException ex) throws Throwable{
     System.out.println("
审核数据异常");
    }
   }
  
  5
Introduction 通知
  
    Introduction
通知在JiontPoint 调用完毕后执行。实现Introduction通知要实现
   IntroductionAdvisor
接口和IntroductionInterceptor接口。
  
  
ProxyFactoryBean创建AOP代理
     
使用org.springfamework.aop.framework.ProxyFactoryBean是创建AOP代理的基本方式。
  
  1
:使用ProxyFactoryBean代理目标类中的所有方法
   
示例代码:
   <beans>
   <bean id="log" class="logAround"/>
   <bean id="logBefore" class="logBefore"/>
   <bean id="logAfter" class="logAfter"/>
   <bean id="logThrow" class="logThrow"/>
   <bean id="timebook" class="TimeBook"/>
   <!-
设定代理类-->
   <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
   <!--
代理的是接口-->
   <property name="proxyInterface">
   <value>TimeBookInterface</value>
   </property>
      <!--
要代理的目标类-->
   <property name="target">
   <ref bean="timebook"/>
   </property>
   <!--
程序中的Advice-->
   <property name="interceptorNames">
   <list>
   <value>logBefore</value>
   <value>logAfter</value>
   <value>logThrow</value>
   </list>
   </property>
   </bean>
   </beans>
  
  
  2
:使用ProxyFactoryBean代理目标类中的指定方法
  
   
示例代码:
   <beans>
   <bean id="log" class="logAround"/>
   <bean id="logBefore" class="logBefore"/>
   <bean id="logAfter" class="logAfter"/>
   <bean id="logThrow" class="logThrow"/>
   <bean id="timebook" class="TimeBook"/>
   <!--
代理目标类的指定方法-->
   <bean id ="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
   <property name="advice">
   <ref bean="log"/>
   </property>
   <!--
指定要代理的方法-->
   <property name="patterns">
   <value>doCheck*</value>
   </property>
   </bean>
   <!-
设定代理类-->
   <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
   <!--
代理的是接口-->
   <property name="proxyInterfaces">
   <value>TimeBookInterface</value>
   </property>
      <!--
要代理的目标类-->
   <property name="target">
   <ref bean="timebook"/>
   </property>
   <!--
程序中的Advice-->
   <property name="interceptorNames">
   <list>
   <value>logAdvisor</value>
   </list>
   </property>
   </bean>
   </beans>
   
   ---------------------------------------------------------
   
  
正则表达式:
  1
.表示可以匹配任何一个字符
  2
[]表示只有[]里指定的字符才能匹配
  3
*表示匹配次数
  4
:?表示可以匹配10
  5
/是正则表达式的连接符
  
  ---------------------------------------------------------------
  Spring
中两种AOP代理方式
  1:
动态代理
  
动态代理是指代理的是接口,Spring默认的是动态代理
  2
CGLIB代理
  <beans>
  <bean id="log" class="logAround"/>
  <bean id="logBefore" class="logBefore"/>
  <bean id="logAfter" class="logAfter"/>
  <bean id="logThrow" class="logThrow"/>
  <bean id="timebook" class="TimeBook"/>
  <bean id="logProxy" class ="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="proxyTargetClass">
  <value>true</value>
  </property>
  <property name="target">
  <ref bean="timebook"/>
  </property>
  <property name="interceptorNames">
  <list>
  <value>logBefore</value>
  <value>logAfter</value>
  <value>logThrow</value>
  </list>
  </property>
  </bean>
  </beans>
  
 -----------------------------------------------------------------------
 Spring
中的自动代理方式 
 
 
自动代理可以跨越多个类,不管哪个类中的方法只要符合要求都可以代理
 <beans>
 <bean id="log" class="logAround"/>
 <bean id="logBefore" class="logBefore"/>
 <bean id="logAfter" class="logAfter"/>
 <bean id="logThrow" class="logThrow"/>
 <bean id="timebook" class="TimeBook"/>
 <bean id="timework" class="TimeWork"/>
 <!--
使用自动代理-->
 <bean id="autoProxy" class ="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
 <bean id="logBeforAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
 <property name="advice">
 <ref bean="logBefore"/>
 </property>
 <property name="patterns">
 <value>.*do.*</value>
 </property>
 </bean>
 </beans>
 
 ------------------------------------------------------------
 Spring
中的事务处理
 
  
事务处理是由多个步骤组成,这些步骤之间有一定的逻辑关系,作为一个整体的操作过程,所有的步骤必须同时成功或失败。
  1
:提交  当所有的操作步骤都被完整执行后,称为该事物被提交。
  2
:回滚  由于某个操作失败,导致所有的步骤都没被提交则事物必须回滚,回到事物执行前的状态。
  
  
事务的特性:
  ACID
:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durablity)
  
  Spring
中的事务处理是基于动态AOP机制的实现。
  
  1
:编程式事务处理:
  
  spring
提供的TransactionTemplate能够以编程的方式实现事务控制。
  
  HelloADO.java:
  
   public int create(String msg){
   DefaultTransactionDefinition def = new DefaultTransactionDefinition();
   TransactionStatus status = transactionManager.getTransaction(def);
  
   try{
    JdbcTemplate jt = new JdbcTemplate(dataSource);
    int i=jt.update("insert into st(name,password) values('zz','zz')");
    return i;
   }catch (Exception e){
    transactionManager.rollback(status);
    return 0;
   }
   finally {
    transactionManager.commit(status);
   }
   }
  applicationContext.xml
  
   <beans>
   <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName">
   <value>com.mysql.jdbc.Driver</value>
   </property>
   <property name="url">
   <value>jdbc:mysql://localhost:3306/newdb</value>
   </property>
   <property name="username">
   <value>root</value>
   </property>
   <property name="password">
   <value>lxl</value>
   </property>
   </bean>
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <bean id="helloDAO" class ="HelloDAO">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   <property name="transactionManager">
   <ref bean="transactionManager"/>
   </property>
   </bean>
   </beans>
  
  2
:声明式事务处理:
  
  HelloADO.java:
  
   public class HelloDAO {
   private DataSource dataSource ;
   private JdbcTemplate jdbcTemplate;
   public void setDataSource(DataSource dataSource) {
    this.dataSource = dataSource;
    jdbcTemplate = new JdbcTemplate(dataSource);
   }
   public void create(String name){
    jdbcTemplate.update("insert into st(name,password)values('lxl','lxl')");
   }
   }
  applicationContext.xml
   <beans>
   <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName">
   <value>com.mysql.jdbc.Driver</value>
   </property>
   <property name="url">
   <value>jdbc:mysql://localhost:3306/newdb</value>
   </property>
   <property name="username">
   <value>root</value>
   </property>
   <property name="password">
   <value>lxl</value>
   </property>
   </bean>
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <bean id="helloDAO" class ="HelloDAO">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <!--
声明式事务处理-->
   <bean id="helloDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager">
   <ref bean="transactionManager"/>
   </property>
   <property name="target">
   <ref bean="helloDAO"/>
   </property>
   <property name="transactionAttributes">
   <props>
   <!--
create方法进行事务管理,PROPAGATION_REQUIRED表示如果没有事务就新建一个事务-->
   <prop key="create*">PROPAGATION_REQUIRED</prop>
   </props>
   </property>
   </bean>  
   </beans>
  -------------------------------------------------------
  Spring
持久层的封装
  
  
通过xml实现DataSource数据源的注入有3种方式:
  1
:使用spring自带的DriverManagerDataSource
  <beans>
   <bean id ="dataSource" class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName">
   <value>com.mysql.jdbc.Driver</value>
   </property>
   <property name="url">
   <value>jdbc:mysql://localhost:3306/newdb</value>
   </property>
   <property name="username">
   <value>root</value>
   </property>
   <property name="password">
   <value>lxl</value>
   </property>
   </bean>
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <bean id="helloDAO" class ="HelloDAO">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <!--
声明式事务处理-->
   <bean id="helloDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager">
   <ref bean="transactionManager"/>
   </property>
   <property name="target">
   <ref bean="helloDAO"/>
   </property>
   <property name="transactionAttributes">
   <props>
   <!--
create方法进行事务管理,PROPAGATION_REQUIRED表示如果没有事务就新建一个事务-->
   <prop key="create*">PROPAGATION_REQUIRED</prop>
   </props>
   </property>
   </bean>  
   </beans>
  
  2:
使用DBCP连接池
  
   <beans>
   <bean id ="dataSource" class ="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName">
   <value>com.mysql.jdbc.Driver</value>
   </property>
   <property name="url">
   <value>jdbc:mysql://localhost:3306/newdb</value>
   </property>
   <property name="username">
   <value>root</value>
   </property>
   <property name="password">
   <value>lxl</value>
   </property>
   </bean>
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <bean id="helloDAO" class ="HelloDAO">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <!--
声明式事务处理-->
   <bean id="helloDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager">
   <ref bean="transactionManager"/>
   </property>
   <property name="target">
   <ref bean="helloDAO"/>
   </property>
   <property name="transactionAttributes">
   <props>
   <!--
create方法进行事务管理,PROPAGATION_REQUIRED表示如果没有事务就新建一个事务-->
   <prop key="create*">PROPAGATION_REQUIRED</prop>
   </props>
   </property>
   </bean>  
   </beans>
  
  3
:使用Tomcat提供的JNDI
  
   <beans>
   <bean id ="dataSource" class ="org.springframework.jndi.JndiObjectFactoryBean">
   <property name="driverClassName">
   <value>com.mysql.jdbc.Driver</value>
   </property>
   <property name="url">
   <value>jdbc:mysql://localhost:3306/newdb</value>
   </property>
   <property name="username">
   <value>root</value>
   </property>
   <property name="password">
   <value>lxl</value>
   </property>
   </bean>
   <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <bean id="helloDAO" class ="HelloDAO">
   <property name="dataSource">
   <ref bean="dataSource"/>
   </property>
   </bean>
   <!--
声明式事务处理-->
   <bean id="helloDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager">
   <ref bean="transactionManager"/>
   </property>
   <property name="target">
   <ref bean="helloDAO"/>
   </property>
   <property name="transactionAttributes">
   <props>
   <!--
create方法进行事务管理,PROPAGATION_REQUIRED表示如果没有事务就新建一个事务-->
   <prop key="create*">PROPAGATION_REQUIRED</prop>
   </props>
   </property>
   </bean>  
   </beans>
  
 ------------------------------------------------------- 
  Spring
Struts的整合使用
  Spring
Struts的整合有3种方式:
  1
:通过SpringActionSupport
  2
:通过SpringDelegatingRequestProcessor
  3
:通过SpringDelegatingActionProxy
  
  
  a: 
通过SpringActionSupport:(对应工程:SpringStruts)
   
方法是Action类不再继承StrutsAction而是继承Spring提供的ActionSupport
   
然后在Action中获得SpringApplicationContext.
   
缺点是ActionSpring耦合在一起,而且Action不在Spring控制之内。也不能处理多个动作在一个Action中的情况。
   
   
步骤:
   1
:加入spring.
   2:
加入struts
   3
:修改struts配置文件struts-config.xml文件注册ContextLoaderPlugIn插件。
    <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
       <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
    </plug-in>
   4:
创建Action时:
   (1)
处,我通过从 Spring ActionSupport 类而不是 Struts Action 类进行扩展,创建了一个新的 Action
   (2)
处,我使用  getWebApplicationContext() 方法获得一个 ApplicationContext。为了获得业务服务,我使用在
            (3)
  查找一个 Spring bean
              //(1)
   public class LoginAction extends ActionSupport {
 
    public ActionForward execute(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response) {
     LoginForm loginForm = (LoginForm) form;
     // TODO Auto-generated method stub
     //(2)
     ApplicationContext ac = this.getWebApplicationContext();//
获得ApplicationContext
     //(3)
     LoginInterface li = (LoginInterface)ac.getBean("loginInterface");//
获得Bean
     boolean you = li.checkUser(loginForm.getName(),loginForm.getPassword());
     if(you){
      request.setAttribute("msg","welcome");
      return mapping.findForward("show");
     }
     else{
      request.setAttribute("msg","failed");
      return mapping.findForward("show");
     }
    }
   
   }
   applicationContext.xml:
   <beans>
   <bean id="loginInterface" class="spring.LoginImp"/>
   
   </beans>
  
  b: 
通过SpringDelegatingRequestProcessor:(对应工程:SpringStruts2)
   
方法是SpringDelegatingRequestProcessor代替StrutsRequstProcessor
   
StrutsAction置于Spring的的控制之下
   
缺点是开发人员可以自己定义RequestProcessor这样就需要手工整合StrutsSpring
   
   
步骤:
   1
:加入spring.
   2:
加入struts
   3
:修改struts配置文件struts-config.xml文件注册ContextLoaderPlugIn插件。
    <struts-config>
      <form-beans >
        <form-bean name="loginForm" type="com.yourcompany.struts.form.LoginForm" />
      </form-beans>
    
      <action-mappings >
        <action
          attribute="loginForm"
          input="/login.jsp"
          name="loginForm"
          path="/login"
          scope="request"
          type="com.yourcompany.struts.action.LogAction">
          <forward name="show" path="/show.jsp" />
        </action>
    
      </action-mappings>
     <controller processorClass="org.springframework.web.struts.DelegatingRequestProcessor"></controller>
       <message-resources parameter="com.yourcompany.struts.ApplicationResources" />
     <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
        <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
     </plug-in>       
    </struts-config>
   4:
创建Action时:
   public class LogAction extends Action {
    private LoginInterface logInterface;
    
    public ActionForward execute(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response) {
     LoginForm loginForm = (LoginForm) form;
     // TODO Auto-generated method stub
     boolean you = logInterface.checkUser(loginForm.getName(),loginForm.getPassword());
     if(you){
      request.setAttribute("msg","welcome");
      return mapping.findForward("show");
     }
     else{
      request.setAttribute("msg","failed");
      return mapping.findForward("show");
     } 
    }
    public void setLogInterface(LoginInterface logInterface) {
     this.logInterface = logInterface;
    }
   
   }


   applicationContext.xml:
   <beans>
   <bean id="loginInterface" class="spring.LoginImp"/>
   <!--
要和Struts的路径对应-->
   <bean name="/login" class="com.yourcompany.struts.action.LogAction">
   <property name="logInterface">
   <ref bean="loginInterface"/>
   </property>
   </bean>
   </beans>
  c: 
通过SpringDelegatingActionProxy:(对应工程:SpringStruts3)
   
方法是SpringDelegatingActionProxy代替StrutsAction
   
StrutsAction置于Spring的的控制之下
   
这种方式最灵活强大。并且它可以利用 Spring AOP 特性的优点。
   
   
步骤:
   1
:加入spring.
   2:
加入struts
   3
:修改struts配置文件struts-config.xml文件注册ContextLoaderPlugIn插件。
    <struts-config>
      <data-sources />
      <form-beans >
        <form-bean name="loginForm" type="com.yourcompany.struts.form.LoginForm" />
      </form-beans>
      <action-mappings >
        <action
          attribute="loginForm"
          input="/form/login.jsp"
          name="loginForm"
          path="/login"
          scope="request"
          type="org.springframework.web.struts.DelegatingActionProxy">
          <forward name="show" path="/show.jsp" />
        </action>
      </action-mappings>
      <message-resources parameter="com.yourcompany.struts.ApplicationResources" />
     <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
       <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml"/>
     </plug-in>
    </struts-config>

   4:创建Action时:
   public class LogAction extends Action {
    private LoginInterface logInterface;
    
    public ActionForward execute(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response) {
     LoginForm loginForm = (LoginForm) form;
     // TODO Auto-generated method stub
     boolean you = logInterface.checkUser(loginForm.getName(),loginForm.getPassword());
     if(you){
      request.setAttribute("msg","welcome");
      return mapping.findForward("show");
     }
     else{
      request.setAttribute("msg","failed");
      return mapping.findForward("show");
     } 
    }
    public void setLogInterface(LoginInterface logInterface) {
     this.logInterface = logInterface;
    }
   
   }


   applicationContext.xml:
   <beans>
   <bean id="loginInterface" class="spring.LoginImp"/>
   <!--
要和Struts的路径对应-->
   <bean name="/login" class="com.yourcompany.struts.action.LogAction">
   <property name="logInterface">
   <ref bean="loginInterface"/>
   </property>
   </bean>
   </beans>
   
   
 
拦截 Struts
             
通过将 Struts 动作委托给 Spring 框架而整合 Struts Spring 的一个主要的优点是:您可以将
              Spring
AOP 拦截器应用于您的 Struts 动作。通过将 Spring 拦截器应用于 Struts
             
动作,您可以用最小的代价处理横切关注点。
             
虽然 Spring 提供很多内置拦截器,但是我将向您展示如何创建自己的拦截器并把它应用于一个 Struts
             
动作。为了使用拦截器,您需要做三件事:
               1
创建拦截器。

               2:注册拦截器。

               3:声明在何处拦截代码。
             
这看起来非常简单的几句话却非常强大。例如,在清单 7 中,我为 Struts 动作创建了一个日志记录拦截器。
             
这个拦截器在每个方法调用之前打印一句话:
             
清单 7. 一个简单的日志记录拦截器
                 public class LoggingInterceptor implements MethodBeforeAdvice {
                     public void before(Method method, Object[] objects, Object o) throws Throwable {
                            System.out.println("logging before!");
                              }
                            }

              这个拦截器非常简单。before()
             
方法在拦截点中每个方法之前运行。在本例中,它打印出一句话,其实它可以做您想做的任何事。下一步就是在 Spring
             
配置文件中注册这个拦截器,如清单 8 所示:
             
清单 8. Spring 配置文件中注册拦截器
              <beans>
                <bean id="bookService" class="ca.nexcel.books.business.BookServiceImpl"/> 
                <bean name="/searchSubmit"         class="ca.nexcel.books.actions.SearchSubmit">
                     <property name="bookService">        <ref bean="bookService"/>     </property> 
                </bean>
                <!--  Interceptors -->  
                <bean name="logger"  class="ca.nexcel.books.interceptors.LoggingInterceptor"/> |(1) 
                <!-- AutoProxies --> 
                <bean name="loggingAutoProxy"  class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> |(2)   
                <property name="beanNames">  <value>/searchSubmit</value> |(3)    </property>   
                <property name="interceptorNames">
                 <list>         
                 <value>logger</value> |(4)       
                 </list>   
                 </property>  
                 </bean>
              </beans>

              您可能已经注意到了,清单 8 扩展了 清单 6 中所示的应用程序以包含一个拦截器。具体细节如下:
               
(1) 处,我注册了这个拦截器。

                (2) 处,我创建了一个 bean 名称自动代理,它描述如何应用拦截器。还有其他的方法定义拦截点,但是这种方法常见而简便。

                (3) 处,我将 Struts 动作注册为将被拦截的 bean。如果您想要拦截其他的 Struts 动作,则只需要在
                "beanNames"
下面创建附加的 <value> 标记。

                (4) 处,当拦截发生时,我执行了在 (1) 处创建的拦截器 bean
               
的名称。这里列出的所有拦截器都应用于“beanNames”
             
就是这样。就像这个例子所展示的,将您的 Struts 动作置于 Spring 框架的控制之下,为处理您的 Struts
             
应用程序提供了一系列全新的选择。在本例中,使用动作委托可以轻松地利用 Spring 拦截器提高 Struts
             
应用程序中的日志记录能力。
             
   -----------------------------------------------------------------------------------------------          
             
           Struts  +  Spring  +  Hibernate
的整合使用
          
          
          
      
开发工具:Eclipse3.1,MyEclipse4.0 ,Tomcat 5.0.28 ,mysql-4.0.18
      
      
      
开发步骤:
       1
:创建web projectSSHlogin 加入struts1.2 
             
          
创建loginForm选择DynaValidatorForm,加入passwordusername,创建jsp文件打上钩,将路径改为 /login.jsp,然后下一步,改LoginActionInput source改为/login.jsp,加入 <forward name="ok" path="ok.jsp" />点击完成
          
          
完成后修改struts-config.xml文件加入
           <plug-in className="org.apache.struts.validator.ValidatorPlugIn">
       <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" />
       </plug-in>
    
拷贝validator-rules.xmlvalidation.xmlWEB-INF目录中  validation.xml文件中加入
       <form-validation>
     <formset>
       <form name="loginForm">
        <field property="username" depends="required">
        <arg0 key="prompt.username" />
        </field>
        <field property="password" depends="required">
         <arg0 key="prompt.password" />
        </field>
       </form>
        </formset>
    </form-validation>
     validator-rules.xml
文件直接考一个就行。
    
编辑资源文件“ApplicationResources.properties”
   
增加以下内容  
    prompt.username=User Name
    prompt.password=User Password
    errors.required={0} is required.
       
             
        
修改LoginAction.java文件的execute方法,内容如下
   public ActionForward execute(
     ActionMapping mapping,
     ActionForm form,
     HttpServletRequest request,
     HttpServletResponse response) {
     DynaValidatorForm loginForm = (DynaValidatorForm) form;
     String username=loginForm.getString("username");
     String password=loginForm.getString("password");
     if(username.equals("test")||password.equals("test")){
      return mapping.findForward("indexGo");
     }else{
      return mapping.getInputForward();
     }
    }
  
好了,现在可以启动Tomcat进行测试了如果不输入任何数据而直接提交表单的话就可以看到效果了。
 
  
好了,如果没有什么问题的话就继续往下看吧,如果有问题的话就得往上看了^_^
  
  2
:加入Spring框架
   
在这里我将Spring所有的包全部加载进去,因为我还不知道具体用到哪些类,全部加进去方便点
 
   
单选框选第二个,这样的话所有的类库和标签等都将拷贝到项目中去,这样方便以后的布署
   
下一步后是创建配置文件,将文件放到“WebRoot/WEB-INF”目录下,文件名称为“applicationContext.xml”
   
   
   
配置struts-config.xml文件,添加(spring)的插件
   
   <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
       <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" />
     </plug-in>
   
    
   
修改LoginAction配置
   
   
原:
   <action
         attribute="loginForm"
         input="/login.jsp"
         name="loginForm"
         path="/login"
         scope="request"
         validate="true"
         type="com.test.struts.action.LoginAction" >
      <forward name="ok" path="ok.jsp" />
       </action>
   
     </action-mappings>
   
   
改为:
   <action
         attribute="loginForm"
         input="/login.jsp"
         name="loginForm"
         path="/login"
         scope="request"
         validate="true"
         type="org.springframework.web.struts.DelegatingActionProxy">
         <forward name="ok" path="ok.jsp" />
       </action>
     </action-mappings>
   
 
   
这里将使用spring的代理器来对Action进行控制
      
   
当提交到/login.do是将控制权交给了spring,然后由spring来决定是否转回到strutsAction
 
   
现在来配置spring
   
   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
   
   <beans>
    <bean name="/login" class="com.test.struts.action.LoginAction" singleton="false"></bean>
   </beans>
   
         
好了,现在可以启动Tomcat进行测试了如果没有什么问题的话就继续往下看吧,如果有问题的话就得往上看了^_^   
 
 
      3
:创建Hibernate框架       
             
         
建立数据库在 这里我使用的是mysql4.1.18
 
   CREATE TABLE `user` (
     `ID` int(11) NOT NULL auto_increment,
     `USERNAME` varchar(50) NOT NULL default '',
     `PASSWORD` varchar(50) NOT NULL default '',
     PRIMARY KEY  (`ID`)
   ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
   
   
添加记录 insert into user (USERNAME,PASSWORD) values ('test','test')
                
  
在配置界面中配置数据库的连接部份,重要的是点击链接将jdbc驱动拷贝到lib目录中
  
使用MyEclipse的数据Database Explorer工具创建User.hmb.xmlAbstractUser.javaUser.java映射文件              
    
      
创建UserDAO.javaUserDAOImp.java
   UserDAO.java

   
   public interface UserDAO {
   
      public abstract boolean isValidUser(String username, String password);
   
   }  
   
   UserDAOImp.java

   
   import java.util.List;
   
   import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
   
   public class UserDAOImp extends HibernateDaoSupport implements UserDAO {
   
    private static String hql = "from User u where u.username=? and password=?";
   
    public boolean isValidUser(String username, String password) {
   
     String[] userlist=new String[2];
     userlist[0]=username;
     userlist[1]=password;
   
     List userList = this.getHibernateTemplate().find(hql,userlist);
   
     if (userList.size() > 0) {
   
      return true;
   
     }
   
     return false;
   
    }
   
   }

   
   
   
修改LoginAction.java文件,使用userDao的方法来进行用户验证
   package com.test.struts.action;
   
   import javax.servlet.http.HttpServletRequest;
   import javax.servlet.http.HttpServletResponse;
   
   import org.apache.struts.action.Action;
   import org.apache.struts.action.ActionForm;
   import org.apache.struts.action.ActionForward;
   import org.apache.struts.action.ActionMapping;
   import org.apache.struts.validator.DynaValidatorForm;
   
   import com.test.UserDAO;
   
   public class LoginAction extends Action {
   
    private UserDAO userDAO;
   
    public UserDAO getUserDAO() {
     return userDAO;
    }
   
    public void setUserDAO(UserDAO userDAO) {
     this.userDAO = userDAO;
    }
   
    public ActionForward execute(ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response) {
     DynaValidatorForm loginForm = (DynaValidatorForm) form;
     // TODO Auto-generated method stub
     String username = (String) loginForm.get("username");
     String password = (String) loginForm.get("password");
     loginForm.set("password", null);
     if (userDAO.isValidUser(username,password)) {
      return mapping.findForward("ok");
     } else {
      return mapping.getInputForward();
     }
    }
   }
             
             
         
现在剩下最后的spring配置了
          <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
   
   <beans>
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
     <property name="driverClassName">
      <value>com.mysql.jdbc.Driver</value>
     </property>
     <property name="url">
      <value>jdbc:mysql://localhost/test</value>
     </property>
     <property name="username">
      <value>root</value>
     </property>
     <property name="password">
      <value>lxl</value>
     </property>
    </bean>
   
    <!--
配置sessionFactory, 注意这里引入的包的不同  -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
     <property name="dataSource">
      <ref local="dataSource" />
     </property>
     <property name="mappingResources">
      <list>
       <value>com/test/Hibernate/User.hbm.xml</value>
      </list>
     </property>
     <property name="hibernateProperties">
      <props>
       <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
       <prop key="hibernate.show_sql">true</prop>
      </props>
     </property>
    </bean>
   
    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
     <property name="sessionFactory">
      <ref local="sessionFactory" />
     </property>
    </bean>
   
    <bean id="userDAO" class="com.test.UserDAOImp">
     <property name="sessionFactory">
      <ref local="sessionFactory" />
     </property>
    </bean>
   
    <bean id="userDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
     <property name="transactionManager">
      <ref bean="transactionManager" />
     </property>
     <property name="target">
      <ref local="userDAO" />
     </property>
     <property name="transactionAttributes">
      <props>
       <prop key="insert*">PROPAGATION_REQUIRED</prop>
       <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
       <prop key="is*">PROPAGATION_REQUIRED,readOnly</prop>
      </props>
     </property>
    </bean>
   
    <bean name="/login" class="com.test.struts.action.LoginAction" singleton="false">
     <property name="userDAO">
      <ref bean="userDAOProxy" />
     </property>
    </bean>
   </beans>
       
现在可以进行测试了!
 
   
在编写代码有配置内容时一定要注意 hibernate hibernate3 ,这两个包的名字就只差一个字,千万不要有错,否则找错误可是很难的。
   
注意要把spring-hibernate.jar或者把spring.jar加到工程lib

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值