SpringMVC

# Spring MVC框架
## 作用

解决了V和C的交互问题,即解决了Controller如果接收用户的请求,并将结果响应给用户的问题。更加具体的说,Spring MVC约定了一套处理用户请求的流程。

SpringMVC

# Spring MVC框架

## HelloWorld

1 创建项目,生成`web.xml`文件,添加`spring-webmvc`依赖,复制Spring配置文件,添加Tomcat运行环境。

2 配置`web.xml`,以配置`DispatcherServlet`,使之在Tomcat启动时就加载Spring的配置文件

<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>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>

3 至此,工作流程进行到图例中的第2步,DispatcherServlet会根据请求路径“询问”HandlerMapping应该由哪个Controller处理此次请求,所以,需要在Spring的配置文件中配置HandlerMapping(具体的实现类是SimpleUrlHandlerMapping):

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.do">helloController</prop>
</props>
</property>
</bean>

以上配置中,明确了`/hello.do`路径的请求将交由Bean Id为`helloController`的控制器进行处理。

4 至此,DispatcherServlet已经明确了由哪个控制器去处理请求了,所以,需要在项目中创建这个控制器类,并交由Spring管理,则先在Spring的配置文件中配置组件扫描:

<context:component-scan 
base-package="cn.tedu.spring" />

然后在对应的包下创建控制器类,使用`@Controller`注解:

@Controller
public class HelloController {
}

5 Spring MVC框架会自动调用这个`HelloController`中指定的方法,为了明确这个方法,所以,使得它实现`Controller`接口:

public class HelloController
implements org.springframework.web.servlet.mvc.Controller {
}

6 添加了抽象方法后,要求返回`ModelAndView`对象,所以,返回新创建的对象,并通过该对象确定View组件的名称:

public ModelAndView handleRequest(
HttpServletRequest request, 
HttpServletResponse response) 
throws Exception {
ModelAndView mav
= new ModelAndView();
mav.setViewName("hello");

return mav;
}

7 至此,DispatcherServlet已经明确最终负责显示的View组件的名称是`hello`,但不确定具体是哪个文件,所以,需要在Spring的配置文件中配置`ViewResolver`(实现类是`InternalResourceViewResolver`):

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" 
value="/WEB-INF/" />
<property name="suffix" 
value=".jsp" />
</bean>

`InternalResourceViewResolver`的工作原理是根据前缀`prefix`、View组件名称、后缀`suffix`拼接出最终负责显示的页面的路径,即`/WEB-INF/hello.jsp`。

8 基于以上设计,所以,在`WEB-INF`中创建`hello.jsp`页面,以显示响应的页面。

9 完成,将项目部署到Tomcat,通过浏览器访问。



# Spring MVC的核心组件

1 DispatcherServlet:分发

2 HandlerMapping:配置请求路径与控制器的对应关系(映射)

3 Controller:控制器,处理请求,并决定如何响应

4 ModelAndView:响应结果,其中包含了Model(数据)和View(视图组件)

5 ViewResolver:视图解析器,根据ModelAndView中封装的View信息决定最终负责显示响应结果的View是哪一个



# @RequestMapping注解

在控制器类的内部,可以为方法添加`@RequestMapping`注解,以标记**请求路径与方法的映射关系**,例如:

@RequestMapping("/login.do")
public ModelAndView showLogin() {
}

映射的方法,名称可以自定义,参数可以按需设计,返回值也可以按需设计。

**注意:@RequestMapping必须添加在控制器类的方法上,即类本身必须是由Spring管理的组件!**

除了为方法添加该注解以外,还可以在类上添加这个注解!例如:尝试将请求路径设计为`http://SERVER:PORT/PORJECT/user/login.do`,可以在类上添加`@RequestMapping("/user")`,然后,在方法上添加`@RequestMapping("/login.do")`,所以,在类上添加的注解是添加了路径的层级,并不能取代在方法上添加的注解。

使用`@RequestMapping`同时对类和方法进行注解,相当于最终将这2处的注解的路径拼接起来,事实上,在写路径时:

"/user" "/login.do"

"/user/" "login.do"

"/user/" "/login.do"

"/user" "login.do"

以上4种组合都是正确的,但是,推荐所有的路径都是以`/`开始,并不以`/`结尾的,也就是,推荐使用以上的第1种做法!

在使用`@RequestMapping`时,还可以:

@RequestMapping(value="/login.do")

如果还需要限制请求方式,就必须添加更多的设置:

@RequestMapping(method=RequestMethod.POST, value="/login.do")

如果设计为以上配置,则`/login.do`只能通过POST请求进行访问,不允许通过GET请求访问,如果一定要通过GET请求进行访问,会响应405错误,提示:Request method 'GET' not supported。

如果没有限制请求方式,默认情况下,既支持GET请求,也支持POST请求。