SSM三大框架之Spring学习,这是一篇面向官方文档开发的Spring学习,基础入门者必看

1.Spring


Spring是一个轻量级控制反转(IOC)面向切面编程(AOP)整合框架

1.1简介

  • Spring:春天 可以理解为软件行业迎来了春天
  • Spring框架是由于软件开发的复杂性而创建的
  • Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情
  • Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
  • 2002年,首次退出了Spring框架的雏形,interface21
  • 2004年3月24日这一天,Spring Framework 1.0 final 框架以interface21为基础正式出现在我们的视野中

1.2设计哲学

当您了解框架时,不仅要了解框架的工作而且要遵循的原则很重要。以下是 Spring 框架的指导原则:

  • 提供每个级别的选择。 Spring 使您可以尽可能推迟设计决策。例如,您可以在不更改代码的情况下通过配置切换持久性提供程序。对于许多其他基础架构问题以及与第三方 API 的集成也是如此。
  • 适应不同的观点。 Spring 拥有灵 Active,并且对如何完成工作一无所知。它从不同的角度支持广泛的应用程序需求。
  • 保持强大的向后兼容性。对 Spring 的 Developing 进行了精心 Management,以使各个版本之间几乎没有重大更改。 Spring 支持精心选择的 JDK 版本和第三方库,以方便维护依赖于 Spring 的应用程序和库。
  • 关心 API 设计。 Spring 团队投入了大量的思想和时间来制作直观,并在许多版本和很多年中都适用的 API。
  • 为代码质量设置高标准。 Spring 框架非常强调有意义,最新和准确的 javadoc。它是极少数可以声明干净代码结构且程序包之间没有循环依赖关系的项目之一。

1.3下载地址

官网:https://spring.io/

官方下载地址:https://repo.spring.io/release/org/springframework/spring/

GitHub下载地址:https://github.com/spring-projects/spring-framework/releases

maven依赖

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>



1.4Spring优点

  • 它是一个开源的免费的框架(容器)
  • 轻量级非入侵式的框架
  • 控制反转(IOC),面向切面编程(AOP)
  • 支持事务的处理对框架整合的支持,大杂烩

2.IOC理论推导

1.Dao接口

package com.ljl.dao;

public interface UserDao {

    int query();
}

2.DaoImpl

package com.ljl.dao;

public class UserDaoImpl implements UserDao {


    public int query() {

        System.out.println("进入mysql方法");
        return 0;
    }
}

3.Service接口

package com.ljl.service;

public interface UserService {
    int query();
}

4.ServiceImpl

package com.ljl.service;

import com.ljl.dao.OraclImpl;
import com.ljl.dao.UserDao;
import com.ljl.dao.UserDaoImpl;

public class UserServiceImpl implements UserService {
    UserDao userDao  ;
    public int query() {

        userDao = new OraclImpl();
        userDao.query();
        return 0;
    }
}

5.测试

import com.ljl.service.UserService;
import com.ljl.service.UserServiceImpl;
import org.junit.Test;

public class MyTest {
@Test
    public void query(){
        UserService userService = new UserServiceImpl();

        userService.query();
    }
}

在我们之前的业务中可能会需要根据用户的需求去更改源代码!如果程序代码量十分大,修改一次代码的成本代价十分昂贵

我们在使用set接口后,程序发生了革命性的变化

    private UserDao userDao  ;
//利用set方法实现动态值得注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
  • 之前,程序主动创建对象!控制权在程序员手上
  • 使用set注入后,程序不再具有主动性,而是被动地接受对象

这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建,系统的耦合性大大降低,可以更加专注在业务的事项上!这就是IOC的原型!

https://www.docs4dev.com/images/spring-framework/5.1.3.RELEASE/container-magic.png

3.HelloSpring

3.1配置元数据

如上图所示,Spring IoC 容器使用一种形式的配置元数据。此配置元数据表示您作为应用程序开发人员如何告诉 Spring 容器实例化,配置和组装应用程序中的对象。

传统上,配置元数据以简单直观的 XML 格式提供,这是本章大部分内容用来传达 Spring IoC 容器的关键概念和功能的内容。

Note

基于 XML 的元数据不是配置元数据的唯一允许形式。 Spring IoC 容器本身与实际写入此配置元数据的格式完全脱钩。如今,许多开发人员为自己的 Spring 应用程序选择Java-based configuration

有关在 Spring 容器中使用其他形式的元数据的信息,请参见:

Spring 配置由容器必须 Management 的至少一个(通常是一个以上)bean 定义组成。基于 XML 的配置元数据将这些 bean 配置为顶级<beans/>元素内的<bean/>元素。 Java 配置通常在@Configuration类中使用@Bean
注解的方法。

这些 bean 定义对应于组成应用程序的实际对象。通常,您定义服务层对象,数据访问对象(DAO),表示对象(例如 Struts Action实例),基础结构对象(例如 Hibernate SessionFactories,JMS Queues等)。通常,不会在容器中配置细粒度的域对象,因为 DAO 和业务逻辑通常负责创建和加载域对象。但是,您可以使用 Spring 与 AspectJ 的集成来配置在 IoC 容器的控制范围之外创建的对象。参见使用 AspectJ 与 Spring 依赖注入域对象

以下示例显示了基于 XML 的配置元数据的基本结构:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <beans>
        <bean id="helloSpring" class="com.ljl.pojo.HelloSpring">
            <property name="name" value="darling"/>
            <property name="age" value="21"/>
        </bean>

    </beans>
</beans>
  • (1) id属性是标识单个 bean 定义的字符串。
  • (2) class属性定义 bean 的类型并使用完全限定的类名。

id属性的值是指协作对象。在此示例中未显示用于引用协作对象的 XML。有关更多信息,请参见Dependencies

3.2实例化容器

提供给ApplicationContext构造函数的位置路径是资源字符串,这些资源字符串使容器可以从各种外部资源(例如本地文件系统,Java CLASSPATH等)加载配置元数据。

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

3.3测试

import com.ljl.pojo.HelloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
@Test
    public void test() {
//    获得管理对象的全局变量
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
//      通过Spring获取对象
    HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring");
    System.out.println(helloSpring.toString());


}
}

做完这一系列测试后我们就能对IOC有了一定的了解,到了现在我们应对不同的需求就不要去更改代码,只需要在xml文件中更改配置,所谓的IOC一句话表示:对象的创建管理装配都由Spring来操作.

4.Spring配置

4.1别名

<!-- 别名 ,起了别名就可以通过别名也能获取到对象-->
        <alias name="helloSpring" alias="helloSpring2"/>
HelloSpring helloSpring = (HelloSpring) applicationContext.getBean("helloSpring2");

4.2Bean的配置

<!--     id :Bean的唯一标识符 我们通过id名才可以获取对象-->
<!--     class:Bean对象对应的全限定名:包名+类名-->
<!--     name: 也相当于给Bean取别名 还可以同时取多个 所以可以不用使用别名标签   -->
<!--     scope:作用域  默认单例模式创建对象-->
        <bean id="helloSpring" class="com.ljl.pojo.HelloSpring" name="helloSpring3,helloSpring4" >
           <constructor-arg name="name" value="小林"/>
            <constructor-arg name="age" value="25"/>

        </bean>

4.3import

import一般用于团队开发使用,它可以将多个配置文件,导入合并为一个

假设这个项目有多个人开发,可以将每个人的不同beans.xml导入到一个总的applicationContext.xml里面,使用时就可以只使用这一个总的配置文件即可

<import resource="beans.xml" />

5.依赖注入(DI)

5.1set注入

常用注入方式

5.1.1环境搭建

1.两个实体类

package com.ljl.pojo;

import java.util.*;

public class Student {
    private String name;
    private Adress adress;
    private List<String> hobbis;
    private Map<String,String> couple;
    private Set<String> card;
    private String [] books;
    private String girlFriend;
    private Properties info;

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public String getGirlFriend() {
        return girlFriend;
    }

    public void setGirlFriend(String girlFriend) {
        this.girlFriend = girlFriend;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Adress getAdress() {
        return adress;
    }

    public void setAdress(Adress adress) {
        this.adress = adress;
    }

    public List<String> getHobbis() {
        return hobbis;
    }

    public void setHobbis(List<String> hobbis) {
        this.hobbis = hobbis;
    }

    public Map<String, String> getCouple() {
        return couple;
    }

    public void setCouple(Map<String, String> couple) {
        this.couple = couple;
    }

    public Set<String> getCard() {
        return card;
    }

    public void setCard(Set<String> card) {
        this.card = card;
    }



    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", adress=" + adress.toString() +
                ", hobbis=" + hobbis +
                ", couple=" + couple +
                ", card=" + card +
                ", books=" + Arrays.toString(books) +
                ", girlFriend='" + girlFriend + '\'' +
                ", info=" + info +
                '}';
    }
}
package com.ljl.pojo;

public class Adress {
    private String adress;

    public String getAdress() {
        return adress;
    }

    public void setAdress(String  adress) {
        this.adress = adress;
    }

    @Override
    public String toString() {
        return "Adress{" +
                "adress=" + adress +
                '}';
    }
}

5.1.2编写xml配置资源

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="adress" class="com.ljl.pojo.Adress">
       <property name="adress" value="四川巴中"/>
    </bean>

    <bean id="student" class="com.ljl.pojo.Student" >
        <property name="name" value="darling"/>
        <property name="adress" ref="adress" >

        </property>
        <property name="hobbis">
            <list>
                <value>games</value>
                <value>football</value>
                <value>code</value>
            </list>
        </property>
        <property name="couple">
            <map>
                <entry key="fat" value="Lsr"></entry>
                <entry key="ljl" value="Lsr"></entry>
                <entry key="lm" value="cz"></entry>
            </map>
        </property>
        <property name="card">
            <set>
                <value>银行卡</value>
                <value>身份证</value>
                <value>学生证</value>
            </set>
        </property>
        <property name="books" >
            <array>
                <value>英语书</value>
                <value>数学书</value>
                <value>Java书</value>
            </array>
        </property>

        <property name="girlFriend" value=""/>
        <property name="info">
            <props>
                <prop key="driver">com.oracle.deploy</prop>
                <prop key="url">jdbc:mysql:localhost:3306//mybatisUserSSL=trueUseEncodingChacter=utf8</prop>
                <prop key="user">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>

</beans>

5.1.3测试

import com.ljl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) applicationContext.getBean("student");
        System.out.println(student.toString());


        /**
         * Student{
         * name='darling',
         * adress=Adress{adress=四川巴中},
         * hobbis=[games, football, code],
         * couple={fat=Lsr, ljl=Lsr, lm=cz},
         * card=[银行卡, 身份证, 学生证],
         * books=[英语书, 数学书, Java书], girlFriend='',
         * info={
         * user=root,
         * password=123456,
         * url=jdbc:mysql:localhost:3306//mybatisUserSSL=trueUseEncodingChacter=utf8,
         * driver=com.oracle.deploy
         * }
         * }
         */
    }
}

5.2Bean的作用域

ScopeDescription
singleton(默认)将每个 Spring IoC 容器的单个 bean 定义范围限定为单个对象实例。
prototype将单个 bean 定义的作用域限定为任意数量的对象实例。
request将单个 bean 定义的范围限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有一个在单个 bean 定义后面创建的 bean 实例。仅在可感知网络的 Spring ApplicationContext中有效。
session将单个 bean 定义的范围限定为 HTTP Session的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
application将单个 bean 定义的范围限定为ServletContext的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
websocket将单个 bean 定义的范围限定为WebSocket的生命周期。仅在可感知网络的 Spring ApplicationContext上下文中有效。
  • 单例模式(Spring默认机制)
<bean id="student" class="com.ljl.pojo.Student" scope="singleton" >
  • 原型模式(手动设置)
<bean id="student" class="com.ljl.pojo.Student" scope="prototype" >
  • 其余的主要在运用在Web应用中

6.Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式

  • Spring会在上下文中自动寻找,并自动给bean装配属性

Spring中有三种装配方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean[重要]

6.1测试

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="com.ljl.pojo.Dog"/>

    <bean  class="com.ljl.pojo.Tiger"/>

    <bean id="people" class="com.ljl.pojo.People" autowire="byType">
        <property name="name" value="大林"/>
<!--        <property name="dog" ref="dog"/>-->
<!--        <property name="tiger" ref="tiger"/>-->
    </bean>

</beans>
import com.ljl.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void test(){

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

        People people = context.getBean("people", People.class);

        people.getDog().shout();
        people.getTiger().shout();
    }
}

6.2使用注解实现自动装配

jdk1.5支持的注解,spring2.5支持的注解

  • 注解 在声明中提供了很多上下文,从而使配置更短,更简洁
  • XML 擅长连接组件而不接触其源代码或重新编译它们。一些开发人员更喜欢将布线放置在靠近源的位置,而另一些开发人员则认为带注解的类不再是 POJO,而且,该配置变得分散且难以控制。
  • 无论选择如何,Spring 都可以容纳两种样式,甚至可以将它们混合在一起。值得指出的是,通过其JavaConfig选项,Spring 允许以非侵入方式使用 注解,而无需接触目标组件的源代码,并且就工具而言,Spring 工具套件支持所有配置样式。

6.2.1使用注解环境搭建

  1. 导入约束:context约束
  2. 配置注解的支持:context:annotation-config/
<?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">

    <context:annotation-config/>

</beans>

6.2.2@Autowired

直接在属性上使用,也可以在set方法上使用

@Autowired
public void setDog(Dog dog) {
    this.dog = dog;
}

@Autowired
public void setTiger(Tiger tiger) {
    this.tiger = tiger;
}

6.2.3@Qualifier

当@Autowired装配环境复杂时,即无法通过这一个注解完成自动装配时,我们可以借助@Qualifier(value=“xxx”)来配合使用指定唯一的bean值注入问题

<bean id="dog111" class="com.ljl.pojo.Dog"/>
<bean id="dog1111" class="com.ljl.pojo.Dog"/>
<bean id="tiger11" class="com.ljl.pojo.Tiger"/>
<bean id="tiger111" class="com.ljl.pojo.Tiger"/>
@Autowired
@Qualifier(value = "dog1111")
public void setDog(Dog dog) {
    this.dog = dog;
}

@Autowired
@Qualifier(value="tiger111")
public void setTiger(Tiger tiger) {
    this.tiger = tiger;
}

6.2.4@Resource(建议使用)

用法类似于@Qualifier和@Autowired配合在一起使用,可以自动装配,还能通过那么属性寻找唯一的bean值注入

 @Resource(name="dog1111")
 public void setDog(Dog dog) {
     this.dog = dog;
 }

@Resource(name="tiger111")
 public void setTiger(Tiger tiger) {
     this.tiger = tiger;
 }

7.使用注解开发

1.bean

@Component
public class User {

2.属性如何注入

 @Value("大林")
private String name;

3.衍生的注解

这三个注解用法类似于实体类的@Conponent 只是为了规范化做了每个类用不同的注解名

  • dao
@Repository
public class UserDao {
  • service
@Service
public class UserService {
}
  • controller
@Controller
public class UserController {
}

4.自动装配注解

前面个讲过了

5.作用域

@Scope(value = "singeltod")
public class User {

6.小结

xml与注解:

  • xml更加万能,适用于任何场合,更易于维护
  • 注解不是自己的类用不了,维护相对负责

xml与注解最佳实践:

  • xml用来管理bean
  • 注解用来属性的注入
  • 使用过程中只需要注意必须让注解生效

8.代理模式

代理模式就是springAOP的底层

代理模式分类:

  • 静态代理

  • 动态代理

9.AOP

9.1SpringAPI接口实现AOP

<!--&lt;!&ndash;配置Bean&ndash;&gt;-->
    <bean id="userServiceImpl" class="com.ljl.service.UserServiceImpl"/>
    <bean id="afterLog" class="com.ljl.log.AfterLog"/>
    <bean id="beforeLog" class="com.ljl.log.BeforeLog"/>

<!--&lt;!&ndash;  方式一:原生SpringAPI&ndash;&gt;-->
<!--&lt;!&ndash;aop配置&ndash;&gt;-->
    <aop:config>
<!--&lt;!&ndash; 切入点  expression:表达式  execution(要执行的位置) :修饰符 返回值 类名 方法名 参数&ndash;&gt;-->
        <aop:pointcut id="pointcut" expression="execution(* com.ljl.service.UserServiceImpl.*(..) )"/>
<!--&lt;!&ndash;    环绕执行&ndash;&gt;-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

9.2自定义类实现AOP

 <bean id="diyPointCut" class="com.ljl.diy.DiyPointCut"/>
  <bean id="userServiceImpl" class="com.ljl.service.UserServiceImpl"/>

<!--    方拾二:自定义类-->
    <aop:config>
<!--   自定义切面 ref:要应用的类-->
        <aop:aspect ref="diyPointCut">
<!--     切入点  expression:表达式  execution(要执行的位置) :修饰符 返回值 类名 方法名 参数-->
            <aop:pointcut id="point" expression="execution(* com.ljl.service.UserServiceImpl.*(..))"/>
          <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

9.3使用注解实现AOP

<!--    方式三:使用注解实现AOP-->
<context:component-scan base-package="com.ljl"/>
    <context:annotation-config></context:annotation-config>
    <aop:aspectj-autoproxy />
package com.ljl.anno;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class annotationAOP {

    @Before("execution(* com.ljl.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("===执行方法前===");
    }
    @After("execution(* com.ljl.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("===执行方法后===");
    }

}

10.整合Mybatis

步骤:

1.导入相关jar包

  • junit
  • mysql
  • mybatis
  • spring
  • aop织入
  • mybatis-spring【new】

2.编写配置文件

3.测试

10.1Mybatis-Spring

11.声明式事务

11.1

11.2Spring中的事务管理

  • 声明式事务:AOP(常用)
  • 编程式事务:代码中进行事务的管理

配置事务的原因:

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果我们不在Spring中配置声明式事务,就需要在代码中手动声明事务
  • 事务在项目开发中十分重要,涉及到数据库的一致性和完整性问题,不容马虎!
<!--   配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>

<!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--    给哪些方法配置事务-->
        <tx:attributes>
            <tx:method name="add"/>
            <tx:method name="deleteUser"/>
<!--   所有方法加事务   propagation:传播 即事务的传播特性  默认REQUIRED-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--   结合AOP实现事务的织入-->
    <aop:config>
<!--    配置事务切入点-->
        <aop:pointcut id="txPointcut" expression="execution(* com.ljl.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

<!--    -->
事务在项目开发中十分重要,涉及到数据库的一致性和完整性问题,不容马虎!

```xml
<!--   配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="dataSource" />
    </bean>

<!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--    给哪些方法配置事务-->
        <tx:attributes>
            <tx:method name="add"/>
            <tx:method name="deleteUser"/>
<!--   所有方法加事务   propagation:传播 即事务的传播特性  默认REQUIRED-->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

<!--   结合AOP实现事务的织入-->
    <aop:config>
<!--    配置事务切入点-->
        <aop:pointcut id="txPointcut" expression="execution(* com.ljl.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

<!--    -->
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值