1. 简介
- M(
Model
)V(View
)C(Controller
),是一种软件设计规范
。 - 以
将业务逻辑、数据、显示分离
的方式来组织代码。 降低
了视图
与业务逻辑
间的双向耦合
。- SpringMVC是Spring Framework的一部分,基于Java实现MVC的轻量级Web框架
MVC
不是一种设计模式,而是一种架构模式
,当然不同的MVC存在差异
。
注:
设计模式
对在某种环境中反复出现的问题以及解决该问题的方案的描述,它比架构更抽象。架构模式
只是针对某一领域的具体实现,一个软件可能包含多种设计模式;而设计模式是一种思想,可适用于各种应用。- 简单来说,框架是软件,而设计模式是软件的知识。
Model (模型)
数据模型,提供要展示的数据,因此包含数据和行为。
可以认为是领域模型或JavaBean组件(包含数据和行为) 。
不过现在一般都分离开来:Value Object (数据Dao)和服务层(行为Service) 。
也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View (视图)
:
负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。
Controller (控制器)
:
接收用户请求,委托给模型进行处理(状态改变) ,处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作。最典型的MVC就是JSP + servlet + javabean的模式。
- 用户发送请求。
- Servlet接收请求数据并调用对应的业务逻辑方法。
- 业务处理完毕返回更新的数据给Servlet。
- Servlet发送到JSP来渲染页面。
- 响应给前端更新后的页面。
特点
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定由于配置
- 功能强大:RESTful、数据验证、格式化、本地化、主题等
- 简洁灵活
2、MVC的演变历史
2.1、Model1
优点
:架构简单,比较适合小型项目开发
缺点
:JSP职责不单一,职责过重,不便于维护
2.2、Model2
Model1虽已在一定程度上解耦,但JSP即要负责页面控制,又要负责逻辑处理,职责不单一。于是Model2应运而生,使得各个部分各司其职。 Model2基于MVC模式:
Controller:控制器
- 取得表单数据
- 调用业务逻辑
- 转向指定的页面
Model:模型
- 业务逻辑
- 保存数据状态
View:视图
- 显示页面
优点
:职责清晰,较适合于大型项目架构
缺点
:分层较多,不适合小型项目开发
区别
:
Model2 在 Model1 的基础上分离了控制,将JSP中的逻辑操作部分分离出来,这样做不仅减轻了JSP的职责,而且更有利于分工开发,耦合性降低。
2.3、三层
Model2巧妙的将JSP中的业务逻辑部分分给了Servlet,使得页面控制与逻辑处理彻底分离,达到了部分解耦的目的。但我们现实项目开发中,
往往在Model2的基础上又进行了分层。将业务逻辑细分为业务逻辑和持久化逻辑两层。
往往使用一个Dao接口隐藏持久化操作的细节,业务对象不需要了解底层的数据库持久化知识。使得业务逻辑与持久化逻辑分离,
业务逻辑通常关系的是应用程序的核心流程和业务规则,持久化逻辑关注的是如何访问和操作持久化数据。
3、SpringMVC工作原理
- 用户发送请求至前端控制器
DispatcherServlet
。 DispatcherServlet
收到请求调用HandlerMapping
处理器映射器。- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给
DispatcherServlet
。 DispatcherServlet
调用HandlerAdapter
处理器适配器。HandlerAdapter
经过适配调用具体的处理器(Controller
,也叫后端控制器)。Controller
执行完成返回ModelAndView
。HandlerAdapter
将controller执行结果ModelAndView
返回给DispatcherServlet
。DispatcherServlet
将ModelAndView
传给ViewReslover
视图解析器。ViewReslover
解析后返回具体View.DispatcherServlet
根据View进行渲染视图
(即将模型数据填充至视图中)。DispatcherServlet响应用户
。
4、Hello,SpringMVC(xml版)
4.1. 创建Maven工程,添加Web框架
4.2. 导入Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
4.3. 在resource目录下创建springmvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--处理器映射器HandlerMapping-->
<!--这个映射器会根据Bean名来找到Bean,实际开发一般不用-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器HandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--处理器Controller-->
<bean id="/myController" class="com.qhit.controller.MyController"/>
<!--视图解析器ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
4.4. 在web.xml中配置DispatcherServlet
<!--SpringMVC核心,前端控制器,请求分发 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定Spring配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别为1,与服务器同生-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--/:表示拦截除jsp页面之别的所有请求-->
<!--/*:拦截所有请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
4.5、编写处理器,配置映射
package com.qhit.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 返回一个ModelAndView对象给HandlerAdapter
ModelAndView mv = new ModelAndView();
// 调用service层
String result = "result";
// 封装执行结果
mv.addObject("result", result);
// 封装跳转地址
mv.setViewName("index");
return mv;
}
}
<!--处理器Controller-->
<bean id="myController" class="com.qhit.controller.MyController" />
4.6、配置Tomcat
4.7、可能遇到的问题
4.7.1、404
原因是jar包添加失败
接下来我们手动添加jar
- Shift+Control+Alt+S快捷键打开Project Structure
- 找到Artifacts,选中报错的项目,检查项目名,在WEB-INF下创建lib
3. 选中lib,点击+号,选择Library Files库文件,选中要添加的jar,确认
4.7.2、库源与类DispatcherServlet的字节码不符
检查maven依赖
4.7.3、1099 is already in use
方案一:按快捷键 Ctrl+Shift+Esc 打开任务管理器,找到java.exe,然后点击“结束任务”即可!
方式二:这种方式适用于所有端口被占用的情况
- 通过端口找到PID
打开dos命令行,输入netstat -ano | find “1099”,得到下列内容,看到最后一列是9280,就是PID:
- 通过PID找到进程
输入:tasklist | find “9280”(双引号里面的是PID)
- 关闭进程
输入命令关闭进程:taskkill /f /t /im java.exe
5、Hello,SpringMVC(注解)
5.1、 新建项目,导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
5.2、配置DispatcherServlet
<!--SpringMVC核心,前端控制器,请求分发 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定Spring配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!--启动级别为1,与服务器同生-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--/:表示拦截除jsp页面之别的所有请求-->
<!--/*:拦截所有请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
5.3、配置springmvc.xml
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--自动扫描包,使包下注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.qhit.controller"/>
<!--设置SpringMVC不处理静态资源-->
<mvc:default-servlet-handler/>
<!---->
<!--支持mvc注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册
DefaultAnnotationHandlerMapping、AnnotationMethodHandLerAdapter实例
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。-->
<mvc:annotation-driven/>
<!--视图解析器ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
5.4、HelloController
package com.qhit.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/hello") //访问地址:/项目名/hello
public class HelloController{
//访问地址:/项目名/hello/h1
@RequestMapping("/h1")
public String hello(Model model){/* model:向前端传递数据 */
model.addAttribute("msg", "hello, springmvc!");
return "hello"; //view名称,会被视图解析器解析
}
}
5.5、配置Tomcat,运行。如上
5.6、注解
@RestController
修饰类,方法直接返回JSON数据,跳过视图解析器
@ResponseBody
将java对象转为json格式的数据。
@Controller
控制层类注解,声明一个类是bean,放入IOC容器,相当于@Component
@PathVariable
加在控制器入参上,用于接收Restful风格的参数。
//访问地址:/项目名/hello/h1
@RequestMapping(path = "/h1/{a}/{b}", method = RequestMethod.DELETE)
@GetMapping //简化
public String hello(@PathVariable int a,@PathVariable int b, Model model){/* model:向前端传递数据 */
model.addAttribute("msg", "hello, springmvc!");
return "hello"; //view名称,会被视图解析器解析
}
6、Restful风格
Restful就是一个资源定位及资源操作的风格。
不是标准也不是协议。
基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等。
7、JSON
7.1、简介
- JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
- JSON 是轻量级的文本数据交换格式
- JSON 独立于语言:JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON 库支持许多不同的编程语言。 目前非常多的动态(PHP,JSP,.NET)编程语言都支持JSON。
- JSON 具有自我描述性,更易理解
7.1.1、与 XML 的异同
- 异
- JSON 是纯文本 JSON 具有"自我描述性"(人类可读)
- JSON 具有层级结构(值中存在值)
- JSON 可通过 JavaScript
- 进行解析 JSON 数据可使用 AJAX 进行传输
- 同
- 没有结束标签
- 更短
- 读写的速度更快
- 能够使用内建的 JavaScript eval() 方法进行解析
- 使用数组
- 不使用保留字
7.1.2、为什么使用 JSON?
对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:
使用 XML
- 读取 XML 文档
- 使用 XML DOM 来循环遍历文档
- 读取值并存储在变量中
使用 JSON
- 读取 JSON 字符串
- 用 eval() 处理 JSON 字符串
7.2、语法
- 数据在名称/值对中
- 数据由逗号分隔
- 大括号 {} 保存对象
- 中括号 [] 保存数组,数组可以包含多个对象,例:
{
"sites": [
{ "name":"菜鸟教程" , "url":"www.runoob.com" },
{ "name":"google" , "url":"www.google.com" },
{ "name":"微博" , "url":"www.weibo.com" }
]
}
可以像这样访问 JavaScript 对象数组中的第一项(索引从 0 开始):
sites[0].name;
返回的内容是:
runoob
可以像这样修改数据:
sites[0].name="菜鸟教程";
7.3、JSON乱码问题
<!--JSON解决乱码问题-->
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="utf-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
7.4、Jackson
7.4.1、maven依赖
<!--Jackson包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
7.4.2、Controller编写
package com.qhit.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController//Controller + ResponseBody
public class HelloController {
//访问地址:/项目名/hello/h1
@GetMapping(path = "/h1")
//@ResponseBody // 返回值不会经过视图解析器,会直接返回字符串
public String hello() throws JsonProcessingException {
return new ObjectMapper().writeValueAsString(new User("1", "Candy"));
}
@GetMapping("h2")
public String jsonDate() throws JsonProcessingException {
ObjectMapper om = new ObjectMapper();
//关闭时间戳(时间解析后的默认格式为:时间戳TimeStamp)
om.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
//定义时间格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
om.setDateFormat(sdf);
return om.writeValueAsString(new Date());
}
}
7.4、FastJSON
7.4.1、依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
7.4.2、Controller编写
8、工具
Lombok
参考文献
框架和设计模式的区别 忘崖
浅析Java开发模式—Model1、Model2和三层 想太多先森