1 Spring MVC 概览
Spring 提供了一个功能齐全的 MVC 框架用于构建 Web 应用程序。Spring 框架可以很容易的和其他的 MVC 框架融合(如 Struts),该框架使用控制反转(IOC)将控制器逻辑和业务对象分离开来。它也允许以声明的方式绑定请求参数到业务对象上。
- DispatcherServlet
- Spring 的 MVC 框架是围绕 DispatcherServlet 来设计的,它用来处理所有的 HTTP 请求和响应。
- WebApplicationContext
- WebApplicationContext 继承了 ApplicationContext,并添加了一些 web 应用程序需要的功能。和普通的 ApplicationContext 不同,WebApplicationContext 可以用来处理主题样式,它也知道如何找到相应的 servlet。
- Controller
- 控制器提供对应用程序行为的访问,通常通过服务接口实现。控制器解析用户的输入,并将其转换为一个由视图呈现给用户的模型。Spring 通过一种极其抽象的方式实现控制器,它允许用户创建多种类型的控制器。
- @Controller 注解表示该类扮演控制器的角色。Spring 不需要继承任何控制器基类或应用 Servlet API。
- @RequestMapping 注解用于将 URL 映射到任何一个类或者一个特定的处理方法上。
1.1 Spring MVC 运行原理
- Spring MVC 通过一个单独的前端控制器(DispatcherServlet)过滤分发请求。
- DispatcherServlet 根据处理器映射(HandlerMapping)和请求携带的 URL 决定将请求发送给某个控制器(Controller)。
- 控制器从请求中取得信息,然后委托业务逻辑组件处理。将处理结果打包在模型(model)中,然后指定一个视图(view)的逻辑名称,然后将请求和模型、视图名称一起发送回 DispatcherServlet。
- DispatcherServlet 用视图名称查找对应的视图解析器(ViewResolver),负责将逻辑名称转换成对应的页面实现。
- 最后一步就是视图的实现。视图会使用模型数据填充到视图实现中,然后将结果放在 HTTP 响应对象中。
1.2 Spring MVC 配置
1)配置前端控制器
继承了 AbstractAnnotationConfigDispatcherServletInitializer,会在项目运行初始化被自动发现并加载。
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// 根容器
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
// Spring mvc 容器,指定配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
// DispatcherServlet 映射,从"/"开始
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
AppInitializer 类需要实现三个方法,RootConfig 和 WebConfig 是两个关键配置类,而 getServletMappings 只需要返回一个 String 的列表,{“/”}的意思是监听访问 url 下所有的请求。
2)配置视图解析器
@EnableWebMvc:启动 Spring MVC 特性
configer.enable():静态资源的请求将转交给 servlert 容器的 default servlet 处理。
- setPrefix() 方法用于设置视图路径的前缀;
- setSuffix() 用于设置视图路径的后缀;
- setExposeContextBeansAsAttributes(true) 使得可以在 JSP 页面中通过 ${ } 访问容器中的 bean
@Configuration
@EnableWebMvc//启动Spring MVC
@ComponentScan("org.test.spittr.web")//启动组件扫描
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
// 配置JSP视图解析器
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
// 可以在JSP页面中通过${}访问beans
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable(); //配置静态文件处理
}
}
3)配置 Bean
RootConfig 在设置扫描机制的时候,将之前 WebConfig 设置过的那个包排除了。
@Configuration
@ComponentScan(basePackages = { "org.test.spittr.controller" }, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
public class RootConfig {
}
2 编写 Controller
2.1 控制器类
控制器类就是含有被 @RequestMapping 注解修饰的方法的类。@Controller 是 @Component 的别名,返回一个视图逻辑名称。
@RequestMapping 可加在类上和方法上,可同时映射多个路径
@Controller
@RequestMapping(value = "/")
public class HomeController {
@RequestMapping(value = { "/", "/homepage" }, method = RequestMethod.GET)
public String home() {
return "home";
}
}
2.2 请求参数
Spring MVC 提供了三种方式,可以让客户端给控制器的 handler 传入参数:
1)查询参数
@RequestParam,可设默认和非必填
@RequestMapping(method = RequestMethod.GET)
public List<Spittle> spittles(@RequestParam("max") long max,
@RequestParam(value = "count", defaultValue = "20") int count) {
return spittleRepository.findSpittles(max, count);
}
2)表单参数
- “redirect:”前缀:解析为重定向的规则, 而不是视图的名称。
- “forward:”前缀:请求将会前往(forward) 指定的 URL 路径, 而不再是重定向。
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String processRegistration(Spitter spitter) {
return "redirect:/spitter/" + spitter.getUsername();
}
3)路径参数
@PathVariable,如果函数参数和占位符名称相同,可省略注解的参数
@RequestMapping(value = "abc/{spittleId}", method = RequestMethod.GET)
public String showSpittle(@PathVariable("spittleId") long spittleId,Model model) {
}
2.3 校验参数
Java Validation API 定义了多个注解, 这些注解可以放到属性上,从而限制这些属性的值。
注 解 | 描 述 |
---|---|
@AssertFalse | 所注解的元素必须是 Boolean 类型, 并且值为 false |
@AssertTrue | 所注解的元素必须是 Boolean 类型, 并且值为 true |
@DecimalMax | 所注解的元素必须是数字, 并且它的值要小于或等于给定的 BigDecimalString 值 |
@DecimalMin | 所注解的元素必须是数字, 并且它的值要大于或等于给定的 BigDecimalString 值 |
@Digits | 所注解的元素必须是数字, 并且它的值必须有指定的位数 |
@Future | 所注解的元素的值必须是一个将来的日期 |
@Max | 所注解的元素必须是数字, 并且它的值要小于或等于给定的值 |
@Min | 所注解的元素必须是数字, 并且它的值要大于或等于给定的值 |
@NotNull | 所注解元素的值必须不能为 null |
@Null | 所注解元素的值必须为 null |
@Past | 所注解的元素的值必须是一个已过去的日期 |
@Pattern | 所注解的元素的值必须匹配给定的正则表达式 |
@Size | 所注解的元素的值必须是 String、 集合或数组, 并且它的长度要符合给定的范围 |
校验 bean 对象
@Valid 注解标注要检验的参数,Errors 参数要紧跟其后面
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String processRegistration(@Valid Spitter spitter, Errors errors) {
if(errors.hasErrors()){
...
}
return "redirect:/spitter/" + spitter.getUsername();
}
2.4 其他注解
- @RequestBody:将方法参数直接绑定到 HTTP 请求 Body 上
- @ResponseBody:将返回值作为响应体
- @RestController:避免重复写 @ResponseBody
- @CookieValue
- @RequestHeader
Spring 4.3 中引进了{@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping} 来帮助简化常用的 HTTP 方法的映射 并更好地表达被注解方法的语义
- @GetMapping 是一个组合注解:是 @RequestMapping(method = RequestMethod.GET) 的缩写
- @PostMapping 是一个组合注解:是 @RequestMapping(method = RequestMethod.POST) 的缩写