Spring MVC基础(一)

普通java项目转换为web项目
JBLJavaToWeb插件

1、SpringMVC概述

1.1 三层架构

SpringMVC 位于web层
在这里插入图片描述​ 开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构.

  • 三层架构

    ​ 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型

    ​ 业务层:处理公司具体的业务逻辑的

    ​ 持久层:用来操作数据库的

  • MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。

    ​ Model:数据模型,JavaBean的类,用来进行数据封装。

    ​ View:指JSP、HTML用来展示数据给用户

    ​ Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等

1.2 什么是SpringMVC

  • 用我们自己的话来说:SpringMVC 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB层框架。

  • 作用: 用于替代我们之前Web里面的Servlet的相关代码

    1. 参数绑定(获得请求参数)
    2. 调用业务
    3. 响应数据
    4. 分发转向等等

1.3 SpringMVC 的优点

1.清晰的角色划分:
​ 前端控制器(DispatcherServlet)
​ 请求到处理器映射(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风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。

2、SpringMVC入门

2.1、引入坐标:

在这里插入图片描述

	<!-- 版本锁定 -->
	<properties>
		<spring.version>5.0.2.RELEASE</spring.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
        
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.12</version>
    	</dependency>
	</dependencies>

2.2、编写HelloController

/**
 * 1. springmvc的配置Controller中的方法接收请求
 *    1. IOC配置,所有的Controller对象配置到spring的核心容器中
 *    2. 进行映射路径的配置,在要处理请求的方法上添加RequestMapping注解来配置映射路径
 *    3. 在配置文件中,配置DispatcherServlet的映射路径,并且配置服务器启动时加载
 *    4. 告诉DispatcherServlet,要加载的spring/springmvc的配置文件的路径
 *       通过servlet的初始化参数
 *
 * 2. 配置跳转到成功页面
 *    1. 配置视图解析器(在spring的配置文件中),将Controller的方法的返回值解析成真正的视图地址
 *    2. 让Controller的方法,返回一个匹配视图解析器的字符串
 */
 
@Controller
public class HelloController {

    @RequestMapping(value="/hello/sayHello")
    public String sayHello(){
        System.out.println("HelloController 的 sayHello 方法执行了。。。。 ");
        return "success";
    }
}

2.3、编写SpringMVC的配置文件

在classpath目录下创建applicationContext.xml

<?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">
    <!--1. 配置spring创建容器时要扫描的包 -->
    <context:component-scan base-package="com.it"></context:component-scan>
    
    <!--2. 加载mvc注解驱动-->
    <mvc:annotation-driven />
    <!--3. 配置视图解析器 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <!--
        配置由DefaultServlet处理静态资源
    -->
    <mvc:default-servlet-handler />
</beans>

<mvc:annotation-driven> 标签说明 :

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

mvc:annotation-driven注解的作用

SpingMVC之<mvc:annotation-driven/>标签

2.4、在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" id="WebApp_ID" version="2.5">
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:applicationContext.xml</param-value>
    </init-param>
    <!-- 配置 servlet 的对象的创建时间点:应用加载时创建。取值只能是非 0 正整数,表示启动顺序 -->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  	 <!-- 根据路径去找Controller方法 -->
    <servlet-name>dispatcherServlet</servlet-name>
    <!--
			除了jsp之外的请求,都要经过它
	-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

在这里插入图片描述
加载流程
1、服务器启动,应用被加载。 读取到 web.xml 中的配置创建 spring 容器并且初始化容器中的对象。
2、浏览器发送请求,被 DispatherServlet 捕获,该 Servlet 并不处理请求,而是把请求转发出去。转发的路径是根据请求 URL,匹配@RequestMapping 中的内容。
3、匹配到了后,执行对应方法。该方法有一个返回值。
4、根据方法的返回值,借助 InternalResourceViewResolver 找到对应的结果视图。
5、渲染结果视图,响应浏览器

3、SpringMVC 的请求响应流程

在这里插入图片描述

3.1 涉及的组件

  • DispatcherServlet:前端控制器**(最重要最关键**)

    ​ 用户请求到达前端控制器,它就相当于 mvc 模式中的 c, dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求, dispatcherServlet 的存在降低了组件之间的耦合性(符合面向对象设计的"迪米特法则")。

  • HandlerMapping:处理器映射器

    ​ HandlerMapping 负责根据用户请求找到 Handler 即处理器, SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

  • Handler:处理器 (自己写的Controller类)

    ​ 它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。

  • HandlAdapter:处理器适配器

    ​ 通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理 器进行执行。

  • View Resolver:视图解析器:将Controller返回的字符串,解析成具体的视图对象

    ​ View Resolver 负责将处理结果生成 View 视图, View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。

  • View:视图

    ​ SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jsp , jstlView、 freemarkerView、 pdfView等。我们最常用的视图就是 jsp。
    ​ 一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。

<mvc:annotation-driven> 注解说明 :

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

3、SpringMVC进阶

客户端传入给服务器端的请求参数一般分为两种:

  1. formdata类型的请求参数,例如:“username=aobama&pwd=123&nickname=圣枪游侠”,获取这类请求参数已经在前面详细讲解过了
  2. json类型的请求参数,例如使用axios发送异步的post请求携带的请求参数,而RequestBody注解的作用就是将json类型的请求参数封装到POJO对象或者Map中

获取(formdata类型)的请求参数

使用SpringMVC在Controller中获取客户端的请求参数,在这里绑定请求参数只是"key=value"类型的请求参数

  • 绑定机制

    ​ 表单提交的数据都是key=value格式的(username=zs&password=123),SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的(要求:提交表单的name和参数的名称是相同的)

  • 支持的数据类型

    ​ 基本数据类型和字符串类型,统称为简单数据类型

    ​ 实体类型(POJO类型)

    ​ 集合数据类型(List、map集合等)

    数组

  • 使用要求

    • 如果是基本类型或者 String 类型: 要求我们的参数名称必须和控制器中方法的形参名称保持一致。 (严格区分大小写) .
    • 如果是 POJO 类型,或者它的关联对象: 要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型 。参数前不能添加RequestParam注解
    • 如果是集合类型,有两种方式: 第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给 List 集合中的元素赋值, 使用下标。给 Map 集合中的元素赋值, 使用键值对。第二种:接收的参数直接封装到List或者Map中,需要加入RequestParam注解

3.1基本类型和 String 类型作为参数

前端页面访问路径

http://localhost:8080/user/findByName?username=jay&age=29

UserController

@RequestMapping("/findByName")
public String findByName(String username, int age){
    System.out.println("根据name为"+username+",查询用户,年龄为:"+age);
    return "success";
}

3.2POJO 类型作为参数

  • pojo
@Data
public class User implements Serializable {
    private String username;
    private String password;
    private String nickname;
    private Date birthday;
}
  • 前端页面
<html>
<head>
    <title>注册页面</title>
</head>
<body>
    <form method="post" action="/user/register">
        用户名<input type="text" name="username"><br>
        密码<input type="text" name="password"><br>
        昵称<input type="text" name="nickname"><br>
        生日<input type="text" name="birthday"><br>
        <input type="submit" value="注册">
    </form>
</body>
</html>
  • UserController.java
@PostMapping("register")
public String register(User user){
    System.out.println(user);
    return "success";
}

3.3POJO 类中包含集合类型参数(使用场景比较少)

3.3.1 POJO 类中包含List

  • User
@Data
public class User implements Serializable {
    private String username;
    private String password;
    private String nickname;
    private Date birthday;
    private List<String> hobbies;
}
  • 前端页面
<html>
<head>
    <title>注册页面</title>
</head>
<body>
    <form method="post" action="/user/register">
        用户名<input type="text" name="username"><br>
        密码<input type="text" name="password"><br>
        昵称<input type="text" name="nickname"><br>
        生日<input type="text" name="birthday"><br>
        兴趣爱好
        <input type="checkbox" name="hobbies" value="basketball">篮球
        <input type="checkbox" name="hobbies" value="football">足球
        <input type="checkbox" name="hobbies" value="yumaoball">羽毛球
        <input type="checkbox" name="hobbies" value="pingpangball">乒乓球<br>
        <input type="submit" value="注册">
    </form>
</body>
</html>
  • UserController.java
@PostMapping("register")
public String register(User user){
    System.out.println(user);
    return "success";
}

3.4 获取请求参数直接封装到List集合中,比如批量删除(项目中会用到)

什么是批量删除:客户端会想服务器端传入一个id的数组,包含要删除的说个id,那么服务器端得获取到客户端提交的数组中的所有id,然后遍历删除

UserController的代码

@RequestMapping("/deleteMore")
public String deleteMore(@RequestParam List<Integer> ids){
    System.out.println("要删除的数据:" + ids);
    return "success";
}

前端页面

<form action="/user/deleteMore" method="post">
    <input type="checkbox" name="ids" value="1">1<br>
    <input type="checkbox" name="ids" value="2">2<br>
    <input type="checkbox" name="ids" value="3">3<br>
    <input type="checkbox" name="ids" value="4">4<br>
    <input type="checkbox" name="ids" value="5">5<br>
    <input type="checkbox" name="ids" value="6">6<br>
    <input type="submit" value="删除">
</form>

注意点: 请求参数名,要和方法的参数名一致;并且要在List参数前添加@RequestParam注解

3.5 获取多个请求参数直接封装到Map中(项目中也会使用到)

  • map的key就是参数名,map的value就是参数值只能是String类型

  • 一定要记得在接收参数的Map前添加@RequestParam注解

UserController的代码

@RequestMapping("/register")
public String register(@RequestParam Map map){
    System.out.println("获取到的请求参数:" + map);
    return "success";
}

前端代码

<html>
    <head>
        <title>注册页面</title>
    </head>
    <body>
        <form method="post" action="/user/register">
            用户名<input type="text" name="username"><br>
            密码<input type="text" name="password"><br>
            昵称<input type="text" name="nickname"><br>
            生日<input type="text" name="birthday"><br>
            兴趣爱好
            <input type="checkbox" name="hobbies" value="basketball">篮球
            <input type="checkbox" name="hobbies" value="football">足球
            <input type="checkbox" name="hobbies" value="yumaoball">羽毛球
            <input type="checkbox" name="hobbies" value="pingpangball">乒乓球<br>
            <input type="submit" value="注册">
        </form>
    </body>
</html>

规律:

  1. 如果客户端是单个请求参数,肯定以简单数据类型接收
  2. 如果客户端的请求参数是多个同名参数,以List或者数组接收
  3. 如果客户端的请求参数是多个不同名的请求参数就以POJO对象接收
  4. 但是有的时候,可能没有对应的pojo对象,此时就使用map接收,接受参数的map中的key,就和请求参数名是一一对应的,map中的value就和请求参数值是一一对应
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 一、获取"name=value&name=value"类型的请求参数:
 *    1. 一个一个参数进行获取: 在处理请求的方法中,添加和请求参数同名的参数即可
 *       	如果请求参数名和方法的参数名不一致,可以通过RequestParam注解,
 * 			指定获取的请求参数名
 *    2. 封装请求参数:
 *       1. POJO类型: 在方法中加入一个POJO类型的参数,要求POJO中的属性和请求参数名一致,
 * 									POJO的属性一定要有set方法, POJO类一定要有无参构造
 * 									参数前不能添加RequestParam注解
 *       2. Map 类型: 在方法中加入一个Map类型的参数,此时map中接收的参数的key就是参数名,
 * 									value就是参数值
 *          一定要在Map类型的参数前添加RequestParam注解
 *
 *       3. 如果是多个同名参数,我们可以使用List或者数组进行封装,比如说"批量删除"
 *          1. 添加RequestParam注解
 *          2. 方法的参数名要和接收的请求参数名一致
 *
 *       4. 如果接收的请求参数是: 既有一个name对应一个value,也有一个name对应多个value
 *          比如说注册的时候: username、password、nickname、birthday、hobbies
 *          那么我们就将请求参数封装到POJO中,一个参数名对应一个参数值的情况我们就使用简单类型
 *          一个参数名对应多个参数值的情况我们就使用List类型
 *  二、获取请求参数当中存在的问题:
 *     1. post请求方式提交参数时候的中文乱码问题: 使用过滤器(使用spring提供的过滤器), 
 * 					我们需要做的就是在web.xml中配置过滤器
 *        1. 在web.xml中配置过滤器的拦截路径
 *        2. 在web.xml中通过过滤器的初始化参数配置,告诉过滤器我们想要使用什么编码
 *
 *     2. Date类型转换的问题
 *        spring中已经内置了很多的类型转换器,比如将String转成数字、将String转成Array、
 * 			将String转成Date
 *        如果有一些转换器是spring里面没有的,但是我们需要使用的,那么就需要自定义(自己指定)
 * 			类型转换规则
 *        例如: 将请求参数中 yyyy-MM-dd 类型的字符串,转换成Date, 实现方式有两种
 *             1. 在要进行类型转换的属性上使用DateTimeFormat注解实现局部类型转换
 *             2. 使用自定义类型转换器的方式,实现全局的类型转换
 *                2.1 编写一个类型转换器,实现Converter接口
 *                2.2 重写convert在这里面实现类型转换
 *                2.3 一定要在spring的配置文件中,配置类型转换器(目的就是让spring使用
 * 						你的类型转换器)
 *
 * 三、获取json类型的请求参数:
 *     1. 只能采用封装的形式,要么封装到POJO中,要么封装到Map中
 *     2. 要在方法的参数前添加RequestBody注解
 *     3. 引入json转换的依赖(springmvc默认支持的是jackson)
 */
@Controller
@RequestMapping("/user")
@SessionAttributes(names = {"uname","age"})
public class UserController {
    @RequestMapping("/findByName")
    public String findByName(@RequestParam("username") String name, int age){
        System.out.println("根据name为"+name+",查询用户,年龄为:"+age);
        return "success";
    }

    @RequestMapping("/register")
    public String register(User user){
        System.out.println("获取到的请求参数:" + user);
        return "success";
    }

    /*@RequestMapping("/register")
    public String register(@RequestParam Map map){
        System.out.println("获取到的请求参数:" + map);
        return "success";
    }*/

    @RequestMapping("/deleteMore")
    public String deleteMore(@RequestParam List<Integer> ids){
        System.out.println("要删除的数据:" + ids);
        return "success";
    }

    @RequestMapping("/useBody")
    public String useRequestBody(@RequestBody String body){
        //目标: 使用body参数来获取请求体的内容----->从请求体中获取参数
        System.out.println("请求体的内容是:" + body);
        return "success";
    }

    @RequestMapping("/useJson")
    public String useJson(@CookieValue("") User user, HttpSession session){
        session.setAttribute("age", 19);
        //目标: 使用body参数来获取请求体的内容----->从请求体中获取参数
        System.out.println("请求体的内容是:" + user);
        return "success";
    }

    /**
     *  .../findCheckItem?mealId=1&groupId=3&itemId=10
     * 目标: /套餐id/检查组的id/检查项的id ----> .../1/3/10
     * @return
     */
    @RequestMapping(method = RequestMethod.GET,path = "/{mealId}/{groupId}/{itemId}")
    public String findCheckItem(@PathVariable("mealId") int
    mealId,@PathVariable("groupId") int groupId,@PathVariable("itemId") int itemId){
        System.out.println("根据id查询:mealId=" + mealId + ",groupId=" + groupId +
         ",itemId=" + itemId);
        return "success";
    }

    @RequestMapping(method = RequestMethod.DELETE,path = "/{mealId}/{groupId}/{itemId}")
    public String deleteCheckItem(@PathVariable("mealId") int mealId,
    @PathVariable("groupId") int groupId,@PathVariable("itemId") int itemId){
        System.out.println("根据id删除:mealId=" + mealId + ",groupId=" + groupId + 
        ",itemId=" + itemId);

        return "success";
    }

    @RequestMapping("/setSessionValue")
    public String setSessionValue(Model model){
        //model是springmvc中的数据模型,其实就是存放数据的对象,数据是存放在request域
        model.addAttribute("uname","奥巴马");
        model.addAttribute("age",19);
        model.addAttribute("address","usa");
        return "success";
    }

    @RequestMapping("/responseJson")
    @ResponseBody
    public User responseJson(){
        //模拟从数据库查询数据
        User user = new User();
        user.setUsername("周杰伦");
        user.setPassword("123456");
        user.setNickname("双节棍");
        user.setBirthday(new Date());
        List<String> hobbiesList = new ArrayList<>();
        hobbiesList.add("basketball");
        hobbiesList.add("football");
        user.setHobbies(hobbiesList);
        //将user转换成json响应给客户端
        return user;
    }
}

获取json类型的请求参数

见下篇

4、SpringMVC相关注解

4.1 RequestParam【重点】

4.1.1使用说明

@RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容(key=value格式的(username=zs&password=123)),Content-Type默认为该属性。

不处理POJO类型

  • 作用:

    1. 把请求中指定名称的参数给控制器中的形参赋值
    2. 获取List、Map类型的请求参数必须添加

4.1.2使用实例

  1. 当方法的参数名与请求参数名不一致时,要有value属性值
    当客户端请求参数名为username,而controller中接收请求参数的变量叫name时候
@RequestMapping("/findByName")
public String findByName(@RequestParam("username") String name, int age){
    System.out.println("根据name为"+name+",查询用户,年龄为:"+age);
    return "success";
}
  1. 当使用RequestParam获取请求参数封装到List或者Map中的时候

属性

public @interface RequestParam {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	boolean required() default true;
	
	String defaultValue() default ValueConstants.DEFAULT_NONE;

}

1。value:请求中传入参数的名称,如果不设置后台接口的value值,则会默认为该变量名。

2。required:该参数是否为必传项。默认是true,表示请求中一定要传入对应的参数,否则会报404错误,如果设置为false时,当请求中没有此参数,将会默认为null,而对于基本数据类型的变量,则必须有值,这时会抛出空指针异常。如果允许空值,则接口中变量需要使用包装类来声明。

3。defaultValue:参数的默认值,如果请求中没有同名的参数时,该变量默认为此值。注意默认值可以使用SpEL表达式,如"#{systemProperties[‘java.vm.version’]}"

SpEL表达式

SpEL 语法扫盲与查询手册

4.2. RequestBody【最重点之一】

请求体: post方式的请求参数,get方式没有请求体

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {

	/**
	 * Whether body content is required.
	 */
	boolean required() default true;

}

4.2.1 具体使用

  1. 用于获取请求参数的POJO前加上RequestBody注解
@RequestMapping("/useJson")
public String useJson(@RequestBody User user){
    //目标: 使用body参数来获取请求体的内容----->从请求体中获取参数
    System.out.println("请求体的内容是:" + user);
    return "success";
}
  1. 前端可以使用postman发送post请求测试

4.3.PathVariable【重点】在以后的项目中使用很多

该注解的作用是,获取RestFul风格的url上的参数

4.3.1使用说明

  • 作用:

    用于绑定 url 中的占位符。 例如:请求 url 中 /delete/{id}, 这个{id}就是 url 占位符。
    url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

  • 属性:

    value: 用于指定 url 中占位符名称。
    required:是否必须提供占位符。

4.4. RequestHeader,也有使用场景

4.4.1使用说明

  • 作用:
    用于获取请求消息头。
  • 属性:
    value:提供消息头名称
    required:是否必须有此消息头
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestHeader {

	@AliasFor("name")
	String value() default "";

	/**
	 * The name of the request header to bind to.
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * Whether the header is required
	 */
	boolean required() default true;

	/**
	 * The default value to use as a fallback.
	 */
	String defaultValue() default ValueConstants.DEFAULT_NONE;

}

4.4.2使用实例

  • UserController
/**
 * 获取userAgent请求头的信息
 */
@RequestMapping("/getUserAgent")
public String getUserAgent(@RequestHeader(value="user-Agent") String userAgent){
    System.out.println("请求头userAgent的信息:" + userAgent);
    return "success";
}

4.5. @CookieValue

4.5.1使用说明

  • 作用:

    用于把指定 cookie 名称的值传入控制器方法参数。

  • 属性:

    value:指定 cookie 的名称。
    required:是否必须有此 cookie。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CookieValue {

	@AliasFor("name")
	String value() default "";

	/**
	 * The name of the cookie to bind to.
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * Whether the cookie is required.
	 */
	boolean required() default true;

	/**
	 * The default value to use as a fallback.
	 */
	String defaultValue() default ValueConstants.DEFAULT_NONE;

}

4.5.2使用实例

  • UserController.java
/**
 * 获取名字叫做JSESSIONID的cookie的值
 */
@RequestMapping("/getCookieValue")
public String getCookieValue(@CookieValue("JSESSIONID") String cookieValue){
    System.out.println("获取的cookie的值为:" + cookieValue);
    return "success";
}

4.6. @ModelAttribute

4.6.1使用说明

  • 作用:

将方法参数或方法返回值绑定到指定模型属性的注释,并将其公开给web视图。支持带有@RequestMapping方法的控制器类。

该注解是 SpringMVC4.3 版本以后新加入的。它可以用于修饰方法和参数。

​ 出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。如果有返回值,则自动将该返回值加入到ModelMap中,通过类型赋值注入到后面的控制器方法中

  • 属性:
    value:用于获取数据的 key。 key 可以是 POJO 的类名称,也可以是 map 结构的 key。

  • 应用场景:
    当表单提交数据不是完整的实体类数据时,保证没有提交数据的字段使用数据库对象原来的数据。
    例如:
    ​ 我们在编辑一个用户时,用户有一个创建信息字段,该字段的值是不允许被修改的。在提交表单数据是肯定没有此字段的内容,一旦更新会把该字段内容置为 null,此时就可以使用此注解解决问题。

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ModelAttribute {
	@AliasFor("name")
	String value() default "";

	/**
	 * The name of the model attribute to bind to.
	 * <p>The default model attribute name is inferred from the declared
	 * attribute type (i.e. the method parameter type or method return type),
	 * based on the non-qualified class name:
	 * e.g. "orderAddress" for class "mypackage.OrderAddress",
	 * or "orderAddressList" for "List&lt;mypackage.OrderAddress&gt;".
	 * @since 4.3
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * Allows declaring data binding disabled directly on an {@code @ModelAttribute}
	 * method parameter or on the attribute returned from an {@code @ModelAttribute}
	 * method, both of which would prevent data binding for that attribute.
	 * <p>By default this is set to {@code true} in which case data binding applies.
	 * Set this to {@code false} to disable data binding.
	 * @since 4.3
	 */
	boolean binding() default true;
}

4.6.2使用实例

UserController(用在方法上面)

    @ModelAttribute
    public Course init(){
        //模拟: 从session中获取用户id,然后设置给course对象
        Course course = new Course();
        course.setUserId(13);
        return course;
    }

    @RequestMapping("/add")
    public String add(Course course){
        //手动从session中获取user,然后往course设置user的id
        System.out.println("添加学科信息:"+course);
        return "success";
    }

@ModelAttribute注解的使用

4.7. @SessionAttributes

4.7.1使用说明

  • 作用:

    用于多次执行(多次请求)控制器方法间的数据共享。(该注解定义在类上)

  • 属性:
    value:用于指定存入的属性名称
    type:用于指定存入的数据类型。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface SessionAttributes {

	@AliasFor("names")
	String[] value() default {};

	/**
	 * The names of session attributes in the model that should be stored in the
	 * session or some conversational storage.
	 */
	@AliasFor("value")
	String[] names() default {};

	/**
	 * The types of session attributes in the model that should be stored in the
	 * session or some conversational storage.
	 */
	Class<?>[] types() default {};

}

4.7.2使用实例

  • SessionController
@Controller
@RequestMapping("/user")
@SessionAttributes(value = {"age","address"})
public class UserController {
/**
 * 调用该方法:往域对象中存放一个msg的值
 * @return
 */
@RequestMapping("/msg")
public String msg(Model model){
    //SpringMVC中model表示数据模型,其实也就是往域对象中存放数据
    //其实就是存放数据的对象,数据是存放在request域
        model.addAttribute("uname","aobama");
        model.addAttribute("age",19);
        model.addAttribute("address","usa");
    return "success";
  }
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
</head>
<body>
    <h1>访问成功!!!</h1>
    获取存放在request域对象中的uname的值${requestScope.uname}<br>
    获取存放在request域对象中的age的值${sessionScope.age}<br>
    获取存放在request域对象中的address的值${sessionScope.address}<br>
</body>
</html>

4.8 @DateTimeFormate

在要进行转换的变量上添加DateTimeFormate注解,指定转换的格式
双向转换的格式String到Date、Date到String

@Data
public class User implements Serializable {
    private String username;
    private String password;
    private String nickname;
    @DateTimeFormate("yyyy-MM-dd")
    //只能使用这种格式,别的格式报错
    private Date birthday;//开发中也只能使用一种格式
    private List<String> hobbies;
}

RequestMapping注解

1)RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系

2)RequestMapping注解可以作用在类和方法上

  • 使用在类上:

    ​ 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。 写的话需要以/开头 .它出现的目的是为了使我们的 URL 可以按照模块化管理

  • 使用在方法上:

    ​ 请求 URL 的第二级访问目录

@Controller
@RequestMapping("/account")
public class AccountController {
    @RequestMapping("/add")
    public String add(){
        System.out.println("添加账户");
        return "success";
    }
    @RequestMapping("/deletet")
    public String deletet(){
        System.out.println("删除账户");
        return "success";
    }
    @RequestMapping("/update")
    public String update(){
        System.out.println("更新账户");
        return "success";
    }
}

3)属性

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    String name() default "";

    @AliasFor("path")
    String[] value() default {};

    @AliasFor("value")
    String[] path() default {};

    RequestMethod[] method() default {};

    String[] params() default {};

    String[] headers() default {};

    String[] consumes() default {};

    String[] produces() default {};
}

1)在@Target中有两个属性,分别为 ElementType.METHOD 和 ElementType.TYPE ,也就是说 @RequestMapping 可以在方法和类的声明中使用

将 @RequestMapping 注解在 UserController 类上,这时类的注解是相对于 Web 根目录,而方法上的是相对于类上的路径

2)可以看到注解中的属性除了 name() 返回的字符串,其它的方法均返回数组,也就是可以定义多个属性值,例如 value() 和 path() 都可以同时定义多个字符串值来接收多个URL请求

3)RequestMapping 支持带占位符的URL ,见@PathVariable注解

path: 指定请求路径的url,可以不写“/”
value: value属性和path属性是一样的
method : 指定该方法的请求方式,可以给 method 同时指定多个请求方式
在Spring中,使用枚举类
org.springframework.web.bind.annotation.RequestMethod来定义浏览器请求的方式。
GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE.

//只能接受post方式请求
@RequestMapping(value = "/add",method ={RequestMethod.POST} )
//@PostMapping("/add")
 public String add(){
    System.out.println("添加账户");
    return "success";
}

可以使用GetMapping、PostMapping注解指定只能使用get、post方式访问

params: 指定限制请求参数的条件

//请求参数必须是money=18,如果不是,则会报错(HTTP Status 400 – Bad Request)
@RequestMapping(value = "/add",params = {"money=18"})
 public String add(){
     System.out.println("添加账户");
     return "success";
}

headers: 发送的请求中必须包含的请求头

 //请求头必须有content-type=text/*,否则就会报错
 @RequestMapping(value = "/add",headers ="content-type=text/*" )
 public String add(){
      System.out.println("添加账户");
      return "success";
}

5、请求参数细节和特殊情况

5.1请求参数乱码处理

  • 在web.xml里面配置编码过滤器
<!--
  配置解决全局乱码的过滤器
 -->
<filter>
    <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

5.2 自定义类型转换器

​ 默认情况下,SpringMVC已经实现一些数据类型自动转换。 内置转换器全都在: org.springframework.core.convert.support 包下 ,如遇特殊类型转换要求,需要我们自己编写自定义类型转换器。

java.lang.Boolean -> java.lang.String : ObjectToStringConverter
java.lang.Character -> java.lang.Number : CharacterToNumberFactory
java.lang.Character -> java.lang.String : ObjectToStringConverter
java.lang.Enum -> java.lang.String : EnumToStringConverter
java.lang.Number -> java.lang.Character : NumberToCharacterConverter
java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory
java.lang.Number -> java.lang.String : ObjectToStringConverter
java.lang.String -> java.lang.Boolean : StringToBooleanConverter
java.lang.String -> java.lang.Character : StringToCharacterConverter
java.lang.String -> java.lang.Enum : StringToEnumConverterFactory
java.lang.String -> java.lang.Number : StringToNumberConverterFactory
java.lang.String -> java.util.Locale : StringToLocaleConverter
java.lang.String -> java.util.Properties : StringToPropertiesConverter
java.lang.String -> java.util.UUID : StringToUUIDConverter
java.util.Locale -> java.lang.String : ObjectToStringConverter
java.util.Properties -> java.lang.String : PropertiesToStringConverter
java.util.UUID -> java.lang.String : ObjectToStringConverter

SpringMVC内置的是将 1999/03/04这种格式的字符串转换成Date,而客户端如果传入的是1999-03-04这种格式的,所以无法进行转换

5.2.1 使用DateTimeFormate注解进行局部类型转换

在要进行转换的变量上添加DateTimeFormate注解,指定转换的格式

@Data
public class User implements Serializable {
    private String username;
    private String password;
    private String nickname;
    @DateTimeFormate("yyyy-MM-dd")
    private Date birthday;
    private List<String> hobbies;
}

这种方式有局限性,只能是添加了DateTimeFormate注解的变量能够进行转换,没有添加的变量还是会使用SpringMVC默认的转换规则

5.2.2 自定义类型转换器

其实SpringMVC中内置有类型转换器,它可以进行一些基本类型的转换,比如说String转成int等等操作

步骤:

  1. 创建一个类实现Converter 接口
  2. 配置类型转换器

实现:

  • 定义一个类,实现 Converter 接口
import org.springframework.core.convert.converter.Converter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateConverter implements Converter<String, Date>{
    @Override
    public Date convert(String source) {
        //source就是要进行类型转换的那个字符串,比如"1999-03-03"
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        //返回值就是转换成的Date
        try {
            return simpleDateFormat.parse(source);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException("Date转换异常!!!");
        }
    }
}
  • 在springmvc.xml里面配置转换器

    spring 配置类型转换器的机制是,将自定义的转换器注册到类型转换服务中去

<!-- 配置类型转换器 -->
<bean id="converterService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <!-- 给工厂注入一个新的类型转换器 -->
    <property name="converters">
        <array>
            <!-- 配置自定义类型转换器 -->
            <bean class="com.it.convert.DateConverter"></bean>
        </array>
    </property>
</bean>
  • 在 annotation-driven 标签中引用配置的类型转换服务
<!--配置Spring开启mvc注解-->
<mvc:annotation-driven conversion-service="converterService">
</mvc:annotation-driven>

5.3 使用 ServletAPI 对象作为方法参数

SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。我们可以把它们直接写在控制的方法参数中使用。 支持原始 ServletAPI 对象有 :

​ HttpServletRequest

​ HttpServletResponse

​ HttpSession

​ java.security.Principal

​ Locale

​ InputStream

​ OutputStream

​ Reader

​ Writer

  • 页面
<a href="account/testServletAPI?name=zs">使用 ServletAPI 对象作为方法参数</a>

AccountController

@RequestMapping("/useServletApi")
public String userServletApi(HttpSession session, HttpServletRequest request){
    String header = request.getHeader("User-Agent");
    System.out.println(header);
    //向使用session对象存值
    session.setAttribute("username","奥巴马");
    return "success";
}

Converter 接口

可以将一种数据类型转换成另一种数据类型的接口,这里 S 表示源类型,T 表示目标类型。

该接口有两个泛型,S:表示接受的类型, T:表示目标类型(需要转成的类型)

package org.springframework.core.convert.converter;

import org.springframework.lang.Nullable;

@FunctionalInterface
public interface Converter<S, T> {
    @Nullable
    T convert(S var1);
}

SpringMVC–Converter(类型转换器)详解

6、JavaWeb四大域对象

JavaWeb四大域对象之request

@CrossOrigin

HttpEntity<T>

表示HTTP请求或响应实体,由报文头和响应体组成。

通常与 org.springframework.web.client.RestTemplate 结合使用。像这样:

   HttpHeaders headers = new HttpHeaders();
   headers.setContentType(MediaType.TEXT_PLAIN);
   HttpEntity<String> entity = new HttpEntity<String>(helloWorld, headers);
   URI location = template.postForLocation("https://example.com", entity);
   
or
   HttpEntity<String> entity = template.getForEntity("https://example.com", String.class);
   String body = entity.getBody();
   MediaType contentType = entity.getHeaders().getContentType();

也可以在Spring MVC中使用,作为@Controller方法的返回值:

   @RequestMapping("/handle")
   public HttpEntity<String> handle() {
     HttpHeaders responseHeaders = new HttpHeaders();
     responseHeaders.set("MyResponseHeader", "MyValue");
     return new HttpEntity<String>("Hello World", responseHeaders);
   }

RestTemplate

同步客户端来执行HTTP请求,在底层HTTP客户端库(如JDK HttpURLConnection、Apache HttpComponents等)上公开一个简单的模板方法API。
除了支持不太常见情况的通用交换和执行方法外,RestTemplate还通过HTTP方法为常见场景提供模板。

注意:从5.0开始,非阻塞的、响应式的org.springframework.web.reactive.client.WebClient提供了一个现代的RestTemplate替代方案,有效地支持同步和异步,以及流场景。RestTemplate将在未来的版本中弃用,今后也不会添加主要的新特性。更多细节和示例代码,请参阅Spring Framework参考文档中的WebClient部分

WebClient

HttpClient

HttpClient
HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

HttpClient通俗的讲就是模拟了浏览器的行为,如果我们需要在后端向某一地址提交数据获取结果,就可以使用HttpClient.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值