likes
comments
collection
share

SpringMVC的视图解析

作者站长头像
站长
· 阅读数 12

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标签

  • 会自动注册RequestMappingHandlerMappingRequestMappingHandlerAdapterExceptionHandlerExceptionResolver 三个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,但是声明的异常有RuntimeExceptionException,此时会根据异常的最近继承关系找到继承深度最浅的那个,也即标记了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注解,可以在发生异常时定制错误页面,效果:

SpringMVC的视图解析

  • 新建一个类,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";
}