SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是DispatcherServlet,DispatcherServlet负责转发每一个Request请求给相应的Handler,Handler处理以后再返回相应的视图(View)和模型(Model),返回的视图和模型都可以不指定,即可以只返回Model或只返回View或都不返回。
DispatcherServlet是继承自HttpServlet的,既然SpringMVC是基于DispatcherServlet的,那么我们先来配置一下DispatcherServlet,好让它能够管理我们希望它管理的内容。HttpServlet是在web.xml文件中声明的。
02 |
< servlet-name >blog</ servlet-name > |
04 |
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > |
05 |
< load-on-startup >1</ load-on-startup > |
08 |
< servlet-name >blog</ servlet-name > |
10 |
< url-pattern >*.do</ url-pattern > |
上面声明了一个名为blog的DispatcherServlet,该Servlet将处理所有以“.do”结尾的请求。在初始化DispatcherServlet的时候,SpringMVC默认会到/WEB-INF目录下寻找一个叫[servlet-name]-servlet.xml的配置文件,来初始化里面的bean对象,该文件中对应的bean对象会覆盖spring配置文件中声明的同名的bean对象。如上面的就会在/WEB-INF目录下寻找一个叫blog-servlet.xml的文件;当然也可以在Servlet中声明配置文件的位置。
03 |
< servlet-name >blog</ servlet-name > |
04 |
< servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > |
06 |
< param-name >contextConfigLocation</ param-name > |
08 |
< param-value >/WEB-INF/blog-servlet.xml</ param-value > |
10 |
< load-on-startup >1</ load-on-startup > |
14 |
< servlet-name >blog</ servlet-name > |
15 |
< url-pattern >*.do</ url-pattern > |
DispatcherServlet会利用一些特殊的bean来处理Request请求和生成相应的视图返回。
关于视图的返回,Controller只负责传回来一个值,然后到底返回的是什么视图,是由视图解析器控制的,在jsp中常用的视图解析器是InternalResourceViewResovler,它会要求一个前缀和一个后缀
2 |
class = "org.springframework.web.servlet.view.InternalResourceViewResolver" > |
3 |
< property name = "prefix" value = "/WEB-INF/" /> |
4 |
< property name = "suffix" value = ".jsp" /> |
在上述视图解析器中,如果Controller返回的是blog/index,那么通过视图解析器解析之后的视图就是/WEB-INF/blog/index.jsp。
要使用注解的SpringMVC需要在SpringMVC的配置文件中进行声明,具体方式为先引入mvc命名空间,然后利用<mvc:annotation-driven />进行声明。
01 |
< beans xmlns = "http://www.springframework.org/schema/beans" |
02 |
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:context = "http://www.springframework.org/schema/context" |
03 |
<span style = "background-color:#00ff00;" >< span style = "color:#ff0000;" >xmlns:mvc="http://www.springframework.org/schema/mvc"</ span ></ span > xsi:schemaLocation="http://www.springframework.org/schema/beans |
04 |
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
05 |
http://www.springframework.org/schema/context |
06 |
http://www.springframework.org/schema/context/spring-context-3.0.xsd |
07 |
< span style = "background-color:#00ff00;color:#ff0000;" > http://www.springframework.org/schema/mvc |
08 |
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"</ span >> |
10 |
< mvc:annotation-driven /> |
主要是说说Controller.
一个类使用了@Controller进行标记的都是Controller
2 |
public class BlogController { |
有了Controller之后,那么到底是怎样请求一个Controller具体的方法的呢,那是通过@RequestMapping来标记的,@RequestMapping可以标记在类上面,也可以标记在方法上,当方法上和类上都标记了@RequestMapping的时候,那么对应的方法对应的Url就是类上的加方法上的,如下面的index方法,其对应的URL应为类上的/blog加上index方法上的/index,所以应为/blog/index,所以当请求/blog/index.do的时候就会访问BlogController的index方法。
02 |
@RequestMapping ( "/blog" ) |
03 |
public class BlogController { |
06 |
@RequestMapping ( "/index" ) |
07 |
public String index(Map<String, Object> map) { |
在上面的代码中,如果index方法上没有RequestMapping注解,而只有BlogController类上有,且该类只有一个方法的时候,直接请求类上的URL就会调用里面的方法,即直接请求/blog.do的时候就会调用index方法。
在RequestMapping中还可以指定一个属性method,其主要对应的值有RequestMethod.GET和RequestMethod.POST,利用该属性可以严格的控制某一方法只能被标记的请求路径对应的请求方法才能访问,如指定method的值为GET,则表示只有通过GET方式才能访问该方法,默认是都可以访问。
在SpringMVC中常用的注解还有@PathVariable,@RequestParam,@PathVariable标记在方法的参数上,利用它标记的参数可以利用请求路径传值,看下面一个例子
1 |
@RequestMapping (value= "/comment/{blogId}" , method=RequestMethod.POST) |
2 |
public void comment(Comment comment, @PathVariable int blogId, HttpSession session, HttpServletResponse response) throws IOException { |
在该例子中,blogId是被@PathVariable标记为请求路径变量的,如果请求的是/blog/comment/1.do的时候就表示blogId的值为1. 同样@RequestParam也是用来给参数传值的,但是它是从头request的参数里面取值,相当于request.getParameter("参数名")方法。
在Controller的方法中,如果需要WEB元素HttpServletRequest,HttpServletResponse和HttpSession,只需要在给方法一个对应的参数,那么在访问的时候SpringMVC就会自动给其传值,但是需要注意的是在传入Session的时候如果是第一次访问系统的时候就调用session会报错,因为这个时候session还没有生成。
接下来讨论一下方法的返回值,主要有一下情况:
- 返回一个ModelAndView,其中Model是一个Map,里面存放的是一对对的键值对,其可以直接在页面上使用,View是一个字符串,表示的是某一个View的名称
- 返回一个View,也就是一个字符串,这个时候如果需要给页面传值,可以给方法一个Map参数,该Map就相当于一个Model,往该Model里面存入键值对就可以在页面上进行访问了
- 返回一个Model也就是一个Map,这个时候将解析默认的生成的view name。
- 什么也不返回,这个时候可以利用HttpServletResponse进行返回,也可以直接使用printStream进行返回
下面是一个简单的实例
01 |
@RequestMapping ( "/{owner}/index" ) |
02 |
public String userIndex(Map<String, Object> map, @PathVariable String owner, HttpServletRequest request) throws ParserException { |
03 |
List<DefCategory> categories = categoryService.find(owner); |
04 |
int offset = Util.getOffset(request); |
05 |
Pager<Blog> pager = blogService.find(owner, 0 , offset, maxResults); |
06 |
int totalRecords = pager.getTotalRecords(); |
07 |
List<Blog> blogs = pager.getData(); |
08 |
Util.shortBlog(blogs); |
10 |
List<Message> messages = messageService.find(owner, 0 , 5 ).getData(); |
11 |
Util.shortMessage(messages, 20 ); |
12 |
map.put( "messages" , messages); |
13 |
map.put( "totalRecords" , totalRecords); |
14 |
List<BlogStore> stores = storeService.find(owner, 0 , 5 ).getData(); |
15 |
map.put( "maxResults" , maxResults); |
16 |
map.put( "blogs" , blogs); |
17 |
map.put( "totalRecords" , totalRecords); |
18 |
map.put( "owner" , userService.find(owner)); |
19 |
map.put( "defCategories" , categories); |
20 |
map.put( "stores" , stores); |
21 |
return "blog/userIndex" ; |