【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?

》》 开发中潜在的问题

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

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

修改方法如下:

在控制器上面通过**@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接收请求参数
相关推荐
李慕婉学姐3 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆5 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin5 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20055 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉5 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国5 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882486 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈6 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_996 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹6 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理