我们的开发架构一般都是基于两种形式,一种 C/S架构 ,也就是客户端/服务器,另一种是 B/S架构 ,也就是浏览器/服务器。在JavaEE开发中,几乎全部都是基于B/S架构的开发。那么在B/S架构中,系统标准的 三层架构 包括: 表现层、业务层、持久层 。三层架构在我们的实际开发中使用的非常多。
也就是我们长说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web层,web需要接收http请求,完成http响应。
表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。
表现层的设计一般都是使用mvc模型。(mvc是表现层的设计模型,和其他层没有关系)
也就是我们常说的 service层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web层依赖业务层,但是业务层不依赖web层。
业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制)
也就是我们常说的dao层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。
通俗的讲,持久层就是和数据交互,对数据库表进行增删改查的。
mvc全名是Model View Controller, 模型(Model)-视图(View)-控制器(Controller) 的缩写,是一种用于设计创建web应用程序表现层的模式。mvc中每个部分各司其职:
模型包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。
通常指的就是我们的jsp或者html。作用一般就是展示数据的。
通过视图是依据模型数据创建的。
是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring框架提供了构建Web应用程序的全功能MVC模块。使用Spring可插入的MVC架构,从而在使用Spring进行Web开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。
SpringMVC已经成为 目前最主流的MVC框架 之一,并 随着Spring3.0的发布,全面超越Struts2,成为最优秀的MVC框架。
它通过一套注解,让一个简单的Java类称为处理请求的控制器,而无需实现任何接口。同时它还支持RESTful编程风格的请求。
Spring MVC和Struts2一样,都是 为了解决表现层问题 的web框架,他们都是基于MCC设计模式的。而这些表现层框架的主要职责就是 处理前端HTTP请求 。
Spring MVC全名叫Spring Web MVC,它是Spring家族Web模块的一个重要成员。这一点,我们可以从Spring的整体结构中看的出来:
也许你会问,为什么要学习Spring MVC呢?struts2不才是主流嘛?看SSH的概念有多火?
其实很多初学者混淆了一个概念,SSH实际上指的是Struts1.x+Spring+Hibernate。这个概念已经有十几年的历史了。在Struts1.x时代,它是当之无愧的霸主,但是在新的MVC框架涌现的时代,形式已经不是这样了,Struts2.x借助了Struts1.x的好名声,让国内开发人员认为Struts2.x是霸主继任者(其实两者在技术上无任何关系),导致国内程序员大多数学习基于Struts2.x的框架,又一个貌似很多的概念出来了S2SH(Struts2+Spring+Hibernate)整合开发。
SpringMVC是基于MVC设计模型的,MVC模式指的就是Model(业务模型)、View(视图)、Controller(控制器)。 SpringMVC处理请求就是通过MVC这三个角色来实现的。
注:不要把 MVC设计模式 和 工程的三层架构 混淆,三层结构指的是 表现层、业务层、数据持久层 。而MVC只针对 表现层进行设计 。
下面让我们看看处理流程吧
访问 /queryItem ,返回商品列表页面,商品数据暂时使用静态数据(不从数据库查询并返回)。
<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.0</modelVersion> <groupId>com.cyb</groupId> <artifactId>springmvc-demo01</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!-- spring ioc组件需要的依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.2.1.RELEASE</version> </dependency> <!-- 基于AspectJ的aop依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.1.RELEASE</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- spring MVC依赖包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.1.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.1.RELEASE</version> </dependency> <!-- jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- servlet --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- 配置Maven的JDK编译级别 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> </configuration> </plugin> <!-- tomcat依赖包 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> </plugin> </plugins> </build> </project>
注:
1、依赖添加完之后,项目上右键->maven->Update Maven Project
2、项目上右键->Java EE Tools->Generate Deployment Descriptor Stub
路径:src/main/webapp/WEB-INF/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_2_5.xsd" version="2.5"> <!-- 学习前置条件 --> <!-- 问题1:web.xml中servelet、filter、listener、context-param加载顺序 --> <!-- 问题2:load-on-startup标签的作用,影响了Servlet对象创建的时机 --> <!-- 问题3:url-pattern:标签的配置方式有四种:/dispatcherServlet、/servlet/*、*.do、/ 以上四种配置--> <!-- 问题4:url-pattern标签的配置为什么配置/就不拦截jsp请求,而配置/*,就会拦截jsp请求 --> <!-- 问题4原因:标签配置为/*报错,因为它拦截了jsp请求,但是又不能处理jsp请求。 --> <!-- 问题5:配置了springmvc去读取spring配置文件之后,就产生了spring父子容器的问题 --> <!-- 配置前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 设置spring配置文件路径 --> <!-- 如果不设置初始化参数,那么DispatcherServlet会读取默认路径下的配置文件 --> <!-- 默认配置文件路径:/WEB-INF/springmvc-servlet.xml --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 指定初始化时机,设置为2,表示Tomcat启动时,它会跟随着启动,DispatcherServlet会跟随着初始化 --> <!-- 如果没有指定初始化时机,DispatcherServlet就会在第一次被请求的时候,才会初始化,而且只会被初始化一次(单例模式) --> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- url-pattern的设置 --> <!-- 不要配置为/*,否则报错 --> <!-- 通俗解释:会拦截整个项目中的资源访问,包含JSP和静态资源的访问,对于JS的访问,springmvc提供了默认Handler处理器 --> <!-- 但是对于JSP来讲,springmvc没有提供默认的处理器,我们也没有手动编写对应的处理器,此时按照springmvc的处理流程分析得知,它down了 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
路径:/src/main/java/com/cyb/springmvc/controller/ItemController.java
package com.cyb.springmvc.controller; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.cyb.springmvc.po.item; /** * 处理器的开发方式有多种,比如实现HttpRequestHandler接口、Controller接口的方式、还有注解的方式 企业中使用的一般都是注解的方式 * 注解的注意事项 * 1、类上加上@Controller注解(必须是Controller,可以通过源码找到答案) * 2、类上或者方法上面要加上@RequestMapping(必须) * * @author apple * */ @Controller public class ItemController { //@RequestMapping此时填写的是url //ModelAndView:Model标识的是数据类型,View就是最终要展示给用户的视图 @RequestMapping("queryItem") public ModelAndView queryItem() { //用静态数据模型 List<item> itemList=new ArrayList<item>(); item item_1=new item(); item_1.setName("苹果手机"); item_1.setPrice(5000); item_1.setDetail("iphoneX苹果手机!"); itemList.add(item_1); item item_2=new item(); item_2.setName("华为手机"); item_2.setPrice(6000); item_2.setDetail("华为5G网速就是快!"); itemList.add(item_2); ModelAndView mvAndView=new ModelAndView(); //设置数据模型,相当于request的setAttribute方法,实质上,底层确实也是转成了request() //先将k/v数据放入map中,最终根据视图对象不同,再进行后续处理 mvAndView.addObject("itemList",itemList); //设置view视图 mvAndView.setViewName("/WEB-INF/jsp/item/item-list.jsp"); return mvAndView; } }
路径:src/main/java/com/cyb/springmvc/po/item.java
package com.cyb.springmvc.po; public class item { private String name; private double price; private String detail; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } }
路径:src/webapp/WEB-INF/jsp/item/item-list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> <!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> <form action="${pageContext.request.contextPath }/itemList.do" method="post"> 查询条件: <table width="100%" border=1> <tr> <td><input type="submit" value="查询" /></td> </tr> </table> 商品列表: <table width="100%" border=1> <tr> <td>商品名称</td> <td>商品价格</td> <td>商品描述</td> <td>操作</td> </tr> <c:forEach items="${itemList }" var="item"> <tr> <td>${item.name }</td> <td>${item.price }</td> <td>${item.detail }</td> <td><a href="${pageContext.request.contextPath }/itemEdit.do?id=${item.name}">修改</a></td> </tr> </c:forEach> </table> </form> </body> </html>
直接下载
注:标记的方法体,跟踪进去读源码就好啦!~~
# Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,/ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,/ org.springframework.web.servlet.function.support.RouterFunctionMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,/ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,/ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,/ org.springframework.web.servlet.function.support.HandlerFunctionAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,/ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,/ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
用户请求到达前端控制器,它就相当于mvc模式中的C,DispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户的请求,DispatcherServlet的存在降低了组件之间的耦合性。
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下,Handler对具体的用户请求进行处理。
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。
springmvc框架提供了很多View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。
一般情况下需要通过页面标签或页面模板技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
再springmvc的各个组件中, 处理器映射器、处理器适配器、视图解析器 称为springmvc的三大组件。需要用户开发的组件有: 处理器、视图
RequestMappingHandlerMapping :注解式处理器映射器
对类中标记@ResquestMapping的方式进行映射,根据ResquestMapping定义的url匹配ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器,HandlerMethod对象中封装url对应的方法Method。
配置如下:
<!--注解映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--注解适配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<mvc:annotation-drivern />
mvc:annotation-drivern标签的作用,详见AnnotationDrivenBeanDefinitionParser类的parse方法。分析源码可知:mvc:annotation-drivern往spring容器中注册以下的一些BeanDefinition
再springmvc.xml文件配置如下:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 该视图解析器,默认的视图类就是JstlView,可以不写 --> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>