Spring集成Web环境

Spring提供了监听器ContextLoaderListener,内部加载Spring配置文件,创建应用上下文对象,存储到ServletContext域中,提供了客户端工具WebApplicationContextUtils供使用者获得应用上下文对象

  • 在web.xml中配置ContextLoaderListener监听器(导入spring-web坐标)
  • 使用WebApplicationContextUtils获得应用上下文对象ApplicationContext

SpringMVC

SpringMVC简介
概述

SpringMVC是一种基于java的实现MVC设计模型的请求驱动类型的轻量级web框架

开发步骤
  1. 导入SpringMVC相关坐标
  2. 配置SpringMVC核心控制器DisplayerServlet
  3. 创建Controller类和视图界面
  4. 使用注解配置Controller类中业务方法的映射地址
  5. 配置SpringMVC核心文件spring-mvc.xml
SpringMVC组件解析
SpringMVC执行流程
  1. 用户发送请求至前端控制器DispatcherServlet。

  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。

  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

  4. DispatcherServlet调用HandlerAdapter处理器适配器。

  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

  6. Controller执行完成返回ModelAndView。

  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet.

  8. DispatcherServlet将ModelAndView传给ViewResolver视图解析器。

  9. ViewResolver解析后返回具体View。

  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。

SpringMVC注解解析

@RequestMapping

  • 作用:用于建立请求URL和处理请求方法之间的对应关系
  • 位置:
    • 类,请求URL的第一级访问目录。不写相当于应用的根目录
    • 方法,请求URL的第二级访问目录,与类上使用的@RequestMapping标注的一级目录一起组成访问路径
  • 属性:
    • value:指定请求的url,和path属性作用一样
    • method:指定请求方式
    • params:指定限制请求参数的条件,支持简单的表达式,要求请求参数的key和value必须和配置一模一样
      • params = {“xxx”}:表示请求参数必须有xxx
      • params = {“xxx!100”}:表示请求参数xxx不能是100
SpringMVC的数据响应
数据响应方式
  1. 页面跳转
    • 直接放回字符串
    • 通过ModelView对象返回
  2. 回写数据
    • 直接返回字符串
    • 返回对象或集合
页面跳转

返回字符串形式

直接返回字符串:此种方式会将返回的字符串与视图解析器前后缀拼接跳转

@RequestMapping("/quick")
 public String quick(){
     return "success";
 }
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/jsp/"></property>
     <property name="suffix" value=".jsp"></property>
 </bean>

返回ModelAndView

ModelAndView modelAndView = new ModelAndView();
     //设置模型数据
     modelAndView.addObject("username","jojo");
     //设置视图名称
     modelAndView.setViewName("success");
     return modelAndView;
回写数据

直接返回字符串

  1. 通过SpringMVC框架注入response对象,使用respons.getWriter().print()回写数据,不需要视图跳转,业务方法返回值为void。@ResponseBody告知SpringMVC框架该方法不进行试图跳转,直接数据响应

  2. 解析json对象,导入:

    jackson-core、jackson-databind、jackson-annotations

返回对象或集合

<!--    配置处理器映射器-->
 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
     <property name="messageConverters" >
         <list>
             <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
         </list>
     </property>
 </bean>

直接返回对象,自动解析

可以使用mvc的注解驱动代替以上配置

<mvc:annotation-driven/>

自动加载以上所有操作

SpringMVC获得请求的数据
获得请求参数

客户端请求参数格式:name:value&...

SpringMVC可以接收如下类型参数:

  • 基本数据类型
  • POJO类型(bean
  • 数组类型参数
  • 集合类型

获得基本类型参数

Controller中业务方法的参数名与请求参数name一致,参数值会自动映射

获得POJO类型参数

Controller中业务方法的POJO参数的属性名与请求参数name一致,参数值会自动映射

获得数组类型参数

Controller中业务方法数组名称与请求参数name一致,参数值会自动映射

获得集合类型参数

获得集合参数时,将集合参数包装到POJO中

使用ajax提交时,可以指定contentType为json格式,无需POJO包装

开发静态资源访问
    <mvc:resources mapping="/js/**" location="/js/"/><mvc:default-servlet-handler/>
配置全局乱码过滤器

当POST请求时,出现乱码问题

<!--  配置全局过滤的filter-->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
参数绑定注解@requestParam

当请求的参数名称与Controller的业务方法参数名称不一致

@RequestParam(value="xxx",required="false")	//xxx为请求参数,自动映射到参数中

在SpringMVC中可以使用占位符进行参数绑定,地址/new/1可以写成/new/{id}

在业务方法中可以使用@PathVariable注解进行占位符的匹配获取工作

@RequestMapping(value = "/quick/{name}")
 @ResponseBody
 public void save(@PathVariable(value="name",required= true) String username)
自定义类型转换器

SpringMVC提供了常用的类型转换器

自定义类型转换器的开发步骤:

  1. 定义转换器类实现Converter接口
  2. 在配置文件中声明转换器
  3. <annotation-driven>中引用转换器
获得Servlet相关API

SpringMVC支持原始ServletAPI对象作为控制器方法的参数进行注入,常用对象如下:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession

直接在方法中进行形参注入哦的

获得请求头

@RequestHeader

  • value:请求头的名称
  • required:是否必须携带此请求头

@CookieValue

  • value:指定cookie的名称
  • required:是否必须携带此cookie
文件上传

文件上传客户端三要素

  • 表单项type=”file”
  • 表单的提交方式:post
  • 表单的enctype属性是多部分表单形式,及enctype= “multipart/form-data”

单文件上传

  • 导入fileupload和io坐标
  • 配置文件上传解析器
<!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--        上传文件总大小-->
        <property name="maxUploadSize" value="5242800"/>
        <property name="maxUploadSizePerFile" value="5242800"/>
<!--        上传文件的编码类型-->
        <property name="defaultEncoding" value="UTF-8"/>
    </bean>
  • 编写文件上传代码
String originalFilename = uploadFile.getOriginalFilename();
      uploadFile.transferTo(new File("E:\\Desktop\\"+originalFilename));

Spring JDBC 模板

JDBC模板

Spring提供的对原始繁琐的JDBC API对象的简单封装

JdbcTemplate开发步骤
  1. 导入spring-jdbc和spring-tx坐标
  2. 创建数据库表和实体
  3. 获取数据源,创建JdbcTemplate对象
  4. 执行数据库操作

SpringMVC拦截器

SpringMVC拦截器相当于过滤器Filter,对处理器进行预处理和后处理

将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。拦截器也是AOP思想的具体实现。

自定义拦截器
  1. 创建拦截器类实现HandlerInterceptor接口
  2. 配置拦截器(spring-mvc
  3. 测试拦截效果
拦截器方法说明
方法名 说明
preHandle() 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor的preHandle方法
postHandle() 该方法是在当前请求进行处理之后被调用,前提是preHandle方法的返回值为true 时才能被调用,且它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作
afterCompletion() 该方法将在整个请求结束之后,也就是在DispatcherServlet渲染了对应的视图之后执行,前提是preHandle方法的返回值为true时才能被调用

SpringMVC异常处理

异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试等手段减少运行时异常的发生。

系统的Dao、Service、Controller出现都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理。

异常处理方式
  • 使用SpringMVC提供的简单异常处理器SimpleMappingExceptionResolver
  • 使用Spring的异常处理接口HandleExceptionResolver自定义异常处理器
<!--配置异常处理器-->
 <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
     <property name="defaultErrorView" value="error"/>
     <property name="exceptionMappings">
         <map>
             <entry key="java.lang.ClassCastException" value="error1"/>
             <entry key="com.itheima.exception.MyException" value="error2"/>
         </map>
     </property>
 </bean>-->

自定义异常处理器

  1. 创建异常处理器类实现HandleExceptionResolver
  2. 配置异常处理器
  3. 编写异常页面

Spring AOP

简介

面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的同样以维护的一种技术

利用AOP可以对业务逻辑各个部分进行隔离,从而使业务逻辑各部分解耦合,提高程序的可重用性,提高开发效率

AOP动态代理技术
  • JDK代理:基于接口的动态代理
  • cglib代理:基于父类的动态代理技术
JDK的动态代理
//返回值就是动态生成的代理对象
        TargetInterface proxyInstance = (TargetInterface) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),//目标对象类加载器
                target.getClass().getInterfaces(),//目标对象接口加载器
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        advice.before();
                        Object invoke = method.invoke(target, args);//执行目标方法
                        advice.after();
                        return invoke;
                    }
                }
        );
        proxyInstance.save();
cglib动态代理
//返回值就是动态生成的代理对象,基于gclib
        //1.创建增强器
        Enhancer enhancer = new Enhancer();
        //2.设置父类(目标)
        enhancer.setSuperclass(Target.class);
        //3.设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {


                advice.before();
                Object invoke = method.invoke(target, objects);

                advice.after();
                return invoke;
            }
        });
        //4.创建代理对象
        Target proxy = (Target) enhancer.create();

        proxy.save();
AOP相关概念

Spring的AOP实现底层就是对动态代理的代码进行了封装,之后只需对需要关注的部分进行代码编写,通过配置方式完成指定目标的方法增强

  • Target:代理的目标对象
  • Proxy:代理对象
  • Joinpoint:连接点,指那些被拦截的点(方法),可以被增强的方法
  • Pointcut:切入点,指要增强的方法
  • Advice:通知/增强,额外功能
  • Aspest:切面,切入点+通知
  • Weaving:将切点和增强结合的过程
基于xml的AOP开发
<!--    目标对象-->
    <bean id="target" class="top.handsomelv.aop.Target"/>
<!--    切面对象-->
    <bean id="myAspect" class="top.handsomelv.aop.MyAspect"/>
<!--    配置织入,哪些方法(切点)需要进行那些增强(前置、后置...)-->
    <aop:config>
<!--        声明切面-->
        <aop:aspect ref="myAspect">
<!--            切面:切点+通知-->
            <aop:before method="before" pointcut="execution(public void top.handsomelv.aop.Target.save())"/>
        </aop:aspect>
    </aop:config>

切点表达式的写法

execution([修饰符] 返回值类型 包名.类名.方法名(参数))

  • 访问修饰符可以省略
  • 返回值类型、包名、类名、方法名可以使用星号*代表任意
  • 包名与类名之间一个点.代表当前包下的类,两个点..表示当前包及其子包下的类
  • 参数列表可以使用两个点..表示任意个数,任意类型的参数列表

当多个增强的切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式。

<aop:aspect ref="myAspect">
<!--            切面:切点+通知-->
         <aop:pointcut id="mypc" expression="execution(* top.handsomelv.aop.*.*(..))"/>
         <aop:before method="before" pointcut-ref="mypc"/>
</aop:aspect>
注解实现AOP
  1. 创建目标接口和目标类(内部有切点
  2. 创建切面类(内部有增强方法
  3. 将目标类和切面类的对象创建权交给spring
  4. 在切面类中使用注解配置织入关系
  5. 在配置文件中开启组件扫描和AOP的自动代理
<aop:aspectj-autoproxy/>	AOP自动代理

注解中切点表达式抽取

@Before("pointcut()")
    public void before(){
        System.out.println("前置增强");
    }
@Pointcut("execution(* top.handsomelv.anno.*.*(..))")
    public void pointcut(){}

Spring事务控制

编程式事务控制相关对象
PlatformTransactionManager

该接口是spring的事务管理器

  • getTranscation():获取事务状态信息
  • commit:提交事务
  • rollback:回滚事务
TransactionDefinition

事务的定义信息对象

  • getIsolationLevel:获取事务的隔离级别
  • getPropogationBehavior:获得事物的传播行为
  • getTimeout:获得超时时间
  • isReadOnly:是否只读
TransactionStatus

事务的运行状态

  • hasSavePoint:是否存储回滚点
  • isCompleted:事务是否完成
  • isNewTransaction:是否为新事务
  • isRollbackOnly:事务是否回滚
基于XML声明式事务控制

仍然是AOP思想。配置文件

  • 平台事务管理器配置
  • 事务通知配置
  • 事务aop织入
!--目标对象  内部的方法就是切点-->
    <bean id="accountService" class="top.handsomelv.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--配置平台事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--通知  事务的增强-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--设置事务的属性信息的-->
        <tx:attributes>
            <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
            <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
            <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!--配置事务的aop织入-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* top.handsomelv.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
基于注解声明式事务配置

利用@Transactional(isolation = Isolation.REPEATABLE_READ...)替代

<!--通知  事务的增强-->
 <tx:advice id="txAdvice" transaction-manager="transactionManager">
     <!--设置事务的属性信息的-->
     <tx:attributes>
         <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
         <tx:method name="save" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false"/>
         <tx:method name="findAll" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
         <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true"/>
         <tx:method name="*"/>
     </tx:attributes>
 </tx:advice>

 <!--配置事务的aop织入-->
 <aop:config>
     <aop:pointcut id="txPointcut" expression="execution(* top.handsomelv.service.impl.*.*(..))"/>
     <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
 </aop:config>

并且添加事务的注解驱动

<!--事物的注解驱动-->
 <tx:annotation-driven transaction-manager="transactionManager"/>
注解配置声明式事务控制解析
  • 使用@Transactional在需要进行事务控制的类或是方法上修饰,注解可用的属性同xml配置方式,例如隔离级别、传播行为等。
  • 注解使用在类上,那么该类下的所有方法都使用同一套注解参数配置。
  • 使用在方法上,不同的方法可以采用不同的事务参数配置。
  • Xml配置文件中要开启事务的注解驱动<tx:annotation-driven/>