自学Spring的笔记和总结

Spring:实现模块间,类之间的解耦合(重点技术:IOC控制反转和AOP面向切面编程)

 官网:Spring.io

一、IOC(技术核心-DI:依赖注入)

概念:把对象的创建,赋值,管理工作都交给代码之外的容器实现

控制:创建对象,对象赋值,对象之间的关系控制

反转:把管理对象的权限交付给代码之外的容器(容器是一个服务器软件或者一个框架)

正转:开发人员new对象,主动控制对象

二、简单Spring的创建

首先,创建一个新的空工程,创建一个在本项目中的Maven模块,在模块的建立过程中把代码的包名设置好(com.node),进入界面后,在main的包下Alt+Insert建立一个resources(mark as resources root);当中自动生成的java文件可以随意删除;在pom.xml中修改JDK为1.8,依赖中添加spring依赖(如下图);在包中创建包名service创建一个接口,并后缀Impl实现该接口;在resources中建立spring config(其中代码如下图)---把完成的spring config复制倒target.classes的目录下(具体原因参见下图);最后在test包中创建实例进行检测。

pom.xml文件中
    <!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>



spring config文件(本次命名为beans.xml)
<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">
    <!--
        告诉spring创建对象
        声明bean 告诉spring要船舰某个类的对象
        id:对象的自定义名称,唯一值,spring通过这个找到对象
        class:类的全限定名称(不能是接口,因为反射机制创建对象,必须使用类)

        spring 完成 SomeService sonmeService = new SomServiceImpl();
        spring是把创建好的对象放入map中,spring框架有一个map存放对象
        springMap.put(id,对象);
          eg:springMap.put("someservice",new SomServiceImpl());
         一个bean创建一个对象
    -->
    <bean id="someservice" class="com.node.service.impl.SomeServiceImpl"/>
</beans>
<!--
    spring的配置文件
    1.beans:根标签,spring把Java对象称为bean。
    2.spring-beans.xsd是约束文件,和mybatis dtd相似。更强的约束文件
-->

spring对象的数量和名称查询

String config="beans.xml";
        ApplicationContext ac = new ClassPathXmlApplicationContext(config);

        //使用spring提供的方法,获取容器中定义的对象数量
        int nums = ac.getBeanDefinitionCount();
        System.out.println(nums);
        //容器每个定义对象的名称
        String names[]=ac.getBeanDefinitionNames();
        for (String name:names){
            System.out.println(name);
        }

三、DI(依赖注入)

1.set注入:

        简单类型:Java的基本数据类型和String类型

        1)简单类型注入

<bean id="xx" class="xx">
     <property name="属性名" value="此属性的值"/>
</bean>

        2)引用类型注入

            <bean id="xx" class="xx">
                <property name="属性名" ref="bean的id"/>
            </bean>

2.构造注入(spring调用类的有参构造)

<constructor-arg>标签:一个代表一个构造方法的参数
<constructor-arg>标签属性:
    name:构造方法的形参名
    index:构造方法的参数位置从0开始
    value:构造方法形参的数据类型为 简单类型
    ref:数据类型为 引用类型
    <bean id="myStudent" class="com.node.k03.Student">
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="20"/>
        <constructor-arg name="school" ref="mySchool"/>
    </bean>
    <!--index的使用-->
    <bean id="myStudent2" class="com.node.k03.Student">
        <constructor-arg index="0" value="李四"/>
        <constructor-arg index="1" value="30"/>
        <constructor-arg index="2" ref="mySchool"/>
    </bean>
    <!-- 声明school对象 -->
    <bean id="mySchool" class="com.node.k03.School">
        <property name="name" value="华师"/>
        <property name="address" value="广州"/>
    </bean>
<!--创建File,使用构造注入-->
    <bean id="myfile" class="java.io.File">
        <constructor-arg name="parent" value="H:\学习作业\JAVA\SpringBaseStudy\ch02-di-xml"/>
        <constructor-arg name="child" value="readme.txt"/>
    </bean>

3、ByName和ByType

引用类型的自动注入:spring框架根据某些规则给引用类型赋值。不用给引用类型赋值了
使用规则 byName,byType
1.byName(按名称注入):Java类中引用类型的属性名和sprig容器中(配置文件)<bean>的id名称一样
                    且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型
2.byType(按类型注入):Java类中引用类型的数据类型和spring容器中(配置文件)<bean>的class属性时同源关系的,
                    这样的bean能够赋值给引用类型
同源:1.Java类中引用类型的数据类型和class的值是一样的。
     2.Java类中引用类型的数据类型和class的值是父子类关系。
     3.Java类中引用类型的数据类型和class的值是接口和实现类关系的。

1.byName

    <!--byName-->
    <!--byName方法只与set方法有关,set方法后的名称与bean的id需要设置成一致-->
    <bean id="myStudent" class="com.node.k04.Student" autowire="byName">
        <property name="name" value="李四"/>
        <property name="age" value="22"/>
        <!-- 引用类型 -->
        <!--<property name="school" ref="mySchool"/>-->
    </bean>
    <!-- 声明school对象 -->
    <!--sch和Student类中声明的学校对象的名字一致-->
    <bean id="sch" class="com.node.k04.School">
        <property name="name" value="华师"/>
        <property name="address" value="广州"/>
    </bean>

2.byType

    <!--byType-->
    <bean id="myStudent" class="com.node.k05.Student" autowire="byType">
        <property name="name" value="李四"/>
        <property name="age" value="22"/>
        <!-- 引用类型 -->
        <!--<property name="school" ref="mySchool"/>-->
    </bean>

    <!-- 声明school对象 -->
    <!--<bean id="mysch" class="com.node.k05.School">
        <property name="name" value="华师"/>
        <property name="address" value="广州"/>
    </bean>-->
    <!-- 声明school子类对象 -->
    <bean id="primarysch" class="com.node.k05.PrimarySchool">
        <property name="name" value="华师"/>
        <property name="address" value="广州"/>
    </bean>

3.spring配置文件的整合

        1)student配置文件

<!--    student 模块 所有bean的声明-->
    <!--byType-->
    <bean id="myStudent" class="com.node.k06.Student" autowire="byType">
        <property name="name" value="李四"/>
        <property name="age" value="30"/>
        <!-- 引用类型 -->
        <!--<property name="school" ref="mySchool"/>-->
    </bean>

        2)school配置文件

    <!--  school 模块 所有bean的声明-->
    <!--byType-->
    <!-- 声明school对象 -->
    <bean id="sch" class="com.node.k06.School">
        <property name="name" value="华师大"/>
        <property name="address" value="广州天河"/>
    </bean>

        3)总配置文件

<!--
    包含关系的配置文件:
        spring-total表示主配置文件:包含其他配置文件,主文件一般不定义对象
        语法:<import resource="其他配置文件的路径"/>
        关键字:"classpath" 表示类路径(class文件所在的目录),
                          在spring的配置文件中指定其他问价的位置
                          需要使用classpath,告诉spring到哪去加载读取文件。
     -->
    <!--加载是文件列表-->
    <!--<import resource="classpath:k06/spring-school.xml"/>
    <import resource="classpath:k06/spring-student.xml"/>-->

    <!--
        在包含关系的文件中,可以使用通配符 *表示任意字符
        注意主文件不要加入范围  避免自我匹配 (所以spring-s*.xml)
    -->
    <import resource="classpath:k06/spring-s*.xml"/>

四、注解(anno)

配置文件applicationContext.xml的使用

<!--    声明组件扫描器(component-scan),组件就是java对象
        base-package:指定注解在你的项目中的包名。
        component-scan工作方式:spring会扫描遍历base-package指定的包,
        把包中和子包中的所有类,找到类中的注解,按照注解的功能创建对象,或给属性赋值
-->

    <context:component-scan base-package="com.Gcompany.node.k01"/>
<!--   指定多个包的三种方式 -->
<!--    第一种:使用多次组件扫描器,指定不同的包-->
    <context:component-scan base-package="com.Gcompany.node.k01"/>
    <context:component-scan base-package="com.Gcompany.node.k02"/>

<!--    第二种:使用分隔符(;或,)分隔多个包名-->
    <context:component-scan base-package="com.Gcompany.node.k01;com.Gcompany.node.k02"/>
    <!--     第三种:指定父包-->
    <context:component-scan base-package="com.Gcompany.node"/>

**<context:component-scan base-package="包全名"/>

1.@Component

/**
 *      @Component 创建对象的,等同于<bean>的功能
 *
 *      属性:value 就是对象的名称,也就是bean的id值,
 *           value的值是唯一的,创建的对象在整个spring容器中就一个
 *      位置:类的上面
 *
 *      @Component(value="myStudent")
 *      =<bean id="myStudent" class="com.Gcompany.node.k01.Student"/>
 *
 *
 *      spring中和@Component功能一致,创建对象的注解滑油:
 *      1.@Repository(用在持久层类上面):放在dao实现类上面,表示创建dao对象,dao对象是能访问数        
                                         据库的。
 *      2.@Service(用在业务层类上面):放在service的实现类上面,创建service对象,
 *                                  service是做业务处理
 *      3.@Controller(用在控制器类上面):创建控制器对象
 *                                     控制器对象,能够接受用户提交的参数,显示请求的处理结果
 *
 *      以上三个注解的使用语法和@Component一样的。都能创造对象,但是这三个注解有额外功能。
 *
 *      @Repository,@Service,@Controller是给项目的对象分层的。
 *
 */

2.@value

    /**
     * @value 简单类型的属性赋值
     *  属性:value是String类型的,表示简单类型的属性值
     *  位置:1.在属性定义的上面,无需set方法,推荐使用
     *      2.在set方法上面
     */

3.@Autowired

引用类型也需要使用@Component创建实例对象且可选择@value赋值

    /**
     * 引用类型
     * @Autowired:spring框架提供的注解,实现引用类型的赋值
     * spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName、byType
     *
     * @Autowired:默认使用byType
     * 位置:1)属性定义的上方,无需set方法  推荐使用
     *      2)set方法上
     *
     * 使用byName方式:1.在属性上方加入@Autowired
     *               2.在属性上加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值
     * 
     * 两个注解没有先后顺序问题
     */

4.@Resource

    /**
     * 引用类型
     * @Resource:来自JDK中的注解,spring框架提供了对这个注解的功能支持,可以使用它给的引用类型赋值
     *            使用的也是自动注入原理,支持byName,byType。默认是byName
     *位置:1.属性定义的上面,无需set
     *     2.set方法上面
     *
     * @Resource只使用byName方式,需要增加一个属性
     * name的值为bean的id
     */
eg:    @Resource(name = "mySchool")//仅使用byName

    //默认是byName:先使用byName自动注入,如果赋值失败,再使用byType

五、aspectj(面向切面的框架)AOP框架

主配置文件的建立

<!--    把对象交给spring容器,由spring容器统一创建,管理对象-->
<!--    声明目标对象-->
    <bean id="myService" class="com.GCompany.node.k03.SomeServiceImpl"/>
    
    <!--    声明切面对象-->
    <bean id="myAspect" class="com.GCompany.node.k03.MyAspect"/>
    
<!--声明自动代理生成器,使用aspectj框架内部的功能,
    创建代理对象是在内存中实现,修改目标对下那个的内存中的结构。创建为代理对象
    所以目标对象就是被修改后的代理对象

    <aop:aspectj-autoproxy />:会把spring容器内中的有所目标对象,一次性都生成代理对象
-->
    <!--
        <aop:aspectj-autoproxy proxy-target-class="true"/>告诉spring框架使用gclib代理
    -->
<!--    <aop:aspectj-autoproxy />-->
   <aop:aspectj-autoproxy proxy-target-class="true"/>

使用AOP框架aspectJ时需要在需要创造ASpect的类上加上注解@Aspect

1.@Before(前置通知)

/**
     * 定义方法:方法实现功能。
     * 方法定义要求:
     * 1.公共方法public
     * 2.方法没有返回值
     * 3.方法名称自定义
     * 4.方法可以存在参数
     *      若存在参数,参数不是自定义的,有几个参数类型可以使用。
     */

    /**
     * @Before: 前置通知注解
     *  属性:value 是切入点表达式,表示切面的功能执行的位置
     *  位置:切面方法的上面
     *  特点:
     *  1.目标方法前执行
     *  2.不影响不改变目标方法的执行和结果
     */
//    @Before(value = "execution(public void com.GCompany.node.k01.SomeServiceImpl.doSome(String, Integer))")
//    public void myBefore(){
//        //切面功能
//        System.out.println("切面功能:在目标方法执行之前输出时间"+new Date());
//    }


//    @Before(value = "execution(void *..SomeServiceImpl.do*(..))")
//    public void myBefore(){
//        //切面功能
//        System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
//    }

    /**
     * 指定通知方法中的参数:JoinPoint
     * JoinPoint:业务方法(要加入切面功能的业务方法)
     *      作用: 可以在通知方法中获取方法执行时的信息,例如方法名称,方法实参
     *      如果你的切面功能中需要用到方法的信息,就加入joinpoint,
     *      这个joinpoint参数的值由框架赋予,必须第一个位置的参数
     */
    @Before(value = "execution(public void *..SomeServiceImpl.do*(..))")
    public void myBefore(JoinPoint jp){
        //使用PJ获取方法的完整定义
        System.out.println("方法的签名="+jp.getSignature());
        System.out.println("方法的名称="+jp.getSignature().getName());
        //获取方法的实参
        Object[] args = jp.getArgs();
        for (Object obj : args) {
            System.out.println("参数="+obj);
        }

        //切面功能
        System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
    }

2.@AfterReturning(后置通知)

/**
     * 后置定义方法:方法实现功能。
     * 方法定义要求:
     * 1.公共方法public
     * 2.方法没有返回值
     * 3.方法名称自定义
     * 4.方法有参数
     *      参数推荐Object,参数名自定义
     */

    @Before(value = "execution(public void *..SomeServiceImpl.do*(..))")
    public void myBefore(JoinPoint jp){
        //使用PJ获取方法的完整定义
        System.out.println("方法的签名="+jp.getSignature());
        System.out.println("方法的名称="+jp.getSignature().getName());
        //获取方法的实参
        Object[] args = jp.getArgs();
        for (Object obj : args) {
            System.out.println("参数="+obj);
        }

        //切面功能
        System.out.println("1切面功能:在目标方法执行之前输出时间"+new Date());
    }

    /**
     * @AfterReturning:后置通知
     *      属性:1.value :切入点表达式
     *           2.returning:自定义的变量,表示目标方法的返回值
     *              自定义变量名必须和通知方法的形参名一样。
     *      位置,方法定义的上面
     *      特点:
     *      1.在目标方法之后执行的
     *      2.能够获取到目标方法的返回值,根据返回值做不同的处理功能
     *          Object res = doOther
     *      3.可以修改返回值
     *
     *
     *      后置通知的执行顺序
     *          Object res = doOther();
     *          myAfterReturning(res);
     *
     */
    @AfterReturning(value = "execution(* com.GCompany.node.k02.SomeServiceImpl.doOther(..))",
            returning ="res" )
    public void myAfterReturning(JoinPoint jp,Object res){
        // res :是目标方法的返回值,根据返回值做切面处理
        System.out.println(jp.getSignature());
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);

        //修改目标方法的返回值  不影响String类型最后的调用结果
        if(res!=null){
            res="hello";
        }

    }
    //修改目标方法的引用类型的返回值  影响最后的调用结果
    @AfterReturning(value = "execution(* com.GCompany.node.k02.SomeServiceImpl.doOther1(..))",
            returning ="res" )
    public void myAfterReturning1(Object res){
        // res :是目标方法的返回值,根据返回值做切面处理
        System.out.println("后置通知:在目标方法之后执行的,获取的返回值是:"+res);
        //改变返回对象的值  引用类型
        Student stu= (Student) res;
        stu.setName("张三");
        stu.setAge(18);
    }

3.@Around(环绕通知)

/**
     * 环绕通知定义方法:方法实现功能。
     * 方法定义要求:
     * 1.公共方法public
     * 2.方法有返回值 推荐使用Object
     * 3.方法名称自定义
     * 4.方法有参数 固定的参数 ProceedingJoinPoint
     *
     *
     *      环绕通知==JDK的动态代理,InvocationHandler接口
     *
     *      参数:ProceedingJoinPoint 就等同于Method
     *              作用:执行目标方法的
     *      返回值:就是目标方法的执行结果,可被修改
     */
    /**
     * @Around:环绕通知
     *      属性:value(切入点表达式)
     *
     *      特点:
     *      1.功能最强的通知
     *      2.在目标方法前后都能增强
     *      3.控制目标方法是否被调用执行
     *      4.可修改原来的目标方法的执行结果,影响最后的调用结果
     *

     */
    @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))")
    public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
        String name="";
        //获取第一个参数的值
        Object[] args = pjp.getArgs();
        if(args!=null && args.length>1){
            Object arg = args[0];
            name = (String)arg;
        }

        //实现环绕通知的功能
        Object result = null;
        System.out.println("环绕通知前:"+new Date());
        //1.目标方法调用
        if("zhangsan".equals(name)){
            //符合条件
            result = pjp.proceed();//method.invoke(); Object result = doFirst();
            System.out.println("目标方法调用后返回值:"+result);
        }

        System.out.println("环绕通知后:提交事务");
        //2.在目标方法的前后键入功能


        //修改目标方法的执行结果
        if(result!=null){
            result="Hello AspectJ";
        }

        //返回目标方法的执行结果
        return result;
    }

**使用pjp.proceed();实现事务方法的调用:原理为:method.invoke();

(可在无接口类中使用)

4.@Pointcut

   @Before(value = "pct()")
    public void myBefore(){
        System.out.println("事务处理前输出时间:"+new Date());
    }


    @Pointcut(value = "execution(* com.GCompany.node.k05.SomeServiceImpl.doSome(..))")
    private void pct(){}

==================================分隔线==================================

一、spring和mybatis整合

/*mybatis复习:

①Maven配置文件导入mybatis、junit、mysql驱动依赖且在build中配置resources,防止资源导出失败

    <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!--在build中配置resources,来防止我们资源导出失败的问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resoures</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

②在resources文件中创建核心配置文件(数据库连接及Mapper配置文件的注册)-mybatis主配置文件

<!--核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=GMT%2B8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册!!!-->
    <mappers>
        <mapper resource="com/GHcode/dao/UserMapper.xml"/>
    </mappers>
</configuration>

③创建工具类MybatisUtils获取SqlsessionFactory对象进一步获取SqlSession对象

    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

④创建domain实体类(实体类的属性必须与数据库的表数据对应)

⑤创建对象的Mapper接口添加数据库的操作功能

⑥配置Mapper.xml文件(注意namespace的包名)

<!--namespace绑定一个指点的Dao/Mapper接口-->
<mapper namespace="com.GHcode.dao.UserMapper">
    <!--查询语句-->
    <select id="getUserList" resultType="com.GHcode.pojo.User">
        select * from mybatis.user;
    </select>
    <!--模糊查询-->
    <select id="getUserLike" resultType="com.GHcode.pojo.User">
        select * from mybatis.user where name like "%"#{value}"%"
    </select>
    <!--通过ID查对象-->
    <select id="getUserById" parameterType="int" resultType="com.GHcode.pojo.User">
        select * from mybatis.user where id = #{param};
    </select>
    <!--通过其他非主键信息查对象-->
    <select id="getUserByOther" parameterType="map" resultType="com.GHcode.pojo.User">
        select * from mybatis.user where name=#{name} and pwd=#{pwd};
    </select>

    <!--增加对象-->
    <insert id="addUser" parameterType="com.GHcode.pojo.User">
        insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd});
    </insert>
    <insert id="addUser2" parameterType="map">
        insert into mybatis.user(id, name, pwd) values (#{userid},#{username},#{userpwd});
    </insert>

    <!--更新对象-->
    <update id="updateUser" parameterType="com.GHcode.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
    </update>

    <!--删除对象-->
    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id};
    </delete>
</mapper>

*/

**

二、整合mybatis的spring

1、Maven主配置文件添加依赖和build

    <dependencies>
    <!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--做spring事务-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql驱动配置-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.27</version>
    </dependency>
    <!--mybatis配置-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.2</version>
    </dependency>
    <!--junit测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--国内阿里公司连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
  </dependencies>

  <build>
    <!--目的是把src/main/resoures/java目录中的文件包含到输出结果中,输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes><!--包括目录下的.properties.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>

      <resource>
        <directory>src/main/resoures</directory>
        <includes><!--包括目录下的.properties.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    <!--指定jdk版本-->
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

2、创建实体类

3、创建对象Mapper接口和Mapper配置文件

public interface StudentMapper {
    int insertStudent(Student student);
    List<Student> selectStudentAll();
}
<mapper namespace="com.GHcode.mapper.StudentMapper">
    <select id="selectStudentAll" resultType="com.GHcode.domain.Student">
        select * from springdb.student order by id desc
    </select>
    <insert id="insertStudent">
        insert into student values(#{id},#{name},#{email},#{age})
    </insert>
</mapper>

4、创建Service接口及对应的实现类

/*Service接口*/
package com.GHcode.service;
import com.GHcode.domain.Student;
import java.util.List;
public interface StudentService {
    int addStudent(Student student);

    List<Student> queryStudents();
}


/*Service接口实现类Impl*/
package com.GHcode.service.impl;
import com.GHcode.domain.Student;
import com.GHcode.mapper.StudentMapper;
import com.GHcode.service.StudentService;

import java.util.List;

public class StudentServiceImpl implements StudentService {
    //引用类型Dao
    private StudentMapper studentMapper;
    //使用set注入  赋值
    public void setStudentMapper(StudentMapper studentMapper) {
        this.studentMapper = studentMapper;
    }
    @Override
    public int addStudent(Student student) {
        return studentMapper.insertStudent(student);
    }
    @Override
    public List<Student> queryStudents() {
        return studentMapper.selectStudentAll();
    }
}

5、mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--设置别名-->
    <typeAliases>
        <!--name:实体类所在的包名-->
        <package name="com.GHcode.domain"/>
    </typeAliases>

    <!--sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--
            name:是包名,包中所有mapper.xml一次都能加载
        -->
        <package name="com.GHcode.mapper"/>
    </mappers>
</configuration>

*6、主配置文件applicationContext.xml(重要的是 数据源DataResoures、SqlSessionFactory类、Mapper对象、Service对象)

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


    <!--声明数据源DataSource,作用是连接数据库-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--使用set注入,给DruidDataSource提供连接数据库的信息-->
        <property name="url" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=GMT%2B8"/><!--GMT%2B8-->
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="20"/>
    </bean>

    <!--声明的是mybatis中所提供的sqlsessionfactoryBean类,这个类用来创建sqlsessionfactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给了dataSource属性-->
        <property name="dataSource" ref="myDataSource"/>

        <!--myBatis主配置文件的位置
            configLocation属性是Resource类型  读取配置文件
            它的赋值使用value,指定文件的路径,classpath表示文件的位置
        -->
        <!--在spring配置文件中,指定其他文件路径,要使用classpath-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--创建Dao/Mapper对象,使用SqlSession的getMapper(StudentMapper.class)-->
    <!--
        MapperScannerConfigurer:在内部调用getMapper()方法生成每个dao/mapper接口代理对象。

    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

        <!--指定Dao/Mapper包名  包名为接口所在的包名
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper;
            得到每个接口的Dao/Mapper对象
            创建的对象放到spring容器中
        -->
        <property name="basePackage" value="com.GHcode.mapper"/><!--多个包用逗号分隔-->
    </bean>

    <!--声明service-->
    <bean id="studentService" class="com.GHcode.service.impl.StudentServiceImpl">
        <property name="studentMapper" ref="studentMapper"/>
    </bean>

</beans>

处理事务

1、声明事务处理器实现类

2、说明需要事务的类型

        1)事务的隔离级别

        DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ;

         Oracle默认为 READ_COMMITTED。
        ➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
        ➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
        ➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
        ➢ SERIALIZABLE:串行化。不存在并发问题。

        2)事务的超时时间:表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。单位是秒, 整数值, 默认是 -1. 

        3)事物的传播行为

            PROPAGATION_REQUIRED
            PROPAGATION_REQUIRES_NEW
            PROPAGATION_SUPPORTS
            以上三个需要掌握的

            PROPAGATION_MANDATORY
            PROPAGATION_NESTED
            PROPAGATION_NEVER
            PROPAGATION_NOT_SUPPORTED

三、spring-trans-anno(注解)

@Transactional

public class BuyGoodsServiceImpl implements BuyGoodsService {
    private SaleDao saleDao;
    private GoodsDao goodsDao;

    /**
     * rollbackFor:表示发生的指定异常一定回滚
     *
     */
    /*@Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {
                    NullPointerException.class,NotEnoughException.class
            }
    )*/
    //直接写Transactional的默认值就是以上的
    //使用的是事务控制的默认值,默认的传播行为是REQUIRED,默认的隔离级别是DEFAULT
    //默认抛出运行时异常,回滚事务
    @Transactional
    @Override
    public void buy(int goodsId, int nums) {
        System.out.println("===========buy方法的开始=============");
        //记录销售信息
        Sale sale = new Sale();
        sale.setGid(goodsId);
        sale.setNums(nums);
        saleDao.insertSale(sale);

        //更新库存
        Goods goods = goodsDao.selectGoods(goodsId);
        if(goods==null){
            //商品不存在
            throw new NullPointerException("编号是:"+goodsId+"商品不存在");
        }else if(goods.getAmount()<nums){
            //商品不足
            throw new NotEnoughException("编号是:"+goodsId+"商品库存不足");
        }
        //修改库存了
        Goods buyGoods = new Goods();
        buyGoods.setId(goodsId);
        buyGoods.setAmount(nums);
        goodsDao.updateGoods(buyGoods);

        System.out.println("===========buy方法的完成=============");

    }

    public void setSaleDao(SaleDao saleDao) {
        this.saleDao = saleDao;
    }

    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }

}

四、spring-trans-aspectj(aop切面)

1、applicationContext配置文件(补充)

 <!--1.   声明式事务处理:和源代码完全分离-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="myDataSource"/>
    </bean>

    <!--2.   声明业务方法它的事务属性(隔离级别、传播行为、超时时间)-->
    <!--
           id:表示自定义名称,表示tx:advice 和 <\tx:aadvice>之间的配置内容
            transaction-manager:事务管理器对象的id
    -->
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <!--  tx:attributes:配置事务的属性  -->
        <tx:attributes>
            <!--tx:method:给具体的方法配置事务属性  method可以有多个,分别给不同的方法设置事务属性
                name:方法名称,1)完整的方法名称,不带有包和类
                             2)方法可以使用通配符,*表示任意字符

                propagation:传播行为
                isolation:隔离级别
                rollback-for:指定的异常类,全限定类型;发生异常一定回滚
            -->
            <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
                       rollback-for="com.GHcode.excep.NotEnoughException,
                       java.lang.NullPointerException"/>

            <!--使用通配符,指定很多的方法-->
            <tx:method name="add*" propagation="REQUIRES_NEW"/>
            <tx:method name="notify*" propagation="REQUIRES_NEW"/>
            <tx:method name="remove*" propagation="REQUIRED"/>
            <!--查询方法-->
            <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!--配置aop-->
    <aop:config>
        <!--切入点表达式:指定哪个包中类,要使用事务
            id:切入点表达式的名称,唯一值
            expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象

            若包中有许多包名都为service则需要指定所需的包
            com.GHcode.service
            com.crm.service
            com.service

        -->
        <aop:pointcut id="servicept" expression="execution(* *..service.*.*(..))"/>

        <!--配置增强器:关联advice和pointcut
            advice-ref:通知,上面tx:advice那里的配置
            pointcut-ref:切入点表达式的id
        -->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="servicept"/>
    </aop:config>

五、在web中使用spring,完成注册

1、创建maven,web项目

2、加入依赖(主要是servlet、jsp、监听器对象依赖)

<dependencies>
    <!--servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!--jsp依赖-->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
      <scope>provided</scope>
    </dependency>
    <!--监听器对象依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>


    <!--spring依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--做spring事务-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql驱动配置-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.27</version>
    </dependency>
    <!--mybatis配置-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.2</version>
    </dependency>
    <!--junit测试-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--国内阿里公司连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
  </dependencies>

  <build>
    <!--目的是把src/main/resoures/java目录中的文件包含到输出结果中,输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes><!--包括目录下的.properties.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>

      <resource>
        <directory>src/main/resoures</directory>
        <includes><!--包括目录下的.properties.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    <!--指定jdk版本-->
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

3、mybatis-config、spring(applicationContext)配置文件

mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--核心配置文件-->
<configuration>

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--设置别名-->
    <typeAliases>
        <!--name:实体类所在的包名-->
        <package name="com.GHcode.domain"/>
    </typeAliases>

    <!--sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--
            name:是包名,包中所有mapper.xml一次都能加载
        -->
        <package name="com.GHcode.mapper"/>
    </mappers>
</configuration>




spring.xml
<!--
        把数据库的配置信息,写在一个独立的文件中,编译修改数据库的配置内容
        spring直到jdbc.properties文件的位置
        <context:property-placeholder location="classpath:jdbc.properties"/>
    -->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!--声明数据源DataSource,作用是连接数据库-->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--使用set注入,给DruidDataSource提供连接数据库的信息-->
        <!--
            使用属性配置文件中的数据,语法${key}
        -->
     <!--   <property name="url" value="jdbc:mysql://localhost:3306/springdb?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF8&amp;serverTimezone=GMT%2B8"/>&lt;!&ndash;GMT%2B8&ndash;&gt;
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
        <property name="maxActive" value="20"/>-->

        <property name="url" value="${jdbc.url}"/><!--GMT%2B8-->
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.pwd}"/>
        <property name="maxActive" value="${jdbc.max}"/>
    </bean>

    <!--  声明的是mybatis中所提供的sqlsessionfactoryBean类,这个类用来创建sqlsessionfactory  -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给了dataSource属性-->
        <property name="dataSource" ref="myDataSource"/>

        <!--myBatis主配置文件的位置
            configLocation属性是Resource类型  读取配置文件
            它的赋值使用value,指定文件的路径,classpath表示文件的位置
        -->
        <!--在spring配置文件中,指定其他文件路径,要使用classpath-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--创建Dao/Mapper对象,使用SqlSession的getMapper(StudentMapper.class)-->
    <!--
        MapperScannerConfigurer:在内部调用getMapper()方法生成每个dao/mapper接口代理对象。

    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

        <!--指定Dao/Mapper包名  包名为接口所在的包名
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper;
            得到每个接口的Dao/Mapper对象
            创建的对象放到spring容器中
        -->
        <property name="basePackage" value="com.GHcode.mapper"/><!--多个包用逗号分隔-->
    </bean>

    <!--声明service-->
    <bean id="studentService" class="com.GHcode.service.impl.StudentServiceImpl">
        <property name="studentMapper" ref="studentMapper"/>
    </bean>



jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/springdb?serverTimezone=GMT%2B8
jdbc.username=root
jdbc.pwd=123456
jdbc.max=20
        
只剩下时区就对了

4、创建一个jsp发起请求,有参数id,name,email,age.

5、创建Servlet,接受请求参数,调用Service,调用dao完成注册

public class RegisterServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        request.setCharacterEncoding("UTF-8");

        String strId = request.getParameter("id");
        String strName = request.getParameter("name");
        String strEmail = request.getParameter("email");
        String strage = request.getParameter("age");

        //创建spring的容器对象
        String config = "spring.xml";
        //ApplicationContext ac = new ClassPathXmlApplicationContext(config);


        WebApplicationContext ctx = null;
        //获取ServletContext中的容器对象,创建好的容器对象,拿来就用
        /*String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
        Object attr = getServletContext().getAttribute(key);
        if (attr!=null){
            ctx= (WebApplicationContext) attr;
        }
        */

        //使用框架中的方法,获取容器对象
        ServletContext sc = getServletContext();
        ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
        System.out.println("容器对象的信息======"+ctx);



        //获取service
        StudentService service = (StudentService) ctx.getBean("studentService");
        Student student = new Student();
        student.setId(Integer.parseInt(strId));
        student.setName(strName);
        student.setEmail(strEmail);
        student.setAge(Integer.parseInt(strage));
        service.addStudent(student);

        //给出一个页面
        request.getRequestDispatcher("/result.jsp").forward(request,response);

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

6、创建jsp作为显示结果页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
        <p>注册学生</p>
        <form action="reg" method="post">
            <table>
                <tr>
                    <td>id</td>
                    <td><input type="text" name="id"></td>
                </tr>
                <tr>
                    <td>姓名</td>
                    <td><input type="text" name="name"></td>
                </tr>
                <tr>
                    <td>email</td>
                    <td><input type="text" name="email"></td>
                </tr>
                <tr>
                    <td>年龄</td>
                    <td><input type="text" name="age"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="注册学生"></td>
                </tr>
            </table>
        </form>
</body>
</html>

result.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    result.jsp 注册成功
</body>
</html>


7、配置Tomcat(详细CSDN)

--------------------------------------------------------------------------暂停更新

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值