首页 > 其他分享 >Spring

Spring

时间:2023-04-09 16:33:14浏览次数:31  
标签:Spring springframework class bean import org public

Spring

核心概念

IoC(控制反转)

(Inversion of Control)

概念

使用对象时,由主动new产生对象转换为由外部提供对象,在此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。

Spring提供了一个容器,称为Ioc容器,用来充当Ioc思想中的“外部”。

IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean。

Ioc入门案例

  • 管理什么? (Service与Dao)
  • 如何将被管理的对象告知Ioc容器? (配置)
  • 被管理的对象交给Ioc容器,如何获取到Ioc容器? (接口)
  • Ioc容器得到之后,如何从容器中获取bean? (接口方法)

DI(依赖注入)

(Dependency Injection)

概念

在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。

目标:充分解耦

  • 使用IoC容器管理bean

  • 在IoC容器内将有依赖关系的bean进行关系绑定

使用对象时不仅可以直接从IoC中取,并且获取到的bean已经绑定了所有的依赖关系。

DI入门案例

  • 基于Ioc管理 bean
  • Service中使用new的形式创建的Dao对象是否保留? (否)
  • Service中需要的Dao对象如何进入到Service中? (提供方法)
  • Service与Dao的关系如何描述? (配置)

AOP(面向切面编程)

(Aspect Oriented Programming)

概念

一种编程范式,指导开发者如何组织程序结构

作用:在不惊动原始设计的基础上为其进行功能增强

Spring理念:无侵入式编程

  • 连接点

    连接点是在应用执行过程中能够插入切面(Aspect)的一个点。这些点可以是调用方法时、甚至修改一个字段时。它是一个虚拟的概念,例如坐地铁的时候,每一个站都可以下车,那么这每一个站都是一个连接点。假如一个对象中有多个方法,那么这个每一个方法就是一个连接点。

    在SpringAOP中,理解为方法的执行

  • 通知

    通知定义了何时,做什么。

    在SpringAOP中,最终体现为方法

  • 切入点

    切入点是一些特使的连接点,是具体附加通知的地方。例如坐地铁的时候,具体在某个站下车,那这个站就是切入点。

    在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法

  • 切面

    切面是通知和切入点的结合,通知规定了在什么时机干什么事,切入点规定了在什么地方。如“在8点钟在西站下车“ 就是一个切面。那么时间8点,动作下车就是一个通知。西站就是一个切入点。

AOP入门案例

  • 制作连接点方法
  • 制作共性功能(通知)
  • 定义切入点
  • 绑定切入点与通知

AOP工作流程

  • Spring容器启动

  • 读取所有切面配置中的切入点(也就是绑定通知的切入点)

  • 初始化bean,判定bean对应类中的方法是否匹配上述切入点

    • 匹配失败,直接创建对象
    • 匹配成功,创建原始对象(目标对象)的代理对象
  • 获取bean执行方法

    • 获取bean,调用方法并执行,完成操作
    • 获取的bean是代理对象,根据代理对象的运行模式运行原始方法与增强内容,完成操作
  • 核心概念

    • 目标对象

      原始功能去掉共性功能对应的类产生的对象,这种对象是无法完成最终工作的

    • 代理

      目标对象无法完成工作,需要对其进行功能回填,通过原始对象的代理对象实现

    • SpringAOP本质:代理模式

AOP切入点表达式

  • 切入点:要进行增强的方法

  • 切入点表达式:对要进行增强的方法的描述方式

  • 切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数) 异常名)

    • 动作关键字:描述切入点执行的动作,例如execution表示执行到切入点
    • 访问修饰符:public、private等,可省略
    • 异常名,可省略
  • 可以使用通配符描述切入点

    • *:单个独立的任意符号(一个单词),可以独立出现,也可以作为前缀或者后缀的匹配符出现

      execution(public * service.*.UserService.select* (*))
      // 匹配service包中任意包中的UserService接口中select开头的具有一个参数的方法
      
    • ..:多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写

      execution(public * *..UserService.selectAll(..))
      // 匹配任意包下的UserService接口中具有任意参数的selecAll方法
      
    • +:专用于匹配子类类型

      execution(* *..*Service+.*(..))
      // 匹配任意业务层接口的任意方法
      

AOP通知类型

AOP通知描述了抽取的共性功能,根据共性功能抽取的位置不同,最终代码运行时将其加入到合理的位置

AOP通知分为五种类型

  • 前置通知@Before

  • 后置通知@After

    @After("test()")
    public void after(JoinPoint joinPoint) {
        System.out.println("after");
    }
    

    就算方法出现异常,也会执行

    finally类似,在return指令之前执行。并且后于finally的执行

  • 环绕通知@Around

    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("before...");
        joinPoint.proceed();
        System.out.println("after...");
    }
    
  • 返回后通知

    方法正确执行后,才会执行

  • 抛出异常后通知

多种通知共存时,前置通知与后置通知离原始方法更近,环绕通知在两侧执行。也可以说BeforeAfter先与原始方法绑定,再进行Around的增强

AOP通知获取数据

Signature signature = joinPoint.getSignature();
String className = signature.getDeclaringTypeName();
String methodName = signature.getName();
Object[] args = joinPoint.getArgs();
@AfterReturning(value = "test()", returning = "ret")
// 如果JoinPoint和其他参数同时出现,JoinPoint必须是第一个
public void afterReturning(Object ret) {
    System.out.println("after returning: " + ret);
}
@AfterThrowing(value = "test()", throwing = "throwable")
public void afterThrowing(Throwable throwable) {
    System.out.println("after throwing:");
    throwable.printStackTrace();
}

bean配置

bean基础配置

类别 描述
名称 bean
类型 标签
所属 beans标签
功能 定义Spring容器管理的对象
格式 <beans>
<bean></bean>
</beans>
属性列表 id:bean的iid,使用容器可以通过id值获取对应的bean,在一个容器中id唯一
class:bean的类型,即配置的bean的全路径类名

bean别名配置

类别 描述
名称 name
类型 属性
所属 bean标签
功能 定义bean的别名,可以定义多个,使用逗号(,)分号(;)空格( )分隔

bean的作用范围配置

类别 描述
名称 scope
类型 属性
所属 bean标签
功能 定义bean的作用范围
singleton:单例
prototype:非单例

bean作用范围说明

  • 为什么bean默认为单例?
  • 适合交给容器管理的bean
    • 表现层对象
    • 业务层对象
    • 数据层对象
    • 工具对象
  • 不适合交给容器管理的bean
    • 封装实体的域对象

bean实例化

  • bean本质上就是对象,使用构造方法创建bean

  • 使用静态工厂实例化bean

    <bean class="静态工厂全路径类名" factory-method="返回实例对象的静态方法"></bean>
    
  • 使用实例工厂实例化bean

    先创建工厂类的bean

    <bean factory-bean="工厂的bean" factory-method="返回实例对象的方法"></bean>
    
  • 使用FactoryBean实例化bean

    先实现FactoryBean接口,也就是创建了一个工厂类

    <bean> class="实现FactoryBean接口的类的全路径名称"</bean>
    

bean的生命周期

  • 初始化容器
    • 创建对象(分配内存)
    • 执行构造方法
    • 执行属性注入(set操作)
    • 执行bean初始化方法
  • 使用bean
    • 执行业务操作
  • 关闭/销毁容器
    • 执行bean销毁方法

bean的销毁时机

  • 容器关闭前触发bean的销毁
  • 关闭容器方式
    • 手工关闭 close()
    • 注册关闭钩子registerShutdownHook

依赖注入方式

  • 思考:向一个类中传递数据的方式有几种?

    • 普通方法(set方法)
    • 构造方法
  • 思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,如果bean运行需要的是数字或字符串呢?

    • 引用类型
    • 简单类型(基本数据类型与String)
  • 依赖注入方式

    • setter注入(简单类型、引用类型)
    • 构造器注入(简单类型、引用类型)
  • 依赖注入方式选择

    • 强制依赖使用构造器进行
    • 可选依赖使用setter注入进行

依赖自动装配

  • Ioc容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
  • 自动装配方式
    • 按类型(最常用)
    • 按名称
    • 按构造方法

依赖自动装配特征

  • 用于引用类型依赖注入,不能对简单类型进行操作
  • 按类型自动装配(byType)必须保障容器中想同类型的bean唯一
  • 按名称自动装配(byName)必须保障容器中具有指定名称的bean
  • 自动装配优先级低于setter与构造器注入,同时出现时自动装配失效

集合注入

  • Array

    <property>
    	<array>
    		<value>值</value>
    		<ref bean="bean的id"></ref>
    		...
    	</array>
    </property>
    
  • List

    <property>
    	<list>
    		<value>值</value>
    		<ref bean="bean的id"></ref>
    		...
    	</list>
    </property>
    
  • Set

    <property>
    	<set>
    		<value>值</value>
    		<ref bean="bean的id"></ref>
    		...
    	</set>
    </property>
    
  • Map

    <property>
    	<map>
    		<entry key="键" value="值"></entry>
    		...
    	</map>
    </property>
    
  • Properties

    <property>
    	<props>
    		<prop key="键">值</prop>
    		...
    	</props>
    </property>
    

容器

  • 创建容器

    • 方式一:类路径加载配置文件

      ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
      
    • 方式二:文件路径加载配置文件

      ClassPathXmlApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
      
    • 加载多个配置文件

      ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "nean2.xml");
      
  • 获取bean

    • 方式一:使用bean名称获取

      Bookdao bookDao = (BookDao) ctx.getBean("bookDao");
      
    • 方式二:使用bean名称获取并指定类型

      Bookdao bookDao = ctx.getBean("bookDao", BookDao.class);
      
    • 方式三:使用bean类型获取

      Bookdoa bookDao = ctx.getBean(bookDao.class);
      

注解开发

定义bean

  • 以下注解标注在类前,表示该类是一个bean

    @Component

    @Controller

    @Service

    @Repository

  • 配置文件中加入该命名空间,告诉spring去哪些包下扫描、加载bean

    <context:component-scan/>

纯注解开发

  • @Configuration

    定义一个配置类SpringConfig,用此注解标注配置类

  • @ComponentScan

    在配置类上添加此注解扫描bean所在包

    @ComponentScan("包名")@ComponentScan({"包名1", "包名2"...})

  • AnnotationConfigApplicationContext

    传入配置类的class来创建该容器对象

bean作用范围

  • @Scope("singleton")@Scope("prototype")

bean生命周期

  • 使用@PostConstruct、@PreDestroy定义生命周期

依赖注入

  • 自动装配

    @Autowired按类型

    @Qualifier有类型冲突时,指定名称

    @Value实现简单类型注入

  • 加载配置文件

    在配置类中使用@PropertySource注解加载配置文件

    多文件使用数组格式,不支持通配符

    加载之后可使用${变量名}来引用

第三方bean管理

在配置类中导入自定义类

@Import(类.class)	//多个使用数组形式

自定义类中:

定义一个方法,返回要管理的bean
添加@Bean表示当前方法的返回值是一个bean

依赖注入

  • 简单类型

    @Value

    一般要加载配置文件,使用@PropertySource注解

  • 引用类型

    对返回所管理bean的方法,定义形参,Spring会根据类型自动装配(形参类型是已经管理的bean)

Spring引入MyBatis

  • 增加MyBatisConfig配置文件
  • Dao层用注解开发或编写SQL映射文件

Spring事务

事务作用:在数据层保障一系列数据库操作同成功或同失败

Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功或同失败

public interface PlatformTransactionManager extends TransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}
public classs DataSourceTransactionManager {
    ...
}

配置

  • 在Spring配置文件中启用事务的注解开发

    @EnableTransactionManagement
    
  • 定义事务管理对象的bean

    @Bean
    public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
    
  • 在想要添加事务管理的业务层接口(类)上添加Spring事务管理的注解

    @Transactional
    

Spring事务角色

  • 事务管理员

    发起事务方,在Spring中通常代指业务层开启事务的方法

  • 事务协调员

    加入事务方,在Spring中通常代指数据层方法,也可以是业务层方法

Spring事务属性

@Transactional(readOnly = true, timeout = -1, rollbackFor = {Exception.class})

默认只有遇到Error和运行时异常才会回滚,对于其他异常,考虑手动设置回滚。

  • 事务传播行为:事务协调员对事务管理员所携带事务的处理态度
@Transactional(propagation = Propagation.REQUIRES_NEW)
传播属性 事务管理员 事务协调员
REQUIRED 开启 加入
新建
REQUIRES_NEW 开启 新建
SUPPORTS 开启 加入
ERROR
NOT_SUPPORTED 开启
新建
MANDATORY 开启 加入
NEVER 开启 ERROR
NESTED 设置savePoint,一旦回滚事务,回滚到savePoint,交由用户提交/回滚

SpringMVC

简介

  • SpringMVC技术与Servlet技术等同,均属于web层开发技术
  • SpringMVC是一种基于Java实现的基于MVC模型的轻量级web框架

配置

  • 添加配置文件

    @Configuration
    @ComponentScan("controller")
    public class SpringConfig {
    }
    
  • 初始化Servlet容器,加载SpringMVC环境,设置SpringMVC处理的请求

    public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
        // 加载SpringMVC容器的配置
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMVCConfig.class);
            return ctx;
        }
    
        //设置那些请求交给SpringMVC处理
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
        // 加载Spring配置
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringConfig.class);
            ctx.registerShutdownHook();
            return ctx;
        }
    }
    
  • 创建SpringMVC控制器类

    添加@Controller注解

    在方法上添加路由配置的注解@RequestMapping和响应体的注解@ResponseBody

    @Configuration
    public class UserController {
        @RequestMapping("/save")
        @ResponseBody
        public String save() {
            return "save";
        }
    }
    
  • 工作流程

    启动服务器初始化过程

    • 服务器启动,执行ServletContainerInitConfig类,初始化web容器
    • 执行createServletApplicationContext方法,创建WebApplicationContext对象
    • 加载SpringMVCConfig配置类
    • 执行@ComponentScan加载对应的bean
    • 加载Controller类,每个@RequestMapping对应一个具体的方法
    • 执行getServletMappings方法,定义所有的请求都通过SpringMVC

    单次请求过程

    • 发送请求/request
    • web容器发现所有请求都通过SpringMVC,将请求交给SpringMVC处理
    • 解析请求路径/request
    • /request匹配并执行对应的方法
    • 检测到有ResponseBody直接将执行方法的返回值作为响应体返回给请求方

请求与响应

请求映射路径

controller类上添加@RequestMapping("/模块名")以防止请求路径冲突,相当于在该控制类下的每个方法的请求路径之前都加上了模块名

请求方式

  • form-data

    • post: form-data

      它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息;

      由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件。

    • post: x-www-from-urlencoded

      会将表单内的数据转换为键值对

    • post: form-data需要进行额外配置

      在初始化SpringMVC环境时,会尝试加载用户对MultipartResolver的配置,这个接口负责form-data格式数据的处理

      // DispatcherServlet.java
      public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
      
      private void initMultipartResolver(ApplicationContext context) {
          try {
              this.multipartResolver = (MultipartResolver)context.getBean("multipartResolver", MultipartResolver.class);
              if (this.logger.isTraceEnabled()) {
                  this.logger.trace("Detected " + this.multipartResolver);
              } else if (this.logger.isDebugEnabled()) {
                  this.logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
              }
          } catch (NoSuchBeanDefinitionException var3) {
              this.multipartResolver = null;
              if (this.logger.isTraceEnabled()) {
                  this.logger.trace("No MultipartResolver 'multipartResolver' declared");
              }
          }
      }
      

      上述代码尝试获取容器中的MultipartResolver对象,若通过注解开发,生成bean的方法名即是该bean的名称,所以方法名必须为multipartResolver,配置文件同理

      按照正常配置类的编写引入MultipartResolver即可

      MultipartResolver.yml

      defaultEncoding: utf-8
      maxUploadSize: 1073741824
      maxInMemorySize: 10240
      uploadTempDir: file:WEB-INF/uploadFile/tmp
      resolveLazily: true
      

      MultipartResolverConfig.java

      package config;
      
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.PropertySource;
      import org.springframework.core.io.FileSystemResource;
      import org.springframework.web.multipart.MultipartResolver;
      import org.springframework.web.multipart.commons.CommonsMultipartResolver;
      
      import java.io.IOException;
      
      @PropertySource("classpath:MultipartResolver.yml")
      public class MultipartResolverConfig {
          @Value("${defaultEncoding}")
          private String defaultEncoding;
      
          @Value("${maxUploadSize}")
          private long maxUploadSize;
      
          @Value("${maxInMemorySize}")
          private int maxInMemorySize;
      
          @Value("${uploadTempDir}")
          private String uploadTempDir;
      
          @Value("${resolveLazily}")
          private boolean resolveLazily;
          @Bean
          public MultipartResolver multipartResolver() throws IOException {
              CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
              commonsMultipartResolver.setDefaultEncoding(defaultEncoding);
              commonsMultipartResolver.setMaxUploadSize(maxUploadSize);
              commonsMultipartResolver.setMaxInMemorySize(maxInMemorySize);
              commonsMultipartResolver.setUploadTempDir(new FileSystemResource(uploadTempDir));
              commonsMultipartResolver.setResolveLazily(resolveLazily);
              return commonsMultipartResolver;
          }
      }
      

      最后,MultipartResolver是SpringMVC的配置,在对应的配置类中加入@Import(MultipartResolverConfig.class)

      若要接收传过来的文件,参数类型应为MultipartFile

    • 请求参数

      • 普通参数

        • 按照相同名称,自动填入形参
        • @RequestParam("请求参数名称") Type param指定填入
      • 引用类型参数

        • 对象内属性均为基础类型,只要属性名称与请求参数对应即可
        • 对象内属性含有引用类型,通过符号.来描述层次关系
      • 数组参数

        • 请求的相同名称的参数,填入同名数组
      • 集合参数

        • 通过@RequestParam将填入请求参数填入同名集合
      • 日期参数

        • 在形参前加入注解,指定日期格式

          @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date
          
  • json

    • 配置

      <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.0</version>
      </dependency>
      

      在SpringMVC配置中加入@EnableWebMvc

      @EnableWebMvc功能之一:根据类型匹配对应的类型转换器

      接收参数前加入@RequestBody

    • json数据

      • json对象
        • 对象内属性均为基础类型,只要属性名称与请求json的属性名称对应即可
        • 对象内属性含有引用类型,按照json的{}格式来描述
      • json普通数组
        • 传递一个json数组,用相应类型列表接收即可,不要求参数名称
      • json对象数组
        • 传递一个json对象数组,用相应类型列表接收即可,不要求参数名称

响应页面

不需要@ResponseBody,只需要以字符串形式返回页面的名称即可

响应数据

  • @ResponseBody将当前控制器返回值作为响应体

    通过HttpMessageConverter接口的实现类进行转换

  • 响应文本数据

    添加@ResponseBody,返回字符串即可

  • 响应json数据

    • json对象、json数组、json对象数组

      添加@ResponseBody

      将返回类型设置为相应类型即可

      返回对象的类中,具有相应get方法的属性才能转换成对应的json,否则不会进行转换

异常处理器

package aop;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import response.Response;

@ControllerAdvice
@ResponseBody
public class ExceptionAdvice {
    @ExceptionHandler(Exception.class)
    public Response handleException(Exception exception) {
        exception.printStackTrace();
        return Response.fail();
    }
}

@ControllerAdvice是spring提供的为controller提供的通知注解

@ExceptionHandler定义处理异常的方法及异常种类

@ResponseBody是对响应的返回数据进行处理,否则只支持ModelAndView,Model,ModelMap,Map,View,void,Sting类型的返回

不要忘记扫描到该类

拦截器

概念

  • 拦截器

    是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

  • 作用

    • 在指定的方法调用前后执行预先设定的代码
    • 阻止原始方法的执行
  • 拦截器与过滤器区别

    • 归属不同

      Filter属于Servlet技术,Interceptor属于SpringMVC技术

    • 拦截内容不同

      Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问增强

入门案例

  • 制作拦截器功能类

    package interceptor;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    @Component
    public class Interceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            System.out.println("pre handle...");
            // 返回false则拦截请求对应方法的执行
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("post handle...");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("after completion...");
        }
    }
    
  • 配置拦截器执行位置

    package config;
    
    import interceptor.Interceptor;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    @ComponentScan("interceptor")
    public class SpringMVCSupport implements WebMvcConfigurer {
        private Interceptor interceptor;
    
        public SpringMVCSupport(Interceptor interceptor) {
            this.interceptor = interceptor;
        }
    
        // 配置资源路径,放开MVC对其的拦截
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("").addResourceLocations("");
        }
    
        // 配置拦截器生效的路径
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(interceptor).addPathPatterns("/book/*");
        }
    }
    

    SpringMVCConfig配置类中,扫描config.support包,以加载该类

不知道为啥extends WebMvcConfigurationSupport实现的类通过Import导入不能生效

也可以让SpringMVCConfig实现WebMvcConfigurer接口,简化配置

拦截器参数

在拦截器的方法中,request、response可以获取原始请求,设置响应

handler代表拦截的请求绑定的控制层方法,是一个HandlerMethod对象

ModelAndView封装了响应做页面跳转相关的数据

Exception是表现层抛出的异常

拦截器链

  • 多拦截器执行顺序
    • 当配置多个拦截器时,形成拦截器链
    • 拦截器链执行顺序按照拦截器添加顺序为准
    • pre1 - pre2 - controller - post2 - post1 - after2 - after1
    • 当拦截器中出现对原始方法的拦截,后续的拦截器post均终止运行
    • 只要拦截器的pre放行了,对应的after就会执行,即使后面的拦截器阻止了原始方法

SSM整合

配置pom.xml的依赖项

<dependencies>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>3.1.0</version>
  <scope>provided</scope>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>

<dependency>
  <groupId>com.mysql</groupId>
  <artifactId>mysql-connector-j</artifactId>
  <version>8.0.31</version>
</dependency>

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.16</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.11</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.1.0</version>
</dependency>

<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.3</version>
</dependency>

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>
</dependencies>

<build>
<finalName>SpringMVC-test</finalName>
<plugins>
  <plugin>
    <groupId>org.apache.tomcat.maven</groupId>
    <artifactId>tomcat7-maven-plugin</artifactId>
    <version>2.1</version>
    <configuration>
      <port>8080</port>
      <path>/</path>
    </configuration>
  </plugin>
</plugins>
</build>

其他配置文件

  • druid.yml

    jdbc.driverClassName: com.mysql.cj.jdbc.Driver
    jdbc.url: jdbc:mysql://127.0.0.1:3306/test?useServerPrepStmts=true
    jdbc.username: root
    jdbc.password: 123456
    # 初始化连接数量
    druid.initialSize: 5
    # 最大连接数
    druid.maxActive: 10
    # 最大等待时间(ms)
    druid.maxWait: 3000
    
  • MultipartResolver.yml

    defaultEncoding: utf-8
    maxUploadSize: 1073741824
    maxInMemorySize: 10240
    uploadTempDir: uploadFile/tmp
    resolveLazily: true
    

配置类

  • SpringConfig

    package config;
    
    import org.springframework.context.annotation.*;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @Configuration
    @ComponentScan({"service", "dao", "aop"})
    @PropertySource("classpath:properties.yml")
    @Import({JdbcConfig.class, MyBatisConfig.class})
    @EnableAspectJAutoProxy
    @EnableTransactionManagement
    public class SpringConfig {
    }
    
  • JdbcConfig

    package 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.sql.DataSource;
    
    @PropertySource("druid.yml")
    public class JdbcConfig {
        @Value("${jdbc.driverClassName}")
        private String driverClassName;
        @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(driverClassName);
            dataSource.setUrl(url);
            dataSource.setUsername(username);
            dataSource.setPassword(password);
            return dataSource;
        }
        
        @Bean
        public PlatformTransactionManager platformTransactionManager(DataSource dataSource) {
            DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
            dataSourceTransactionManager.setDataSource(dataSource);
            return dataSourceTransactionManager;
        }
    }
    
  • MyBatisConfig

    package config;
    
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.mapper.MapperScannerConfigurer;
    import org.springframework.context.annotation.Bean;
    
    import javax.sql.DataSource;
    
    public class MyBatisConfig {
        @Bean
        public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            // 类型别名,对指定包下的类可以直接用不区分大小写的类名代替全类名
            sqlSessionFactoryBean.setTypeAliasesPackage("domain");
            sqlSessionFactoryBean.setDataSource(dataSource);
            return sqlSessionFactoryBean;
        }
    
        @Bean
        public MapperScannerConfigurer mapperScannerConfigurer() {
            MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
            // 包扫描加载sql映射文件
            mapperScannerConfigurer.setBasePackage("dao");
            return mapperScannerConfigurer;
        }
    }
    
  • SpringMVCConfig

    package config;
    
    import controller.interceptor.Interceptor;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    @ComponentScan({"controller"})
    @Import({MultipartResolverConfig.class})
    @EnableWebMvc
    public class SpringMVCConfig implements WebMvcConfigurer {
        private Interceptor interceptor;
    
        public SpringMVCConfig(Interceptor interceptor) {
            this.interceptor = interceptor;
        }
    
        // 配置资源路径,放开MVC对其的拦截
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("").addResourceLocations("");
        }
    
        // 配置拦截器生效的路径
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(interceptor).addPathPatterns("/book/*");
        }
    }
    
  • ServletContainerInitConfig

    package config;
    
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
    
    public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
        // 加载SpringMVC容器的配置
        @Override
        protected WebApplicationContext createServletApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringMVCConfig.class);
            return ctx;
        }
    
        //设置那些请求交给SpringMVC处理
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        // 加载Spring配置
        @Override
        protected WebApplicationContext createRootApplicationContext() {
            AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
            ctx.register(SpringConfig.class);
            ctx.registerShutdownHook();
            return ctx;
        }
    }
    
  • MultipartResolverConfig

    package config;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.PropertySource;
    import org.springframework.core.io.FileSystemResource;
    import org.springframework.web.multipart.MultipartResolver;
    import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    
    import java.io.IOException;
    
    @PropertySource("classpath:MultipartResolver.yml")
    public class MultipartResolverConfig {
        @Value("${defaultEncoding}")
        private String defaultEncoding;
    
        @Value("${maxUploadSize}")
        private long maxUploadSize;
    
        @Value("${maxInMemorySize}")
        private int maxInMemorySize;
    
        @Value("${uploadTempDir}")
        private String uploadTempDir;
    
        @Value("${resolveLazily}")
        private boolean resolveLazily;
        @Bean
        public MultipartResolver multipartResolver() throws IOException {
            CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
            commonsMultipartResolver.setDefaultEncoding(defaultEncoding);
            commonsMultipartResolver.setMaxUploadSize(maxUploadSize);
            commonsMultipartResolver.setMaxInMemorySize(maxInMemorySize);
            commonsMultipartResolver.setUploadTempDir(new FileSystemResource(uploadTempDir));
            commonsMultipartResolver.setResolveLazily(resolveLazily);
            return commonsMultipartResolver;
        }
    }
    

dao

定义接口,并通过注解或mapper映射文件实现sql语句

此层不需要在SpringConfig中扫描或在类上添加@Repository注解,org.apache.ibatis.binding下的MapperProxy<T>会自动代理该接口,并绑定为bean交给Spring容器

service

分为接口与实现类正常编写即可

对应dao层对象通过构造方法进行依赖注入

controller

@Controller
public class UserController {
    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @RequestMapping("/save")
    @ResponseBody
    public String save() {
        List<User> users = userService.selectAll();
        System.out.println(users);
        return "save";
    }
}

执行

引入ServletContainerInitConfig之前按照如下方式获取bean并执行

获取容器,再通过容器获取bean,执行业务

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
ctx.registerShutdownHook();

引入之后,请求交给AnnotationConfigWebApplicationContext容器,在容器内部寻找处理对应请求的bean(controller),不再需要手动获取bean。并且通过Spring的依赖注入,即可调用service、dao层的相应方法来完成响应

项目异常处理

业务异常

类型:

  • 规范的用户行为产生的异常
  • 不规范的用户行为产生的异常

解决方案:

  • 发送对应消息给用户,提醒规范操作

系统异常

类型:

  • 项目运行过程中可预计且无法避免的异常

解决方案:

  • 发送固定消息给用户,告知用户
  • 发送特定消息给运维,提醒维护
  • 记录日志

其他异常

类型:

  • 开发人员未预期到的异常

解决方案:

  • 发送固定消息给用户,告知用户

  • 发送特定消息给运维,提醒维护

  • 记录日志

放开MVC对页面的拦截

package config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/目录/**").addResourceLocations("/目录/");
    }
}

将此配置类加载到SpringMVCConfig

标签:Spring,springframework,class,bean,import,org,public
From: https://www.cnblogs.com/Lerjiu/p/17300530.html

相关文章

  • Spring Boot 3.0正式发布及新特性解读
    官网新特性解读:Springboot3.0新特性解读SpringBoot最新最全的实战代码已上传Github:SpringBoot3实战SpringBoot3.0简介**Java17+Spring6+Maven3.5/Gradle7.3**JDK要求最低版本Java17SpringBoot3底层默认依赖Spring6支持JakartaEE10,由于JavaEE已经变更为Jaka......
  • Spring Cloud Admin添加微信通知
    SpringCloud发送微信消息推送参考https://blog.csdn.net/qq_44697754/article/details/128035736。  SpringCloudAdmin要增加微信通知,需要继承AbstractStatusChangeNotifier类,在doNotify方法按照模板发送消息。 AdminServe添加依赖:<dependency><groupId>common......
  • Idea点击Run或者Debug无法启动项目_调试按钮按下以后变灰色_一会又恢复成绿色_但项目
    这个现象很烦人,点击了无数次了,就是项目启动不起来,很郁闷后来终于弄明白了,是这里,点击settings,然后找到这个runner这里,然后左上角这个delegateIDE...这个把勾去掉,去掉就可以了. 可以看到去掉以后,然后再点击运行可以看到,就已经显示正在运行中了. 终于弄好~......
  • ava: 程序包com.alibaba.nacos.api.common不存在_RuoYi-Cloud-Plus-master_jar包不存
    来看看原因吧,jar包是存在的,但是就是在idea中引用不到,来看看怎么回事: 原来就是这个包找不到,但是从下面看是有的: 但是注意,这里的com.alibaba.nacos.api...原来可不是这样的,这个是我后来修改过的,原来是只有com.alibaba.nacos.common,而引用的是com.alibaba.nacos.api.commo......
  • ruoyi-cloud微服务版启动过程报错_20230320版_ Verion 9 of Highlight.js has reached
      Verion9ofHighlight.jshasreachedEOL. Itwillnolonger报错: 这里修改成10.7.3版本D:\2023\qdBigData\RuoYi-Cloud-master\ruoyi-ui>npminstall--registry=https://registry.npm.taobao.org然后到对应目录,再去执行编译去看看.不报错了 >npmrundev然后执行看......
  • SpringBoot中日志的使用
    springboot默认就是使用SLF4J作为日志门面,logback作为日志实现来记录日志的文章目录1.SpringBoot中的日志设计2.SpringBoot日志使用1.SpringBoot中的日志设计springboot中的日志<dependency> <artifactId>spring-boot-starter-logging</artifactId> <groupId>org.springfr......
  • Java SpringBoot Bean InitializingBean
    Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。Spring初始化bean有两种方式:实现InitializingBean接口,实现afterPropertiesSet方法。(比通过反射......
  • Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了
    如何阻止JavaSpringBootTest单元测试中包括多线程时,没跑完就结束了使用CountDownLatchCountDownLatch、CyclicBarrier使用区别多线程ThreadPoolTaskExecutor应用JavaBasePooledObjectFactory对象池化技术@SpringBootTestpublicclassPoolTest{@Testvoid......
  • Spring 源码解析 --AOP
        ......
  • 不依赖 Spring 的简单 Main 工程
    1.搭建一个没有spring的工程importorg.jetbrains.kotlin.gradle.tasks.KotlinCompileplugins{kotlin("jvm")version"1.8.10"application}group="com.demo"version="1.0-SNAPSHOT"repositories{mavenCent......