原作者:https://blog.csdn.net/sujin_/article/details/78700158
Spring是一个轻量级的开源框架,是为解决企业应用开发的复杂性而创建的;它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。(Spring 核心就是IOC和AOP)
2.Spring 容器的实例化
3.Spring容器的使用
4.Bean的实例化,初始化过程:https://www.cnblogs.com/fyx158497308/p/3977391.html
https://www.cnblogs.com/xrq730/p/6285358.html
5.Bean的命名
6.Bean的作用域:https://blog.csdn.net/qq_33800083/article/details/80166144
7.Bean的生命周期
8.Bean延迟实例化
9.制定Bean依赖关
2. 什么是控制反转(IoC=Inversion of Control 或依赖注入DI=Dependency Injection)?
Spring容器最基本的接口是BeanFactory,他负责配置、创建、管理bean.他的子接口之一:ApplicationContext,也叫做spring的上下文。ApplicationContext是BeanFactory的子接口,
在web应用中,通常会用到XmlWebApplicationContext、AnnotationCofigWebApplicationContext两个实现类。
3. 实现Spring的IoC
在Spring当中定义和配置一个javabean
Bean的基本配置:
第一步:新建spring工程
第二步:创建Helloworld类
package com.manning.readinglist;
|
第三步:在xml中配置bean
|
第四步:写测试类
import org.springframework.context.ApplicationContext; |
第五步:运行结果
Spring 框架由6个定义好的模块组成:(六大模块,不同功能)
2.Spring 的主要功能有哪些?
1. Spring Core核心容器: Core封装包是框架的最基础部分,提供IOC和依赖注入特性。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。BeanFactory使用依赖注入的方式提供给组件依赖。
2. Spring Context: 构建于Core封装包基础上的 Context封装包,提供了一种框架式的对象访问方法,有些象JNDI注册器。Context封装包的特性得自于Beans封装包,并添加了对国际化(I18N)的支持(例如资源绑定),事件传播,资源装载的方式和Context的透明创建,比如说通过Servlet容器。
3. Spring DAO: DAO (Data Access Object)提供了JDBC的抽象层,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。 并且,JDBC封装包还提供了一种比编程性更好的声明性事务管理方法,不仅仅是实现了特定接口,而且对所有的POJOs(plain old Java objects)都适用。
4. Spring ORM: ORM 封装包提供了常用的“对象/关系”映射APIs的集成层。 其中包括JPA、JDO、Hibernate 和 iBatis 。利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如前边提到的简单声明性事务管理。
5. Spring AOP: Spring的 AOP 封装包提供了符合AOP Alliance规范的面向方面的编程实现,让你可以定义,例如方法拦截器(method-interceptors)和切点(pointcuts),从逻辑上讲,从而减弱代码的功能耦合,清晰的被分离开。而且,利用source-level的元数据功能,还可以将各种行为信息合并到你的代码中。
6. Spring Web: Spring中的 Web 包提供了基础的针对Web开发的集成特性,例如多方文件上传,利用Servlet listeners进行IOC容器初始化和针对Web的ApplicationContext。当与WebWork或Struts一起使用Spring时,这个包使Spring可与其他框架结合。
7. Spring Web MVC: Spring中的MVC封装包提供了Web应用的Model-View-Controller(MVC)实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型,在领域模型代码和Web Form之间。并且,还可以借助Spring框架的其他特性
如果这听起来有点难以理解,不必对此过于担心。这个模块所提供的Instrumentation使用场景非常有限,在本书中,我们不会介绍该模块。
鉴于开发者自测的重要性,Spring提供了测试模块以致力于Spring应用的测试。 通过该模块,你会发现Spring为使用JNDI、Servlet和Portlet编写单元测试提供了一系列的mock对象实现。对于集成测试,该模块为加载Spring 应用上下文中的bean集合以及与Spring上下文中的bean进行交互提供了支持。 在本书中,有很多的样例都是测试驱动的,将会使用到Spring所提供的测试功能。
1.Spring降低Java开发复杂性所采用的的策略:
二: 容器和Bean管理
1.Spring容器的简介
在基于Spring的应用中,你的应用对象生存于Spring容器(container)中。如图所示,Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,从生存到死亡(在这里,可能就是new到finalize())。
2.Spring 容器的实例化
3.Spring容器的使用
使用最多的spring容器就是ApplicationContext(Spring应用上下文beanFactory的接口之一)
4.Bean的实例化,初始化过程:
https://www.cnblogs.com/fyx158497308/p/3977391.html
https://www.cnblogs.com/xrq730/p/6285358.html
5.Bean的命名
6.Bean的作用域:https://blog.csdn.net/qq_33800083/article/details/80166144
7.Bean的生命周期
8.Bean延迟实例化
9.制定Bean依赖关
三:容器的IOC应用
可以把IoC模式看做是工厂模式的升华,可以把IoC看作是一个大工厂,只不过这个大工厂里要生成的对象都是在XML文件中给出定义的,然后利用Java 的“反射”编程,根据XML中给出的类名生成相应的对象。从实现来看,IoC是把以前在工厂方法里写死的对象生成代码,改变为由XML文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
IoC中最基本的Java技术就是“反射”编程。
2. Setter注入
3.构造器装配
4.自动装配
第一部分:Spring基础
第二章、装配bean
Spring配置的可选方案
Bean的装配方式:Spring中的bean都是单例,同一个实例可以注入到任意数量的其他bean当中。Spring 会拦截所有对同一个实例的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用。
在XML中进行显式配置。
Xml启动扫描:
JavaConfig(配置代码)
@Configuration:注解表明这个类是一个配置类,该类应该包含了在Spring应用上下文中如何创建bean的细节。
@Bean
注入:1)引用创建bean的方法来进行装配,需要与被引用的bean声明在同一个配置类中
2)通过参数引用,可以在不同的配置类中进行声明,甚至没有要求CompactDisc必须要在JavaConfig中声明
3)通过setter方法来注入,或者其他任意方法进行注入
@Configuration表明该java类是一个配置类,等价于XML中的
@Bean等价于XML的
隐式的bean发现机制和自动装配(从两个角度来实现)
组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
自动装配(autowiring):Spring自动满足bean之间的依赖
***组件扫描***详解@ComponentScan和@Component********
@Component: 注解表明该类会作为组件类,并告知Spring要为这个类创建bean
** 不过,组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。
@ComponentScan注解,这个注解能够在Spring中启用组件扫描。
如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包及所有子包,查找带有@Component注解的类,将其创建为bean。
通过XML的方案来启用组件扫描,
Spring支持将@Named(由Java依赖注入规范Java Dependency Injection提供)作为@Component注解的替代方案。两者之间有一些细微的差异,但是在大多数场景中,它们是可以互相替换的。
@ComponentScan("com.bean.soundSystem") //设置一个基础扫描包,以String类型表示,但是不安全not-safe,重构代码后报名可能会变
@ComponentScan(basePackages = {"com.bean.soundSystem","com.bean.soundSystem2"})设置多个基础扫描包
@ComponentScan(basePackageClasses = {SgtPeppers.class , SgtPeppers2.class})将扫描的包用包中所包含的类或接口来指定。
**可以使用空标记接口来制定要扫描的包,对重构更加友好
*****自动装配,使得spring自动满足bean依赖**@Autowired****
构造器上添加@Autowired注解
在setter方法上添加@Autowired 注解
@Autowired注解可以用在类的任何方法上。
不管是构造器、Setter方法还是其他的方法,Spring都会尝试满足方法参数上所声明的依赖。
@Autowired(required = false)
如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属 性设置为false。
@Inject注解来源于Java依赖注入规范,该规范同时还为我们定义了@Named注解。在自动装配中,Spring同时支持@Inject和@Autowired。尽管@Inject和@Autowired之间有着一些细微的差别,但是在大多数场景下,它们都是可以互相替换的。
导入和混合配置
在javaconfig中引用xml配置
@Import注解:
@ImportResource
在xml中引用springconfig
第三章、Bean的高级装配:主要知识点
Spring profile :
它可以理解为我们在Spring容器中所定义的Bean的逻辑组名称,只有当这些Profile被激活的时候,才会将Profile中所对应的Bean注册到Spring容器中。
环境与profile:
简单来讲,profile就是一组配置,不同profile提供不同组合的配置,程序运行时可以选择使用哪些profile来适应环境。
例子:DATA Source管理:在不同环境中会有所不同,我们必须要有一种方法来配置DataSource,使 其在每种环境下都会选择最为合适的配置。
JNDI管理的DATA Source更适合生产环境;
在QA环境中可以选择完全不同的DATA Source配置为Commons DBCP连接池;
在开发环境试用嵌入式数据库来进行自测;
解决方法一:在单独的配置类(或XML文件)中配置每个bean,然后在构建阶段(可能会使用Maven的profiles标签)确定要将哪一个配置编译 到可部署的应用中。但环境变更的构建可能会引入bug
解决方法二:使用Spring提供的解决方案,通过Profile配置,Spring可以在根据环境在运行阶段来决定bean的创建与否,先举例如下,主要从Profile bean的配置和激活来展开。
配置profile bean
SpringConfig中的配置 :@Profile("dev")
* @Profile被加载类级别上,如果dev profile没有被激活,那么类中对应的所有bean就不会被创建
* 如果当前是dev环境被激活了,被标记为其他的profile如@Profile("prod"),则不会创建相应的bean。没有指定profile的bean始终都会被创建,与激活哪个profile没有关系。
* @Profile不仅仅可以加载类级别上,还可以加载方法上
XML配置profile
* 通过
* 可以在根
激活profile
* 激活需要依赖两个独立的属性spring.profiles.active和spring.profiles.default
* 如果spring.profile.active被赋值了,则spring.profile.default就不会起作用,如果spring.profie.active没有赋值,则使用默认的spring.profile.default设置的值。当然,如果两者都没有设置的话,则只会创建那些没有定义在pofile中的bean。
* 可以同时激活多个profile,这可以通过列出多个profile名称,并以逗号分隔来实现。
* 有多种方式来设置这两个属性:比如在web.xml中就是作为dispatcherServlet参数传值。
作为DispatcherServlet的初始化参数;
条件化的bean:
@Conditional:它可以用到带有@Bean注解的方法 上。如果给定的条件计算结果为true,就会创建这个bean,否则的话,这个bean会被忽略。
public interface Condition { boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); } |
设置给@Conditional的类可以是任意实现了Condition接口的类型。可以看出来,这个接口实现起来很简单直接,只需提 供matches()方法的实现即可。如果matches()方法返回true,那么就会创建带有@Conditional注解的bean。如果matches()方法返 回false,将不会创建这些bean。
ConditionContext和AnnotatedTypeMetadata是两个接口
*** ConditionContext ***
借助getRegistry()返回的BeanDefinitionRegistry检查bean定义;
借助getBeanFactory()返回的ConfigurableListableBeanFactory检查bean是否存在,甚至探查bean的属性;
借助getEnvironment()返回的Environment检查环境变量是否存在以及它的值是什么;
读取并探查getResourceLoader()返回的ResourceLoader所加载的资源;
借助getClassLoader()返回的ClassLoader加载并检查类是否存在
*** AnnotatedTypeMetadata ***
借助isAnnotated()方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的那些方法,我们能够检 查@Bean注解的方法上其他注解的属性。
*** @Profile注解在4.0之后进行了重构,使其基于@Conditional和Condition实现。作为如何使 用@Conditional和Condition的例子。
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) @Documented @Conditional(ProfileCondition.class) public @interface Profile { String[] value(); } |
@Profile本身也使用了@Conditional注解,并且引用ProfileCondition作为Condition实现。如下所示,ProfileCondition实现了Condition接口,并且在做出决策的过程中,考虑到 了ConditionContext和AnnotatedTypeMetadata中的多个因素 :
** ProfileCondition通过AnnotatedTypeMetadata得到了用于@Profile注解的所有属性。借助该信息,它会明确地检 查value属性,该属性包含了bean的profile名称。然后,它根据通过ConditionContext得到的Environment来检查[借 助acceptsProfiles()方法]该profile是否处于激活状态。
** 可以模仿@Profile注解来自定义条件化注解
处理自动装配的歧义性:
标示首选的bean@primary
* 隐式装配:@Primary与@Component组合用在组件扫描的bean上
* JavaConfig显式装配:@Primary与@Bean组合用在Java配置的bean声明中。
* XML显示装配:
限定自动装配的bean:使用限定符@Qalifier,可以与@Awtowire与@Inject协同使用,在注入时指定需要的bean
** 使用默认的beanId作为限定符
为@Qualifier注解所设置的参数就是想要注入的bean的ID。例:@Qualifier("iceCream")
@Qualifier("iceCream")所引用的bean要具有String类型的“iceCream”作为限定符。如 果没有指定其他的限定符的话,所有的bean都以bean的ID作为默认限定符。
缺点:与类名紧密耦合,不利于代码重构修改类名
** 创建自定义的限定符
在bean声明上添加@Qualifier注解。
例如,与@Component组合使用:
@Qualifier("clod") @Component public class IceCream implements Dessert{ …… } |
在这种情况下,cold限定符分配给了IceCreambean。因为它没有耦合类名,因此可以随意重构IceCream的类名,而不必担心会破坏自动装配。在注入的地方,只要引用cold限定符就可以了
@Qualifier("cold") @Autowired public void setDessert (Dessert dessert){ this. dessert = dessert; } |
Java配置显式定义bean的时候,@Qualifier也可以与@Bean注解一起使用,为bean添加自己定义限定符:
@Qualifier("cold") @Bean public Dessert iceCream(){ return new IceCream(); } |
** 自定义限定符注解:
创建一个注解借助这个注解来表达bean需要限定的特性,该注解需要用@Qualifier来标注,通过在定义时添加@Qualifier注解来拥有@Qualifier注解的特性,使得该注解成为限定符注解。
定义多个限定符注解,来使用必要的限定符注解进行任意组合,从而将可选范围缩小到只有一个bean满足需求。相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解也更为类型安全。
3.4Bean的作用域
Spring定义了多种作用域,可以基于这些作用域
创建bean:
单例是默认的作用域,但对于易变的类型并不适用,要选择其他的作用域需要使用@Scope注解
@Scope可以与@Component和@Bean注解一起使用:
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
使用ConfigurableBeanFactory类的SCOPE_PROTOTYPE常量设置了原型作用域。当然也可以使用@Scope("prototype"),但是使用SCOPE_PROTOTYPE常量更加安全并且不易出错。
在XML显示配置时可以使用
** 使用会话和请求作用域
代理模式,懒解析(设计模式)
proxyMode属性:指定作用域代理
proxyMode属性设置为ScopedProxyMode.INTERFACES,表明这个代理要实现ShoppingCart接口,并将调用委托给实现bean。 如果ShoppingCart是接口而不是类的话,这是可以的(也是最为理想的代理模式)。但如果ShoppingCart是一个具体的类的话,Spring 就没有办法创建基于接口的代理了。此时,它必须使用CGLib来生成基于类的代理。所以,如果bean类型是具体类的话,我们必须要将proxyMode属性设置为ScopedProxyMode.TARGET_CLASS,以此来表明要以生成目标类扩展的方式创建代理。
在xml中指定作用域代理:需要使用Spring aop命名空间的一个新元素
以request为例,要启用他需要保证应用的“上下文”是web模式,例如XmlWebApplicationContext,其他情况下会抛出异常。然后"scope=request"的工作方式就是外部发起一个请求后,web层(servlet)启用一个线程来响应这个请求。到了业务层面我们需要指定一些bean来处理这个请求,当这些bean设定为request时,那么它仅仅用于这一次请求就抛弃。下一次请求出现时会创建一个新的实例。
所以不管是request、session、application还是websocket,实际上都是通过prototype模式创建的实例,也就是设计模式中的原型模式,虽然并不一定是教科书般的标准,但是在整个容器中他实现了原型的特性。
Spring表达式语言:避免硬编码值,运行时注入值
***属性占位符: 占位符的形式为使用“${ ... }”
注入外部的值:
声明属性源
@PropertySource("classpath:application.properties")
通过Spring的Environment来检索属性。
@Configuration @PropertySource("classpath:application.properties") public class CDConfig { @Autowired Environment env; @Bean public CompactDisc sgtPeppers(){ return new SgtPeppers( env.getProperty("disc.title"), env.getProperty("disc.artist","不知名作者")//设置默认值 ); } } |
没有配置文件,隐式声明的bean注入外部值时直接在构造器中使用@Value注解
SgtPeppers(@Value("${disc.title} ") String title, @Value("${disc.artist} ") String artist){ this.artist=artist; this.title=title; } |
XML注入外部值
|
*** 深入学习Spring的Environment
属性相关
获取属性值的方法并不唯一:getProperty有四个重载的变形形式
String getProperty(String key); String getProperty(String key, String defaultValue); 例:env.getProperty("db.connection.count",Integer.class,30); |
getRequiredProperty()获取的属性必须定义,否则抛出出IllegalStateException异常
用Environment的containsProperty()方法:检查属性是否存在
属性解析为类用getPropertyAsClass()方法:
env.getPropertyAsClass("disc.class",CompactDisc.class);
检查哪些profile处于激活状态:
String[] getActiveProfiles():返回激活profile名称的数组;
String[] getDefaultProfiles():返回默认profile名称的数组;
boolean acceptsProfiles(String... profiles):如果environment支持给定profile的话,就返回true。
***解析属性占位符
使用占位符必须先配置:PropertyPlaceHolderConfigurer bean或者
PropertySourcesPlaceHolderConfigurer bean(推介使用,可以给予environment及其属性源来解析占位符)
在JavaConfig中配置
@Bean public PropertySourcesPlaceholderConfigurer placeholderConfigurer(){ return new PropertySourcesPlaceholderConfigurer(); } |
在XML中配置:Spring context命名空间中的
|
****解析外部属性能够将值的处理推迟到运行时,但是它的关注点在于根据名称解析来自于Spring
Environment和属性源的属性。而Spring表达 式语言提供了一种更通用的方式在运行时计算所要注入的值。
***Spring表达式(SEL,使用spring表达式语言进行装配)表达式要放在 “#{ ... }”之中
JAVA注解详解:https://blog.csdn.net/sw5131899/article/details/54947192
java中元注解有四个: @Retention @Target @Document @Inherited;
@Retention:注解的保留位置
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Target:注解的作用目标
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
@Document:说明该注解将被包含在javadoc中
@Inherited:说明子类可以继承父类中的该注解
第四章、面向切面的Spring
AOP还需要再学习
面向切面编程:分离横切关注点(散布于应用多处的功能,如日志、安全和事务管理)与业务逻辑
面向切面编程的基本原理
通过POJO创建切面
使用@AspectJ注解
为AspectJ切面注入依赖:横切关注点被模块化为特殊的类,这些类称为切面
优点:1)每个关注点都集中在一个地方分散在代码各处;
2)服务模块更简洁,只需关注核心功能的业务代码
AOP术语:
在对象的生命周期中有多个点可以织入
编译期:切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增 强该目标类的字节码。AspectJ 5的加载时织入(load-time weaving,LTW)就支持以这种方式织入切面。
运行期:切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态地创建一个代理对象。Spring AOP就是以这种方式织入切面的。
Spring AOP(基于动态代理)
Spring提供 了4种类型的AOP支持:
基于代理的经典Spring AOP;
纯POJO切面;
@AspectJ注解驱动的切面;
注入式AspectJ切面(适用于Spring各版本)
** 前三种都是Spring AOP实现的变体,Spring AOP构建在动态代理基础之上,因此,Spring对AOP的支持局限于方法拦截。
借助Spring的aop命名空间(XML配置)
注解驱动的AOP
定义切点(使用AspectJ的切点表达式语言)
Spring AOP只支持AspectJ切点指示器的一个子集,在Spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常
Spring引入新的bean()指示器
***创建切面类
@Aspect:表明这是一个切面类,AspectJ自动代理会为使用@Aspect注解的bean创建一个代理
@Pointcut(“切点表达式”):定义命名的切点
@Before @After @Around @AfterReturning @AfterThrowing :五种通知方式
装配切面类
***启动自动代理
JavaConfig在配置类的类级别上使用@EnableAspectJAutoProxy启用自动代理功能
使用XML的aop命名空间
***创建环绕通知:ProceedingJoinPoint的proceed()方法。
接受ProceedingJoinPoint作为参数,该对象必须要有。
***处理通知中的参数
***通过注解引入新功能
1)创建切面类,添加@DeclareParents注解:为对象添加新方法
@DeclareParents(value ="com.Performance+",defaultImpl=DefaultEncoreable.class) public static Encoreable encoreable; |
value属性指定了哪种类型的bean要引入该接口。在本例中,也就是所有实现Performance的类型。(标记符后面的加号表示是Performance的所有子类型,而不是Performance本身。)
defaultImpl属性指定了为引入功能提供实现的类。在这里,我们指定的是DefaultEncoreable提供实现。
@DeclareParents注解所标注的静态属性指明了要引入了接口。在这里,我们所引入的是Encoreable接口
2)在Spring中将该切面类声明为一个bean
* Spring的自动代理机制获取到切面类bean的声明,当Spring发现一个bean使用了@Aspect注解时,Spring就会创建一个代理,然后将调用委托给被代理的bean或被引入的实现,这取决于调用的方法属于被代理的bean还是属于被引入的接口。
*** Spring XML配置中声明切面:借用Spring 的aop命名空间
AOP配置元素及用途
|
XML中通过切面引入新功能
implement-interface="com.Encoreable" types-matching="com.Performance" delegate-ref="defaultEncoreable"/> |
***注入AspectJ
使用factory-method来调用asepctOf()
Spring 的IOC和AOP
https://www.jianshu.com/p/40d0a6ad21d2
第二部分:SpringWeb
构建Spring Web应用程序
映射请求到Spring控制器
透明地绑定表单参数
一、跟踪SpringMVC请求
请求从离开浏览器开始到获取响应返回,它会经历好多站,在每站都会留下一些信息同时也会带上其他信息。图5.1 展示了请求使用Spring MVC所经历的所有站点。
二、搭建SpringMVC (简单搭建,近运行控制器)
1. 配置DispatcherServlet
Web.xml替代方式:扩展AbstractAnnotationConfigDispatcherServletInitializer类;
DispatcherServlet启动时创建Spring应用上下文:加载包含web组件的bean
ContextLoaderListener创建另外的应用上下文,加载应用中的其他bean,如:驱动应用后端的中间层和数据层组件
2. 启动springMVC
1)启用注解驱动的springMVC : @EnableWebMvc
2)编写基本控制器:@Controller @RequestMapping
3) 使用mockmvc测试控制器
4) 定义类级别的请求处理:将@RequestMapping加到类上@RequestMapping接受一个String类型的数组
5)传递模型数据到视图中
3.处理查询参数
查询参数(Query Parameter)@RequestParam(value="max" ,defaultValue= "10") long max
路径变量(Path Variable)@PathVariable
** 在理想情况下,要识别的资源应该通过URL路径进行标示,而不是通过查询参数。从面向资源的角度来看,对“/spittles/12345”发起GET请求要优于对“/spittles/show?spittle_id=12345”发起请求。前者能够识别出要查询的资源,而后者描述的是带有参数的一个操作——本质上是通过HTTP发 起的RPC。
处理表单:表单参数(Form Parameter) POST请求
return "redirect:/spitter/"+spitter.getUserName;
当InternalResourceViewResolver看到视图格式中的“redirect:”前缀时,它就知道要将其解析为重定向的规则,而不是视图的名称。本例中,它将会重定向到用户基本信息的页面。例如,如果Spitter.username属性的值为“jbauer”,那么视图将会重定向 到“/spitter/jbauer”。
校验表单
* 使用Spring对Java校验API(Java Validation API,又称JSR-303)的支持
* 比如Hibernate Validator,在类路径下包含相关依赖包即可
* Java校验API定义了多个注解,这些注解可以放到属性上,从而限制这些属性的值。所有的注解都位于javax.validation.constraints包中。
注 解 描 述
@AssertFalse 所注解的元素必须是Boolean类型,并且值为false
@AssertTrue 所注解的元素必须是Boolean类型,并且值为true
@DecimalMax 所注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString
@DecimalMin 所注解的元素必须是数字,并且它的值要大于或等于给定的BigDecimalString值
@Digits 所注解的元素必须是数字,并且它的值必须有指定的位数
@Future 所注解的元素的值必须是一个将来的日期
@Max 所注解的元素必须是数字,并且它的值要小于或等于给定的值
@Min 所注解的元素必须是数字,并且它的值要大于或等于给定的值
@NotNull 所注解元素的值必须不能为null
@Null 所注解元素的值必须为null
@Past 所注解的元素的值必须是一个已过去的日期
@Pattern 所注解的元素的值必须匹配给定的正则表达式
@Size 所注解的元素的值必须是String、集合或数组,并且它的长度要符合给定的范围
添加校验注解
启用校验功能:
在controller层方法的要校验的参数上添加@Valid注解,并传入一个Errors对象来检查校验失败(Errors参数要紧跟在带有@Valid注解的参数后面)
方法中首先调用Errors的hasErrors方法检查是否有错误
if (errors.hasErrors()) |
SpringMVC的高级技术
将DispatcherServlet配置到web.xml中
自定义DispatcherServlet:对Abstract-AnnotationConfigDispatcherServletInitializer类的其他方法进行重载,以实现额外的配置
必须重载的三个方法
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { //将一个或多个路径映射到DispatcherServlet上。 @Override @Override MultipartConfigElement("/tmp/spittr/uploads")); //处理multipart请求和文件上传 } |
***借助customizeRegistration()方法中的ServletRegistration.Dynamic,我们能够完成多项任务,包括通过调用setLoadOnStartup()设置load-on-startup优先级,通过setInitParameter()设置初始化参数,通过调 用setMultipartConfig()配置Servlet 3.0对multipart的支持。在前面的样例中,我们设置了对multipart的支持,将上传文件的临时存储目录设置在“/tmp/spittr/uploads”中。
添加其他的servlet和filter
添加其他的servlet和filter,只需创建一个新的初始化器就可以了。最简单的方式就是实现Spring的WebApplicationInitializer接口。
JavaConfig
@Override |
在webxml中声明DispatcherServlet:
典型的Spring MVC应用中,我们会需要DispatcherServlet和Context-LoaderListener。AbstractAnnotationConfigDispatcherServletInitializer会自动注册它们,但是如果需要在web.xml中注册的 话,那就需要我们自己来完成这项任务了。
|
*********处理mutilpart形式数据:使用SpringMVC实现文件上传
借助MultipartResolver策略接口的实现类来解析multipart请求中的内容。从Spring 3.1开始,Spring内置了两个MultipartResolver的实现供我们选择:
第一步:将StandardServletMultipartResolver声明为bean
@Bean |
第二步:在Servlet中指定multipart的配置。(写入的文件临时路径,限制上传文件大小等)
使用servlet初始化类的方式来配置DispatcherServlet,初始化类已经实现了WebApplicationInitializer
public void onStartup(ServletContext servletContext) throws ServletException{ DispatcherServlet ds=new DispatcherServlet(); //注册servlet ServletRegistration.Dynamic myServlet = servletContext.addServlet("myServlet",ds); //映射servlet myServlet.addMapping("/custom/*"); //设置临时路径 myServlet.setMultipartConfig(new MultipartConfigElement("tmp/spittr/upload")); } |
配置DispatcherServlet的Servlet初始化类继承了Abstract AnnotationConfigDispatcherServletInitializer或AbstractDispatcher-ServletInitializer
protected void customizeRegistration(ServletRegistration.Dynamic registration){ registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads")); }//重载customizeRegistration()方法 |
只有一个参数的MultipartConfigElement构造器,这个参数指定的是文件系统中的一个绝对目录,上传文件 将会临时写入该目录中。
*上传文件的最大容量(以字节为单位)。默认是没有限制的。
*整个multipart请求的最大容量(以字节为单位),不会关心有多少个part以及每个part的大小。默认是没有限制的。
*在上传的过程中,如果文件大小达到了一个指定最大容量(以字节为单位),将会写入到临时文件路径中。默认值为0,也就是所有上传 的文件都会写入到磁盘上。
protected void customizeRegistration(ServletRegistration.Dynamic registration){ registration.setMultipartConfig(new MultipartConfigElement( //参数:location,maxFileSize,maxRequestSize,FileSizeThreshold "/tmp/spittr/uploads",2097152,4194304,0 )); } |
使用web.xml配置MultipartConfigElement,可以使用
org.springframework.web.servlet.DispatcherServlet
|
配置3.0以前的MutilpartResolver
将CommonsMultipartResolver声明为Spring bean
@Bean public MultipartResolver commonsMultiPartResolver() throws IOException{ CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setUploadTempDir(/spittr/uploads/); multipartResolver.setMaxUploadSize(2097152); multipartResolver.setMaxInMemorySize(0); return multipartResolver; } |
修改html,