一、什么是SpringMVC
SpringMVC是Spring框架的一部分,是一个表现层框架,它是基于模型视图-控制器(Model-View-Controller,MVC)模式实现,能够帮助我们构建想Spring框架那样灵活和松耦合的Web应用程序。
二、SpringMVC架构
1、架构流程图
2、流程说明:
①用户发送请求至 前端控制器DispatcherServlet(是一个单实例的Servlet将请求委托给应用程序的其他组件来执行实际的处理)。
②前端控制器DispatcherServlet收到请求后调用处理器映射器HandlerMapping,来确定请求的下一站是哪里。
③处理器映射器HandlerMapping根据请求的Url找到具体的处理器,生成处理器对象Handler及处理器拦截器HandlerIntercepter(如果有则生成)一并返回给前端控制器DispatcherServlet。
④前端控制器DispatcherServlet通过处理器适配器HandlerAdapter调用处理器Controller。
⑤执行处理器(Controller,也叫后端控制器)。
⑥执行完后返回ModelAnView。
⑦处理器映射器HandlerAdapter将处理器Controller执行返回的结果ModelAndView返回给前端控制器DispatcherServlet。
⑧前端控制器DispatcherServlet将ModelAnView传给视图解析器ViewResolver。
⑨视图解析器ViewResolver解析后返回具体的视图View。
⑩前端控制器DispatcherServlet对视图View进行渲染视图(即:将模型数据填充至视图中)
⑪前端控制器DispatcherServlet响应用户。
3、组件说明:
①DisPatcherServlet(前端控制器):用户请求到达前端控制器,它相当于MVC模式中的C(Controller),DispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。作用:作为接受请求,相应结果,相当于转发器,中央处理器,减少其他组件之间的耦合度。
②HandlerMapping(处理器映射器):HandlerMapping负责根据用户请求找到Handler(处理器),SpringMVC提供了不同的映射器实现实现不同的映射方式,例如:配置文件方式、实现接口方式、注解方式等。作用:根据请求的Url 查找Handler。
③HandLer(处理器):Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下,Handler对具体的用户请求进行处理。由于Handler设计到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。注意:编写Handler时按照HandlerAdpter的要求去做,这样才可以去正确执行Handler。
④HandlerAdapter(处理器适配器):通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。作用:按照特定的规则(HandlerAdapter要求的规则)去执行Handler。
⑤ViewResolver(视图解析器):ViewResolver负责将处理结果生成View视图,ViewResolver首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面的展示给用户。作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)。
⑥View视图:View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf)。
三、基于JavaConfig的SpringMVC入门程序
1、工程结构如下:
2、配置DispacherServlet,ApiWebInitializer
package com.caofanqi.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* 配置DispatcherServlet:扩展AbstractAnnotationConfigDispatcherServletInitializer的任意类都会
* 自动地配置DispatcherServlet和Spring应用上下文 ,Spring的应用上下文会位于应用程序的Servlet上下文之中。
*
* 注:使用AbstractAnnotationConfigDispatcherServletInitializer配置DispatcherServlet是传统web.xml方式的替代方案。
* 需要Servlet3.0以上才支持
*/
public class ApiWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* 将一个或多个路径映射到DispatcherServlet上;
* “/”:表示拦截除了JSP的所有请求
* “/*”:表示拦截所有Url包括JSP
*/
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
/**
* 返回的带有@Configuration注解的类将会用来配置DispatcherServlet加载应用上下文时的bean。
* 加载包含Web组件的bean,如控制器、视图解析器以及处理器映射器。
*/
@Override
protected Class>[] getServletConfigClasses() {
return new Class>[] { WebConfig.class };
}
/**
* 返回的带有@Configuration注解的类将会用来配置ContextLoaderListtener创建的应用上下文bean。
* 这些bean通常是驱动应用后端中间层和数据层组件。
*/
@Override
protected Class>[] getRootConfigClasses() {
return new Class>[] { RootConfig.class };
}
}
3、WebConfig
package com.caofanqi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc // JavaConfig 启用SpringMVC
@ComponentScan("com.caofanqi.controller")
public class WebConfig extends WebMvcConfigurerAdapter {
/**
* 配置JSP视图解析器
*/
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
/**
* 配置静态资源处理1:
* 此时会注册一个默认的Handler:DefaultServletHttpRequestHandler,这个Handler也是用来处理静态文件的,它会尝试映射/*。
* 当DispatcherServelt映射/时(/和/*是有区别的),并且没有找到合适的Handler来处理请求时,就会交给DefaultServletHttpRequestHandler
* 来处理。注意:这里的静态资源是放置在web根目录下,而非WEB-INF 下。 例如:在WebRoot目录下有一个图片:1.png
* 我们知道Servelt规范中web根目录(WebRoot)下的文件可以直接访问的,但是由于DispatcherServlet配置了映射路径是:/,
* 它几乎把所有的请求都拦截了,从而导致1.png 访问不到,这时注册一个DefaultServletHttpRequestHandler
* 就可以解决这个问题。其实可以理解为DispatcherServlet破坏了Servlet的一个特性(根目录下的文件可以直接访问),
* DefaultServletHttpRequestHandler是帮助回归这个特性的。
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
/**
* 配置静态资源处理2: addResoureHandler指的是对外暴露的访问路径,addResourceLocations指的是文件放置的目录
* 此方法用来专门注册一个Handler,来处理静态资源的,例如:图片,js,css等。举例:
* 当请求http://localhost:8090/stuspringmvc/resources/1.png时,会把/WEB-INF/resources/1.png返回。
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
super.addResourceHandlers(registry);
registry.addResourceHandler("/resources/**").addResourceLocations("/WEB-INF/resources/");
}
}
4、RootConfig
package com.caofanqi.config;
import java.util.regex.Pattern;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
@Configuration
@ComponentScan(basePackages = { "com.caofanqi" }, excludeFilters = {
@Filter(type = FilterType.CUSTOM, value = RootConfig.WebPackage.class) })
public class RootConfig {
/**
* 通过excludeFilters过滤指定包不进行装载到容器(因为WebConfig中已经扫描了)
*/
public static class WebPackage extends RegexPatternTypeFilter {
public WebPackage() {
super(Pattern.compile("com\\.caofanqi\\.controller"));
}
}
}
5、HomeController
package com.caofanqi.controller;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller // 声明为一个控制器
@RequestMapping(value = "/") // @RequestMapping可以加载类上,表示该类所有的方法路径前面都要包括该value
public class HomeController {
@RequestMapping(method = GET) // 处理对/的get请求
public String home() {
return "home"; // 视图名为home
}
}
6、home.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
StuSpringMVC
" >
Hello SpringMVC
">UserList |
">Register
启动项目,访问http://localhost:8090/stuspringmvc/ 如下所示:
四、基于web.xml的SpringMVC入门程序
1、工程目录
2、web.xml
contextConfigLocation
/WEB-INF/spring/root-context*.xml
org.springframework.web.context.ContextLoaderListener
stuspringmvc-xml
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
/WEB-INF/spring/springmvc-context.xml
1
stuspringmvc-xml
/
3、springmvc-context.xml
4、root-context.xml
HomeController和home.jsp不变,访问
http://localhost:8090/stuspringmvc/ 如下所示:
到此,两种模式的SpringMVC入门已经完成。
五、传递模型数据到视图中
类上注解为:
@Controller
@RequestMapping("/products")
public class ProductController {
...
}
1、我们可以在方法的参数列表上添加一个Model(也可使用ModelAndView,Map),然后视图可以根据指定的key获取value,如下所示:
@RequestMapping(method = RequestMethod.GET)
public String products(Model model) {
model.addAttribute("productList", productService.listProducts());
return "products";
}
2、如果不指定key的话,key会根据值的对象类型推断确定,比如List
@RequestMapping(method = RequestMethod.GET)
public String products(Model model) {
model.addAttribute(productService.listProducts());
return "products";
}
3、还有一种,不返回视图名称,也不显示地设定模型,当处理器方法返回对象或集合时,这个值会放到模型中,模型的key会根据其类型推断得出,逻辑视图的名称将会根据请求路径推断得出。比如这个方法是处理“/products”的GET请求,视图名称将会是products(去掉开头的/)。如下所示:
@RequestMapping(method = RequestMethod.GET)
public List products() {
return productService.listProducts();
}
上面几种方式都可以将数据放入模型中,当视图是JSP时,数据模型会作为请求属性放到请求(request)中。可以使用JSTL的
">