使用 RestTemplate 获取并处理外部API数据:去重与重塑

使用 resttemplate 获取并处理外部api数据:去重与重塑

本文详细介绍了如何使用 Spring RestTemplate 从外部 API 获取数据,并对获取到的数据进行处理,包括去重、过滤以及将原始数据结构转换为更适合自身 API 响应的自定义数据传输对象(DTO)。通过示例代码,演示了如何结合 Java Stream API 实现高效的数据处理流程,确保输出数据的准确性和一致性,从而提升API的可用性。

1. 引言:RestTemplate与外部数据集成

在现代微服务架构中,应用程序经常需要与各种外部服务进行交互,获取数据或调用功能。Spring Framework 提供了 RestTemplate 作为一种便捷的方式来执行 HTTP 请求。然而,从外部 API 获取的数据往往需要经过一系列的清洗、转换和过滤,才能符合我们自身 API 的设计要求。本教程将以一个具体的案例为例,讲解如何利用 RestTemplate 获取数据,并进一步对其进行去重和结构重塑,最终以自定义的格式暴露给前端

2. 原始数据结构与需求分析

假设我们正在构建一个服务,需要从一个外部天气API获取省份数据。原始数据结构如下:

Provinces 类

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.annotation.JsonProperty;import java.util.List;@JsonIgnoreProperties(ignoreUnknown = true)public class Provinces {    @JsonProperty("provincial")    private List provinces;    public Provinces() {}    public Provinces(List provinces) {        this.provinces = provinces;    }    @JsonProperty("provincial")    public List getprovinces() {        return provinces;    }    @JsonProperty("Test") // 示例中存在此注解,实际应修正为正确的setter注解    public void setprovinces(List provinces) {        this.provinces = provinces;    }}

ProvincesData 类

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;import com.fasterxml.jackson.annotation.JsonProperty;@JsonIgnoreProperties(ignoreUnknown = true)public class ProvincesData {    @JsonProperty("CODPROV")    private String codProv;    @JsonProperty("NOMBRE_PROVINCIA")    private String nomeProvincia;    @JsonProperty("CODAUTON")    private String codAuton;    @JsonProperty("COMUNIDAD_CIUDAD_AUTONOMA")    private String comunidadeCidadeAutonoma;    public ProvincesData() {}    public ProvincesData(String codProv, String nomeProvincia, String codAuton, String comunidadeCidadeAutonoma) {        this.codProv = codProv;        this.nomeProvincia = nomeProvincia;        this.codAuton = codAuton;        this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;     }    @JsonProperty("CODPROV")    public String getCodProv() {        return codProv;    }    @JsonProperty("Test") // 示例中存在此注解,实际应修正为正确的setter注解    public void setCodProv(String codProv) {        this.codProv = codProv;    }    // 省略其他属性的getter和setter,确保它们是正确的    @JsonProperty("NOMBRE_PROVINCIA")    public String getNomeProvincia() {        return nomeProvincia;    }    public void setNomeProvincia(String nomeProvincia) {        this.nomeProvincia = nomeProvincia;    }    @JsonProperty("CODAUTON")    public String getCodAuton() {        return codAuton;    }    public void setCodAuton(String codAuton) {        this.codAuton = codAuton;    }    @JsonProperty("COMUNIDAD_CIUDAD_AUTONOMA")    public String getComunidadeCidadeAutonoma() {        return comunidadeCidadeAutonoma;    }    public void setComunidadeCidadeAutonoma(String comunidadeCidadeAutonoma) {        this.comunidadeCidadeAutonoma = comunidadeCidadeAutonoma;    }}

我们的核心需求是:

从外部API获取 Provinces 对象,其中包含 List。对 List 进行过滤,移除基于 codAuton 字段重复的数据,只保留唯一的自治区编码。将过滤后的数据转换为一个新的列表结构,其中只包含 codAuton 和 comunidadeCidadeAutonoma 字段,并且可能需要重命名这些字段以适应我们自己的API规范。

3. 使用 RestTemplate 获取原始数据

首先,我们需要一个辅助方法来使用 RestTemplate 调用外部 API 并获取原始数据。

import org.springframework.web.client.RestTemplate;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;public class Templates {    public static Provinces restTemplateProvince(RestTemplate restTemplate) {        String provinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";        Provinces province = restTemplate.getForObject(provinceCommunityURL, Provinces.class);        return province;    }}

在实际应用中,RestTemplate 实例通常通过 Spring 的依赖注入机制进行管理。

4. 核心处理:数据去重与过滤

获取到原始 Provinces 对象后,下一步是处理其内部的 List,以移除基于 codAuton 字段的重复项。我们可以利用 Java 8 的 Stream API 结合一个辅助 Set(或 List)来实现高效去重。

以下是优化后的 restTemplateProvince 方法,它在获取数据后立即执行去重逻辑:

import org.springframework.web.client.RestTemplate;import java.util.ArrayList;import java.util.HashSet; // 推荐使用HashSet进行更高效的去重判断import java.util.List;import java.util.Set;import java.util.stream.Collectors;public class Templates {    public static Provinces restTemplateProvince(RestTemplate restTemplate) {        String provinceCommunityURL = "https://www.el-tiempo.net/api/json/v2/provincias";        Provinces province = restTemplate.getForObject(provinceCommunityURL, Provinces.class);        if (province != null && province.getprovinces() != null) {            // 使用 HashSet 比 ArrayList 更高效地检查元素是否存在            Set includedCodAuton = new HashSet();             List filteredProvinces = province.getprovinces()                .stream()                .filter(p -> {                    // 如果 codAuton 已经存在于 Set 中,则过滤掉此项(返回false)                    // 否则,将其添加到 Set 中并保留此项(返回true)                    return includedCodAuton.add(p.getCodAuton());                })                .collect(Collectors.toList());            province.setprovinces(filteredProvinces);        }        return province;    }}

去重逻辑说明:

我们创建了一个 HashSet includedCodAuton 来存储已经处理过的 codAuton 值。HashSet 提供了 O(1) 的平均时间复杂度来检查元素是否存在和添加元素,这比 ArrayList.contains() 的 O(n) 效率更高。stream().filter() 方法遍历 ProvincesData 列表。在 filter 的 lambda 表达式中,includedCodAuton.add(p.getCodAuton()) 会尝试将当前 ProvincesData 对象的 codAuton 添加到 Set 中。如果 codAuton 之前不存在于 Set 中,add() 方法会返回 true,表示添加成功,当前 ProvincesData 对象会被保留。如果 codAuton 已经存在于 Set 中,add() 方法会返回 false,表示添加失败(因为 Set 不允许重复元素),当前 ProvincesData 对象会被过滤掉。最终,collect(Collectors.toList()) 将过滤后的元素收集成一个新的 List。

5. 数据转换与重塑:生成自定义API响应

仅仅去重还不足以满足我们的所有需求。我们还需要将数据结构重塑,只包含 codAuton 和 comunidadeCidadeAutonoma 字段,并且可能希望重命名这些字段。最专业的做法是定义一个专门用于 API 响应的数据传输对象 (DTO)。

定义 AutonomyRegionDTO:

// AutonomyRegionDTO.javapublic class AutonomyRegionDTO {    private String regionCode; // 对应原始的 codAuton    private String regionName; // 对应原始的 comunidadeCidadeAutonoma    public AutonomyRegionDTO(String regionCode, String regionName) {        this.regionCode = regionCode;        this.regionName = regionName;    }    // Getters and Setters    public String getRegionCode() {        return regionCode;    }    public void setRegionCode(String regionCode) {        this.regionCode = regionCode;    }    public String getRegionName() {        return regionName;    }    public void setRegionName(String regionName) {        this.regionName = regionName;    }}

现在,我们可以在 ProvinceService 中执行数据获取、去重和转换的完整流程。

改造 ProvinceService:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;import java.util.List;import java.util.stream.Collectors;@Servicepublic class ProvinceService {    @Autowired    private RestTemplate restTemplate; // 确保 RestTemplate 已被正确配置和注入    public List getUniqueAutonomyRegions() {        Provinces rawProvinces = Templates.restTemplateProvince(restTemplate); // 调用包含去重逻辑的方法        if (rawProvinces != null && rawProvinces.getprovinces() != null) {            // 将过滤后的 ProvincesData 列表映射到 AutonomyRegionDTO 列表            return rawProvinces.getprovinces().stream()                .map(pData -> new AutonomyRegionDTO(pData.getCodAuton(), pData.getComunidadeCidadeAutonoma()))                .collect(Collectors.toList());        }        return List.of(); // 返回空列表或抛出异常,根据业务需求而定    }}

map 操作说明:

在去重后的 ProvincesData 列表上,我们继续使用 stream().map() 方法。map 方法将每个 ProvincesData 对象转换为一个新的 AutonomyRegionDTO 对象,只提取并重命名了我们关心的字段。collect(Collectors.toList()) 将转换后的 DTO 收集成一个 List。

6. API层暴露处理后的数据

最后,我们的 RestController 将调用 ProvinceService 来获取处理后的数据,并将其作为 API 响应返回。

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestControllerpublic class ShowcaseController {    @Autowired    private ProvinceService provinceService;    @GetMapping("/autonomy-regions")    public List getAutonomyRegions(){      return provinceService.getUniqueAutonomyRegions();     }}

现在,当访问 /autonomy-regions 接口时,将返回一个只包含去重后的自治区编码和名称的列表,并且字段名也已根据 AutonomyRegionDTO 的定义进行了重命名。

7. 注意事项与最佳实践

RestTemplate 配置:确保 RestTemplate 在 Spring 应用程序中正确配置并作为 Bean 注入。通常推荐使用 RestTemplateBuilder 来创建和配置 RestTemplate 实例,例如添加拦截器、消息转换器等。错误处理:在实际应用中,restTemplate.getForObject() 调用可能会因为网络问题、API 不可用或响应格式不正确而抛出异常。应添加 try-catch 块或使用 ResponseEntity 来处理这些潜在错误,提供健壮的用户体验。性能考量:对于非常大的数据集,虽然 HashSet 提供了高效的去重,但整个 Stream 处理过程仍需要将数据加载到内存。如果数据量极其庞大,可能需要考虑分页、外部存储或更高级的数据处理框架。DTO 的重要性:使用 DTO(Data Transfer Object)是 API 设计中的一个最佳实践。它允许你将内部数据模型与外部 API 响应解耦,确保 API 响应的稳定性和安全性,同时可以根据客户端需求定制数据结构。关注点分离:将数据获取、去重、转换等逻辑分别封装在不同的方法或服务中,可以提高代码的可读性、可维护性和可测试性。JSON 属性映射:@JsonProperty 注解用于将 JSON 字段名映射到 Java 对象的属性名。请确保在 ProvincesData 和 Provinces 类中的 setter 方法上不要使用错误的 @JsonProperty(“Test”) 注解,这可能导致反序列化问题。通常,@JsonProperty 只用于 getter 或字段本身。

8. 总结

本教程演示了如何利用 Spring RestTemplate 从外部 API 获取数据,并通过 Java Stream API 结合 HashSet 实现高效的数据去重。更重要的是,我们展示了如何将原始的、可能冗余的数据结构转换为一个更精简、更符合自身 API 需求的自定义 DTO 列表。通过这种方式,我们不仅解决了数据处理的实际问题,也遵循了良好的软件设计原则,如关注点分离和使用 DTO 进行数据传输。

以上就是使用 RestTemplate 获取并处理外部API数据:去重与重塑的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/50773.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
探索jQuery字符串的起始规则
上一篇 2025年11月8日 18:44:33
自动更新怎么关闭方法教程(关闭电脑自动更新的详细步骤)
下一篇 2025年11月8日 18:44:40

相关推荐

  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    100
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 怎么在PHP代码中实现图片上传功能_PHP图片上传功能实现与安全处理教程

    首先创建含enctype的HTML表单,再用PHP接收文件,检查目录、移动临时文件,验证类型与大小,生成唯一文件名,并调整php.ini限制以确保上传成功。 如果您尝试在PHP项目中添加图片上传功能,但服务器无法正确接收或保存文件,则可能是由于表单配置、文件处理逻辑或安全限制的问题。以下是实现该功能…

    2026年5月10日
    100
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • c++中的SFINAE技术是什么_c++模板编程中的SFINAE原理与应用

    SFINAE 是“替换失败不是错误”的原则,指模板实例化时若参数替换导致错误,只要存在其他合法候选,编译器不报错而是继续重载决议。它用于条件启用模板、类型检测等场景,如通过 decltype 或 enable_if 控制函数重载,实现类型特征判断。尽管 C++20 引入 Concepts 简化了部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • RichHandler与Rich Progress集成:解决显示冲突的教程

    在使用rich库的`richhandler`进行日志输出并同时使用`progress`组件时,可能会遇到显示错乱或溢出问题。这通常是由于为`richhandler`和`progress`分别创建了独立的`console`实例导致的。解决方案是确保日志处理器和进度条组件共享同一个`console`实例…

    2026年5月10日
    000
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 《魔兽世界》将于6月11日开启国服回归技术测试

    《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试《魔兽世界》将于6月11日开启国服回归技术测试

    《%ign%ignore_a_1%re_a_1%》官方宣布,将于6月11日开启国服回归技术测试,时间为7天,并称可以在6月内正式开服,玩家们可以访问官网下载战网客户端并预下载“巫妖王之怒”客户端,技术测试详情见下图。 WordAi WordAI是一个AI驱动的内容重写平台 53 查看详情 以上就是《…

    2026年5月10日 用户投稿
    200
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 前端缓存策略与JavaScript存储管理

    根据数据特性选择合适的存储方式并制定清晰的读写与清理逻辑,能显著提升前端性能;合理运用Cookie、localStorage、sessionStorage、IndexedDB及Cache API,结合缓存策略与定期清理机制,可在保证用户体验的同时避免安全与性能隐患。 前端缓存和JavaScript存…

    2026年5月10日
    200
  • HTML5网页如何实现手势操作 HTML5网页移动端交互的处理技巧

    首先利用原生touch事件实现滑动判断,再通过preventDefault解决滚动冲突,接着引入Hammer.js处理复杂手势,最后通过优化点击区域、避免事件冲突和增加视觉反馈提升体验。 在移动端浏览器中,HTML5网页可以通过触摸事件实现手势操作,提升用户体验。虽然原生JavaScript提供了基…

    2026年5月10日
    000
  • 深入理解 Express.js 中 next() 参数的作用与中间件机制

    本文深入探讨 express.js 中间件函数中的 `next()` 参数。它负责将控制权传递给请求-响应周期中的下一个中间件或路由处理程序。文章将详细解释 `next()` 的工作原理、中间件的注册与执行顺序,以及不正确使用 `next()` 可能导致请求挂起的风险,并通过代码示例和实际应用场景,…

    2026年5月10日
    000
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000
  • Python命令怎样使用profile分析脚本性能 Python命令性能分析的基础教程

    使用Python的cProfile模块分析脚本性能最直接的方式是通过命令行执行python -m cProfile your_script.py,它会输出每个函数的调用次数、总耗时、累积耗时等关键指标,帮助定位性能瓶颈;为进一步分析,可将结果保存为文件python -m cProfile -o ou…

    2026年5月10日
    000
  • 使用 WebCodecs VideoDecoder 实现精确逐帧回退

    本文档旨在解决在使用 WebCodecs VideoDecoder 进行视频解码时,实现精确逐帧回退的问题。通过比较帧的时间戳与目标帧的时间戳,可以避免渲染中间帧,从而提高用户体验。本文将提供详细的解决方案和示例代码,帮助开发者实现精确的视频帧控制。 在使用 WebCodecs VideoDecod…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信