SpringMVC01_MVC的执行和注解开发
一、SpringMVC概述
SpringMVC 是 Spring 框架的一个模块,因此 SpringMVC 无需和 Spring 进行整合就可以使用。SpringMVC 是一个基于 MVC 的 Web 框架,即 Spring Web MVC。Spring Web MVC 和 Struts2 都属于表现层的框架,它是 Spring 框架的一部分。
copy<!-- 引入 Spring 框架的 WebMVC 的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
(一)SpringMVC 的执行流程
1.用户发起请求,请求被 servlet 拦截后,转发给 MVC 框架
2.SpringMVC 中的 DispacherServlet 核心控制器,接受请求并转发给 HandlerMapping
3.HandlerMapping 负责解析请求根据请求信息和配置信息找到匹配的 Controller 类,如果配置了拦截器会按照顺序执行拦截器中的 preHandler 方法
4.找到匹配的 Controller 后会把请求参数传递给 Controller 里面的方法
5.Controller 里面的方法执行完成之后会返回一个 ModeAndView 对象(视图名称和需要传递给视图的模型数据)
6.视图解析器根据名字找到视图并把数据模型填充到视图内,再渲染成 HTML 内容,返回网页。
(二)Spring MVC 入门案例
1.从 mvn 模板新建一个 webapp,添加如下依赖
copy<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
</dependencies>
2.在 web.xml 中配置前端控制器
可以引入 spring-beans.xml 的头文件,MVC 是 Spring 中的模块,所以 SpringMVC 和 Spring 有着相同的头部信息。
配置 DispatcherServlet 时,需要为其 contextConfigLocation 属性指定要加载的 SpringMVC 的配置 文件。该文件中指定 SpringMVC 框架需要使用的处理器映射器、处理器适配器、视图解析器等组件。、
如果 DispatcherServlet 初始化时没有为 contextConfigLoaction 属性指定要加载的文件,那么前端控制器就默认加载类路径下的以 DispatcherServlet 的 Servlet 名称-servlet.xml 格式的配置文件。
copy<!-- 配置前端控制器 -->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置初始化参数,为 contextConfigLocation 属性指定要加载的 SpringMVC 的配置文件,
如果不配置,则默认加载 DispatcherServlet 的 ServletName 为名称的配置文件,例如:
SpringMVC-servlet.xml
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
</servlet>
3.配置前端控制器映射
下面的 url-pattern 表示凡是以 action 结尾的任何请求都会被这个 DispacherServlet 所解析
copy<!-- 配置前端控制器的映射 -->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
4.处理器映射器
SpringMVC 提供了 一个 BeanNameUrlHandlerMapping 的处理器映射器类。该类的作用是将容器中 Java Bean 的 name 属性当作 url 来进行匹配,改类是 SpringMVC 框架使用,因此不需要为该 Bean 配置 id。
BeanNameUrlHandlerMapping:根据 bean 名称匹配 URL 地址,即下面的 Handler 处理器。
copy<!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
5.配置处理器适配器
MVC 框架提供了 SimpleControllerHandlerAdapter 处理器适配器类,用于执行相应的 Handler 类。Handler 类就是我们需要编写的代码。
copy<!-- 配置处理器适配器 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
6.配置处理器适配器
copy<!-- 配置 Handler 处理器 -->
<bean name="/book_list.action" class="com.ls.springmvc.controller.BookController"/>
7.编写 Handler 处理器
copy@Data
@Accessors(chain = true)
public class Book {
private Long id;
private String name;
private Double price;
}
public class BookController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView modelAndView = new ModelAndView();
ArrayList<Book> books = new ArrayList<>();
for (int i = 0; i < 10; i++) {
books.add(new Book().setId(Long.valueOf(i)).setName("spring"+i).setPrice(100.00+i));
}
modelAndView.addObject("bookList",books);
modelAndView.setViewName("bookList");
return modelAndView;
}
}
8.配置视图解析器
MVC 框架中提供了 InternalResourceViewResolver 视图解析器类,该类为 SpringMVC 框架使用,因此只需要将其配置到 Spring 容器中即可,不需要提供 id 属性。
prefix 属性:用于配置物理视图 url 路径中固定的前缀部分。
suffix 属性:用于配置物理视图 url 路径中固定的后缀路径。
所以上面的处理器的全名称应该为 modelAndView.setViewName("/WEB-INF/jsp/bookList.jsp");
copy<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
9.编写 JSP
注意有的版本的 isELIgnored 是 false 也有的是 true,所以直接在头声明。将所有的 JSP 页面放到 web-inf 下,因为浏览器不能直接请求 web-inf 下的页面,只能通过后端程序完成请求转发,方便在后台控制。
copy<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
图书列表:${bookList}
</body>
</html>
10.打包发布
成功显示
这一部分配置比较多,所以需要结合 MVC 的执行流程来看才能更清楚。
(三) 非注解的映射器、适配器
1.映射器
前面我们使用处理器映射器 BeanNameUrlHandlerMappinp 配置处理器映射器,但是她不能对 bean 的 url 进行集中管理,SpringMVC提供了可以进行 url 与 bean 映射的映射器 SimpleUrlHandlerMapping ,需要为其属性 mappings 提供一个 Properties 集合对象。其中 Properties 属性对象的 key 值就是 url,value 值就是 handler bean 的 id 属性值。
更改配置如下所示,其中 HelloController 依然是实现了 Controller。
copy <!-- 配置处理器映射器 -->
<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/person.action">personController</prop>
<prop key="/hello.action">helloController</prop>
</props>
</property>
</bean>
<!-- 配置 Handler 处理器 -->
<bean id="personController" class="com.ls.controller.PersonController"/>
<bean id="helloController" class="com.ls.controller.HelloController"/>
2.适配器
SpringMVC 还提供了另外一种非注解的处理器适配器 HttpRequestHandlerAdapter,其中包含两个主要的方法,supports 方法返回一个布尔类型的值,用于判断只有 HttpRequestHandler 类型的对象才可以被当作 Handler 来执行。HttpRequestHandler 是 SpringMVC 框架提供的一个接口,只要实现了该接口的类都可以被当作 Handler 对象来执行。handle 方法执行一 个 Handler 对象,并返回一个 ModelAndView 逻辑视图。
copy <!-- 配置处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/book.action">bookController</prop>
</props>
</property>
</bean>
<!-- 配置处理器适配器 -->
<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>-->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
<!-- 配置 Handler 处理器 -->
<!-- <bean id="personController" class="com.ls.controller.PersonController"/>-->
<!-- <bean id="helloController" class="com.ls.controller.HelloController"/>-->
<bean id="bookController" class="com.ls.controller.BookController"></bean>
需要编写的 Controller 实现 HttpRequestHandler
copypublic class BookController implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Book接收请求");
}
}
二、注解形式开发
上面那些混个脸熟即可,主要理解处理过程,平时开发应该没人用罢
(一)配置映射器和适配器
SpringMVC 框架为了简化使用,提供了 mvc 命名空间。该空间下提供了 mvc:annotation-driven 元素,用于简化注解方式的映射器、适配器在 spring-mvc.xml 文件中的配置。
不仅可以替代上面两个 bean 类的配置,而且 mvc:annotation-driven 的驱动类还默认加载了多个参数绑定的方法,比如 json 转换解析器就默认加载。
引入 mvc 命名空间之后,在配置文件中配置注解的适配器和映射器,并配置自动扫描包。
copyxmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd"
<!--配置注解形式的适配器和映射器-->
<mvc:annotation-driven/>
<!--自动扫描包-->
<context:component-scan base-package="com.ls"></context:component-scan>
我是新建了一个 mvc 的配置文件,头文件是差不多的,不过不要忘了如果修改的话在 web.xml 里面把读取配置文件的信息改了,md就因为忘了改耽误半小时,,,,,,
copy<!--配置注解形式的适配器和映射器-->
<mvc:annotation-driven/>
<!--自动扫描包-->
<context:component-scan base-package="com.ls"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
(二)编写 Handler
注解@Controller 标记的类,Spring 容器自动加载该 Bean 类并进行管理。对于该 Bean 中的使用注解 @RequestMapping 修饰的方法会进行自动映射。映射的 url 路径需要在 @RequestMapping 注解中定义。
使用注解方式的映射器就不需要在 xml 中配置 url 和 Handler 之间的映射关系,让应用的配置信息得到极大的简化。
copy@Data
@Accessors(chain = true)
public class Car {
private Integer id;
private String name;
}
//---------------------------------------------------------------------------------
@Controller
@RequestMapping("/car")
public class CarController {
@RequestMapping("/list.action")
public ModelAndView list() {
System.out.println("查询车辆列表");
ArrayList<Car> cars = new ArrayList<>();
for (int i = 0; i < 10; i++) {
cars.add(new Car().setId(i+1).setName("宏光"+i));
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("carList");
modelAndView.addObject("carList",cars);
return modelAndView;
}
}
随便来个页面测试
copy<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>CarList</title>
</head>
<body>
${carList}
</body>
</html>
使用注解方式编写的 Handler,在项目中开发业务模块时,一个业务模块下的增、删、改、查等相关联的 操作,不用再分散到各个类中,而是集中到一个 Controller 类中来完成。业务变的不再分散,在业务模块中增加新的功能也变的更加灵活与方便。
三、Controller、Service、Mapper和POJO
之前写博客的时候一直混乱搞不清这几个哥们的具体作用,找了一些不错的博主回答:原文链接
(一)Entity层:实体层 数据库在项目中的类
Entity层是实体层,也就是所谓的model,也称为pojo层,是数据库在项目中的类,该文件包含实体类的属性和对应属性的set、get方法;
(二)DAO层: 持久层 主要与数据库进行交互
DAO层=mapper层,现在用Mybatis逆向工程生成的mapper层,其实就是dao层。DAO层会调用entity层,DAO中会定义实际使用到的方法,比如增删改查。DAO 层的数据源和数据库连接的参数都是在配置文件中进行配置的,配置文件一般在同层的XML文件夹中。数据持久化操作就是指,把数据放到持久化的介质中,同时提供增删改查操作。
(三)Service层:业务层 控制业务
Service层主要负责业务模块的逻辑应用设计。先设计放接口的类,再创建实现的类,然后在配置文件中进行配置其实现的关联。service层调用dao层接口,接收dao层返回的数据,完成项目的基本功能设计。
封装Service层的业务逻辑有利于业务逻辑的独立性和重复利用性。
(四)Controller层:控制层 控制业务逻辑
Controller层负责具体的业务模块流程的控制,controller层负责前后端交互,接受前端请求,调用service层,接收service层返回的数据,最后返回具体的页面和数据到客户端。
Controller层像是一个服务员,他把客人(前端)点的菜(数据、请求的类型等)进行汇总什么口味、咸淡、量的多少,交给厨师长(Service层),厨师长则告诉沾板厨师(Dao 1)、汤料房(Dao 2)、配菜厨师(Dao 3)等(统称Dao层)我需要什么样的半成品,副厨们(Dao层)就负责完成厨师长(Service)交代的任务。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律