spring
2024-02-21 18:13:10 0 举报
AI智能生成
spring
作者其他创作
大纲/内容
AOP
面向切面编程思想:对共同内容进行抽取,在需要用到的地方用动态代理的方式进行插入,在不修改源代码的基础
上,还能对源码进行加强
上,还能对源码进行加强
底层为动态代理:对目标类进行功能增强
对目标类方法进行加强的方式
继承
缺点:需要直到要增强的方法的类才能继承
装饰者模式
缺点:需要有接口,这个接口下除了要增强的方法外别的方法也要实现
动态代理模式
JDK
需要接口但可以指定增强方法,不需要实现全部方法
Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
返回一个指定接口的代理类实例
返回一个指定接口的代理类实例
参数列表:和目标对象相同的类加载器;目标类所有的接口;增强类(可以自定义增强类并实现InvlcationHandler
接口并重写其内部方法,也可以在此处直接定义匿名内部类)
接口并重写其内部方法,也可以在此处直接定义匿名内部类)
此处的InvocationHandler可以是一个匿名内部类,实现内部的invoke方法,在该方法中定义增强逻辑
该方法的参数:代理类对象;要被增强的方法(在将目标类所有接口传进去时就已经知道所有的代理方法了);
方法需要的参数。
该方法的参数:代理类对象;要被增强的方法(在将目标类所有接口传进去时就已经知道所有的代理方法了);
方法需要的参数。
细节
proxyPerson.run(); // 执行这个方法 invoke都会执行一遍 执行的内容就是针对该方法的增强
返回值 return 谁调用返回给谁 返回的内容就是最终值而不是需要增强的方法的返回值
通过if-else判断方法名来增强指定方法
CGLIB
不需要接口,可以指定增强方法,但代码量比较大
CGLIB原理
该代理模式是用拦截器和过滤器的方式进行继承,对目标类的方法进行增强
AOP的三种方式
自由式
步骤
确定目标类(要被切的类,即需要被加强的类),需要定义切入点,此处切入点为需要增强的方法
确定切面类,即用来切类的刀,需要定义增强后的方法
织入配置,把增强方法指定在切入点之前、之后、环绕、异常、最终 执行
配置文件
织入时机
前置增强
用<aop:before>标签配置
切入点即需要增强的方法,在切入点前介入即在需要增强的方法前介入其他业务逻辑,例如在执行
原方法前打印日志或者其他操作
原方法前打印日志或者其他操作
后置增强
用<aop:after>标签配置
在原方法执行结束后介入增强后的方法
环绕增强
用<aop:around>标签配置,需要在增强后的方法中传参:ProceedingJoinPoint类型的对象,这个对象
中包含着目标类需要增强的方法,需要在增强后的方法中调用pjp.proceed()方法,相当于调用原方法,
在该方法前后需要写自己的业务逻辑实现环绕介入
中包含着目标类需要增强的方法,需要在增强后的方法中调用pjp.proceed()方法,相当于调用原方法,
在该方法前后需要写自己的业务逻辑实现环绕介入
异常增强
用<aop:after-throwing>标签配置
在原方法发生异常时会介入,一般用于对数据库事务的处理
最终增强
用<aop:after-returning>标签配置
在需要增强的方法正确地返回之后执行
接口规范式
步骤
定义切面类,让其实现特定接口(五类织入时机)
确定目标类(被介入的类),确定其切点
确定切面类(做介入角色的类)
配置文件
前置增强
定义的切面类需要实现MethodBeforeAdvice接口并实现befor方法
该方式底层会调用目标类中需要增强的方法,在该切面类中的before方法中只需要写自己的业务逻辑即可
后置增强
定义的切面类需要实现AfterReturnAdvice接口并实现afterReturn方法
参数
Object returnValue
原方法返回值
Method method
目标方法
Object[] args
目标方法执行需要的参数数组
Object target
目标对象,即被代理的类的对象
环绕增强
切面类需要实现MethodInterceptor接口并实现invoke(MethodInvocation invocation)方法
这种增强方式需要在invoke方法中调用invocation的proceed()方法调用目标方法,在该语句前后实现自己的
业务逻辑达到环绕增强的效果
业务逻辑达到环绕增强的效果
异常增强
切面类实现ThrowsAdvice接口,该接口是一个空接口,需要在该切面类中自定义名为afterThrowing(Exception e)方法
最终增强
注解介入
springmvc
什么是springmvc
springmvc实际上是springframwork的一个模块,这个模块主要是对web的支持
springmvc是基于IoC和aop的
servlet缺点
获取参数比较繁琐,如果类型不是字符串类型则需要进行类型转换,还需要判断是否为空
如果每个servlet对应一个请求,则会产生大量的servlet,如果一个servlet对应多个请求,则违反可单一原则
原理
springmvc提供了一个servlet,我们把所有的请求都发送给这个servlet,这个servlet我们称之为核心控制器
核心控制器在tomcat启动时就会创建,在其init方法中会读取配置文件并扫描指定的包,会为由@Controller注解标记
的类创建对象,并把所有的由@RequestMapping注解标记的映射关系放到HandlerMapping中,键放注解的地址,值放
方法
的类创建对象,并把所有的由@RequestMapping注解标记的映射关系放到HandlerMapping中,键放注解的地址,值放
方法
当在地址栏输入地址,核心控制器会根据资源路径从HandlerMapping中寻找要执行的方法,找到后并调用
在控制类的方法中处理请求和响应,用return实现请求转发(携带的参数放到ModelMap中)和重定向(在返回的字符串前加redirect)
三大核心组件
处理器映射器
作用:帮我们找到对应的controller
HandlerMapping
传统开发方式,即配置文件方式
依赖BeanNameUrlHandlerMapping类
注解开发方式,已过时类
AnnotationMethodHandlerAdapter(过时的注解开发方式)
注解开发方式,最新类
RequestMappingHandlerAdapter(最新版本的注解开发方式)
在springmvc内部配置文件中,注解开发方式配置的还是过时的注解驱动类,需要在springmvc配置文件中用
<mvc:annotation-driven/>标签配置新版注解驱动类
<mvc:annotation-driven/>标签配置新版注解驱动类
处理器适配器
作用:帮我们找到响应的方法
方法返回ModelAndView
视图解析器
在springmvc配置文件中配置,用来配置contorller类中方法返回的字符串类型的前缀和后缀,简化返回的静态地址的字符串
将结果渲染成页面
控制类中的注解
@Controller
标记控制类,该类拥有处理请求的能力
@RequesMapping
标注方法,定义请求路径
窄化映射,可以定义到controller类上,隔离各个控制类中的方法
value和path属性
标注这个方法处理请求的地址,支持传数组,可以响应多个请求
method
设置接收的请求的请求方式
RequestMethod.GET, RequestMethod.POST
@ResponseBody
用此注解标记该方法,则底层会将该方法的返回值转换为json格式,spring没有内置转json的类,需要依赖三方jar包
@CrossOrigin
设置跨域访问
传统方式需要设置响应头setHeader("Access-Control-Allow-Origin", "协议+ip+端口")
浏览器的同源策略
同源指的是同一个服务器
如果a服务器向b服务器发送ajax请求,b服务器接收并响应数据,在默认情况下,a服务器的ajax拒绝接收b
服务器的响应,所以需要在b服务器端设置跨域访问,解决跨域错误问题
服务器的响应,所以需要在b服务器端设置跨域访问,解决跨域错误问题
@PathVaribale
用于绑定url的占位符,例如:在请求的url中,/emplist/{empId},{empId}就是一个占位符,在参数列表中想要对应占位符的参数前用
该注解标注,该注解中的值应当与占位符的值一致。url支持占位符是在spring3.0以后引入的
该注解标注,该注解中的值应当与占位符的值一致。url支持占位符是在spring3.0以后引入的
用于实现restful风格
如果想要实现restful风格,则需要将web.xml文件中核心控制器的请求路径设置为/,但此时将会把所有的静态文件例如js、css等
也作为请求发送到核心控制器并去找相应的方法执行,此时就会访问不到静态资源,所以释放静态资源
也作为请求发送到核心控制器并去找相应的方法执行,此时就会访问不到静态资源,所以释放静态资源
在springmvc配置文件中配置静态资源,用<mvc:resources location="请求地址例如:/js/(以js开头的请求)"
mapping="映射位置例如 :/js/**(项目下js文件夹下所有的文件的子文件)" />
mapping="映射位置例如 :/js/**(项目下js文件夹下所有的文件的子文件)" />
restful风格
用占位符的方式接收参数,占位符的参数名叫啥,前端name应该叫啥
传统风格
RequestMapping("/delete")
localhost:8080/delete?id=10
localhost:8080/delete?id=10
restful风格
RequestMapping("/delete/{id}")
restful风格:localhost:8080/delete/10
restful风格:localhost:8080/delete/10
@ModelAttribute
被该注解标注的方法会先执行
适用场景:当前端提交表单,带着表单数据向控制类中的某个方法发送请求,但表单数据并不是一个完整的JavaBean对象的
数据,此时可以定义一个新的方法,用该注解标注,那么在执行对应请求方法时会先执行该方法,该方法也可以从请求中
获取请求参数,可以在该方法中通过请求参数从数据库查询完整数据,并将最后JavaBean对象返回,这样数据就会完整,另
一种方式是无返回值方法,可以参参数列表定义一个map集合,将最后的JavaBean放入map集合中,在对应的请求方法的
参数列表中也用ModelAttribute注解标注参数,并在注解中给出放入map集合的key
数据,此时可以定义一个新的方法,用该注解标注,那么在执行对应请求方法时会先执行该方法,该方法也可以从请求中
获取请求参数,可以在该方法中通过请求参数从数据库查询完整数据,并将最后JavaBean对象返回,这样数据就会完整,另
一种方式是无返回值方法,可以参参数列表定义一个map集合,将最后的JavaBean放入map集合中,在对应的请求方法的
参数列表中也用ModelAttribute注解标注参数,并在注解中给出放入map集合的key
注解语法糖
在spring4.2.x版本及以后出现了复合注解
@GetMapping("/")
@PostMapping
直接指明请求方式
@RestController
@Controller和@ResponseBody的符合注解
参数绑定
默认参数绑定
request
response
session
ModelMap
基本数据类型
在对应方法的参数列表中定义请求参数
类型写你需要的,底层会帮你转,要求参数列表中的参数名与请求参数名一致
原理
mvc会反射你的方法参数列表,根据参数名去找请求参数对应的值,会尝试将数据转成你想要的类型,
如果不能转成你想要的,抛异常
如果不能转成你想要的,抛异常
bean方式
可以使用对象接收,在参数列表定义对象类型,mvc可以直接自动封装成对象,前提是对象的属性名跟请求参数名一致
绑定包装的bean
即对象中有对象引用,要求前端数据的name为bean中的bena名称.属性名,例如订单实体中有商品实体(pro),如果要绑定商品
id,则在前端需要将参数name定义为pro.id
id,则在前端需要将参数name定义为pro.id
数组绑定
一般用于批量删除,在前端定义复选框,复选框的名称相同且和控制类对应方法的数组名一致,springmvc可自动帮你获取参数
集合绑定
应用场景不多,一般用于批量修改,前端修改n条数据,提交多个对象到后台,但只能支持向对象中接收集合,即
控制类对应方法中需要定义一个集合,接收参数时会接收到该对象的集合中,而且要求前端name属性为集合名[下标].对象属性名
在jsp页面的c:foreach标签中的status属性可以获取遍历的集合的每次索引值
控制类对应方法中需要定义一个集合,接收参数时会接收到该对象的集合中,而且要求前端name属性为集合名[下标].对象属性名
在jsp页面的c:foreach标签中的status属性可以获取遍历的集合的每次索引值
注解方式
@RequestParam注解,标记参数列表
注解属性
value/name
指明要获取的参数名,用于跟请求参数名匹配
required
默认为true,要求请求参数必须有,如果没有,则出现400,设为false则可以没有
defaultValue
用于定义参数列表的默认值,如果请求参数没有传来,则默认值生效
自定义转换器
当前端参数出现springmvc无法自动转换的参数时,例如时间,可以使用自定义转换器
步骤
创建一个类,实现Converter<T, V>,T:源,V:目标,即需要将什么类型转换为什么类型
实现convert(T t)方法并返回想要的
将自定义转换器配置到springmvc容器中
在注册新版处理器映射器,处理器适配器驱动时,将自定义转换器配置
<mvc:annotation-driven conversion-service="自定义转换器id"/>
<mvc:annotation-driven conversion-service="自定义转换器id"/>
配置自定义转换器
<bean id="" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="convers">
<set><bean class="自己定义的转换器类的全限定名"/></set>
</property>
</bean>
<bean id="" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="convers">
<set><bean class="自己定义的转换器类的全限定名"/></set>
</property>
</bean>
注解方式解决mvc不支持的参数绑定
将spring不支持的绑定类型参数上用@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
springmvc如何响应
返回String类型的地址
在方法中直接return页面地址默认就是请求转发
在返回的页面地址字符串前加redirect:则为重定向
请求转发携带的参数需要放到ModelMap中
例如
配置视图解析器
在spring配置文件中配置前缀和后缀
配置语法
将配置文件的前缀和后缀与控制类中方法return的字符串拼接即可得到想要的路径
拦截器
框架提供的有跟过滤器功能类似但更强大的拦截器
拦截器会拦截Controller类中方法的调用
在controller类中方法执行前被拦截
在controller类的方法执行之后但在视图解析前被拦截
方法执行完且视图解析之后拦截
快速入门
1. 定义一个类实现HandlerInterceptor接口
2. 实现该接口中的方法,所有的方法
返回值为boolean,真放行,假拦截
返回值为boolean,真放行,假拦截
该接口中的方法为默认方法,每个方法都有不同的拦截时机
preHandle(req,resp)
在controller的方法被调用之前执行该方法
postHandle(req, resp)
在方法被调用视图解析之前调用
afterCompletion(req, resp)
在方法执行完视图解析之后调用
3. 在配置文件中配置拦截器,可以配置多个拦截器,
哪个在上边,最先执行哪个拦截器
哪个在上边,最先执行哪个拦截器
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置哪个方法需要拦截 -->
<mvc:mapping path="/**">
<!-- 配置哪个方法不需要拦截 -->
<mvc:exclued-mapping path="">
<!-- 设置拦截器类路径 -->
<bean class="拦截器类全限定名">
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptor>
<!-- 配置哪个方法需要拦截 -->
<mvc:mapping path="/**">
<!-- 配置哪个方法不需要拦截 -->
<mvc:exclued-mapping path="">
<!-- 设置拦截器类路径 -->
<bean class="拦截器类全限定名">
</mvc:interceptor>
</mvc:interceptors>
执行顺序
两个兰拦截器,1拦截器配置在前,2拦截器配置在后
文件上传
springmvc文件上传原理
浏览器通过input标签将需要上传的文件自动读入到内存,当提交表单的时候,会将该文件发送到后台核心控制器,在请求中
会携带这个文件,此时会调用到文件解析器,文件解析器会解析请求对象,将请求对象的文件解析出来返回给核心控制器
会携带这个文件,此时会调用到文件解析器,文件解析器会解析请求对象,将请求对象的文件解析出来返回给核心控制器
核心控制器再调用处理器映射器,找到相应的控制类的方法,通过参数绑定的形式,绑定给该方法,该方法的参数类型必须
是MultipartFile类型,参数名必须要和input标签中的name属性保持一致,最后调用该MultipartFile对象的方法进行上传
是MultipartFile类型,参数名必须要和input标签中的name属性保持一致,最后调用该MultipartFile对象的方法进行上传
文件解析器配置
前后端要求
页面要求
传统表单方式
1. 表单提交方式一定是post
2. 表单的enctype的值一定是multipart/form-data
3. input的type一定是file
ajax方式
1. type:post
2. data:FormData
3. processData: false
4. contentType: false,
springmvc要求
1. 需要两个jar包commons-io.jar和commons-fileupload.jar
2. 在ppringmvc配置文件中配置文件解析器
3. 绑定参数类型一定为MultipartFile,参数名字要和input的name属性的值保持一致
springmvc和struts2优劣
相同点
都基于mvc设计模式
底层都是对ServletAPI的封装
处理请求的机制都是一个核心控制器
区别
springmvc的入口是Servlet,struts2的入口是Filter
springmvc的最小单元是方法,是基于方法设计的,struts2的最小单元是基于类,每次执行都会创建一个动作类,所以mvc更快
springmvc使用更简洁,发送ajax更方便
s2的OGNL表达式使页面开发效率更高,但执行效率没有并没有比JSTL有所提升
博客地址
什么是Spring
Spring是一个轻量级的IOC和AOP容器的开源框架
Spring提倡以最少侵入(可以理解为耦合度)的方式来管理应用中的代码
IOC
概念
控制反转
控制:对对象的创建和管理
反转:对对象的控制由程序员转变为框架
核心目的
让spring来管理对象
优点
单例
降低耦合(类与类之间的依赖关系)
IoC核心容器
顶层接口BeanFactory和
ApplicationContext的区别
ApplicationContext的区别
单例对象适用
AplicationContext在构建核心容器时,创建对象采用的是立即加载的方式,即配置文件一读取完,立马创建对象
AplicationContext在构建核心容器时,创建对象采用的是立即加载的方式,即配置文件一读取完,立马创建对象
多例对象适用
BeanFactory在构建核心容器时,创建对象采用的是延迟加载方式,即什么时候通过Id获取对象,什么时候创建
BeanFactory在构建核心容器时,创建对象采用的是延迟加载方式,即什么时候通过Id获取对象,什么时候创建
ApplicationContext常用实现类
ClassPathXmlApplicationContext
读取类路径下的配置文件
FileSystemXmlApplicationContext
读取电脑任意位置的配置文件
AnnotationConfigApplicationContext
用于使用新注解+配置类的方式代替xml配置文件时
IOC创建对象方式
无参构造器
在spring配置文件中用bean标签配置
bean标签的属性
id
创建的对象名
class
需要被管理的类的全路径
静态工厂
条件:需要工厂类,该工厂类中需要有静态方法
配置文件语法
<bean id="factory" class="com.wxs.factory.BeanFactory" factory-method="静态方法名" />
当用spring容器调用getBean方法时会创建工厂类对象,并执行工厂类中的方法返回需要的对象并放入spring容器中
实例工厂
条件:需要工厂类,这个工厂类中需要有普通方法
配置文件语法
<bean id="factory" class="com.wxs.factory.BeanFactory" />
<bean id="car" factory-bean="factory" factory-method="普通方法名">
需要先创建工厂对象再调用工厂中的普通方法
DI(依赖注入)的方式
setter注入
条件:属性必须有setter方法
bean标签下<property>标签
name:属性名
value:属性值,针对基本类型和String类型
ref:针对对象类型,指向的是bean标签的id属性的值
复杂注入(map、list、[]...)
list类型语法
数组类型与list类型类似只是没有ref标签
map类型
<bean id="empService" class="com.wxs.service.EmpService">
<property name="list">
<map>
<entry key="" value=""></entry>
</map>
</property>
</bean>
<property name="list">
<map>
<entry key="" value=""></entry>
</map>
</property>
</bean>
properties类型
<bean id="empService" class="com.wxs.service.EmpService">
<property name="p">
<props>
<prop key="" value=""></prop>
</props>
</property>
</bean>
<property name="p">
<props>
<prop key="" value=""></prop>
</props>
</property>
</bean>
有参构造器注入
条件:必须要有构造器
bean标签下<constructor-arg>标签
name属性:属性名
value:值,针对基本类型和Stirng
ref:针对对象类型
p名称空间注入
条件:需要在配置文件中导入p的命名空间(spring提供的),底层还是set方式,所以属性也必须有setter方法
IOC三种开发方式
手动配置方式
bean标签:在配置文件中用bean标签配置一个类
id属性:用来给对象命名
class属性:用于写实体类的全路径名,供反射适用
scope属性
singleton
单例
只要配置文件被加载,就会创建对象,创建的对象放在spring容器中,这个容器底层为
map集合,key为bean标签的id值,value为这个对象
map集合,key为bean标签的id值,value为这个对象
当调用容器的getBean方法的时候,总是获取到唯一的实例
service/dao需要单例模式
proyotype
多例
当配置文件加载的时候不创建对象,当调用容器的getBean方法时,创建对象并返回,调用一次getBean则创建一次
action适合多例
request
作用于web应用的请求范围
session
作用于web应用的会话范围
globle-session
作用于集群环境的会话范围(全局范围)
对象销毁时机
singleton
当spring容器关闭的时候对象销毁
proyotype
长时间不用则被GC回收
若需要给一个类中的成员变量赋初始值则需要在bean标签中定义property子标签
name属性:类的属性名
value:定义普通成员变量的值
ref:如果一个类中引用到其他类的对象,需要用此属性注入
***注意:在配置文件中给属性设置初始值需要提供该属性的setter方法
property子标签<list>
专门用于给list集合类型的成员变量赋初始值
格式
<bean id="empService" class="com.wxs.service.EmpService">
<property name="list">
<list>
<value>11</value>
</list>
</property>
</bean>
<property name="list">
<list>
<value>11</value>
</list>
</property>
</bean>
半自动配置方式
半自动配置方式主要是将类与类之间的依赖关系用注解的方式实现
类的对象还是需要手动配置,但类的依赖关系用注解@Autowired自动实现,
例如A类中引用了B类,在配置文件中用bean标签配置A,在A中用注解标记引用的B
例如A类中引用了B类,在配置文件中用bean标签配置A,在A中用注解标记引用的B
***注意:Spring框架为了效率,默认在扫描类的时候不会扫描注解,所以默认情况下只加Autowired注解是无法
自动注入的,需要在配置文件用<context:annotation-config/ >进行配置
自动注入的,需要在配置文件用<context:annotation-config/
全自动配置方式
基本不用配置文件
在类上用@Component注解标记,类中的依赖关系用@Autowired注解标记
在配置文件中用<context:component-scan base-package="com.wxs" />配置需要扫描的包
在全自动配置方式中,对于私有的成员变量,也无须提供setter方法,反射会自动打开访问权限强制访问
***注意:如果通过一个类型匹配到了多个实现类,则会报错,解决方式为在引用类型上添加@Qualifier("")注解指明需要的类
四个创建对象的注解
Component:无法划分类的时候
Repository:一般用于标注dao层或者说标注数据库操作层
Service:业务层
Controller:控制层/表现层(springmvc替代servlet)
**以上四个注解没有区别,只是用于不同场景
Scope:定义类的单例多例
PreDestory
指定销毁方法
PostConstruct
指定初始化方法
三个依赖注入的注解
Value
针对基本数据类型和String类型
Autowired
该注解由Spring框架提供
按类型去找,如果找不到就是没有,如果找到多个就报错,解决方式是搭配Qualifier注解指明适用哪个注解
Resource
该注解由JDK提供
先按名字去找,第一种是name属性配置名字@Resource(name = "名字"),如果没有指定名字
则把变量名当作要寻找的属性名,如果再找不到,最后按类型去找
则把变量名当作要寻找的属性名,如果再找不到,最后按类型去找
spring新注解
写一个类,用新注解标注,可以让该类的作用和application.xml的作用一样
@Configuration
表名该被标注的类是一个配置类,但本质作用并不是标注它是一个配置类,而是加上这个注解之后,该类中的所有方法会被
CGLib代理,方法会跟原来的方法完全不一样,这样就保证了对象的生命周期和作用域。
如果不加该注解,在该类中用Bean注解照样好用,用AnnotationApplicationContext去容器取对象也好用,只不过如果该类
中的一个创建对象的方法调用了另一个创建对象的方法,那么另一个对象将被创建多次,不能保证对象的单例,即作用域scope
不能被保证
CGLib代理,方法会跟原来的方法完全不一样,这样就保证了对象的生命周期和作用域。
如果不加该注解,在该类中用Bean注解照样好用,用AnnotationApplicationContext去容器取对象也好用,只不过如果该类
中的一个创建对象的方法调用了另一个创建对象的方法,那么另一个对象将被创建多次,不能保证对象的单例,即作用域scope
不能被保证
@ComponentScan
通过该注解告诉spring在创建容器时需要扫描的包
属性value,和xml配置文件中的<context:component-scan>标签中的basePackage属性作用一样
@Bean
用于标注配置类中的方法,将方法的返回值对象存入spring容器中
name属性用于定义bean的id,当不写时,存入容器集合时key默认为方法名,值为对象
细节:当我们使用注解配置方法时,如果方法有参数,spring会自动去容器中找有没有可用的bean,查找的方式与@Autowired
注解的方式一致
注解的方式一致
此时不再使用ClassPathXmlApplicationContext,而是要用AnnotationConfigApplication,并将该配置类的class对象传入
原理
如何创建对象
通过IO读取配置文件
利用反射创建对象:class.forName(配置文件中的全路径名)
如果是全自动模式,则通过IO读取配置文件读到的是包,然后再通过IO去扫描这个包下所有的类(包括子包)
扫描的类如果由Component注解标记,则创建该类对象,如果没有,则忽略
扫描的类如果由Component注解标记,则创建该类对象,如果没有,则忽略
重点是反射+IO
如何管理依赖关系
扫描所有成员变量,如果成员变量带有自动注入注解,则从自己容器中寻找要注入的对象,利用反射对其进行注入,如果
找到相应对象,暴力破解直接赋值,如果没找到,则报错
找到相应对象,暴力破解直接赋值,如果没找到,则报错
spring整合junit
在spring下junit的问题
程序的入口为main
junit单元测试中没有main方法也能执行
junit内部集成了一个main方法
当执行时,会利用反射判断该测试类有没有被@Test标注的方法
如果有,.invoke执行该方法
junit不会管我们是否用框架
在执行测试方法的时候,junit根本不知道我们是否使用了框架,所以在执行的时候根本不会为我们通过配置文件或者
配置类来创建spring容器
配置类来创建spring容器
所以,在用junit测试的时候根本没有ioc容器,就算使用Autowired方法也不会有效果
整合思路
导入spring整合junit的jar包--->spring-test.jar
使用junit提供的一个注解,把原有的main方法替换了,替换成spring自己的main
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringJUnit4ClassRunner.class)
告知spring运行器,spring和ioc创建是基于xml还是注解,并说明位置
用@ContextConfiguration--->locations属性:指定xml文件位置,加上classpath关键字,表示该文件在类路径下
classes属性:指定配置类所在位置
用@ContextConfiguration--->locations属性:指定xml文件位置,加上classpath关键字,表示该文件在类路径下
classes属性:指定配置类所在位置
当我们用spring5.x版本的时候,要求junit版本在4.12及以上版本
开发模式
jsp开发模式
开发效率较高
执行效率与交互效果低
每次请求都是整个页面刷新,当页面数据量大,用户设备老旧或者网速较差,会出现页面卡顿问题
以至于交互效果较差
以至于交互效果较差
不灵活,解决多端变化问题较难
如果有多个前端页面例如手机版、电脑版、iPad版,那得写多套控制层,较难
前后端分离
后台一律响应数据(json格式)而不响应页面,前端利用前端语言和后台的网络接口进行接收数据和显示
优点
灵活,易于解决多端变化问题
只需要写一套后台,不同前端用不同方式与后台交互
缺点
开发效率较低
前后端分离开发模式开发前需要先设计文档,规定后台与前端所需要接口和参数的标准格式,以便于前后端同时开发且
不容易出现前端调用后台接口出问题的情况
不容易出现前端调用后台接口出问题的情况
跨域问题
跨域带数据
跨域带数据
同源策略
同源
协议相同、ip相同、端口号相同
DOM 同源策略:禁止对不同源页面 DOM 进行操作。
这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
做一个假网站,里面用 iframe 嵌套一个银行网站 http://mybank.com。
把 iframe 宽高啥的调整到页面全部,这样用户进来除了域名,
别的部分和银行的网站没有任何差别。
别的部分和银行的网站没有任何差别。
这时如果用户输入账号密码,我们的主网站可以跨域访问到
http://mybank.com 的 dom 节点,就可以拿到用户的账户密码了。
http://mybank.com 的 dom 节点,就可以拿到用户的账户密码了。
XMLHttpRequest 同源策略:
禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
在不同源情况下,一个服务器向另一个服务器发送ajax
请求,浏览器默认是禁止的,,会产生跨域错误
请求,浏览器默认是禁止的,,会产生跨域错误
解决方案
1. 设置后台允许接受跨域请求
在后端设置响应头
response.setHeader("Access-Control-Allow-Origin", "http://localhost:63342");
该服务器路径可以通过请求对象动态获取
request.getHeader("Origin")
或者通过注解设置
在每个Controller类上加@CrossOrigin注解,该注解允许请求服务器默认为*
但是当前端设置为允许跨域携带参数后不允许将跨域访问路径设为*,虽然该注解可以设置路径,但需要在每个注解中设置
跨域请求服务器路径,所以该方式不太方便
跨域请求服务器路径,所以该方式不太方便
通过拦截器设置
在mvc.xml配置文件中配置拦截器
将该拦截器设置在所有拦截器的最上方,所有请求来之后都先被该拦截器拦截
在拦截器类中为response设置响应头
response.setHeader("Access-Control-Allow-Origin", "http://localhost:63342");
response.setHeader("Access-Control-Allow-Origin", "http://localhost:63342");
2. 设置前端允许跨域请求携带数据
在前端页面设置xhr对象的属性
在ajax请求中设置属性
xhrFields:{
withCredentials:true
},
withCredentials:true
},
XHR原生对象的withCredentials是用于跨域请求的,默认为false
如果想要跨域请求并携带数据则需要将其打开
如果想要跨域请求并携带数据则需要将其打开
***在这种可携带数据的跨域模式下不可以设置为*
3. 后台允许跨域请求携带数据
在拦截器类中设置响应头
response.setHeader("Access-Control-Allow-Credentials", "true");
spring事务管理
API方式/硬编码
PlatformTransactionManager 平台事务管理器 是一个接口
定义了开启事务、提交事务、回滚的方法
定义了开启事务、提交事务、回滚的方法
我们使用DataSourceTransactionManager这一实现类 主要针对
dbutils和jdbcTemplate 对jdbc的封装这个实现类就是一个切面类
dbutils和jdbcTemplate 对jdbc的封装这个实现类就是一个切面类
TransactionDefinition:定义事务参数的接口
事务的隔离级别
事务的超时时间
事务的是否只读
事务的传播行为
TransactionStatus:事务运行状态接口
查看当前事务是否完成
查看是否为新事务
查看是否回滚
声明式/配置文件式
通过配置文件告诉spring,让spring去使用事务控制,这种配置文件的方式实际上是对API的封装
jar包
事务包spring-tx.jar
事务依赖包
AOP联盟
aspectj.jar
spring-aspects.jar
步骤
确定切面类即配置
事务管理器
事务管理器
用<bean>标签配置DataSourceTransactionManager类,
该类需要一个数据源用ref属性配置
该类需要一个数据源用ref属性配置
<bean id="事务管理器名" class="事务类全路径">
<property name="" ref="bean标签中的数据源">
</bean>
<property name="" ref="bean标签中的数据源">
</bean>
细节:需要为事务配置一些事务参数:是否只读、超时时间、传播行为(标签)
用<tx:advice transaction-manager="bean标签中配置的平台事务管理器">标签配置,
必须有这个标签进行配置,事务参数可以不写,不写就为默认值
必须有这个标签进行配置,事务参数可以不写,不写就为默认值
配置声明事务即切面
<tx:advice id="事务名" transaction-manager="需要的事务管理器名">
<tx:attributes>
<!-- 需要进行事务管理的方法 -->
<tx:method name="方法名"/>
</tx:attributes>
</tx:advice>
<tx:attributes>
<!-- 需要进行事务管理的方法 -->
<tx:method name="方法名"/>
</tx:attributes>
</tx:advice>
配置织入
用<aop:advisor>标签配置切面类,用<aop:pointcut>标签配置切点
用事务作为切点
注解
ssm整合
在web.xml中配置
配置核心控制器
核心控制器路径,此处的url-pattern如果是/则指的是除jsp文件以外的所有请求都包含,/*则包含jsp
核心控制器创建时机
核心控制器需要的配置文件
配置监听器
当服务器启动时,该监听器会通过配置文件来初始化spring容器,实现ioc
如果想通过配置监听来实现ioc,需要配下方的配置全局参数
配置全局参数
该参数指向spring配置文件(该配置文件用于整合spring、mybatis),监听器会加载该配置文件,将配置文件
中的数据源、对象以及mapper扫描器创建
中的数据源、对象以及mapper扫描器创建
持久层(dao)
mybatis.xml(可有可无),一般在该文件下配置settings和typeAliases,不过在配置sqlFactoryFactoryBean时也可以配置别名
applicationContext-dao.xml
数据源(druid)
sqlSessionFactory
数据源
别名
<property name="typeAliasesPackage" value="com.wxs.entity">
配置mapper扫描器
在配置sqlSession工厂时,通过property标签,让name值为mapperLocations
value值为classpath:com/wxs/mapper,这里需要使用斜线
value值为classpath:com/wxs/mapper,这里需要使用斜线
用这种方式可以扫描项目下任意路径,可以解决mapper映射器文件和接口不在同意路径下的问题
mapper扫描器
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
在该bean标签下配置sqlSessionFactoryBean,因为mapper接口的底层还是需要由sqlSession得到的
配置需要扫描的包
业务层
applicationContext-service.xml
事务
包扫描器(主要针对@Service注解)
web层(有mvc支持)
springmvc.xml
注解驱动版本
<mvc:annotation-driven/>
配置处理器适配器、处理器映射器最新驱动
包扫描器,主要针对@Controller注解
视图解析器
以setter方式注入前缀和后缀
异常处理器,文件解析器,拦截器
***父子容器关系
spring容器(配置文件)与springmvc容器(配置文件)是父子容器关系
在这两个容器中都只能出现一个<context:property-placeholder location="">
标签加载文件,且子容器可以访问父容器加载到的配置文件,而父容器不能访问子容器加载的文件
在这两个容器中都只能出现一个<context:property-placeholder location="">
标签加载文件,且子容器可以访问父容器加载到的配置文件,而父容器不能访问子容器加载的文件
0 条评论
下一页