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。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
7、mvc: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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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 {//转发到/test1System.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> {@Overridepublic 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里面加入配置函数运行就好了。
@InitBinderprotected 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";}
3、RequestBody注解测试结果
(四)CookieValue
1、CookieValue注解介绍
用于方法入参位置,把指定 cookie 名称的值传入控制器方法参数。
2、CookieValue注解使用案例
//CookieValue注解使用案例@RequestMapping("cookieValue")public String testCookieValue(@CookieValue("JSESSIONID") String cookie){System.out.println(cookie);return "RequestSuccessful";}
3、CookieValue注解测试结果
(五)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注解测试结果
相关文章:

SpringMVC学习笔记(一)
一、SpringMVC的基本概念 (一)三层架构和MVC 1、三层架构概述 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中&…...

kaggle 如何利用API下载数据集
首先 上传kaggle官网生成得 API 密钥: kaggle.json 文件。放到该代码同目录下,再运行一下代码。 注: 只需要修改下载竞赛数据集,就可以选择你的指定数据集。 jupyter文件运行 #首先 上传 kaggle.json 文件并设置 API 密钥 #再…...

第一个 Flutter 项目(1)共46节
前端开发工具vs code,安装Flutter sdk,如果你的下载速度比较慢,可以选择这个😄 flutter sdk 解压码:stwq 配置可以看这Flutter 新建工程一直等待 解决办法-CSDN博客 如果你是新的 Flutter 开发者,我们建…...

学术论文写作丨机器学习与深度学习
目录 第一章、ChatGPT-4o使用方法与技巧 第二章、ChatGPT-4o辅助文献检索、总结与分析 第三章、ChatGPT-4o辅助学术论文选题、创新点挖掘与实验方案设计 第四章、ChatGPT-4o辅助学术论文开题与大纲生成 第五章、ChatGPT-4o辅助学术论文写作马拉松活动介绍 第六章、ChatGP…...

导-4涉及的知识点
除了本课题,3D结构几何修复领域还有以下一些值得关注的研究: 1. **Poisson图像编辑**: 成功地将给定的纹理块融合到可能完全不同的背景图像上。 2. **张量投票(TV)框架**: - 讨论了使用张量投票框架进…...

从0开始深度学习(28)——序列模型
序列模型是指一类特别设计来处理序列数据的神经网络模型。序列数据指的是数据中的每个元素都有先后顺序,比如时间序列数据(股票价格、天气变化等)、自然语言文本(句子中的单词顺序)、语音信号等。 1 统计工具 前面介绍…...

vue2使用 <component> 标签动态渲染不同的表单组件
在后台管理系统中,涉及到大量表单信息的修改和新增。现在想对模板中代码做一些简单的优化。 1. 使用 v-for 循环简化表单项 可以将表单项的定义提取到一个数组中,然后使用 v-for 循环来生成这些表单项。这将减少重复代码,提高可维护性。 2…...

C#实现在windows上实现指定句柄窗口的指定窗口坐标点击鼠标左键和右键的详细情况
在Windows编程中,有时我们需要对特定窗口进行操作,比如模拟鼠标点击。这在自动化测试、脚本编写或某些特定应用程序的开发中尤为常见。本文将深入探讨如何在C#中实现对指定句柄窗口进行鼠标点击操作,包括左键和右键点击。我们会从理论背景开始…...

探索Python自动化新境界:Invoke库的神秘面纱
文章目录 **探索Python自动化新境界:Invoke库的神秘面纱**第一部分:背景介绍第二部分:Invoke库是什么?第三部分:如何安装Invoke库?第四部分:Invoke库函数使用方法1. 定义任务2. 执行任务3. 任务…...

CSS样式实现3D效果
CSS 3D效果是通过CSS3中的transform和perspective等属性来实现的。这些属性允许你创建具有深度感和三维外观的网页元素。以下是一些常见的CSS 3D效果及其实现方法: 1. 3D旋转(Rotate) 使用transform: rotateX(), rotateY(), rotateZ()来分别…...

华为eNSP:MSTP
一、什么是MSTP? 1、MSTP是IEEE 802.1S中定义的生成树协议,MSTP兼容STP和RSTP,既可以快速收敛,也提供了数据转发的多个冗余路径,在数据转发过程中实现VLAN数据的负载均衡。 2、MSTP可以将一个或多个VLAN映射到一个Inst…...

modbus协议 Mthings模拟器使用
进制转换 HEX 16进制 (0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F表示0-15) dec 10进制 n(16进制) -> 10 abcd.efg(n) d*n^0 c*n^1 b*n^2 a*n^3 e*n^-1 f*n^-2 g*n^-3(10) 10 -> n(16进制) Modbus基础概念 高位为NUM_H&…...

内网安全-代理技术-socket协议
小迪安全网络架构图: 背景:当前获取window7 出网主机的shell。 1.使用msf上线,查看路由 run autoroute -p 添加路由: run post/multi/manage/autoroute 使用socks模块开启节点,作为流量跳板 msf6 exploit(multi/ha…...

选择排序(C语言)
一、步骤 选择排序的基本思想:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。 1.首先,我们先建立一个乱序数组,如࿱…...

✍Qt自定义带图标按钮
✍Qt自定义带图标按钮 📝问题引入 近段时间的工作中,有遇到这样一个需求 📝: 一个按钮,有normal、hover、pressed三种状态的样式,并且normal和hover样式下,字体颜色和按钮图标不一样。 分析…...

【Git】如何在 Git 项目中引用另一个 Git 项目:子模块与子树合并
如何在 Git 项目中引用另一个 Git 项目:子模块与子树合并 在进行软件开发时,我们经常会遇到需要将一个 Git 项目(B 项目)引用到另一个 Git 项目(A 项目)的情况。这种需求通常出现在以下场景: …...

webstorm 打开prettier的项目代码后面会出现红色的波浪线
效果如图所有代码后面都有红色的波浪线。 解决File-Settings 找到Editor下面的inspections ...按照图示取消勾选ESLint再点Apply ok...

用 Python 从零开始创建神经网络(二):第一个神经元的进阶
第一个神经元的进阶 引言1. Tensors, Arrays and Vectors:2. Dot Product and Vector Additiona. Dot Product (点积)b. Vector Addition (向量加法) 3. A Single Neuron with NumPy4. A Layer of Neurons with NumPy5…...

一、文心一言问答系统为什么要分对话,是否回学习上下文?二、文心一言是知识检索还是大模型检索?三、文心一言的词向量、词语种类及多头数量
目录 一、文心一言问答系统为什么要分对话,是否回学习上下文? 二、文心一言是知识检索还是大模型检索? 三、文心一言的词向量、词语种类及多头数量 一、文心一言问答系统为什么要分对话,是否回学习上下文? 文心一言问答系统分对话的原因在于其设计初衷就是提供一个交互…...

C++ 的协程
现代C中的协程(coroutines)是C20引入的一项重大语言特性,它们允许函数在执行过程中可以暂停并稍后从暂停点恢复执行。协程提供了一种控制流机制,使得函数可以包含多个入口点和出口点,这与传统的单入口、单出口的函数模…...

D3的竞品有哪些,D3的优势,D3和echarts的对比
D3 的竞品 ECharts: 简介: ECharts 是由百度公司开发的一款开源的 JavaScript 图表库,提供了丰富的图表类型和高度定制化的配置选项。特点: 易于使用,文档详尽,社区活跃,支持多种图表类型(如折线图、柱状图、饼图、散点…...

大厂计算机网络高频八股文面试题及参考答案(面试必问,持续更新)
目录 请简述 TCP 和 UDP 的区别? TCP 和 UDP 分别对应的常见应用层协议有哪些? UDP 的优缺点是什么?它适用于哪些场景? UDP 如何实现可靠传输? 请简述 HTTP 和 HTTPS 的区别? HTTP 协议的工作原理是什么? HTTP 状态码有哪些常见的类型及其含义? HTTP 哪些常用的…...

【bayes-Transformer-GRU多维时序预测】多变量输入模型。matlab代码,2023b及其以上
% 1. 数据准备 X_train 训练数据输入; Y_train 训练数据输出; X_test 测试数据输入; % 2. 模型构建 inputSize size(X_train, 2); numHiddenUnits 100; numResponses 1; layers [ … sequenceInputLayer(inputSize) biLSTMLayer(numHiddenUnits, ‘OutputMode’, ‘se…...

动手学深度学习69 BERT预训练
1. BERT 3亿参数 30亿个词 在输入和loss上有创新 两个句子拼起来放到encoder–句子对 cls-class分类 sep-seperate 分隔符 分开每个句子 告诉是哪个句子 两个句子给不同的向量 位置编码不用sin cos, 让网络自己学习 bert–通用任务 encoder 是双向的,…...

【2024软考架构案例题】你知道 Es 的几种分词器吗?Standard、Simple、WhiteSpace、Keyword 四种分词器你知道吗?
👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主 ⛪️ 个人社区&#x…...

Elman 神经网络 MATLAB 函数详解
Elman 神经网络 MATLAB 函数详解 一、引言 Elman 神经网络是一种在时间序列分析和动态系统建模领域广泛应用的递归神经网络(RNN)。MATLAB 提供了一系列强大的函数来创建、训练和应用 Elman 神经网络,使得用户能够方便地利用其处理具有时间序…...

vue el-date-picker 日期选择器禁用失效问题
当value-format"yyyy-MM-dd"的格式不要改为"yyyyMMdd",否则会导致日期选择器禁用失效问题,因为该组件默认的格式就是yyyy-MM-dd。 <el-col v-for"(item, index) in formData" :key"index" ><el-date-…...

搭建Python2和Python3虚拟环境
搭建Python3虚拟环境 1. 更新pip2. 搭建Python3虚拟环境第一步:安装python虚拟化工具第二步: 创建虚拟环境 3. 搭建Python2虚拟环境第一步:安装虚拟环境模块第二步:创建虚拟环境 4. workon命令管理虚拟机第一步:安装扩…...

【HarmonyOS NEXT】一次开发多端部署(以轮播图、Tab栏、列表为例,配合栅格布局与媒体查询,进行 UI 的一多开发)
关键词:一多、响应式、媒体查询、栅格布局、断点、UI 随着设备形态的逐渐增多,应用界面适配也面临着很大问题,在以往的安卓应用开发过程中,往往需要重新开发一套适用于大屏展示的应用,耗时又耗力,而鸿蒙提供…...

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