【Spring】Spring MVC高级技术
前言
前面学习了简单的
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
的方法,无实际的方法体。当AbstractAnnotationConfigDispatcherServletInitializer
将DispatcherServlet
注册到Servlet
容器中后,就会调用customizeRegistration
方法,并将Servlet
注册后得到的Registration.Dynamic
传入。可通过重写customizeRegistration
方法设置MultipartConfigElement
,如下所示。
@Override
protected void customizeRegistration(Dynamic registration) {
registration.setMultipartConfig(
new MultipartConfigElement("/tmp/spittr/uploads"));
}
添加其他Servlet和Filter
AbstractAnnotationConfigDispatcherServletInitializer
会创建DispatcherServlet
和ContextLoaderListener
,当需要添加其他Servlet
和Filter
时,只需要创建一个新的初始化器即可,最简单的方式是实现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
应用而言,需要配置DispatcherServlet
和ContextLoaderListener
,web.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
中配置了DispatcherServlet
和ContextLoaderListener
,并且定义了上下文,该上下文会被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>
上面使用DispatcherServlet
和ContextLoaderListener
加载各自的上下文,但实际情况中,基于Java
的配置更为通用,此时只需要配置DispatcherServlet
和ContextLoaderListener
使用AnnotationConfigWebApplicationContext
,这样它便可加载Java
配置类,而非使用xml
,可设置contextClass
和DispathcerServlet
的初始化参数,如下所示。
<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
中内置了CommonsMultipartResolver
和StandardServletMultipartResolver
两个解析器。
- 使用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}";
若username
为leesf
;id
为123456
。这样访问的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
对象。
总结
本篇博文讲解了如何配置DispatcherServlet
和ContextLoaderListener
,以及如何处理异常和控制器通知,最后分析如何在重定向时传递数据。
【Spring】Spring MVC高级技术的更多相关文章
- 七、Spring MVC高级技术
知识点 处理文件上传 使用flash属性 在控制器中处理异常 关键词 控制器通知 (Controller Advice) 7.1 处理异常 Spring提供了多种方式将异常转换为响应: 特定的Spri ...
- spring-mvc高级技术
Spring MVC高级技术包括但不限于web.xml配置.异常处理.跨重定向请求传递数据 1.web.xml文件的配置 <!DOCTYPE web-app PUBLIC "-//Su ...
- 第07章-Spring MVC 的高级技术
Spring MVC 的高级技术 1. Spring MVC配置的替代方案 1.1 自定义DispatcherServlet配置 AbstractAnnotationConfigDispatcherS ...
- Spring 事务管理高级应用难点剖析--转
第 1 部分 http://www.ibm.com/search/csass/search/?q=%E4%BA%8B%E5%8A%A1&sn=dw&lang=zh&cc=CN& ...
- MyBatis+Spring+Spring MVC整合开发
MyBatis+Spring+Spring MVC整合开发课程观看地址:http://www.xuetuwuyou.com/course/65课程出自学途无忧网:http://www.xuetuwuy ...
- .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 ...
- Java面试题(设计模式篇+Spring/Spring MVC篇)
设计模式 88.说一下你熟悉的设计模式? 自行熟悉. 89.简单工厂和抽象工厂有什么区别? 简单理解简单工厂:对 一个对象的创建进行封装.抽象工厂:对 一组对象的创建进行封装. 比如生产 陶瓷马 和 ...
- spring + spring mvc + tomcat 面试题(史上最全)
文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...
- 基于Spring + Spring MVC + Mybatis + shiro 高性能web构建
一直想写这篇文章,前段时间 痴迷于JavaScript.NodeJs.AngularJS,做了大量的研究,对前后端交互有了更深层次的认识. 今天抽个时间写这篇文章,我有预感,这将是一篇很详细的文章,详 ...
随机推荐
- Python实战之Selenium自动化测试web登录
#!/usr/bin/env python3 # -*- coding:utf-8 -*- from selenium import webdriver from selenium.webdriver ...
- Winform窗体间传递数据
public string passText { get { return textBox1.Text; } } //Form1中还有个按钮button1在其点击事件中有: private void ...
- oracle状态
Oracle_四种状态 oracle四种状态 1.shutdown(完全关闭) 2.nomount(未加载) 3.mount(已加载) 4.open(完全打开) Shutdown状态 Shutdown ...
- Ubuntu配置OpenStack 一:主机环境配置以及问题总结
本文包含openstack配置的实验环境的基本步骤.在下面的步骤中将逐步讲解如何操作. 1.准备三台虚拟机 主机名字分别命名为controller.network.computer[desktop版或 ...
- springcloud干货之服务消费者(ribbon)
本章介绍springcloud中的服务消费者 springcloud服务调用方式有两种实现方式: 1,restTemplate+ribbon, 2,feign 本来想一篇讲完,发现篇幅有点长,所以本章 ...
- 浅谈javascript继承体系
最近做web项目,接触了jquery等框架,虽然使用方便,但是还是想学习下Javascript,今天分享下最近对js原型继承的理解,不足之处欢迎指正. 一.构造器的原型属性与原型对象 刚接触js时通常 ...
- ASP.NET Core 网站发布到Linux服务器(转)
出处;ASP.NET Core 网站发布到Linux服务器 长期以来,使用.NET开发的应用只能运行在Windows平台上面,而目前国内蓬勃发展的互联网公司由于成本的考虑,大量使用免费的Linux平台 ...
- Kinect v2(Microsoft Kinect for Windows v2 )配置移动电源解决方案
Kinect v2配置移动电源解决方案 Kinect v2如果用于移动机器人上(也可以是其他应用场景),为方便有效地展开后续工作,为其配置移动电源是十分必要的. 一.选择移动电源 Kinect v2原 ...
- 【深度学习】keras + tensorflow 实现猫和狗图像分类
本文主要是使用[监督学习]实现一个图像分类器,目的是识别图片是猫还是狗. 从[数据预处理]到 [图片预测]实现一个完整的流程, 当然这个分类在 Kaggle 上已经有人用[迁移学习](VGG,Resn ...
- URL的编码和解码
URL的编码和解码 参考:阮一峰--关于URL编码 1 为什么要URL编码 在因特网上传送URL,只能采用ASCII字符集 也就是说URL只能使用英文字母.阿拉伯数字和某些标点符号,不能使用其他文字和 ...