SpringMVC 拦截器 springmvc+spring+mybatis 整合

学习目标

  • 掌握 SpringMVC 的统一异常处理

  • 掌握springmvc拦截器

  • 掌握ssm(springmvc+spring+mybatis)整合

统一异常处理

在J2EE程序中,异常分类为预期的异常和运行时异常。预期的异常可以通过捕获进行处(try{…}catch(Exception e){…});运行时异常只能通过规范代码编写,增加测试来减少。

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第1张图片

异常处理思路

请求流程

客户端(浏览器)–>前端控制器(DispatcherServlet)–>表现层(controller)–>业务层(service)–>持久层(dao)

处理思路

从持久层dao开始,每一层发生异常都向上一层抛出,一直抛到前端控制器(DispatcherServlet)。到此不能再抛出,我们不能把异常抛给用户。在前端控制器需要进行异常处理,前端控制器是中央处理器,不负责具体的业务处理,因此在前端控制器需要调用异常处理器进行异常处理,最终返回一个友好的异常提示页面,提示用户。

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第2张图片

方案1:控制层写 try …catch …

控制层的方法写 try …catch …

 @RequestMapping("save2")
    public String save2() {
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            return "error";
        }
        return "success";
    }

方案2:异常过滤器

异常过滤器 (servlet 技术实现控制层 )拦截所有请求 *,过滤器拦截所有请求: controller 、servlet 、jsp 、html /css/js /css/js /

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第3张图片

方案3:使用框架异常处理机制

例如: springmvc 中 HandlerExceptionResolver 异常处理器接口。

自定义异常处理器

写一个异常处理类,实现接口: HandlerExceptionResolver

package com.exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        //打印异常信息
        e.printStackTrace();

        ModelAndView modelAndView = new ModelAndView();
        //保存错误信息
        modelAndView.addObject("error","小伙子,请联系系统管理员");
        //设置错误页面
        modelAndView.setViewName("error");

        return modelAndView;
    }
}

配置异常管理器

  
 <bean class="com.exception.CustomerExceptionResolver"/>

springmvc拦截器

拦截器介绍

springmvc框架中的拦截器,相当于web阶段学习的过滤器(filter),可以实现前置增强和后置增强功能。在springmvc框架中,拦截器可以对处理器方法执行预处理(前置增强),和执行后处理(后置增强)。

拦截器执行机制案例演示

创建项目

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第4张图片

编写自定义拦截器1

springmvc框架中,自定义拦截器需要实现接口(HandlerInterceptor)。

package com.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoHandlerInterceptor1 implements HandlerInterceptor {

    public DemoHandlerInterceptor1() {
        System.out.println("创建拦截器对象");
    }

    /**
     * 前置增强的方法:preHandle
     * 方法参数:
     * request:请求对象
     * response:响应对象
     * handler:目标处理器方法
     * 拦截的方法,业务逻辑控制校验代码都写到这里。
     * 此方法返回true,表示放行。放行的含义是指,如果有下一个拦截器就执行下一个,
     * 如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
     * 此方法返回false,表示不放行,不会执行下一个拦截器以及控制器
     * 如何调用? 按拦截器定义顺序调用
     * 何时调用? 只要配置了都会调用
     * 有什么用? 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回 true。
     * 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("DemoHandlerInterceptor1执行了preHandle方法");
        return true;
    }

    /**
     * 后置增强的方法:postHandle
     * 方法参数:
     * request:请求对象
     * response:响应对象
     * handler:目标处理器方法
     * modelAndView:模型和视图
     * 如何调用?
     * 按拦截器定义逆序调用
     * 何时调用? 在拦截器链内所有拦截器返成功调用
     * 有什么用? 在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用。
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("DemoHandlerInterceptor1执行了postHandle");

    }

    /**
     * 后置增强的方法:afterCompletion
     * 方法参数:
     * request:请求对象
     * response:响应对象
     * handler:目标处理器方法
     * ex:异常对象
     * 如何调用? 按拦截器定义逆序调用
     * 何时调用? 只有 preHandle 返回 true 才调用
     * 有什么用? 在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("DemoHandlerInterceptor1执行了afterCompletion");
    }
}

配置拦截器

在springmvc.xml增加配置:

 
    <mvc:interceptors>
        
        <mvc:interceptor>
            
            <mvc:mapping path="/**"/>
            
            <bean class="com.interceptor.DemoHandlerInterceptor1"/>
        mvc:interceptor>
    mvc:interceptors>

编写InterceptorController

package com.interceptor;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class InterceptorController {

    public InterceptorController() {
        System.out.println("开始生成InterceptorController");
    }

    @RequestMapping("interceptor")
    public ModelAndView test() {
        System.out.println("开始执行controller方法");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("cn", "china");
        modelAndView.setViewName("success");
        return modelAndView;
    }

    @RequestMapping("interceptor2")
    public ModelAndView test2() {
        System.out.println("开始执行controller2方法");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("usa", "american");
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

执行测试

preHandle方法返回true

图一:

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第5张图片

图二:

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第6张图片

执行结果说明:

  1. 首先执行拦截器方法:preHandle

  2. 执行处理器方法:testInterceptor

  3. 执行拦截器方法:postHandle

  4. 响应jsp页面(在postHandle方法封装的模型数据,页面可以获取到)

  5. 执行拦截器方法:afterCompletion

preHandle方法返回false

图一:(没有数据)

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第7张图片

图二:

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第8张图片

执行结果说明:

  1. preHandle方法返回false。只执行了拦截器preHandle方法,后续流程终止执行。

拦截器方法作用说明

方法 方法说明
preHandle preHandle方法,在处理器方法执行前执行,在响应jsp页面前执行。是对处理器方法执行预处理。 该方法返回布尔类型的值。返回true继续执行;返回false终止执行。 在实际项目中,适合于在该方法实现检查用户是否登录、是否有资源操作的权限等业务逻辑处理
postHandle postHandle方法,在处理器方法执行后执行,在响应jsp页面前执行。是对处理器方法执行后处理。 该方法中提供了ModelAndView参数对象,可以封装响应的模型数据。 在实际项目中,适合于在该方法实现公共模型数据的设置。比如页面头部的欢迎信息、页面尾部的友情 链接、备案、免责声明等信息。
afterCompletion afterCompletion方法,在处理器方法执行后执行,在响应jsp页面后执行。是对处理器方法执行后处理。 该方法的特点是只要当前拦截器preHandle方法返回true,就可以得到执行。 在实际项目中,适合于在该方法实现记录用户访问日志、释放资源。

拦截器链(多个拦截器)

编写拦截器二

package com.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class DemoHandlerInterceptor2 implements HandlerInterceptor {

    public DemoHandlerInterceptor2() {
        System.out.println("创建拦截器对象");
    }


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("DemoHandlerInterceptor2执行了preHandle方法");
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("DemoHandlerInterceptor2执行了postHandle");
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("DemoHandlerInterceptor2执行了afterCompletion");
    }
}

增加拦截器二配置

<mvc:interceptor>
      <mvc:mapping path="/**"/>
      <bean class="com.interceptor.DemoHandlerInterceptor2"/>
mvc:interceptor>

测试

拦截器一返回true,拦截器二返回true

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第9张图片

执行结果说明:

  1. preHandle方法按照配置顺序执行

  2. postHandle方法按照配置逆序执行

  3. afterCompletion方法按照配置逆序执行

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第10张图片

ssm(springmvc+spring+mybatis)整合

整合思路

项目分层

  1. 表现层:springmvc(controller)

  2. 业务层:service

  3. 持久层:mybatis(mapper)

controller、service、mapper都是javaBean,通过spring框架进行整合。

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第11张图片

整合前准备工作

准备数据库数据

创建账户表

create table account(
    id int primary key auto_increment,
    name varchar(40),
    money float
)ENGINE=InnoDB character set utf8 collate utf8_general_ci;

insert into account(name,money) values('小明',1000);
insert into account(name,money) values('小花',1000);
insert into account(name,money) values('小王',1000);

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第12张图片

配置pom.xml,导入依赖

  • spring核心支持包

  • aspectj 切面支持

  • spring事务支持、jdbc包

  • springmvc支持包

  • mybatis支持包

  • spring整合mybatis支持包

  • spring对junit支持包、junit–>

  • 数据库驱动、连接池、servlet/jsp支持包、jstl支持包



<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0modelVersion>  
  <groupId>springgroupId>  
  <artifactId>ssmartifactId>  
  <version>1.0-SNAPSHOTversion>  
  <packaging>warpackaging>
  <dependencies> 
      
    <dependency> 
      <groupId>org.springframeworkgroupId>  
      <artifactId>spring-contextartifactId>  
      <version>5.0.2.RELEASEversion> 
    dependency>  
      
    <dependency> 
      <groupId>org.aspectjgroupId>  
      <artifactId>aspectjweaverartifactId>  
      <version>1.9.1version> 
    dependency>  
      
    <dependency> 
      <groupId>org.springframeworkgroupId>  
      <artifactId>spring-txartifactId>  
      <version>5.0.2.RELEASEversion> 
    dependency>  
    <dependency> 
      <groupId>org.springframeworkgroupId>  
      <artifactId>spring-jdbcartifactId>  
      <version>5.0.2.RELEASEversion> 
    dependency>  
      
    <dependency> 
      <groupId>org.springframeworkgroupId>  
      <artifactId>spring-webmvcartifactId>  
      <version>5.0.2.RELEASEversion> 
    dependency>  
      
    <dependency> 
      <groupId>org.mybatisgroupId>  
      <artifactId>mybatisartifactId>  
      <version>3.4.6version> 
    dependency>  
      
    <dependency> 
      <groupId>org.mybatisgroupId>  
      <artifactId>mybatis-springartifactId>  
      <version>1.3.2version> 
    dependency>  
      
    <dependency> 
      <groupId>junitgroupId>  
      <artifactId>junitartifactId>  
      <version>4.12version> 
    dependency>  
    <dependency> 
      <groupId>org.springframeworkgroupId>  
      <artifactId>spring-testartifactId>  
      <version>5.0.2.RELEASEversion> 
    dependency>  
    
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>5.1.47version>
    dependency>
    <dependency> 
      <groupId>com.alibabagroupId>  
      <artifactId>druidartifactId>  
      <version>1.1.10version> 
    dependency>  
    <dependency> 
      <groupId>javax.servletgroupId>  
      <artifactId>servlet-apiartifactId>  
      <version>3.0version> 
    dependency>  
    <dependency> 
      <groupId>javax.servletgroupId>  
      <artifactId>jsp-apiartifactId>  
      <version>2.0version> 
    dependency>  
    <dependency> 
      <groupId>jstlgroupId>  
      <artifactId>jstlartifactId>  
      <version>1.2version> 
    dependency> 
  dependencies> 
project>

编写实体类

package ssm.po;

@Component
public class Account {
    private int id;
    private String name;
    private double money;

    public Account() {
    }

    public Account(int id, String name, double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

编写持久层对象

编写账户dao接口(只写dao接口即可)

package ssm.dao;

import org.apache.ibatis.annotations.Select;
import ssm.po.Account;

import java.util.List;

public interface AccountDao {


    List<Account> findAll();
}

编写mybatis文件

编写接口映射文件



<mapper namespace="ssm.dao.AccountDao">

    
    <select id="findAll" resultType="ssm.po.Account">
        select * from account
    select>

mapper>

编写数据库连接属性文件(db.properties)

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/zzw?characterEncoding=utf8
jdbc.username=root
jdbc.password=root
jdbc.initialSize=3
jdbc.maxActive=10

编写log4j日志文件(log4j.properties)

# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

编写业务层对象

编写账户service接口

package ssm.server;

import ssm.po.Account;

import java.util.List;

public interface AccountServer {

    List<Account> findAll();
}

编写账户service实现类

package ssm.server.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ssm.dao.AccountDao;
import ssm.po.Account;
import ssm.server.AccountServer;

import java.util.List;

@Service
public class AccountServerImpl implements AccountServer {

    @Autowired
    private AccountDao accountDao;


    @Override
    public List<Account> findAll() {
        return accountDao.findAll();
    }
}

配置spring独立运行

配置spring配置文件


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="ssm.server"/>

beans>

spring测试

在spring配置文件中增加实体类bean进行测试

<bean id="account" class="ssm.po.Account"/>
package spring;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import ssm.po.Account;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans.xml")
public class Springtest {

    @Autowired
    private Account account;

    @Test
    public void test() {
        System.out.println(account);
    }


}

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第13张图片

spring整合springmvc

编写springmvc.xml配置文件

  • 配置包扫描controller

  • 配置处理器映射器

  • 配置处理器适配器

  • 配置视图解析器


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    
    <context:component-scan base-package="ssm.controller"/>

    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"/>
        <property name="suffix" value=".jsp"/>
    bean>

    
    <mvc:annotation-driven/>
beans>

在web.xml,配置前端控制器


<servlet>
    <servlet-name>dispatcherServletservlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
    <init-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath:mvc.xmlparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
servlet>

<servlet-mapping>
    <servlet-name>dispatcherServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>

在web.xml配置spring监听器(ContextLoaderListener)

问题:

要让spring与springmvc协作起来,即在springmvc的控制器中需要知道spring的容器,并且从spring容器获取到账户service对象。那么问题来了:如何创建spring容器?又如何从spring容器中获取service对象呢?

推导:

在web项目中,tomcat服务器加载每一个web项目,都会创建一个application域的对象,它是ServletContext。

我们只要通过监听器,监听ServletContext对象的创建,一旦ServletContext对象创建,立即创建spring容器,并且把spring容器放入ServletContxt对象中。那么问题来了:需要我们创建这样的监听器吗?

答案:

spring框架给我们提供了一个监听器ContextLoaderListener,它实现了ServletContextListener监听器接口。它会在ServletContext对象创建的时候,帮助我们创建spring的容器,并且把spring容器放入ServletContext对象中。我们只需要配置即可。

在web.xml配置ContextLoaderListener:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VqE3EfFo-1582269649076)(…/Day57-springmvc%E7%AC%AC%E4%B8%89%E5%A4%A9/media/2e8e9aa8bcbc43bf7a0fd4b4925144d9.png)]


<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>

<context-param>
    <param-name>contextConfigLocationparam-name>
    <param-value>classpath:beans.xmlparam-value>
context-param>

spring-测试

编写账户controller

package ssm.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import ssm.po.Account;
import ssm.server.AccountServer;

import java.util.List;

@Controller
public class AccountController {

    @Autowired
    private Account account;

    @RequestMapping("list")
    public ModelAndView findAll() {
        System.out.println(account);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("list");
        return modelAndView;

    }
}

发布测试

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第14张图片

spring整合mybatis

spring配置文件整mybatis

  1. 加载jdbc.properties文件
  2. 创建连接池bean
  3. Spring整合SqlSessionFactoryBean
  4. 配置包扫描器(扫描dao接口所在包,对包下所有的dao类自动生成代理)
  5. 配置Spring声明式事务配置

    <context:property-placeholder location="classpath:jdbc.properties"/>

    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    bean>

    
    <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="ssm.dao"/>
    bean>

    
    
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    bean>
    
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
        tx:attributes>
    tx:advice>
    
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* ssm.server.impl.*.*(..))"/>
    aop:config>

测试

SpringMVC 拦截器 springmvc+spring+mybatis 整合_第15张图片

你可能感兴趣的:(Spring,MVC)