什么是MVC?
模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计思想。它主要通过分离模型,视图以及控制器在应用程序中的角色将业务逻辑从界面中解耦。通常,模型负责封装应用程序数据在视图层展示。视图层仅仅是展示这些数据,不包含任何业务逻辑。控制器负责接收来自用户的请求,并调用后台服务(service或dao)来处理业务逻辑处理后, 后台业务层可能会返回了一些数据在视图层展示。 控制器收集这些数据及准备模型在视图层展示。 MVC 模式的核心思想是将业务逻辑从界面中分离出来, 允许它们单独改变而不会相互影响。
SpringMVC是什么?
Spring MVC 是 Spring 家族中的一个 web 成员, 它是一种基于 Java 的实现了 Web MVC 设计思想的请求驱动类型的轻量级 Web 框架, 即使用了 MVC 架构 模式的思想, 将 web 层进行职责解耦, 基于请求驱动指的就是使用请求-响应模型, 框架的目的就是帮助我们简化开发, Spring MVC 也是要简化我们日常Web 开发的。Spring MVC 是服务到工作者思想的实现。 前端控制器是DispatcherServlet; 应用控制器拆为处理器映射器(Handler Mapping)进行处理器管理和视图解析器(View Resolver)进行视图管理; 支持本地化/国际化(Locale) 解析及文件上传等; 提供了非常灵活的数据验证、 格式化和数据绑定机制; 提供了强大的约定大于配置(惯例优先原则) 的契约式编程支持。
SpringMVC可以帮助我们做什么?
- 让我们能非常简单的设计出干净的 Web 层;
- 进行更简洁的 Web 层的开发;
- 天生与 Spring 框架集成(如 IoC 容器、 AOP 等);
- 提供强大的约定大于配置的契约式编程支持;
- 能简单的进行 Web 层的单元测试;
- 支持灵活的 URL 到页面控制器的映射;
- 非常容易与其他视图技术集成, 如 Velocity、 FreeMarker 等等,因为模型数据不放在特定的 API 里, 而是放在一个Model (Map 数据结构实现, 因此很容易被其他框架使用);
- 非常灵活的数据验证、 格式化和数据绑定机制, 能使用任何对进行数据绑定, 不必实现特定框架的 API;
- 支持灵活的本地化等解析;
- 更加简单的异常处理;
- 对静态资源的支持;
- 支持 Restful 风格
SpringMVC框架简析
1.SpringMVC请求处理流程分析
SpringMVC框架是一个基于请求驱动的web框架,并且使用了前端控制器模式进行处理。
SpringMVC请求处理流程:
1.首先用户发送请求,请求被SpringMVC前端控制器(DispatherServlet)捕获;
2.前端控制器对请求URL解析获取URI,根据URI调用HandlerMapping;
3.前端控制器获得返回的HandlerExecutionChain包括(Handler 对象以及 Handler 对象对应的拦截器 );
4.DispatcherServlet 根据获得的HandlerExecutionChain,选择一个合适的HandlerAdapter;
5.HandlerAdapter根据请求的Handler适配并执行对应的Handler;
HandlerAdapter(提取 Request 中的模型数据, 填充 Handler 入参, 开始执行 Handler(Controller)。 在填充 Handler 的入参过程中, 根据配置, Spring 将做一些额外的工作:
HttpMessageConveter: 将请求消息(如 Json、 xml 等数据) 转换成一个对象, 将对象转换为指定的响应信息。
数据转换: 对请求消息进行数据转换。 如 String 转换成 Integer、 Double等
数据格式化: 对请求消息进行数据格式化。 如将字符串转换成格式化数字
或格式化日期等
数据验证: 验证数据的有效性(长度、 格式等) , 验证结果存储到
BindingResult 或 Error 中)
6.Handler执行完毕,返回一个ModelAndView(即模型和视图)给HandlerAdaptor;
7.HandlerAdaptor适配器将执行结果ModelAndView返回给前端控制器;
8.前端控制器接收到ModelAndView后,请求对应的视图解析器;
9.视图解析器解析ModelAndView后返回对应的view;
10.渲染视图并返回渲染后的视图给前端控制器
11.最终前端控制器将渲染后的页面响应给用户或客户端
2.SpringMVC核心架构图
3.SpringMVC的优势
1.清晰的角色划分: 前端控制器(DispatcherServlet) 、 请求到处理器映射(HandlerMapping) 、 处理器适配器(HandlerAdapter) 、 视图解析器ViewResolver) 、 处理器或页面控制器(Controller) 、 验证器( Validator) 、 命令对象(Command 请求参数绑定到的对象就叫命令对 象) 、 表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象) 。
2、 分工明确, 而且扩展点相当灵活, 可以很容易扩展, 虽然几乎不需要;
3、 和 Spring 其他框架无缝集成, 是其它 Web 框架所不具备的;
4、 可适配, 通过 HandlerAdapter 可以支持任意的类作为处理器;
5、 可定制性, HandlerMapping、 ViewResolver 等能够非常简单的定制;
6、 功能强大的数据验证、 格式化、 绑定机制;
7、 利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试;
8、 本地化、 主题的解析的支持, 使我们更容易进行国际化和主题的切换。
9、 强大的 JSP 标签库, 使 JSP 编写更容易。还有比如 RESTful(一种软件架构风格, 设计风格而不是标准, 只是提供了一组设计原则和约束条件。 它主要用于客户端和服务器交互类的软件, 目前了解即可) 风格的支持、 简单的文件上传、 约定大于配置的契约式编程支持、 基于注解的零配置支持等等。
SpringMvc 注解特性
1.@Controller控制器定义
在spring3.0中,通过@Controller注解即可将一个class定义为一个controller类。为了使spring能够找到定义为cotroller的bean,需要在spring-context配置文件中增加如下定义:
<context:component-scan base-package="com.shsxt.controller"/>
注:实际上,使用@component,也可以起到@Controller 同样的作用。
2.@RequestMapping地址绑定
在类前面定义,则将url和类绑定;在方法前面定义,则将url和类的方法绑定。
//url: http://localhost:8080/springmvc01/hello2/test01
@RequestMapping("test01")
public ModelAndView test01(){
ModelAndView mv=new ModelAndView();
mv.setViewName("hello");
mv.addObject("hello", "hello test01");
return mv;
}
//url: http://localhost:8080/springmvc01/hello2?test01
@RequestMapping(params="test02")
public ModelAndView test02(){
ModelAndView mv=new ModelAndView();
mv.setViewName("hello");
mv.addObject("hello", "hello test02");
return mv;
}
//url: http://localhost:8080/springmvc01/hello2/test03
@RequestMapping("test03")
public String test03(Model model){
model.addAttribute("hello", "hello test03");
return "hello";
}
3.@RequestParam参数绑定
请求参数到处理器功能处理方法的方法参数上的绑定, 对于参数绑定非常灵活
4.@SessionAttributes
用于声明 session 级别存储的属性, 放置在处理器类上
@Controller
@SessionAttributes({"userName"})// userName 放入 session
public class UserController {
@RequestMapping("/queryUser")
public ModelAndView queryUser(String userName){
ModelAndView mv=new ModelAndView();
mv.addObject("userName", userName);
mv.setViewName("user");
return mv;
}
}
页面取值
<body>
${sessionScope.a}|||${sessionScope.b}
</body>
请求转发与重定向
Springmvc 默认采用服务器内部转发的形式展示页面信息。同样也支持重定向页面
@RequestMapping("/queryView")
public String queryView1(){
return "redirect:v1.jsp?a=123";
}
获取request,response对象
public ModelAndView queryUser(HttpServletRequest request,HttpServletResponse response){
String userName= request.getParameter("userName");
ModelAndView mv=new ModelAndView();
mv.addObject("userName", userName);
mv.setViewName("request");
return mv;
}
ModelAndView 模型视图类
ModelAndView 中的 Model 代表模型,View代表视图。即,这个类把要显示的数据存储到了 Model 属性中,要跳转的视图信息存储到了 view 属性。
SpringMVC之Json数据开发
@ResponseBody该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到 Response 对象的 body 数据区。
@RequestBody该注解用于读取 Request 请求的 body 部分数据,使用系统默认配置的HttpMessageConverter 进行解析,然后把相应的数据绑定到要返回的对象上 ,再把HttpMessageConverter 返回的对象数据绑定到 controller 中方法的参数上 。
SpringMVC之拦截器
SpringMVC 中的 Interceptor 拦截器也是相当重要和相当有用的,它的主要作
用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断
用户是否登陆等操作。
对于 springmvc 拦截器的定义方式有两种方式
- 实现接口: org.springframework.web.servlet.HandlerInterceptor
- 继承适配器
org.springframework.web.servlet.handler.HandlerInterceptorAdapter
SpringMVC之环境搭建
idea+jdk1.8+maven+jetty
1.新建web工程
2.导入依赖
<!-- spring web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring mvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- web servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<!-- 添加json 依赖jar包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 添加文件上传 依赖jar包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
3.配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- 表示容器启动时 加载上下文配置 这里指定spring 相关配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:*.xml</param-value>
</context-param>
<!-- 启用spring容器环境上下文监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 编码过滤 utf-8 -->
<filter>
<description>char encoding filter</description>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- servlet请求分发器 -->
<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:servlet-context.xml</param-value>
</init-param>
<!-- 表示启动容器时初始化该Servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<!-- 这是拦截请求, /代表拦截所有请求,拦截所有请求 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.servlet-context.xml 配置
<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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
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.xsd">
<!-- 扫描com.shsxt.controller 下包 -->
<context:component-scan base-package="com.shsxt.controller" />
<!-- mvc 请求映射 处理器与适配器配置-->
<mvc:annotation-driven/>
<!--配置视图解析器 默认的视图解析器- -->
<bean id="defaultViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="contentType" value="text/html" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- json 支持 -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
</list>
</property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<mvc:exclude-mapping path="/user/login"/>
<bean class="com.shsxt.interceptor.LoginInteceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
</beans>
5.页面控制器的编写
/**
* 采用注解扫描形式
*/
@Controller
public class HelloController {
/**
* 请求映射地址 /hello.do
* @return
*/
@RequestMapping("/hello")
public ModelAndView hello(){
ModelAndView mv=new ModelAndView();
mv.addObject("hello", "hello spring mvc");
mv.setViewName("hello");
return mv;
}
}
6.添加视图页面
在 WEB-INF 下新建 jsp 文件夹 ,并在文件加下新建 hello.jsp
SpringMVC之文件上传
依赖与配置上面已经有了,直接进行代码编写
@Controller
public class FileController {
@RequestMapping("fileUpload")
@ResponseBody
public ResultInfo fileUpload(HttpServletRequest request){
ResultInfo info = new ResultInfo();
// 1. 强转
MultipartHttpServletRequest mr = (MultipartHttpServletRequest) request;
// 2. 获取上传文件
MultipartFile file = mr.getFile("file");
if (null != file && !file.isEmpty()){
// 3. 获取上传文件目录
String path = request.getSession().getServletContext().getRealPath("upload");
// 4. 获取上传文件名
String filename = file.getOriginalFilename();
// 5. 存储
try {
file.transferTo(new File(filename));
info.setCode(200);
info.setMsg("上传成功");
} catch (IOException e) {
e.printStackTrace();
info.setCode(300);
info.setMsg("上传失败!");
}
}else {
info.setCode(300);
info.setMsg("文件不存在!");
}
return info;
}
}
HTML页面
<form action="uploadFile.do" method="post" enctype="multipart/formdata">
<input type="file" name="file" />
<button type="submit"> 提交</button>
</form>