springmvc03

 
springmvc03
线索Cues
笔记Notes
  • 开篇
  • 提示
  • 听课后复习的思考
  • 图表
 
  • springmvc配置的替代方法
 
前面通过实现AbstractAnnotationConfigDispatcherServletInitializer可以轻松的配置DispatcherServlet,除此之外,我们还可以配置其他servlet和Fillter,Listener。在01中我提过,只要实现了WebApplicationInitializer接口的类都会被自动注入到servlet容器中,所以要想配置其他类,就要实现WebApplicationInitialize接口
 
  • Fillter的配置
 
 
  • servlet的配置
 
  • 在web.xml中声明DispatcherServlet
 
尽量不用web.xml,但还是记录一下,便于维护其他人代码
 
 
 
  • 上传数据
 
DispatcherServlet并没有实现任何解析multipart请求数据的功能。它将该任务委托给了 Spring中MultipartResolver策略接口的实现,通过这个实现类来解析multipart请求中的内 容。从Spring 3.1开始,Spring内置了两个MultipartResolver的实现供我们选择:
CommonsMultipartResolver:使用Jakarta Commons FileUpload解析multipart请求; 
StandardServletMultipartResolver:依赖于Servlet 3.0对multipart请求的支持(始 于Spring 3.1)。 
对于大部分项目而言,如果使用spring3.1以上,就直接使用后者吧。
 
配置方式有两种,如果你使用了前面说的实现了WebApplicationInitializer接口,那么使用如下配置:
 
public class MyServletInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
 
DispatcherServlet ds=new DispatcherServlet();
 
ServletRegistration.Dynamic registration=servletContext.addServlet("appServlet",ds);
registration.addMapping("/");
 
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}
}
 
如果你使用了继承AbstractAnnotationConfigDispatcherServletInitializer的配置,那么可以使用如下配置:
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
      registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads"));
}
 
添加一种web.xml的配置:
 
 
在前端需要enctype转化为multipart/form-data:
 
controller层
 
 
  • 配置Jakarta Commons FileUpload multipart解析器
 
 
通常来讲,StandardServletMultipartResolver会是最佳的选择,但是如果我们需要 将应用部署到非Servlet 3.0的容器中,那么就得需要替代的方案。如果喜欢的话,我们可以编 写自己的MultipartResolver实现。不过,除非想要在处理multipart请求的时候执行特定的 逻辑,否则的话,没有必要这样做。Spring内置了CommonsMultipartResolver,可以作 为StandardServletMultipartResolver的替代方案。 将CommonsMultipartResolver声明为Spring bean的最简单方式如
 
与StandardServletMultipartResolver有所不同,CommonsMultipart-Resolver 不会强制要求设置临时文件路径。默认情况下,这个路径就是Servlet容器的临时目录。不过, 通过设置uploadTempDir属性,我们可以将其指定为一个不同的位置:
 
实际上,我们可以按照相同的方式指定其他的multipart上传细节,也就是设 置CommonsMultipartResolver的属性。例如,如下的配置就等价于我们在前文通过 MultipartConfigElement所配置的StandardServletMultipartResolver:
在这里,我们将最大的文件容量设置为2MB,最大的内存大小设置为0字节。这两个属性直接 对应于MultipartConfigElement的第二个和第四个构造器参数,表明不能上传超过2MB 的文件,并且不管文件的大小如何,所有的文件都会写到磁盘中。但是 与MultipartConfigElement有所不同,我们无法设定multipart请求整体的最大容量。
 
  • 处理异常
spring做了好多对于异常的处理,方便我们对于异常进行获取和返回。
 
spring会将自身的异常转换为合适的状态码。
 
但是我觉得最大的作用spring支持对自定义异常的映射为HTTP状态码,通过@ResponseStatus可以指定状态码,甚至是报错原因。
 
效果图
 
 
还有一种我觉得更好的方式,spring可以编写异常处理的方式,通过@ExceptionHandler注解,可以编写处理指定注解的方法
 
 
但是这种方法指定处理当前类的出现的异常,如果想要将所有控制类的异常进行处理。那么就要在使用控制器通知,就是@ControllerAdvice注解,如果你使用的json格式的话,还可以使用@RestControllerAdvice
 
 
 
 
 
  • 通过url模板进行重定向
 
       在控制器方法返回的视图名称中,我们借助了“redirect:”前缀的力量。当控制器 方法返回的String值以“redirect:”开头的话,那么这个String不是用来查找视图的,而 是用来指导浏览器进行重定向的路径。我们可以回头看一下程序清单5.17,可以看 到processRegistration()方法返回的“redirect:String”如下所示:
“redirect:”前缀能够让重定向功能变得非常简单。你可能会想Spring很难再让重定向功 能变得更简单了。但是,请稍等:Spring为重定向功能还提供了一些其他的辅助功能。 具体来讲,正在发起重定向功能的方法该如何发送数据给重定向的目标方法呢?一般来讲, 当一个处理器方法完成之后,该方法所指定的模型数据将会复制到请求中,并作为请求中的 属性,请求会转发(forward)到视图上进行渲染。因为控制器方法和视图所处理的是同一个请 求,所以在转发的过程中,请求属性能够得以保存。 但是,如图7.1所示,当控制器的结果是重定向的话,原始的请求就结束了,并且会发起一个新 的GET请求。原始请求中所带有的模型数据也就随着请求一起消亡了。在新的请求属性中,没 有任何的模型数据,这个请求必须要自己计算数据。
 
 
显然,对于重定向来说,模型并不能用来传递数据。但是我们也有一些其他方案,能够从发起 重定向的方法传递数据给处理重定向方法中: 使用URL模板以路径变量和/或查询参数的形式传递数据; 通过flash属性发送数据。 首先,我们看一下Spring如何帮助我们通过路径变量和/或查询参数的形式传递数据。
 
通过路径变量和查询参数传递数据看起来非常简单。例如,在程序清单5.19中,我们以路径变 量的形式传递了新创建Spitter的username。但是按照现在的写法,username的值是直接 连接到重定向String上的。这能够正常运行,但是还远远不能说没有问题。当构建URL或 SQL查询语句的时候,使用String连接是很危险的。
除了连接String的方式来构建重定向URL,Spring还提供了使用模板的方式来定义重定向URL。 例如,在程序清单5.19中,processRegistration()方法的最后一行可以改写为如下的形 式:
现在,username作为占位符填充到了URL模板中,而不是直接连接到重定向String中,所 以username中所有的不安全字符都会进行转义。这样会更加安全,这里允许用户输入任何想 要的内容作为username,并会将其附加到路径上。 除此之外,模型中所有其他的原始类型值都可以添加到URL中作为查询参数。作为样例,假设 除了username以外,模型中还要包含新创建Spitter对象的id属性,那 processRegistration()方法可以改写为如下的形式:
所返回的重定向String并没有太大的变化。但是,因为模型中的spitterId属性没有匹配 重定向URL中的任何占位符,所以它会自动以查询参数的形式附加到重定向URL上。 如果username属性的值是habuma并且spitterId属性的值是42,那么结果得到的重定向 URL路径将会是“/spitter/habuma?spitterId=42”。 通过路径变量和查询参数的形式跨重定向传递数据是很简单直接的方式,但它也有一定的限 制。它只能用来发送简单的值,如String和数字的值。在URL中,并没有办法发送更为复杂的 值,但这正是flash属性能够提供帮助的领域。
 
 
  • 使用flash属性
    假设我们不想在重定向中发送username或ID了,而是要发送实际的Spitter对象。如果我 们只发送ID的话,那么处理重定向的方法还需要从数据库中查找才能得到Spitter对象。但 是,在重定向之前,我们其实已经得到了Spitter对象。为什么不将其发送给处理重定向的方 法,并将其展现出来呢? Spitter对象要比String和int更为复杂。因此,我们不能像路径变量或查询参数那么容易 地发送Spitter对象。它只能设置为模型中的属性。 但是,正如我们前面所讨论的那样,模型数据最终是以请求参数的形式复制到请求中的,当重 定向发生的时候,这些数据就会丢失。
      因此,我们需要将Spitter对象放到一个位置,使其能 够在重定向的过程中存活下来。 有个方案是将Spitter放到会话中。会话能够长期存在,并且能够跨多个请求。所以我们可以 在重定向发生之前将Spitter放到会话中,并在重定向后,从会话中将其取出。当然,我们还 要负责在重定向后在会话中将其清理掉。 
       实际上,Spring也认为将跨重定向存活的数据放到会话中是一个很不错的方式。但 是,Spring认为我们并不需要管理这些数据,相反,Spring提供了将数据发送为flash属性 (flash attribute)的功能。按照定义,flash属性会一直携带这些数据直到下一次请求,然后才 会消失。
     Spring提供了通过RedirectAttributes设置flash属性的方法,这是Spring 3.1引入的Model 的一个子接口。RedirectAttributes提供了Model的所有功能,除此之外,还有几个方法 是用来设置flash属性的。 具体来讲,RedirectAttributes提供了一组addFlashAttribute()方法来添加flash属 性。重新看一下processRegistration()方法,我们可以使用addFlashAttribute() 将Spitter对象添加到模型中:
在这里,我们调用了addFlashAttribute()方法,并将spitter作为key,Spitter对象作 为值。另外,我们还可以不设置key参数,让key根据值的类型自行推断得出: 因为我们传递了一个Spitter对象给addFlashAttribute()方法,所以推断得到的key将 会是spitter。 在重定向执行之前,所有的flash属性都会复制到会话中。在重定向后,存在会话中的flash属性 会被取出,并从会话转移到模型之中。处理重定向的方法就能从模型中访问Spitter对象了,就 像获取其他的模型对象一样。图7.2阐述了它是如何运行的。
 
为了完成flash属性的流程,如下展现了更新版本的showSpitterProfile()方法,在从数 据库中查找之前,它会首先从模型中检查Spitter对象:
可以看到,showSpitterProfile()方法所做的第一件事就是检查是否存有key 为spitter的model属性。如果模型中包含spitter属性,那就什么都不用做了。这里面包 含的Spitter对象将会传递到视图中进行渲染。但是如果模型中不包含spitter属性的话, 那么showSpitterProfile()将会从Repository中查找Spitter,并将其存放到模型中。
 
 
 
 
 
 
 
总结Summary
  • 记录最重要几点
  • 写成可以快速检索形式
  • 课后复习总结
 
 
@ResponseStatus
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Spittle Not Found")
指定自定义异常的状态码和原因
@ExceptionHandler
@ExceptionHandler(DuplicateSpittleException.class)
定义异常处理方法,可以处理指定参数的异常
@ControllerAdvice
 
控制器通知注解
@RestControllerAdvice
 
控制器通知注解,返回的是json格式
 
 

你可能感兴趣的:(springmvc03)