SpringMVC学习笔记(一)

一、SpringMVC的基本概念

(一)三层架构和MVC

1、三层架构概述

        我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,几乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使用的非常多,所以我们课程中的案例也都是基于三层架构设计的。
三层架构中,每一层各司其职,接下来我们就说说每层都负责哪些方面:
(1)表现层:也就是我们常说的web层。它负责接收客户端请求,向客户端响应结果,通常客户端使用http协议请求web 层,web 需要接收 http 请求,完成 http 响应。
表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
(2)业务层:也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项目的需求息息相关。
(3)持久层:也就是我们是常说的 dao 层。负责数据持久化,和数据库做交互。

2、model1模式介绍

        这种模式十分简单,页面显示,控制分发,业务逻辑,数据访问全部通过Jsp去实现

3、model2模式介绍

        这种模式通过两部分去实现,即Jsp与Servlet。Jsp负责页面显示,Servlet负责控制分发,业务逻辑以及数据访问。

4、MVC模式介绍

        MVC模式则分为三大块,即视图(View)控制器(Control)模型(Model).视图是Jsp负责的页面显示,控制器则是Servlet负责的控制分发,模型包括Service和Dao两个部分,分别负责业务逻辑和数据访问。

5、三种模型对比

Model1 模式的优缺点:
        优点:架构简单,比较适合小型项目开发
        缺点:JSP 职责不单一,职责过重,不便于维护
Model2 模式的优缺点:
        优点:职责清晰,较适合于大型项目架构
        缺点:不适合小型项目开发
MVC模式的优缺点:
        优点:分工明确,各司其职,互不干涉。适用于大型项目架构,有利于组件的重构
        缺点:增加了系统开发的复杂度

(二)SpringMVC 概述

1、springMVC是什么?

        SpringMVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持RESTful编程风格的请求。

2、SpringMVC在三层架构中的位置?

        springMVC位于三层架构中的表现层,作用是接收请求响应数据,响应的数据通过视图、模板展示给用户。

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风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等。

二、SpringMVC入门

(一)SpringMVC 的入门案例

1、入门案例需求分析

        构建页面index.jsp发起请求,在服务器端处理请求,控制台打印处理请求成功,跳转main.jsp成功页面;

2、构建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.jn</groupId>
  <artifactId>SpringMVC01</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>SpringMVC01 Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>

<!--junit-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

<!--spring-webmvc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.3.4</version>
    </dependency>

<!--spring-web-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.3.4</version>
    </dependency>

<!--spring-context-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.4</version>
    </dependency>
  </dependencies>
</project>

3、在web-app目录下配置index.jsp页面 

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/hello/test1"></a>

</body>
</html>

4、在web-app目录下配置跳转页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>请求处理成功</h2>
</body>
</html>

5、web.xml中配置核心控制器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>

  <!-- 配置Spring MVC的前端控制器 -->
  <servlet>
    <!-- servlet的名称 -->
    <servlet-name>spring-mvc</servlet-name>
    <!-- servlet的类路径,指向Spring的请求分发器 -->
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 初始化参数,指定Spring MVC配置文件的位置 -->
    <init-param>
      <!-- 参数名称:配置文件位置 -->
      <param-name>contextConfigLocation</param-name>
      <!-- 参数值:配置文件在类路径下的位置 -->
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>

  <!-- 配置spring-mvc servlet的URL映射规则 -->
  <servlet-mapping>
    <!-- 对应的servlet名称 -->
    <servlet-name>spring-mvc</servlet-name>
    <!-- URL模式,匹配以.do结尾的请求 -->
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

</web-app>

6、配置springMVC的配置文件springmvc.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: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/context 
       https://www.springframework.org/schema/context/spring-context.xsd">

<!--扫描注解的包-->
    <context:component-scan base-package="com.jn.controller"/>
    
<!--处理映射器:根据请求路径匹配映射路径找到对应的执行器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    </bean>
    
<!--处理适配器:根据处理映射器返回的执行器对象去执行执行器对象-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    </bean>
    
<!--视图解析器:解析视图-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

   7、控制层controller

package com.jn.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloController {
    @RequestMapping("hello")
    public String test1(){
        System.out.println("请求处理成功");
        return "RequestSuccessful";
    }
}

8、测试 

        启动tomcat进行测试 ,然后点击hello超链接跳转到成功页面。

注意:使用tomcat10以上版本会报错,所以本次测试使用的是tomcat8版本

(二)SpringMVC执行过程及原理分析

1、案例的执行过程

        浏览器客户端发起请求,请求到达服务器tomcat,tomcat将请求相关信息参数封装到对象request和response中,再将request和response对象交给service方法处理,在service方法中会根据请求路径将请求交给对应的controller执行器处理。

2、SpringMVC的请求响应流程

        浏览器发送请求,被DispatcherServlet捕获,DispatcherServlet没有直接处理请求,而是将请求交给HandlerMapping处理器映射器,处理器映射器根据请求路径去controller控制层中匹配对应的执行器,并将匹配结果返回给DispatcherServlet,由DispacherServlet调用HandlerAdapter处理器适配器来执行控制层执行器方法;
        执行器方法执行后的返回结果,由DispatcherServlet交给视图解析器ViewResolver来处理,找到对应的结果视图,渲染视图,并将结果响应给浏览器。

(三)SpringMVC常用组件介绍

1、DispatcherServlet:前端控制器

        用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。

2、HandlerMapping:处理器映射器

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

3、Handler:处理器

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

4、HandlAdapter:处理器适配器

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

5、View Resolver:视图解析器

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

6、View:视图

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

7mvc:annotation-driven标签说明:

        在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。使用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping(处理映射器)和RequestMappingHandlerAdapter ( 处 理 适 配 器 ),可 用 在 SpringMVC.xml 配 置 文 件 中 使 用<mvc:annotation-driven>替代处理映射器和适配器的配置(一般开发中都需要该标签)。注意:我们只需要编写处理具体业务的控制器以及视图。
    
<mvc:annotation-driven> 标签相当于以下配置:

<!--处理映射器:根据请求路径匹配映射路径找到对应的执行器-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    </bean>

<!--处理适配器:根据处理映射器返回的执行器对象去执行执行器对象-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    </bean>

(四)RequestMapping 注解

        用于定义映射路径,建立请求url和控制层方法之间的对应关系;

1、RequestMapping 注解源码解读

@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 {};
}

2、RequestMapping 注解的描述

(1)注解位置:
            a.类上:定义一级映射路径;
            b.方法上:定义二级映射路径;
(2)注解属性:   
            value:用于指定映射路径url。它和 path 属性的作用是一样的。
            method:用于指定请求的方式。
            params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的     key 和 value 必须和配置的一模一样。eg:params = {"username"},表示请求参数必须有 username;
            headers:用于指定限制请求消息头的条件。
    注意:多个属性之间是与的关系;

三、SpringMVC中的请求参数绑定

(一)绑定说明

1、绑定的机制

我们都知道,表单中请求参数都是基于 key=value 的。SpringMVC绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。

2、支持的数据类型

基本类型参数:包括基本类型和 String 类型
POJO 类型参数:包括实体类,以及关联的实体类
数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)

3、使用要求:

如果是基本类型或者 String 类型:要求我们的参数名称必须和控制器中方法的形参名称保持一致。(严格区分大小写)
如果是 POJO 类型,或者它的关联对象:要求表单中参数名称和 POJO 类的属性名称保持一致。并且控制器方法的参数类型是 POJO 类型。
如果是集合类型,有两种方式:
(1)第一种:要求集合类型的请求参数必须在 POJO 中。在表单中请求参数名称要和 POJO 中集合属性名称相同。给 List 集合中的元素赋值,使用下标。给 Map 集合中的元素赋值,使用键值对。
(2)第二种:接收的请求参数是 json 格式数据。需要借助一个注解实现。

(二)参数绑定示例

1、基本类型和 String 类型作为参数

(1)页面定义请求:
<form action="stringTest" method="post">
    name :<input type="text" name="name"><br>
    age :<input type="text" name="age"><br>
    <input type="submit" value="提交">
</form>
(2)执行器方法绑定参数:
    //测试String类型作为参数
    @RequestMapping("stringTest")
    public String testString(String name,int age){
        System.out.println("name:" + name);
        System.out.println("age:" + age);
        return "RequestSuccessful";
    }

2、POJO 类型作为参数

(1)实体类创建:

Car: 

package com.jn.pojo;

public class Car {
    private String name;
    private int price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

User: 

package com.jn.pojo;

public class User {
    private String name;
    private int age;
    private Car car;


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                '}';
    }
}
(2)页面定义请求:
<div>
    <form action="pojoTest">
        name :<input type="text" name="name"><br>
        age :<input type="text" name="age"><br>
        carName :<input type="text" name="car.name"><br>
        carPrice :<input type="text" name="car.price"><br>
        <input type="submit" value="提交">
    </form>
</div>
(3)执行器方法绑定参数:
    //测试Pojo类型作为参数
    @RequestMapping("pojoTest")
    public String testPojo(User user){
        System.out.println(user);
        return "RequestSuccessful";
    }


3、POJO 类中包含集合类型参数

(1)User类修改
package com.jn.pojo;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class User {
    private String name;
    private int age;
    private Car car;
    private List<Car> carList;
    private Set<Car> carSet;
    private HashMap<String,Car> carMap;
    
    
    User(){
        //初始化set集合
        carSet=new HashSet<>();
        Car car = new Car();
        Car car1=new Car();
        carSet.add(car);
        carSet.add(car1);
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public List<Car> getCarList() {
        return carList;
    }

    public void setCarList(List<Car> carList) {
        this.carList = carList;
    }

    public Set<Car> getCarSet() {
        return carSet;
    }

    public void setCarSet(Set<Car> carSet) {
        this.carSet = carSet;
    }

    public HashMap<String, Car> getCarMap() {
        return carMap;
    }

    public void setCarMap(HashMap<String, Car> carMap) {
        this.carMap = carMap;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", car=" + car +
                ", carList=" + carList +
                ", carSet=" + carSet +
                ", carMap=" + carMap +
                '}';
    }
}
(2)页面定义请求:
<div>
    <form action="listTest">
        name :<input type="text" name="name"><br>
        age :<input type="text" name="age"><br>
        carName :<input type="text" name="car.name"><br>
        carPrice :<input type="text" name="car.price"><br>
        listCarName :<input type="text" name="carList[0].name"><br>
        listCarPrice :<input type="text" name="carList[0].price"><br>
        listCarName1 :<input type="text" name="carList[1].name"><br>
        listCarPrice1 :<input type="text" name="carList[1].price"><br>
        setCarName :<input type="text" name="carSet[0].name"><br>
        setCarPrice :<input type="text" name="carSet[0].price"><br>
        setCarName1 :<input type="text" name="carSet[1].name"><br>
        setCarPrice1 :<input type="text" name="carSet[1].price"><br>
        mapCarName :<input type="text" name="carMap['x'].name"><br>
        mapCarPrice :<input type="text" name="carMap['x'].price"><br>
        mapCarName1 :<input type="text" name="carMap['y'].name"><br>
        mapCarPrice1 :<input type="text" name="carMap['y'].price"><br>
        <input type="submit" value="提交">
    </form>
</div>
(3)执行器方法绑定参数:
    //测试List类型作为参数
    @RequestMapping("listTest")
    public String testList(User user){
        System.out.println(user);
        return "RequestSuccessful";
    }


4、数组类型参数

(1)页面定义请求:
<div>
    <form action="arrTest">
        hobby1 :<input type="text" name="hobbies" ><br>
        hobby2 :<input type="text" name="hobbies" ><br>
        hobby3 :<input type="text" name="hobbies" ><br>
        hobby4 :<input type="text" name="hobbies" ><br>
        <input type="submit" value="提交">
    </form>
</div>
(2)执行器方法绑定参数:
    //测试数组类型作为参数
    @RequestMapping("arrTest")
    public String testArray(String[] hobbies){
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
        return "RequestSuccessful";
    }

5、使用 ServletAPI 对象作为方法参数

(1)引入servletAPI的依赖jar包

(注意jar包作用范围provided:不参与项目部署)

<!--servlet-api依赖-->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.1</version>
      </dependency>
(2)执行器方法绑定参数

        浏览器启动时直接访问servletTest然后就能进行跳转到hello 

    //servlet API对象作为返回参数
    @RequestMapping("servletTest")
    public void testServlet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //转发到/test1
        System.out.println("正在请求转发");
        request.getRequestDispatcher("/hello").forward(request,response);
    }

6、请求参数乱码问题

        tomacat 对 GET 和 POST 请求处理方式是不同的:
(1)GET 请求的编码问题,要改 tomcat 的 server.xml配置文件:

进行修改:

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8"/>
(2)POST 请求的编码问题,要在web.xml文件中配置编码过滤器:

        在进行过滤器添加的时候报错The content of element type "web-app" must match "(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resourc。最后发现是DOM树里面的元素<head>  版本不匹配,我们改为以下配置就行:

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">


</web-app>

        然后加入过滤器:

<!--配置post请求时的编码过滤器-->
  <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>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


7、静态资源访问:

        静态资源的配置有两种方式,下面的两种配置方式任选一种配置就行 

(1)将静态资源交给默认的DefaultServlet处理

         在springMVC.xml配置文件中加如下配置:

<!--开启静态资源配置-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
(2)指定静态资源的访问路径:

        在springMVC.xml配置文件中加如下配置:

<!--开启静态资源配置 第二种方式-->
    <mvc:resources mapping="/images/**" location="/images/"/>
(3)web-app目录下新建images存入图片
(4)index.jsp配置显示静态路径图片
<div>
    <img src="./images/girls.jpg">
</div>
(5)测试

        图片正常显示

(三)自定义参数处理

1、使用场景:

        SpringMVC不能自动识别参数转换为我们需要的数据类型,浏览器报400错误,类型转换异常;

2、使用步骤:

(1)定义类型转换器
package com.jn.utils;

import org.springframework.core.SimpleAliasRegistry;
import org.springframework.core.convert.converter.Converter;

import java.text.SimpleDateFormat;
import java.util.Date;
/*
定义类型转化器
定义了一个名为 MyDateConverter 的类,该类实现了 Converter<String, Date> 接口。
主要功能是将字符串格式的日期转换为 Date 对象。
 */
public class MyDateConverter implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = sdf.parse(s);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return date;
    }
}
(2)配置类型转换器
<!--配置类型转换器
将自定义的 MyDateConverter 注册到 Spring 的类型转换服务中,使得在应用中可以使用 MyDateConverter 来进行字符串到日期的转换。-->
    <bean id="formattingConversionServiceFactoryBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <bean class="com.jn.utils.MyDateConverter"></bean>
        </property>
    </bean>
(3)引用类型转换器
        1.页面定义请求 
    //测试自定义类型转换器
    @RequestMapping("typeChange")
    public String testDate(Date birthday){
        System.out.println(birthday);
        return "RequestSuccessful";
    }
       2. 执行器方法绑定参数:
    //测试自定义类型转换器
    @RequestMapping("typeChange")
    public String testDate(Date date){
        System.out.println(date);
        return "RequestSuccessful";
    }
        3.发现错误 

         Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date': no matching editors or conversion strategy found

        然后死活不知道怎么修改这个错误,最后折腾了半个小时发现只要早controller里面加入配置函数运行就好了。

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }


四、SpringMVC的注解详解

(一)RequestParam

1、RequestParam注解介绍

        使用在方法入参位置,用于指定请求参数名称,将该请求参数绑定到注解参数位置。
属性:name:指定要绑定的请求参数名称;
     required:指定请求参数是否必传;
     defaultValue:指定当没有传入请求参数时的默认取值;

2、RequestParam注解使用案例

//测试RequestParam注解测试
    @RequestMapping("requestParam")
    public String testRequestParam(@RequestParam("username") String name){
        System.out.println("name:" + name);
        return "RequestSuccessful";
    }

3、RequestParam注解测试结果

        启动Tmocat 输入:

http://localhost:8080/SpringMVC01_war_exploded/requestParam?username=hhh

(二)RequestHeader

1、RequestHeader注解介绍

        注解在方法入参位置,用于获取请求头信息。

2、RequestHeader注解使用案例

    //测试RequestHeader注解
    @RequestMapping("requestHeader")
    public String testRequestHeader(@RequestHeader("User-Agent") String header){
        System.out.println("header:" + header);
        return "RequestSuccessful";
    }

3、RequestHeader注解测试结果

(三)RequestBody

1、RequestBody注解介绍

        用于方法入参位置,获取请求体内容。直接使用得到是 key=value&key=value...结构的数据。get 请求方式不适用。通常用于将json格式字符串绑定到bean对象中;

2、RequestBody注解案例

(1)直接获取请求体内容
<div>
    <form action="typeChange">
        birthday :<input type="date" name="birthday"><br>
        <input type="submit" value="提交">
    </form>
</div>
    //测试requestBody
    @RequestMapping("requestBody")
    public String testRequestBody(@RequestBody String body){
        System.out.println(body);
        return "RequestSuccessful";
    }
(2)将json格式请求参数绑定到指定对象bean中
        新建jsp页面实现ajax请求:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script>
        //页面加载时间
        $(function () {
            //为按钮绑定点击事件
            $("#btn").click(function () {
                $.ajax({
                    url:"ajaxTest",
                    data:'{"name":"Tom","age":18}',
                    type:"POST",
                    contentType:"application/json",
                    success:function (obj) {
                        //将控制层操作成功响应信息通过弹窗展示
                        alert(obj);
                    },
                })
            })
        })
    </script>
</head>
<body>
<button id="btn">发送ajax请求</button>
</body>
</html>
         RequestBody注册使用案例:
    //测试json对象的RequestBody
    @RequestMapping("ajaxTest")
    public String testRequestBodyJson(@RequestBody String car){
        System.out.println(car);
        return "RequestSuccessful";
    }

3RequestBody注解测试结果

(四)CookieValue

1、CookieValue注解介绍

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

2、CookieValue注解使用案例

    //CookieValue注解使用案例
    @RequestMapping("cookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID") String cookie){
        System.out.println(cookie);
        return "RequestSuccessful";
    }

3CookieValue注解测试结果

(五)ModelAttribute

1、ModelAttribute注解介绍

        该注解是SpringMVC4.3版本以后新加入的。它可以用于修饰方法和参数。出现在方法上,表示当前方法会在控制器的方法执行之前,先执行。它可以修饰没有返回值的方法,也可以修饰有具体返回值的方法。出现在参数上,获取指定的数据给参数赋值。

2、ModelAttribute注解使用案例

(1)注解在方法上:

    //ModelAttribute注解用于方法  用来绑定一个公共的参数sharParam
    @ModelAttribute("sharParam")
    public String testModelAttribute(){
        System.out.println("我是公共参数");
        return "公共参数";
    }

(2)注解在参数位置:

    //测试ModelAttribute注解用于参数
    @RequestMapping("modelAttribute")
    public String testModelAttribute(@ModelAttribute("sharParam") String modelAttribute){
        System.out.println("modelAttribute:" + modelAttribute);
        return "RequestSuccessful";
    }

3、ModelAttribute注解测试结果 

 

(六)SessionAttributes

1、SessionAttributes注解介绍

        注解在类上,作用将请求域中的参数存放到session域中,用于参数共享。

2、将参数放入Session请求域

    //将请求对象放入到请求域
    @RequestMapping("requestAttribute")
    public ModelAndView testRequestAttribute(HttpServletRequest request, ModelAndView mv){
        mv.addObject("aa","AA");
        mv.addObject("bb","BB");
        mv.addObject("cc","CC");

        HttpSession session = request.getSession();
        session.setAttribute("aa", "AA");
        session.setAttribute("bb", "BB");
        session.setAttribute("cc", "CC");

        mv.setViewName("RequestSuccessful");
        return mv;
    }

3、 将参数放入到Session作用域

package com.jn.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Controller
@SessionAttributes(value = {"aa","bb"})
public class SessionAttributeTest {

    // 从Session中获取属性并添加到模型,用于在另一个请求中展示
    @RequestMapping("/getSessionAttributes")
    public String getSessionAttributes(HttpServletRequest request, Model model) {
        // 从 Session 中获取属性
        HttpSession session = request.getSession();
        String aaFromSession = (String) session.getAttribute("aa");
        String bbFromSession = (String) session.getAttribute("bb");
        String ccFromSession = (String) session.getAttribute("cc");

        // 将 Session 中的属性添加到模型中
        model.addAttribute("aaFromSession", aaFromSession);
        model.addAttribute("bbFromSession", bbFromSession);
        model.addAttribute("ccFromSession", ccFromSession);

        return "sessionAttributesShow";
    }
}

4、请求成功页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h2>设置Session属性后的结果页面</h2>
<p>属性aa的值:${aa}</p>
<p>属性bb的值:${bb}</p>
<p>属性cc的值:${cc}</p>
</body>
</html>

3、SessionAttributes注解测试结果

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程

一、概述 【软件资源文件下载在文章最后】 小面馆叫号取餐流程 佳易王面馆米线店点餐叫号管理系统操作教程 点餐软件以其实用的功能和简便的操作&#xff0c;为小型餐饮店提供了高效的点餐管理解决方案&#xff0c;提高了工作效率和服务质量 ‌点餐管理‌&#xff1a;支持电…

【.NET 8 实战--孢子记账--从单体到微服务】--简易权限--角色可访问接口管理

咱们继续来编写孢子记账的简易权限&#xff0c;这篇文章中我们将编写角色可访问接口的管理API&#xff0c;同样我不会把完整的代码全都列出来&#xff0c;只会列出部分代码&#xff0c;其余代码我希望大家能自己手动编写&#xff0c;然后对比项目代码。废话不多说&#xff0c;开…

Linux上Python使用MySQLdb包连接MySQL5.7和MySQL8的问题

在一台安装有MySQL8的Linux上用MySQLdb包连接MySQL5.7&#xff0c;连接参数中加上ssl_mode‘DISABLED’,能正常连接&#xff1b;不加ssl_mode参数&#xff0c;会报 而在连接MySQL8时加不加ssl_mode都能正常连接&#xff0c;但在使用过程&#xff0c;加了ssl_mode参数&#xff…

列表(list)

一、前言 本次博客主要讲解 list 容器的基本操作、常用接口做一个系统的整理&#xff0c;结合具体案例熟悉自定义内部排序方法的使用。如有任何错误&#xff0c;欢迎在评论区指出&#xff0c;我会积极改正。 二、什么是list list是C的一个序列容器&#xff0c;插入和删除元素…

spring使用xml文件整合事务+druid+mybatis

1.事务 事务&#xff08;Transaction&#xff09;是数据库管理系统中的一个重要概念&#xff0c;它表示一组不可分割的操作序列&#xff0c;这些操作要么全部执行成功&#xff0c;要么全部不执行&#xff0c;以确保数据库从一个一致性状态转换到另一个一致性状态。事务具有以下…

大语言模型LLM综述

一、LM主要发展阶段 1.1、统计语言模型SLM 基于统计学习方法&#xff0c;基本思想是基于马尔可夫假设HMM建立词概率预测模型。如n-gram语言模型 1.2、神经语言模型NLM 基于神经网络来做词的分布式表示。如word2vec模型 1.3、 预训练语言模型PLM 预训练一个网络模型来做词表…

【Jenkins实战】Windows安装服务启动失败

写此篇短文&#xff0c;望告诫后人。 如果你之前装过Jenkins&#xff0c;出于换域账号/本地帐号的原因想重新安装&#xff0c;你大概率会遇上一次Jenkins服务启动失败提示&#xff1a; Jenkins failed to start - Verify that you have sufficient privileges to start system…

Linux kernel 堆溢出利用方法(二)

前言 本文我们通过我们的老朋友heap_bof来讲解Linux kernel中off-by-null的利用手法。在通过讲解另一道相对来说比较困难的kernel off-by-null docker escape来深入了解这种漏洞的利用手法。&#xff08;没了解过docker逃逸的朋友也可以看懂&#xff0c;毕竟有了root权限后&a…

微服务(一)

目录 1.认识微服务 1.1.单体架构 1.2.微服务 1.3.SpringCloud SpringCloud版本 SpringBoot版本 2.服务注册和发现 2.1.注册中心原理 2.2.Nacos注册中心 2.3.服务注册 2.3.1.添加依赖 2.3.2.配置Nacos 2.4.服务发现 2.4.1.引入依赖 2.4.2.配置Nacos地址 2.4.3.发…

ubontu--cuDNN安装

1. 下载 cuDNN https://developer.nvidia.com/cudnn 2. 拷贝到服务器/home/<username>文件夹下 解压缩到当前文件夹&#xff1a; tar -xvf cudnn-linux-x86_64-9.5.1.17_cuda11-archive.tar.xz复制头文件和库文件到cuda安装目录/usr/local/cuda/ sudo cp /home/usern…

Vue 批量注册组件实现动态组件技巧

介绍 Vue 动态组件的应用场景很多,可应用于动态页签,动态路由等场景,其核心原理是批量注册。在Vue2和Vue3中实现原理相同,只是语法略有差异。 Vue2 实现 基于 webpack require.context() 是webpack提供的一个自动导入的API 参数1&#xff1a;加载的文件目录 参数2&#xff…

WEB攻防-通用漏洞SQL读写注入MYSQLMSSQLPostgraSQL

知识点&#xff1a; 1、SQL注入-MYSQL数据库&#xff1b; 2、SQL注入-MSSQL数据库&#xff1b; 3、SQL注入-PostgreSQL数据库&#xff1b; 首先要找到注入点 详细点&#xff1a; Access无高权限注入点-只能猜解&#xff0c;还是暴力猜解 MYSQL&#xff0c;PostgreSQL&am…

NocoBase 本周更新汇总:提升工作流易用性

汇总一周产品更新日志&#xff0c;最新发布可以前往我们的博客查看。 NocoBase 目前更新包括两个分支&#xff1a;main 和 next 。 main &#xff1a;截止目前最稳定的版本&#xff0c;推荐安装此版本。 next&#xff1a;内测版&#xff0c;包含一些未发布的新特性&#xff…

python高级之面向对象编程

一、面向过程与面向对象 面向过程和面向对象都是一种编程方式&#xff0c;只不过再设计上有区别。 1、面向过程pop&#xff1a; 举例&#xff1a;孩子上学 1. 妈妈起床 2. 妈妈洗漱 3. 妈妈做饭 4. 妈妈把孩子叫起来 5. 孩子起床 6. 孩子洗漱 7. 孩子吃饭 8. 妈妈给孩子送学校…

❤React-React 组件基础(类组件)

❤React-React 组件基础 1、组件化开发介绍 组件化开发思想&#xff1a;分而治之 React的组件按照不同的方式可以分成类组件&#xff1a; 划分方式一&#xff08;按照组件的定义方式&#xff09; 函数组件(Functional Component )和类组件(Class Component)&#xff1b; …

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战

目录 前言 一、原始的处理办法 1、使用Set方法来转换 2、使用构造方法转换 二、基于ModelMapper的动态转换 1、ModelMapper简介 2、集成到项目中 3、Shapefile属性读取 三、总结 前言 在现代软件开发中&#xff0c;尤其是在多层架构中&#xff0c;经常需要将数据从一个…

Arduino IDE Windows 系统 离线安装 esp32 开发板 亲测好用。

1、前提条件需要具备特殊网络。 2、官方文档地址&#xff1a;Installing - - — Arduino ESP32 latest documentation 3、系统&#xff1a;Windows10 Arduino IDE 版本2.3.3 之前安装的esp32开发板的版本是2.0.13&#xff0c;由于之前没有接触过esp32开发&#xff0c;也没…

期权懂|请问如何用期权进行风险管理?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 请问如何用期权进行风险管理&#xff1f; 一、期权可以选择交易活跃的期权合约进行风险管理&#xff1a; 对于初级投资者来说&#xff0c;选择交易活跃的期权合约是非常重要的。…

GNU构建系统和Autotool

1、前言 经常使用Linux的开发人员或者运维人员&#xff0c;可能对configure->make->make install相当熟悉。事实上&#xff0c;这叫GNU构建系统&#xff0c;利用脚本和make程序在特定平台上构建软件。这种方式成为一种习惯&#xff0c;被广泛使用。本文从用户视角和开发…

NLP论文速读|ScPO:自我一致性的偏好优化(Self-Consistency Preference Optimization)

论文速读|Self-Consistency Preference Optimization 论文信息&#xff1a; 简介&#xff1a; 这篇论文试图解决的问题是如何在没有人类标注数据的情况下&#xff0c;提高大型语言模型&#xff08;LLMs&#xff09;在复杂推理任务上的性能。现有的自我对齐技术往往因为难以分配…