Spring

  希望这遍博客可以帮助你,共同进步!

💕喜欢的朋友可以关注一下,下次更新不迷路!💕(●'◡'●)

 

目录

前言

Bean

IoC控制反转

 DI依赖注入

注入引用类型

注入基本数据类型 

注入集合

注解开发

AOP

 AOP切入表达式

AOP通知类型

事务

 事务隔离

Spring的事务支持

编程式事务

 声明式事务

事务管理模型

PlatformTransactionManager

事务传播行为

Spring事务隔离级别(与数据库事务隔离不同)

事务超时时间

事务的只读属性

事务的回滚策略

@Transaction失效场景

SSM整合

配置

SpringConfig

JdbcConfig、jdbc.properties

MybatisConfig

模型

Book

数据层标准开发

BookDao

业务层标准开发

BookService

BookServiceImpl

测试接口

BookServiceTest

 异常处理器

前后端联调

访问静态资源

crud功能


 

前言

Spring 整合 MyBatis 指的是将 MyBatis 这个持久层框架与 Spring 框架结合起来使用,以充分利用两个框架的优点。

Spring 是一个轻量级的 Java 企业级应用开发框架,而 MyBatis 是一个 SQL 映射框架,它允许开发者以 XML 或注解的方式将 SQL 语句与 Java 方法关联起来,使得数据库的操作更加便捷。

Spring 整合 MyBatis 的主要步骤通常包括:

  1. 配置数据源:在 Spring 的配置文件中配置数据源(DataSource),指定数据库连接信息。

  2. 配置 SQL 会话工厂:通过 Spring 的 SqlSessionFactoryBean 来创建 MyBatis 的 SqlSessionFactory。这个工厂 bean 负责根据数据源和 MyBatis 的配置文件来创建 SqlSessionFactory

  3. 配置映射器:在 Spring 中配置 MyBatis 的映射器(Mapper),这样就可以通过 Spring 的依赖注入功能将映射器注入到业务逻辑层。

  4. 事务管理:利用 Spring 的事务管理功能来管理 MyBatis 执行数据库操作的 transaction。通常情况下,会使用 Spring 的声明式事务管理。

Bean

【Java基础】Spring 中 Bean 的理解与使用_spring中的bean-CSDN博客

例子:

创建一个ApplicationContext对象,它是Spring框架的核心接口,用于提供Bean的创建、管理和访问。

ApplicationContext称为Spring上下文容器,它是Spring框架中一个核心接口,是Spring IoC容器的顶层接口。

该函数通过传入一个SpringConfig.class参数,告诉Spring容器使用该配置类来加载Bean的定义信息,并自动扫描包路径下所有的组件。

通过这个ApplicationContext对象,我们可以获取到容器中所有的Bean实例,方便进行依赖注入和统一管理。

通过ctx.getBean()方法从Spring上下文中获取一个BookDao类型的Bean实例。

BookDao是一个数据访问对象,用于对Book实体进行数据库操作。

通过注入BookDao,可以在其他Bean中使用它来执行数据库操作,例如查询、插入、更新或删除书籍信息。 

IoC控制反转

定义

使用对象时,在程序不要主动使用new产生对象,转换由外部提供对象

Spring提供了一个IoC容器,用来充当“外部”

IoC容器负责对象的创建,初始化等工作,被创建或管理的对象统称为Bean

在容器中建立Bean和Bean之间的依赖关系,称为依赖注入

问题

业务层
public class BookServiceImpl implements BookService{
    private BookDao bookDao = new BookDaoImpl();
    //改为private BookDao bookDao =new BookDaoImPl2()时需要大量修改代码
    
    public void save(){
        bookDao.save();
    }
}
数据层实现
public class BookDaoImpl implements BookDao{
    public void save(){
        System.out.println("book dao save...");
    }
}

public class BookDaoImpl2 implements BookDao{
    public void save(){
        System.out.println("book dao save...2");
    }
}

 解决

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--1.导入spring的坐标spring-context,对应版本是5.2.10.RELEASE-->

    <!--2.配置bean-->
    <!--bean标签标示配置bean
    id属性标示给bean起名字
    class属性表示给bean定义类型-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--7.配置server与dao的关系-->
        <!--property标签表示配置当前bean的属性
        name属性表示配置哪一个具体的属性
        ref属性表示参照哪一个bean-->
        <property name="bookDao" ref="bookDao"/>
    </bean>

</beans>

实现 

public class App2 {
    public static void main(String[] args) {
        //3.获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取bean(根据bean配置id获取)
//        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//        bookDao.save();

        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();

    }
}

 DI依赖注入

【Spring】依赖注入之 setter 注入、构造器注入_setter注入和构造器注入-CSDN博客

1、简介

  • 简单来说,依赖注入就是通过某种方式给属性赋值。
  • 依赖注入有两种方式,一种是setter注入;另一种是构造器注入。
  • 注入的数据类型有:基本数据类型和引用数据类型。

2、注入方式的选择

  • 对于强制依赖关系,可以使用构造器注入方式,因为在创建对象时一定会调用到构造器方法;而setter注入方法有较低概率不进行注入。
  • 在自己开发过程中,一般情况下更推荐使用setter注入方式。

3、setter注入

注入引用类型

1.定义所需dao层接口及其实现类,service接口及其实现类 

1)BeanDao接口

public interface BeanDao {
    public void save();
}

2)BeanDaoImpl实现类

public class BeanDaoImpl implements BeanDao {
    public void save() {
        System.out.println("beanDao save...");
    }
}

 3)BeanService接口

public interface BeanService {
    public void save();
}

4)BeanServiceImpl实现类,该类需要依赖注入BeanDao 

public class BeanServiceImpl implements BeanService {
    private BeanDao beanDao;

    public void setBeanDao(BeanDao beanDao) {
        this.beanDao = beanDao;
    }

    public void save() {
        System.out.println(" bean service save...");
        beanDao.save();
    }
}

 2、applicationContext.xml文件中配置bean对象及完成依赖注入操作

<bean id="beanDao" class="dao.impl.BeanDaoImpl"/>
<bean id="beanService" class="service.impl.BeanServiceImpl">
    <property name="beanDao" ref="beanDao" />
</bean>
  • 使用“property”标签来实现依赖注入操作。
  • 其中“name”属性指"BeanServiceImpl"类中指定的属性名
  • “ref”属性指定前面创建的bean对象的id属性值“beanDao"。

3、测试代码 

public class App {
    public static void main(String[] args) {
        // 加载配置文件,获得上下文对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanService beanService = (BeanService) context.getBean("beanService");
        beanService.save();
    }
}

4、测试结果 

bean service save...
beanDao save...

注入基本数据类型 

1、定义所需dao层接口及其实现类

1)BeanDao接口

public interface BeanDao {
    public void save();
}

2)BeanDaoImpl实现类 - 定义了String类型的name和Integer类型的age及setter方法 

public class BeanDaoImpl implements BeanDao {
    private String name;
    private Integer age;

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

    public void setAge(Integer age) {
        this.age = age;
    }

    public void save() {
        System.out.println("beanDao save...");
        System.out.println("name : " + name + " , age : " + age);
    }
}

2、在xml文件中配置bean 

<bean id="beanDao" class="dao.impl.BeanDaoImpl">
    <property name="name" value="qdxorigin"/>
    <property name="age" value="22"/>
</bean>
  • 对于引用数据类型,需要使用“ref”属性指定bean对象的id属性值。
  • 而对于基本数据类型,只需要通过“value”属性直接赋值即可。

 3、编写测试代码

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BeanDao beanDao = (BeanDao) context.getBean("beanDao");
        beanDao.save();
    }
}

4、测试结果 

beanDao save...
name : qdxorigin , age : 22
//成功输出则证明注入成功

注入集合

Spring——集合依赖注入_springboot 数组,集合依赖注入-CSDN博客

注解开发

注解开发定义Bean,纯注解开发,bean的作用范围和生命周期,第三方的bean管理,xml和注解的区别_定义第三方bean使用的注解是什么-CSDN博客

AOP

定义:面向切面编程,一种编程范式,用于指导开发者如何组织程序结构;类似oop:面向对象编程

用法:将代码中共性的方法抽取出来写成通知类,类似写接口,让有需要的地方实现接口(利用AOP可以对业务逻辑 的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高 了开发的效率。)

 AOP切入表达式

AOP通知类型

事务

Spring的事务详解

事务感觉类似于Java的多线程

简介:事务在逻辑上是一组操作,要么执行,要不都不执行。主要是针对数据库而言的。

原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
 

一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
 

事务隔离(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
 

持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

 事务隔离

事务能否生效,取决于数据库引擎是否支持事务,MySQL 的 InnoDB 引擎是支持事务的,但 MyISAM 就不支持。

未提交读(Read uncommitted),最低的隔离级别,允许“脏读”(dirty reads),事务可以看到其他事务“尚未提交”的修改。如果另一个事务回滚,那么当前事务读到的数据就是脏数据。
 

提交读(read committed),一个事务可能会遇到不可重复读(Non Repeatable Read)的问题。不可重复读是指,在一个事务内,多次读同一数据,在这个事务还没有结束时,如果另一个事务恰好修改了这个数据,那么,在第一个事务中,两次读取的数据就可能不一致。
 

可重复读(repeatable read),一个事务可能会遇到幻读(Phantom Read)的问题。幻读是指,在一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在的记录时,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。
 

串行化(Serializable),最严格的隔离级别,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。虽然 Serializable 隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用 Serializable 隔离级别。

Spring的事务支持

Spring 支持两种事务方式,分别是编程式事务和声明式事务,后者最常见,通常情况下只需要一个 **@Transactional **就搞定了(代码侵入性降到了最低)

编程式事务

编程式事务是指将事务管理代码嵌入嵌入到业务代码中,来控制事务的提交和回滚。

比如说,使用 TransactionTemplate 来管理事务:

//注入开启事务所需要的对象
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
        //执行其中的方法
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            //重写其中的方法,实现”提交事务“和”回滚事务“
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

                try {

                    // ....  业务代码
                } catch (Exception e){
                    //回滚
                    transactionStatus.setRollbackOnly();
                }

            }
        });
}

 声明式事务

声明式事务将事务管理代码从业务方法中抽离了出来(也就是在业务层中声明),以声明式的方式来实现事务管理。

要想实现事务管理和业务代码的抽离,就必须得用到 Spring 当中的AOP,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚。

比如说,使用@Transactional

/**
 * 模拟转账
 */
@Transactional
public void handle() {
 // 转账
 transfer(double money);
 // 减自己的钱
  Reduce(double money);
}

事务管理模型

Spring 将事务管理的核心抽象为一个事务管理器(TransactionManager(父类)),它的源码只有一个简单的接口定义,属于一个标记接口:

该接口有两个子接口,分别是编程式事务接口 ReactiveTransactionManager(子类) 和声明式事务接口 PlatformTransactionManager(子类)。

public interface TransactionManager {

}
PlatformTransactionManager

通过 PlatformTransactionManager 这个接口,Spring 为各个平台如 JDBC(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

interface PlatformTransactionManager extends TransactionManager{
    // 根据事务定义获取事务状态
    TransactionStatus getTransaction(TransactionDefinition definition)
            throws TransactionException;

    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;

    // 事务回滚
    void rollback(TransactionStatus status) throws TransactionException;
}

 参数类TransactionDefinition 和 @Transactional 注解是对应的,比如说 @Transactional 注解中定义的事务传播行为、隔离级别、事务超时时间、事务是否只读等属性,在 TransactionDefinition 都可以找得到。返回类型 TransactionStatus 主要用来存储当前事务的一些状态和数据,比如说事务资源(connection)、回滚状态等。
TransactionDefinition如下:

public interface TransactionDefinition {

 // 事务的传播行为
 default int getPropagationBehavior() {
  return PROPAGATION_REQUIRED;
 }

 // 事务的隔离级别
 default int getIsolationLevel() {
  return ISOLATION_DEFAULT;
 }

  // 事务超时时间
  default int getTimeout() {
  return TIMEOUT_DEFAULT;
 }

  // 事务是否只读
  default boolean isReadOnly() {
  return false;
 }
}

@Transactional注解包含如下参数:

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

 Propagation propagation() default Propagation.REQUIRED;
 Isolation isolation() default Isolation.DEFAULT;
  int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
  boolean readOnly() default false;

}

@Transactional 注解中的 propagation 对应 TransactionDefinition 中的 getPropagationBehavior,默认值为 Propagation.REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED)。
@Transactional 注解中的 isolation 对应 TransactionDefinition 中的 getIsolationLevel,默认值为 DEFAULT(TransactionDefinition.ISOLATION_DEFAULT)。
@Transactional 注解中的 timeout 对应 TransactionDefinition 中的 getTimeout,默认值为TransactionDefinition.TIMEOUT_DEFAULT。
@Transactional 注解中的 readOnly 对应 TransactionDefinition 中的 isReadOnly,默认值为 false。

事务传播行为

当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。
声明式事务的传播行为可以通过 @Transactional 注解中的 propagation 属性来定义,比如说: 

@Transactional(propagation = Propagation.REQUIRED)
public void savePosts(PostsParam postsParam) {
}

 TransactionDefinition 一共定义了 7 种事务传播行为

PROPAGATION_REQUIRED
这也是 @Transactional 默认的事务传播行为,指的是如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。更确切地意思是:
如果外部方法没有开启事务的话,Propagation.REQUIRED 修饰的内部方法会开启自己的事务,且开启的事务相互独立,互不干扰。
如果外部方法开启事务并且是 Propagation.REQUIRED 的话,所有 Propagation.REQUIRED 修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务都需要回滚。

也就是说如果a方法和b方法都添加了注解,在默认传播模式下,a方法内部调用b方法,会把两个方法的事务合并为一个事务。

PROPAGATION_REQUIRES_NEW
创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都会开启自己的事务,且开启的事务与外部的事务相互独立,互不干扰。

当类A中的 a 方法用默认 Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.REQUIRES_NEW模式,然后在 a 方法中调用 b方法操作数据库,然而 a方法抛出异常后,b方法并没有进行回滚,因为Propagation.REQUIRES_NEW会暂停 a方法的事务 ,总结就是a不影响b,b影响a

PROPAGATION_NESTED
如果当前存在事务,就在当前事务内执行;否则,就执行与 PROPAGATION_REQUIRED 类似的操作。

当类A中的 a 方法用默认 Propagation.REQUIRED模式,类B中的 b方法加上采用 Propagation.NESTED模式,然后在 在a 方法里调用 b方法操作数据库,然而 b方法抛出异常后,a方法是不的回滚 ,总结就是b不影响a,a影响b。

PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

PROPAGATION_NOT_SUPPORTED
以非事务方式运行,如果当前存在事务,则把当前事务挂起。

PROPAGATION_MANDATORY
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

PROPAGATION_NEVER
以非事务方式运行,如果当前存在事务,则抛出异常。

Spring事务隔离级别(与数据库事务隔离不同)

TransactionDefinition 中一共定义了 5 种事务隔离级别:

ISOLATION_DEFAULT,使用数据库默认的隔离级别,MySql 默认采用的是 REPEATABLE_READ也就是可重复读。
ISOLATION_READ_UNCOMMITTED最低的隔离级别,可能会出现脏读、幻读或者不可重复读。
ISOLATION_READ_COMMITTED允许读取并发事务提交的数据,可以防止脏读,但幻读和不可重复读仍然有可能发生。
ISOLATION_REPEATABLE_READ,对同一字段的多次读取结果都是一致的,除非数据是被自身事务所修改的,可以阻止脏读和不可重复读,但幻读仍有可能发生。
ISOLATION_SERIALIZABLE,最高的隔离级别,虽然可以阻止脏读、幻读和不可重复读,但会严重影响程序性能。
通常情况下,我们采用默认的隔离级别 ISOLATION_DEFAULT 就可以了,也就是交给数据库来决定。

事务超时时间

事务超时**timeout **,也就是指一个事务所允许执行的最长时间,如果在超时时间内还没有完成的话,就自动回滚。
假如事务的执行时间格外的长,由于事务涉及到对数据库的锁定,就会导致长时间运行的事务占用数据库资源。

事务的只读属性

事务的只读属性readOnly, 如果一个事务只是对数据库执行读操作,那么该数据库就可以利用事务的只读属性,采取优化措施,适用于多条数据库查询操作中。
为什么一个查询操作还要启用事务支持呢?
这是因为 MySql(innodb)默认对每一个连接都启用了 autocommit 模式,在该模式下,每一个发送到 MySql 服务器的 SQL 语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务。
那如果我们给方法加上了 @Transactional 注解,那这个方法中所有的 SQL 都会放在一个事务里。否则,每条 SQL 都会单独开启一个事务,中间被其他事务修改了数据,都会实时读取到。
有些情况下,当一次执行多条查询语句时,需要保证数据一致性时,就需要启用事务支持。否则上一条 SQL 查询后,被其他用户改变了数据,那么下一个 SQL 查询可能就会出现不一致的状态。

事务的回滚策略

类似于Java的异常处理

**回滚策略rollbackFor **,用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。默认情况下,事务只在出现运行时异常(Runtime Exception)时回滚,以及 Error,出现检查异常(checked exception,需要主动捕获处理或者向上抛出)时不回滚。

也可设置不回滚。

只有运行时异常出现,事务才会回滚(编译时异常如IOException则事务不会回滚)

@Transaction失效场景

protected、private修饰的方法上使用 @Transactional 注解,虽然事务无效,但不会有任何报错。

propagation设置问题,会导致事务不生效,也就事务不会回滚
rollbackFor指定事务回滚的异常类型
同个类中的调用被@transaction修饰的方法,会失效,因为只有当事务方法被当前类以外的代码调用,才会由spring生成的代理对象来管理。

 

try catch导致失效
 

数据库不支持事务

SSM整合

配置

SpringConfig

@Configuration    //说明为配置类
@ComponentScan("com.itheima")    //指示Spring在启动时应该扫描哪些包以及它们的子包,以查找带有        
                                    @Component注解的类,并将其自动注册为Spring容器中的Bean。
@PropertySource("classpath:jdbc.properties")    //设置jdbc.properties文件中的数据库为数据源
@Import({JdbcConfig.class,MybatisConfig.class})    //导入两个配置类
public class SpringConfig{
}

JdbcConfig、jdbc.properties

public class JdbcConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=1234567

MybatisConfig

public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setTypeAliasesPackage("com.example.pojo");
        factoryBean.setDataSource(dataSource);
        return factoryBean;
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.example.mapper");
        return configurer;
    }
}

模型

Book

public class Book {
    private Integer id;
    private String name;
    private String type;
    private String description;
}

数据层标准开发

BookDao

public interface BookDao {
    @Insert("insert into book(name,author,price) values(#{name},#{author},#{price})")
    void add(Book book);
    @Delete("delete from book where id=#{id}")
    void delete(int id);
    @Update("update book set name=#{name},author=#{author},price=#{price} where id=#{id}")
    void update(Book book);
    @Select("select * from book where id=#{id}")
    Book getById(int id);
    @Select("select * from book")
    List<Book> getAll();
}

业务层标准开发

BookService

public interface BookService {
    void add(Book book);
    void delete(int id);
    void update(Book book);
    Book getById(int id);
    List<Book> getAll();
}

BookServiceImpl

public class BookServiceImpl implements BookService{
    @Autowired
    private BookDao bookDao;
    @Override
    public void add(Book book) {
        bookDao.add(book);
    }

    @Override
    public void delete(int id) {
        bookDao.delete(id);
    }

    @Override
    public void update(Book book) {
        bookDao.update(book);
    }

    @Override
    public Book getById(int id) {
        return bookDao.getById(id);
    }

    @Override
    public List<Book> getAll() {
        return bookDao.getAll();
    }
}

测试接口

BookServiceTest

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class BookServiceTest {
    @Autowired
    private BookService bookService;
    @Test
    public void testGetById()
    {
        Book book = bookService.getById(1);
        System.out.println(book);
    }
    @Test
    public void testGetAll()
    {
        List<Book> list = bookService.getAll();
        for (Book book : list)
        {
            System.out.println(book);
        }
    }
}

 异常处理器

@RestControllerAdvice    //该注解相当于处理器的开关
public class ProjectExceptionAdvice{
    @ExceptionHandler(Exception.class)   //括号内填写异常类名,表示需要处理哪些异常
 //指定了当任何类型的Exception发生时,应该调用这个方法来处理。
    public Result doException(Exception ex){
        return new Result(666,null);
    }
}

异常又可分为业务异常,系统异常,自定义异常。

系统异常:

@RestControllerAdvice
public class ProjectExceptionAdvice{
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员
        return new Result(ex.getCode(),ex.getMessage());//返回异常的编号和异常信息
}

前后端联调

访问静态资源

由于Servlet设置了Filter,因此在访问页面时需要放行映射到某个资源路径上。 SpringMvc拦截器

例子: 

1、创建拦截器

首先,创建一个拦截器类,实现HandlerInterceptor接口:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 请求处理前执行的操作
        System.out.println("Pre-handle logic...");
        return true; // 如果返回false,则不会继续执行后续的操作
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 请求处理后执行的操作
        System.out.println("Post-handle logic...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 请求完成后执行的操作
        System.out.println("After-completion logic...");
    }
}

 2、注册拦截器

在Spring MVC的配置文件中注册拦截器:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**") // 指定拦截的URL路径模式
                .excludePathPatterns("/static/**"); // 排除静态资源的URL路径模式
    }
}

3、映射静态资源

在Spring MVC的配置文件中,你可以通过ResourceHandlerRegistry来映射静态资源:

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/") // 指定静态资源的实际位置
            .setCachePeriod(365 * 24 * 60 * 60); // 设置缓存有效期(秒)
}

完整 

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")// 指定拦截的URL路径模式
                .excludePathPatterns("/static/**");// 排除静态资源的URL路径模式
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")// 指定静态资源的实际位置
                .setCachePeriod(365 * 24 * 60 * 60);// 设置缓存有效期(秒)
    }
}

 这样,当请求URL匹配/static/**模式时,Spring MVC会从classpath:/static/目录下查找静态资源,并返回给客户端。

crud功能

通过前端发送请求,后端返回数据实现。这里不赘述。

  • 36
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值