【SSM详细教程】-13-SpringMVC详解

 精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482

02. 《SpringBoot详细教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482

03.《SpringBoot电脑商城项目》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482

04.《VUE3.0 核心教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482

05. 《SSM详细教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12806942.html?spm=1001.2014.3001.5482

================================

||     持续分享系列教程,关注一下不迷路 ||

||                视频教程:墨轩大楼               ||

================================

4. SpringMvc详解

4.1. 请求路径映射

》》 当两个控制器中不同方法绑定了相同的请求路径时,会出现什么状况?

package com.moxuan.study.controller;

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

@Controller
public class UserController {

        @RequestMapping("/save")
        @ResponseBody
        public String saveUser(){
            System.out.println("user save....");
            return "{'msg':'攀哥保存了一个大宝贝儿'}";
        }
}


===============================================================================
package com.moxuan.study.controller;

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

@Controller
public class AddressController {

    @RequestMapping("/save")
    @ResponseBody
    public String saveAddress(){
        System.out.println("Address save....");
        return "{'msg':'女朋友给攀哥寄了一个大宝贝儿'}";
    }

}
    

运行起来之后,会出现如下异常:

从异常信息提示可以分析出原因:

UserController有一个saveUser方法,绑定了"/save"。那么它的访问路径为http://localhost/save

AddressController有一个saveAddress方法,也绑定了"/save".访问路径为http://localhost/save

当访问http://localhost/saved的时候,到底是访问UserController还是 AddressController?

》》 开发中潜在的问题

团队多人开发,每人设置不同的请求路径,冲突问题该如何解决?

解决思路:为不同模块设置模块名作为请求路径前置

  • 对于Address模块的save,将其访问路径设置http://localhost/address/save
  • 对于User模块的save,将其访问路径设置http://localhost/user/save
  • 这样在同一个模块中出现命名冲突的情况就比较少了。

修改方法如下:

在控制器上面通过@RequestMapping("命名空间")来设置映射路径,具体代码如下图所示:

package com.moxuan.study.controller;

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

@Controller
@RequestMapping("user")
public class UserController {

    @RequestMapping("/save")
    @ResponseBody
    public String saveUser(){
        System.out.println("user save....");
        return "{'msg':'攀哥保存了一个大宝贝儿'}";
    }


}


====================================================================================
package com.moxuan.study.controller;

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

@Controller
@RequestMapping("address")
public class AddressController {

    @RequestMapping("/save")
    @ResponseBody
    public String saveAddress(){
        System.out.println("Address save....");
        return "{'msg':'女朋友给攀哥寄了一个大宝贝儿'}";
    }

}

》》 然后分别用postman测试,结果如下:

发送:http://localhost:8080/user/save

发送:http://localhost:8080/address/save

虽然有乱码,但是可以看到,此时两个请求地址都可以正常访问。这里的乱码问题实际上解决起来比较简单,只需要在请求后面添加 produces = "text/html;charset=UTF-8" 即可,具体代码如下:

@RequestMapping(value = "/save",produces = "text/html;charset=UTF-8")
@ResponseBody
public String saveUser(){
    System.out.println("user save....");
    return "{'msg':'攀哥保存了一个大宝贝儿'}";
}

再次发送请求时,即可看到正确效果:

》》 @Controller 用法

名称

@Controller

类型

类注解

位置

SpringMVC控制器类定义上方

作用

设定SpringMVC的核心控制器bean

》》@RequestMapping用法

名称

@RequestMapping

类型

类注解或方法注解

位置

SpringMVC控制器类或方法定义上方

作用

设置当前控制器方法请求访问路径

相关属性

value(默认),请求访问路径

》》 @ResponseBody用法

名称

@ResponseBody

类型

类注解或方法注解

位置

SpringMVC控制器类或方法定义上方

作用

设置当前控制器方法响应内容为当前返回值,无需解析

4.2. 参数传递

4.2.1. GET 请求传递一个参数

》》 发送请求与参数,格式如下:

http://localhost:8080/user/sayHello?name='攀哥'

》》编写控制器

@RequestMapping(value="/sayHello",produces = "text/html;charset=UTF-8")
@ResponseBody
public String sayHello(String name){
    System.out.println(name);
    return "{'msg': '"+name+"你好呀'}";
}

》》 运行效果

4.2.2. GET请求传递多个参数

》》 请求地址

http://localhost:8080/user/sayHello?name=攀哥&age=18

》》 编写控制器

@RequestMapping(value="/sayHello",produces = "text/html;charset=UTF-8")
@ResponseBody
public String sayHello(String name,int age){
    System.out.println("我叫"+name+",今年"+age+"岁");
    return "{'msg': '"+name+"你好呀,你好年轻呀,才"+age+"岁'}";
}

》》测试结果:

由此可以看出,当我们需要传递参数的时候,只需要在控制器的方法中添加与需要传递的参数同名的参数即可。

4.2.3. POST请求传递参数

》》 发送请求的方式,控制器方法不变

4.2.4. POST请求乱码问题

上面的案例中,纵使我们按照解决get请求乱码问题一样添加了produces,也是没有效果,如果是Post请求的话,我们需要在web.xml中配置过滤器,具体配置方法如下:

<filter>
  <filter-name>encode</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>encode</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

》》重启服务,运行效果如下:

4.3. 请求参数传递

在前面的案例中我们可以使用GET和POST来发送请求和数据,所携带的数据都是比较简单的,接下来,我们在这个基础上研究一下复杂的参数传递。

4.3.1. 普通参数

前面的案例中我们传递的就是普通参数,前面的案例中我们传递时,请求参数的名字和控制器方法中的参数名字相同,可以直接传递,但是如果不相同会出现什么样状况?

@RequestMapping(value="/showCommParam", produces = "text/html;charset=utf-8")
@ResponseBody
public String showParam(String friendName,String sex,Integer age){
    System.out.println("我是攀哥的"+sex+"朋友,我叫"+name+"今年"+age+"岁");
    return "我是攀哥的"+sex+"朋友,我叫"+name+"今年"+age+"岁";
}

》》发送请求:

》》 请求结果:

》》 解决方案:

可以在控制器方法参数名之前使用@RequestParam 指定这个参数是用来接收哪个请求参数的,比如:

@RequestMapping(value="/showCommParam", produces = "text/html;charset=utf-8")
@ResponseBody
public String showParam(@RequestParam("name") String friendName, String sex, Integer age){
    System.out.println("我是攀哥的"+sex+"朋友,我叫"+friendName+"今年"+age+"岁");
    return "我是攀哥的"+sex+"朋友,我叫"+friendName+"今年"+age+"岁";
}

》》运行结果:

注意:写上@RequestParam注解框架就不需要自己去解析注入,能提升框架处理性能。

4.3.2. 实体类对象Pojo数据

普通参数类型一般处理的是参数个数比较少的请求,如果参数比较多,后台接收参数的时候就比较复杂,这个时候我们可以考虑使用Pojo类型参数。

注意:Pojo参数,请求参数名与对象的属性名相同,这样请求参数的数据会自动注入道对象属性中,接下来我们看看案例:

》》 POJO实体类Friend

@Data  // 自动添加getter和setter方法,toString方法
@NoArgsConstructor  // 自动添加无参构造器
@AllArgsConstructor // 自动添加全参构造器
public class Friend {
    private String name;
    private String sex;
    private int age;
}

》》 后台接收参数:

@RequestMapping(value="/showPoJoParam", produces = "text/html;charset=utf-8")
@ResponseBody
public String showPoJoParam(Friend friend){
    System.out.println(friend);
    return "我是攀哥的"+friend.getSex()+"朋友,我叫"+friend.getName()+"今年"+friend.getAge()+"岁";
}

》》发送请求:

4.3.3. 嵌套POJO类型参数

实际项目中,往往PoJo对象中会嵌套其他PoJo对象,比如:朋友会有地址,地址会有省份,城市等等,具体如下:

》》 地址POJO类Address

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
    private String province;
    private String city;
}

》》朋友POJO类Friend

@Data  // 自动添加getter和setter方法,toString方法
@NoArgsConstructor  // 自动添加无参构造器
@AllArgsConstructor // 自动添加全参构造器
public class Friend {
    private String name;
    private String sex;
    private int age;

    private Address address;
}

注意:Friend类中我们添加了地址Address对象

》》 控制器接收请求参数

@RequestMapping(value="/showInnerPoJo", produces = "text/html;charset=utf-8")
@ResponseBody
public String showInnerPoJo(Friend friend){
    System.out.println(friend);
    return "我是攀哥的"+friend.getSex()+"朋友," +
            "我叫"+friend.getName()+"今年"+friend.getAge()+"岁," +
            "我住在"+friend.getAddress().getProvince()+"省," +
            friend.getAddress().getCity()+"市";
}

》》 发送请求:

4.3.4. 数组类型参数

举个简单例子,如果前端需要做用户批量删除或者获取用户的爱好,这些情况下选择的大多是多条数据,那如果遇到这种情况应该如何发送数据和接受数据呢?

注意: 数组参数,请求参数名与控制器方法参数名相同且请求参数为多个,可以定义数组来接收请求参数。

@RequestMapping(value="/showMyLove", produces = "text/html;charset=utf-8")
@ResponseBody
public String showMyLove(String[] loves){

    return "给大家介绍一下我的老婆们:"+ Arrays.toString(loves);

}

》》发送请求:

由结果可以看出,同名请求参数可以直接映射到对应的控制器方法的数组参数中。

4.3.5. 集合类型参数

既然数组可以接收多个参数,那么集合是否以可以呢?我们修改一下代码看看:

@RequestMapping(value="/showMyLoveList", produces = "text/html;charset=utf-8")
@ResponseBody
public String showMyLoveList(List<String> loves){
     return "给大家介绍一下我的老婆们:"+ loves;

}

》》 发送请求

结果会发现报错了,报错的原因是,SpringMVC将List看作是一个PoJo对象来处理,将其创建一个对象并准备把前端的数据封装到对象中,但是List是一个接口无法创建对象,所以会报错:

解决办法就是在集合前面添加@RequestParam来解决。

@RequestMapping(value="/showMyLoveList", produces = "text/html;charset=utf-8")
@ResponseBody
public String showMyLoveList(@RequestParam List<String> loves){
     return "给大家介绍一下我的老婆们:"+ loves;
}

有的同学可能会想,既然List不能直接用,能不能使用ArrayList呢?这个卖点关子,童靴们自己尝试一下吧。关于RequestParam具体使用方法如下:

名称

@RequestParam

类型

形参注解

位置

SpringMVC控制器方法形参定义前面

作用

绑定请求参数与处理器方法形参间的关系

相关参数

required:是否为必传参数 defaultValue:参数默认值

4.4. JSON数据传输参数

现在流行前后端分离开发模式,而往往在前后端传输数据的时候,会使用JSON。所以接下来我们研究一下当前端发送的是JSON数据时,后端该如何接收?

对于JSON数据类型,我们常见格式有以下几种:

》》JSON 普通数组

["value1","value2","value3",......]

》》JSON 对象

{"key1":"value1","key2":"value2","key3":"value3",.......}

》》JSON 对象数组

[{key1:value1,...},{key2:value2,...}]

SpringMVC 默认的是以jackson来处理JSON的转换,所以我们需要在pom.xml中引入jackson依赖,依赖如下:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.10.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.10.2</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.10.2</version>
</dependency>

在SpringMVC中,解析JSON请求数据需要使用到HttpMessageConverter。

SpringMVC默认提供了多个HttpMessageConverter实现,其中包括MappingJackson2HttpMessageConverter,它可以将JSON数据转换为Java对象。

要使用MappingJackson2HttpMessageConverter,需要在SpringMVC配置文件中进行配置。可以通过以下方式配置:

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
  <property name="messageConverters">
    <list>
      <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
      <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </list>
  </property>
</bean>
4.4.1. 发送普通JSON数组

》》 发送请求

注意发送请求之前一定要按照如下方式在Headers中设置Content-Type,将其设置为application/json

如下图所示依次选择Body,raw, JSON 编写JSON格式的字符串

》》 代码

@RequestMapping(value="/showJsonParam", produces = "text/html;charset=utf-8")
@ResponseBody
public String showJsonParam(@RequestBody String loves){
    // 解析JSON格式的字符串
    List<String > mys = (List<String>) JSON.parse(loves);
    for (String myLove:mys){
        System.out.println(myLove);
    }
    System.out.println(mys);
    return loves.toString();
}

》》运行结果:

4.4.2. 传输JSON对象数据 

》》 发送如下请求

》》 控制器代码如下:

@RequestMapping(value="/showJsonFriend", produces = "text/html;charset=utf-8")
@ResponseBody
public String showJsonFriend(@RequestBody Friend friend){
    System.out.println(friend);
    return friend.toString();
}

》》运行结果:

从效果可以看出,当json格式中的数据key和对象中的属性同名时,json数据会自动注入到对象的属性中去。

4.4.3. JSON对象数组

》》发送请求如下图所示:

》》控制器代码如下:

@RequestMapping(value="/showJsonManyFriend", produces = "text/html;charset=utf-8")
@ResponseBody
public String showJsonManyFriend(@RequestBody List<Friend> friends){
    for (Friend friend:friends){
        System.out.println(friend);
    }
    return friends.toString();
}

》》运行结果:

4.4.4. @RequestBody与@RequestParam区别
  • 区别
    • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
    • @RequestBody用于接收json数据【application/json】
  • 应用
    • 后期开发中,发送json格式数据为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数

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

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

相关文章

SQL实战训练之,力扣:1532最近的三笔订单

目录 一、力扣原题链接 二、题目描述 三、建表语句 四、题目分析 五、SQL解答 六、最终答案 七、验证 八、知识点 一、力扣原题链接 1532. 最近的三笔订单 二、题目描述 客户表&#xff1a;Customers ------------------------ | Column Name | Type | --------…

Redis进阶:Spring框架中利用Redis实现对象的序列化存储

前言 由于Redis只能提供基于字符串型的操作&#xff0c;而Java中使用的却以类对象为主&#xff0c;所以需要Redis存储的字符串和Java对象相互转换。如果我们自己编写这些规则&#xff0c;工作量是比较大的&#xff0c;因此本文介绍如何使用Spring框架快速实现Java数据类型在Red…

Flask-SocketIO 简单示例

用于服务端和客户端通信&#xff0c;服务端主动给客户端发送消息 前提&#xff1a; 确保安装了socket库&#xff1a; pip install flask-socketio python-socketio服务端代码 from flask import Flask from flask_socketio import SocketIO import threading import timeap…

计算机网络:网络层 —— IPv4 地址的应用规划

文章目录 IPv4地址的应用规划定长的子网掩码变长的子网掩码 IPv4地址的应用规划 IPv4地址的应用规划是指将给定的 IPv4地址块 (或分类网络)划分成若干个更小的地址块(或子网)&#xff0c;并将这些地址块(或子网)分配给互联网中的不同网络&#xff0c;进而可以给各网络中的主机…

2023IKCEST第五届“一带一路”国际大数据竞赛--社交网络中多模态虚假 媒体内容核查top11

比赛链接&#xff1a;https://aistudio.baidu.com/competition/detail/1030/0/introduction PPT链接&#xff1a;https://www.ikcest.org/bigdata2024/zlxz/list/page.html 赛题 社交网络中多模态虚假媒体内容核查 背景 随着新媒体时代信息媒介的多元化发展&#xff0c;各种内容…

Handler、Looper、message进阶知识

Android Handler、Looper、Message的进阶知识 在Android开发中&#xff0c;Handler、Looper和Message机制是多线程通信的核心。为了深入理解并优化它们的使用&#xff0c;尤其是在高并发和UI性能优化中&#xff0c;可以利用一些高级特性。 1. Handler的高阶知识 Handler在基本…

基于SpringBoot的“心灵治愈交流平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“心灵治愈交流平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统功能界面图 登录、用户注册界面图 心灵专…

从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?

在工业检测领域&#xff0c;传统的检测手段常因效率低下、精度不足和潜在的安全风险而受到诟病。随着科技的不断进步&#xff0c;一种新兴的检测技术——红外热成像技术&#xff0c;正逐渐在该领域崭露头角。近期&#xff0c;小编对一款集成红外热成像技术的AORO A23防爆手机进…

FineReport 分栏报表

将报表中的数据根据所需要的展示的样式将数据进行分栏展示列分栏 报表中数据是横向扩展的,超过一页的数据会显示在下一页,而每页下面会有很大的一片空白区域,不美观且浪费纸张。希望在一页中第一行扩展满后自动到下一行继续扩展 1、新建数据集 SELECT * FROM 公司股票2、内…

C++游戏开发中的多线程处理是否真的能够显著提高游戏性能?如果多个线程同时访问同一资源,会发生什么?如何避免数据竞争?|多线程|游戏开发|性能优化

目录 1. 多线程处理的基本概念 1.1 多线程的定义 1.2 线程的创建与管理 2. 多线程在游戏开发中的应用 2.1 渲染与物理计算 3. 多线程处理的性能提升 3.1 性能评估 3.2 任务分配策略 4. 多线程中的数据竞争 4.1 数据竞争的定义 4.2 多线程访问同一资源的后果 4.3 避…

交换机:端口安全与访问控制指南

为了实现端口安全和访问控制&#xff0c;交换机通常通过以下几种机制和配置来保护网络&#xff0c;防止未经授权的访问和恶意攻击。 01-端口安全 定义及功能 端口安全功能允许管理员限制每个交换机端口可以学习的MAC地址数量。 通过绑定特定的MAC地址到交换机的某一端口上&a…

微信小程序的日期区间选择组件的封装和使用

组件化开发是一种将大型软件系统分解为更小、更易于管理和复用的独立模块或组件的方法。这种方法在现代软件开发中越来越受到重视&#xff0c;尤其是在前端开发领域。微信小程序的日期区间选择组件的使用 wxml 代码 <view><view bind:tap"chooseData">…

【K8S系列】Kubernetes Pod节点CrashLoopBackOff 状态及解决方案详解【已解决】

在 Kubernetes 中&#xff0c;Pod 的状态为 CrashLoopBackOff 表示某个容器在启动后崩溃&#xff0c;Kubernetes 尝试重启该容器&#xff0c;但由于持续崩溃&#xff0c;重启的间隔时间逐渐增加。下面将详细介绍 CrashLoopBackOff 状态的原因、解决方案及相关命令的输出解释。 …

水轮发电机油压自动化控制系统解决方案介绍

在现代水电工程中&#xff0c;水轮机组油压自动化控制系统&#xff0c;不仅直接关系到水轮发电机组的安全稳定运行&#xff0c;还影响着整个水电站的生产效率和经济效益。 一、系统概述 国科JSF油压自动控制系统&#xff0c;适用于水轮发电机组调速器油压及主阀&#xff08;蝶…

论文笔记(五十一)Challenges for Monocular 6-D Object Pose Estimation in Robotics

Challenges for Monocular 6-D Object Pose Estimation in Robotics 文章概括摘要I. 介绍II. 正在进行的研究和常见数据集A. 数据集B. 正在进行的研究问题 III. 未来挑战A. 物体本体B. 可变形和关节物体C. 场景级一致性D. 基准现实性E. 环境影响F. 通用物体操控 IV. 结论 Estim…

HeterGCL 论文写作分析

HeterGCL 论文写作分析 这篇文章&#xff0c;由于理论证明较少&#xff0c;因此写作风格了polygcl是两种风格的。polygcl偏向理论的写作风格&#xff0c;而hetergcl就是实践派的风格 首先看标题&#xff0c;其的重点是Graph contrastive learning Framework。其重点是framewo…

C语言初阶:十.结构体基础

♥感谢您阅读本篇文章&#xff0c;文章内容为个人对所学内容的整理总结&#xff0c;欢迎大佬在评论区指点一二。♥ ♥个人主页&#xff1a;折枝寄北-CSDN博客折枝寄北擅长C语言初阶,等方面的知识,折枝寄北关注python,c,java,qt,c语言领域.https://blog.csdn.net/2303_80170533?…

QT仿QQ聊天项目,第一节,创建项目并布置编辑登录界面

目录 一&#xff0c;创建项目 二&#xff0c;编辑登录界面 1&#xff0c;登录界面整体构造 2&#xff0c;登录界面的宽高 3&#xff0c;登录界面使用到的控件 4&#xff0c;登录界面中的控件所在的位置和大小 &#xff08;1&#xff09;qq图标label位置和大小 &#xff0…

《计算机原理与系统结构》学习系列——处理器(中)

系列文章目录 目录 流水线数据通路与控制概述5个流水级指令周期与流水级 流水线性能流水线时钟周期的长度T和数量cycles流水线性能 流水线数据通路流水线寄存器流水线分析图形化流水线流水线控制 流水线数据通路与控制 概述 5个流水级 指令周期与流水级 单周期实现中&#x…

【JavaEE】【多线程】volatile,wait/notify

目录 一、volatile关键字1.1 内存可见性1.2 volatile解决内存可见性问题 二、wait和notify2.1 wait2.2 notify2.3 使用例子2.3.1 例子12.3.2 例子二 一、volatile关键字 volatile可以保证内存可见性&#xff0c;只能修饰变量。 1.1 内存可见性 在前面介绍线程不安全原因时介…