首页 > 编程语言 > 详细

视图渲染+Spring MVC进阶技术 -- 《Spring In Action》

时间:2020-09-07 21:11:05      阅读:88      评论:0      收藏:0      [点我收藏+]

视图解析

Spring MVC将控制器中请求处理的逻辑和视图中的渲染实现解耦(所编写的控制器方法没有直接产生浏览器中渲染所需要的HTML,这些方法只是将一些数据填充到模型中,然后将模型传递给用来渲染的视图)

视图解析能够将逻辑视图名转换为物理实现

视图解析器 描述
BeanNameViewResolver 将视图解析为Spring应用上下文的Bean,其中Bean的ID与视图的名字相同
ContentNegotiatingViewResolver 根据客户端需要的内容类型来解析视图,委托给另一个能够产生对应内容类型的视图解析器
FreeMarkerViewResolver 将视图解析为FreeMarker模板
InternalResourceViewResolver 将视图解析为Web应用的内部资源(eg: JSP)
JasperReportsViewResolver 将视图解析为JasperReports定义
ResourceBundleViewResolver 将视图解析为资源bundle(一般为属性文件)
UrlBasedViewResolver 直接根据视图的名称解析视图,视图的名称会匹配一个物理视图的定义
XmlViewResolver 将视图解析为特定XML文件中的Bean定义,类似于BeanNameViewResolver
XsltViewResolver 将视图解析为XSLT转换后的结果

配置适用于JSP的视图解析器

InternalResourceViewResolver所采取的的方式是在视图名上添加前缀和后缀,进而确定一个Web应用中视图资源的物理路径。

例如:
视图名:home
通用实践将JSP文件放入Web应用的WEB-INF目录以防止对其直接访问。
技术分享图片

配置InternalResourceView Resolver

使用Java类配置

@Bean
public ViewResolver viewResovler(){
	InternalResourceViewResolver resolver = new InternalResourceViewResolver();
	resolver.setPrefix("/WEB-INF/views/");
	resolver.setSuffix(".jsp");
	return resolver;
}

使用XML配置

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/views/"
p:suffix=".jsp"/>

通过配置将逻辑视图名解析为JSP文件物理地址
例如:
* home解析为/WEB-INF/views/home.jsp
* productList解析为/WEB-INF/views/productList.jsp
* books/detail解析为/WEB-INF/views/books/detail.jsp

Spring MVC进阶技术

处理异常

当处理请求的时候,抛出异常该如何处理?如果发生了这样情况该如何给出客户端响应?
无论是否异常,Servlet请求的输出都是一个Servlet响应,如果在请求处理的时候出现异常,输出依然会是Servlet响应。异常必须以某种方式转换为响应

Spring提供多种方式将异常转换为响应:

  • 特定的Spring异常会自动映射为指定的HTTP状态码;
  • 异常上添加@ResponseStatus,将其映射为某一个HTTP状态码;
  • 在方法上添加@ExceptionHandler注解,使其用来处理异常;
    处理异常的最简单方式:将其映射到HTTP状态码上,进而放到响应之中。

将异常映射为HTTP状态码

默认情况下,Spring会将自身的异常自动转换为合适的状态码

Spring异常 HTTP状态码
BindException 400 - Bad Request
ConversionNotSupportedException 500 - Internal Server Error
HttpMediaTypeNotAcceptableException 406 - Not Acceptable
HttpMediaTypeNotSupportedException 415 - Unsupported Media Type
HttpMessageNotReadableException 400 - Bad Request
HttpMessageNotWritableException 500 - Internal Server Error
HttpRequestMethodNotSupportedException 405 - Method Not Allowed
MethodArgumentNotValidException 400 - Bad Request
MissingServletRequestParameterException 400 - Bad Request
MissingServletRequestPartException 400 - Bad Request
NoSuchRequestHandlingMethodException 404 - Not Found
TypeMismatchException 400 - Bad Request

异常一般为Spring自身抛出,作为DispatcherServlet处理过程中或执行校验时出现问题的结果。
Spring可以通过@ResponseStatus注解将异常映射为HTTP 状态码

  • 使用@ResponseStatus注解: 将异常映射为特定的状态码
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found") // 将异常状态映射为404
public class SpittleNotFoundException extends RuntimeException{
}

引入@ResposneStatus注解之后,如果控制器方法抛出SpittleNotFoundException异常的话,响应将会具有404状态码

  • 抛出SpittleNotFoundException将异常映射为特定的状态码
@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
public String spittle(@PathVariable("spittleId") long spittleId, Model model){
      Spittle spittle = spittleRepository.findOne(spittleId);
      if(spittle == null){
            throw new SpittleNotFoundException();
      }
      model.addAttribute(spittle);
      return "spittle";
}

编写异常处理方法

之前通过异常映射为状态码但如果需要将响应中不仅要包含状态码还要有所产生的错误,则就不同将异常视为HTTP错误需要按照处理请求的方式来处理异常

  • 传统的在处理请求的方法中直接处理异常
@RequestMapping(method=RequestMethod.POST)
public String saveSpittle(SpittleForm form, Model model){
	try{
		spittleRepository.save(new Spittle(null, form.getMessage(), new Date(), form.getLongitude(), form.getLatitude()));
		return "redirect:/spittles";
	}catch(DuplicateSpittleException e){
		return "error/duplicate";
	}
}
  • 异常处理方法
@ExceptionHandler(DuplicateSpittleException.class)
public String handleDuplicateSpittle(){
      return "error/duplicate";
}

handleDuplicateSpittle()方法添加@ExceptionHandler注解,当抛出DuplicateSpittleException异常时候,将委托该方法进行处理。
对于@ExceptionHandler注解标注的方法能处理同一个控制器中所有处理器方法所抛出的异常。

为控制器添加通知

控制器类的特定切面能够运用到整个应用程序的所有控制器中。
控制器通知(Controller Advice)是任意带有@ControllerAdvice注解的类,此类包含一个或多个以下类型的方法

  • @ExceptionHandler
  • @InitBinder
  • @ModelAttribute

@ControllerAdvice实用的一个场景是将所有的@ExceptionHandler方法收集到一个类中,这样所有控制器的异常就能在一个地方进行一致的处理。

使用@ControlerAdvice为所有的控制器处理异常

@ControllerAdvice
public class AppWideExceptionHandler{ // 定义控制器类
	@ExceptionHandler(DuplicateSpittleException.class)
	public String duplicateSpittleHandler(){ // 定义异常处理方法
		return "error/duplicate";
	}
}

将DuplicateSpittleException的处理方法用到整个应用程序的所有控制器上。现在,如果任意的控制器方法抛出了DuplicateSpittleException不管这个方法位于哪个控制器中,都会调用这个duplicateSpittleHandler()方法来处理异常。

跨重定向请求传递数据

技术分享图片

对于重定向来说,模型无法用来传递数据。

  • 重定向携带数据的方法
  1. 使用URL模板以路径变量或查询参数的形式传递数据
  2. 通过flash属性发送数据

通过URL模板重定向

  • 传统方法
    通过路径变量和查询参数传递数据
    例如以路径变量的形式传递新创建Spitter的username。username的值是直接连接到重定向String上的。虽能正常运行但无法满足安全性要求
return "redirect:/spitter/{username}"
  • 使用模板的方式来定义重定向URL
@RequestMapping(value="/register", method=POST)
public String processRegistration(Spitter spitter, Model model){
	spitterRepository.save(spitter);
	model.addAttribute("username", spitter.getUsername());
	return "redirect:/spitter/{username}";
}

此时username作为占位符填充到URL模板中,不是直接连接到重定向String中,所以username中所有的不安全字符都会进行转义。允许用户输入任何想要的内容作为username,并将其附加到路径上。
模型中所有其他的原始类型值都可以添加到URL中作为查询参数。

@RequestMapping(value="/register", method=POST)
public String processRegistration(Spitter spitter, Model model){
	spitterRepository.save(spitter);
	model.addAttribute("username", spitter.getUsername());
	model.addAttribute("spitterId", spitter.getId()); // 此时spitterId属性没有匹配重定向中URL的任何占位符,会自动以查询参数的形式附加到重定向URL上
	return "redirect:/spitter/{username}";
}

eg: 如果username属性是testxxxspitterId42,则结果重定向URL路径是: /spitter/testxxx?spitterId=42
通过路径变量和查询参数的形式跨重定向传递数据是最简单直接的方式,但只限传输一些简单数据eg:String和数字值当发送复杂数据需要通过flash属性提供帮助的领域

使用flash属性

如果需要发送实际的Spitter对象。
如果发送Spitter对象ID,处理重定向方法还需要从数据库中查找才能得到Spitter对象。但是在重定向之前已经获取Spitter对象如何直接将该已经存在的对象直接发送给处理重定向的方法则需要flash

Spitter对象比String和int更为复杂,不能像路径变量和查询参数那么容易发送Spitter对象。只能将其设置为模型中的属性。

存在的另一种方案。将Spitter放到会话中,会话能够长期存在,且能够跨越多个请求。可以在重定向发生之前将Spitter放到会话中。并在重定向后,从会话中将其取出,最后在重定向后在会话中将其清理掉。

Spring提供RedirectAttributes设置flash属性的方法。RedirectAttributes提供Model的所有功能还有用来设置flash属性的方法

RedirectAttributes提供一组addFlashAttribute()方法来添加flash属性。

@RequestMapping(value="/register", method=POST)
public String processRegistration(Spitter spitter, RedirectAttributes model){
	spitterRepository.save(spitter);
	model.addAttribute("username", spitter.getUsername());
	model.addFlashAttribute("spitter", spitter);
	return "redirect:/spitter/{username}";
}

调用addFlashAttribute()方法,将spitter作为key,Spitter对象作为值。还可以不设置key参数,让key根据值的类型自行推断:model.addFlashAttribute(spitter)

在重定向执行之前,所有的flash属性都会复制到会话中。
在重定向执行之后,存在会话中的flash属性会被取出,并从会话转移到模型之中。处理重定向的方法能从模型中访问Spitter对象,像获取其他的模型对象一样。
技术分享图片

视图渲染+Spring MVC进阶技术 -- 《Spring In Action》

原文:https://www.cnblogs.com/openmind-ink/p/13628704.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!