SpringMVC的视图解析
方法返回的字符串是如何解析成对应的视图?如何处理静态资源?以及如何优雅的返回错误信息呢?一起来讨论❤️
视图解析流程
InternalResourceViewResolver
视图解析器:处理视图请求转发- 请求处理方法执行完成后,最终返回一个
ModelAndView
对象。对于那些返回Stirng
,View
或者ModeMap
等类型的处理方法,SpringMVC
也会在内部将他们装配成一个ModelAndView
对象,他包含了逻辑名和模型对象的视图 SpringMVC
借助视图解析器(ViewResolver)
得到最终得视图对象(View),最终的视图可以是jsp,也可能是Excel等各种表现形式的视图- 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现MVC的充分解耦
视图
- 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给用户
- 为了实现视图模型和具体实现技术的解耦,Spring在
org.springframework.web.servlet
包中定义了一个高度抽象的View
接口 - 视图对象由视图解析器负责实例化。由于视图是
无状态
的所以他们不会有线程安全
的问题。也即每次请求都会创建一个新的视图对象
视图解析器
- SpringMVC为逻辑视图名的解析提供了不同的策略,可以在SpringWEB上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一种具体的视图解析器实现类
- 视图解析器的作用比较单一:将一个逻辑视图解析成具体的视图对象
- 所有的视图解析器都必须实现
ViewResolver
接口
处理静态资源
- 如果不配置
mvc:annotation-driven
标签,则在网址中直接输入succes页面可进入,通过handler返回success就会是404 - 所以在实际开发中要配置
<mvc:annotation-driven></<mvc:annotation-driven>
- 在配置
springMvc
的时候,会在web.xml
中配置DispatcherServlet
为/
,拦截所有请求(*.do就是拦截以.do结尾的请求)
,那么在jsp页面中请求静态资源比如js,jpg等时springMvc会进行拦截,所以会导致请求不到资源 - 然而优雅的rest风格url不希望带.do等的后缀所以需要配置一个
<mvc:default-servlet-handler/>
<mvc:default-servlet-handler/>
将在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler
,他会对进入DispatcherServlet
的请求进行筛查,如果发现是没有经过映射的请求,就将该请求交给WEB应用服务器默认的Servlet
处理,如果不是静态资源的请求,才有DispatcherServlet
继续处理- 一般WEB应用服务器默认的servlet名称都是default,若所使用的WEB服务器的默认servlet名字不是default,则需要通过
default-servlet-name
属性显示的指定
mvc:annotation-driven标签
- 会自动注册
RequestMappingHandlerMapping
、RequestMappingHandlerAdapter
、ExceptionHandlerExceptionResolver
三个bean,还提供一下支持- 支持使用
conversionService
实例对表单参数进行类型转换 - 支持使用
@NumberFormat
@DateTimeFormat
注解完成数据类型的格式化 - 支持使用
@Valid
注解对javaBean实例进行jsr303
验证 - 支持使用
@RequestBody
和@ResponseBody
注解
- 支持使用
- 可以加载自定义的类型转换器
<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"></mvc:annotation-driven>
<bean id="conversionServiceFactoryBean" class="org.springframework.context.supprot.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="studentConverter" />
</set>
</property>
</bean>
@Component
public class StudentConverter implementsConverter<String, Student>{
@Override
public Student convert(String source){
//转换
return new Student();
}
}
- 注意:
springmvc的ioc容器中的bean可以引用spring ioc容器中的bean,反过来不行
@RequestBody
注解:声明在参数左边,指定入参以json形式进行解析默认是使用jackson开源jar包进行解析,可以手动更改设置成fastjson:
<!-- 设置配置方案 -->
<mvc:annotation-driven>
<!-- 设置不使用默认的消息转换器 -->
<mvc:message-converters register-defaults="false">
<!-- 配置spring的转换器 -->
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter"></bean>
<!-- 配置fastjson中实现的HttpMessageConverter接口的转换器 -->
<bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 加入支持的媒体类型,返回contentType -->
<property name="supportedMediaTypes">
<list>
<!-- 这里顺序不能反,一定先写text/html,不然IE下会出现下载提示 -->
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
异常处理
- SpringMVC通过
HandlerExceptionResolver
处理程序的异常,包括Handler映射、数据绑定以及目标方法执行时发生的异常。 ExceptionHandlerExceptionResolver
主要处理Handler中用@ExceptionHandler
注解定义的方法@ExceptionHandler
注解定义的方法存在优先级问题:例如发生的是NullPointerException
,但是声明的异常有RuntimeException
和Exception
,此时会根据异常的最近继承关系找到继承深度最浅的那个,也即标记了RuntimeException
的方法ExceptionHandlerMethodResolver
内部如果找不到@ExceptionHandler
注解的话,会找@ControllerAdvice
中的@ExceptionHandler
注解方法
//这样在发生BusinessException(这是我自定义的异常)到页面中(传值到页面上)则需要返回值不是String了要是ModelAndView对象。
//注意:此方法只能处理当前handler发生的异常!!
@ExceptionHandler({BusinessException.class})
public String handlerBusinessException(Exception e){
System.out.println("异常: "+e);
return "error";
}
//如果需要处理所有handler中的异常,需要配置一个全局的异常处理
//声明一个类,并用 @EnableWebMvc
//@ControllerAdvice(basePackages="com.xxx")注解声明,在这个类里边放所有的异常处理,可以将异常处理的方法集中起来。
@EnableWebMvc
@ControllerAdvice(basePackages="com.xxx")
public class HandleException{
@ExceptionHandler({BusinessException.class})
public ModelAndView BusinessExceptionHandle(Exception e){
ModelAndView view = new ModelAndView("/error");
view.addObject("message",e);
return view;
}
}
ResponseStatus
注解,可以在发生异常时定制错误页面,效果:
- 新建一个类,
extend RuntimeException
并添加@ResponseStatus
注解就能在 抛出这个类的异常的时候 显示定制的页面
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="哈哈哈,丢了!")
public class NotFoundException extends RuntimeException{
}
//定义好异常之后,写一个handler,抛出这个异常,查看页面效果
@RequestMapping("/testException")
public String testException(int i){
if(i == 0){
throw new NotFoundException();
}
return "success";
}
转载自:https://juejin.cn/post/7246204866036154423