零、什么是MVC
模型(Dao+Service)、视图(JSP)、控制器(Servlet)
是一种软件设计规范
将业务、逻辑、数据进行分离。
Model(模型):数据模型、包含数据和行为,可以认为是领域模型或者JavaBean组件,不过现在一般表示为:Value Object(数据Dao)和服务层(行为Service)。也就是提供了子模型数据查询和模型数据状态的更新等功能,包括数据和业务。
前端 数据传输 实体类
View(视图):负责进行模型展示,一般就是我们见到的用户界面,客户想看到的东西
Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据交给视图,也就是说控制器负责调度。
最典型的MVC就是JSP+servlet+Javabean
pojo:User
- vo:UserVo——视图层实体类
- dto:数据传输的实体类
Model-1时代
- web早期的开发中,通常采用的是Model-1的模式
- Model-1中,主要分为两层:视图层+模型层
Model-1优点:架构简单,比较适合小型项目的开发
Model-1缺点:JSP职责不单一,职责过重,不利于维护;
项目架构是设计好的还是逐步演进的
答:演进的
阿里巴巴《淘宝的十年革命》
王坚——>提出去IOE——>MySQL—>AliSQL+ALiRedis
All in One——>微服务
Model-2时代
Model-2把一个项目分成三个部分:视图+控制+模型
- 用户发布请求
- Servlet接收请求数据,并调用对应的业务逻辑
- 业务处理完成,返回更新后的数据给Servlet
- Servlet转向JSP,由JSP来渲染页面
- 响应给前端更新后的页面
职责分析
Controller层:控制层
- 取得表单的数据
- 调用业务逻辑
- 转向指定的页面
Model层:模型层
- 业务逻辑
- 保存数据的状态
View:视图层
- 显示页面
优点:提高代码的复用率和项目的扩展性,大大降低了项目的维护成本。
控制层(controller)的职能是负责读取视图表现层的数据,控制用户的输入,并调用业务层的方法;
业务层(service)需要根据系统的实际业务需求进行逻辑代码的编写,有些业务逻辑需要通过与数据库交互的,则业务逻辑层需要调用数据访问层的相关方法实现与数据库的交互,对于一些不需要与数据库进行交互的,则直接编写业务代码,将执行结果反馈给控制层即可;
数据访问层(dao)只负责与数据库的数据交互,将数据进行存储读取操作
MVC框架要做哪些事情
- 将URL映射到Java类或者Java类的方法
- 封装用户提交的数据
- 处理请求—调用相关的业务处理—封装响应数据
- 将响应的数据进行渲染,JSP/HTML 等表示层数据。
一、SpringMVC
SpringMVC 是 Spring Framework的一部分,是基于java实现MVC的轻量级Web框架。
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html
SpringMVC的特点:
- 轻量级、简单易学
- 高效、基于请求响应的MVC框架
- 与Spring兼容性好,无缝结合
- 约定优于配置
- 功能强大:REST ful -URL地址风格、数据验证、格式化、本地化、主题等
- 简洁灵活
1、中心控制器
Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。从Spring2.5开始,使用Java5或者以上版本的用户可以采用基于注解的controller什么方式。
SpringMVC 框架像许多其他MVC框架一样,以请求委屈的,围绕一个中心Servlet分配请求以及提供其他功能,DispatcherServlet是一个实际的Servlet(他继承自HTTPServlet基类)
SpringMVC原理
SpringMVC执行原理图
实现代表SpringMVC框架提供的技术,不需要开发者实现,
虚线表示需要开发者自己实现
简要分析执行流程
1.DispatcherServlet表示前置控制器,是整个SpringMVC 的控制中心。用户发出请求,DispatcherServlet 接收请求并拦截请求。
- 假设我们请求的url为:http://localhost:8080/SpringMVC/hello
- 如上url拆成三部分
- http://localhost:8080/ 服务器域名
- /SpringMV/部署在服务器上的web站点
- hello表示控制器
- 通过分析,如上的url表示为==>请求位于服务器localhost:8080上的SpringMVC站点的hello控制器
2.HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求的url查找Handler
3.HandlerExecution表示具体的Handler,其主要的作用是根据URL查找控制器,如上url被查找控制器为hello;
4.HandlerExecution将解析后的信息传递给DispatcherServlet如解析控制器映射等;
5.HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。
6.Handler让具体的Controller执行;
7.Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView;
8.HandlerAdapter将视图逻辑名或者模型传递给DispatcherServlet;
9.DispatcherServlet 调用视图解析器(View Resolver)来解析HandlerAdapter传递的逻辑视图名。
- 获得了ModelAndView的数据
- 解析ModelAndView的视图名
- 拼接视图名字,找到对应的视图
10.视图解析器将解析的逻辑视图名传递给DispatcherServlet。
11.DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图;
12.最终呈现给用户。
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- DispatcherServlet:SpringMVC的核心:请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</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>
<!-- 在 SpringMVC中 / /*
/ 只匹配所有的请求,不会匹配jsp页面
/* 会匹配所有的请求,包括jsp页面-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置Spring配置文件
-
处理器映射器
-
处理器适配器
-
视图解析器
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!-- 处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!-- 视图解析器:模板引擎:Thymeleaf Freemarker-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB_INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!-- BeanNameUrlHandlerMapping: bean-->
<bean id="/hello" class="com.lsw.controller.HelloController"/>
</beans>
controller层
**
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//业务代码
String result = "HelloSpringMVC";
mv.addObject("msg",result);
//视图跳转路径
mv.setViewName("test");
//需要返回给view的值
return mv;
}
}
前端
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h2>${msg}</h2>
</body>
</html>
2、注解模式开发
第一步:导包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.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.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.74</version>
</dependency>
</dependencies>
第二步:配置资源过滤\
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
第三步:配置web.xml
- 注册DispatcherServlet
- 关联SpringMVC 配置文件
- 启动级别为1
- 映射路径为/
<!-- DispatcherServlet:SpringMVC的核心:请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</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>
<!-- 在 SpringMVC中 / /*
/ 只匹配所有的请求,不会匹配jsp页面
/* 会匹配所有的请求,包括jsp页面-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
第四步:添加SpringMVC配置文件springmvc-servlet.xml
- 让IOC的注解生效
- 静态资源过滤:HTML、JS、CSS、图片、视频等
- MVC注解驱动
- 配置视图解析器
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描包,让指定的包下的注解生效,有IOC容器统一管理-->
<context:component-scan base-package="com.lsw.controller"/>
<!-- 让SpringMVC不出来静态资源-->
<mvc:default-servlet-handler/>
<!-- 支持MVC注解驱动
在spring中一般采用的是@RequestMapping注解来完成映射关系
要想使用@RequestMapping注解生效
必须向上下文注册DefaultAnnotationHandlerMapping
和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理
而annotation-driven配置帮助我们自定完成上述两个实例的注入!
-->
<mvc:annotation-driven/>
<!-- 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
在视图解析器中我们把所有的视图都存放在/WEB-INF/目录下,这样可以保证视图的安全,因为这个目录下文件客户端是不能直接访问的。
第五步:创建Controller
@Controller
public class HelloController {
//url请求
@RequestMapping("/hello")
public String hello(Model model){
//封装数据
model.addAttribute("msg","Hello,SpringMVcAnnotation!");
//返回的字符串就是我们要的视图的名字。会被视图解析器处理
return "hello";
}
}
@Controller
是为了让Spring IOC容器初始化是自动扫描到@RequestMapping("/hello")
是为了映射请求路径- 方法中声明的Model类型的参数就是为了吧Action中的数据带到视图层中
- 方法返回的结果是视图的名称hello,加上配置文件中的前后缀就是我们访问的jsp页面
第六步:拿到数据展示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
注解模式小结
- 新建一个web项目
- 导入相关的jar包
- 编写web.xml,注册DispatcherServlet
- 编写SpringMVC配置文件
- 接下来就是创建对应的控制类,controller
- 最后完善前端视图和controller之间的对应关系
- 测试运行调试
使用SpringMVC的必须配置的三大件:
-
处理器映射器
-
处理器适配器
-
视图解析器
通常,我们只需要 手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可完成,而省去大段xml配置。
3、Controller
控制器Controller
- 控制器负责提供访问应用程序的行为,通常通过接口定义或者注解定义两种方式来实现。
- 控制器负责解析用户的请求并将其转化为一个模型。
- 在SpringMVC中一个控制器类可以有多个方法
- 在SpringMVC中,对于一个Controller的配置方式有很多种
注解方式
web.xml——配置DispatchServlet
<!-- 配置DispatchServlet-->
<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:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
springmvc-servlet.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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.lsw.controller"/>
<!-- <mvc:default-servlet-handler/>-->
<!-- <mvc:annotation-driven/>-->
<!-- 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
Controller类
@Controller
//代表这个类会被Spring接管
//被这个注解的类中的所有方法,如果返回值是String并且具有页面可以跳转,那么就会被视图解析器解析。
public class ControllerTest2 {
@RequestMapping("/t2")
public String hello(Model model){
model.addAttribute("msg","Hello_ControllerTest2");
return "test";
}
}
@Controller
被这个注解的类中的所有方法,如果返回值是String并且具有页面可以跳转,那么就会被视图解析器解析。
@RequestMapping
- @RequestMapping 注解用于映射url到控制器类或者一个特定的处理程序的方法。可以用于类或者方法上,用于类上,表示这个类中的所有响应请求的方法都是以该地址作为父路径。
- 同时注解类和方法,表示父路径和子路径
4、RestFul风格
概念:RestFul风格就是一个资源定位以及资源操作的风格,不是标准也不是协议,只是一种风格,基于这种风格设计的软件可以更简洁更有层次更易于实现缓存等机制
功能:
- 资源:互联网中的所有事务都可以被抽象为资源
- 资源操作::使用POST、DELETE、PUT、GET使用不同方法对资源进行操作。
- 分别对应 添加、删除、修改、查询
传统的方式操作资源:通过不同的参数来实现不同的效果。方法较为单一,只有post、get
http://localhost/item/querylem?id=1 ——>查询GET
新增和更新——post
删除——post/get
使用ResFul风格操作资源:可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可能不同
- http://localhost/item/1 查询GET
- http://localhost/item 新增POST
- http://localhost/item 更新PUT
- http://localhost/item/1 删除DELETE
传参风格
过去的方式传参:http://localhost:8000/add?a=1&b=3
RestFul风格传参:http://localhost:8000/add/a/b
需要使用@PathVariable
注解,让方法参数的值对应绑定到一个URL模板变量上。
@RequestMapping("/add/{a}/{b}")
public String test_1(@PathVariable int a,@PathVariable int b, Model model){
int res = a + b;
model.addAttribute("msg","结果为:"+res);
return "test";
}
约束类型
我们可以在@RequestMapping中加入method来约束类型
@RequestMapping(value = "/add/{a}/{b}",method = RequestMethod.GET)
public enum RequestMethod {
GET,
HEAD,
POST,
PUT,
PATCH,
DELETE,
OPTIONS,
TRACE;
}
所有的地址栏请求默认的是GET类型
方法级别的注解约束类型的变体:
@GetMapping("/add/{a}/{b}")
@PostMapping
@PutMapping
@DeleteMapping
优点:简单、安全、高效-支持缓存
5、结果跳转方式
5.1、ModelAndView
设置ModelAndView对象,根据view名称,和视图解析器跳到指定的页面。
页面位置:【视图解析器前缀】+ viewName +【视图解析器后缀】
<!-- 视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀-->
<property name="suffix" value=".jsp"/>
</bean>
5.2、ServletAPI方式
通过设置ServletAPI,不想需要设置视图解析器。
- 通过HTTPServletResponse进行输出
resp.getwriter().println("Hello,Spring By Servlet Api")
- 通过HTTPServletResponse实现重定向
resp.sendReairect("/index.jsp")
- 通过HTTPServletResponse实现转发
req.getRequestDispathcher(/test.jsp).forward(req.rsp)
@Controller
public class ModelTest_1 {
@RequestMapping("/m1/t1")
public String test(HttpServletRequest request, HttpServletResponse response){
HttpSession session = request.getSession();
System.out.println("session=="+session);
return "test";
}
}
5.3、SpringMVC方式
不配置视图解析器的情况下
通过SpringMVC来实现转发和重定向-无需视图解析器
测试前需要将视图解析器注释掉
@RequestMapping("/m1/t1")
public String test(Model model){
model.addAttribute("msg","This is ModelTest1 ");
//转发
return "/WEB-INF/jsp/test.jsp";
}
@RequestMapping("/m1/t2")
public String test2(Model model){
model.addAttribute("msg","This is ModelTest2 ");
//转发
return "forward:/WEB-INF/jsp/test.jsp";
}
@RequestMapping("/m1/t3")
public String test3(Model model){
model.addAttribute("msg","This is ModelTest2 ");
//重定向
return "redirect:/index.jsp";
}
配置了视图解析器的情况下
@RequestMapping("/m1/t1")
public String test(Model model){
model.addAttribute("msg","This is ModelTest1 ");
//转发
return "test.jsp";
}
@RequestMapping("/m1/t2")
public String test(Model model){
model.addAttribute("msg","This is ModelTest1 ");
//重定向
return "redirect:/index.jsp";
}