作者: gh-xiaohe
gh-xiaohe的博客
觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分
M:Model,模型层,指工程中的JavaBean,作用是处理数据
JavaBean分为两类:
V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据
C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器
MVC的工作流程:
用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器
SpringMVC是Spring的一个后续产品,是Spring的一个子项目
SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。
注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet
①用户用过视图层将请求发送到服务器,在服务器中请求被Controller接收
②Controller(调用相对应servlet处理业务逻辑,service在调用dao层来进行数据的操作 —> 将数据库访问的结果在 返回给 service 在返回到控制层 )调用响应的Model层处理请求,处理完毕将结果返回给Controller,Controller在根据请求处理的结果找到相应的Veiw视图,渲染数据后最终响应给浏览器
浏览器中以不同的方式来发送一个请求 ,超链接,form表单,发送一个请求,需要根据请求的地址,来找到相对应的servlet,在servlet中(servlet的声明周期 三个方法) 获取请求参数来调用 service 来处理 业务逻辑 service处理完业务逻辑后,返回一个结果。 比如查询操作 把数据放到指定的域对象中、或者说登录功能,需要把用户信息放到session中 处理数据后,根据结果,根据service处理业务逻辑之后的结果,来选择不同的方式,响应浏览器
在spring mvc,所以封装的,所封装的功能的servlet中,把我们处理请求的过程都进行了封装。
1.创建Maven工程 --> web工程 —> war包 依赖
2.web.xml
① 默认方式: ② 拓展方式:
a.前端控制器b.
路径 <init-param> <param-name>contextConfigLocationparam-name> <param-value>classpath:springMVC.xmlparam-value> init-param>
c.将初始化时间提前,不在第一次请求时生效
<load-on-startup>1load-on-startup>
注解 + 扫描的方式
3.创建请求控制器(注解)
4.配置SpringMVC的配置文件(扫描)
5.测试访问 Hello World
①实现对首页的访问
②通过超链接跳转到制定页面
打包方式 war 包、依赖
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>SpringMVC-demo1artifactId>
<version>1.0-SNAPSHOTversion>
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.3.1version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.thymeleafgroupId>
<artifactId>thymeleaf-spring5artifactId>
<version>3.0.12.RELEASEversion>
dependency>
dependencies>
project>
provided已被提供:当前的服务器中已经提供了servlet jar包
在此时把工程打成war包之后 这个 servlet的 jar包就不会 存在于当前打的 war 之后的 web-info 下的 lib中 这个jar包由服务器提供
完成
此配置作用下,SpringMVC 的配置文件默认位于 WEB-INF 下,默认名称为 《servlet-name>-servlet.xml,例如,以下配置所对应 SpringMVC 的配置文件位于 WEB-INF 下,文件名为 springMVC-servlet.xml
<servlet>
<servlet-name>springMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>springMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
可通过 init-param 标签设置 SpringMVC 配置文件的位置和名称,通过 load-on-startup 标签设置 SpringMVC 前端控制器 DispatcherServlet 的初始化时间
<servlet>
<servlet-name>springMVCservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:springMVC.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>springMVCservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
注解 + 扫描组件的方式
创建一个控制类 (HelloController) 并声明控制层注解 @Controller
一个类标识为IOC容器的注解有四个
@Compoment --> 普通组件
@Controller --> 控制层组件
@Server --> 业务层组件
@Repository --> 持久层组件
@Controller
public class HelloController {
}
由于前端控制器对浏览器发送的请求进行了统一的处理,但是具体的请求有不同的处理过程,因此需要创建处理具体请求的类,即请求控制器
请求控制器中每一个处理请求的方法成为控制器方法
因为 SpringMVC 的控制器由一个 POJO(普通的 Java 类)担任,因此需要通过 @Controller 注解将其标识为一个控制层组件,交给 Spring 的 IoC 容器管理,此时 SpringMVC 才能够识别控制器的存在
xml (可以直接复制剪贴使用)
<context:component-scan base-package="com.atguigu.mvc.controller">context:component-scan>
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
bean>
property>
bean>
property>
bean>
想要跳转到index.html 是不可以的
why? WEB-INF 下面的内容 通过浏览器是不是直接访问的、通过重定向也是不可以直接访问的 只能通过转发来进行访问
通过视图解析器,来解析我们当前的视图
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/templates/">property>
<property name="suffix" value=".jsp">property>
bean>
当控制器方法中,仅仅用来实现页面跳转,即只需要设置视图名称时,可以将处理器方法使用view-controller标签进行表示
@RequestMapping("/")
public String index() {
return "index";
}
@RequestMapping("/test_view")
public String testView() {
return "test_view";
}
可以书写成
<mvc:view-controller path="/" view-name="index">mvc:view-controller>
<mvc:view-controller path="/test_view" view-name="test_view">mvc:view-controller>
<mvc:annotation-driven />
<mvc:default-servlet-handler/>
注:
当SpringMVC中设置任何一个view-controller时,其他控制器中的请求映射将全部失效,此时需要在SpringMVC的核心配置文件中设置开启mvc注解驱动的标签:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="defaultCharset" value="UTF-8" />
<property name="supportedMediaTypes">
<list>
<value>text/htmlvalue>
<value>application/jsonvalue>
list>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
<filter>
<filter-name>CharacterEncodingFilterfilter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
init-param>
<init-param>
<param-name>forceResponseEncodingparam-name>
<param-value>trueparam-value>
init-param>
filter>
<filter-mapping>
<filter-name>CharacterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
注意:
①SpringMVC中处理编码的过滤器一定要配置到其他过滤器之前,否则无效
②设置请求编码的前提条件:如果在此之前已将获取了某一个请求参数,所设置的编码没有效果
使用put delect 请求 HiddenHttpMethodFilter 隐藏的http的请求方式
<filter>
<filter-name>HiddenHttpMethodFilterfilter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
注意:
有多个过滤器时,过滤器的执行顺序有决定,配置的越靠前,就先执行
目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter
原因:
在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的
request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作
而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:
String paramValue = request.getParameter(this.methodParam);
依赖
<dependency>
<groupId>commons-fileuploadgroupId>
<artifactId>commons-fileuploadartifactId>
<version>1.3.1version>
dependency>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">bean>
<!--配置方式一: bean-->
<mvc:interceptors>
<!--所写的拦截器 路径-->
<!--一个bean就是IOC的组件(对象) 表示某一个类型的对象就是一个拦截器-->
<bean class="com.atguigu.interceptor.FirstInterceptor"></bean>
</mvc:interceptors>
<!--配置方式二: ref-->
<!--ref引用IOC容器中的某个bean的id,引用某一个拦截器的id-->
<mvc:interceptors>
<!--所写的拦截器 类名 需要使用普通组件注解@Component 表示为IOC容器 + 扫描 -->
<ref bean="firstInterceptor"></ref>
</mvc:interceptors>
<!-- 以上两种配置方式都是对DispatcherServlet所处理的所有的请求进行拦截,没有办法设置拦截规则 -->
<!--配置方式三:--> (推荐)
<mvc:interceptors>
<mvc:interceptor>
<!--需要拦截的请求-->
<mvc:mapping path="/**"/>
<!--需要排除的请求,即不需要拦截的请求-->
<mvc:exclude-mapping path="/testRequestEntity"/>
<!--和上面的两种写法一样 bean 或者 ref-->
<ref bean="firstInterceptor"></ref>
</mvc:interceptor>
</mvc:interceptors>
<!--
以上配置方式可以通过ref或bean标签设置拦截器,通过mvc:mapping设置需要拦截的请求,通过mvc:exclude-mapping设置需要排除的请求,即不需要拦截的请求
-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.ArithmeticException">errorprop>
props>
property>
<property name="exceptionAttribute" value="ex">property>
bean>
//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {
//@ExceptionHandler用于设置所标识方法处理的异常
@ExceptionHandler(value = {ArithmeticException.class, NullPointerException.class})
//ex表示当前请求处理中出现的异常对象
public String handleArithmeticException(Exception ex, Model model){
model.addAttribute("ex", ex);
return "error";
}
}
@Controller
public class HelloController {
// 通过@RequestMapping注解,可以通过请求路径匹配要处理的具体的请求
// /表示的当前工程的上下文路径
@RequestMapping("/")
public String index(){
return "index";
// -> WEB-INF\templates\index.html
// -> 去掉前缀WEB-INF\templates
// -> 去掉后缀.html
}
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页title>
head>
<body>
<h1>首页h1>
body>
html>
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>首页title>
head>
<body>
<h1>首页h1>
<a th:href="@{/hello}">HelloWorlda><br />
body>
html>
在里面写入:
DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>Titletitle>
head>
<body>
HelloWorld
body>
html>
@RequestMapping("/hello")
public String HelloWorld() {
return "target";
}
①浏览器发送请求,若请求地址符合前端控制器的 url-pattern
②该请求就会被前端控制器 DispatcherServlet 处理。
③前端控制器会读取 SpringMVC 的核心配置文件,通过扫描组件找到控制器
④将请求地址和控制器中 @RequestMapping 注解的 value 属性值进行匹配,
⑤若匹配成功,该注解所标识的控制器方法就是处理请求的方法。
⑥处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被视图解析器解析,加上前缀和后缀组成视图的路径
⑦通过 Thymeleaf 对视图进行渲染,
⑧最终转发到视图所对应页面。