目录
- spring MVC简介
- Spring MVC工作流程
- Spring MVC适配器模式
- Spring MVC注解
- json消息转发器
一、Spring MVC简介
Spring MVC是Spring提供的一个实现了Web MVC设计模式的轻量级Web框架。与Struts2框架一样,都属于MVC框架,但其使用和性能等方面比Struts2更加优异。
MVC框架主要处理的问题是如何接收请求以及如何响应请求;
特点:
1)是Spring框架的一部分,可以方便的利用Spring所提供的其他功能;
2)灵活性强,易于与其他框架集成;
3)提供了一个前端控制器DispatcherServlet,使开发人员无需额外开发控制器对象;
4)可自动绑定用户输入,并能正确的转换数据类型;
5)内置了常见的校验器,可以教研用户输入。如果校验不通过,就会重定向到输入表单;
6)支持国际化。可以根据用户区域显示躲过语言;
7)支持多种模板引擎:JSP,beetl,FreeMarker,Velocity等;
8)使用基于XML的配置文件,在编辑后,不需要重新编译应用程序。
二、Spring MVC工作流程:
① 用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet拦截;
② DispatcherServlet拦截到请求后,会调用HandlerMapping处理器映射器;
③ 处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
④ DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器);
⑤ HandlerAdapter会调用并执行Handler(处理器),这里的处理器值得就是程序中编写的Controller类,也被称为后端控制器;
⑥ Controller执行完后,会返回一个ModelAndView对象,该对象中会包含视图名或包含模型和视图名;
⑦ HandlerAdapter将ModelAndView对象返回给DispatcherServlet;
⑧ DispatcherServlet会根据ModelAndView对象选择一个合适的ViewReslover(视图解析器);
⑨ ViewReslover解析后,会向DispatcherServlet中返回具体的View(视图);
⑩DispatcherServlet对View进行渲染(即将模型数据填充至视图中);视图渲染的结果会返回给客户端浏览器显示
Spring核心包和Spring MVC核心包:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!-- Spring MVC 包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
在 web.xml 中配置前端控制器:
<web-app>
<servlet>
<!--配置前端控制器对访问进行拦截-->
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>//类路径下的配置文件
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
三、Spring MVC----适配器模式
好处:
代码发布之后如果要增加新的组件或者标准,用户可根据需求来写,只要添加一个组件和它对应的适配器即可,标准在adapter适配器中,从而使标准和实现进行解耦了。用户写一个类,加上他所需的适配器,告诉Tomcat怎么运行,自己写handle,就不用遵循http组件的标准了。只需遵循自己的适配器标准即可,先走什么,再走什么方法,都是由自己handle
首先了解下分别使用bean name方式(HttpHandlerAdapter),简单映射方式(SimpleHandlerAdapter)和注解方式(AnnotationHandlerAdapter)实现适配器模式的总结构:
1)创建组件和适配器的接口
public interface MockController {
}
/*
* Spring MVC的适配器模式
*/
public interface MockAdapter {
//传入一个类,判断当前类是否能被适配器适配
public boolean support(Object handler);
//如果当前适配器能适配,则调用该方法处理,,handle处理,handler当前被处理的对象
public void handle(Object handler);
}
2)三大实现方式的Controller组件:
/*
* Spring MVC的适配器模式,通过bean name实现的Controller组件
*
* 要让组件能够工作,必须添加能让其工作的适配器:HttpHandleAdapter即http处理适配器
*/
public class HttpController implements MockController{
public void doHttpController() {
// TODO Auto-generated method stub
System.out.println("HttpController");
}
}
/*
* Spring MVC的适配器模式,通过simple简单映射方式实现
*/
public class SimpleController implements MockController{
public void doSimpleController() {
System.out.println("SimpleController");
}
}
/*
* Spring MVC的适配器模式,通过注解方式实现
*/
public class AnnotationController implements MockController{
public void doAnnotationController() {
System.out.println("AnnotationController");
}
}
3)编写三种实现方式的适配器及实现其标准
support方法:传入一个类对象,判断当前类是否能被适配器适配
handle方法:如果当前适配器能适配,则调用该方法处理,handle处理,handler当前被处理的对象
HttpHandleAdapter .java
/*
* 实现适配器接口,适配器和控制器都是由用户提供的
*/
public class HttpHandleAdapter implements MockAdapter{
//处理 bean name方式的handler
public boolean support(Object handler) {
//如果传进来的是HttpController的子类
if(handler instanceof HttpController) {
return true;
}
return false;
}
//经过support方法的逻辑确认是HttpController的子类,所以可以直接进行强转
public void handle(Object handler) {
HttpController httpController = (HttpController) handler;
httpController.doHttpController();
}
}
SimpleHandlerAdapter.java 和 AnnotationHandlerAdapter.java 实现与上基本一致,略过。。。
4)模拟Spring MVC框架的DispatcherServlet前端控制器:
/*
* 框架源码,模拟spring MVC的DispatcherServlet,将其核心逻辑取出来
*/
import java.util.ArrayList;
import java.util.List;
public class MockDispatcherServlet {
//集合中收集了所有Adapter的实现,spring收集所有存在的adapter然后通过@Autowired自动注入
//但此时没有spring所以重写构造器,将所有adapter创建出来
private List<MockAdapter> adapters= new ArrayList<MockAdapter>();
//构造方法
public MockDispatcherServlet() {
adapters.add(new HttpHandleAdapter());
adapters.add(new SimpleHandleAdapter());
adapters.add(new AnnotationHandleAdapter());
}
public static void main(String[] args) {
new MockDispatcherServlet().doService();
}
public void doService() {
AnnotationController annoController = new AnnotationController();
//HttpController httpHontroller = new HttpController();
//SimpleController simpleHontroller = new SimpleController();
//遍历所有的适配器
for (MockAdapter mockAdapter : adapters) {
//如果当前用户请求支持
if (mockAdapter.support(annoController)) {
//执行相应的方法
mockAdapter.handle(annoController);//AnnotationController
}
}
}
}
四、注解方式
1.在applicationContext-mvc.xml文件中加上约束:
在namespaces中勾选 context 和 mvc
2.开启注解
<!-- 开启springMVC注解支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 开启默认的对静态资源文件访问的支持 -->
<mvc:default-servlet-handler />
<!-- 开启对于Spring 组件扫描的支持 spring容器中,只注册controller注解 -->
<context:component-scan base-package="net.xikee">
<context:include-filter type="annotation" //表示注解
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
注:为避免和spring配置文件applicationContext.xml文件扫描到同样的组件,产生两个相同的bean,此处需要配置一个过滤器 include-filter,只扫描包含Controller的组件
然后在applicationContext.xml文件中设置exclude-filter:
<!-- 开启对于Spring 组件扫描的支持 spring容器中,只注册除controller外的注解 -->
<context:component-scan base-package="net.xikee">
<context:exclude-filter type="annotation" //表示注解
expression="org.springframework.stereotype.Controller" />
</context:component-scan>
3.测试:
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/1")
public String SayHello() {
System.out.println("hello controller");
return "hello.jsp";
}
@RequestMapping("/hello")注解表示当前类的所有方法有个共有的头,加上@RequestMapping("/1")注解表示当前方法访问路径是:/hello/1
此时通过requestMapping分发请求,而不像以前需要判断用户请求,然后通过switch进行分发
五、Spring MVC的 消息转发器中 json 与对象之间的转换
导入jackson所需的 jar 包:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
applicationContext-mvc.xml文件中的配置:
<!-- Spring MVC中的请求映射处理适配器 -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters"><!-- 消息转发器:json转对象&&对象转json -->
<!-- jackson是spring支持json消息转发器的底层实现 -->
<bean
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</property>
</bean>
restful风格
在测试类HelloController类 (@RequestMapping("/hello"))中:
未加@ResponseBody之前,浏览器访问 /hello/3这个接口会报404,浏览器不知道返回的users类型是什么
加上@ResponseBody之后,浏览器访问接口会返回20个json形式的数据
@ResponseBody
@RequestMapping("/3")
public List<User> queryAllUser(){
List<User> users = new ArrayList<User>();
for(int i=0; i<20; i++) {
users.add(new User(i, "xikee"+i, "123456", 10d));
}
return users;
}
如果在类上面加上@RestController,除有@Controller功能外,还相当于在每个方法上加上@ResponseBody