SpringBoot框架学习笔记(六):自定义转换器、内容协商 和 Thymeleaf

news2024/11/28 0:37:05

1 自定义转换器

1.1 基本介绍

(1)SpringBoot在响应客户端请求时,将提交的数据封装成对象时,使用了内置的转换器,一共提供了124个内置转换器,核心源码,在 GenericConverter 接口的内部类 ConvertiblePair 中

(3)可以在包 org.springframework.core.convert.support 下看到所有的124个内置转换器

(3)SpringBoot也支持自定义转换器

1.2 自定义转换器应用实例

需求说明:演示自定义转换器 String-Car

代码实现:

(1)准备如下代码

实体类 Car.java

package com.springboot.entity;

import lombok.Data;
import org.springframework.stereotype.Component;


@Data
@Component
public class Car {
    private String name;
    private Double price;
}

实体类 Monster.java,表单提交的数据直接封装到这个实体类中

package com.springboot.entity;

import lombok.Data;
import org.springframework.stereotype.Component;

import java.util.Date;

@Data
@Component
public class Monster {
    private Integer id;
    private String name;
    private Integer age;
    private Boolean isMarried;
    private Date birth;
    private Car car;
}

前端静态页面 save.html,car 属性的封装使用自定义转换器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加妖怪</title>
</head>
<body>
<h1>添加妖怪(测试封装POJO)</h1>
<form action="/saveMonster" method="post">
    编号: <input name="id" value="100"><br/>
    姓名: <input name="name" value="牛魔王"><br/>
    年龄: <input name="age" value="500"><br/>
    婚否: <input name="isMarried" value="true"><br/>
    生日: <input name="birth" value="2000/11/11"><br/>
    <!--这里使用自定义转换器关联car,字符串整体提交,使用,号作为分隔符-->
    坐骑: <input name="car" value="奔驰,666.6"><br/>
    <input type="submit" value="保存">
</form>
</body>
</html>

后端 Controller 方法

// 添加monster
@PostMapping("/saveMonster")
public String saveMonster(Monster monster) {
    System.out.println("monster-" + monster);
    return "success";
}

(2)创建软件包 config,在该包下创建 WebConfig.java 作为配置类来配置自定义转换器

package com.springboot.config;

import com.springboot.entity.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.util.ObjectUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @Configuration(proxyBeanMethods = false)
 * 1. 表示 WebConfig 是一个配置类
 * 2. proxyBeanMethods = false 使用Lite模式,每个@Bean方法被调用多少次返回的组件都是单实例的。
 * 默认为true,即full模式,每个@Bean方法被调用多少次返回的组件都是新创建的
 */
@Configuration(proxyBeanMethods = false)
public class WebConfig {

    // 注入bean WebMvcConfigurer
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {

        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {
                /**
                 * 1. 在 addFormatters 方法中,增加一个自定义的转换器 String -> Car
                 * 2. 增加的自定义转换器会注册到 converters 容器中
                 * 3. converters 底层结构是 ConcurrentHashMap 内置有124个转换器
                 */

                // 1. 创建自定义转换器
                Converter<String, Car> converter = new Converter<String, Car>() {

                    @Override
                    public Car convert(String source) {// source就是传入的字符串
                        // 在这里加入自定义的转换业务逻辑代码

                        // 判断是否为空
                        if (ObjectUtils.isEmpty(source)){
                            return null;
                        }

                        // 不为空就进行转换
                        Car car = new Car();
                        String[] split = source.split(",");
                        car.setName(split[0]);
                        car.setPrice(Double.valueOf(split[1]));
                        return car;
                    }
                };

                // 添加转换器到converters
                registry.addConverter(converter);
            }
        };
    }

}

小细节:转换器的key是 原类型-> 目标类型,所有如果自定义两个相同的转换器,后面加入的转换器会把前面的覆盖掉

(3)启动主程序,浏览器输入 http://localhost:8080/wwj/save.html 进行测试

 

 点击保存后控制台输出如下

2 内容协商

2.1 基本介绍

(1)根据客户端接收能力不同,SpringBoot返回不同媒体类型的数据

(2)比如:客户端Http请求 Accept: application/xml 则返回xml数据,客户端Http请求 Accept: application/json 则返回json数据

(3)如果 Accept 的值为 */*,表示所有类型的数据都接收,这时候就会按默认的格式,即JSON返回数据

2.2 应用实例

(1)创建 ResponseController.java,注意方法上需要加上@ResponseBody注解

package com.springboot.controller;

import com.springboot.entity.Car;
import com.springboot.entity.Monster;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

@Controller
public class ResponseController {

    // 返回Monster数据-要求以json格式返回

    @GetMapping("/get/monster")
    @ResponseBody
    public Monster getMonster(){

        // 实际开发中是从DB中获取,这里模拟一个monster对象
        Monster monster = new Monster();
        monster.setId(100);
        monster.setName("地宫王");
        monster.setAge(200);
        monster.setIsMarried(false);
        monster.setBirth(new Date());
        Car car = new Car();
        car.setName("奔驰");
        car.setPrice(2222.2);
        monster.setCar(car);
        return monster;
    }
}

(2)使用postman进行测试,先测试返回json数据

(3)成功返回json数据后,再来测试一下返回xml 类型数据。

要想返回xml类型数据,需要在pom.xml文件中加入一个依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

打开postman进行测试

2.3 注意事项

(1)没有加入xml依赖时,浏览器会默认返回json格式数据,当加入了xml依赖后,浏览器就会返回xml格式数据。这是为什么呢,我们看一下浏览器请求头的 Accept 字段的值就知道了

请求头的 Accept 字段的值为 text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9。

分析

  • 支持接收 html,xhtml+xml,xml,且q=0.9,表示权重为0.9
  • 支持接收 image 和 */*,且q=0.8,表示权重为0.8
  • 所以,服务器会优先返回 xml

(2)对于浏览器,我们无法修改其Accept的值,怎么办?解决方案: 开启支持基于请求参数的内容协商功能

修改application.yml, 开启基于请求参数的内容协商功能

spring:
  mvc:
    # 修改静态资源访问前缀
    static-path-pattern: /wwj/**
    hiddenmethod:
      filter:
        # 开启页面表单的 Rest 功能
        enabled: true
    # 配置视图解析器
    view:
      # 后缀
      suffix: .html
      # 前缀
      prefix: /wwj/ # 这里需要注意 prefix 需要和当前的 static-path-pattern一致
    contentnegotiation:
      favor-parameter: true # 开启基于请求参数的内容协商功能

重启服务器,打开浏览器进行测试

当我们输入 http://localhost:8080/get/monster?format=json 时,就会返回json类型数据

输入 http://localhost:8080/get/monster?format=xml 时,就会返回xml类型数据

(3)参数名format是规定好的,在开启请求参数的内容协商功能后,SpringBoot底层ParameterContentNegotiationStrategy会通过format来接收参数,然后返回对应的数据格式。可以在application.yml文件中指定参数名

spring:
  mvc:
    # 修改静态资源访问前缀
    static-path-pattern: /wwj/**
    hiddenmethod:
      filter:
        # 开启页面表单的 Rest 功能
        enabled: true
    # 配置视图解析器
    view:
      # 后缀
      suffix: .html
      # 前缀
      prefix: /wwj/ # 这里需要注意 prefix 需要和当前的 static-path-pattern一致
    contentnegotiation:
      favor-parameter: true # 开启基于请求参数的内容协商功能
      parameter-name: wwjformat # 指定接收参数名

进行测试,现在需要在浏览器输入 http://localhost:8080/get/monster?wwjformat=xml 才能返回对应类型数据格式

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

澳洲联储按兵不动,通胀阴霾难散

澳洲联储核心通胀率仍远高于目标水平&#xff0c;经济增长依然强劲&#xff0c;因此维持高利率是必要的。 鹰派立场坚定 澳洲联储的这一决定与全球其他央行的政策走向形成了鲜明对比。许多发达经济体的央行已经开始降息&#xff0c;以应对经济增长放缓的风险。然而&#xff0…

TapData 信创数据源 | 国产信创数据库 OceanBase 数据同步指南,加速国产化进程,推进自主创新建设

随着国家对自主可控的日益重视&#xff0c;目前在各个行业和区域中面临越来越多的国产化&#xff0c;采用有自主知识产权的国产数据库正在成为主流。长期以来&#xff0c;作为拥有纯国产自研背景的 TapData&#xff0c;自是非常重视对于更多国产信创数据库的数据连接器支持&…

WiFi模块无线通信交互,乐鑫ESP32物联网方案,启明云端乐鑫代理商

随着物联网(IoT)技术的飞速发展&#xff0c;我们正步入一个智能化、互联化的世界。在这一进程中&#xff0c;无线WiFi模块作为连接物理世界与数字世界的桥梁&#xff0c;扮演着至关重要的角色。 WiFi模块是一种基于WiFi协议的无线模块&#xff0c;它可以实现设备之间的无线通信…

ACM MM 2024 | 比SDXL和DALL-E·3更引人入胜!ReCorD:交互场景生成最新SOTA!

文章链接&#xff1a;https://arxiv.org/pdf/2407.17911 git链接&#xff1a;https://alberthkyhky.github.io/ReCorD/ 亮点直击&#xff1a; 引入了一种新颖的推理框架&#xff0c;将潜在扩散模型&#xff08;LDM&#xff09;与视觉语言模型&#xff08;VLM&#xff09;相结合…

私域成交的关键点

私域运营&#xff0c;私域团购&#xff0c;私域秒杀&#xff0c;私域发售

单张图像降噪Masked and Shuffled Blind Spot Denoising for Real-World Images

文章目录 Masked and Shuffled Blind Spot Denoising for Real-World Images1.噪声的空间相关性2.mask3.loss4.masking ratio 与 spatial correlation的关系5.空间噪声去相关6.Automated selection of the BSD masking ratio7.小结 Masked and Shuffled Blind Spot Denoising f…

深入 Dify 源码,洞察 Dify RAG 切片机制实现细节

背景介绍 最近测试时发现 Dify 的 RAG 分片效果一般&#xff0c;不管是使用之前 深入 Dify 源码&#xff0c;洞察 Dify RAG 核心机制 中有调研过的默认解析还是 Unstructured 解析。因此调研比较了 大量的开源框架 实现了特定格式的结构化解析方案&#xff0c;并与 Dify 现有解…

高通8255 Android Virtio Virtio-IIC 配置方法

目录 一&#xff1a;VirtIO和Passthrough的区别 方法一&#xff1a; passthrough 方法二&#xff1a;virtIO 二&#xff1a;配置逻辑 三&#xff1a;示例Virtio-I2C配置 Virtio-I2C框架 步骤一&#xff1a;QNX IIC资源配置 & 测试 配置 测试 步骤二&#xff1a;B…

干货整理: 什么软件能够监控电脑? 六大好用监控电脑软件抢手推荐

如何保障电脑的安全是许多企业用户关注的焦点。 除了常见的杀毒软件外&#xff0c;电脑监控软件也是一道重要的防线。 这些软件能够实时监控电脑的各项运行状况&#xff0c;及时发现并处理潜在的安全威胁&#xff0c;确保电脑的正常运行和用户数据的安全。 接下来&#xff0…

优思学院|防呆法的十大原理

防呆法&#xff08;Poka-Yoke&#xff09;&#xff0c;又称防错法&#xff08;Mistake-Proofing&#xff09;&#xff0c;是一种通过预防错误的发生来提高工作效率&#xff0c;也是精益管理、六西格玛中常用的管理工具。以下就是防呆法的十大原理&#xff1a; 1. 断根原理 断…

算法_链表专题---持续更新

文章目录 前言两数相加题目要求题目解析代码如下 两两交换链表中的结点题目要求题目解析代码如下 重排链表题目要求题目解析代码如下 合并K个升序链表题目要求题目解析 K个一组翻转链表题目要求题目解析代码如下 前言 本文将记录leetcode链表算法题解&#xff0c;包含题目有&a…

Why Memory Matters?(记忆力为何如此重要?)

What is memory? The general consensus is that memory is a multitude of cognitive systems which allow us to store information for certain periods of time so that we can learn from our past experiences and predict the future. 什么是记忆?人们普遍的共识是&am…

《PostgreSQL 数据库在国内的发展前景》

从DB-engines这张2024年8月的最新排名图上可以看出&#xff0c;PostgreSQL数据库的发展趋势还是非常好的&#xff0c;在国内&#xff0c;PostgreSQL数据库也展现出令人振奋的发展前景&#xff0c;非常明显的一种表现就是腾讯云、人大金仓、阿里云、华为等众多厂商都有基于Postg…

推荐一个uniapp选择文件上传的插件

插件地址&#xff1a;文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 支持 H5 / App / 微信小程序

警惕!SCI投稿也有“假网址”!3秒教你查询正确的期刊官网网址

【SciencePub学术】很多没有发表过SCI论文的学者&#xff0c;对于投稿是非常陌生的。首先第一步&#xff0c;对于寻找正确的SCI/SSCI期刊官网都是一项难题。 01 假网站泛滥 • 目前市面上很多假的期刊官网&#xff0c;甚至于界面都所差无几&#xff0c;但是网址仅仅相差一个“…

【两周年纪念日】我将竭尽全力,只为和最美丽的自己早日汇合

​ 您好&#xff0c;我是程序员小羊&#xff01; 存在有其原因&#xff0c;经历有其始终&#xff0c;年华有其始末&#xff0c;拼搏要有结果。 2023来去匆匆&#xff0c;2024奋斗始终&#xff0c;献出一份感情&#xff0c;收获一份心情&#xff0c;拼出一段经验&#xff0c;收获…

两个方法 搞定伦敦金涨跌预测

受美联储降息预期和地缘局势紧张的关系影响&#xff0c;近期伦敦金价格再次出现了强势的上涨&#xff0c;盘中攀升超过30美元。这波涨势的出现&#xff0c;实在是在很多人的意料之外&#xff0c;那么下一步投资者就要开始考虑伦敦金的上涨的终点在哪里&#xff1f;实际上这就是…

计算机组成原理 - 中央处理器

中央处理器 考纲内容 CPU的功能和基本结构指令执行过程数据通路的功能和基本结构控制器的功能和工作原理异常和中断机制 异常和终端的基本概念&#xff1b;异常和中断的分类&#xff1b;异常和中断的检测与响应指令流水线 指令流水线的基本概念&#xff1b;指令流水线的基本实…

动态规划:买卖股票系列

目录 1. 买卖股票的最佳时机1-只能买卖一次(LeetCode121) 解法1&#xff1a;暴力解法 解法2&#xff1a;贪心算法 解法3&#xff1a;动态规划 2. 买卖股票的最佳时机2-可以买卖多次(LeetCode122) 解法1&#xff1a;贪心算法 解法2&#xff1a;动态规划 3. 买卖股票的最…

【架构设计】软件设计原则中的7种耦合和内聚(详解)

文章目录 一、前言二、内聚1、定义2、7 种内聚类型及其描述3、设计要求 三、耦合1、定义2、7 种耦合类型及其描述3、设计要求 四、总结 一、前言 耦合&#xff08;Coupling&#xff09;和内聚&#xff08;Cohesion&#xff09;是衡量软件模块设计质量的两个非常重要的概念。高…