使用Spring Boot创建Spring MVC项目,访问url请求出现问题:Circular view
path

姓名:祝双     学号:16040520067 

IDEA建立Spring MVC Hello World 详细入门教程,springmvc

引子,其实从.NET转Java已经有几个月时间了,项目也做了不少,但是很多配置都是根据公司模板或者网上教程比忽略画瓢,对其中最简单的配置和设置并不完全理解,依旧是小白用户。最近项目不忙,重新梳理了一下Spring
MVC的相关配置,顺便保存下来,希望也能帮到其他同学……高手忽略~~~

 

目录

  • 通过IDEA新建Spring MVC项目
  • 设置运行、调试相关配置
  • 导入Spring MVC 相关类库
  • 添加 Controller
  • 修改 url-pattern(web.xml)
  • 配置 component-scan(dispatcher-servlet.xml)
  • 配置 ViewResolver(dispatcher-servlet.xml)
  • 添加视图文件(.jsp)
  • 通过 Model 向 View 传值

 

通过IDEA新建Spring MVC项目

先创建项目,从封面或者主窗体都可以创建

必发娱乐官方网站 1

必发娱乐官方网站 2

 “New Project”窗口,选择附加的类库”Spring MVC”

 必发娱乐官方网站 3

选择项目名称和存放的位置

必发娱乐官方网站 4

 最后点击Finish按钮,IDEA会帮你下载需要的类库

必发娱乐官方网站 5

 创建完成后项目有这些文件,主要是三个xml文件+一个index.jsp

这个jsp文件最后肯定是不要的,不过也先不要慌着删

 必发娱乐官方网站 6

 

设置运行、调试相关配置

 项目建好后,并不能直接运行,Run和Debug菜单都是灰色不能点击的

要需要做一下运行和调试的相关配置

作为.NET转Java的码农,有时候真的很怀念宇宙第一IDE:Visual
Studio,根据模板创建的项目很少有不能直接运行的,算了,不说也罢,继续配置。。。

必发娱乐官方网站 7必发娱乐官方网站 8

必发娱乐官方网站 9

先设置“Server”选项卡

 必发娱乐官方网站 10

点开“Deployment”选项卡,继续设置,

创建Artifact,最后记得点OK保存

 必发娱乐官方网站 11

现在,Run菜单下出现了Run
‘mvc-helloworld’的菜单项目(Shift+F10运行,Shift+F9调试)

工具栏上也有了运行和调试按钮,你可以选择自己喜欢的方式运行项目

必发娱乐官方网站 12必发娱乐官方网站 13

虽然我们还没开始写代码,但是毕竟IDEA帮我们生成了一个jsp文件,可以用这个文件看看站点能否打开(index.jsp代码如下)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  $END$
  </body>
</html>

浏览器输入地址 

必发娱乐官方网站 14

项目是运行不起来的(其实离运行起来,还缺不少配置,继续往后看),

啥情况?当然要看日志。。。点开下面的“Tomcat Localhost
Log”,可以看到问题出在哪里。。。

 必发娱乐官方网站 15

java.lang.ClassNotFoundException:
org.springframework.web.context.ContextLoaderListener

意思就是找不到ContextLoaderListener这个类

导入Spring MVC相关类库

 Java中,ClassNotFoundException好像是个挺常见的异常,先检查相应的jar包有没有包含进来…

打开Project Structure,跟项目相关配置基本都在个菜单里边。。。

 必发娱乐官方网站 16

点开”Artifacts”选项卡后,上面有多出很明显的提示,缺失Spring
MVC相关类库的引用

尽管IDEA搞这么多提醒,为啥我感觉还是不够醒目?

 必发娱乐官方网站 17

 按照下面的几个方法修复错误,随便选一种就行

让程序部署的时候,把Spring MVC相关类库复制到lib文件夹中

 必发娱乐官方网站 18

重新运行一次项目(Shift+F10运行,Shift+F9调试)……

如果你上次没有Stop,这次运行可能会弹出这个对话框,选择“Restart
server”然后”OK”吧…

必发娱乐官方网站 19

再一次访问 

这次终于可以看见点内容了,起码说明服务启动了。。

 必发娱乐官方网站 20

如果再看刚才的日志,原来报错也没有了

 

添加Controller

站点可以打开了,不过我们这个不是MVC,因为没有M、没有V也没有C

我们就从MVC中的C(Controller)开始,继续配置

在新建Controller之前,首先要建一个包,SpringMVC是没法运行在默认包下的,按照如下方式建包,

我建的包名称为:wormday.springmvc.helloworld

其实包名随意,但是必须要有。。。

必发娱乐官方网站 21

 

 必发娱乐官方网站 22

必发娱乐官方网站 23

 再这个包下新建Java Class文件 HiController

 必发娱乐官方网站 24

代码如下

package wormday.springmvc.helloworld;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/hi")
public class HiController {

    @RequestMapping("/say")
    public String say() {
        return "/WEB-INF/jsp/say.jsp";
    }
}

如果你跟我一样又迫不及待的要访问一下这个Controller的Action 地址应该是:

   
其实这个时候访问结果是404,因为后边还有不少配置没有做…

 必发娱乐官方网站 25

 

类上的注解@RequestMapping(“/hi”)指定 Url路径前边一部分

方法上的注解@RequestMapping(“/say”)指定 Url路径最后一部分

也可以只把注解写在方法上,比如@RequestMapping(“/hi/say”)

那个结尾的form是什么鬼,就接着看下一段 url-pattern…

修改 url-pattern(web.xml)

先打开web\WEB-INF\web.xml文件

有关于ServletMapping的设置,通过这个设置,可以配置那些类型的url用那些servlet来处理

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.form</url-pattern>
    </servlet-mapping>

结合这一段xml,我们可以看到,IDEA默认帮我配置了一个名字叫做dispatcher的Servlet

这个Servlet使用org.springframework.web.servlet.DispatcherServlet这个类来处理

这个Servlet对应的Url是*.form

如果你跟我一样不喜欢每个MVC Url后边都带一个form,可以改成斜杠

<url-pattern>/</url-pattern>

如果你现在重新启动程序,然后继续访问

发现,依旧404,并且伴随每次访问,都在Server的Output窗口有一个错误日志

org.springframework.web.servlet.PageNotFound.noHandlerFound No mapping
found for HTTP request with URI [/hi/say] in DispatcherServlet with
name ‘dispatcher’

必发娱乐官方网站 26

意思就是没有找到相应的Controller,不但要把Controller的代码写好,还要告诉Spring(在这里其实是dispatcher
servlet)去哪里找这些Controller。。。

作为验证,你可以在Controller里边加一个断点,然后刷新页面,程序根本就没有执行到Controller里边

必发娱乐官方网站 27

所以现在轮到修改另外一个配置文件了,dispatcher-servlet.xml

 

配置 component-scan(dispatcher-servlet.xml)

 component-scan就是告诉Servlet去哪里找到相应的Controller

打开 dispatcher-servlet.xml

在已经存在的<beans></beans>中间加上

<context:component-scan base-package="wormday.springmvc.helloworld"/>

base-package指定的就是存放Controller的包

 做完这一步之后,重新启动项目,再次访问  

这次应该还是404错误,不过比刚才的404错误前进了一大步

毕竟这次Controller已经执行了,如果刚才的断点没有去掉,你可以验证一下看看

这一回是因为是“/WEB-INF/jsp/say.jsp”这个View找不到(我们刚才确实只是告诉他这个位置,但是从来没有创建过这个文件)

再强调一次,Spring
Mvc如果找不到Controller或者View都会报404错误,具体找不到的是谁,要具体分析了,好在一般都能简单的分辨出来。

必发娱乐官方网站 28

这个地方有个问题要额外说明一下,一般来说Controller代码的返回值是成字符串“say”就可以了,不需要.jsp,也不需要前边的路径,比如

必发娱乐官方网站 29

但是如果现在这样写,会报一个很奇怪的500错误,而不是404
必发娱乐官方网站 30

1、问题描述

文章转载自

HTTP Status 500 – Circular view path [say]: would dispatch back to the current handler URL [/hi/say] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

 原因是:

但是目前必须制定View的绝对路径,因为我们还没有配置 配置
ViewResolver,后边会专门说到这个问题 

 

添加视图文件(.jsp)

 

 这个没啥好解释的,刚才你让Spring去哪里找这个View,就把这个View创建在哪里

如果找不到,他就简单粗暴的报404错误,根据前边我写的代码,创建位置应该入下图。

必发娱乐官方网站 31

其实Spring并不限制你必须创建在WEB-INF下,但是这样更安全,因为WEB-INF目录用户是不能直接访问的,毕竟View里边可能会有一些代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>hello world</body>
</html>

再次访问 

终于不再报错了,看起来Controller也把相应的视图找到了

必发娱乐官方网站 32

  

配置 ViewResolver(dispatcher-servlet.xml)

还记得刚才Controller返回值必须是View的绝对路径这个事情么?一般情况下,我们是不会这样写的

网上的教程大部分也仅仅返回View的名字,比如

 必发娱乐官方网站 33

原因是一般都会在dispatcher-servlet.xml上指定如下的代码。

    <!--指定视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 视图的路径 -->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!-- 视图名称后缀  -->
        <property name="suffix" value=".jsp"/>
    </bean>

 class
指定ViewResolver的实现的类,你可以根据不同的情况,使用不用的ViewResolver,这里指定的是 org.springframework.web.servlet.view.InternalResourceViewResolver

刚才我没有指定,默认的也是这个类

后边的前缀和后缀比较简单,看看就明白了

记得改完xml之后,同步修改Controller的返回值。。不然又要404了

通过 Model 向 View 传值

通过上面的操作,已经完成了MVC中的(V和C),M还没见影子,让我们继续修改

打开刚才定义的Controller 也就是 HiController.java文件

修改如下(修改点我已经高亮了)

package wormday.springmvc.helloworld;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; // 这里导入了一个Model类
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/hi")
public class HiController {

    @RequestMapping("/say")
    public String say(Model model) { // 参数中传入Model
        model.addAttribute("name","wormday"); // 指定Model的值
        model.addAttribute("url","http://www.cnblogs.com/wormday/p/8435617.html"); // 指定Model的值
        return "say";
    }
}

然后再打开View,也就是say.jsp文件,修改如下

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
hello world,${name}
<br/>${url}</body>
</html>

两个之间的关系就不解释了,然后重新运行项目,刷新页面

必发娱乐官方网站 34

一个最简单的MVC项目完成了!!!

 

MVC Hello World
详细入门教程,springmvc
引子,其实从.NET转Java已经有几个月时间了,项目也做了不少,但是很多配置都是根据公司…

控制台打印:

原文出处:chanjarster

javax.servlet.ServletException: Circular view path [greeting]: would
dispatch back to the current handler URL [/greeting] again. Check your
ViewResolver setup! (Hint: This may be the result of an unspecified
view, due to default view name generation.)

【嵌牛导读】:可以让你学会如何处理这种情况

必发娱乐官方网站 35

【嵌牛鼻子】:java

浏览器访问:

【嵌牛提问】:这些处理方法哪种效率最高

必发娱乐官方网站 36

【嵌牛正文】:

2、项目代码

默认行为

(1)Spring MVC的controller

根据Spring Boot官方文档的说法:

 1 package com.hello.web;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.ui.Model;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RequestParam;
 7 
 8 @Controller
 9 public class GreetingController {
10     @RequestMapping("/greeting")
11     public String greeting(@RequestParam(value="name",required=false,defaultValue="World")String name, Model model) {
12         model.addAttribute("name", name);
13         return "greeting";
14     }
15 }

For machine clients it will produce a JSON response with details of the
error, the HTTP status and the exception message. For browser clients
there is a ‘whitelabel’ error view that renders the same data in HTML
format

 

也就是说,当发生异常时:

(2)页面代码

如果请求是从浏览器发送出来的,那么返回一个Whitelabel Error Page

使用 thymeleaf模板框架,负责服务端渲染html页面

如果请求是从machine客户端发送出来的,那么会返回相同信息的json

 1 <!DOCTYPE html>
 2 <html xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4 <title>Spring Boot thymeleaf 应用</title>
 5 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 6 </head>
 7 <body>
 8     <p th:text="'hello, '+${name}+'!'" />
 9 </body>
10 </html>

你可以在浏览器中依次访问以下地址:

3、解决方法

在 项目的 pom.xml中添加 thymeleaf 的 spring boot starter

1 <dependency>
2     <groupId>org.springframework.boot</groupId>
3     <artifactId>spring-boot-starter-thymeleaf</artifactId>
4 </dependency>

4、问题解决

再次通过浏览器地址栏,访问:

必发娱乐官方网站 37

Donate捐赠

如果我的文章帮助了你,可以赞赏我 1 元,让我继续写出更好的内容)

必发娱乐官方网站 38   必发娱乐官方网站 39

  (微信)                                        (支付宝)

微信/支付宝 扫一扫

 

会发现FooController和FooRestController返回的结果都是一个Whitelabel Error
Page也就是html。

但是如果你使用curl访问上述地址,那么返回的都是如下的json:

1

2

3

4

5

6

7

8

9

{

“timestamp”:1498886969426,

“status”:500,

“error”:”Internal Server Error”,

“exception”:”me.chanjar.exception.SomeException”,

“message”:”…”,

“trace”:”…”,

“path”:”…”

}

但是有一个URL除外:

本章节代码在me.chanjar.boot.def,使用DefaultExample运行。

注意:我们必须在application.properties添加server.error.include-stacktrace=always才能够得到stacktrace。

为何curl text/plain资源无法获得error

如果你在logback-spring.xml里一样配置了这么一段:

1

那么你就能在日志文件里发现这么一个异常:

1

2

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not
find acceptable representation

要理解这个异常是怎么来的,那我们来简单分析以下Spring MVC的处理过程:

curl :
*/*,会匹配到FooController.returnTextPlain(produces=text/plain)方法,注意:如果请求头不是Accept:
*/*或Accept:
text/plain,那么是匹配不到FooController.returnTextPlain的。

RequestMappingHandlerMapping根据url匹配到了(见AbstractHandlerMethodMapping.lookupHandlerMethod#L341)FooController.returnTextPlan(produces=text/plain)。

方法抛出了异常,forward到/error。

RequestMappingHandlerMapping根据url匹配到了(见AbstractHandlerMethodMapping.lookupHandlerMethod#L341)BasicErrorController的两个方法errorHtml(produces=text/html)和error(produces=null,相当于produces=*/*)。

因为请求头Accept:
*/*,所以会匹配error方法上(见AbstractHandlerMethodMapping#L352,RequestMappingInfo.compareTo,ProducesRequestCondition.compareTo)。

error方法返回的是ResponseEntity>,会被HttpEntityMethodProcessor.handleReturnValue处理。

HttpEntityMethodProcessor进入AbstractMessageConverterMethodProcessor.writeWithMessageConverters,发现请求要求*/*(Accept:
*/*),而能够产生text/plain(FooController.returnTextPlan
produces=text/plain),那它会去找能够将Map转换成String的HttpMessageConverter(text/plain代表String),结果是找不到。

AbstractMessageConverterMethodProcessor抛出HttpMediaTypeNotAcceptableException。

那么为什么浏览器访问

那么这个问题怎么解决呢?我会在自定义ErrorController里说明。

自定义Error页面

前面看到了,Spring Boot针对浏览器发起的请求的error页面是Whitelabel Error
Page,下面讲解如何自定义error页面。

注意2:自定义Error页面不会影响machine客户端的输出结果

方法1

根据Spring Boot官方文档,如果想要定制这个页面只需要:

to customize it just add a View that resolves to ‘error’

这句话讲的不是很明白,其实只要看ErrorMvcAutoConfiguration.WhitelabelErrorViewConfiguration的代码就知道,只需注册一个名字叫做error的View类型的Bean就行了。

本例的CustomDefaultErrorViewConfiguration注册将error页面改到了templates/custom-error-page/error.html上。

本章节代码在me.chanjar.boot.customdefaulterrorview,使用CustomDefaultErrorViewExample运行。

方法2

方法2比方法1简单很多,在Spring官方文档中没有说明。其实只需要提供error
View所对应的页面文件即可。

比如在本例里,因为使用的是Thymeleaf模板引擎,所以在classpath
/templates放一个自定义的error.html就能够自定义error页面了。

本章节就不提供代码了,有兴趣的你可以自己尝试。

自定义Error属性

前面看到了不论error页面还是error
json,能够得到的属性就只有:timestamp、status、error、exception、message、trace、path。

如果你想自定义这些属性,可以如Spring Boot官方文档所说的:

simply add a bean of type ErrorAttributes to use the existing mechanism
but replace the contents

在ErrorMvcAutoConfiguration.errorAttributes提供了DefaultErrorAttributes,我们也可以参照这个提供一个自己的CustomErrorAttributes覆盖掉它。

如果使用curl访问相关地址可以看到,返回的json里的出了修改过的属性,还有添加的属性:

1

2

3

4

5

6

7

8

9

10

{

“exception”:”customized exception”,

“add-attribute”:”add-attribute”,

“path”:”customized path”,

“trace”:”customized trace”,

“error”:”customized error”,

“message”:”customized message”,

“timestamp”:1498892609326,

“status”:100

}

本章节代码在me.chanjar.boot.customerrorattributes,使用CustomErrorAttributesExample运行。

自定义ErrorController

在前面提到了curl

请求的时候指定Accept头,避免匹配到BasicErrorController.error方法。比如:curl
-H ‘Accept: text/plain’

提供自定义的ErrorController。

下面将如何提供自定义的ErrorController。按照Spring Boot官方文档的说法:

To do that just extend BasicErrorController and add a public method with
a @RequestMapping that has a produces attribute, and create a bean of
your new type.

所以我们提供了一个CustomErrorController,并且通过CustomErrorControllerConfiguration将其注册为Bean。

本章节代码在me.chanjar.boot.customerrorcontroller,使用CustomErrorControllerExample运行。

ControllerAdvice定制特定异常返回结果

根据Spring
Boot官方文档的例子,可以使用@ControllerAdvice和@ExceptionHandler对特定异常返回特定的结果。

我们在这里定义了一个新的异常:AnotherException,然后在BarControllerAdvice中对SomeException和AnotherException定义了不同的@ExceptionHandler:

SomeException都返回到controlleradvice/some-ex-error.html上

AnotherException统统返回JSON

在BarController中,所有*-a都抛出SomeException,所有*-b都抛出AnotherException。下面是用浏览器和curl访问的结果:

urlBrowsercurl

http://localhost:8080/bar/html-asome-ex-error.htmlsome-ex-error.html

http://localhost:8080/bar/html-bNo
converter found for return value of type: class
AnotherExceptionErrorMessageAbstractMessageConverterMethodProcessor#L187error(json)

http://localhost:8080/bar/json-asome-ex-error.htmlsome-ex-error.html

http://localhost:8080/bar/json-bCould
not find acceptable representationerror(json)

http://localhost:8080/bar/text-plain-asome-ex-error.htmlsome-ex-error.html

http://localhost:8080/bar/text-plain-bCould
not find acceptable representationCould not find acceptable
representation

注意上方表格的Could not find acceptable
representation错误,产生这个的原因和之前为何curl
text/plain资源无法获得error是一样的:无法将@ExceptionHandler返回的数据转换@RequestMapping.produces所要求的格式。

所以你会发现如果使用@ExceptionHandler,那就得自己根据请求头Accept的不同而输出不同的结果了,办法就是定义一个void
@ExceptionHandler,具体见@ExceptionHandler javadoc。

定制不同Status Code的错误页面

Spring Boot 官方文档提供了一种简单的根据不同Status
Code跳到不同error页面的方法,见这里。

我们可以将不同的Status Code的页面放在classpath: public/error或classpath:
templates/error目录下,比如400.html、5xx.html、400.ftl、5xx.ftl。

打开浏览器访问以下url会获得不同的结果:

urlResult

http://localhost:8080/loo/error-403static
resource: public/error/403.html

http://localhost:8080/loo/error-406thymeleaf
view: templates/error/406.html

http://localhost:8080/loo/error-600Whitelabel
error page

http://localhost:8080/loo/error-601thymeleaf
view: templates/error/6xx.html

注意/loo/error-600返回的是Whitelabel error
page,但是/loo/error-403和loo/error-406能够返回我们期望的错误页面,这是为什么?先来看看代码。

在loo/error-403中,我们抛出了异常Exception403:

1

2

@ResponseStatus(HttpStatus.FORBIDDEN)

publicclassException403extendsRuntimeException

在loo/error-406中,我们抛出了异常Exception406:

1

2

@ResponseStatus(NOT_ACCEPTABLE)

publicclassException406extendsRuntimeException

注意到这两个异常都有@ResponseStatus注解,这个是注解标明了这个异常所对应的Status
Code。
但是在loo/error-600中抛出的SomeException没有这个注解,而是尝试在Response.setStatus(600)来达到目的,但结果是失败的,这是为什么呢?:

1

2

3

4

5

6

@RequestMapping(“/error-600”)

publicString error600(HttpServletRequest request, HttpServletResponse
response)throwsSomeException {

request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE,600);

response.setStatus(600);

thrownewSomeException();

}

要了解为什么就需要知道Spring MVC对于异常的处理机制,下面简单讲解一下:

Spring
MVC处理异常的地方在DispatcherServlet.processHandlerException,这个方法会利用HandlerExceptionResolver来看异常应该返回什么ModelAndView。

目前已知的HandlerExceptionResolver有这么几个:

DefaultErrorAttributes,只负责把异常记录在Request
attributes中,name是org.springframework.boot.autoconfigure.web.DefaultErrorAttributes.ERROR

ExceptionHandlerExceptionResolver,根据@ExceptionHandler resolve

ResponseStatusExceptionResolver,根据@ResponseStatus resolve

DefaultHandlerExceptionResolver,负责处理Spring MVC标准异常

Exception403和Exception406都有被ResponseStatusExceptionResolver处理了,而SomeException没有任何Handler处理,这样DispatcherServlet就会将这个异常往上抛至到容器处理(见DispatcherServlet#L1243),以Tomcat为例,它在StandardHostValve#L317、StandardHostValve#L345会将Status
Code设置成500,然后跳转到/error,结果就是BasicErrorController处理时就看到Status
Code=500,然后按照500去找error page找不到,就只能返回White error
page了。

实际上,从Request的attributes角度来看,交给BasicErrorController处理时,和容器自己处理时,有几个相关属性的内部情况时这样的:

Attribute nameWhen throw up to TomcatHandled by HandlerExceptionResolver

DefaultErrorAttributes.ERRORHas valueHas Value

DispatcherServlet.EXCEPTIONNo valueHas Value

javax.servlet.error.exceptionHas valueNo Value

PS. DefaultErrorAttributes.ERROR =
org.springframework.boot.autoconfigure.web.DefaultErrorAttributes.ERROR

PS. DispatcherServlet.EXCEPTION =
org.springframework.web.servlet.DispatcherServlet.EXCEPTION

解决办法有两个:

1.给SomeException添加@ResponseStatus,但是这个方法有两个局限:

如果这个异常不是你能修改的,比如在第三方的Jar包里

如果@ResponseStatus使用HttpStatus作为参数,但是这个枚举定义的Status
Code数量有限

  1. 使用@ExceptionHandler,不过得注意自己决定view以及status code

第二种解决办法的例子loo/error-601,对应的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

@RequestMapping(“/error-601”)

publicString error601(HttpServletRequest request, HttpServletResponse
response)throwsAnotherException {

thrownewAnotherException();

}

@ExceptionHandler(AnotherException.class)

String handleAnotherException(HttpServletRequest request,
HttpServletResponse response, Model model)

throwsIOException {

// 需要设置Status Code,否则响应结果会是200

response.setStatus(601);

model.addAllAttributes(errorAttributes.getErrorAttributes(newServletRequestAttributes(request),true));

return”error/6xx”;

}

总结:

1.
没有被HandlerExceptionResolverresolve到的异常会交给容器处理。已知的实现有(按照顺序):

DefaultErrorAttributes,只负责把异常记录在Request
attributes中,name是org.springframework.boot.autoconfigure.web.DefaultErrorAttributes.ERROR

ExceptionHandlerExceptionResolver,根据@ExceptionHandler resolve

ResponseStatusExceptionResolver,根据@ResponseStatus resolve

DefaultHandlerExceptionResolver,负责处理Spring MVC标准异常

  1. @ResponseStatus用来规定异常对应的Status Code,其他异常的Status
    Code由容器决定,在Tomcat里都认定为500(StandardHostValve#L317、StandardHostValve#L345)

3.
@ExceptionHandler处理的异常不会经过BasicErrorController,需要自己决定如何返回页面,并且设置Status
Code(如果不设置就是200)

  1. BasicErrorController会尝试根据Status Code找error
    page,找不到的话就用Whitelabel error page

本章节代码在me.chanjar.boot.customstatuserrorpage,使用CustomStatusErrorPageExample运行。

利用ErrorViewResolver来定制错误页面

前面讲到BasicErrorController会根据Status
Code来跳转对应的error页面,其实这个工作是由DefaultErrorViewResolver完成的。

实际上我们也可以提供自己的ErrorViewResolver来定制特定异常的error页面。

1

2

3

4

5

6

7

8

9

@Component

publicclassSomeExceptionErrorViewResolverimplementsErrorViewResolver {

@Override

publicModelAndView resolveErrorView(HttpServletRequest request,
HttpStatus status, Map model) {

returnnewModelAndView(“custom-error-view-resolver/some-ex-error”,
model);

}

}

不过需要注意的是,无法通过ErrorViewResolver设定Status Code,Status
Code由@ResponseStatus或者容器决定(Tomcat里一律是500)。

本章节代码在me.chanjar.boot.customerrorviewresolver,使用CustomErrorViewResolverExample运行。

@ExceptionHandler 和 @ControllerAdvice

前面的例子中已经有了对@ControllerAdvice和@ExceptionHandler的使用,这里只是在做一些补充说明:

@ExceptionHandler配合@ControllerAdvice用时,能够应用到所有被@ControllerAdvice切到的Controller

@ExceptionHandler在Controller里的时候,就只会对那个Controller生效

Author

发表评论

电子邮件地址不会被公开。 必填项已用*标注