spring揭秘22-springmvc01-概述

news2024/9/23 7:33:01

文章目录

  • 【README】
  • 【1】MVC模式实现web应用架构
    • 【1.1】MVC模式
    • 【1.2】单个集中式控制器实现
      • 【1.2.1】引入2层控制器
  • 【2】springmvc概述
    • 【2.1】一级控制器:DispatcherServlet
      • 【2.1.1】HandlerMapping处理器映射
      • 【2.1.2】springmvc二级控制器Controller
      • 【2.1.3】View与ViewResolver(视图与视图解析器)
    • 【2.2】springmvc的物理结构(代码实现)
      • 【2.1.1】ContextLoaderListener-上下文加载器监听器
      • 【2.1.2】DispatcherServlet与XXX-servlet.xml
    • 【2.3】springmvc实现web应用代码示例
      • 【2.3.1】web.xml-整个web应用程序的部署描述符文件(web环境全局配置文件)
      • 【2.3.2】指定ContextLoaderListener加载web容器时使用的多个xml配置文件(加载顶层WebApplicationContext)
      • 【2.3.3】 一级控制器 DispatcherServlet启动时,加载多个xml配置文件(加载子WebApplicationContext-子web容器)
      • 【2.3.4】springmvc提供的组件
      • 【2.3.5】业务组件(MVC)
      • 【2.3.6】maven依赖

【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>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2156992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【自动驾驶】控制算法(十)深度解析车辆纵向控制 | Carsim 油门刹车标定表的制作

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

7款国内AI搜索引擎大全网站

与传统搜索引擎相比&#xff0c;AI搜索引擎利用先进的自然语言处理、机器学习和深度学习技术&#xff0c;提供更加精准和个性化的搜索服务。小编就来和大家分享国内免费的AI搜索引擎网站&#xff0c;方便大家体验使用。 AI搜索引擎网站大全&#xff1a;https://www.bgrdh.com/f…

java日志框架之Log4j

文章目录 一、Log4j简介二、Log4j组件介绍1、Loggers (日志记录器)2、Appenders&#xff08;输出控制器&#xff09;3、Layout&#xff08;日志格式化器&#xff09; 三、Log4j快速入门四、Log4j自定义配置文件输出日志1、输出到控制台2、输出到文件3、输出到数据库 五、Log4j自…

ESP32无线WiFi蓝牙SOC,设备物联网通信方案,启明云端乐鑫代理商

在当今数字化时代&#xff0c;物联网(IoT)正迅速成为连接我们生活各个方面的无形纽带&#xff0c;越来越多的日常物品被赋予了智能功能&#xff0c;从灯泡到插座&#xff0c;从门锁到家电设备&#xff0c;这些设备正在改变我们与家庭环境的互动方式。 随着智能产品的普及&…

*C++:string

一.STL简介 1.STL STL(standard template libaray- 标准模板库 ) &#xff1a; 是 C 标准库的重要组成部分 &#xff0c;不仅是一个可复用的组件库&#xff0c;而且 是一个包罗数据结构与算法的软件框架 。 2.STL六大组件 二.标准库里的string类 标准string库网址&#xff1…

【AI算法岗面试八股面经【超全整理】——NLP】

AI算法岗面试八股面经【超全整理】 概率论【AI算法岗面试八股面经【超全整理】——概率论】信息论【AI算法岗面试八股面经【超全整理】——信息论】机器学习【AI算法岗面试八股面经【超全整理】——机器学习】深度学习【AI算法岗面试八股面经【超全整理】——深度学习】NLP【A…

Crack道路裂缝检测数据集——目标检测数据集

【Crack道路裂缝检测数据集】共3684张。 目标检测数据集&#xff0c;标注文件为YOLO适用的txt格式。已划分为训练、验证集。 图片分辨率&#xff1a;224*224 类别&#xff1a;crack Crack道路裂缝检测数据集 数据集描述 该数据集是一个专门用于训练和评估基于YOLO&#xff0…

[笔记]某变频器,功能列表及参数表

产品代号&#xff1a;INVT GOODDRIVE&#xff0c;这家公司我的产品我似乎在特检院看到过&#xff1f;或者在某个地铁建设工地看到过。是深圳的。 1.产品功能点&#xff1a; 变频锥形电机控制、抱闸转矩验证&#xff1f;抱闸反馈零位检测行程限位超载防护轻载升速&#xff08;…

机器学习课程学习周报十三

机器学习课程学习周报十三 文章目录 机器学习课程学习周报十三摘要Abstract一、机器学习部分1. 文生图模型概述2. Stable Diffusion概述3. ControlNet概述4. 概率论复习&#xff08;二&#xff09; 总结 摘要 本周的学习内容涵盖了文生图模型、Stable Diffusion、ControlNet以…

从零开始讲DDR(5)——读懂Datasheet

对于开发人员来说&#xff0c;需要根据实际场景和使用的需要&#xff0c;使用不同厂家&#xff0c;不同型号的DDR&#xff0c;虽然原理上大同小异&#xff0c;但是还是有一些细节上的需要注意的地方&#xff0c;接触一个新的DDR芯片&#xff0c;首先就是需要找到对应的datashee…

Mybatis 返回 Map 对象

一、场景介绍 假设有如下一张学生表&#xff1a; CREATE TABLE student (id int NOT NULL AUTO_INCREMENT COMMENT 主键,name varchar(100) NOT NULL COMMENT 姓名,gender varchar(10) NOT NULL COMMENT 性别,grade int NOT NULL COMMENT 年级,PRIMARY KEY (id) ) ENGINEInnoD…

LeetCode讲解篇之238. 除自身以外数组的乘积

文章目录 题目描述题解思路题解代码 题目描述 题解思路 对于该题&#xff0c;我们可以先使用一个循环记录所有非零元素的乘积结果和非零元素的个数 如果非零元素个数为0&#xff0c;则非零元素的乘积除以数组对应位置的数字就是除自身以外的数组的乘积如果非零元素个数为1&am…

新质农业——水肥一体化技术

橙蜂智能公司致力于提供先进的人工智能和物联网解决方案&#xff0c;帮助企业优化运营并实现技术潜能。公司主要服务包括AI数字人、AI翻译、埃域知识库、大模型服务等。其核心价值观为创新、客户至上、质量、合作和可持续发展。 橙蜂智农的智慧农业产品涵盖了多方面的功能&…

【人工智能学习】8_人工智能其他通用技术

知识图谱 在看影视剧或小说时&#xff0c;若其中的人物很多、人物关系复杂&#xff0c;我们一般会用画人物关系图谱来辅助理解人物关系。那什么是知识图谱呢&#xff1f; 知识是人类对信息进行处理之后的认识和理解&#xff1b;对数据和信息的凝练、总结后的成果。 将信息转…

MySQL-排名函数ROW_NUMBER(),RANK(),DENSE_RANK()函数的异同

MySQL-排名函数ROW_NUMBER()&#xff0c;RANK()&#xff0c;DENSE_RANK()函数的异同 前言 假设有如下表结构与数据&#xff0c;class_id表示班级&#xff0c;需求&#xff1a;现在要按照班级分组&#xff0c;每个班级的学生进行年龄从小到大排序 一、ROW_NUMBER()函数 ROW_NUM…

YOLO航拍车辆和行人识别

YOLO航拍车辆和行人识别 图片数量9695&#xff0c;标注为xml和txt格式&#xff1b; class&#xff1a;car&#xff0c;pedestrian&#xff0c;truck&#xff0c;bus 用于yolo&#xff0c;Python&#xff0c;目标检测&#xff0c;机器学习&#xff0c;人工智能&#xff0c;深度学…

软件测试分类篇(下)

目录 一、按照测试阶段分类 1. 单元测试 2. 集成测试 3. 系统测试 3.1 冒烟测试 3.2 回归测试 4. 验收测试 二、按照是否手工测试分类 1. 手工测试 2. 自动化测试 3. 手工测试和自动化测试的优缺点 三、按照实施组织分类 1. α测试(Alpha Testing) 2. β测试(Beta…

图像放大效果示例【JavaScript】

实现效果&#xff1a; 当鼠标悬停在小图&#xff08;缩略图&#xff09;上时&#xff0c;大图&#xff08;预览图&#xff09;会随之更新为相应的小图&#xff0c;并高亮当前悬浮的小图的父元素。 代码&#xff1a; 1. HTML部分 <!DOCTYPE html> <html lang"z…

Nginx简介;Nginx安装

一&#xff0c;Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。是一个高性能的HTTP和反向代理web服务器 &#xff0c;同时也提供了IMAP/POP3/SMTP服务。 其特点是占有内存少…

OpenCV特征检测(8)检测图像中圆形的函数HoughCircles()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在灰度图像中使用霍夫变换查找圆形。 该函数使用霍夫变换的一种修改版本在灰度图像中查找圆形。 例子&#xff1a; #include <opencv2/imgp…