一,什么是MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
总结:
MVC就是类似三层的一种架构,主要还是采用封装(分层)的思想,来降低耦合度,从而使我们的系统更加的灵活,扩展性更好。
结构:
Model(模型) |
是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。 |
View(视图) |
是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。 |
Controller(控制器) |
是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据 |
优点:
重用性 |
多个视图能共享一个模型。同一个模型可以被不同的视图重用,大大提高了代码的可重用性。 |
松耦合 |
由于MVC的三个模块相互独立,改变其中一个不会影响其他两个,所以依据这种设计思想能构造良好的松耦合的构件。 |
灵活性/可配置性 |
控制器提高了应用程序的灵活性和可配置性。控制器可以用来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。 |
缺点:
复杂性 |
对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。 |
紧密性 |
视图与控制器是相互分离,但是却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。 |
低效率访问 |
视图对模型数据的低效率访问,根据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,会损害操作性能。 |
二,Spring MVC
Spring MVC框架是一个开源的Java平台,为开发强大的基于Java的Web应用程序提供全面的基础架构支持非常容易和非常快速。
Spring MVC的特点:
1、轻量
2、高效
3、与Spring兼容性好
4、功能强大
5、简洁灵活
Spring MVC主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。他的两个核心是:
处理器映射器 |
选择使用哪个控制器来处理请求。 |
视图解析器 |
选择结果应该如何渲染。 |
通过以上两点,Spring MVC保证了如何选择控制处理请求和如何选择视图展现输出之间的松耦合。
三,Maven创建Spring MVC项目
1,创建Maven项目
具体创建项目教程请参考:创建Maven Web项目
2,添加依赖的jar包
修改pom.xml文件、添加jar包的依赖。
主要有:Spring框架核心库、Spring MVC、JSTL等,内容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Zender</groupId> <artifactId>SpringMVCDemo</artifactId> <version>0.0.1</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.0.RELEASE</spring.version> </properties> <dependencies> <!--Spring框架核心库 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> </project>
3,修改web.xml,注册中心控制器DispatcherServlet
Spring MVC框架像许多其他MVC框架一样,请求驱动,围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)。它处理所有的HTTP请求和响应。DispatcherServlet的请求处理工作流如下图所示:
以下是对应于到DispatcherServlet的传入HTTP请求的事件顺序:
1,在接收到HTTP请求后,DispatcherServlet会查询HandlerMapping(处理器映射器)以调用相应的Controller。
2,Controller接受请求并根据使用的GET或POST方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给DispatcherServlet。
3,DispatcherServlet将从ViewResolver(视图解析器)获取请求的定义视图。
4,当视图完成,DispatcherServlet将模型数据传递到最终的视图,并在浏览器上呈现。
修改web.xml文件注册该Servlet,web.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <servlet> <servlet-name>SpringMVC</servlet-name> <!-- Servlet类 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 启动顺序,数字越小,启动越早 --> <load-on-startup>1</load-on-startup> <init-param> <!--SpringMVC配置参数文件的位置 --> <param-name>contextConfigLocation</param-name> <!--默认名称为ServletName-servlet.xml --> <param-value>classpath*:SpringMVC-Servlet.xml</param-value> </init-param> </servlet> <!--所有请求都会被SpringMVC拦截 --> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
4,添加Spring MVC配置文件
在src/main/resources目录下添加SpringMVC-Servlet.xml配置文件,配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd"> <!-- 自动扫描包,实现支持注解的IOC --> <context:component-scan base-package="com.zender.controller" /> <!-- Spring MVC不处理静态资源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驱动 --> <mvc:annotation-driven /> <!-- 视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/WEB-INF/view/" /> <!-- 后缀 --> <property name="suffix" value=".jsp" /> </bean> </beans>
注意:
在视图解析中,把所有的视图都存放在/WEB-INF/目录下,这样是为了视图安全,因为这个目录客户端不能直接访问。
5,创建视图
在WEB-INF/view目录中创建视图,具体内容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 内容:${text} </body> </html>
6,创建控制器
创建一个普通的类HelloWorldController,内容如下:
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/HelloWorld") public class HelloWorldController { @RequestMapping("/Hello") public String Hello(Model model){ model.addAttribute("text", "Hello Spring MVC!"); return "hello"; } }
注意:
@Controller |
为了让Spring IOC容器初始化时自动扫描到。 |
@RequestMapping |
为了映射请求路径。 |
这里因为类与方法上都有映射,所以访问时应该是/HelloWorld/Hello。方法中声明Model类型的参数是为了把Action中的数据带到视图中,方法返回的结果是视图的名称hello,也就是jsp/html文件的文件名。
7,测试
四,@RequestMapping详解
@RequestMapping注释用于映射url到控制器类或一个特定的处理程序方法。可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。该注解共有8个属性。源码如下:
/** * 用于映射url到控制器类或一个特定的处理程序方法. * 该注解只能用于方法或类型上 */ @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface RequestMapping { /** * 指定映射的名称 */ String name() default ""; /** * 指定请求的路径映射,指定的地址可以是uri模板,别名为path */ @AliasFor("path") String[] value() default {}; /** 别名为value,使用path更加形象 * 只有用在一个Servlet环境:路径映射URI(例如“/myPath.do”)。 * Ant风格的路径模式,同时也支持(例如,“/myPath/*.do”)。在方法层面,在主要的映射在类型级别表示相对路径(例如,“edit.do”) * 的支持。路径映射的URI可能包含占位符(例如“/$ {}连接”) */ @AliasFor("value") String[] path() default {}; /** * 指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE. 收窄请求范围 The */ RequestMethod[] method() default {}; /** * 映射请求的参数,收窄请求范围 */ String[]params() default {}; /** * 映射请求头部,收窄请求范围 * RequestMapping(value = "/something", headers = "content-type=text/*") */ String[] headers() default {}; /** * 指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围 The */ String[] consumes() default {}; /** * 指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回 * produces = "text/plain" * produces = {"text/plain", "application/*"} * produces = "application/json; charset=UTF-8" */ String[] produces() default {}; }
1,value 属性
value 属性,指定请求的实际地址,指定的地址可以是URL模板,正则表达式或路径占位,该属性与path互为别名关系,@RequestMapping("/zender")} 与 @RequestMapping(path="/zender")相同。该属性是使用最频繁,最重要的一个属性,如果只指定该属性时可以把value略去。
例如:
1,只注解方法:
@Controller public class SpringMVCController { @RequestMapping("/zender") public String zender(){ return "zender/index"; } }
访问路径:http://localhost:8081/SpringMVCDemo/zender
2,同时注解类与方法:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping("/zender") public String zender(){ return "zender/index"; } }
访问路径:http://localhost:8081/SpringMVCDemo/SpringMVC/zender
3,当value为空值:
注解在方法上时,如果value为空则表示该方法为类下默认的Action。
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping("/zender") public String zender(Model model){ model.addAttribute("text", "zender方法"); return "zender/index"; } @RequestMapping public String zender2(Model model){ model.addAttribute("text", "zender2方法"); return "zender/index"; } }
访问zender2的路径是:http://localhost:8081/SpringMVCDemo/SpringMVC/
4,注解在类上时,当value为空值则为默认的控制器可以用于设置项目的起始页。
@Controller @RequestMapping public class SpringMVCController { @RequestMapping("/zender") public String zender(Model model){ model.addAttribute("text", "zender方法"); return "zender/index"; } @RequestMapping public String zender2(Model model){ model.addAttribute("text", "首页"); return "zender/index"; } }
访问zender2的路径是:http://localhost:8081/SpringMVCDemo/
5,路径变量占位的URI模板
在Spring MVC可以使用@PathVariable 注释方法参数的值绑定到一个URI模板变量。例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping("/zender/{p1}/{p2}") public String zender(@PathVariable int p1, @PathVariable int p2, Model model){ model.addAttribute("text", "结果:" + (p1 + p2)); return "zender/index"; } }
6,正则表达式模式的URI模板
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { //正则要求id必须为6位的数字,而name必须为3位小写字母 @RequestMapping("/zender/{id:\d{8}}-{name:[a-z]{6}}") public String zender(@PathVariable String id, @PathVariable String name, Model model){ model.addAttribute("text", "id:" + id + ",name:" + name); return "zender/index"; } }
7,Ant风格路径模式
@RequestMapping注解也支持ant风格的路径模式,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping("/zender/*.html") public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
2,method属性
method属性,用于约束请求的谓词类型,可以收窄请求范围。指定请求谓词的类型如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping(value="/zender/*.html" ,method={RequestMethod.POST}) public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
要访问zender请求谓词类型必须是POST,否则访问结果是405
将POST修改为GET,再次访问,就可以访问了:
3,consumes属性
consumes属性,指定处理请求的提交内容类型(Content-Type),例如application/json, text/html,收窄请求范围,如果用户发送的请求内容类型不匹配则方法不会响应请求,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping(value="/zender/*.html" ,consumes="text/html") public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
在zender的注解中约束发送到服务器的Content-Type必须是text/html类型,如果类型不一致则会报错(415)
更改Content-Type为text/html,再次访问:
4,produces属性
produces属性,指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回,方法才处理客户端的请求否则会报406错误,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping(value="/zender/*.html" ,produces="text/html") public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
更改produces属性等于application/json; charset=UTF-8
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { @RequestMapping(value="/zender/*.html" ,produces="application/json; charset=UTF-8") public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
再次访问:
5,params属性
params属性,映射请求的参数,收窄请求范围。可以限制客户端发送到服务器的请求参数为某些特定值或不为某些值,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { //请求的参数必须包含id=888,name=zender,age不等于18 @RequestMapping(value="/zender/*.html" ,params={"id=888","name=zender","age!=18"}) public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
访问地址:http://localhost:8081/SpringMVCDemo/SpringMVC/zender/1.html?id=888&name=zender&age=18
访问地址:http://localhost:8081/SpringMVCDemo/SpringMVC/zender/1.html?id=888&name=zender&age=19
6,headers属性
headers属性,映射请求头部,收窄请求范围。约束客户端发送的请求头部信息中必须包含某个特定的值或不包含某个值,例如:
@Controller @RequestMapping("/SpringMVC") public class SpringMVCController { //请求头部信息中必须包含Host=localhost:8082 @RequestMapping(value="/zender/*.html" ,headers="Host=localhost:8082") public String zender(Model model){ model.addAttribute("text", "zender"); return "zender/index"; } }
更改参数headers="Host=localhost:8081"或者修改Host为8082,再次访问: