Spring MVC 简介
传统的 MVC 架构 web 开发
-
Model1
- 早期的 Java Web开发,统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来操作,称之为
Model1
- 弊端:
- JSP 和 JavaBean 的耦合太高 大量的Java 代码和 HTML 耦合在一起
- 开发者的前后端水平都要高 前后端高度依赖
- 代码不好复用等
- 早期的 Java Web开发,统一把显示层、控制层、数据层的操作全部交给 JSP 或者 JavaBean 来操作,称之为
-
Model2
-
model1
很快就被servlet + JSP + JavaBean
替代 早期的model2
-
MVC三层架构很明显了
-
-
Spring MVC
- 为了解决持久层的一直没有解决好的数据库事务编程的问题 迎合
NoSql
的崛起,Spring MVC给出了一种解决
-
NoSQL,指的是非关系型的数据库,用于超大规模的存储
-
传统的模型层被拆分为了业务层(Service)和数据访问层(DAO,Data Access Object)。 在 Service 下可以通过 Spring 的声明式事务操作数据访问层,而在业务层上还允许我们访问 NoSQL,这样就能够满足异军突起的 NoSQL 的使用了,它可以大大提高互联网系统的性能。
- 为了解决持久层的一直没有解决好的数据库事务编程的问题 迎合
概述
Spring MVC 是一种基于 MVC 设计模式的, 请求驱动类型的 轻量级 Web 框架。是Spring 框架的一个模块。
Spring MVC 也是服务到工作模式的实现,可进行优化。前端控制器是 DispatcherServlet
、应用控制器被拆分为 处理器映射器 Handler Mapping
和 视图解析器 ViewResolver
、处理器为 Controller
接口(仅包含 ModelAndView
handleRequest(request, response)方法的实现)(也可以是任何 POJO类)、支持本地化
Locale` 解析、主题解析和文件上传等;提供了非常灵活的数据验证、格式化和数据绑定机制;提供了强大的约定大于配置(惯例优先原则)的契约式编程支持。
优点
- 容易设计清爽干净的web层。
- 与Spring框架集成(IOC容器、AOP等)。
- 提供约定优于配置的契约式编程支持。
- 更加快捷、简单的单元测试。
- 灵活的URL到控制器的映射。
- 支持Rest风格。
- …
体系结构
Spring MVC的整体处理流程如下:
![image-20211126235405374](https://gitee.com/big_data7/picgo/raw/master/20220104200631.png)
- 前端控制器:
DispatcherServlet
【分发servlet】 - 应用控制器:拆分为 处理器映射器【
HandlerMapping
】 和 视图解析器 【ViewResolver
】 - 处理适配器:
HandlerAdapter
需要我们开发的组件:
Handler View
构建第一个Spring MVC架构项目
-
创建 maven 项目
-
选择 war 包
-
加入 spring mvc、jstl、servlet、jsp 等依赖
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gpb</groupId> <artifactId>springmvc1</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- **********************编译器配置**************************** --> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <maven.compiler.compilerVersion>11</maven.compiler.compilerVersion> <!-- 自定义属性 --> <spring.version>5.2.0.RELEASE</spring.version> </properties> <dependencies> <!-- spring mvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- jsp --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> <scope>provided</scope> </dependency> </dependencies> <!-- tomcat7 插件 --> <build> <finalName></finalName> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/springmvc</path> <port>8082</port> <server>tomcat7</server> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
-
在
src/main/webapp
下面加入WEB-INF
主要是下面的web.xml
【没加这个之前会报错的 pom war 的那行】 -
配置文件:
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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.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-4.3.xsd"> <!-- 启动组件扫描 --> <context:component-scan base-package="com.gpb"/> <!-- 启动mvc注解 --> <mvc:annotation-driven/> <!-- 启动视图解析 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
-
启动组件扫描
-
启动 mvc 的注解
-
启动视图解析
-
Bean的位置:
org.springframework.web.servlet.view.InternalResourceViewResolver
-
属性:
- 配置
viewClass
这个属性是JstlView
类:org.springframework.web.servlet.view.JstlView
prefix
:配置的controller
转发页面的前缀suffix
:配置的controller
转发页面的后缀
记得配置的路径要在项目里面存在并且在 controller 层返回的时候加上这个前后缀路径是存在的
- 配置
-
-
-
在
web.xml
配置分发控制器去拦截请求<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://JAVA.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>test</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> </welcome-file-list> <!-- 配置 DisPatchServlet 分发控制器 拦截请求到这个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:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
- 可能你的 servlet标签 会报红 把上面的
xmlns="http://JAVA.sun.com/xml/ns/javaee"
里面的第一个java
全大写 【这里已经大写了】
- 可能你的 servlet标签 会报红 把上面的
-
跑
controller
package com.gpb.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class UserInfoController { @RequestMapping("/index") public String name(Model model) { model.addAttribute("welcome", "欢迎来到SpringMVC框架"); return "index"; } }
-
创建一个
UserInfoController
-
这个方法在返回
index
后 在后面拼接好 位置 采取转发的【定义的视图解析器的前后缀】/WEB-INF/views/index.jsp
注意:这里的类是普通类 不用专门去建立servlet 而且这里可以写很多控制器方法 以前的 servlet 但是一般都是一张表一个类的
-
开发 Handler 【我们常说的MVC里面的Controller】
URL映射到Controller的方法
@RequestMapping
-
设置映射路径
-
@RequestMapping("/index")
:一个参数 -
@RequestMapping( value = "/index")
:一个参数 -
@RequestMapping({"/index","/index.do"})
:多个 value 值是数组
-
-
设置请求方式
-
@RequestMapping(value= "/index", method=RequestMethod.GET)
:设置请求方式只能是GET -
@RequestMapping(value= "/index", method=RequestMethod.POST)
:设置请求方式只能是POST -
@RequestMapping(value="/editGoods",method={RequestMethod.GET,RequestMethod.POST})
:GET和POST都可以
-
@GetMapping
@GetMapping(value = "/home")
仅限与 GET 方式请求映射
@PostMapping
@PostMapping(value = "/home")
仅限与 POST 方式请求映射
Controller 方法的返回值
在MVC架构中,controller返回值需要包含视图的URL和视图中显示的数据。视图的URL可以是JSP文件,显示的数据通常来自于数据库。
ModelAndView
public ModelAndView(String viewName, Map<String, ?> model) {
this.view = viewName;
if (model != null) {
getModelMap().addAllAttributes(model);
}
}
ModelAndView
: springmvc 底层封装的 包含视图名称或视图对象以及一些模型属性setViewName(String viewName)
:跳转到指定页面addObject(String attributeName, Object attributeValue)
:设置要返回的值,键值对的方式设置,页面中利用${keyName}
取值【使用 jstl 表达式, 它返回到页面的 request 域中】- 通过构造将 跳转的页面 和 键值对绑定的数据 放进去 然后返回这个对象就好了
DispatchServlet
前端控制器会调用ViewResolver
页面解析器 解析 并返回View
然后渲染View
最后响应请求
void
老式 Servlet
控制器里面的写法,用请求转发或者地址重定向, 但是方法里面要把常用的几个对象传进去,框架会自动注入的
@Controller
@RequestMapping("/goods")
public class HomeController {
@RequestMapping("/list")
public void home(HttpServletRequest request,HttpServletResponse response, HttpSession session) {
try {
request.getRequestDispatcher("/index.jsp").forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 请求转发:
request.getRequestDispatcher("/index.jsp").forward(request, response);
- 服务器端跳转,访问不需要加项目名
- 地址栏不发生变化
- 返回数据:
resquest.setAttribute(键值对);
- 响应:
response.sendRedirect(request.getContextPath()+"/index.jsp");
- 客户端跳转, 需要加上项目名【根就变到端口号去了】
- 地址栏发生变化
- 指定响应数据:
response.getWrite().write("json串");
String
-
controller
方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址return home;
-
视图解析器为
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean>
-
视图解析器解析后的地址:
WEB-INF/views/home.jsp
-
-
Redirect
重定向:return "redirect:/index.jsp";
- 相当于
response.sendRedirect(...);
- 由于重定向后请求和响应都失效了,所以参数传递可以使用 :
/index.jsp?id=1&…..
- 浏览器地址变化
- 注意:这里面的地址是写全的
- 相当于
-
forward
转发:"forward:/goods/update.action";
- 相当于请求转发
- 请求和响应没有失效,正常使用
- 浏览器地址不变
- 地址写全
Controller的参数绑定
处理器适配器【HandlerAdapter
】在执行 controller
之前需要把 http
请求的 key/value
数据绑定到 controller
方法形参上,相当于request.getParameter(“key”)
。默认支持的参数类型如下,处理器适配器会自动识别并注入进去。
- 什么是参数绑定:就是将URL中的的请求参数,进行类型转换(String或其他类型),将转换后的值在赋值给Controller方法形参中,然后Controller就可以直接使用该形参。
默认参数类型
-
HttpSession、HttpServletResponse、 HttpServletRequest
:获取请求信息、处理响应信息、获取session信息 -
Model
和ModelMap
:通过 它们 向页面传输数据-
ModelMap
是Model
接口的一个实现类,作用是将 Model 数据填充到 request 域,即使使用 Model, 其内部绑定还是 ModelMap【父类LinkedHashMap—> 继承自HashMap —> 实现Map接口】- 整个链条上都可以, 不过后面他们没有
addAttribute
这样的方法, 只能使用原生的自己的方法
- 整个链条上都可以, 不过后面他们没有
-
model.addAttribute("goods", goods);
:页面通过${goods.属性}
取得 goods 属性值 -
使用
Model
和ModelMap
的效果一样,如果直接使用Model
,springmvc
会实例化ModelMap
。保存到Model
或ModelMap
中的数据会被springmvc
保存到request
作用域中,因此界面可以通过${}
获取。
-
基本数据类型的绑定
基本数据类型(byte short int long char boolean float double
),自动获得,不给默认初始值
包装数据类型的绑定
包装类 (Byte Short Integer Long Character Float Double
),自动获得,不给报异常
String 类型
正常使用,类似 get 地址栏传参,不给报异常
POJO实体类的绑定
自动获得,和以前使用一样, form
表单的属性 name
要与 实体的属性相同
VO类型的绑定
和以前使用一样,但是注意在页面取值时,用 对象.属性
去取值,name
也要注意
数组集合类型的绑定
- 数组:
Controller
方法中可以用String[]
接收,多选框的名字得一致,通过这个名字去注入取值 - List:
List
中存放对象,并将定义的List
放在包装类中,controller
使用包装对象接收。 - Map:
注意
-
传递的参数名称不同:
@RequestParam(value="paramName") String str
给这个参数给个别的名字 -
不穿参数异常的解决办法:
@RequestParam(value="isResult",required = true,defaultValue = "8")
加入默认值以及是否必须 -
表单不要写该属性:
disabled=``"disabled"
不会提交,可以改用:readonly="readonly"
-
Date 日期 单独在实体类中使用注解处理一下:
@DateFormat("yyyy-MM-dd")
-
tomcat
中WEB-INF
目录是受保护的目录,该目录中的所有文件都不允许通过浏览器地址栏直接访问,只能通过后台程序通过请求转发访问,所以访问的话需要专门写个Controller
去访问。 -
中文乱码问题
-
POST 提交数据:在
web.xml
中配置springmvc
提供的过滤器<!-- post乱码 --> <filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
GET 提交数据:
-
修改
tomcat
的server.xml
配置文件<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
-
ISO8859-1
是tomcat
默认编码,需要将tomcat
编码后的内容转换为utf-8
编码String userName = new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8");
-
-