MVC回顾
1:什么是MVC
MVC(Model View Controller)是一种软件设计的框架模式,它采用模型(Model)-视图(View)-控制器(controller)的方法把业务逻辑、数据与界面显示分离。把众多的业务逻辑聚集到一个部件里面,当然这种比较官方的解释是不能让我们足够清晰的理解什么是MVC的。用通俗的话来讲,MVC的理念就是把数据处理、数据展示(界面)和程序/用户的交互三者分离开的一种编程模式。
注意!MVC不是设计模式!
MVC框架模式是一种复合模式,MVC的三个核心部件分别是
1:Model(模型):所有的用户数据、状态以及程序逻辑,独立于视图和控制器
2:View(视图):呈现模型,类似于Web程序中的界面,视图会从模型中拿到需要展现的状态以及数据,对于相同的数据可以有多种不同的显示形式(视图)
3:Controller(控制器):负责获取用户的输入信息,进行解析并反馈给模型,通常情况下一个视图具有一个控制器
1.2:为什么要使用MVC
程序通过将M(Model)和V(View)的代码分离,实现了前后端代码的分离,会带来几个好处
1:可以使同一个程序使用不同的表现形式,如果控制器反馈给模型的数据发生了变化,那么模型将及时通知有关的视图,视图会对应的刷新自己所展现的内容
2:因为模型是独立于视图的,所以模型可复用,模型可以独立的移植到别的地方继续使用
3:前后端的代码分离,使项目开发的分工更加明确,程序的测试更加简便,提高开发效率
1.3:JavaWeb中MVC模式的应用
在JavaWeb程序中,MVC框架模式是经常用到的,举一个Web程序的结构可以更好的理解MVC的理念
V:View视图,Web程序中指用户可以看到的并可以与之进行数据交互的界面,比如一个Html网页界面,或者某些客户端的界面,在前面讲过,MVC可以为程序处理很多不同的视图,用户在视图中进行输出数据以及一系列操作,注意:视图中不会发生数据的处理操作。
M:Model模型:进行所有数据的处理工作,模型返回的数据是中立的,和数据格式无关,一个模型可以为多个视图来提供数据,所以模型的代码重复性比较低
C:Controller控制器:负责接受用户的输入,并且调用模型和视图去完成用户的需求,控制器不会输出也不会做出任何处理,只会接受请求并调用模型构件去处理用户的请求,然后在确定用哪个视图去显示返回的数据
1.4:Web程序中MVC模式的优点
耦合性低:视图(页面)和业务层(数据处理)分离,一个应用的业务流程或者业务规则的改变只需要改动MVC中的模型即可,不会影响到控制器与视图
部署快,成本低:MVC使开发和维护用户接口的技术含量降低。使用MVC模式使开发时间得到相当大的缩减,它使程序员(Java开发人员)集中精力于业务逻辑,界面程序员(HTML和JSP开发人员)集中精力于表现形式上
可维护性高:分离视图层和业务逻辑层也使得WEB应用更易于维护和修改
1.5:Web程序中MVC模式的缺点
调试困难:因为模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难,每个构件在使用之前都需要经过彻底的测试
不适合小型,中等规模的应用程序:在一个中小型的应用程序中,强制性的使用MVC进行开发,往往会花费大量时间,并且不能体现MVC的优势,同时会使开发变得繁琐
增加系统结构和实现的复杂性:对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率
视图与控制器间的过于紧密的连接并且降低了视图对模型数据的访问:视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能
Spring MVC请求响应
SpringMVC把视图渲染、请求处理、模型创建分离了,遵循了MVC框架模式的思想
SpringMVC的请求相应要经过七个阶段,蓝色的方框是Spring框架已经实现好的,第二阶段到第六阶段对应着Spring MVC中的一些核心理念,分别是前端控制器、处理映射器、控制器(处理器)、视图解析器、视图。要注意的是:前端控制器和控制器不是一个东西,前端控制器负责任务分发,控制器是模型的一部分,负责业务和数据的处理
SpringMVC核心控制类的请求流程
SpringMVC的请求相应步骤如下
1、用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获
2、DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回
3、DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
4、提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作
HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
1.数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
2.数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
3.数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5、Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象
6、根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet
7、ViewResolver 结合Model和View,来渲染视图
8、将渲染结果返回给客户端
基于xml和注解结合的springmvc入门案例:
目录结构:
项目所需的依赖:
<?xml version="1.0" encoding="UTF-8"?>
<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>groupId</groupId>
<artifactId>springmvc-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.24</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
再写项目之前需要看看这些包有没有打包,idea好像没有对这些打包,需要我们自己打包,新建lib,然后将所有的jar包都放进去。避免404
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">
<!--1.注册DispatcherServlet-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
<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>
<!--/ 匹配所有的请求;(不包括.jsp)-->
<!--/* 匹配所有的请求;(包括.jsp)-->
<!-- 只要用户发的请求都被拦截 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
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
http://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="controller"/>
<!-- 让Spring MVC不处理静态资源 .css ,.html,.mp3 .... -->
<!-- <mvc:default-servlet-handler />-->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/html/" />
<!-- 后缀 -->
<property name="suffix" value=".html" />
</bean>
</beans>
HelloController类:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello") //用户.../hello请求时
public String hello(Model model){
model.addAttribute("msg","hello");
return "hello"; //会被视图解析器解析 WEB-INF/html/hello.html,也就是跳转到hello.html
}
}
hello.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
大胆刁民还不下跪
</body>
</html>
运行结果:
纯注解实现springmvc案例
先了解一下RequestMapping的用法
使用@RequestMapping 注解映射请求路径即你可以使用@RequestMapping注解来将请求URL映射到整个类上或某个特定的方法上,即@RequestMapping 既可以定义在类上,也可以定义方法上
(1)映射单个URL
@RequestMapping("") 或 @RequestMapping(value="")
(2)映射多个URL
@RequestMapping({"",""}) 或 @RequestMapping(value={"",""})
路径开头是否加斜杠/均可,建议加上,如:@RequestMapping("/hello")
(3)限制请求方法的URL 映射
在HTTP 请求中最常用的请求方法是 GET、POST,还有其他的一些方法,如:DELET、PUT、HEAD 等
限制请求方法,例如:
@RequestMapping(value="/hello", method=RequestMethod.POST)
如需限制多个请求方法,以大括号包围,逗号隔开即可,例如:
method={RequestMethod.GET,RequestMethod.POST}
(4)限制请求参数的URL 映射
限制请求参数来映射URL,例如:
@RequestMapping(value="/user/show", params="userId")
参数的限制规则如下:
(1)params=“userId” 请求参数中必须包含 userId
(2)params="!userId" 请求参数中不能包含 userId
(3)params=“userId!=1” 请求参数中必须包含 userId,但不能为 1
(4)params={“userId”,“userName”} 必须包含 userId 和 userName 参数
目录结构:
依赖与上面都一样
initialzer类:
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
/**获取Spring应用容器的配置文件*/
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
//表明要求DispathcherServlet加载应用上下文时,使用定义在WebConfig配置类中的bean,(即使用Java配置)
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//将一个或多个路径映射到DispatcherServlet上,这里给定的是"/",意思是由DispatcherServlet处理所有向该应用发起的请求
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
WebConfig类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
/*@Configuration标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,
作用为:配置spring容器(应用上下文)*/
@EnableWebMvc
//相当于<mvc:annotation-driven/>
//注解就是为了引入一个DelegatingWebMvcConfiguration Java 配置类
@ComponentScan("Controller")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
// @Bean注册一个bean,就相当于我们之前写的一个bean标签.这个方法的名字,就相当丁bean 标签中的id属性。这个方法的返回值,就相当bean标签中的class属性
public ViewResolver viewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/html/");
viewResolver.setSuffix(".html");
return viewResolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
HelloController类:
package Controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HelloController {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
public String hello(Model model){
return "hello"; //会被视图解析器解析 WEB-INF/html/hello.html,也就是跳转到hello.html
//return "h";会被视图解析器解析 WEB-INF/html/h.html,也就是跳转到h.html
//但是要将之前tomcat打开的页面关掉要不然可能不显示。
}
}
新建一个h.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
老铁
</body>
</html>
hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
我是大胆刁民
</body>
</html>
运行结果:
