写点什么

不是吧,都 2021 年了你别说你还不会 Spring MVC 基本应用

  • 2021 年 11 月 25 日
  • 本文字数:5936 字

    阅读完需:约 19 分钟

1.1 经典三层结构


在 JavaEE 开发中,几乎全部都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用得非常多,接下来我们详细了解下这三层架构。


表现层:也就是我们常说的 web 层。它负责接收客户端请求,向客户端响应结果。


表现层包括展示层和控制层:控制层负责接受请求,展示层负责结果的展示。


表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。


表现层的设计一般都使用 MVC 模型。


业务层也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。业务层在业务处理时如果需要持久化,会依赖持久层


持久层也就是我们常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口。通俗地说,持久层就是对数据库进行增删改查的。


1.2 MVC 设计模式


不是吧,都 2021 年了你别说你还不会 Spring MVC 基本应用 MVC 设计模式是针对表现层的一种设计模式。


MVC 全名是 Model View Controller,是模型(Model)-视图(view)-控制器(controller)的缩写,是一种用户设计创建 Web 应用程序表现层的模式。下面详细介绍:


Model:包含业务模型和数据模型,数据模型用于封装数据,业务模型用于处理业务。View:通常就是指我们的 JSP 或者 HTML。作用一般是展示数据,通常是依据模型数据来展示的 Controller:是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。MVC 提倡:每一层只编写自己的东西,不编写其他的代码;分层的目的是为了解耦,为了更好地维护。


1.3 Spring MVC


Spring MVC 全名叫 Spring Web MVC,是一种基于 java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品。


不是吧,都 2021 年了你别说你还不会 Spring MVC 基本应用 Spring MVC 已经成为最主流的 MVC 框架之一。它通过一套注解,让一个简单的的 java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。


Spring MVC 的本质可以认为是对 servlet 的封装,简化开发。


Spring Mvc 和原生 Servlet 的区别:


不是吧,都 2021 年了你别说你还不会 Spring MVC 基本应用配置 SpringMvc 应用 0. 引入 pom 依赖


<?xml version="1.0" encoding="UTF-8"?><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"><parent><artifactId>lagou-study</artifactId><groupId>com.mmc</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><packaging>war</packaging>


<artifactId>spring-mvc</artifactId>
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.12.RELEASE</version> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency></dependencies>
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins></build>
复制代码


</project>配置前端控制器(DispatcherServlet)<!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>Archetype Created Web Application</display-name><servlet>    <servlet-name>springmvc</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet>
<servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 方式1:带后缀,比如*.action 方式2:/ 不会拦截*.jsp 方式3:/* 拦截所有,包括*.jsp,所以一般不用 --> <url-pattern>/</url-pattern></servlet-mapping>
复制代码


</web-app>编写 Controller 等接收请求的业务逻辑代码


@Controller@RequestMapping("/demo")public class DemoController {


@RequestMapping("/test")public ModelAndView test(){    Date date=new Date();    ModelAndView mv=new ModelAndView();    //添加数据,同request.setAttribute("date",date);    mv.addObject("date",date);    //试图信息,封装跳转的页面    mv.setViewName("success");    return mv;
}
复制代码


}编写 jsp 页面


<%@ page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" %><%@ page isELIgnored="false" %>


<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"/></head><body>跳转成功,当前服务器时间: ${date}</body></html>xml 配置文件配置 controller 扫描,<?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:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsd">


    <context:component-scan base-package="com.mmc.mvc.controller"></context:component-scan>

<!--配置试图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value=".jsp"></property> </bean>
<mvc:annotation-driven></mvc:annotation-driven> </beans>
复制代码


不是吧,都 2021 年了你别说你还不会 Spring MVC 基本应用 2.2 Spring MVC 九大组件


HandlerMapping (处理器映射器)HandlerMapping 是用来查找 Handler 的,也就是处理器,具体的表现形式可以是类,也可以是方法。比如,标注了 @RequestMapping 的每个方法都可以看成是一个 Handler。Handler 负责具体实际的请求处理,在请求到达后,HandlerMapping 的作用便是找到请求相应的处理器 Handler 和 Interceptor


HandlerAdapter (处理器适配器)HandlerAdapter 是⼀个适配器。因为 Spring MVC 中 Handler 可以是任意形式的,只要能处理请求即可。但是把请求交给 Servlet 的时候,由于 Servlet 的⽅法结构都是 doService(HttpServletRequest req,HttpServletResponse resp)形式的,要让固定的 Servlet 处理⽅法调⽤ Handler 来进⾏处理,便是 HandlerAdapter 的职责


HandlerExceptionResolverHandlerExceptionResolver ⽤于处理 Handler 产⽣的异常情况。它的作⽤是根据异常设置 ModelAndView,之后交给渲染⽅法进⾏渲染,渲染⽅法会将 ModelAndView 渲染成⻚⾯


ViewResolverViewResolver 即视图解析器,⽤于将 String 类型的视图名和 Locale 解析为 View 类型的视图,只有⼀个 resolveViewName()⽅法。从⽅法的定义可以看出,Controller 层返回的 String 类型视图名 viewName 最终会在这⾥被解析成为 View。View 是⽤来渲染⻚⾯的,也就是说,它会将程序返回的参数和数据填⼊模板中,⽣成 html⽂件。ViewResolver 在这个过程主要完成两件事情:ViewResolver 找到渲染所⽤的模板(第⼀件⼤事)和所⽤的技术(第⼆件⼤事,其实也就是找到视图的类型,如 JSP)并填⼊参数。默认情况下,Spring MVC 会⾃动为我们配置⼀个 InternalResourceViewResolver,是针对 JSP 类型视图的。


RequestToViewNameTranslatorRequestToViewNameTranslator 组件的作⽤是从请求中获取 ViewName.因为 ViewResolver 根据 ViewName 查找 View,但有的 Handler 处理完成之后,没有设置 View,也没有设置 ViewName,便要通过这个组件从请求中查找 ViewName。


LocaleResolerViewResolver 组件的 resolveViewName ⽅法需要两个参数,⼀个是视图名,⼀个是 Locale。LocaleResolver ⽤于从请求中解析出 Locale,⽐如中国 Locale 是 zh-CN,⽤来表示⼀个区域。这个组件也是 i18n 的基础。


ThemeResolverThemeResolver 组件是⽤来解析主题的。主题是样式、图⽚及它们所形成的显示效果的集合。Spring MVC 中⼀套主题对应⼀个 properties⽂件,⾥⾯存放着与当前主题相关的所有资源,如图⽚、CSS 样式等。创建主题⾮常简单,只需准备好资源,然后新建⼀个“主题名.properties”并将资源设置进去,放在 classpath 下,之后便可以在⻚⾯中使⽤了。SpringMVC 中与主题相关的类有 ThemeResolver、ThemeSource 和 Theme。ThemeResolver 负责从请求中解析出主题名,ThemeSource 根据主题名找到具体的主题,其抽象也就是 Theme,可以通过 Theme 来获取主题和具体的资源


MultipartResolverMultipartResolver ⽤于上传请求,通过将普通的请求包装成 MultipartHttpServletRequest 来实现。MultipartHttpServletRequest 可以通过 getFile() ⽅法 直接获得⽂件。如果上传多个⽂件,还可以调⽤ getFileMap()⽅法得到 Map<FileName,File>这样的结构,MultipartResolver 的作⽤就是封装普通的请求,使其拥有⽂件上传的功能。


FlashMapManagerFlashMap ⽤于重定向时的参数传递,⽐如在处理⽤户订单时候,为了避免重复提交,可以处理完 post 请求之后重定向到⼀个 get 请求,这个 get 请求可以⽤来显示订单详情之类的信息。这样做虽然可以规避⽤户重新提交订单的问题,但是在这个⻚⾯上要显示订单的信息,这些数据从哪⾥来获得呢?因为重定向时么有传递参数这⼀功能的,如果不想把参数写进 URL(不推荐),那么就可以通过 FlashMap 来传递。只需要在重定向之前将要传递的数据写⼊请求(可以通过 ServletRequestAttributes.getRequest()⽅法获得)的属性 OUTPUT_FLASH_MAP_ATTRIBUTE 中,这样在重定向之后的 Handler 中 Spring 就会⾃动将其设置到 Model 中,在显示订单信息的⻚⾯上就可以直接从 Model 中获取数据。FlashMapManager 就是⽤来管理 FalshMap 的


2.3 url parttern 配置及静态资源处理


<servlet-mapping><servlet-name>springmvc</servlet-name><url-pattern>/</url-pattern></servlet-mapping>三种配置方式:


第一种:后缀型,如*.action 第二种:/ 这种方式会拦截所有请求,包括静态资源(html、js、css、jpg 等)。但是不会拦截 jsp。为什么呢?


因为 tomcat 容器中有一个 web.xml(父),我们项目里也配置了一个 web.xml(子),他们是一个继承关系,两个 xml 的 url-pattern 都是/,子类的 xml 文件就会覆盖掉父类的,把所有静态资源的处理也接管到 spring mvc 里来了。


那么为什么 jsp 却不会被拦截呢?因为 tomcat 里面处理 jsp 的 servlet 配置的 url-parttern 是*.jsp,不会被子类的 xml 覆盖。


tomcat 里面的 servlet 配置如下:


<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping>第三种:/* 匹配所有请求静态资源处理两种方案


    <!--方案一    配置该标签后,会在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler对象,这个对象如同一个    检查人员,对进入DispathcherServlet的url请求进行过滤,如果发现是静态资源就把请求转给web应用服务器(tomcat)    默认的DefaultServlet来处理。    -->    <mvc:default-servlet-handler></mvc:default-servlet-handler>

<!--方案二,SpringMVC框架自己处理静态资源--> <mvc:resources mapping="/resources/**" location="images"></mvc:resources>
复制代码


2.4 自定义请求参数转换


当我们在请求参数中传入一个日期字符串时,期望后端能直接以日期格式接收。示例如下:


@RequestMapping("/testDate")public String testDate(Date date, Model model){model.addAttribute("date",date);return "success";}访问连接:http://localhost:8080/demo/testDate?date=2021-01-01


发现项目报错


[WARNING] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2021-01-01'; nested exception is java.lang.IllegalArgumentException]


Spring MVC 没有为我们默认处理这种情况,需要我们自己处理。


解决方案:自定义参数转换器


编写 DateConvert 类 public class DateConvert implements Converter<String, Date> {


@Overridepublic Date convert(String s) {    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");    try {        Date date = simpleDateFormat.parse(s);        return date;    } catch (ParseException e) {        e.printStackTrace();    }    return null;}
复制代码


}注册类型转换器<mvc:annotation-driven conversion-service="conversionServiceBean"></mvc:annotation-driven>


    <!--自定义类型转换器-->    <bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">        <property name="converters">            <set>                <bean class="com.mmc.mvc.convert.DateConvert"></bean>            </set>        </property>    </bean>
复制代码


书山有路勤为径,学海无涯苦作舟

用户头像

还未添加个人签名 2021.10.14 加入

还未添加个人简介

评论

发布
暂无评论
不是吧,都2021年了你别说你还不会Spring MVC基本应用