简介
SpringMVC框架是一个
MVC框架,通过实现Model-View-Controller模式来很好的将数据、业务与展现进行分离。
SpringMVC的设计是围绕
DispatcherServlet展开,
DispatcherServlet负责将
请求派发到特定的
handler。
通过可配置的
HandlerMapping(映射处理器)、
controller(控制器)、
ViewResolver(视图解析器)进行MVC的模式的体现
SpringMVC的C层框架的核心是
DispatcherServlet,它的作用是将
请求分发 给不同的
后端处理器(Controller)。
SpringMVC的C层框架使用了后端控制器、映射处理器、视图解析器来共同完成C层框架的主要工作。并且真正的把业务层处理的
数据结果和
相应的视图拼成一个对象,即
ModelAndView 对象。
原理
1、客户端向服务器发送
请求,被Spring前端控制器
DispatcherServlet捕获;
2、
DispatcherServlet 解析 URL,得到
URI(资源标识符),根据URI调用
HandlerMapping 来获得Handler配置的对象(
Handler对象 以及 对应的拦截器),以
HandlerExecutionChain对象的形式返回
3、
DispatherServlet 根据
Handler选择
HandlerAdapter。执行对应的
Controller。(如果有拦截器,则先执行拦截器的preHandler() 方法)
4、提取Request中的模型数据,
将Handler填入参数,开始
执行Handler(Controller) ,此时根据配置先执行如下工作:
①HttpMessageConveter:将请求消息(Json、xml等)转换为一个对象,将对象转换为指定的响应消息
②数据转换:对请求消息进行数据转换。如String转Integer、Double等
③数据格式化:如将字符串转换成格式化数字或格式化日期
④数据验证:验证数据的有效性(长度、格式),验证结果存储到BindingResult或Error中。
5、
Handler执行完成后,向
DispatcherServlet返回一个
ModelAndView对象;
6、根据返回的
ModelAndView,选择合适
ViewResolver (已注册到spring的ViewResolver-即配置在xml文件中的viewResolver) 返回给
DispatcherServlet;
7、
ViewResolver 结合
Model 和
View ,来
渲染视图
8、将渲染结果返回客户端
处理器
映射
HandlerMapping
spring MVC中,映射处理器 HandlerMapping可以把web请求映射到正确的处理器上,常用的有
- BeanNameUrlHandlerMapping(默认) 官方推荐使用
- SimpleUrlHandlerMapping
- ControllerClassNameHandlerMapping
1 . BeanNameUrlHandlerMapping
DispatcherServlet会查找spring容器中
和请求的url同名的bean,
不需要配置,spring在找不到handlerMapping的情况下会使用BeanNameUrlHandlerMapping。
例如请求url为:
localhost:8080/SpringMVCStudy/index.html
spring配置为:
<!-- 配置handlerMapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <!--可以不配置-->
<!-- 配置controlller -->
<bean name="index.html" class="com.mj.TestController">
2 . SimpleUrlHandlerMapping
SimpleUrlHandlerMapping可以让开发者
自由的配置请求的 url 和 handler的映射关系
例如spring配置为:
<!-- 配置HandlerMapping -->
<bean id="simplerUrlHandlerMapping" class="com.springframework.web.servlet.handler.SimplerUrlHandlerMapping">
<list> <!-- 配置多个interceptor -->
<ref bean="interceptor1" />
<ref bean="interceptor2" />
</list>
<property name="mappings">
<props>
<prop key="/index">indexController</prop> <!-- 为不同的url配置不同的handler -->
</props>
</property>
<property name="order" value="1"/>
</bean>
<!-- 配置controller -->
<bean id="indexController" class="com.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="viewName" value="index"/>
</bean>
请求的url就可以为:
localhost:8080/SpringMVCStudy/index
3 . ControllerClassNameHandlerMapping
ControllerClassNameHandlerMapping 只要我们的Controller的
命名方式是以
XXXController的方式命名,则将控制器类名的
Controller后缀删除,
转换成小写之后作为请求url的前缀
例如spring配置为:
<bean id="controllerClassNameHandlerMapping" class="org.springframework.web.servlet.handler.ControllerClassNameHandlerMapping" />
如果是普通的Controller,则映射规则为
localhost:8080/SpringMVCStudy/home // 映射到 HomeController
localhost:8080/SpringMVCStudy/helloworld // 映射到 HelloWorldController
如果是MultiActionController,则映射规则为
localhost:8080/SpringMVCStudy
/userinfo/valid //映射到
UserInfoController 的
valid 方法
控制器 Controller
1 . AbstractController
2 . MultiActionController
3 . SimpleFormController
1 . AbstractController
属性
/** Set of supported HTTP methods */
private Set<String> supportedMethods;
private boolean requireSession = false;
/** Use HTTP 1.0 expires header? */
private boolean useExpiresHeader = true;
/** Use HTTP 1.1 cache-control header? */
private boolean useCacheControlHeader = true;
/** Use HTTP 1.1 cache-control header value "no-store"? */
private boolean useCacheControlNoStore = true;
private int cacheSeconds = -1;
要继承AbstractController,则需要实现 handleRequest方法
public
ModelAndView handleRequest(
HttpServletRequest request, HttpServletResponse response){
ModelAndView mav = new ModelAndView(); //返回值是一个ModelAndView对象
mav.setViewName("dictionary/index.html"); //设置返回的视图文件(相对于Servlet路径)
mav.addObject("username","Michael"); //设置返回的对象
mav.addAllObjects(Map modelMap); //设置返回的对象map
return mav;
}
2 . MultiActionController
MutilActionController 控制器将
多个请求处理方法合并在一个处理器中,可以把相关的功能组合在一起
方法一: 让自定义的控制器继承 MultiActionController
public class MyMultiActionController
extends MultiActionController{
public ModelAndView method1(HttpServletRequest request,HttpServletResponse response){}
public ModelAndView method2(HttpServletRequest request,HttpServletResponse response){}
}
配置参数 MethodNameResolver 进行方法名的调用
① InternalPathMethodNameResolver
<!-- 配置Controller -->
<bean id= "multiActionController" class ="com.springmvc.controller.MyMultiActionController">
<property name ="methodNameResolver">
<bean class ="org.springframework.web.servlet.mvc.multiaction.
InternalPathMethodNameResolver">
</bean>
</property>
</bean>
访问的url为: localhost:8080/SpringMVCStudy
/multi/method1 //访问MyMultiActionController的method1方法
localhost:8080/SpringMVCStudy
/multi/method2 //访问MyMultiActionController的method2方法
②ParameterMethodNameResolver
<!-- 配置Controller -->
<bean id= "multiActionController" class ="com.springmvc.controller.MyMultiActionController">
<property name ="methodNameResolver">
<bean class ="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName" value="method" /> <!-- value代表方法的参数 -->
</bean>
</property>
</bean>
访问的url为: localhost:8080/SpringMVCStudy/multi/xxx.action?method=index //只需要method为上面配置的value
localhost:8080/SpringMVCStudy/multi/xxx.action?method=hello
③PropertiesMethodNameResolver
不常用,必须与SimpleUrlHandlerMapping配合使用,一个定位controller,一个定位method
方法二 : 使用代理对象;不用继承MultiActionController类,定义MultiActionController的
delegate属性即可
<!-- 配置包含多方法的controller -->
<bean id="
multiMethodController" class="com.springmvc.controller.MultiMethodController"> //自己定义的
</bean>
<!-- 配置代理controller对象 -->
<bean id="proxyController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
<property name="methodNameResolver"> //配置methodName解析器
<bean class ="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver">
</bean>
</property>
<property name="delegate"> //配置delegate属性,指向自定义的多方法的controller
<ref bean="multiMethodController" />
</property>
</bean>
视图解析器 ViewResolver
在SpringMVC中可以同时
定义多个ViewResolver 视图解析器,然后会组成一个
ViewResolver链,当Controller处理器方法返回一个逻辑视图名称后,ViewResolver链将根据其中ViewResolver的
优先级来进行处理。所有的ViewResolver实现了Ordered接口,在ViewResolver通过
order属性来制定顺序,值越小,优先级越高。
InternalResourceViewResolver 可以
解析所有的视图,永远返回一个
非空的View对象,一定要
放在ViewResolver链的最后
1 . InternalResourceViewResovler
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp" /> //前缀
<property name="suffix" value=".jsp" /> //后缀
</bean>
例如: Controller返回一个ViewName为
index
的 ModelAndView 对象
则视图解析器将根据配置的前缀后后缀寻找到
/WEB-INF/jsp/index.jsp //根据配置的前缀和后缀拼成
2 . AbstractCachingViewResolver
3 . UrlBasedViewResolver
4 . XmlViewResolver
5 . BeanNameViewResolver
6 . ResourceBundleViewResolver
7 . FreeMarkerViewResolver
8 . VolocityViewResolver
基于注解的SpringMVC
--
Spring可已通过 @Controller 注解自动发现你的控制器类以及 @RequestMapping 注解中的请求映射
1 . 免去了在Bean配置文件中的配置,
2 . 控制器和处理程序方法在访问上下文资源(请求参数、模型属性、会话属性)也会更加灵活
1 . 注解配置
需要引入mvc命名空间
<mvc:annotation-driven /> //自动注册RequestMappingHandlerMapping 与 RequestMappingHandlerAdapter
-RequestMappingHandlerMapping 匹配HandlerMapping的关系
-RequestMappingHandlerAdapter 调用method前对参数进行处理
<context:component-scan base-package="com.mj.controller" /> //扫描包中的注解.
2 . 具体使用
2.1 @Controller
@Controller对应的是
后端控制器(Controller)的Bean,使用注解@Controller标记的Bean
不需要继承SpringMVC框架提供的类或实现接口,
一切使用了@Controller标记的类都是Spring容器管理的Controller,此时在Spring容器中会存在一个名字为首字母小写的控制器。如果指定value值,则使用value值做bean的名字
对于一个普通的POJO(Bean),只有@Controller注解时,只是向spring容器申明了它是一个
Controller,但此时
并不具有真正controller的功能。真正让其具有SpringMVC Controller功能的是@RequestMapping注解
2.2 @RequestMapping
@RequestMapping请求路径映射
① 标注在类处: 将Controller与特定的请求关联起来
② 标注在方法处: 对请求进行进一步的分流(分配到不同的方法上)
参数:
value: 指定请求的实际url
method:指定请求的method类型,GET,POST等 (RequestMethod.POST)
params: 设置参数必须包含的内容,才会处理该方法
headers:设置请求头必须包含的内容
consumes : 指定请求的提交内容(Content-Type) 例如 : application/json , text/html
produces : 指定返回的内容类型 例如: text/plain
方法的返回值可以为多种类型
@RequestMapping支持的 Ant风格和带{xxx}占位符的URL:
/user/*/login : 匹配/user/aaa/login, /user/任意字符/login等
/user/**/login : 匹配/user/login, /user/aaa/bbb/login等
/user/login?? : 匹配/user/loginAA , /user/loginbb 等
/user/{userId} : 匹配 /user/123 , /user/234等
/user/**/{userId} : 匹配/user/aaa/bbb/123 , /user/aaa/234等
2.3 @PathVariable
@PathVariable 标记为请求路径
变量,即在url中的
参数的标记
① 在RequestMapping中使用
{ }包含变量名
② 在方法的参数中,在对应的变量前注解 @PathVariable
③ 若两个参数不同名,则将RequestMapping中的变量名赋给PathVariable: @PathVariable("xxx");
2.4 @RequestParam
@RequestParam也是用来传递参数的,但是是从 request 的参数里取值,
相当于 request.getParameter("参数名")的方法,取值规则和@PathVariable一样
以 2.1 2.2 2.3 2.4共同举例
@Controller //为类注解@Controller
@RequestMapping("/blog") //为类注解@RequestMapping,指定请求为/blog
public class AnnotationController{ //普通POJO
/* 最普通的注解方式 */
@RequestMapping("index") //为方法注解RequestMapping,指定请求方法url为/index
public String index(HttpServletRequest request,HttpServletResponse response){
....
return "index";
}
/* 带有参数的注解,使用PathVariable */
@RequestMapping("/detail/{name}") //为方法注解RequestMapping,并带有参数id,指定请求方法为/detail/
public String detail(
@PathVariable String
name){ //为方法参数注解@PathVariable,对应url参数
...
return "detail";
}
/* 带有参数注解,使用PathVariable("param")来申明参数 */
@RequestMapping("/content/{id}") //注解RequestMapping,定有url参数id
public String content(
@PathVariable("id") String contentID){
... //由于参数名与上面不同,则@PathVariable中申明对应url参数
return "content";
}
/* 带有两个或多个参数的注解,分别对每个参数使用@PathVariable */
@RequestMapping("/dictionary/{name}/{id}") //注解RequestMapping,带有两个参数name,id
public String dictionary(
@PathVariable String
name ,
@PathVariable String
id){
... //配置PathVariable,分别对应url的不同参数
return "dictionary";
}
/* 使用RequestParam传值,无需再RequestMapping中配置,只需在方法的参数里申明*/
@RequestMapping("/comment")
public String comment(@RequestParam int id ,@RequestParam("name") String username){
... //配置@RequestParam,默认从request中取值
return "comment";
}
}
2.5 @ModelAttribute
@ModelAttribute通过在Controller方法的参数上使用该注解来实现模型与页面数据的绑定,要求表单数据的name属性与Model的属性名称相同。
//相关的Controller
@Controller
@RequestMapping("/course")
public class Course{
@RequestMapping("/add")
public String add(
@ModelAttribute Course course){
....
return "/course/detail";
}
}
//相关的Model
public class Course{
private String
courseName;
private String
courseType;
private String
courseIntro;
public String getCourseName(){
return this.courseName
}
....
....
}
//相关的表单
<form action="course/add" method="post">
<input type="text" name="
courseName" />
<!-- name属性与Model中的属性对应 -->
<input type="text" name="
courseType" />
<input type="textarea" cols="10" name="
courseIntro" />
<input type="submit" value="提交" />
</form>
异常处理
SpringMVC处理异常有三种方式:
(1) 使用SpringMVC提供的简单的异常处理器
SimpleMappingExceptionResolver;
(2) 实现Spring的异常处理接口
HandlerExceptionResolver 自定义自己的异常处理器;
(3) 使用
@ExceptionHandler 注解实现异常处理
1 . SimpleMappingExceptionResolver
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 定义
默认的异常处理页面,当异常发生时跳转至该页面 -->
<property name="
defaultErrorView" value="error" />
<!-- 定义异常处理页面中用于获取
异常信息的变量名,
默认为
exception -->
<property name="
exceptionAttribute" value="ex" />
<!-- 定义需要
特殊处理的异常,用类名或全路径名作为key,异常页名作为值 -->
<property name="
exceptionMappings">
<props>
<prop key="com.springmvc.MyException">error-my</prop>
</props>
</property
</bean>
2 . 实现
HandlerExceptionResolver,
覆写resolveException,跟据参数Exception的类型进行view的跳转
public class MyExceptionHandler
implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response , Object handler ,
Exception ex){
if(ex instanceof MyException){
return new ModelAndView("error_my");
}else{
return new ModelAndView("error");
}
}
}
然后在xxx-servlet.xml中配置该异常处理器ExceptionHandler
<bean id = "myExceptionHandler" class="com.springmvc.exception.MyExceptionHandler" />
3 . @ExceptionHandler 注解
@ExceptionHandler注解
应该注解在一个Controller的方法里,当该Controller中任何一个方法发生异常,则会被该方法拦截。
@Controller
public class MyController{
@ExceptionHandler(Exception.class)
public String catchException(Exception exception, ModelMap modelMap){
return "error";
}
}
使用注解的方法,则需要在xxx-servlet.xml中配置
<context-component-scan base-package="com.springmvc.exception" />
四大注解类(Controller / Component / Service / Repository)
① Controller 标注web控制器 ,在上面已介绍过
② Component 通用标注
③ Service 标注Service层的服务
④ Respository 标注DAO层的数据访问
拦截器 Interceptor
SpringMVC中的Interceptor 拦截请求时通过HandlerInterceptor类实现。在SpringMVC定义Interceptor:
① 定义Interceptor类,实现
HandlerInterceptor接口
推荐
② 定义Interceptor类,继承Spring提供的
抽象类 HandlerInterceptorAdapter;
推荐
③ 定义Interceptor类,实现WebRequestInterceptor接口
1 . 实现 HandlerInteceptor 接口
① preHandler() 在
业务处理器处理请求之前被调用,对request进行处理,
返回值若为
false,则
拦截该请求,不再继续向下传递
返回值若为
true,则
继续向下执行
参数:Object arg2 为被拦截的请求的目标对象
② postHandler() 在
业务处理器处理请求之后被调用,也就是在
Controller方法调用之后执行,可以对ModelAndView
进 行操作, 在当前Interceptor的
preHandler返回值为true才会执行。
参数:ModelAndView arg3 为请求处理后返回的ModelAndView对象,可拦截该对象改变显示的视图和Model
③ afterCompletion() 在
DispatcherServlet完全处理完请求之后被调用,可以进行一些资源清理的操作。需要当前对应
的Interceptor的
preHandler方法返回值为true
2 . 注册拦截器
通过mvc:interceptors 标签注册或HandlerMapping上拦截
<!-- 通过mvc标签注册 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/*" /> //需要拦截的url地址
<bean class="com.springmvc.interceptor.MyInterceptor"/> //自定义的Interceptor
</mvc:interceptor>
</mvc:interceptors>
<!-- 在HandlerMapping上拦截 -->
<bean id="simpleUrlHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.springmvc.interceptor.MyInterceptor" />
</list>
</property>
</bean>
3 . 多个拦截器协同工作时
4 . 使用场景
使用原则:处理所有请求的共同问题
1、解决乱码问题
2、解决权限验证问题
SpringMVC 文件上传
SpringMVC & JSON
ContentNegotiatingViewResolver
ResponseEntity
@ResponseBody / @RequestBody
相关网页收藏
http://haohaoxuexi.iteye.com/blog/1753271 SpringMVC Controller
http://www.admin10000.com/document/6436.html 史上最强SpringMVC
http://www.iteye.com/blogs/subjects/springMVC SpringMVC介绍