温馨提示:这篇文章已超过454天没有更新,请注意相关的内容是否还可用!
摘要:Spring是一个流行的Java开源框架,旨在简化企业级应用程序的开发。它提供了全面的功能,包括依赖注入、事务管理、数据访问和Web应用程序开发等。Spring框架通过减少代码冗余和复杂性,提高了开发效率,并促进了模块化开发。它还支持各种企业级服务,如安全性、集成和消息传递等。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 的主要步骤通常包括:
配置数据源:在 Spring 的配置文件中配置数据源(DataSource),指定数据库连接信息。
配置 SQL 会话工厂:通过 Spring 的 SqlSessionFactoryBean 来创建 MyBatis 的 SqlSessionFactory。这个工厂 bean 负责根据数据源和 MyBatis 的配置文件来创建 SqlSessionFactory。
配置映射器:在 Spring 中配置 MyBatis 的映射器(Mapper),这样就可以通过 Spring 的依赖注入功能将映射器注入到业务逻辑层。
事务管理:利用 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
实现
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对象及完成依赖注入操作
- 使用“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
- 对于引用数据类型,需要使用“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 getAll(); }
业务层标准开发
BookService
public interface BookService { void add(Book book); void delete(int id); void update(Book book); Book getById(int id); List 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 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 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功能
通过前端发送请求,后端返回数据实现。这里不赘述。
还没有评论,来说两句吧...