前言

前面学习了简单的Spring Web知识,接着学习更高阶的Web技术。

高级技术

Spring MVC配置的替换方案

自定义DispatcherServlet配置

在第五章我们曾编写过如下代码。


public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
} @Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
} @Override
protected String[] getServletMappings() {
return new String[] { "/" };
} }

可以看到SpitterWebinitializer实现了AbstractAnnotationConfigDispatcherServletInitializer抽象类,并重写了三个必须的方法,实际上还可对更多方法进行重写,以便实现额外的配置,如对customizeRegistration方法进行重写,该方法是AbstractDispatcherServletInitializer的方法,无实际的方法体。当AbstractAnnotationConfigDispatcherServletInitializerDispatcherServlet注册到Servlet容器中后,就会调用customizeRegistration方法,并将Servlet注册后得到的Registration.Dynamic传入。可通过重写customizeRegistration方法设置MultipartConfigElement,如下所示。


@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads"));
}

添加其他Servlet和Filter

AbstractAnnotationConfigDispatcherServletInitializer会创建DispatcherServletContextLoaderListener,当需要添加其他ServletFilter时,只需要创建一个新的初始化器即可,最简单的方式是实现WebApplicationInitializer接口。


import org.springframework.web.WebApplicationInitializer; import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic; public class MyServletInitializer implements WebApplicationInitializer { public void onStartup(ServletContext servletContext) throws ServletException {
Dynamic servlet = servletContext.addServlet("myServlet", MyServlet.class);
servlet.addMapping("/custom/**"); FilterRegistration.Dynamic filter = servletContext.addFilter("myFilter", MyFilter.class);
filter.addMappingForUrlPatterns(null, false, "/custom/*"); }
}

在xml文件中声明DispatcherServlet

对基本的Spring MVC应用而言,需要配置DispatcherServletContextLoaderListenerweb.xml配置如下。


<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> </web-app>

可以看到在web.xml中配置了DispatcherServletContextLoaderListener,并且定义了上下文,该上下文会被ContextLoaderListener加载,从中读取bean。也可指定DispatcherServlet的应用上下文并完成加载,配置web.xml如下。


<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

上面使用DispatcherServletContextLoaderListener加载各自的上下文,但实际情况中,基于Java的配置更为通用,此时只需要配置DispatcherServletContextLoaderListener使用AnnotationConfigWebApplicationContext,这样它便可加载Java配置类,而非使用xml,可设置contextClassDispathcerServlet的初始化参数,如下所示。


<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param> <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>ch7.RootConfig</param-value>
</context-param> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> <servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param> <init-param>
<param-name>contextConfigLocation</param-name>
<param-value>ch7.WebConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> <servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping> </web-app>

处理multipart形式数据

处理multipart数据主要用于处理文件上传操作。需要配置multipart解析器读取multipart请求。

配置multipart解析器

DispatcherServlet并未实现任何解析multipart请求数据功能,它只是将任务委托给MultipartResolver策略接口实现,通过该实现解析multipart请求内容,Spring中内置了CommonsMultipartResolverStandardServletMultipartResolver两个解析器。

  • 使用StandardServletMultipartResolver

使用Java配置如下


@Override protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(new MultipartConfigElement("/tmp/spittr/uploads", 2 * 1024 * 1024, 4 * 1024 * 1024, 0));
}

使用xml配置如下,在servlet标签中配置multipart-config


<multipart-config>
<location>/tmp/spittr/uploads</location>
<max-file-size>2 * 1024 * 1024</max-file-size>
<max-request-size>4 * 1024 * 1024</max-request-size>
</multipart-config>
  • 使用CommonsMultipartResolver

使用Java配置如下


@Bean
public MultipartResolver multipartResolver() throws IOException {
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setUploadTempDir(new FileSystemResource("/tmp/spittr/uploads")); return commonsMultipartResolver;
}

处理multipart请求

可在控制器的方法参数上添加@RequestPart注解,如下所示。


@RequestMapping(value="/register", method=POST)
public String processRegistration(
@RequestPart("profilePicture") byte[] profilePicture,
@Valid Spittr spitter,
Errors errors) {
profilePicture.transferTo(new File("/data/spittr" + profilePicture.getOriginalFilename()));
}

处理异常

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

  • 特定的异常将会自动映射为指定的HTTP状态码。
  • 异常上可以添加@ResponseStatus注解,从而将其映射为某个HTTP状态码。
  • 在方法上可添加@ExceptionHandler注解,使其用来处理异常。

将异常映射为HTTP状态码

Spring异常与状态码对应关系如下。

编写异常处理方法

可在请求中直接使用try/catch处理异常,其与正常Java方法中的try/catch相同,同时,也可编写处理器来处理特定异常,当出现特定异常时,将有处理器委托方法进行处理。


@ExceptionHandler(DuplicateSpittleException.class)
public String handleDuplicateSpittle() {
return "error/duplicate";
}

为控制器添加通知

控制器通知是任意带有@ControllerAdvice注解的类,该类包含如下类型的一个或多个方法。

  • @ExceptionHandler注解标注的方法。
  • @InitBinder注解标注的方法。
  • @ModelAttribute注解标注的方法。

上面方法会运用到整个应用程序所有控制器中带有@RequestMapping注解的方法上。


@ControllerAdvice
public class AppWideExceptionHandler {
@ExceptionHandler(DuplicateSpittleException.class)
public String duplicateSpittleHandler() {
return "error/duplicate";
}
}

经过上述配置,任意控制器方法抛出了DuplicateSpittleException异常,都会调用这个duplicateSpittleHandler方法处理异常。

跨重定向请求传递数据

对于重定向而言,若需要从发起重定向的方法传递数据给处理重定向方法中,有如下两种方法

  • 使用URL模版以路径变量和/或查询参数形式传递数据。
  • 通过flash属性发送数据。

通过URL模版进行重定向

如前面讲到的通过redirect:/spitter/{username}进行重定向,该方法会直接根据username确定url,并非十分安全的做法,可使用进行如下处理。


model.addAttribute("username", spitter.getUsername());
return "redirect:/spitter/{username}";

当需要传递参数,如id时,可进行如下处理。


model.addAttribute("username", spitter.getUsername());
model.addAttribute("spitterId", spitter.getId());
return "redirect:/spitter/{username}";

usernameleesfid123456。这样访问的url/spitter/leesf?spitterId=123456。这种方法只能传递简单的值,无法发送更为复杂的值,此时需要使用flash属性。

使用flash属性

通过RedirectAttributes设置flash属性,这样可直接传递对象。


@ReuqestMapping(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}";
}

这样spitter对象也被传递到重定向页面中,可直接访问spitter对象。

总结

本篇博文讲解了如何配置DispatcherServletContextLoaderListener,以及如何处理异常和控制器通知,最后分析如何在重定向时传递数据。

【Spring】Spring MVC高级技术的更多相关文章

  1. 七、Spring MVC高级技术

    知识点 处理文件上传 使用flash属性 在控制器中处理异常 关键词 控制器通知 (Controller Advice) 7.1 处理异常 Spring提供了多种方式将异常转换为响应: 特定的Spri ...

  2. spring-mvc高级技术

    Spring MVC高级技术包括但不限于web.xml配置.异常处理.跨重定向请求传递数据 1.web.xml文件的配置 <!DOCTYPE web-app PUBLIC "-//Su ...

  3. 第07章-Spring MVC 的高级技术

    Spring MVC 的高级技术 1. Spring MVC配置的替代方案 1.1 自定义DispatcherServlet配置 AbstractAnnotationConfigDispatcherS ...

  4. Spring 事务管理高级应用难点剖析--转

    第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...

  5. MyBatis+Spring+Spring MVC整合开发

    MyBatis+Spring+Spring MVC整合开发课程观看地址:http://www.xuetuwuyou.com/course/65课程出自学途无忧网:http://www.xuetuwuy ...

  6. .NET/ASP.NET/C#/WCF/SQL Server/My SQL/Java/JSP/JDBC/Spring/Spring MVC/PHP/Python/Ruby/Shell/Agile/CSS/HTML/HTTP/Unix/Linux大量PDF书籍/电子书籍下载, Effective Java 下载

    223本电子书籍,囊括了.NET/ASP.NET/C#/WCF/SQL Server/My SQL/Java/JSP/JDBC/Spring/Spring MVC/PHP/Python/Shell/A ...

  7. Java面试题(设计模式篇+Spring/Spring MVC篇)

    设计模式 88.说一下你熟悉的设计模式? 自行熟悉. 89.简单工厂和抽象工厂有什么区别? 简单理解简单工厂:对 一个对象的创建进行封装.抽象工厂:对 一组对象的创建进行封装. 比如生产 陶瓷马 和  ...

  8. spring + spring mvc + tomcat 面试题(史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  9. 基于Spring + Spring MVC + Mybatis + shiro 高性能web构建

    一直想写这篇文章,前段时间 痴迷于JavaScript.NodeJs.AngularJS,做了大量的研究,对前后端交互有了更深层次的认识. 今天抽个时间写这篇文章,我有预感,这将是一篇很详细的文章,详 ...

随机推荐

  1. Python二维数据分析

    一.numpy二维数组 1.声明 import numpy as np #每一个[]代表一行 ridership = np.array([ [ 0, 0, 2, 5, 0], [1478, 3877, ...

  2. ZOJ1171

    错误代码先放这 #include<cstdio> #include<cstdlib> #include<iostream> #include<cstring& ...

  3. structs2的核心和工作原理

     在学习struts2之前,首先我们要明白使用struts2的目的是什么?它能给我们带来什么样的好处? 设计目标 Struts设计的第一目标就是使MVC模式应用于web程序设计.在这儿MVC模式的 ...

  4. mysql explain 分析sql语句

    鉴于最近做的事情,需要解决慢sql的问题,现补充一点sql语句性能分析之explain的使用方式! 综合返回数据情况,分析各个参数,可以了解sql 使用方法:explain  + sql语句 如 :e ...

  5. Jquery.Uploadify实现批量上传显示进度条 取消 上传后缩略图显示 可删除

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="UpLoad.aspx.cs&q ...

  6. ovs2.7 在系统重启后,再次使用时提示数据库无法连接的问题。

    问题现象如下,ovs开始安装后,对ovs的操作是正常的,但是,现在系统重启后,OVS的操作第一条命令就失败,如下: 问题解决方法: 参考  http://blog.csdn.net/xyq54/art ...

  7. 初学者易上手的SSH-struts2 04值栈与ognl表达式

    什么是值栈?struts2里面本身提供的一种存储机制,类似于域对象,值栈,可以存值和取值.,特点:先进后出.如果将它当做一个容器的话,而这个容器有两个元素,那么最上面的元素叫做栈顶元素,也就是所说的压 ...

  8. css 页面特殊显示效果

    1.移动端最小设置字体为12px,如果想要更小字体效果: -webkit-transform:scale(0.9); 2.文字超过两行时,末尾显示点点的效果: overflow:hidden;text ...

  9. escape、encodeURI和encodeURIComponent的区别及使用

    编码 javascript中的编码函数有三种 escape(string) encodeURI(string) encodeURIComponent(string) 解码 相应的解码函数也有以下三种 ...

  10. tar split cat 创建、合并分卷压缩包

    最近用微盘传文件遇到的问题,超过100M不能一次传啊,想想win下有rar和zip创建分卷压缩包很简单,就像linux的tar打包器应该也可以吧,搜了下,要和split配合完成 具体命令如下:对文件: ...