首页 > 技术文章 > springMvc学习

xiamengz 2020-12-08 17:25 原文

SpringMVC学习

SpringMVC概述

​ SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功 能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1(现在一般不用),Struts2 等。 SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2,成 为最优秀的 MVC 框架。 它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。

SpringMVC 的优势

1、清晰的角色划分:

​ 前端控制器(DispatcherServlet)

​ 请求到处理器映射(HandlerMapping)

​ 处理器适配器(HandlerAdapter)

​ 视图解析器(ViewResolver)

​ 处理器或页面控制器(Controller)

​ 验证器( Validator)

​ 命令对象(Command 请求参数绑定到的对象就叫命令对象)

​ 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。

2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。

3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。

4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。

5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。

6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。

7、功能强大的数据验证、格式化、绑定机制。

8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。

9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。

10、强大的 JSP 标签库,使 JSP 编写更容易。

………………还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配 置支持等等。

SpringMVC 的搭建

1、导入springMVC的相关jar包;

2、在web.xml文件中配置springMVC的核心控制器(处理请求):dispatcherServlet

3、新建springMVC.xml配置文件,并做相应配置。

SpringMVC环境搭建

1、导入springMVC相应jar包

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.9.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.9.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.2.9.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.0</version>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

2、在web.xml配置文件中配置dispatchServlet

  <!--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>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

3、新建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.test.controller"></context:component-scan>

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

    <!--配置spring开启注解mvc的支持 -->
    <mvc:annotation-driven></mvc:annotation-driven>
</beans>

4、编写index.jsp文件

<html>
<body>
<h2>Hello World!</h2>
<a href="hello">hello</a>
</body>
</html>

5.创建controller控制器

@Controller
public class HelloWorld {
	/**
	 *接收请求
	**/
    @RequestMapping("hello")
    public String hello(){
        System.out.println("hello SpringMVC!");
        //跳转到success页面
        return "success";
    }
}

6、在WEB-INf目录下创建pages文件夹,编写success.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
</head>
<body>
    <h3>成功!</h3>
</body>
</html>

目录结构图:

运行结果:

点击“hello” a标签,跳转到success.jsp页面

SpringMVC注解命令

@Controller注解

@Controller用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是真正处理请求的处理器。

/**
 * @Controller注解:
 *  将HelloWorld作为SpringMVC的控制类
 */
@Controller
public class HelloWorld {
    /**
     * @RequestMapping : 设置请求映射,把请求和控制层中的方法设置映射关系
     * 当请求路径和@RequestMapping的value属性值一致时,则该注解所标注的方法即为处理请求的方法。
     * @return
     */
    @RequestMapping("hello")
    public String hello(){
        System.out.println("hello SpringMVC!");
        return "success";
    }
}

@RequestMapping注解

@RequestMapping : 设置请求映射,把请求和控制层中的方法设置映射关系。

RequestMapping属性:

value属性:

​ 请求的映射名称,可以有多个值。

//跳转登录
@RequestMapping(value={"/","/first","/login"})
public String login(){
    return "login";
}
//如RequestMapping只填写value属性则只有一个值时,value可省略不写
@RequestMapping("/hello"})
public String hello(){
    return "hello";
}

method属性:

​ 用来设置请求方式,只有客户端发送请求的方式和method的值一致,才能处理请求

​ 请求方式:GET 查询 POST 添加 PUT 修改 DELETE 删除

@RequestMapping(value = "method",method = RequestMethod.GET)
    public String requestMethod(){
        System.out.println("requestMethod is running!");
        return "success";
    }
<a href="/method">method</a>

当RequestMapping的请求方式改成POST时

@RequestMapping(value = "method",method = RequestMethod.POST)
    public String requestMethod(){
        System.out.println("requestMethod is running!");
        return "success";
    }

会提示以下错误

20-Nov-2020 14:40:33.448 警告 [http-nio-8080-exec-4] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported]

param属性:

​ 处理请求参数。用来设置客户端传到服务器的数据,支持表达式。

​ 客户端发送的请求必须带有param设置的参数。

@RequestMapping(value = "params",params = {"username","age!=12"})
public String params(){
    System.out.println("params is running");
    return "success";
}
<a href="/params?username=zhangsan&age=11">params</a>

​ 如客户端发送的请求与param设置的请求参数不一致,会报以下错误

20-Nov-2020 14:48:53.330 警告 [http-nio-8080-exec-4] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.web.bind.UnsatisfiedServletRequestParameterException: Parameter conditions "username, age!=12" not met for actual request parameters: username={zhangsan}, age={12}]

header属性

​ 用来设置请求头信息,所发送的请求的请求头信息一定要和headers属性中所设置的一致

@RequestMapping(value = "header",headers = {"Accept-Language=zh-CN;"})
public String header(){
    System.out.println("header is running!");
    return "success";
}

Ant风格

​ RequestMapping支持Ant路径风格

​ Ant风格资源地址支持3中匹配符:

​ ?:匹配文件名中的一个字符

​ * :匹配文件名中的任意字符

​ ** :匹配多层路径

/user/*/creatUser
匹配 /user/aaa/creatUser、 /user/bbb/creatUser等URL
/user/**/creatUser
匹配 /user/creatUser、 /user/aaa/bbb/creatUser等URL
/user/createUser??
匹配 /user/createUseraa、 /user/createUserbb等URL
@RequestMapping(value = "/*/testAnt")
public String testAnt(){
    System.out.println("Ant is running!");
    return "success";
}
<a href="/test/testAnt">testAnt</a>

PathVatiabl注解

一般与RequestMapping一起使用,Pathvatiabl的作用是获取占位符的值

/**
     * 以前:localhost:8080/projectName/testRest?id=1001&username=admin
     * 现在:localhost:8080/projectName/testRest/1001/admin
     */
@RequestMapping("testRest/{id}/{username}")
public String testRest(@PathVariable("id")Integer id, @PathVariable("username")String username){
    System.out.println("id:"+id+",username:"+username);
    return "success";
}
<a href="/testRest/1001/admin">testRest</a>

如不填写占位符的参数,会报404错误。

rest风格编程

在HTTP协议里面,有以下几个表示操作方式的动词:
GET、POST、PUT、DELETE,分别对应着查询、增加、修改、删除操作。

在SpringMVC中可以使用rest风格占位符的方式,使用注解@PAthVariable实现将URL中的数据复制到Java的具体变量上。

比如以下:

路径 HTTP方式 解释
http://localhost:8080/stu/1 GET 获取id为1的数据(这里假设要取的是学生数据)
http://localhost:8080/stu GET 获取所有的学生数据
http://localhost:8080/stu/1 DELETE 删除id为1的学生的数据信息
http://localhost:8080/stu/1 PUT 修改id为1的学生的数据信息
http://localhost:8080/stu POST 新增一条学生数据

a链接标签中只有get请求方式,from表单只有get,post请求两种方式。

可以通过hiddenhttpmethodfilter过滤器:转换请求方式。条件:提交方式:post,请求参数必须有:_method

在web.xml做如下配置:

 <!-- 配置HiddenHttpMethedFilter 用于REST风格编程:form表单只有:GET/POST,两种请求方式,该Filter可以将POST请求转换成PUT/DELETE请求 -->
  <filter>
  	<filter-name>HiddenHttpMethodFilter</filter-name>
  	<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  
  <filter-mapping>
  	<filter-name>HiddenHttpMethodFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

@RequestParam

@RequestMapping注解中的params属性类似。

//value代表参数名称,required代表是否必须
@RequestMapping("/requsetParam")
public String requsetParam(@RequestParam(value = "username",required = true)String userName){
    System.out.println("requsetParam is running!"+userName);
    return "success";
}
<a href="/requsetParam?username=zxm">requsetParam</a>

ModelAndView方法

在SpringMVC中,无论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后再进行页面的跳转。

@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
    ModelAndView mav = new ModelAndView();
    //往request作用域中放值
    mav.addObject("username","admin");
    //设置视图名称,实现页面跳转
    mav.setViewName("success");
    return mav;
}
@RequestMapping("/testMap")
public String testMap(Map<String,Object> map){
    //往作用域中放值
    map.put("username","admin");
    //返回视图名称
    return "success";
}
@RequestMapping("/testModel")
public String testModel(Model model){
    //往作用域放值
    model.addAttribute("username","admin");
    //返回视图名称
    return "success";
}

以上的三个例子,Map和Model的底层方法都是ModelAndView

SpringMVC的转发和重定向

在WEB-INF下的文件无法直接通过文件链接访问,需通过Controller中的转发访问文件。

请求的3中方式:

1、请求经过视图解析器

<a href="/login">跳转到登录页面</a>
@RequestMapping("login")
public String login() {
    System.out.println("login方法执行了!!");
    return "login";
}

2、通过forward转发或redirect重定向

//转发
@RequestMapping("login")
public String login() {
    System.out.println("login方法执行了!!");
    //return "login";
    return "forward:/WEB-INF/pages/login.html";
}
//重定向
@RequestMapping("testRedirect")
public String testRedirect() {
    //重定向中的testReturnString是controller控制器的一个方法。重定向方法无法访问WEB-INF目录下的文件。
    return "redirect:testReturnString";
}
@RequestMapping("/testReturnString")
public String testReturnString() {
    System.out.println("testRedirect方法执行了!!");
    return "login";
}

注意:转发和重定向url时有斜线/和没有斜线的区别,有斜线是项目级别,无斜线是类级别下的

@RequestMapping("/testRedirect")
public String testRedirect() {
    //重定向到webapp目录下的login.html文件。
    return "redirect:login.html";
}

3、使用原生Servlet

@RequestMapping("/forwardServlet")
public void forwardServlet(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("forwardServlet方法执行了!");
    req.getRequestDispatcher("/WEB-INF/pages/login.html").forward(req, resp);
}

类型转换器

  • ConversionService是Spring类型转换体系的核心接口。
  • 可以利用ConversionSeviceFactoryBean在Spring的IOC容器中定义ConversionService.Spring将自动识别出IOC容器中的ConversionService,并在Bean属性配置及Spring MVC处理方法入参绑定等场合使用它进行数据的转换
  • 可通过ConversionServiceFactoryBean的converters属性注册自定义的类型转换器

Spring支持的转换器

  • Spring定义了3中类型的转换器接口,实现任意一个转换器接口都可以作为自定义转换器注册到ConversionServiceFactoryBean中:
    • Converter<S,T>:将S类型对象转为T类型对象
    • ConverterFactory:将相同系列多个“同质”Converter封装在一起。如果希望将一种类型的对象转换为另一种类型及其子类的对象(例如将String转换为Number及Number子类(Integer、Long、Double等)对象)可使用该转换器工厂类
    • GenericConverter:会根据源类对象及目标类对象所在的宿主类中的上下文信息进行类型转换

实例:

/**
 * 自定义类型转换器:将字符串转换为日期格式
 */
public class StringToDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        DateFormat format = null;
        try {
            if(StringUtils.isEmpty(s)) {
                throw new NullPointerException("请输入要转换的日期");
            }
            format = new SimpleDateFormat("yyyy-MM-dd");
            Date date = format.parse(s);
            return date;
        } catch (Exception e) {
            throw new RuntimeException("输入日期有误");
        }
    }
}

在springmvc配置自定义转换器

<!--配置spring开启注解mvc的支持 -->
<!-- conversion-service: 引用自定义类型转换器-->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>

<!-- 配置类型转换器工厂 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <!-- 给工厂注入一个新的类型转换器 -->
    <property name="converters">
        <array>
            <!-- 配置自定义的类型转换器 -->
            <bean class="com.test.utils.StringToDateConverter"></bean>
        </array>
    </property>
</bean>

文件上传下载

文件上传

springMVC将File文件封装成MultipartFile,通过配置multipartResolver解析器进行处理;其中multipartResolver解析器名称不能改变。

1、在springmvc.xml配置文件中配置文件上传解析器

<!--配置文件上传解析器,id名称固定为:multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="UTF-8"></property>
    <property name="maxUploadSize" value="88888888"></property>
</bean>

2、html页面代码

<form action="/testUpload" method="post" enctype="multipart/form-data">
    文件:<input type="file" name="uploadFile">
    描述:<input type="text" name="desc">
    <input type="submit" value="上传">
</form>

3、Controller控制器代码

@RequestMapping("/testUpload")
public String testUpload(MultipartFile uploadFile,String desc,HttpSession session) throws IOException {
    System.out.println(desc);
    //获取文件名称
    String originalFilename = uploadFile.getOriginalFilename();
    //获取保存文件目录路径
    String realPath = session.getServletContext().getRealPath("/upload");
    System.out.println(realPath);
    File file = new File(realPath);
    //如文件目录不存在,则创建文件目录
    if (!file.exists()){
        file.mkdir();
    }
    //文件绝对路径
    realPath = realPath + File.separator + originalFilename;
    File file2 = new File(realPath);
    //上传文件
    uploadFile.transferTo(file2);
    return "success";
}

MultipartFile 为固定写法,如上传多个文件时,可写成MultipartFile[]

uploadFile 文件名要与html 中的文件名一致。如上传多个文件,文件名都要保持一致。

文件下载

<a href="/testDown">testDown</a>
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testDown(HttpSession session) throws IOException {
    //获取下载文件的路径
    String realPath = session.getServletContext().getRealPath("/upload")+File.separator+"5de76a75b246a.jpg";
    InputStream in = new FileInputStream(realPath);
    //available():获取输入流所读取的文件的最大字节数
    byte[] b = new byte[in.available()];
    in.read(b);
    //设置请求头
    HttpHeaders headers = new HttpHeaders();
    //attachment:表示浏览器以附件的形式下载文件
    headers.add("Content-Disposition","attachment;filename=zzz.jpg");
    //设置相应状态
    HttpStatus statusCode = HttpStatus.OK;
    ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(b,headers,statusCode);
    return entity;
}

注意:attachment:表示浏览器以附件的形式下载文件;

拦截器

Spring MVC 可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现 HandlerInterceptor 接口,也可以继承HandlerInterceptorAdapter 适配器类。

(1)、preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求request进行处理。如对请求拦截处理后还要调用其它的拦截器,或是业务处理器进行处理,返回true;如不需要调用其它的组件去处理请求,则返回false.

(2)、postHandle():这个方法在业务处理器处理完请求后,在DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。

(3)、afterCompletion():这个方法在DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

拦截器流程图:

image-20201123154915700

实例:

1、编写自定义拦截器

/**
 * 自定义拦截器
 */
public class CustomInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("我是自定义拦截器的preHandle方法!!!");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法执行了!!!");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion..............");
    }
}

2、在springmvc配置文件中配置拦截器

<!-- 配置拦截器 -->
<mvc:interceptors>
    <!--默认拦截所有 -->
    <bean id="customInterceptor" class="com.test.utils.CustomInterceptor"></bean>
</mvc:interceptors>

3、测试拦截器

@RequestMapping("/testInterceptor")
public String testInterceptor(){
    System.out.println("测试拦截器!!");
    return "success";
}

测试结果

我是自定义拦截器的preHandle方法!!!
测试拦截器!!
postHandle方法执行了!!!
afterCompletion..............

实例二:配置多个拦截器

//第二个拦截器
public class SecondInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("SecondpreHandle...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SecondpostHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SecondafterCompletion...s");
    }
}

在springmvc.xml配置文件中配置

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!--需要拦截的请求-->
        <mvc:mapping path="/**"/>
        <!--不需要拦截的请求-->
        <mvc:exclude-mapping path="/method"/>
        <!--默认拦截所有 -->
        <bean id="customInterceptor" class="com.test.utils.CustomInterceptor"></bean>
    </mvc:interceptor>

    <mvc:interceptor>
        <!--需要拦截的请求-->
        <mvc:mapping path="/**"/>
        <!--不需要拦截的请求-->
        <mvc:exclude-mapping path="/hello"/>
        <!--默认拦截所有 -->
        <bean id="secondInterceptor" class="com.test.utils.SecondInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

执行结果

我是自定义拦截器的preHandle方法!!!  -->第一个拦截器的preHandler
SecondpreHandle...    -->第二个拦截器的preHandler
测试拦截器!!    --> 业务处理器方法
SecondpostHandle...   -->第二个拦截器的postHandler
postHandle方法执行了!!!          -->第一个拦截器的postHandler
SecondafterCompletion... -->第二个拦截器的afterCompletion
afterCompletion..............  -->第一个拦截器的afterCompletion

异常处理

​ 在项目开发中各层中都会不可避免的遇到各种可预知和不可预知的异常需要处理,为只专注业务逻辑的实现,需要将异常信息进行统一管理维护处理。

​ springmvc就是将异常层层向外抛出,最后由springmvc的前端控制器调用异常处理组件HandlerExceptionResolver(处理器异常解析器)进行处理。

实例:

/**
 * 自定义异常类
 */
public class MyException extends Exception {
    //异常信息
    private String message;

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

    public MyException(){};

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
/**
 * 自定义异常处理器
 */
public class CustomExceptionHandler implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        //定义异常信息
        String msg;
        //判断异常类型
        if(e instanceof MyException){
            //如果是自定义异常,读取异常信息
            msg = e.getMessage();
        }else{
            //如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
            Writer writer = new StringWriter();
            PrintWriter s = new PrintWriter(writer);
            e.printStackTrace(s);
            msg = "运行时异常,请联系管理员!";
        }
        //返回错误页面,给用户友好页面显示错误信息
        ModelAndView mav = new ModelAndView();
        mav.addObject("msg",msg);
        mav.setViewName("error");
        return mav;
    }
}

在springmvc中配置异常处理器

<!--配置异常处理器-->
<bean class="com.test.utils.CustomExceptionHandler"></bean>

SpringMVC的常用配置

1、web.xml文件配置

<servlet>
  		<!-- 配置springMVC核心控制器 -->
    	<!--作用:加载springmvc的配置文件,在下方的配置方式下,DispatcherServlet自动加载配置文件,此时的配置文件有默认的位置和名称。
		默认位置:WEB-INF下,默认名称<servlet-name>-servlet.xml,例如以下配置方式的文件名:dispatcherServlet-servlet.xml-->
  		<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启动时加载对象 取值只能是非 0 正整数,表示启动顺序 -->
  		<load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  		<servlet-name>dispatcherServlet</servlet-name>
  		<!-- /与/*的区别:/*:拦截所有请求,包括静态资源,jsp等
  		                 /:  拦截请求,不拦截jsp等页面请求 -->
  		<url-pattern>/</url-pattern>
  </servlet-mapping>
<!-- 配置springmvc编码过滤器,解决请求参数乱码问题 -->
  <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>
  	<!-- 启动过滤器 -->
  	<init-param>
  		<param-name>forceEncoding</param-name>
  		<param-value>true</param-value>
  	</init-param>
  </filter>
  <!-- 过滤所有请求 -->
  <filter-mapping>
  	<filter-name>characterEncodingFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!-- 配置HiddenHttpMethedFilter 用于REST风格编程:form表单只有:GET/POST,两种请求方式,该Filter可以将POST请求转换成PUT/DELETE请求 -->
  <filter>
  	<filter-name>HiddenHttpMethodFilter</filter-name>
  	<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>
  
  <filter-mapping>
  	<filter-name>HiddenHttpMethodFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>

2、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">
        
       <!-- 开启注解扫描,将加上@Controller注解的类作为springMVC的控制层 -->
       <context:component-scan base-package="com.test"></context:component-scan>
       
       
       <!-- 配置html视图解析器  -->
       <bean  class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
                <property name="templateLoaderPath">
                        <value>/WEB-INF/pages/</value>
                </property>
        </bean>
         <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
                <property name="contentType" value="text/html;charset=UTF-8"></property>
                <property name="suffix" value=".html" />
                <property name="order" value="0"/>
        </bean>
        
        <!-- 配置视图解析器 -->
       <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       		<!--前缀名  -->
       		<property name="prefix" value="/WEB-INF/pages/"></property>
       		<!-- 后缀名 -->
       		<property name="suffix" value=".jsp"></property>
       </bean>

       <!-- 开启springmvc框架注解的支持 -->
       <!-- 引用自定义类型转换器 -->
       <mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
       <!-- 将静态资源交给Tomcat中的Servlet处理 -->
       <mvc:default-servlet-handler/>
       
       <!-- 配置类型转换器工厂 -->
       <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
       		<!-- 给工厂注入一个新的类型转换器 -->
       		<property name="converters">
       			<array>
       				<!-- 配置自定义的类型转换器 -->
       				<bean class="com.test.convert.StringToDateConverter"></bean>
       			</array>
       		</property>
       </bean>
    
       
       <!-- 设置静态资源不过滤  1. location元素表示webapp目录下的包下的所有文件 2. mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b-->
       <mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
       
       <!-- 配置文件上传解析器 要求id名称必须是是multipartResolver  -->
       <bean  id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> 
       		<property name="maxUploadSize" value="10485760"></property>
       </bean>
       
       <!-- 配置拦截器 -->
       <mvc:interceptors>
       	<mvc:interceptor>
       		<mvc:mapping path="/**" />
       		<bean id="FirstInterceptor" class="com.test.interceptor.FirstInterceptor"></bean>
       	</mvc:interceptor>
       	
       	<mvc:interceptor>
       		<mvc:mapping path="/**"/>
       		<bean id="SecondInterceptor" class="com.test.interceptor.SecondInterceptor"> </bean>
       	</mvc:interceptor>
       		
       </mvc:interceptors>
       
       <!-- 配置自定义异常处理器 -->
       <bean id="testExceptionResolver" class="com.test.interceptor.testExceptionResolver"></bean>
</beans>

推荐阅读