栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > 架构设计

SpringIOC、SpringAOP、Spting、SpringMVC等知识点集合

架构设计 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringIOC、SpringAOP、Spting、SpringMVC等知识点集合

1、Spring 概述 1.1 框架 框架概念

框架:指软件框架,是在实际开发中解决项目需求的技术集合,简化代码编写,缩短开发周期,对固定人员要求不高,对系统升级具有灵活的标准。

​ 框架仅仅是框架,是一种已经编写好的固定规范,并不是系统架构,一个架构可以拥有多个框架

1.2 框架的作用
  1. 提高开发效率
  2. 增强代码可重用性
  3. 节约维护成本
  4. 提高编写规范
  5. 解耦底层实现原理
1.3 框架的必要性
  1. Spring(包括:springmvc、spingBoot、spingData等)和mybatis是企业开发的最为基础的两个框架
  2. 从企业角度:几乎都会使用,个人:可以实现持久层操作时代码变得非常精简
1.4 Sping 官网

https://spring.io

2、Spring简介

Spring是分层的JavaSE/EE 应用的轻量级开源框架。

是以 IOC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核提供了展现层(Web层)SpringMVC和持久层Spring JDBC

以及业务层事务管理等众多的企业级应用技术,也整合了许多第三方框架、类库

  • 老的框架组合
    • Struts2+Spring+Hibernate(SSH)
    • SpringMVC+Spring+MyBatis(SSM)
  • 新的框架
    • Spring+SpringBoot+MyBatis(新SSM)
2.1 Spring发展历史
  • 1997 IBM提出类EJB的思想
  • 1998 SUM制定开发标准规范EJB1.0
2.1.1 了解EJB
  • EJB 可以像是一个Web Service,编写的EJB业务组件放置在EJB容器上,然后提供给客户端访问,EJB提供了很多的规范,而这些规范只有在EJB容器上才能正常运行,EJB是一个重量级框架
  • Spring 容器取代了原来的EJB容器,因此Spring框架为核心的应用无需EJB的支持,可以在web容器运行,Spring容器不同于EJB,而是一个POJOBean。
  • 目前Spring最新版本spring 5.3.1 通用版(GA)
2.2 Spring的优势
  • 方便解耦,简化开发
    • 通过Spring提供的IOC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的程序过度耦合,用户也不必再为单例模式,属性文件解析等这些底层的需要写代码,可以更加专注上层的应用
  • AOP编程的支持
    • 通过Spring 的AOP功能,方便进行面向切面的编程。
  • 声明式事务的支持
    • 可以将我们从繁琐的事务管理代码解脱出来,通过声明式灵活的进行事物的管理,提高开发效率和质量
  • 方便程序的测试
    • 可以用非容器依赖的编程方式经行几乎所有的测试工作
  • 方便集成各种优秀的框架
    • Spring可以降低各种框架的使用框架,提供了对各种框架的支持
  • 降低Java EE API 的使用难度
    • Spring 对Java EE API 进行了封装
  • Spring 源码是经典实践规范
    • 源码是JAVA技术最佳的时间范例
2.3 Spring 框架体系

3、控制反转IOC–Inverse Of Control 3.1 程序的耦合 3.1.1 什么是耦合
  • 耦合性:也叫耦合度,是对模块之间关联程序的度量
  • 在软件工程中,耦合指的就是对象之间的依赖关系,对象之间的耦合越高,则模块的独立性和可重用性越差,并且维护成本越高。
  • 软件设计通常用耦合度和内聚度作为衡量模块独立性的标准,划分模块的一个标准就是高内聚低耦合。
3.1.2 内聚和耦合
  • 内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐藏和局部化概念的自然扩展,内聚是从功能角度来度量模块内的练习,一个好的内聚模块是只做一件事,它描述的是模块内的功能联系
  • 耦合是软件结构中各个模块之间相互连接的一种度量,耦合强弱取决于模块之间的复杂程度、进入或访问一个模块的点以及通过接口的数据的复杂成都,程序讲究的是低耦合,高内聚。就是同 一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依赖度却不要那么紧密。
3.1.3 框架

框架:指软件框架,使用框架会大大节约时间,方便维护,但是框架也有一定的规范我们必须遵循这个规范

3.2 工厂模式解耦 3.2.1 解耦及其必要性

解耦:解除耦合,消除任何依赖关系,如果两个模块没有任何依赖关系,则表示他们是独立的,不会有任何交叉或者协同工作的可能,解耦并不是消除代码之间的耦合,而是减少其依赖关系。

低耦合是开发中的一个最基本的要求,可以使独立性提高,增加模块的复用性,也会在后期维护成本、项目的升级,减少重构的风险

3.2.2 思路

第一:使用反射创建对象 第二:创建对象用到全限定类名配置在配置文件中

3.2.3 示例

在JDBC中一般通过反射进行注册通过反射的方式和通过注册驱动的方式

DriverManager.registerDriver(new  com.mysql.cj.jdbc.Driver());

Class.forName("com.mysql.cj.jdbc.Driver");//此处只是一个字符串
  • 第一种方式,就会导致驱动进行注册两次,如果修改数据库时,就要更改源代码,但是第二种class的方式则不会
  • 使用一些不是频繁创建对象时,采用反射的方式则更加合理,而反 射创建时需要提供创建类的全限定类名,这个名称如果写在java代码中,造成的结果就是修改仍然 避免不了修改源代码。所以,我们需要使用配置文件,把要创建类的全限定名配置在配置文件中。
3.3 设计模式 – 工厂模式

工厂模式是最常用的实例化对象模式,是用工厂的方法代替new创建对象的一种设计模式

我们以MyBatis的SqlSession接口为例,它有一个实现类DefaultSqlSession,如果我们要创建该接口的 实例对象:

SqlSession sqlSession=new DefaultSqlSession();

可是,实际情况是,通常我们都要在创建SqlSession实例的时候做点初始化的工作,比如解析XML,封装 连接数据库的信息等等。

在创建对象时,如果有一些不得不做的初始化操作时,我们首先想到的是,可以用构造方法,这样的创建对象时就写成

SqlSession sqlSession=new DefaultSqlSession(传入配置文件的路径);

但是,如果创建SqlSession实例时所做的初始化工作不是简单赋值这样的事情,可能是很长的一段代 码,如果也写入构造方法,那你的代码就不是特别的规范。

SqlSessionFactory factory=new SqlSessionFactory().build("mybatis-config.xml"); SqlSession sqlSession=factory.openSession();

所以,MyBatis框架在使用时为我们提供了SqlSessionFactory工厂类,通过openSession()方法获取到SqlSession对象,openSession()同时有很多重载,用于实现不同的需求。它支持传入Connection参数 来保证连接的一致性,支持传入true或false来保证事务的提交时机不同等待。

3.3.1 运用工厂模式解耦 步骤1:创建业务层接口和实现类
package bdit.service;


public interface AccountService {

    void saveAcccount();
}
package bdit.service.impl;

import bdit.dao.AccountDao;
import bdit.factory.BeanFactory;
import bdit.service.AccountService;


public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;//调用dao层

    @Override
    public void saveAcccount() {
        accountDao= (AccountDao)BeanFactory.getBean("accountDao");
        accountDao.saveAccount();
    }
}
步骤2:创建持久层接口和实现类
import bdit.dao.AccountDao;


public class AccountDaoImpl implements AccountDao {

    @Override
    public void saveAccount() {

    }
}
package bdit.dao;


public interface AccountDao {
    public void saveAccount();
}
步骤3:配置文件beans.xml


    
    

    
    
    


步骤4:工厂类
package bdit.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class BeanFactory {
    //创建map对象,key:String,Value:Object类型,反射创建好的对象
    private static Map map = new HashMap<>();
    //静态代码块,类加载时执行,只会被执行一次
    static{
        //解析xml,获取所有对象的全限定名
        SAXReader reader = new SAXReader();
        try {
            Document doc = reader.read(BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml"));
            //获取根节点
            Element element = doc.getRootElement();
            //获取根节点下的所有子节点
            List elementList = element.elements();
            for (Element e:elementList){
                String idvalue = e.attributeValue("id");
                String classvalue = e.attributeValue("class");
                //反射创建对象,存储到容器中
                Class cla = Class.forName(classvalue);
                Object obj = cla.getDeclaredConstructor().newInstance();
                //存储到容器中
                map.put(idvalue,obj);
            }

        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Object getBean(String id){
        return map.get(id);
    }
}

步骤5:测试类
import bdit.factory.BeanFactory;
import bdit.service.AccountService;
import org.junit.Test;


public class Text {
    @Test
    public void testSave(){
        AccountService accountService = (AccountService) BeanFactory.getBean("accountService");
        System.out.println(accountService);
        accountService.saveAcccount();
        System.out.println("成功");
//        AccountService accountService = (AccountService) BeanFactory.getBean("accountDao");
//        System.out.println(accountService);
//        accountService.saveAcccount();
//        System.out.println("成功");
    }
}
4、关于IOC 4.1.1 IOC
  • 全称是Inverse Of Control,控制反转,它不是一个技术,而是一种思想,作用是:消减代码的耦合,实现思想是利用了工厂的设计模式,把创建对象的代码从具体类中分离出来,交给工厂,从而降低了代码的依赖关系。
    • 将原先的资源—app转换成了 资源–工厂–app

IOC作用:降低了代码之间的依赖关系,消减程序中的耦合

5、Spring的IOC

Spring中两大核心IOC和AOP

使用Spring IOC配置时,它支持纯XML配置或者纯注解配置以及XML和注解混合配置三种方式

5.1 案例:

本案例要解决 账户的业务层和持久层的依赖关系

步骤1 创建业务层接口和实现类
package com.bdit.service;


public interface AccountService {

void saveAccount();
}

package com.bdit.service.impl;


import com.bdit.dao.AccountDao;
import com.bdit.dao.impl.AccountDaoImpl; import com.bdit.service.AccountService;


public class AccountServiceImpl implements AccountService {
//调用DAO层
private AccountDao accountDao=new AccountDaoImpl();


@Override
public void saveAccount() {
    
accountDao.saveAccount();
}
步骤2:创建DAO层接口和实现类
package com.bdit.dao;


public interface AccountDao {

public void saveAccount();
}
package com.bdit.dao.impl;

import com.bdit.dao.AccountDao;


public class AccountDaoImpl implements AccountDao { @Override
public void saveAccount() {
System.out.println("===========添加账户信息=============");
}
}

6、BeanFactroy 和 ApplicationContext
  • BeanFactory 是Spring中IOC容器的顶层接口,而ApplicationContext是它的一个字接口,所以ApplicationContext具备BeanFactory提供的全部功能
  • 通常情况下,称BeanFacotry是Spring IOC的基础容器,而ApplicationContext是容器的高级接口,它比BeanFactory多了很多重要的功能
  • BeanFacory 和 ApplicationContext 区别
    • 创建对象的时间点不一样
      • ApplicationContext :是要一度配置文件,默认情况下就会创建对象
      • BeanFactory:什么时候使用什么时候创建对象
6.1 ApplicationContext
  • ClassPathXmlApplicationContext:
    • 它是从类的根路径下加载配置文件
  • FileSystemXmlApplicationContext:
    • 它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置
  • AnnotaionConfigcationContext:
    • 当我们使用注解配置容器对象时,需要使用此类来创建Spring容器,它用来读取注解
6.2 IOC中Bean标签和管理对象 6.2.1 Bean 标签的对象获取
  • 通过getBean方法
    • 三种方式
      • 第一步:创建Spring的容器实例
      • 第二步:根据bean id属性获取对象
      • 第三步: 执行方法
  • 代码示例(第一种):
 System.out.println("===========第一种");
//  1、使用ApplicationcationContext接口,获取spring容器
        ApplicationContext appl = new ClassPathXmlApplicationContext("spring-beans.xml");
      
//  2、根据bean  id 属性获取对象
        AccountService accountService = (AccountService)appl.getBean("accountService");
        System.out.println(accountService);
        AccountDao accountDao = (AccountDao)appl.getBean("accountDao");
        System.out.println(accountDao);
  • 代码示例(第二种):
System.out.println("===========第二种:通过字节码");
        AccountService accountService1 = appl.getBean(AccountService.class);
        System.out.println(accountService1);
        AccountDao accountDao1 = appl.getBean(AccountDao.class);
        System.out.println(accountDao1);
  • 代码示例(第三种):
 System.out.println("==========第三种:通过字节码和id");
        AccountService accountService2 = appl.getBean("accountService",AccountService.class);
        System.out.println(accountService2);
        AccountDao accountDao2 = appl.getBean("accountDao",AccountDao.class);
        System.out.println(accountDao2);
6.3 Bean 标签的作用和属性
  • 作用:
    • 用于配置对象,让Spring来创建
    • 默认情况下调用的是类中的无参的构造方法,如果没有则无法创建
  • 属性:
    • id:给对象在容器中提供一个唯一的标识,用于获取对象
    • class:指定类的全限定名,用于反射创建对象
    • scope:指定对象的作用范围
      • singleton:默认值,单例对象
      • prototype:多例
      • request:WEB项目中,Spring创建一个Bean对象,将对象存入到request域中
      • session:WEB项目中,Spring创建一个Bean对象,将对象存入到session域中
    • init-method:指定类中的初始化方法名称
    • destroy-method:指定类中销毁方法名称
6.4 Bean 标签的生命周期
  • 单例对象:scope=“singleton”
    • 一个应用只有一个对象的实例,它的作用范围是整个应用
    • 生命周期:
      • 对象创建时:当使用对象事,创建新的对象实例
      • 对象存活:只要容器在,对象就一直存活
      • 对象销毁:当对象长时间不用,就会被java垃圾回收器所回收
  • 总结:spring框架只负责创建,不负责销毁
6.5 Bean实例化
  • 方式一:spring使用默认无参数的构造方法
    • 默认情况下,spring会根据默认无参数的构造方法来创建类的对象,如果bean中没有默认的无参数构造方法,将会失败
  • 方式二:spring管理静态工厂----使用静态工厂的方法创建对象
    • 使用 StaticFactory类中的静态方法创建对象,并存入spring容器

工厂类

package bdit.factory;

import bdit.service.impl.AccountServiceImpl;


public class AccountServiceFactory {
    public static AccountServiceImpl accountServicefactory(){
        return new AccountServiceImpl();
    }
}

xml

    
    

测试

    @Test
    public void accountService01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
        AccountService accountService = context.getBean("accountService01",AccountService.class);
        System.out.println(accountService);
    }
  • 方式三:spring管理实例工厂----使用实例工厂的方法创建对象
    • 使用此工厂创建对象,必须有实现工厂类的对象,在调用方法

工厂类

public class InstanceFactory {
public AccountService createAccountService(){ return new AccountServiceImpl();
}
}

xml






测试

@Test
public void test3(){ ApplicationContext context=new
ClassPathXmlApplicationContext("beans.xml");
AccountService accountService=context.getBean("accountService3",AccountService.class);
System.out.println(accountService);

7、Spring的依赖注入(DI) 7.1 依赖注入
  • 依赖注入:DI(Dependency Injection) 就是让Spring框架给Bean对象的属性进行赋值,它是Spring框架核心IOC的具体体现
    • 依赖注入就是利用框架把所需要的对象传递过来,而不需要我们去获取,IOC解耦的时候只是降低耦合,并不会直接消除
7.2 使用构造方法进行注入
  • 使用类的构造方法,利用soring框架进行(仅需这三个)

pojo

package com.bdit.pojo;


import java.util.Date;


public class User {
    private Integer id;
    private String name;
    private double scoure;
    private Date britday;
	//方法省略
}

xml

   
	
    
    
        
        
        
        
    
	
	
	
           
           
           
           
      

	
	  
           
           
           
           
       

测试

    @Test
    public void userOne(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ex-spring.xml");
        User u = context.getBean("userOne", User.class);
        System.out.println(u);
    }
7.3 使用Set方法注入

需要Set方法,必须是标准的完整的

pojo省略

xml


	
        
        
        
        
    

测试

@Test
    public void userset(){
        ApplicationContext context = new ClassPathXmlApplicationContext("ex-spring.xml");
        UserSet u = context.getBean("userset", UserSet.class);
        System.out.println(u);
    }

7.4 业务层注入DAO实例

DAO层接口

package bdit.dao;


public interface AccountDao {
    public void saveAccount();
}

DAO层实现类

package bdit.dao.impl;


import bdit.dao.AccountDao;


public class AccountDaoImpl implements AccountDao {

    @Override
    public void saveAccount() {

    }

    public AccountDaoImpl(){
        System.out.println("============AccountDaoImpl 无参---单例");
    }

}

业务层

package bdit.service;


public interface AccountService {

    void saveAcccount();
}

业务层实现类

package bdit.service.impl;


import bdit.dao.AccountDao;
import bdit.dao.impl.AccountDaoImpl;
import bdit.service.AccountService;


public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;//实现Dao层的引入Impl中

    public AccountServiceImpl(AccountDaoImpl accountDao) {
        System.out.println("===================构造方法");
    }

    @Override
    public void saveAcccount() {
        accountDao.saveAccount();
    }
}

xml

    

    
    
        
        
    

测试

//    通过以Dao为id引入Impl中的注入
    @Test
    public void servicedao(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans-two.xml");
        AccountService accountService = context.getBean("accountService",AccountService.class);
        System.out.println(accountService);
    }
7.4 注入集合

就是给类中的集合成员赋值,它用的是set方式注入,只不过数据类型都是集合

JavaBean

package bdit.pojo;

import java.util.*;


public class GatherArray {
    private List mylist;
    private Set myset;
    private Map mymap;
    private Properties myproperties;
    private String[] myarray;
//省略方法
}

xml


    
        
            
                list
                1111
                2222
            
        
        
            
                array
                2222
                3696
            
        
        
            
                myset
                2222
                2222
            
        
        
            
                proper
                2222
                3333
            
        
        
            
                
                
                
            
        
    

测试

//    数组、集合的注入
    @Test
    public void gatherArray(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans-two.xml");
        GatherArray gatherArray = context.getBean("gatherArray",GatherArray.class);
        System.out.println(gatherArray);
        System.out.println(gatherArray.getMylist());
        System.out.println(gatherArray.getMyset());
        System.out.println(gatherArray.getMymap());
        System.out.println(gatherArray.getMyproperties());
        System.out.println(gatherArray.getMyarray());
        System.out.println(Arrays.toString(gatherArray.getMyarray()));
    }
8、 Spring 基于注解的开发 8.1 bean标签和注解的对于关系 最开始基础的配置
  • DAO层的接口
package com.bdit.dao;

public interface AccountDao {
    public void saveAccount();
}

  • DAO接口的实现类
package com.bdit.dao.impl;

import com.bdit.dao.AccountDao;
import org.springframework.stereotype.Component;

public class AccountDaoImpl implements AccountDao {

    @Override
    public void saveAccount() {

    }

    public AccountDaoImpl(){
        System.out.println("DAO层   ==");
    }

}
  • 业务层接口
package com.bdit.service;

import org.springframework.stereotype.Component;

@Component
public interface AccountService {

    void saveAcccount();
}

  • 业务层实现类
package com.bdit.service.impl;

import com.bdit.dao.AccountDao;
import com.bdit.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public AccountServiceImpl(){
        System.out.println("============= 业务层默认的构造方法 ==========");
    }

    @Override
    public void saveAcccount() {
        accountDao.saveAccount();
    }
}

  • 测试类
public class TextAccount {
}
  • beans.xml





  • 目录结构

8.1.1 创建对象的(标记于业务层)
  • @Component:作用就和在xml配置文件中的 标签实现的功能是一样的
  • 作用:用于把当前类对象存入Spring容器(key=value形式存在)中
  • 属性:
    • value:1、用于指定bean的id,当未在 @Component(value = “”)中定义是,value就是当前类名,且首字母小写
    • 2、如果只有一个则value可以省略直接是:@Component(”accountService“)
  • @Component三个子注解
    • @Controller(一般用在表现层)
    • @Service(一般用在业务层)
    • @Repository(一般用在持久层)
  • 【以上三个注解(@Controller @Service @Repository) 作用和属性与Component作用、属性一模一样,这三个是Spring框架提供的明确三层使用的注解,使三层对象更加清晰】
  • @PostConstruct和@PreDestory和@Resouce注解都是jdk提供的,它们位 于javax.annotation包中

	javax.annotation
	javax.annotation-api
	1.3.2

应用:

  • 在 package com.bdit.service.impl.AccountServiceImpl中加入
@Component  //将 AccountServiceImpl 类反射创建一个对象存入Spring容器中
public class AccountServiceImpl implements AccountService {}
  • xml文件中



    
    
    


  • 测试类中
    @Test
    public void text01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
        AccountService a = context.getBean("accountServiceImpl",AccountService.class);
        System.out.println(a);
    }
8.1.2 用于注入数据

用于注入数据

作用和xml配置文件中的bean标签内的 标签作用一致

  • @Autowired:

  • 作用:自动按照类型注入,只要容器中有唯一一个bean对象类型和要注入的变量类型匹配,就可以注入成功

  • 如果IOC容器中没有任何bean类型和要注入的变量匹配,则报错

  • 如果IOC容器中有多个类型匹配时,先用过数据类型去匹配,这是会匹配到多个,再通过变量名称确定唯一

    • 例如:
    @Autowired
    private     AccountDao   accountDao02 =  null;
    访问修饰符    数据类型       变量名称      数据类型
    
  • 放置位置:可以是变量上,也可以是方法上

  • 注意:在使用注解注入的时,set方法不是必须的了

​ Spring的IOC容器是一个 MAP( key(String) value(Object) ) 结构

  • @Qualifier:
    • 作用:在按照类中注入的基础之上再按照名称注入,再给类成员注入的时候不能单独使用,如果通过构造方法注入,该注解则需要放在构造方法参数的前面
    • 属性:
      • value:用于指定注入的ID
  • @Resource:
    • 作用:直接按照bean的id注入可以独立使用,不能用在构造方法上,此时类中也不要提供有参数的构造方法。
    • 属性:
    • name:用于指定bean的id
    • type:用于指定注入的class 例如: @Resource(type = AccountDaoImpl.class)
  • 注意:
    • 以上只能注入其它bean类型的数据,基本数据类型、String类型无法使用上述注解完成,集合的注入只能通过xml来实现
  • @Value
    • 作用:用于注入基本上类型和String类型的数据
    • 属性:
      • value:用于指定数据的值,可以使用spring中的spel(el表达式)
        spel写法:${表达式}

业务层接口实现类

package com.bdit.service.impl;

import com.bdit.dao.AccountDao;
import com.bdit.dao.impl.ACCountDaoImpl02;
import com.bdit.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Component  //将 AccountServiceImpl 类反射创建一个对象存入Spring容器中
public class AccountServiceImpl implements AccountService {

    //第一种(其余都可不变)
    @Autowired
    private AccountDao accountDao02;

    //第二种(方式一)
    @Autowired
    @Qualifier("accountDao02")
    public AccountServiceImpl(AccountDao accountDao) {
        this.accountDao=accountDao;
        System.out.println("===================AccountServiceImpl的构造方法,不是dao的构造方法==================");
    }
    //第二种(方式二)
    @Autowired
    public AccountServiceImpl(@Qualifier("accountDao02")AccountDao accountDao) {
        this.accountDao=accountDao;
        System.out.println("===================AccountServiceImpl的构造方法,不是dao的构造方法==================");
    }

    

    //第三种
    @Resource(name = "accountDao02" )//(方式一)
    @Resource(type = ACCountDaoImpl02.class )//(方式二)
    public void setAccountDao(AccountDao accountDao) {
        System.out.println("===========SetAccountDao");
        this.accountDao = accountDao;
    }

    public AccountServiceImpl(){
        System.out.println("============= 业务层默认的构造方法 ==========");
    }

    @Override
    public void saveAcccount() {
        accountDao.saveAccount();
        System.out.println("============ AccountServiceImpl  中实现 AccountService.class 的 saveAcccount() ===========");
    }

}

  • DAO层实现类

    • 实现两个实现类,数据类型相同,但value值不一样

    第一个

package com.bdit.dao.impl;

import com.bdit.dao.AccountDao;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;


@Repository("accountDao01")
public class AccountDaoImpl implements AccountDao {

    @Override
    public void saveAccount() {
        System.out.println("============ AccountDaoImpl  中实现 AccountDao.class 的 saveAcccount() ===========");
    }

    public AccountDaoImpl(){
        System.out.println("============ DAO层 AccountDaoImpl默认的构造方法 ============");
    }

}

第二个

package com.bdit.dao.impl;

import com.bdit.dao.AccountDao;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;


@Repository("accountDao02")
public class ACCountDaoImpl02 implements AccountDao {
    @Override
    public void saveAccount() {
        System.out.println("ACCountDaoImpl02");
    }

}
  • 测试类
public class TextAccount {
    @Test
    public void text03(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
        AccountService a = context.getBean("accountServiceImpl",AccountService.class);
        a.saveAcccount();
    }

}

注入总结

  • 第一种:
    • @Autowired //作用:自动按照类型注入
    • private AccountDao accountDao02;//需要定义注入的变量名称
  • 第二种
    • @Autowired
    • @Qualifier(“accountDao02”)
    • 注意:使用 @Qualifier 放在构造方法时,最好把 @Autowired 放在构造方法之上

例如:

 private AccountDao accountDao;
@Autowired
public AccountServiceImpl(@Qualifier(value = "accountDao02") AccountDao accountDao) {
		this.accountDao=accountDao;
		System.out.println("===================构造方法");
}
  • 第三种
@Resource(name="accountDao02")
private AccountDao accountDao;

或者

@Resource(type = AccountDaoImpl.class)
private AccountDao accountDao;

注意:

private AccountDao accountDao;
@Autowired
@Resource(name = "accountDao02" )//或@Resource(type = ACCountDaoImpl02.class )
public void setAccountDao(AccountDao accountDao) {
System.out.println("===========SetAccountDao");
this.accountDao = accountDao;
}
8.1.3 用于改变作用范围

用于改变作用范围的

  • 作用:和bean标签中的scope属性实现的功能是一样的
  • Scope
    • 作用:指定bean的作用范围
    • 属性:
      • value:指定范围的取值,常用取值:singleton单例 prototype多例(默认是单例)
  • 业务层实现类
@Component
@Scope("prototype")//默认不写为单例
public class AccountServiceImpl implements AccountService {其余不变}
  • 测试类
public class TextAccount {
    @Test
    public void text04(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
        AccountService a = context.getBean("accountServiceImpl",AccountService.class);
        a.saveAcccount();
    }

}
8.1.4 用于改变生命周期
用于生命周期的
      作用:与bean标签中的 init-method 和 destroy-methode 的作用是一样的
      @PreDestroy:作用:用于指定销毁方法
      @PostConstruct:作用:用于指定初始化方法
  • 业务层实现类
package com.bdit.service.impl;

import com.bdit.dao.AccountDao;
import com.bdit.dao.impl.ACCountDaoImpl02;
import com.bdit.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

@Component
//@Scope("prototype")
public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    @Autowired
    @Resource(type = ACCountDaoImpl02.class )
    public void setAccountDao(AccountDao accountDao) {
        System.out.println("===========SetAccountDao");
        this.accountDao = accountDao;
    }

    public AccountServiceImpl(){
        System.out.println("============= 业务层默认的构造方法 ==========");
    }

    @Override
    public void saveAcccount() {
        accountDao.saveAccount();
        System.out.println("============ AccountServiceImpl  中实现 AccountService.class 的 saveAcccount() ===========");
    }

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


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

  • 测试类
public class TextAccount {
    @Test
    public void text04(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
        AccountService a = context.getBean("accountServiceImpl",AccountService.class);
        a.saveAcccount();
    }

}
8.1.5 Spring对Junit的支持
  • junit运行的时候底层使用了Runner对象,有一个默认的Runnit对象
  • spring对junit,其实是自己实现了一个Runner对象
  • 好处
    • 配置完成后不需要我们手动启动Spring
    • 可以在junit中使用@AutoWried等方式诸如对象,直接对其进行调用测试
//明确Runner对象,使用Spring框架中的Runner对象,替换Junit中的Runner对象
@RunWith(SpringJUnit4ClassRunner.class)
//明确Spring框架启动的入口,xml配置文件的位置,必须以classpath开头
@ContextConfiguration(locations ="classpath:beans.xml")

示例:

//明确Runner对象,使用Spring框架中的Runner对象,替换Junit中的Runner对象
@RunWith(SpringJUnit4ClassRunner.class)
//明确Spring框架启动的入口,xml配置文件的位置,必须以classpath开头
@ContextConfiguration(locations ="classpath:beans.xml")
public class StudentTest {
@Autowired
private IStudentService studentService;
@Test
public void testFindAll(){
List list=studentService.findAll();
for(Student student:list){
System.out.println(student);
}
}
}

9、AOP 9.1 AOP概述
  • AOP:全称是 Aspect Oriented Programming,面向切面编程
  • AOP 就是把程序中重复的代码抽取出来,在需要执行的时候和,在使用动态代理技术,在不改变源代码的基础上,对我们已有的方法进行增强
  • AOP是对OOP的一种补充
9.2 Spring中AOP的相关
  • Joinpoint(连接点)
    • 是指那些需要被拦截到的点,在Sspring中,这些点指的就是方法,因为Spring只基于方法的连接
  • PointCut(切入点)
    • 既是指对那些连接点进行拦截的定义
  • Advice(通知/增强)
    • 是指对拦截到的连接点之后所要做的事情
    • 通知类型:前置通知、后置通知、异常通知、最终通知、环绕通知
  • Introducation(引入----引介)
    • 是一种特殊的通知,可以在不修改类代码的前提下,引介可以在运行期间动态的增加一些方法或着属性
  • Target(目标对象)
    • 代理的目标对象
  • Weaving(织入)
    • 就是把增强应用到目标对象创建新的代理对象的过程
    • spring采用动态代理的织入,而Aspectj采用编译器织入和类装载期织入
  • Proxy(代理)
    • 一个类被AOP织入增强后,就产生一个结果代理类
  • Aspect(切面)
    • 就是切入点和通知(引介)的结合
9.3 基于XML的AOP配置
  • 导入 aspect 和环绕通知的jar包


org.aspectj
aspectjweaver
1.9.6
runtime




org.aspectj
aspectjrt
1.9.6


  • 在spring配置文件中导入约束




  • 切面类
package com.bdit.aspect;

import com.bdit.pojo.Usera;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;


public class LogginAspect {

    //     基于XML的AOP配置

    private Logger loggerasper = LogManager.getLogger(LogginAspect.class);

    
    public void beforeks(){
        loggerasper.info("==========AOP 前置通知 开始日志==========");
    }

    
    public void afterRunningHz() {
        loggerasper.info("==========AOP 后置通知 日志记录成功==========");
    }

    
    public void afterThrowingHz(){
        loggerasper.info("==========AOP 后置异常通知 日志输出==========");
    }
    
    
    
    public void afterHz(){
        loggerasper.info("==========AOP 后置最终通知 日志输出==========");
    }

    

    public void aroundHuanRao(ProceedingJoinPoint proceedingJoinPoint){
        //获取方法执行所需的参数
        Object[] obj = proceedingJoinPoint.getArgs();
        Usera usera = (Usera)obj[0];
        System.out.println(usera);
        System.out.println(proceedingJoinPoint.getTarget());
        loggerasper.info("==================开启 环绕通知  事务==================");
        try{
            proceedingJoinPoint.proceed(obj); //执行目标方法
            loggerasper.info("=============提交  环绕通知 事务==================");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            loggerasper.info("==============异常  环绕通知    事务================");
        }finally {
            loggerasper.info("==============关闭  环绕通知    事务==============");
        }
    }
}
  • xml


    

    
    
    
    
    
        
        

            
            

            
            

            
            

            
            

            
            

            
            
        
    


  • 业务层
package com.bdit.service.impl;

import com.bdit.pojo.Usera;
import com.bdit.service.IUseraServicr;


public class UseraImpl implements IUseraServicr {
    @Override
    public void transfer(String source, String target, double money) {
        

        System.out.println(10/0);
        System.out.println("----------------转账----------------");

    }

    @Override
    public Integer save(Usera usera) {
        System.out.println("----------------增加----------------");
        return null;
    }

    @Override
    public Integer delect(Integer integer) {
        System.out.println("----------------删除----------------");
        return null;
    }

    @Override
    public Integer update(Usera usera) {
        System.out.println("----------------修改----------------");
        return null;
    }

    @Override
    public Usera queryById(Integer integer) {
        System.out.println("----------------按照ID查询----------------");
        return null;
    }

    @Override
    public Usera queryAll() {
        System.out.println("----------------查询全部----------------");
        return null;
    }
}
  • 测试
package com.bdit.text;

import com.bdit.pojo.Usera;
import com.bdit.service.IUseraServicr;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Text01 {

    

    @Test
    public void textaop(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-mybatis.xml");
        IUseraServicr iUseraServicr = context.getBean(IUseraServicr.class);
        iUseraServicr.transfer("甲一","甲二",200);
    }

    @Test
    public void texthr(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-mybatis.xml");
        IUseraServicr iUseraServicr = context.getBean(IUseraServicr.class);
        Usera u = new Usera();
        iUseraServicr.save(u);
    }
}

9.4 切入点表达式
  • AspectJ:在Spring2.x以上的版本,可以使用基于AspectJ注解活着基于xml配置的AOP
  • AspectJ表达式说明
    • execution:匹配方法的执行
    • 表达式语法: execution([修饰符] 返回值类型 包名.类名.方法名(参数))
    • 写法说明:
      • 全匹配写法: public void com.bdit.service.impl.AccountServiceImpl.save(com.bdit.pojo.Account)
      • 访问修饰符可以省略: void com.bdit.service.impl.AccountServiceImpl.save(com.bdit.pojo.Account)
      • 返回值可以使用*号,表示任意类型: * com.bdit.service.impl.AccountServiceImpl.save(com.bdit.pojo.Account)
      • 包名可以使用 * 号,表示任意包,包有几级,就写几个* :* . * . * .*.AccountServiceImpl.save(com.bdit.pojo.Account)
      • 使用…来表示当前包,及其子包:* com…AccountServiceImpl.save(com.bdit.pojo.Account)
      • 类名也可以使用*号,表示任意类 : * com… * .save(com.bdit.pojo.Account)
      • 方法名也可以使用*号,表示任意方法 * com… * . * (com.bdit.pojo.Account)
      • 参数列表可以使用*,表示任意参数类型,但是必须有参数 * com… * . *( * )
      • 参数列表可以使用*,标识任意参数类型,有参数无参数都可以 * com…* .*(…)
      • 全通匹配 * * … * . *(…) 通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切入业务层的实现类。
9.5 基于半注解半xml的aop文件

**在xml中配置要指定扫描的包和 xml启用Spring对AOP注解的支持 **




    
    
    
    


切面类

package com.bdit.aspect;

import com.bdit.pojo.Usera;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


@Component
@Aspect //声明为切面类
public class LogginAspect {
//     

    private Logger loggerasper = LogManager.getLogger(LogginAspect.class);

    

    @Pointcut(value = "execution(* com.bdit.service.impl.*.*(..))")
    public void lei(){};

    
//    @Before(value = "execution(* com.bdit.service.impl.*.*(..))")
    @Before(value = "lei()")
    public void beforeks(){
        loggerasper.info("==========AOP 前置通知 开始日志==========");
    }

    
    @AfterReturning(value = "execution(* com.bdit.service.impl.*.*(..))")
    public void afterRunningHz() {
        loggerasper.info("==========AOP 后置通知 日志记录成功==========");
    }

    
    @AfterThrowing(value = "execution(* com.bdit.service.impl.*.*(..))")
    public void afterThrowingHz(){
        loggerasper.info("==========AOP 后置异常通知 日志输出==========");
    }

    
    @After(value="execution(* com.bdit.service.impl.*.*(..))")
    public void afterHz(){
        loggerasper.info("==========AOP 后置最终通知 日志输出==========");
    }

    
    @Around(value="execution(* com.bdit.service.impl.*.*(..))")
    public void aroundHuanRao(ProceedingJoinPoint joinPoint){
        Object[] obj = joinPoint.getArgs();
        Usera a = (Usera)obj[0];
        System.out.println(joinPoint.getTarget());
        System.out.println(a);
        loggerasper.info("============ AOP 开启环绕通知 日志输出 ===========");
        try{
            joinPoint.proceed(obj);//执行目标方法
            loggerasper.info("============ AOP  环绕通知 提交  日志输出 ==============");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            loggerasper.info("============ AOP  环绕通知出现异常 日志输出 ==============");
        }finally {
            loggerasper.info("============ AOP  环绕通知销毁 日志输出 ==============");
        }

    }
    
}

【其余几乎都一样】

9.6 纯注解的AOP配置
  • Spring的配置类
package com.bdit.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;



@Configuration
@ComponentScan(basePackages = {"com.bdit"})
@EnableAspectJAutoProxy //启用Spring对AOP注解的支持
public class SpringConfig {
}

  • 配置切面类
package com.bdit.aspect;

import com.bdit.pojo.Usera;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


@Component
@Aspect //声明为切面类
public class LogginAspect {
//     

    private Logger loggerasper = LogManager.getLogger(LogginAspect.class);

    

    @Pointcut(value = "execution(* com.bdit.service.impl.*.*(..))")
    public void lei(){};

    
//    @Before(value = "execution(* com.bdit.service.impl.*.*(..))")
    @Before(value = "lei()")
    public void beforeks(){
        loggerasper.info("==========AOP 前置通知 开始日志==========");
    }

    
    @AfterReturning(value = "lei()")
    public void afterRunningHz() {
        loggerasper.info("==========AOP 后置通知 日志记录成功==========");
    }

    
    @AfterThrowing(value = "lei()")
    public void afterThrowingHz(){
        loggerasper.info("==========AOP 后置异常通知 日志输出==========");
    }

    
    @After(value = "lei()")
    public void afterHz(){
        loggerasper.info("==========AOP 后置最终通知 日志输出==========");
    }

    
    @Around(value = "lei()")
    public void aroundHuanRao(ProceedingJoinPoint joinPoint){
        Object[] obj = joinPoint.getArgs();
        Usera a = (Usera)obj[0];
        System.out.println(joinPoint.getTarget());
        System.out.println(a);
        loggerasper.info("============ AOP 开启环绕通知 日志输出 ===========");
        try{
            joinPoint.proceed(obj);//执行目标方法
            loggerasper.info("============ AOP  环绕通知 提交  日志输出 ==============");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            loggerasper.info("============ AOP  环绕通知出现异常 日志输出 ==============");
        }finally {
            loggerasper.info("============ AOP  环绕通知销毁 日志输出 ==============");
        }

    }
    

}
  • 测试类
package com.bdit.text;





import com.bdit.config.SpringConfig;
import com.bdit.pojo.Usera;
import com.bdit.service.IUseraServicr;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})
public class Text01 {

    

    

    @Autowired
    private IUseraServicr iUseraServicr;
    @Test
    public void textaopsave(){
        iUseraServicr.save(new Usera());
    }


}
10、事务 10.1 Spring事务
  • JavaEE事务处理位于业务层,Spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现
  • PlatformTransactionManager 此接口是Spring的事务管理器,提供了我们常用的操作事物的方法
    • 获取事物的状态的信息:
      • TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    • 提交事务:
      • void commit(TransactionStatus var1) throws TransactionException;
    • 回滚事务:
      • void rollback(TransactionStatus var1) throws TransactionException;
  • 一般使用其实现类
    • 真正管理事务的对象 org.springframework.jdbc.datasource.DataSourceTransactionManager 使用JDBC或MyBatis进行 持久化数据时使用。
    • org.springframework.orm.hibernate5.HibernateTransactionManager 使用Hibernate持久化数据 时使用
10.2 TransactionDefinition

它是事务的定义信息对象,里面包含如下方法:

  • 获取事务对象名称: String getName();
  • 获取事务的隔离级别: int getIsolationLevel();
  • 获取事务的传播行为: int getPropagationBehavior();
  • 获取事务超时时间: int getTimeout();
  • 获取事务是否只读: boolean isReadOnly();
10.3 事物的隔离级别

事务隔离级别反映事务提交并发访问时的处理态度:

  • ISOLATION_DEFAULT :默认级别,归属下列某一种

  • ISOLATION_READ_UNCOMMITTED :可以读取未提交的数据

  • ISOLATION_READ_COMMITTED:只能读取已提交的数据,解决脏读问题(Oracle默认级别)

  • ISOLATION_PERPEATABLE_READ :是否读取其它事务提交修改后的数据,解决不可重复读问题(MySQ默认的级别)

  • ISOLATION_SERIALIZABLE :是否读取其它事务提交添加好的数据,解决幻读问题,最高的隔离级别,不允许并发访问,效率低

10.4 事物的传播行为
  • REQUIRED:如果当前没有事务,就创建一个事务,如果已经存在一个事务中,加入到这个事务中,一 般选择(默认值)
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行(没有事务)
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常
  • REQUERS_NEW:新建事务,如果当前在事务中,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式操作,如果当前存在事务,就把当前事务挂起
  • NEVER:以非事务方式运行,如果当前存在事务,抛出异常
  • NESTED:如果当前存在事务,则嵌套事务内执行,如果当前没有事务,则执行REQUIRED类似的操作。
10.5 超时时间

默认值为-1,就是用不超时,但可以设置,单位为秒

10.6 是否只读事务

查询时反馈的数据最好为只读------获取事务是否只读: boolean isReadOnly();

10.7 TransactionStatus

此接口提供的是事务的运行状态,方法如下:

  • 获取事务是否为新的事务 boolean isNewTransaction();
  • 获取是否是存储点 boolean hasSavepoint();
  • 设置事务回滚 void setRollbackOnly();
  • 获取事务是否回滚 boolean isRollbackOnly();
  • 刷新事务 void flush();
  • 事务是否完成 boolean isCompleted();
11、Spring事务配置相关标签及属性
  • 事务配置: 通知标签
    • 属性id:自定义唯一标识
    • transaction-manager属性:事务管理类,配置事物的管理类的id属性
  • 事务属性配置:
    • 子标签属性:
      • name:方法名(业务层的方法名,支持通配符*)
      • read-only:是否只读事务,查询都是只读,其他是非只读,默认配置为false
      • propagation:事物的传播行为,默认配置为REQUIRED
      • isolation:事物的隔离级别,默认配置为DEFAULT
      • timeout:事物的超时时间,默认为-1
      • no-rollback-for:遇到什么异常不回滚,配置异常类名,多个类名逗号分开
      • rollback-for:遇到什么异常回滚
  • aop切面配置
    • 子标签 属性:
      • advice-of:引用通知,配置 tx:advice 标签的属性值
      • pointcut-ref:引入切入点
11.1 Spring基于xml的事务配置

基于转账的案例

  • 标签详解

    • 作用:配置事物的通知

    • 出现位置:beans标签内部

    • 属性:id:为事务通知提供一个唯一标识

      ​ transacyion-manager:为事务通知指定一个事务管理器ID的引用

  • 标签详解

    • 作用:配置事务的属性
    • 的位置:要去写在标签内部
  • 标签

    • 作用:用于配置每个需要事务支持的方法,所使用的特征
    • 出现位置:要求写在标签内部
    • 属性:name:指定方法的名称支持通配符的配置方式,例如:* 表示所有的方法,find* 表示以find开头的方法
    • read-only:指定是否为只读事务,默认值false,只有查询方法可以设置为true
    • propagation:指定事务的传播行为,默认值是REQUIRED,表示必须有事务。查询方法设置为 SUPPORTS,表示有事务就支持,没有事务就以非事务进行。
    • timeout:指定事务超时的时间,默认值是-1,表示永不超时,取值为正整数,以秒为单位
    • isolation:事务隔离级别,默认值是DEFAULT,表示采用数据库的默认隔离级别,不同的数据库默认隔 离级别不一样,mysql为REPEATABLE_READ,oracle为 READ COMMITTED
    • rollback-for:用于指定一个异常,当该异常产生时,事务回滚。产生其他异常时,事务不回滚,没有 默认值,即产生任何异常都回滚。
    • no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其它异常,事务回滚。没 有默认值,即产生任何异常都回滚。
  • 标签

    • 作用: 用于建立通知和切入点表达式的关系
    • 出现位置: 要求写在标签内部
    • 属性:
      • id:唯一标识
      • advice-ref:用于指定通知的引用
      • pointcut-ref:用于指定切入点表达式的引用
      • pointcut:用于指定切入点表达式
      • order:当配置多个advisor,用于指定执行的优先级
  • javabean

package com.bdit.pojo;

import lombok.Data;

import java.io.Serializable;


@Data
public class Account implements Serializable {
    private int aid;
    private String name;
    private Double money;
}
  • dao接口实现类
package com.bdit.mapper;

import com.bdit.pojo.Account;


public interface IAccountMapper {
    public Account queryByName(String name);

    public int update(Account account);
}
  • 业务层接口
package com.bdit.service;

import com.bdit.pojo.Account;


public interface IAccountService {
    public void transfer(String source, String target, double money);
    
    public int update(Account account);
}
  • 业务层接口实现类
package com.bdit.service.impl;

import com.bdit.mapper.IAccountMapper;
import com.bdit.pojo.Account;
import com.bdit.service.IAccountService;



public class AccountServiceImpl implements IAccountService {

    private IAccountMapper accountMapper;

    public void setAccountMapper(IAccountMapper accountMapper) {
        this.accountMapper = accountMapper;
    }

    @Override
    public void transfer(String source, String target, double money) {

        Account accountSource = accountMapper.queryByName(source);
        Account accountTarget = accountMapper.queryByName(target);

        accountSource.setMoney(accountSource.getMoney() - money);
        accountMapper.update(accountSource);

        System.out.println(10/0);

        accountTarget.setMoney(accountTarget.getMoney() + money);
        accountMapper.update(accountTarget);
    }
    
    @Override
    public int update(Account account) {
        return accountMapper.update(account);
    }
}
  • xml



    
    
    

    
    
        
        
        
        
    

    
    
        
        
        
        
    

    
    
        
    


    
    
        
    


    
    
    
        
        
    

    
    
        
        
            
            
        
    

    
    
        
        
        
    



测试

package com.bdit.text;


import com.bdit.service.IAccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;




public class Text1 {
//aop事务 xml 实现 转账
    @Test
    public void text(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        IAccountService accountService = context.getBean("accountService",IAccountService.class);
        accountService.transfer("张三","李四",200);
    }
}
11.2 Spring基于注解的事务注解

xml




    
    

    
    
    

    
    
        
        
        
        
    

    
    
        
        
        
        
    

    
    
        
    
    

    
    
        
        
    

    
    

业务层

package com.bdit.service.impl;

import com.bdit.mapper.IAccountMapper;
import com.bdit.pojo.Account;
import com.bdit.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


@Service("accountService")
@Transactional(transactionManager = "transactionManager",propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountMapper accountMapper;

    public void setAccountMapper(IAccountMapper accountMapper) {
        this.accountMapper = accountMapper;
    }

    @Override
    public void transfer(String source, String target, double money) {

        Account accountSource = accountMapper.queryByName(source);
        Account accountTarget = accountMapper.queryByName(target);

        accountSource.setMoney(accountSource.getMoney() - money);
        accountMapper.update(accountSource);


        System.out.println(10/0);

        accountTarget.setMoney(accountTarget.getMoney() + money);
        accountMapper.update(accountTarget);

    }

    @Override
    public Account queryByName(String name) {
        return accountMapper.queryByName(name);
    }

    @Override
    public int update(Account account) {
        return accountMapper.update(account);
    }
}

测试类

package com.bdit.text;


import com.bdit.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring.xml")
public class Text1 {
//aop事务 半xml半注解  实现 转账

    @Autowired
    private IAccountService accountService;
    @Test
    public void text(){

        accountService.transfer("张三","李四",200);
    }
}
11.3 注解详解

@Transactional

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {}
11.4 全注解

xml




    
    

    
    
    

    
    
        
        
        
        
    

    
    
        
        
        
        
    

    
    
        
    
    

    
    
        
        
    

    
    


  • MyBatisConfig
package com.bdit.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;


public class MyBatisConfig {

    @Bean(value = "sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("druidDataSource")DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        sqlSessionFactoryBean.setTypeAliasesPackage("com.bdit.pojo");
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
        scannerConfigurer.setBasePackage("com.bdit.mapper");
        return scannerConfigurer;
    }
}

DataSourceConfig

package com.bdit.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;


@PropertySource(value = {"classpath:db.properties"})
public class DataSourceConfig {
    @Value("${jdbc.driver}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean(value = "druidDataSource")
    public DataSource createDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }
}

TransactionManagerConfig

package com.bdit.config;

import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;


public class TransactionManagerConfig {

    @Bean
    public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
        return new DataSourceTransactionManager(dataSource);
    }
}

SpringConfig

package com.bdit.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@Configuration
@ComponentScan(basePackages = {"com.bdit"})
@Import({DataSourceConfig.class,MyBatisConfig.class,TransactionManagerConfig.class})
@EnableTransactionManagement  //开启Spring注解事务的支持
public class SpringConfig {
}

业务层

package com.bdit.service.impl;

import com.bdit.mapper.IAccountMapper;
import com.bdit.pojo.Account;
import com.bdit.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;


@Service("accountService")
@Transactional
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountMapper accountMapper;

    public void setAccountMapper(IAccountMapper accountMapper) {
        this.accountMapper = accountMapper;
    }

    @Override
    public void transfer(String source, String target, double money) {

        Account accountSource = accountMapper.queryByName(source);
        Account accountTarget = accountMapper.queryByName(target);

        accountSource.setMoney(accountSource.getMoney() - money);
        accountMapper.update(accountSource);

//        System.out.println(10/0);

        accountTarget.setMoney(accountTarget.getMoney() + money);
        accountMapper.update(accountTarget);

    }

    @Override
    public Account queryByName(String name) {
        return accountMapper.queryByName(name);
    }

    @Override
    public int update(Account account) {
        return accountMapper.update(account);
    }
}

测试类

package com.bdit.text;

import com.bdit.config.SpringConfig;
import com.bdit.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class Text1 {
//aop事务 半xml半注解  实现 转账

    @Autowired
    private IAccountService accountService;
    @Test
    public void text(){
        accountService.transfer("张三","李四",200);
    }
}
12、SpringMVC 12.1 三层架构
  • Java开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器。另一种是B/S架构,也就是浏 览器/服务器。
  • 在JavaEE开发中,几乎全部都是基于B/S架构的开发。那么在B/S架构中,系统标准的三层架 构包括:表现层、业务层、持久层。
    • 表现层:也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请 求web层,web需要接收http请求,完成http响应。
    • 表现层包括展示层和控制层,控制层负责接收请求,展示层负责结果的展示。 表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。 表现层的设计一般都使用MVC模式(MVC是表现层的设计模式,和其它层没有关系)
    • 业务层: 也就是我们常说的service层,它负责业务逻辑处理,和我们开发项目的需求息息相关。Web 层依赖业务层,但业务层不依赖web层。 业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要 保证事务一致性。(也就是我们说的事务应该放到业务层来控制)
    • 持久层: 也就是我们常说的dao层,负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化 到数据库中。通俗的将,持久层就是和数据库交互,对数据库表进行增删改查操作的。
12.2 MVC
  • MVC全名是 Model View Controller,是模型(model)—视图(view)—控制器(controller)的 缩写,是一种用于设计创建web应用程序表现层的模式。
  • MVC中每个部分各司其职: Model(模型): 通常指的是我们的数据模型,作用一般情况用于封装数据 View(视图): 通常指的就是我们的jsp或者 html,作用一般就是展示数据的 通常视图是依赖模型数据创建的。
  • Controller(控制器): 是应用程序中处理用户交互的部分,作用一般就是处理程序逻辑的。
12.3 SpringMVC 的执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MA998iBb-1606224110780)(C:UsersLenovoDesktop流程.PNG)]

  • 用户发送请求到前端控制器DispatcherServlet
  • DispatcherServlet收到请求调用到HandlerMapping处理器映射器
  • 处理器映射器找到具体的处理器(可以根据xml、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  • DispatcherServlet调用HandlerAdapater处理器适配器
  • HandlerAdapter 经过适配调用具体的处理器(Controller 也叫后端控制器)
  • Controller执行完成后返回ModelAndVies
  • HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  • DispatcherServlet将MmodelAndView传给ViewReslover视图解析器
  • ViewReslover解析后返回具体的View
  • DispathcherServlet根据View进行渲染视图(即将模型数据填充至视图中)DispatcherServlet响应用户
12.4 SpringMVC组件解析
  • 前端控制器:DispatcherServlet
    • 用户请求到达前端控制器,它就相当于 MVC 模式中的 C,DispatcherServlet 是整个流程控制的中 心,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。
  • 处理器映射器:HandlerMapping HandlerMapping
    • 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现 不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  • 处理器适配器:HandlerAdapter
    • 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型 的处理 器进行执行。
  • 处理器:Handler
  • 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
  • 视图解析器:View Resolver
    • View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图 名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用 户。
  • 视图:View
    • SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView 等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用 户,需要由程序员根据业务需求开发具体的页面
12.5 SpringMVC注解解析

@RequestMapping

作用:用于建立请求URL和处理请求方法之间的对于关系

位置:类上,请求URL的第一级访问目录,不写,默认是应用的根目录

​ 方法上:请求URL的第二级访问目录,与类上使用的@RequestMapping标注的一级目录一起组成访问的虚拟目录

属性:value:用于指定请求的url,他和path属性的作用是一样的

​ method:用于请求的方式

如果请求方式和方法处理请求的方式不匹配时,出现405

params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的key和value必须和 配置的一模一样

12.6 MVC实现 HELLO

web.xml




  
  
    dispatcherServlet
    org.springframework.web.servlet.DispatcherServlet
    
    
      contextConfigLocation
      classpath:spring-mvc.xml
    
  
  
    dispatcherServlet
    /
  


spring-mvc.xml




    
    
    
    
        
        
            
        

    


HelloControlle.java

package com.bdit.controlle;

import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
@RequestMapping(value = {"/user"})   // 根标签,访问时必须是 user/hellow
public class HelloControlle {

    //value:通过url(hello)访问
    //method:确定访问方式,RequestMethod.POST 确定访问类型是 post(访问类型不是post则爆405)
    //params:数据、参数,里面的数据必须出现在url地址中
    @RequestMapping(value = {"/hello"},method = RequestMethod.GET,params = {"name=aa","pass!=100"})
    public String welcom(){
        System.out.println("======================= 用户访问信息到达,接收成功 =======================");
        return "successon";//指访问的jsp等
    }
}

successon.jsp

<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/19
  Time: 11:04
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    successon


successon(在HellcControlle.class中return)



index.jsp



Hello World!
HelloWold


12.7 MVC命名空间引入
命名空间:xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
约束地址:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
12.8 组件扫描

SpringMVC基于Spring容器,所以在进行SpringMVC操作时,需要将Controller存储到Spring容器中, 如果使用@Controller注解标注的话,就需要使用进行组件扫描。

12.9 SpringMVC的xml配置解析

SpringMVC有默认组件配置,默认组件都是DispatcherServlet.properties配置文件中配置的,该配置文 件地址org/springframework/web/servlet/DispatcherServlet.properties,该文件中配置了默认的视图 解析器,如下:

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

可以看到该解析器的默认设置,如下:

REDIRECT_URL_PREFIX = "redirect:" --重定向前缀
FORWARD_URL_PREFIX = "forward:" --转发前缀(默认值)
prefix = ""; --视图名称前缀
suffix = ""; --视图名称后缀

视图解析器 我们可以通过属性注入的方式修改视图的的前后缀






12.10 SpringMVC的相关组件、SpringMVC的注解和配置

SpringMVC的相关组件

  • 前端控制器:DispatcherServlet
  • 处理器映射器:HandlerMapping
  • 处理器适配器:HandlerAdapter
  • 处理器:Handler
  • 视图解析器:View Resolver
  • 视图:View

SpringMVC的注解和配置

  • 请求映射注解:@RequestMapping
  • 视图解析器配置:
    • REDIRECT_URL_PREFIX = “redirect:”
    • FORWARD_URL_PREFIX = “forward:”
    • prefix = “”;
    • suffix = “”;
13、SpringMVC的请求和响应 13.1 SpringMVC的数据响应方式
  • 页面跳转
    • 直接返回字符串
    • 返回ModelAndView对象
  • 回写数据
    • 直接返回字符串
    • 返回对象或集合
13.2 基本配置
  • spring-mvc.xml


    

    
    
        
        
    


    
        
            
                
            
        
    

    
    


    
    "/conTwo"})
public class ControllerTwo {

    //数据响应---跳转页面
    @RequestMapping(value = {"/controller01"})
    public ModelAndView controller01(){
        //封装响应数据和视图
        ModelAndView mav = new ModelAndView();
        //相应的数据,默认放在请求域中
        mav.addObject("accountName","甲一");
        mav.addObject("accountName","甲二");
        //设置视图名
        mav.setViewName("controllers");
        return mav;
    }

    //数据响应---跳转页面
    @RequestMapping(value = "/controller02")
    public ModelAndView controller02(ModelAndView mav){
        mav.addObject("accountName","甲三");
        mav.setViewName("controllers");
        return mav;
    }

    //数据响应---跳转页面
    @RequestMapping("/controller03")
    public String controller03(Model model){
        model.addAttribute("accountName","model");
        return "controllers";
    }

    //数据响应---跳转页面
    @RequestMapping(value = "/controller04")
    public String controller04(HttpServletRequest httpServletRequest){
        //响应的数据放在请求域中
        httpServletRequest.setAttribute("accountName","甲四");
        return "controllers";
    }
}    

controllers.jsp

<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/19
  Time: 17:37
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Controller



Controller----succeed
${accountName}



数据响应—回写数据

ControllerTwo.java

//数据响应---回写数据
@RequestMapping(value = "/controller05")
@ResponseBody
public String controller05(){
    return "甲五";
}

//数据响应---回写数据
@RequestMapping(value = "/controller06")
@ResponseBody
public void controller06(HttpServletResponse resp) throws IOException {
    resp.getWriter().print("06-----甲六");
}

//数据响应---回写数据-直接回写JSON格式字符串
@RequestMapping("/controller07")
@ResponseBody
public String controller07() throws JsonProcessingException {
    Account account = new Account();
    account.setAid(1001);
    account.setName("甲七");
    account.setMoney(100.0);
    ObjectMapper obj = new ObjectMapper();
    String json = obj.writeValueAsString(account);
    return json;
}

@RequestMapping("/controller07_1")
public String controller07_1(HttpServletRequest httpServletRequest) throws JsonProcessingException {
    Account account = new Account();
    account.setAid(1001);
    account.setName("甲七");
    account.setMoney(100.0);
    ObjectMapper obj = new ObjectMapper();
    String json = obj.writeValueAsString(account);
    httpServletRequest.setAttribute("accountName",json);
    return "jsontwo";
}

//数据响应--回写数据--返回对象或集合(需在 spring-mvc.xml声明)
@RequestMapping("/controller08")
@ResponseBody
public Account controller08(){
    Account account = new Account();
    account.setAid(1002);
    account.setName("甲八");
    account.setMoney(96.36);
    return account;
}
    @RequestMapping(value = "/controller09")
    @ResponseBody
    public List controller09(){
        List list = new ArrayList<>();
        list.add("一一");
        list.add("二二");
        list.add("三三");
        list.add("四四");
        return list;
    }
    @RequestMapping(value = "/controller10")
    @ResponseBody
    public List controller10(){
        List accountList = new ArrayList<>();
        Account account = new Account();
        account.setAid(1003);
        account.setName("五五");
        account.setMoney(153.36);
        accountList.add(account);

        Account account1 = new Account();
        account1.setAid(1004);
        account1.setName("六六");
        account1.setMoney(963.36);
        accountList.add(account1);
        return accountList;
    }
}

index.jsp

controller
ModelAndView01--null
ModelAndView02--ModelAndView
ModelAndView03--model
ModelAndView04--HttpServletRequest
ModelAndView05--xiangying--null
ModelAndView06--xiangying-HttpServletResponse
ModelAndView07--xiangying--json
ModelAndView07_1--xiangying--json
ModelAndView08--xiangying--duixiang/jihe
ModelAndView09--xiangying--duixiang/jihe
ModelAndView10--xiangying--duixiang/jihe

controller.jsp

<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/19
  Time: 17:37
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Controller



Controller----succeed
${accountName}



jsontwo.jsp

<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/19
  Time: 21:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    jsontwo


jsontwo
${json}


13.4 数据请求

客户端请求参数的格式是:name=value&name=value…

服务器端要获得请求的参数,有时还需要对数据进行封装,

SpringMVC可以接收如下类型的参数: 基本类型参数 POJO类型参数 数组类型参数 集合类型参数

Controller中方法的参数名称要和请求参数的name一致,参数值会自动映射匹配,并且能够自动做类型 转换。 自动类型转换是指从String向其它类型转换

ContorllerThree.java

package com.bdit.controller;

import com.bdit.pojo.Account;
import com.bdit.pojo.Vo;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Arrays;
import java.util.List;


@Controller
@RequestMapping(value = {"/conThree"})
public class ContorllerThree {

    //SpringMVC的请求--获得请求参数--基本类型参数
    @RequestMapping(value = "/contorller01")
    public String contorller01(String name,int age){
        System.out.println("姓名:"+name+" 年龄:"+age);
        return "qingqiu";
    }

    //SpringMVC的请求--获得请求参数--pojo类型参数
        //Controller中方法的POJO参数的属性名与请求参数的name一致,参数值会自动映射匹配
    @RequestMapping(value = "/contorller02")
    public String contorller02(Account account){
        System.out.println(account);
        return "qingqiu";
    }

    //SpringMVC的请求--获得请求参数--数组类型参数
    @RequestMapping(value = "/contorller03")
    public String contorller03(String[] str){
        System.out.println(str.toString()+"  yi");
        System.out.println(Arrays.asList(str) +"  er");

        return "qingqiu";
    }

    // SpringMVC的请求--获得请求参数--集合类型参数
        //获得集合参数时,需要将集合参数包装到一个POJO中才可以,method = RequestMethod.POST
    @RequestMapping(value = "/contorller04")
    @ResponseBody
    public void contorller04(Vo vo){
        List list = vo.getList();
        for (Account a : list){
            System.out.println(a);
        }
//        return "qingqiu";
    }



}

Vo.java

package com.bdit.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.List;


@Data
public class Vo implements Serializable {
    private List list;
}

qingqiu.jsp

<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/19
  Time: 20:34
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    qingqiu


请求页面


index.jsp

qingqiu----jibencanshu
qingqiu----json
qingqiu----shuzhu






13.5SpringMVC请求—静态资源访问的开启

当有静态资源需要加载时,比如jquery文件,图片、css等,默认情况下是无法加载的。因为SpringMVC 的前端控制器DispatcherServlet的url-parttern配置的是/,代表对所有的资源进行过滤操作,我们可以 通过两种方式指定放行静态资源: 在spring-mvc.xml配置文件中指定放行的资源



        System.out.println("========================resultRedirect=====================");
        modelMap.addAttribute("date",new Date());

        return "redirect:/account/cdx";
    }

    @RequestMapping(value = "/cdx")
    public String cdx(ModelMap modelMap){
        System.out.println("====================zf====================");
        Date date=(Date) modelMap.getAttribute("date");
        System.out.println(date);

        return "success";
    }

    

    @RequestMapping(value = "/forward")
    public String resultForward(HttpServletRequest request){
        request.setAttribute("data","aa");
        System.out.println("====================forward===============");
        return "forward:/account/zf";
    }

    @RequestMapping(value = "/zf")
    public String zf(HttpServletRequest request){
        System.out.println("===========zf===========");
        String data = (String) request.getAttribute("data");
        System.out.println(data);
        return "success";
    }

    
    @RequestMapping(value = "/param")
    public String param(@RequestParam("aid") int bid,@RequestParam("name") String namee,@RequestParam("money") String moneyss){
        return "success";
    }

indes.jsp

 重定向 
 请求转发 
14.1 JSON格式数据实现AJAX交互

JSON数据是企业开放中数据交换最常用的一种方式,它是轻量级,格式比较清晰。

交互:前端和后端的互动

  • 前端传递JSON字符串到后台,后台如何能够自动转换为pojo对象。
  • @RequestBody注解,将JSON字符串转换为POJO对象
    • 用于获取请求(消息)体的内容,不适用于GET请求方式
  • 后台return对象,可以通过@ResponseBody注解,将后台的对象转换为JSON格式的字符串。

代码演示,页面

<%@page pageEncoding="UTF-8" contentType="text/html; UTF-8" %>


vue+axios


SpringMVC框架和AJAX进行交互  JSON


{{accoutList}}







Controller

package com.bdit.controller;


import com.bdit.pojo.Account;
import  org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList; import java.util.List;

 @RestController
@RequestMapping(value = {"/ajax"}) public class AjaxJsonController {


@RequestMapping(value = {"/textAjax"})
public Account testAjax(@RequestBody Account account){ System.out.println("account====>"+account); List list=new ArrayList<>();
Account account1=new Account(); account1.setId(1002);
account1.setName("哈哈哈1");
account1.setMoney(11111.3);

Account account2=new Account(); account2.setId(1003); account2.setName("哈哈哈2"); account2.setMoney(12221.3);

Account account3=new Account(); account3.setId(1004); account3.setName("哈哈哈4"); account3.setMoney(1441111.3); list.add(account1); list.add(account2); list.add(account3);
return account1;
                                                     }
}
14.2 REST和RESTful

REST(Representational State Transfer):表现层状态转移,是一种软件架构风格。REST并没有一个明确的标准,而更像是一种设计的风格。它本身并没有什么实用性,其核心价值在于如何设计出符合REST风格的API。

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一 张图片、一首歌曲、一种服务、总之就是一个就具体的存在,可以用一个URI(统一资源定位符)指向 它,每种资源对应一个特定的URI,要获取这个资源,访问它的URI就可以,因此URI即为每个资源 的独一无二的识别符。
  • 表现层(Representational):把资源具体呈现出来的形式,叫做它的表现层。 比如:文本可以用txt 格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式。
  • 状态转化 (State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。 HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必 须通过某种手段,让服务器端发生“状态转化”,而这种转化是建立在表现层之上的,所以就是“表现 层状态转化”。具体说,就是HTTP协议里面,四个表示操作方式的动词,GET、POST、PUT、

DELETE。他们分别对应四种基本操作,GET用来获取资源,POST用来新建资源,PUT用来更新资 源,DELETE用来删除资源。

【RESTful就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格,基于这个风格设 计的软件可以更加简洁、更有层次】

14.3 使用RESTful操作资源

先定义对象

http://localhost:8080/springmvc/account/1 操作对象account,查询GET

http://localhost:8080/springmvc/account 新增 POST

http://localhost:8080/springmvc/account 更新 PUT

http://localhost:8080/springmvc/account/1 删除 DELETE

14.4 传统方式操作资源

操作啥(原来URL)?操作谁(传入的参数)

url中先定义动作,然后传递的参数表明这个动作操作的是哪个对象

先定位动作,然后定位对象

http://localhost:8080/springmvc/account/findById?id=1 查询

http://localhost:8080/springmvc/account/saveAccount 新增

http://localhost:8080/springmvc/account/updateAccount 更新

http://localhost:8080/springmvc/account/delete?id=1 删除

14.5 HiddenHttpMethodFilter过滤器

由于浏览器form表单只支持GET与POST请求。而DELETE,PUT等method并不支持,Spring3.0之后添 加了一个过滤器,可以将浏览器请求改为指定的请求方式,发送给处理器的方法,使得支持GET、POST、PUT与DELETE请求。

package com.bdit.controller;

import com.bdit.pojo.Account;
import org.springframework.web.bind.annotation.*;


@RestController
public class Aone {

    @RequestMapping(value = {"/account/{id}"},method = RequestMethod.GET)
    public String gett(@PathVariable("id")Integer id){
        System.out.println("GET================="+id);
        return "info";
    }

    @RequestMapping(value = {"/account/{id}"},method = RequestMethod.DELETE)
    public String deflect(@PathVariable("id") Integer integer){
        System.out.println(integer+"========删除============");
        return "info";
    }

    @RequestMapping(value = {"/account"},method = RequestMethod.PUT)
    public String findById(Account account){
        System.out.println(account+"========修改============");
        return "info";
    }

    @RequestMapping(value = {"/account"},method = RequestMethod.POST)
    public String query(Account account){
        System.out.println(account+"========查询============");
        return "info";
    }

}
<%--
  Created by IntelliJ IDEA.
  User: Ling
  Date: 2020/11/15
  Time: 11:59
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    index


Hello World!

GET


账户名:
money:
账户名:
money:
15、SpringMVC实现文件上传 15.1 SpringMVC实现本地的上传
  • 注意:
    • from表单的请求方式必须是 post
    • 添加from表单参数 enctype(enctype=“multipart/from-data”)
    • 添加依赖:commons-fileupload,commons-io

本地上传

  • 引入依赖
  
    
      commons-fileupload
      commons-fileupload
      1.4
    
  • spring-mvc.xml配置文件上传解析器和相关参数
    
    
        
        
            
            5242880
        
    
  • 页面配置

姓名:

文件:

  • Controller
package com.bdit.file;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;


@Controller
public class Fileuplode {

    
    @RequestMapping(value = "/load")
    public String uplode(MultipartFile multipartFile, HttpServletRequest request){
        //通过UUID来编写新的文件名称
        String uuid = UUID.randomUUID().toString();
        System.out.println(uuid);
        //获取文件名称
        String filename = multipartFile.getOriginalFilename();
        System.out.println(filename);
        //获取上传路径
        String realPath = request.getSession().getServletContext().getRealPath(request.getContextPath()+"/upload/");
        //创建一个file对象
        File file = new File(realPath,uuid+filename);
        //实现上传
        try{
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "success";
    }
}

15.2 跨服上传
  • 引入依赖
  
    
    
      com.sun.jersey
      jersey-core
      1.19.4
    
    
    
      com.sun.jersey
      jersey-client
      1.19.4
    
  • 可以通过修改Tomcat配置等来实现跨服

    • Tomcat默认不能跨服

      • 在 tomcat/conf/web.xml 中,找到 defaultServlet配置添加
      
      readonly
      false
      
      
    • 增加一个tomcat并且更改其端口号和本地地址

      • 创建一个web项目,并在其webapp目录下创建一个upload目录,在upload目录下创建一个新的文件,否则,这个upload目录则不会编译
  • Controller代码

package com.bdit.file;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;


@Controller
public class FileRealm {

    @RequestMapping(value = "/realm")
    public String realm(MultipartFile multipartFile, HttpServletRequest request){
        //32位随机数  .replace("-"," ")
        String uuid = UUID.randomUUID().toString();
        //文件名称
        String filename = multipartFile.getOriginalFilename();
        //获取文件的后缀
        String str = filename.substring(filename.lastIndexOf("."));
        //跨服上传的地址
        String serverUrl = "http://localhost:8081/springmvc_file_02/upload";
        Client client = Client.create();
        WebResource resource = client.resource(serverUrl+"/"+uuid+str);
        try{
            resource.put(String.class,multipartFile.getBytes());
        }catch (IOException io){
            io.printStackTrace();
        }
        return "success";
    }
}
16、SpringMVC中异常的统一处理
  • 需要先定义一个异常解析器
package com.bdit.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        e.printStackTrace();
        ModelAndView mav = new ModelAndView();
        mav.addObject("yichang","系统出错"+e.getMessage());
        mav.setViewName("error");
        return mav;
    }
}

  • 在spring-mvc.xml配置


17、SpringMVC拦截器 17.1 拦截器简介
  • Servlet:处理Request请求和Response响应
  • 过滤器(Filter):对Request请求起到过滤的作用,在请求到达Servlet之前,如果配置为 public class BlockerHhelp implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=================请求到达拦截器1======================"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("================== 拦截器1 在Handler方法执行完成,但是还未进行页面跳转=================="); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("================== 拦截器1 响应执行完毕===================="); } }

spring-mvc.xml


    
        <!–拦截当前目录下的所有子目录–">>
        
        if ("jiayi".equals(name) && "1234".equals(password)){
            request.getSession().setAttribute("name",name);
            return "redirect:/findall/queryAll";
        }else{
            return "redirect:/index.jsp";
        }
    }
}

FindAll.java

package com.bdit.blocker.anli;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;


@Controller
@RequestMapping(value = "/findall")
public class FindAll {

    @RequestMapping(value = "/queryAll")
    public String queryAll(Model model){
        model.addAttribute("model",new Date());
        return "lanjieqi";
    }
}

AnliLanJieQi.java

package com.bdit.blocker;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class AnliLanJieQi implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求的URL
        String url = request.getRequestURI();
        System.out.println("===拦截器中获取的请求的URL="+url);
        //判断是否是请求登录,如果是就放行
        if ("/springmvc_dom05_file/save".equals(url)){
            return true;
        }
        //如果不是请求登录,则利用Session判断是否存储了用户名
        Object obj = request.getSession().getAttribute("name");
        if (obj!=null){
            //如果有,就放行
            return true;
        }else{
            //如果没有登录,跳转到登录页面
            response.sendRedirect("/springmvc_dom05_file/");
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
 System.out.println("================== 拦截器1 响应执行完毕====================");
    }
}
spring-mvc.xml


    
        <!–拦截当前目录下的所有子目录–>
        
        if ("jiayi".equals(name) && "1234".equals(password)){
            request.getSession().setAttribute("name",name);
            return "redirect:/findall/queryAll";
        }else{
            return "redirect:/index.jsp";
        }
    }
}

FindAll.java

package com.bdit.blocker.anli;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;


@Controller
@RequestMapping(value = "/findall")
public class FindAll {

    @RequestMapping(value = "/queryAll")
    public String queryAll(Model model){
        model.addAttribute("model",new Date());
        return "lanjieqi";
    }
}

AnliLanJieQi.java

package com.bdit.blocker;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class AnliLanJieQi implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取请求的URL
        String url = request.getRequestURI();
        System.out.println("===拦截器中获取的请求的URL="+url);
        //判断是否是请求登录,如果是就放行
        if ("/springmvc_dom05_file/save".equals(url)){
            return true;
        }
        //如果不是请求登录,则利用Session判断是否存储了用户名
        Object obj = request.getSession().getAttribute("name");
        if (obj!=null){
            //如果有,就放行
            return true;
        }else{
            //如果没有登录,跳转到登录页面
            response.sendRedirect("/springmvc_dom05_file/");
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/912315.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号