SpringMVC
文章目录
一. web.xml与springMVC.xml
web.xml是整个项目的配置文件,它用来搭配tomcat等容器食用。
springMVC.xml是springMVC框架的配置文件。spring框架的作用是IoC和AOP,那么springMVC就是以spring为基础,加入对于MVC功能的支持。springMVC是集成了一些现成的类,如分发器,适配器等,作为一个新的子框架运行。
二. step by step搭建
使用Maven构建,首先要加入spring和springMVC依赖依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.10.RELEASE</version>
</dependency>
1. 容器部分
对于一个web项目,其本质就是一个又一个的http请求。而我们所要做的就是,当给定一个url能给客户返回一个他们想要的资源。
web容器为我们做的是,当请求来到了HTTP服务器,服务器会转交给Web容器,此时容器会创建一个代表当前的请求的 HttpServletRequest 对象,并将请求相关信息设置给该对象。同样也会创建一个相应的对象 HttpServletResponse,作为之后要对客户端进行响应的 Java 对象。
正常来说,我们会使用<servlet>和<servlet-mapping>标签告诉容器什么样的路径匹配到哪个servlet。每个servlet都会直接写成java文件进行声明。
然而现在我们有了springMVC,我们要使用spring容器来管理servlet:
配置一个DispatcherServlet,这个类由springMVC框架提供,还要使用init-param将参数指向配置springMVC的xml文件。init-param是用来定义servlet范围内的参数的。
<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*:springMVCContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
有了这个配置后,web容器在接收到请求后,就会将其传递给spring容器中的DispatcherServlet对象,进而,会引发一系列的处理。
2. springMVC部分
前面已经说到请求已经通过web容器传递给DispatcherServlet对象了。下面就具体说说springMVC是如何进行处理的。
A. 获取handler对象
接收到请求后,DispatcherServlet从容器中取出所有 HandlerMapping 的实例并遍历,其最终。目的是找到可以处理请求到Handler
因此,我们需要在springcontext.xml中配置要使用的HandlerMapping实例。
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
这相当于是告诉spring容器实例化一个RequestMappingHandlerMapping对象(这个类实现了HandlerMapping接口)。
对于RequestMappingHandlerMapping这个对象,会将请求map到controller的方法。(而有一些HandlerMapping对象会将请求map到一个controller)。
在找到对应的handler(执行程序)后,再加上HandlerInterceptor(拦截器)形成HandlerExecutionChain返回给DispatcherServlet对象。
[有关更多的HandlerMapping具体详见:https://www.cnblogs.com/tengyunhao/p/7658952.html]
[了解核心流程源码看这个:https://blog.csdn.net/hong10086/article/details/88715960]
B. 执行handler处理方法
通过职责链——HandlerExecutionChain,分发Servlet就可以获得最后能处理请求的Handler对象。然而,这个方法不能直接用,会有一个handlerApdater适配器来操作Handler对象,比如获取入参传入Handler方法。
handlerApdater同样需要在springcontect.xml中进行声明,由spring容器进行管理。
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
在处理结束后,MVC中的C就完成了。通过handler处理方法可以返回一个对象ModelAndView。而接下来也会进入view的生成部分。
不过,在此之前,需要看一眼这段流程中的demo。
这整个流程中,我们需要编写的只涉及两个方面,一个是处理器,一个是拦截器。
Handler编写:
在Controller中, @RequestMapping使HanlerMapping能够通过请求找到这个方法。
@Controller本质上是一种@Component。在spring.xml中配置<context:component-scan base-package="com.etc.web" />
对包内容进行扫描,即可用spring容器管理该对象。
@Controller
public class AController {@RequestParam("ename")
@RequestMapping("/hello")
public ModelAndView hello(@RequestParam("ename") String name){
//...
}
}
拦截器编写:
[最简单的拦截器编写在这里:https://my.oschina.net/fengshuzi/blog/364397]
拦截器和过滤器容易分不清,简单来说,过滤器是一种特殊的servlet,其使用用在web容器中的。而过滤器是基于spring的AOP原理,切面编程,动态拦截,其拦截目标是controller的方法。
[过滤器和拦截器的区别:https://blog.csdn.net/nizhengjia888/article/details/86605243]
web容器启动时,就会加载过滤器,而拦截器只会在url申请发生时进行拦截。
C. 生成视图1——ModelAndView
在上一步中,handler方法返回了一个对象叫做ModelAndView。这个对象并不是真正的视图,它是一种逻辑视图。接下来由ViewResolver和View来生成真正的视图。
ViewResolver就会把该逻辑视图名称解析为真正的视图View对象。View是真正进行视图渲染,把结果返回给浏览器。
ViewResolver允许定义前缀后缀,为ModelAndView返回的viewName拼接url。同样,要把这个对象加入spring容器中进行管理;
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
当分发Servlet收到返回的ModelAndView时候,就会遍历视图解析器实例,找到适合的viewResolver,来获取视图。最后返回视图并进行渲染。
@RequestMapping("/hello")
public ModelAndView hello(@RequestParam("ename") String name){
System.out.println(name);
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("hello");//寻找“/hello.jsp”
modelAndView.addObject("message",name);
return modelAndView;
}
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello</title>
</head>
<body>
<% // request作用域获取model
String msg = request.getAttribute("message").toString();
out.print(msg);
%>
</body>
</html>
渲染过程就是hello.jsp转换为浏览器可以认识的html模样。
D. 生成视图2——返回json
虽然正儿八经的叫springMVC模式,但是如果一个请求想要返回的不是view,而仅仅是一个json对象呢?
Controler配置
@RestController
public class ReController {
@RequestMapping("api/all")
public CodeMessage fetchAll(){
CodeMessage codeMessage = new CodeMessage();
codeMessage.setCode("200");
List<Item> lists = new ArrayList<>();
Item item = new Item();
item.setId(6);
codeMessage.setData(lists);
return codeMessage;
}
}
但是!没找到合适的视图解析器!!待补充!
于是暂时替换为:
@RequestMapping("api/all")
public String fetchAll(){
CodeMessage codeMessage = new CodeMessage();
codeMessage.setCode("200");
....
//target为要传回去的数据对象
codeMessage.setData(target);
// java对象直接转换字符
ObjectMapper om = new ObjectMapper();
String result = null;
try {
result = om.writeValueAsString(codeMessage);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return result;
}