1.SpringMVC是什么?
SpringMVC是Spring提供给Web应用的框架设计。
在我的理解中,他其实就是一个封装好的Servlet,通过看他配置。
//web.xml中
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
通过在web,xml的配置中可以看出,SpringMVC是一个由SpringMVC封装好的servlet,所有的请求都映射到了这个servlet中(不过这种配置不唯一,可以自行配置映射关系)。
2.SpringMVC执行流程
既然我们要用人家的轮子,那我们就得按照人家的规矩办事。
看看人家设定的流程:
用户发起请求,把请求全部分给Springmvc中的DispatcherServlet,然后 DispatcherServlet把用户请求地址转给iHandlerMapper也就是第二步,那么我们从哪里去找这个HandlerMapper呢?
这时候我们需要告诉SpringMVC他在哪?除了这个Handler以后我们还要告诉SpringMVC用到的其他组件在哪?
这时候SpringMVC提供了他自己的配置(xml)方式,那首先需要告诉SpringMVC你的这个xml配置文件在哪?所以我们在初始化的时候需要告诉他:
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
通过在初始化的时候指定配置文件的路径,让SpringMVC成功找到他的配置文件。
然后要在SpringMVC中配置你需要用到的组件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
</beans>
这样在初始化SpringMVC的时候就加载了要使用的SpringMVC的组件了。
HanderMapper根据用户请求的地址去寻找程序员设置的Mappering映射。那这个映射是怎么配置的呢?
SpringMVC也提供了很方便的映射处理,常用有两种方式:
1:xml配置(使用不太多)
2:注解配置(使用较多)
如果我们使用XML的方式需要单独去加载去配置一个XML文件,这比较麻烦,所以一般使用注解方式开发。
使用注解方式只需要在类上加一个@Controller的注释,那么SpringMVC就能识别出这个Controller的。
当然我们首先要告诉SpringMVC我用的注解方式,然后你去哪扫描。
需要在SpringMVC的配置文件(也就是上边那个配置文件)中加上下面内容:
<!-- 开启注解 -->
<mvc:annotation-driven/>
<!-- 自动扫描controller -->
<context:component-scan base-package="com.questiontest.controller"/>
当然base-package也就是你的Controller所在的包。
现在已经成功拿到Controller了,但是为什么用户请求我就调用这个方法来执行呢?MapperingHandler凭什么让我去执行这个用户的请求呢?
所以我们在创建每一个Controller的时候都要去告诉SpringMVC,我是处理哪个请求的。
这一步我们通常通过@RequestMapping(value=“请求路径”,method="请求方法")这个注解进行配置。
如下面:
@RequestMapping(value = "addAnswer.action", method = RequestMethod.POST)
public void addAnswer(Answer answer) {
}
这样用户在请求addAnswer.action的时候,就会由他下边这个方法去执行了。
但是我们看上面的执行流程的时候,执行的是一个chain,这是怎么回事呢?
因为开发的时候我并不能让所用人都能访问我的Controller,我需要对访问的人加以限制,满足我条件的人才能访问也就是拦截器,我需要拦截一部分非法请求。
那我肯定要先配置拦截器。
这时候就需要在SpringMVC进行配置了。
首先需要定义拦截器,实现SpringMVC提供给我们的HandlerInterceptor接口
public class Encoding implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
可以看到SpringMVC提供给我们了前置方法,处理器,后置拦截。这提供的是非常舒服的,在使用起来就非常方便。
下面就是看是在SpringMVC的配置文件中进行配置了。
<mvc:interceptors>
<!-- 编码拦截器 -->
<mvc:interceptor>
<mvc:mapping path="*.action"/>
<bean class="com.questiontest.interceptor.Encoding"/>
</mvc:interceptor>
</mvc:interceptors>
到这里终于可以进行处理请求了吧,嘿嘿,其实还没完,首先我要对你的参数进行校验,也就是常说的表单验证。表单校验也有两种方式:
1.JSR303注解验证输入内容
2.使用Validator验证器进行校验
第二种方式也是使用SpringMVC提供的Validator这个核心接口实现的。
在这里就不具体举例了。
请求完了以后需要响应用户了,通常由两种响应,一是跳转页面,二是返回数据。
这里SpringMVC推崇了一种ModelAndView的方式来响应用户,不得不说这种方式确实也挺好用的,但是小编不喜欢用,嘻嘻。
我更推崇使用直接返回的方式。通过使用@ResponseBody来直接进行JSON交互。
如下:
@RequestMapping(value = "addAnswer.action", method = RequestMethod.POST)
public @ResponseBody ResponseMessage addAnswer(Answer answer) {
boolean flag = service.addAnswer(answer);
ResponseMessage message = new ResponseMessage();
message.setFlag(flag);
if (flag) {
message.setMessage("添加成功");
} else {
message.setMessage("添加失败");
}
return message;
}
这样这个message对象就直接以JSON的格式返回给前台了。
这里也就是跳过了视图解析器,因为我并没有跳转页面。
如果我进行页面跳转可以这样做:
@RequestMapping(value = "addAnswer.action", method = RequestMethod.POST)
public String addAnswer(Answer answer) {
boolean flag = service.addAnswer(answer);
ResponseMessage message = new ResponseMessage();
message.setFlag(flag);
if (flag) {
message.setMessage("添加成功");
} else {
message.setMessage("添加失败");
}
return "success.html";
}
这样就直接跳转到success.html这个界面了。这可都是视图解析器的功劳哦(视图解析器会去寻找对应的文件)。当然我们可以在初始化视图解析的时候加上一些参数,比如前缀后缀,这样我们return的时候就可以少些前缀后缀了。