Spring MVC,即 Spring Model-View-Controller,是一个实现了通用开发模式(模型-视图-控制器)的Web框架,它经过一个DispatcherServlet处理HTTP请求、完成资源映射、递交请求给控制器完成业务逻辑,相应数据则经过Model传递给视图解析器解析为相应的页面或数据流返回给客户端。
这里,咱们能够经过Spring官方给出的图示大体了解其内部的工做机制: 前端
DispatcherServlet做为前端控制器(Front Controller)过滤全部客户端发来的请求,检查请求路径并根据配置好的映射规则,将请求提交给指定的控制器(Controller),完成业务逻辑处理(好比,数据库访问),生成数据模型(model),传递给指定视图解析器(Spring内部已为咱们定义好的一系列模板,拿来用便可)解析为相应的视图数据,最后返回客户端响应。 web
其实,比如咱们最初学习Java Web开发同样,首先要在web.xml文件中配置DispatcherServlet: spring
01 |
<!-- Spring Dispatcher Servlet--> |
03 |
<servlet-name>SpringDispatcher</servlet-name> |
04 |
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> |
06 |
<param-name>contextConfigLocation</param-name> |
07 |
<param-value>classpath:config/springDispatcher.xml</param-value> |
09 |
<load-on-startup>1</load-on-startup> |
12 |
<servlet-name>SpringDispatcher</servlet-name> |
13 |
<url-pattern>/</url-pattern> |
这里配置了名为SpringDispatcher的Servlet,处理全部客户端的请求,contextConfigLocation参数指明了同时要加载的Spring MVC配置信息。 数据库
既然SpringDispatcher会过滤全部的请求,那若是请求的是静态资源的话,咱们这样作就有点得不偿失了。不过不用担忧,Spring MVC为咱们提供了处理静态资源的解决办法: json
在springDispatcher.xml文件中,引入spring mvc标记,并添加<mvc:resource>标签便可: spring-mvc
01 |
<?xml version="1.0" encoding="UTF-8"?> |
02 |
<beans xmlns="http://www.springframework.org/schema/beans" |
03 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
04 |
xmlns:mvc="http://www.springframework.org/schema/mvc" |
06 |
http://www.springframework.org/schema/mvc |
07 |
http://www.springframework.org/schema/mvc/spring-mvc.xsd |
08 |
http://www.springframework.org/schema/beans |
09 |
http://www.springframework.org/schema/beans/spring-beans.xsd> |
10 |
<!-- Handle requests for static resources --> |
11 |
<mvc:resources mapping="/resources/**" location="/resources/"/> |
如上所配置,<mvc:resources>会将全部直接返回以/resources/开始的静态资源请求,而不会经过SpringDispatcher进行处理。 mvc
DispatcherServlet配置好后,接下来就须要建立咱们的控制器类了,Spring MVC里咱们能够经过组件扫描来注册咱们所写的控制器,自动织入所需的bean: app
1 |
http://www.springframework.org/schema/context |
2 |
http://www.springframework.org/schema/context/spring-context.xsd> |
4 |
<!-- Enable annotation-driven features --> |
5 |
<mvc:annotation-driven/> |
7 |
<!-- Enable component-scan features --> |
8 |
<context:component-scan base-package="com.alan"/> |
控制器类以下:
02 |
@RequestMapping("/user") |
03 |
public class UserController { |
05 |
private final UserService userService; |
08 |
public UserController(UserService userService) { |
09 |
this.userService = userService; |
12 |
@RequestMapping("/queryAll") |
13 |
public String queryAll(@RequestParam("type") int type, Model model) { |
15 |
List<User> users = userService.findAll(); |
16 |
model.addAttribute("users", users); |
经过注解技术,咱们能够很方便的将咱们的业务类注册给控制器,在初始化时由Spring容器帮咱们完成依赖注入。其中@RequestMapping注解则告诉Spring全部以“/user”开始的请求将由UserController来处理,而"/user/queryAll"则交由queryAll方法处理。@RequestParam则会接收URL请求参数,这里为type,而且自动转化为对应的参数类型。Model即为数据模型,由Spring提供,咱们能够将处理后的结果数据绑定到Model上,返回Model给指定视图解析器。queryAll方法最后的return "UserList"意思是告诉视图解析器返回哪个页面。这里咱们须要再增长视图解析器的配置到springDsipatcher.xml中:
1 |
<!-- Configure view resolver --> |
2 |
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
3 |
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> |
4 |
<property name="prefix" value="/WEB-INF/views/"/> |
5 |
<property name="suffix" value=".jsp"/> |
以上XML配置代表,咱们使用JstlView视图(支持JSTL),而且返回“/WEB-INF/views/”下面全部以“.jsp”为后缀的文件。本例中,即为“
/WEB-INF/views/UserList.jsp
”。
是否是很easy呢?不过,可能有的同窗要问了,若是我不想返回页面,而是直接返回字符串或者IO流怎么办。好吧,Spring框架固然也想到了。咱们能够在方法上增长@ResponseBody标记以代表直接返回响应内容,而不是转交视图解析器处理,就像下面这样:
框架
01 |
@RequestMapping("/queryAll2") |
03 |
public String queryAll2(@RequestParam("type") int type) { |
04 |
JSONObject jsonObj = new JSONObject(); |
06 |
List<User> users = userService.findAll(); |
07 |
jsonObj.put("users", users); |
09 |
return jsonObj.toString(); |
咱们便可很轻松的返回字符串数据,好比返回JSON字符串。 jsp
InternalResourceViewResolver一般使用转发的方式返回页面数据。若是咱们须要重定向到某个页面,则能够在方法返回的时候增长“redirect:”标记便可:
1 |
return "redirect:/UserList"; |
固然,若是须要转发至某个Controller的方法也很方便:
1 |
return "forward:/user/queryAll2?type=2" |
此外,常常使用Struts的同窗也比较喜欢表单数据绑定到Model的功能以减轻本身获取全部请求参数的繁琐工做,Spring亦有提供实现。便可经过@ModelAttribute标记获取表单参数(这须要Spring MVC所提供的form tag库的支持):
2 |
public class HelloWorldController { |
4 |
@RequestMapping(value = "/helloWorld", method=RequestMethod.POST) |
5 |
public String helloWorld(@ModelAttribute User user) { |
好像还少了点什么对不对?是的,我若是要在Controller里得到ServletContext对象呢?别担忧,只要咱们implements ServletContext便可,这样咱们就能够在Controller里获取Servlet上下文,于是什么request、response都不在话下了,这里给出一个上传JPG图片的例子:
02 |
@RequestMapping("/upload") |
03 |
public class FileUploadController implements ServletContextAware { |
05 |
private ServletContext servletContext; |
07 |
public void setServletContext(ServletContext servletContext) { |
08 |
this.servletContext = servletContext; |
11 |
@RequestMapping("/jpg") |
12 |
public String uploadJPG(@RequestParam("image") MultipartFile image, Model model) { |
14 |
if(!image.isEmpty()) { |
15 |
validateImage(image, "image/jpeg"); |
17 |
model.addAttribute("img", "resources/upload" + File.separator + image.getName()); |
19 |
} catch (UploadImageException e) { |
20 |
model.addAttribute("msg", e.getMessage()); |
26 |
private void saveImage(MultipartFile image) throws UploadImageException { |
27 |
String name = image.getName(); |
29 |
File file = new File(servletContext.getRealPath("/resources/upload") + File.separator + name); |
30 |
FileUtils.writeByteArrayToFile(file, image.getBytes()); |
31 |
} catch (IOException e) { |
32 |
throw new UploadImageException("保存图片出错!"); |
37 |
private void validateImage(MultipartFile image, String type) throws UploadImageException { |
38 |
if(!image.getContentType().equals(type)) { |
39 |
throw new UploadImageException("只接受JPG格式的文件!"); |
还有,还有,记得咱们常常会用到Session来保存一些共享数据,Spring MVC里能够在Controller上加上@SessionAttributes标记来完成这个功能:
02 |
@RequestMapping("/user") |
03 |
@SessionAttributes("user") |
04 |
public class UserController { |
06 |
private final UserService userService; |
09 |
public UserController(UserService userService) { |
10 |
this.userService = userService; |
惊喜远远不只如此,Spring MVC还提供了更多,这里再也不一一列举,有了以上的这些简单介绍,想必
你
对Spring MVC的开发模式有了必定的了解,不得不说这个框架用起来其实仍是蛮方便、蛮体贴的。