SpringMVC文件上传

必要前提

  1. form表单的enctype取值必须是:multipart/form-data (默认值是:application/x-www-form-urlencoded) enctype:是表单请求正文的类型
  2. method属性取值必须是Post
  3. 提供一个文件选择域<input type="file" />

环境搭建

创建maven项目

导入相关依赖

pom.xml中导入相关依赖

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <!--spring版本锁定-->
  <spring.version>5.0.2.RELEASE</spring.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-api</artifactId>
    <version>7.0.47</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper-el</artifactId>
    <version>7.0.47</version>
  </dependency>
  <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
  </dependency>
</dependencies>

配置核心控制器

web.xml中配置SpringMVC核心控制器

<web-app>

  <!--配置SpringMVC核心控制器-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>

    <!-- 配置servlet启动时加载对象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--配置springmvc过请求过滤器,/表示所有请求都经过springmvc处理-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

编写核心配置文件

编写SpringMVC核心配置文件springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置创建spring容器要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--SpringMVC注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

单文件上传

配置文件解析器

springmvc.xml中配置文件解析器

<!--
    配置文件上传解析器
    id的值是固定的
    class的值也是固定的
 -->
<beanid="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>

编写文件上传页面

编写文件上传页面upload.jsp

<h1>SpringMVC方式文件上传</h1>
<form action="${pageContext.request.contextPath }/file/upload2" method="post" enctype="multipart/form-data" >
    文件描述:<input type="text" name="desc"><br>
    文件上传:<input type="file" name="file"><br>
    <input type="submit" value="开始上传">
</form>

编写控制层代码

编写控制层代码FileController

@RequestMapping(path="/upload2",method = RequestMethod.POST)
public String upload2(MultipartFile file) throws Exception {
    //1. 获取一个文件输出的磁盘路径
    String path = "C:\\Users\\Administrator\\Desktop\\upload";
    File dir = new File(path);
    if(!dir.exists()){
        dir.mkdir();
    }

    //2. 获取文件名称
    String filename = file.getOriginalFilename();

    //3. 获取文件内容
    InputStream is = file.getInputStream();//获取文件内容

    //4. 创建输出流
    OutputStream os = new FileOutputStream(path + "/" + filename);

    //5. 将文件内容通过输出流写到磁盘文件中
    int i = 0;
    byte[] bys = new byte[1024];

    while ((i = is.read()) != -1) {
        os.write(bys, 0, i);
    }
    os.close();

    return "success";
}

多文件上传

编写文件上传页面

编写文件上传页面upload.jsp

<h1>SpringMVC方式多选文件上传</h1>
<form action="${pageContext.request.contextPath }/file/multi" method="post" enctype="multipart/form-data" >
    文件描述:<input type="text" name="desc"><br>
    文件上传:<input type="file" name="files"><br>
    文件上传:<input type="file" name="files"><br>
    <input type="submit" value="开始上传">
</form>

编写控制层代码

编写控制层代码FileController

@RequestMapping(path="/multi",method = RequestMethod.POST)
public String upload3(MultipartFile[] files) throws Exception {

    //1. 获取一个文件输出的磁盘路径
    String path = "C:\\Users\\Administrator\\Desktop\\upload";
    File dir = new File(path);
    if(!dir.exists()){
        dir.mkdir();
    }

    //遍历文件集合
    for (MultipartFile file : files) {
        //2. 获取文件名称
        String filename = file.getOriginalFilename();
        //3. 获取文件内容
        InputStream is = file.getInputStream();//获取文件内容

        //4. 创建输出流
        OutputStream os = new FileOutputStream(path + "/" + filename);

        //5. 将文件内容通过输出流写到磁盘文件中
        int i = 0;
        byte[] bys = new byte[1024];

        while ((i = is.read()) != -1) {
            os.write(bys, 0, i);
        }
        os.close();
    }

    return "success";
}

SpringMVC拦截器

1. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
2. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
3. 拦截器和过滤器的功能比较类似,有区别
    1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
    2. 拦截器是SpringMVC框架独有的。
    3. 过滤器配置了/*,可以拦截任何资源。
    4. 拦截器只会对控制器中的方法进行拦截。
4. 拦截器也是AOP思想的一种实现方式
5. 想要自定义拦截器,需要实现HandlerInterceptor接口。

环境搭建

创建maven项目

导入相关依赖

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <!--spring版本锁定-->
  <spring.version>5.0.2.RELEASE</spring.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-api</artifactId>
    <version>7.0.47</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper-el</artifactId>
    <version>7.0.47</version>
  </dependency>
</dependencies>
</project>

编写核心控制器

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <!--配置SpringMVC核心控制器-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>

    <!-- 配置servlet启动时加载对象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--配置springmvc过请求过滤器,/表示所有请求都经过springmvc处理-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

编写核心配置文件

编写核心配置文件springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置创建spring容器要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--SpringMVC注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

编写页面代码

编写页面代码index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<title>SpringMVC拦截器</title>
</head>
<body>
<h1>SpringMVC拦截器</h1>
<a href="${pageContext.request.contextPath}/user/add">添加用户</a>
</body>
</html>

编写控制层代码

package com.itheima.web;

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

@Controller
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/add")
    public String add(){
        System.out.println("控制层add方法执行了.....");
        return "success";
    }
}

自定义拦截器

创建拦截器

编写一个普通类实现HandlerInterceptor接口

package com.itheima.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

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

public class MyInterceptor1 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle拦截器执行了.....");
        return true;
    }
}

配置拦截器

springmvc.xml中配置拦截器(掌握)

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!--
            配置拦截器拦截的方法
            /** 代表拦截所有方法
            /user/* 代表拦截/user路径下的所有方法
        -->
        <mvc:mapping path="/user/*"/>
        <!--配置不拦截的方法
        <mvc:exclude-mapping path="" />
        -->
        <bean id="myInterceptor1" class="com.itheima.interceptor.MyInterceptor1"></bean>
    </mvc:interceptor>
</mvc:interceptors>

拦截器的细节

拦截器的放行

放行的含义是指,如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。



拦截器中方法的说明

方法名 说明
preHandle() 方法将在请求处理之前进行调用, 该方法的返回值是布尔值Boolean类型的,当它返回为false时, 表示请求结束, 后续的Interceptor和Controller都不会再执行; 当返回值为true时就会继续调用下一个Interceptor的preHandle方法
postHandle() 该方法是在当前请求进行处理之后被调用, 前提是preHandle方法的返回值为true时才能被调用, 且它会在DispatcherServlet进行视图返回渲染之前被调用, 所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作
afterCompletion() 该方法将在整个请求结束之后, 也就是在Dispatcher Servlet渲染了对应的视图之后执行, 前提是preHandle方法的返回值为true时才能被调用,常用于接口返回修改
1. `preHandle()`是controller方法执行前拦截的方法
    1. 可以使用request或者response跳转到指定的页面
    2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。
    3. return false不放行,不会执行controller中的方法。

2. `postHandle()`是controller方法执行后执行的方法,在JSP视图执行前。
    1. 可以使用request或者response跳转到指定的页面
    2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。

3. `afterCompletion()`方法是在JSP执行后执行
    1. request或者response不能再跳转页面了

拦截器的作用路径

<mvc:interceptor>
    <!--
        配置拦截器拦截的方法
        /** 代表拦截所有方法
        /user/* 代表拦截/user路径下的所有方法
    -->
    <mvc:mapping path="/user/*"/>
    <!--配置不拦截的方法
    <mvc:exclude-mapping path="" />
    -->
    <bean id="myInterceptor1" class="com.itheima.interceptor.MyInterceptor1"></bean>
</mvc:interceptor>

多个拦截器配置

<!-- 配置拦截器 -->
<mvc:interceptors>
   <mvc:interceptor>

       <mvc:mapping path="/user/*"/>

       <bean id="myInterceptor1" class="com.itheima.interceptor.MyInterceptor1"></bean>
   </mvc:interceptor>

   <mvc:interceptor>
       <mvc:mapping path="/user/*"/>
       <bean id="myInterceptor2" class="com.itheima.interceptor.MyInterceptor2"></bean>
   </mvc:interceptor>
</mvc:interceptors>

拦截器实现权限控制

登录代码编写

在登陆页面输入用户名密码,点击登陆,通过用户名密码进行查询,如果登陆成功,则将用户信息实体存入session,然后跳转到首页,如果登陆失败则继续回到登陆页面

表现层

package com.itheima.web;

import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * @Author 王磊
 * @Date 2019/11/1/001
 */
@Controller
@RequestMapping(path = "/user")
public class UserController {

    @RequestMapping(path = "/login")
    public String login(@RequestParam(name="user") String username , String password , Model model , HttpSession session){
        //用户登录
        User user = userService.login(username, password);
        //判断是否登录成功 , 响应页面
        //用户登录失败
        if(user==null){
            model.addAttribute("msg","用户名或密码错误");
            return "login";
        }

        //登录成功 , 跳转到用户列表页面
        //保存到Session域对象
        session.setAttribute("user",user);
        //页面跳转 , 注意不能直接跳转到list.jsp页面
        return "redirect:/user/findAll";
    }
}

业务层

package com.itheima.service;

import com.itheima.pojo.User;

import java.util.List;

/**
 * @Author 王磊
 * @Date 2019/11/1/001
 */
public interface UserService {

    /**
     * 用户登录
     * @return
     */
    public User login(String username , String password);

}

package com.itheima.service.impl;

import com.itheima.dao.UserDao;
import com.itheima.pojo.User;
import com.itheima.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author 王磊
 * @Date 2019/11/1/001
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao ;

    @Override
    public User login(String username, String password) {
        return userDao.findByUsernameAndPassword(username,password);
    }

}

数据访问层

package com.itheima.dao;

import com.itheima.pojo.User;

import java.util.List;

/**
 * @Author 王磊
 * @Date 2019/11/1/001
 */
public interface UserDao {

    /**
     * 根据用户名或密码查询用户数据
     * @param username
     * @param password
     * @return
     */

    public User findByUsernameAndPassword(String username , String password);

}
package com.itheima.dao.impl;

import com.itheima.dao.UserDao;
import com.itheima.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @Author 王磊
 * @Date 2019/11/1/001
 */
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate ;

    @Override
    public User findByUsernameAndPassword(String username, String password) {
        try {
            //queryForObject如果查询到数据会封装返回 , 如果查询不到数据抛出异常
            String sql = select * from tb_user where username=? and password = ?";
            return jdbcTemplate.queryForObject(sql,new BeanPropertyRowMapper<User>(User.class),username,password);
        } catch (DataAccessException e) {
            e.printStackTrace();
            return null ;
        }
    }
}

配置文件

druid.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/springmvc_02
jdbc.username=root
jdbc.password=zl

springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<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="com.itheima"> </context:component-scan>

    <!--加载属性配置文件-->
    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>

    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

    <!--配置jdbcTemplate对象-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--开启注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!--释放静态资源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

    <!--配置视图解析器  list  /list.jsp-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

    <!--配置字符串编码过滤器-->
    <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>

    <!--配置前端控制器-->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!--加载SpringMVC配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/js/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/fonts/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/css/*</url-pattern>
    </servlet-mapping>

</web-app>

定义拦截器

package com.itheima.interceptor;

import com.itheima.pojo.User;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * @Author 黑马程序员
 */
public class PrivilegeInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断用户是否登录
        //1. 获取session中保存的用户信息
        User user = (User) request.getSession().getAttribute("user");
        //2. 判断用户信息是否为null
        if (user == null) {
            //3. 如果为null代表用户为登录, 返回到登录页面
            request.setAttribute("msg", "权限不足 , 请登录!!");
            request.getRequestDispatcher("/login.jsp").forward(request, response);
            return false;
        }

        //4. 如果不为null代表用户登录成功 ,放行
        return true;
    }
}

配置拦截器

此时仍然登陆不上,因为我们需要将登陆请求url让拦截器放行,添加资源排除的配置

<!--配置拦截器信息-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--配置哪些请求需要拦截-->
        <mvc:mapping path="/**"/>
        <!--配置哪些请求不需要拦截-->
        <mvc:exclude-mapping path="/user/login"></mvc:exclude-mapping>
        <mvc:exclude-mapping path="/js/**"></mvc:exclude-mapping>
        <mvc:exclude-mapping path="/fonts/**"></mvc:exclude-mapping>
        <mvc:exclude-mapping path="/css/**"></mvc:exclude-mapping>
        <bean class="com.itheima.interceptor.PrivilegeInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

SpringMVC异常处理

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

系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:


异常环境搭建

导入相关依赖

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <maven.compiler.source>1.8</maven.compiler.source>
  <maven.compiler.target>1.8</maven.compiler.target>
  <!--spring版本锁定-->
  <spring.version>5.0.2.RELEASE</spring.version>
</properties>

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-api</artifactId>
    <version>7.0.47</version>
  </dependency>
  <dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jasper-el</artifactId>
    <version>7.0.47</version>
  </dependency>
</dependencies>
</project>

编写核心控制器

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <!--配置SpringMVC核心控制器-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

    <!-- 配置Servlet的初始化参数,读取springmvc的配置文件,创建spring容器 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>

    <!-- 配置servlet启动时加载对象 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--配置springmvc过请求过滤器,/表示所有请求都经过springmvc处理-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

编写核心配置文件

编写核心配置文件springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置创建spring容器要扫描的包 -->
    <context:component-scan base-package="com.itheima"></context:component-scan>

    <!--SpringMVC注解驱动-->
    <mvc:annotation-driven></mvc:annotation-driven>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>


</beans>

编写前端页面

编写前端页面index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>SpringMVC异常处理</title>
</head>
<body>
<h2>SpringMVC异常处理</h2>
<a href="${pageContext.request.contextPath}/exception/test">异常处理</a>
</body>
</html>

编写控制层代码

编写控制代码ExceptionController

package com.itheima.web;

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

@Controller
@RequestMapping("/exception")
public class ExceptionController {

    @RequestMapping("/test")
    public String testException() throws Exception{
        System.out.println("控制器执行成功...");
        int i = 10/0;
        return "success";
    }
}

异常处理方式

在SpringMVC中提供了二种异常处理方式 :

  • 使用Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver

  • 实现Spring的异常处理接口HandlerExceptionResolver 自定义自己的异常处理器

简单异常处理器

SpringMVC已经定义好了该类型转换器,在使用时可以根据项目情况进行相应异常与视图的映射配置

<!--配置简单映射异常处理器-->
<bean class=“org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>       <property name=“defaultErrorView” value=“error”/>   默认错误视图
    <property name=“exceptionMappings”>
        <map>       异常类型                                     错误视图
            <entry key="com.itheima.exception.MyException" value="error"/>
            <entry key="java.lang.ClassCastException" value="error"/>
        </map>
    </property>
</bean>

自定义异常处理器

编写自定义异常CustomException

①创建异常处理器类实现HandlerExceptionResolver
②配置异常处理器
③编写异常页面
④测试异常跳转

package com.itheima.exception;

public class CustomException extends Exception {

    private String message;

    public CustomException(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

定义异常处理器

自定义异常处理器CustomExceptionResolver

public class CustomExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception ex) {
        ex.printStackTrace();
        CustomException customException = null;
        //如果抛出的是系统自定义异常则直接转换
        if (ex instanceof CustomException) {
            customException = (CustomException) ex;
        } else {
            //如果抛出的不是系统自定义异常则重新构造一个系统错误异常。
            customException = new CustomException("系统错误,请与系统管理 员联系!");
        }

        //创建ModelAndView对象
        ModelAndView modelAndView = new ModelAndView();
        //保存错误信息
        modelAndView.addObject("message", customException.getMessage());
        //设置跳转的视图名称
        modelAndView.setViewName("error");

        return modelAndView;
    }
}

编写错误页面

编写错误页面error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>执行失败</title>
</head>
<body>
 执行失败! ${message }
</body>
</html>

配置异常处理器

springmvc.xml中配置异常处理器

<!-- 配置自定义异常处理器 -->
<bean id="handlerExceptionResolver" class="com.itheima.exception.CustomExceptionResolver"/>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容