第二章 SpringMVC

回顾

依赖注入:给对象中的属性赋值

构造赋值,set赋值

注解赋值

1.创建对象用的:

Component (controller service Repository)

2.注入数据
@Value基本类型和字符串类型

@Autowired 根据类型注入

@Qualifier 找bean名字

@Resource

3.@Scope

4.生命周期相关的

springMVC:

核心:前端控制器

参数接收:

1.普通参数,对象接收参数,@ResquestBody(复杂类型)

@ResquestMapping() @RequestParam

课前测:

模拟controller, dao,service层,使用bean.xml配置。

本章内容

第一节:SpringMVC 的简介

1.关于三层架构和MVC
  • 三层架构
    我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,所以我们课程中的案例也都是基于三层架构设计的。三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面。
    表现层:
    也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。表现层依赖业务层,接收到客户端请求一般会调用业务层进行业务处理,并将处理结果响应给客户端。表现层的设计一般都使用 MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
    业务层:
    也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务一致性。(也就是我们说的,事务应该放到业务层来控制
    持久层:
    也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进行持久化的载体,数据访问层是业务层和持久层交互的接口,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进行增删改查的。
  • MVC
    MVC 全名是 Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职:
    **Model(模型):**通常指的就是我们的数据模型。作用一般情况下用于封装数据。
    **View(视图):**通常指的就是我们的 jsp 或者 html。作用一般就是展示数据的。
    通常视图是依据模型数据创建的。
    **Controller(控制器):**是应用程序中处理用户交互的部分。作用一般就是处理程序逻辑的。
2.SpringMVC的概述

Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发,Spring Web MVC也是要简化我们日常Web开发的。

3.SpringMVC的优点

javaWeb : servlet,filter ,listener

1、清晰的角色划分:

前端控制器(DispatcherServlet)—> Dispatcher(调度) + Servlet

对不同的Servlet进行调度 分发,MVC核心

请求到处理器映射(HandlerMapping)

处理器适配器(HandlerAdapter)

视图解析器(ViewResolver)

处理器或页面控制器(Controller)

验证器( Validator)

命令对象(Command 请求参数绑定到的对象就叫命令对象)

表单对象(Form Object 提供给表单展示和提交到的对象就叫表单对象)。

2、分工明确,而且扩展点相当灵活,可以很容易扩展,虽然几乎不需要。

3、由于命令对象就是一个 POJO,无需继承框架特定 API,可以使用命令对象直接作为业务对象。

4、和 Spring 其他框架无缝集成,是其它 Web 框架所不具备的。

5、可适配,通过 HandlerAdapter 可以支持任意的类作为处理器。

6、可定制性,HandlerMapping、ViewResolver 等能够非常简单的定制。

7、功能强大的数据验证、格式化、绑定机制。

8、利用 Spring 提供的 Mock 对象能够非常简单的进行 Web 层单元测试。

9、本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换。

10、强大的 JSP 标签库,使 JSP 编写更容易。

……还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等

4. SpringMVC和 Struts2 的优略分析(记住面试题)

共同点:它们都是表现层框架,都是基于 MVC 模型编写的。它们的底层都离不开原始 ServletAPI。它们处理请求的机制都是一个核心控制器。

javaWeb三大组件:servlet , filter , listener

区别

Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter

Spring MVC 是基于方法设计的,而 Struts2 是基于类,Struts2 每次执行都会创建一个动作类。所

以 Spring MVC 会稍微比 Struts2 快些。

Spring MVC 使用更加简洁,同时还支持 JSR303, 处理 ajax 的请求更方便

(JSR303 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们 JavaBean 的属性上面,就可以在需要校验的时候进行校验了。)

Struts2 的 OGNL 表达式使页面的开发效率相比 Spring MVC 更高些,但执行效率并没有比 JSTL 提

升,尤其是 struts2 的表单标签,远没有 html 执行效率高。

第二节:SpringMVC的入门项目(*)

1.需求分析
  • 前台index.jsp页面 有超链接 / form表单 向后台发送请求
  • 到后台的controller接收请求,并做出响应
  • 跳转到success.jsp页面
2.环境的搭建
2.1 创建web项目并拷贝jar包
<!--加依赖-->
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.8</version>
        </dependency>
    </dependencies>
2.2 在web.xml文件中配置核心容器
<web-app>
  <servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>
2.3 创建springmvc配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启注解包扫描-->
    <context:component-scan base-package="com.bai" ></context:component-scan>
    <!--配置视图解析器-->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>   
    <!--springmvc注解驱动,@RequestMapping  -->
    <mvc:annotation-driven />
</beans>
2.4 编写控制器并使用注解配置
package com.bai.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * @ClassName HelloSpringMvc
 * @Description ToDo
 * @Auther teacher Bai
 * @Date 2020/12/22 0:16
 */
@Controller
public class HelloSpringMvc {

    //配置访问的路径
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("你好哈哈h");
        //对应jsp页面
        return "success";
    }
}
2.5 测试运行,观察结果。
2.6 springMVC入门案例的流程总结

前端jsp页面/html页面《—》发出请求----》controller《----》dao《----》数据库

2.7 入门案例中组件的简介

面试题:springmvc的运行原理 背住!

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、DispatcherServlet响应用户。

  • DispatcherServlet:前端控制器
    用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
  • HandlerMapping:处理器映射器
    HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等
  • Handler:处理器
    它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
  • HandlAdapter:处理器适配器
    通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  • View Resolver:视图解析器
    SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
2.8 < mvc:annotation-driven>注解说明

在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。使 用 mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器) 和RequestMappingHandlerAdapter ( 处 理 适 配 器),可 用 在 SpringMVC.xml 配 置 文 件 中 使 用mvc:annotation-driven替代注解处理器和适配器的配置。

2.9 RequestMapping注解

作用用于建立请求 URL 和处理请求方法之间的对应关系。

出现位置:可以是类上,也可以是方法上。

如果是作用于类上的叫窄化处理(精准定位)

属性:

value: 用于指定请求的url ,跟path属性完全相同。

method: 用于指定请求的方法。

@RequestMapping(value="findItem",method=RequestMethod.GET);
@RequestMapping(value="findItem",method=RequestMethod.POST);
@RequestMapping(value="findItem",method={RequestMethod.GET,RequestMethod.POST});

params:属性基本没用了,不用记忆


使用RequestMapping()访问多级目录


请求的注解:

@GetMapping          //该方法只接收get请求
@PostMapping         
@PutMapping         
@DeleteMapping

第三节:请求的参数传递

1.普通参数传递入门

请求的Controller方法中直接接收参数。

2.请求参数封装实体对象类型

使用set方法接收参数。name名字和类的属性名一致。

参数到达控制器后,会按照实体类中的set方法自动封装成javaBean对象。

3.设置请求的编码乱码问题
  • 可以使用servlet的过滤器
    参考servlet字符编码过滤器
  • 可以使用SpringMVC提供的过滤器
<!-- 字符串配置-->
    <filter>
        <filter-name>charfilter</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>charfilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
4.常用注解
  • @RequestParam
    **作用:**把请求中指定名称的参数给控制器中的形参赋值。
    属性:
    value:请求中参数的名称
  • @RequestBody
    **作用:**用于获取请求体内容。直接使用得到是 key=value&key=value…结构的数据。
    get 请求方式不适用。
    @requestBody注解用来处理 content-type 不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。
    发送ajax请求时,如果设置content-type:‘application/json;charset=utf-8’ ,可以直接将json类型的数据封装到javaBean对象中。
    **属性:**required:是否必须有请求体。默认值是:true。当取值为 true 时,get 请求方式会报错。如果取值为 false,get 请求得到是 null。
    1.导入jackson的三个jar包
<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.4</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.12.4</version>
        </dependency>

2.前台发送请求:

3.后台controller接收请求

  • @PathVariable 路径变量
    作用:用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个**{id}**就是 url 占位符。url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 restful 风格 URL 的一个重要标志。
    **属性:**value:用于指定 url 中占位符名称。required:是否必须提供占位符。
RESTful 风格 URL

什么是 rest:**REST(英文:Representational State Transfer,简称 REST)描述了一个架构样式的网络系统,比如 web 应用程序。它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种 Web 服务交互方案中,REST 相比于 SOAP(Simple Object Access protocol,简单对象访问协议)以及 XML-RPC 更加简单明了,无论是对 URL 的处理还是对 Payload 的编码,REST 都倾向于用更加简单轻量的方法设计和实现。值得注意的是 REST 并没有一个明确的标准,而更像是一种设计的风格。它本身并没有什么实用性,其核心价值在于如何设计出符合 REST 风格的网络接口。restful 的优点它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

restful 的特性:资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个 URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的 URI 就可以,因此 URI 即为每一个资源的独一无二的识别符。 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层 (Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。状态转化(State Transfer):每 发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP 协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GETPOSTPUTDELETE

它们分别对应四种基本操作:

GET 用来获取资源

POST 用来新建资源 添加

PUT 用来更新资源 修改

DELETE 用来删除资源 删除

restful 的示例:

/account/1 HTTP GET : 得到 id = 1 的 account

/account/1 HTTP DELETE: 删除 id = 1 的 account

/account/1 HTTP PUT: 更新 id = 1 的 account

<form action="emp/1" method="post">
    <input name="_method" value="delete">
    <input type="submit" value="删除一号图书" >
</form>
<form action="/book/1" method="post">
    <input name="_method" value="put">
    <input type="submit" value="更新一号图书"  >
</form>

第四节:响应数据和结果视图

1.响应字符串(String)类型数据

controller 方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。

通过spring内置的Model对象可以传输数据。

2.响String类型

方式类似于servlet的方式,直接调用servlet相应的请求和响应对象

请求转发

重定向

直接写出数据writer

也可以不经过视图解析器,直接完成请求转发和重定向。

return “forward:xxx.jsp”;//转发

return “redirect:testReturnModelAndView”; //重定向 页面不能在WEB-INF目录下


return “forward:xxx.jsp”;//转发

return “redirect:testReturnModelAndView”; //重定向 页面不能在WEB-INF目录下

3.响应ModelAndView类型

跟方式1响应字符串传参数类似。

ModelAndView mv = new ModelAndView();

mv.addObject(String,Object);设置数据:

mv.setViewName(“success”);设置视图的名字


4.请求和响应的静态资源放行

我们配置的前端控制器会拦截所有的请求,所以我们在项目中引入的静态资源,js文件,css文件,图片文件,都会被拦截,导致不能使用,所以需要配置。

在springmvc.xml中配置放行静态资源
<!--设置静态资源的放行-->
<mvc:resources mapping="/js/**" location="/js/"></mvc:resources>
在web.xml中配置静态资源放行
<!--配置静态资源放行-->
<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
    <url-pattern>*.jpg</url-pattern>
    <url-pattern>*.css</url-pattern>
</servlet-mapping>
<!--默认放行一切静态资源-->
<mvc:default-servlet-handler/>
5.@ResponseBody注解 (跟我们的ajax请求相关了)

为什么要学它?页面和后台之间有一些数据的交互,就是json数据。

通过@ResponseBody 设定当前函数的返回值要进行json转换(jackson)并且响应ajax。

加过该注解之后,不再走SpringMVC的视图解析器,直接返回数据给页面等需要获取json的url。

@ResponseBody的作用其实是将java对象转为json格式的字符串数据。

@ResponseBody注解的作用是将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过response对象输出指定格式的数据。 resp.getWriter.write()

@ResponseBody是作用在方法上的,@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用【也就是AJAX】。

我们现在的开发模式是 前后台分离。也就是说前端网页发送ajax请求获取后台数据。后台java只需要写接口,响应ajax请求返回json数据。此时如果一个类中所有的函数都是返回json数据,我们可以每个函数都添加@ResponseBody,也可以每个函数都不添加,将当前类设置成**@RestController**。===>@Controller + @ResponseBody。

环境:Springmvc 默认用 MappingJacksonHttpMessageConverter 对 json 数据进行转换,需要加入jackson 的包。

关于springmvc中日期数据在前后台传递时的问题:

解决方法一:

需要在实体类的date字段上添加注解。

//数据从前台传到后台时,日期是字符串无法封装成Date类型,使用以下注解解决问题。
@DateTimeFormat(pattern = "yyyy-MM-dd") 
//数据从后台发到前台显示时间戳格式,使用以下注解解决问题。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")

解决方法二:

<mvc:annotation-driven>
    <!-- 配置时间转换器 -->
    <mvc:message-converters>
        <!-- jackson  2.5.x -->
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="com.fasterxml.jackson.databind.ObjectMapper">
                    <property name="dateFormat">
                        <bean class="java.text.SimpleDateFormat">
                            <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss"></constructor-arg>
                        </bean>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

作业:

使用spring+springmvc+ajax+layui+jdbc打通整个项目。一套增删改查(把日期加进去。)。

做到:

清楚每一个注解的含义。

当做某一步操作时,回想一下,使用servlet是怎么搞的?现在使用spring/springmvc是怎么做的

自己总结对比一波。只有你自己真正对比过了,你才能知道,spring/springmvc好在哪!

```

作业:

使用spring+springmvc+ajax+layui+jdbc打通整个项目。一套增删改查(把日期加进去。)。

做到:

清楚每一个注解的含义。

当做某一步操作时,回想一下,使用servlet是怎么搞的?现在使用spring/springmvc是怎么做的

自己总结对比一波。只有你自己真正对比过了,你才能知道,spring/springmvc好在哪!