spring揭秘22-springmvc01-概述
文章目录
【README】
本文总结自《spring揭秘》,作者王福强,非常棒的一本书,墙裂推荐;
【1】MVC模式实现web应用架构
【1.1】MVC模式
1)mvc模式:指的是模型Model-视图View-控制器Controller
- 模型Model: 封装业务逻辑与数据状态; 如业务逻辑代码实现是 Service(如ddd中的ApplicationService,DomainService),数据状态代码实现是 Dto,PO等;
- 视图View:发送请求给控制器及接收控制器响应报文,并展示报文数据,渲染前端窗体;
- 控制器Controller:负责接收视图发送的请求,根据请求报告找到对应模型Model进行业务逻辑处理及业务数据操作(包括但不限于增删改查,如发送消息队列等); 待模型处理完成后,把处理结果(响应报文)返回给对应视图;
【注意】模型Model是包括了业务逻辑与数据状态;(实际上有很多同学确实不清楚mvc模型的含义)
2)在jsp+servlet的web开发时代,mvc的具体实现如下;jsp充当视图,servlet充当控制器,javabean充当模型;
3)问题:如上,servlet作为控制器;那一个web系统中是有一个控制器,还是说有多个?(注意这里讨论的是业务控制器,运维监控非业务控制器不在讨论范围)
- 多控制器:即一个servlet处理一个请求;难运维,通常不选择;但特殊业务场景可以选择多个控制器,如restapi,如发送请求给es集群的restapi;
- 单个集中式控制器:一个servlet处理所有业务请求;请求报文带有业务模型标识,即由哪个业务模型来处理该请求;
- 问题:servlet如何编码实现通过请求报文中业务模型标识找到对应业务模型呢; 硬编码? 显然不合理;
【1.2】单个集中式控制器实现
1)由上文,多个控制器模式通过配置的请求路径与控制器映射关系找到对应控制器;不存在找业务模型的问题;
2)单个集中式控制器模式中: 1个控制器处理所有业务请求, 如何通过请求报文的模型标识,(以解耦方式而不是硬编码)找到对应模型进行业务处理,成了一个问题 ;
【1.2.1】引入2层控制器
1)设置2层控制器(解决通过请求报文模型标识找对应模型的问题):
- 一级控制器(FrontController):原先由servlet实现的单个集中式控制器;
- 维护模型标志与二级控制器映射关系(map容器实现);
- 接收到请求后,根据模型标识到map中查找二级控制器,并把请求报文转发给二级控制器处理;
- 二级控制器(PageControler):接收一级控制器转发下来的请求,并把请求转给模型进行具体业务处理;
- 二级控制器可以与业务模型绑定,即1对1的关系;
- 二级控制器也可以与业务模型不绑定,如通过策略模式找到具体策略实现类;
- 当然:二级控制器本身也可以充当业务模型角色处理具体业务逻辑(而无需具体业务模型),但不建议,因为无法实现业务逻辑代码复用;
【总结】一级控制器与二级控制器共同组成了整个应用程序的控制器, 以分离流程控制逻辑与具体web请求处理逻辑; 具体步骤如下:
- 步骤1: 一级控制器接收到web请求;
- 步骤2:根据请求报文中的标识(可以是业务模型标识,也可以是二级控制器标识),从二级控制器与请求标识映射关系map中查找到二级控制器,并把请求转发给二级控制器;
- 步骤3:二级控制器接收请求后,转发给具体业务模型处理;
- 步骤4:业务模型处理完成后,返回模型数据及视图名;
【2】springmvc概述
1)springmvc是对mvc模式的具体实现;
- springmvc控制器层:
- HandlerMapping: 处理web请求与二级控制器之间的映射关系;
- springmvc视图层:
- 通过引入 ViewSolver和View,分离视图类型选择及渲染与控制器之间的耦合; 使得各种视图技术可以很容易集成到spirngmvc框架中;
- 如使用 jsp/jstl ,Velocity/FreeMaker,甚至PDF/Excel 等二进制格式的视图形式,可以通过配置集成到spirngmvc;
【2.1】一级控制器:DispatcherServlet
1)把DispatcherServlet注册到web.xml, 用于拦截所有请求; (web.xml是整个web应用程序的部署描述符文件)
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>springmvcDiscover</display-name>
<!-- 注册一级控制器DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
【2.1.1】HandlerMapping处理器映射
1)HandllerMapping:处理web请求与二级控制器之间的映射关系;
2)一级控制器DispatcherServlet接收到请求后,根据请求报文中的请求标识从二级控制器与请求标识映射容器中查找对应二级控制器;其中二级控制器与标识映射容器通过HandlerMapping来实现;
- 即,web请求到达一级控制器DispatcherServlet后,DispatcherServlet将根据请求标识到HandlerMapping查找具体的二级控制器,并把请求转发给二级控制器做处理;
【2.1.2】springmvc二级控制器Controller
1)二级控制器通过 Controller来实现;
2)二级控制器Controller处理逻辑完成后,返回一个 ModelAndView实例,ModelAndView包含两部分信息;
- 视图逻辑名称(或者具体的视图实例);
- 模型数据;
【总结】springmvc一级控制器通过DispatcherServlet实现, 二级控制器通过controller(org.springframework.web.servlet.mvc.Controller)来实现 ;
【2.1.3】View与ViewResolver(视图与视图解析器)
1)View:springmvc引入View,用于抽象视图的生成策略;
- 一级控制器DispatcherServlet 根据二级控制器Controller处理完成后返回的ModelAndView 查找到具体View视图,然后通过该View渲染模型数据(Model);
2)ViewResolver视图解析器: 用于封装逻辑视图名与视图实例间的映射关系;(如 逻辑视图名=test,视图实例=test.jsp)
- ViewResolver 根据 ModelAndView中的逻辑视图名查找对应View实例,然后把查找结果(View实例)返回给 一级控制器DispatcherServlet ;
- 一级控制器DispatcherServlet最终会把 ModelAndView中的模型数据交给该View实例来做视图渲染;
- 至此,整个DispatcherServlet的处理流程结束;
【2.2】springmvc的物理结构(代码实现)
1)web.xml文件:是整个web应用程序的部署描述符文件;【2.1】中,web.xml文件可以配置一级控制器;此外,web.xml还可以配置Listener监听器;
【2.1.1】ContextLoaderListener-上下文加载器监听器
1)web.xml 中可以通过<listener> 元素配置 ServletContextListener;ServletContextListener接口的通用具体实现是 ContextLoaderListener ;
- ContextLoaderListener 的作用:加载顶层WebApplicationContext;而WebApplicationContext作用是注册中间层服务,包括数据源,数据访问对象DAO,服务对象Service等;
- WebApplicationContext:可以理解为与spring容器ClassPathXmlApplicationContext类似的功能;只不过WebApplicationContext是spring web环境的容器;
2)与ClassPathXmlApplicationContext容器需要xml配置类似, 顶层WebApplicationContext是spring容器,也需要xml配置文件,其默认配置文件是 /WEB-INF/applicationContext.xml ; (applicationContext.xml,需要符合spring ioc容器xml配置文件格式)
- web.xml 中可以通过指定名称为contextConfigLocation来指定具体的web容器xml配置文件;
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>springmvcDiscover</display-name>
<!-- 指定ContextLoaderListener加载web容器时使用的多个xml配置文件(默认使用/WEB-INF/applicationContext.xml) -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-module1.xml</param-value>
</context-param>
<!-- 配置监听器ContextLoaderListener,其加载顶层WebApplicationContext web容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 注册一级控制器DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
3)ContextLoaderListener监听器:加载相应路径下的xml容器配置文件,构建顶层WebApplicationContext,并将该WebApplicationContext绑定到ServletContext上下文;可以通过WebApplicationContextUtils获取顶层WebApplicationContext;如
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
4)把WebApplicationContext绑定到ServletContext的目的: 任何类型的web应用,只要能够获取ServletContext,就能获取并使用WebApplicationContext;
【2.1.2】DispatcherServlet与XXX-servlet.xml
1)DispatcherServlet作为一级控制器,依赖多个组件实现web请求的处理;组件包括 HandlerMapping, Controller二级控制器,ViewResolver视图控制器等;组件配置需要通过单独的XXX-servlet.xml 来配置,其中XXX表示DispatcherServlet的servlet名称,如dispatcher-servlet.xml ;(dispatcher是web.xml中注册的DispatcherServlet的servlet名字)
<!-- 注册一级控制器DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
2)dispatcher-servlet.xml 需要符合springioc容器xml配置文件格式;
【dispatcher-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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注册HandllerMapping bean到springweb容器 -->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!-- 注册视图解析器bean到springweb容器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
</beans>
如果DispatcherServlet依赖的组件过多,也加载多个xml配置文件,web.xml中注册的DispatcherServlet配置信息如下(通过contextConfigLocation属性指定多个文件);
<!-- 注册一级控制器DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml,/WEB-INF/dispatcher-servlet2.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
3)一级控制器DispatcherServlet启动后,将加载 xxx-servlet.xml(如dispatcher-servlet.xml),并构建相应的WebApplicationContext;该WebApplicationContext把 ContextLoaderListener加载的顶层WebApplicationContext作为父容器; (即使用DispatcherServlet对应配置文件加载的WebApplicationContext,可以注入来自顶层WebApplicationContext的依赖(bean))
【2.3】springmvc实现web应用代码示例
1)业务场景:查询用户列表;
2)基于springmvc实现web应用的文件目录如下:
3)访问效果:
【2.3.1】web.xml-整个web应用程序的部署描述符文件(web环境全局配置文件)
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>springmvcDiscover</display-name>
<!-- 指定ContextLoaderListener加载web容器时使用的多个xml配置文件(默认使用/WEB-INF/applicationContext.xml) -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-module1.xml</param-value>
</context-param>
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<servlet-name>dispatcher</servlet-name>
</filter-mapping>
<!-- 配置监听器ContextLoaderListener,其加载顶层WebApplicationContext web容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 注册一级控制器DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml,/WEB-INF/dispatcher-servlet2.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
【2.3.2】指定ContextLoaderListener加载web容器时使用的多个xml配置文件(加载顶层WebApplicationContext)
1)顶层WebApplicationContext: 实际上就是web环境下的spring ioc容器;而且是父容器;它是父,什么是子容器;如 一级控制器DispatcherServlet加载的web容器就是子容器 ;
2)指定ContextLoaderListener加载web容器时使用的多个xml配置文件(默认使用/WEB-INF/applicationContext.xml);
- 包括/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-module1.xml (本文故意使用2个xml配置文件用于ContextLoaderListener加载顶层web容器,以演示可以使用多个配置文件;实际上1个xml配置文件也是可以的)
<!-- 指定ContextLoaderListener加载web容器时使用的多个xml配置文件(默认使用/WEB-INF/applicationContext.xml) -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/applicationContext-module1.xml</param-value>
</context-param>
【applicationContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userAppService" class="com.tom.springmvc.model.UserAppService" />
</beans>
【applicationContext-module1.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userAppService2" class="com.tom.springmvc.model.UserAppService" />
</beans>
【2.3.3】 一级控制器 DispatcherServlet启动时,加载多个xml配置文件(加载子WebApplicationContext-子web容器)
<!-- 注册一级控制器 DispatcherServlet,用于拦截所有请求(匹配url-pattern) -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- DispatcherServlet启动读取xml配置文件加载组件,构建web容器(子),通过contextConfigLocation为其配置多个xml文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dispatcher-servlet.xml,/WEB-INF/dispatcher-servlet2.xml</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
补充: 实际上1个xml配置文件也是可以的,本文使用多个配置文件是为了演示DispatcherServlet可以加载多个xml配置文件;
【dispatcher-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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注册HandllerMapping bean到springweb容器, BeanNameUrlHandlerMapping使用URL与Controller的bean名称进行匹配 -->
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!-- 注册视图解析器bean到springweb容器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
【dispatcher-servlet2.xml】
HandlerMapping封装了请求标识(路径)与二级控制器间映射关系,本文使用的是BeanNameUrlHandlerMapping, 即使用URL与二级控制器Controller的bean名称进行匹配;所以在注册控制器时,控制器的名称要与请求路径相同;
如控制器名称为 /userController.do , 请求路径是 http://localhost:8080/springmvcDiscoverFirstDemo/userController.do ,即该请求才会被HanderMapping转发给 名称为 /userController.do 的二级控制器做处理;
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注册控制器 -->
<bean id="/userController.do" class="com.tom.springmvc.controller.UserController">
<property name="userAppService" ref="userAppService" />
</bean>
</beans>
【补充】控制器bean, UserController , 使用了顶层Web容器中的userAppService;这不就是子容器使用父容器bean进行依赖注入吗?
- 父容器: ContextLoaderListener加载的顶层web容器;
- 子容器: DispatcherServlet加载的web容器; 子容器可以复用父容器的bean进行依赖注入;
【2.3.4】springmvc提供的组件
1)HandlerMapping: 处理器映射容器, 处理web请求与二级控制器之间的映射关系;本文使用的是 BeanNameUrlHandlerMapping ,即根据请求URL到HandlerMapping中找出与URL同名的控制器,然后把请求转发给该控制器;
2)ViewResolver:视图解析器,InternalResourceViewResolver; 用于封装逻辑视图名与视图实例间的映射关系;
【2.3.5】业务组件(MVC)
1)二级控制器层
public class UserController extends AbstractController {
private UserAppService userAppService;
@Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("handleRequestInternal 被访问了");
ModelAndView modelAndView = new ModelAndView("userListPage");
modelAndView.addObject("userList", userAppService.listUser());
return modelAndView;
}
public void setUserAppService(UserAppService userAppService) {
this.userAppService = userAppService;
}
}
2)业务模型逻辑层 (为简单起见,本文没有使用数据源,而是内存mock了用户列表)
public class UserAppService {
public List<UserDto> listUser() {
// 这里本应该调用dao层或http,为简单期间,我们在内存mock一个userlist
return List.of(
UserDto.build(1L, "张三1", "17612340001", "成都高新区地址01号")
, UserDto.build(2L, "张三2", "17612340002", "成都高新区地址02号")
, UserDto.build(3L, "张三3", "17612340003", "成都高新区地址03号")
);
}
}
3)业务模型数据状态层
public class UserDto {
private Long id ;
private String name;
private String mobilePhone;
private String address;
public UserDto() {
// do nothing.
}
public static UserDto build(Long id, String name, String mobilePhone, String address) {
UserDto userDto = new UserDto();
userDto.id = id;
userDto.name = name;
userDto.mobilePhone = mobilePhone;
userDto.address = address;
return userDto;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobilePhone() {
return mobilePhone;
}
public void setMobilePhone(String mobilePhone) {
this.mobilePhone = mobilePhone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
4)视图层
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="java.util.List" import="java.util.ArrayList" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>用户列表</title>
</head>
<body>
<table border="1" cellpadding="0" cellspacing="0" bordercolor="#000000">
<tr>
<td>用户编号</td>
<td>用户名称</td>
<td>手机</td>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.mobilePhone}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
【2.3.6】maven依赖
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tom</groupId>
<artifactId>springmvcDiscoverFirstDemo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>springmvcDiscover Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>6.1.10</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>6.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.16</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.22</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>
原文地址:https://blog.csdn.net/PacosonSWJTU/article/details/142444726
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!