摆脱“空”检查的盛宴:使用JSON Patch正确执行PATCH

今天,我们将就REST(ful)服务和API进行一次对话,更准确地说,围绕许多经验丰富的开发人员正在努力解决的一个独特主题。 为了使事情更直观,我们将讨论Web API,其中REST(ful)原则遵循HTTP协议并大量利用HTTP方法的语义,(通常但不一定)使用JSON表示状态。

一种特殊的HTTP方法非常引人注目,尽管其含义听起来很简单,但实现方法远非如此。 是的,我们正在寻找您, PATCH 。 那到底是什么问题呢? 这只是更新,对不对? 是的,实质上,在基于HTTP的REST(ful)Web服务的上下文中, PATCH方法的语义是资源的部分更新。 现在,Java开发人员将如何做到这一点? 这就是乐趣的开始。

让我们来看一个非常简单的图书管理API示例,该示例使用最新的JSR 370:RESTful Web服务的Java API(JAX-RS 2.1)规范(最终包括@PATCH注释!)和出色的Apache CXF框架进行建模 。 我们的资源只是一个非常简单的Book类。

public class Book {private String title;private Collection>String< authors;private String isbn;
}

您将如何使用PATCH方法实施部分更新? 可悲的是,强力解决方案,即null宴席,在这里显然是赢家。

@PATCH
@Path("/{isbn}")
@Consumes(MediaType.APPLICATION_JSON)
public void update(@PathParam("isbn") String isbn, Book book) {final Book existing = bookService.find(isbn).orElseThrow(NotFoundException::new);if (book.getTitle() != null) {existing.setTitle(book.getTitle());}if (book.getAuthors() != null) {existing.setAuthors(book.getAuthors());}// And here it goes on and on ...// ...
}

简而言之,这是空保护的PUT克隆。 可能有人会声称这行得通,并在这里宣布胜利。 但是希望对我们大多数人来说,这种方法显然存在很多缺陷,因此永远不应该采用。 备择方案? 是的,绝对是RFC-6902:JSON补丁 ,目前还不是官方标准,但已经实现了。

RFC-6902:JSON修补程序通过表达一系列操作以应用于JSON文档,从而彻底改变了游戏。 为了说明这一思想的实际效果,让我们从更改书名的简单示例入手,以所需的结果来描述。

{ "op": "replace", "path": "/title", "value": "..." }

看起来很干净,那么添加作者呢? 简单 …

{ "op": "add", "path": "/authors", "value": ["...", "..."] }

太棒了,卖完了,但是……从实现角度看,这似乎需要很多工作,不是吗? 如果我们依赖最新和最强大的JSR 374:JSON处理1.1的Java API,它完全支持RFC-6902:JSON Patch,则不是真的。 有了合适的工具,这次让我们做对了。

org.glassfishjavax.json1.1.2

有趣的是,没有多少人知道Apache CXF和通常的任何JAX-RS兼容框架都与JSON-P紧密集成并支持其基本数据类型。 对于Apache CXF ,只需添加cxf-rt-rs-extension-providers模块依赖项即可:

org.apache.cxfcxf-rt-rs-extension-providers3.2.2

并在服务器工厂bean中注册JsrJsonpProvider ,例如:

@Configuration
public class AppConfig {@Beanpublic Server rsServer(Bus bus, BookRestService service) {JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean();endpoint.setBus(bus);endpoint.setAddress("/");endpoint.setServiceBean(service);endpoint.setProvider(new JsrJsonpProvider());return endpoint.create();}
}

将所有部分连接在一起,我们的PATCH操作可以使用JSR 374:仅用于JSON Processing 1.1的Java API来实现,仅需几行:

@Service
@Path("/catalog")
public class BookRestService {@Inject private BookService bookService;@Inject private BookConverter converter;@PATCH@Path("/{isbn}")@Consumes(MediaType.APPLICATION_JSON)public void apply(@PathParam("isbn") String isbn, JsonArray operations) {final Book book = bookService.find(isbn).orElseThrow(NotFoundException::new);final JsonPatch patch = Json.createPatch(operations);final JsonObject result = patch.apply(converter.toJson(book));bookService.update(isbn, converter.fromJson(result));}
}

BookConverter执行Book类及其JSON表示之间的转换(反之亦然),我们正在手工进行操作,以说明JSR 374:JSON处理1.1的Java API提供的另一种功能。

@Component
public class BookConverter {public Book fromJson(JsonObject json) {final Book book = new Book();book.setTitle(json.getString("title"));book.setIsbn(json.getString("isbn"));book.setAuthors(json.getJsonArray("authors").stream().map(value -> (JsonString)value).map(JsonString::getString).collect(Collectors.toList()));return book;}public JsonObject toJson(Book book) {return Json.createObjectBuilder().add("title", book.getTitle()).add("isbn", book.getIsbn()).add("authors", Json.createArrayBuilder(book.getAuthors())).build();}
}

最后,让我们将这个简单的JAX-RS 2.1 Web API包装到漂亮的Spring Boot信封中。

@SpringBootApplication
public class BookServerStarter {    public static void main(String[] args) {SpringApplication.run(BookServerStarter.class, args);}
}

并运行它。

mvn spring-boot:run

结束讨论,让我们通过在目录中故意添加一本不完整的书 ,来探讨一些更实际的例子。

$ curl -i -X POST http://localhost:19091/services/catalog -H "Content-Type: application\json" -d '{"title": "Microservice Architecture","isbn": "978-1491956250","authors": ["Ronnie Mitra","Matt McLarty"]}'HTTP/1.1 201 Created
Date: Tue, 20 Feb 2018 02:30:18 GMT
Location: http://localhost:19091/services/catalog/978-1491956250
Content-Length: 0

在本书的描述中,我们要纠正一些错误,即将标题设置为完整的“微服务体系结构:原则,实践和文化的 一致性 ,并包括失踪的合著者Irakli NadareishviliMike Amundsen 。 借助我们不久前开发的API,这很容易。

$ curl -i -X PATCH http://localhost:19091/services/catalog/978-1491956250 -H "Content-Type: application\json" -d '[{ "op": "add", "path": "/authors/0", "value": "Irakli Nadareishvili" },{ "op": "add", "path": "/authors/-", "value": "Mike Amundsen" },{ "op": "replace", "path": "/title", "value": "Microservice Architecture: Aligning Principles, Practices, and Culture" }]'HTTP/1.1 204 No Content
Date: Tue, 20 Feb 2018 02:38:48 GMT

前两个操作的路径引用可能看起来有些混乱,但是不用担心,让我们澄清一下。 因为authors是一个集合(或就JSON数据类型而言,是一个数组),所以我们可以使用RFC-6902:JSON Patch数组索引符号来指定要插入新元素的确切位置。 第一个操作使用索引'0'来表示头部位置,而第二个操作使用'-'占位符来简化说“添加到集合的末尾”。 如果我们在更新后立即检索到该书,则应该看到我们所做的修改完全按照我们的要求进行了应用。

$ curl http://localhost:19091/services/catalog/978-1491956250{"title": "Microservice Architecture: Aligning Principles, Practices, and Culture","isbn": "978-1491956250","authors": ["Irakli Nadareishvili","Ronnie Mitra","Matt McLarty","Mike Amundsen"]
}

干净,简单而强大。 公平地说,要付出代价是一种额外的JSON操作形式(以应用补丁程序),但是值得付出努力吗? 我相信是……

下次您要设计新颖的REST(ful)Web API时 ,请认真考虑RFC-6902:JSON补丁以支持资源的PATCH实现。 我相信还将与JAX-RS进行更紧密的集成(如果还没有的话),以直接支持JSONPatch类及其家族。

最后但并非最不重要的一点是,在本文中,我们仅涉及服务器端实现,但JSR 374:用于JSON处理1.1的Java API也包括方便的客户端支架,从而对补丁提供了完整的编程控制。

final JsonPatch patch = Json.createPatchBuilder().add("/authors/0", "Irakli Nadareishvili").add("/authors/-", "Mike Amundsen").replace("/title", "Microservice Architecture: Aligning Principles, Practices, and Culture").build();

完整的项目资源可在Github上找到 。

翻译自: https://www.javacodegeeks.com/2018/02/run-away-null-checks-feast-patch-properly-json-patch.html

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

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

相关文章

Java面向对象(5)--类的成员构造器(构造方法)

创建对象&#xff1b;给对象进行初始化。 ①隐式无参构造器&#xff08;没有创建时&#xff0c;系统默认提供的&#xff09; ②显式定义一个或多个构造器&#xff08;无参、有参&#xff09; 基本格式 修饰符 类名 (参数列表) {初始化语句&#xff1b; }特征 ①它具有与类相…

java单链表 提供增删改查_java实现单链表增删改查的实例代码详解

package 数据结构算法.链表;/**定义节点* 链表由节点构成*/public class node {private e e; //数据dataprivate node next; //指向下一个节点public node() {}public node(e e) {this.e e;}public node getnext() {return next;}public void setnext(node next) {this.next …

Java面向对象(6)--this关键字使用

this可理解为:当前对象或当前正在创建的对象 ①在类的方法中&#xff0c; 我们可以使用"this.属性"或"this.方法"的方式&#xff0c;调用当前对象属性或方法。通常情况下&#xff0c;我们都选择省略"this."。特殊情况下&#xff0c;如果方法的形…

spring 4.3.x_如何在Spring 3.x中使用事件

spring 4.3.x创建松耦合应用程序的概念和技术很多&#xff0c;Event是其中之一。 事件可以消除代码中的许多依赖关系。 有时没有事件&#xff0c;很难实施SRP *。 Java中的Observable接口可以帮助我们实现事件&#xff08;通过Observer Pattern&#xff09;。 但是&#xff0c…

java接口安全怎么处理_Restful API 接口安全性设计

1.API接口设计规范2.安全性设计a.白名单限制仅接受特定系统的请求响应&#xff0c;调用方的IP地址需要在本系统中报备&#xff0c;否则无法调用b.合法身份合法性验证Basic Authentication :这种方式是直接将用户名和密码放到Header中&#xff0c;使用 Authorization: Basic Zm9…

使用Spring开发Java RESTful Web服务的7个理由

REST现在已成为开发Web服务的标准方法&#xff0c;涉及Java时&#xff0c;可以使用许多框架和库&#xff0c;例如JAX-RS&#xff0c;Restlet&#xff0c;Jersey&#xff0c;RESTEasy&#xff0c;Apache CFX等&#xff0c;但是我鼓励Java开发人员使用Spring框架来开发Java。开发…

Java面向对象(7)--package和import关键字

package关键字 ①为了更好的实现项目中类的管理&#xff0c;提供包的概念 ②使用package声明类或接口所属的包&#xff0c;声明在源文件的首行 ③包&#xff0c;属于标识符&#xff0c;遵循标识符的命名规则、规范( xxxyyyzzz) ④每"."一次&#xff0c;就代表一层文…

java圆形排列_位图排序java版

1、《编程珠玑》第一章第一题就相当的精彩&#xff0c;做个笔记。题目如下&#xff1a;输入: 一个包含n个正整数的文件&#xff0c;每个正整数小于n,n等于10的7次方(一千万)。并且文件内的正整数没有重复和关联数据。输出: 输入整数的升序排列约束&#xff1a; 限制在1M左右…

(3.1)HarmonyOS鸿蒙单击事件4种写法

第二种和第四种常用 实现步骤: 1.通过id找到组件。 2.给需要的组件设置单击事件。 3.实现ClickedListener接口。 4.重写onClicked方法。 第一种&#xff0c;自定义实现类&#xff08;在当前类外面写实现类&#xff09; ①MainAbilitySlice.java文件 package com.example.yem…

JSON指针:JSON-P 1.1概述系列

Java EE 8包括对JSON处理API的更新&#xff0c;并使其与JSON的最新IEFT标准保持同步。 他们是&#xff1a; JSON指针 &#xff08;RFC 6901&#xff09; JSON修补程序&#xff08;RFC 6902&#xff09; JSON合并补丁&#xff08;RFC 7396&#xff09; 我将在这个迷你系列中…

Java获取oracle字段注释_java读取ORACLE数据库表字段信息以及注释信息

最近在做编程工具&#xff0c;便于快速开发程序&#xff0c;用过太多框架&#xff0c;但是发觉只有自己制作代码工具才开发起来痛快。这个类是用来读取oracle数据库表结构的&#xff0c;也包括列的注释&#xff0c;对于生成代码有很好的帮助。1.[文件] OracleTable.java ~ 3KB …

(3.2)HarmonyOS鸿蒙双击事件

跟单击事件类似&#xff0c;双击事件也有4种写法&#xff0c;这里采用当前类作为实现类这种写法&#xff0c;其他写法可以参见《单击事件的4种写法》。不同的是双击事件需要的是Component.DoubleClickedListener。 实现步骤: 1.通过id找到组件。 2.给需要的组件设置双击事件。…

java文件和xml文件_用Java分割大型XML文件

java文件和xml文件上周&#xff0c;我被要求用Java编写一些东西&#xff0c;该东西能够将一个30GB的XML文件拆分为可配置文件大小的较小部分。 文件的使用者将是一个中间件应用程序&#xff0c;该应用程序在XML的大尺寸方面存在问题。 在幕后&#xff0c;它使用某种DOM解析技术…

oracle java 并发_【转】JAVA并发教程(ORACLE官网资料)

本文是Oracle官方的Java并发相关的教程&#xff0c;感谢并发编程网的翻译和投递。计算机的使用者一直以为他们的计算机可以同时做很多事情。他们认为当其他的应用程序在下载文件&#xff0c;管理打印队列或者缓冲音频的时候他们可以继续在文字处理程序上工作。甚至对于单个应用…

(3.3)HarmonyOS鸿蒙长按事件

跟单击事件类似&#xff0c;长按事件也有4种写法&#xff0c;这里采用当前类作为实现类这种写法&#xff0c;其他写法可以参见《单击事件的4种写法》。 实现步骤: 1.通过id找到组件。 2.给需要的组件设置长按事件。 3.本类实现LongClickedListener接口。 4.重写onLongClicked方…

部署Spring Boot Angular App(Maven和Tomcat)的4种方法

在上一篇有关Spring Boot angular 5的文章中 &#xff0c;我们使用Spring Boot angular 5实现了一个完整的堆栈端到端Web应用程序。在本文中&#xff0c;我们将讨论在tomcat上部署Spring Boot和Angle App的不同方法。 我们将创建一个具有后端&#xff08;服务器&#xff09;和前…

java中true转换为int_在Java中将字节转换为int的最优雅的方式

示例代码&#xff1a;int a 255;byte b (byte) a;int c b & 0xff; // Here be dragonsSystem.out.println(a);System.out.println(b);System.out.println(c);所以我们从一个整数值255开始&#xff0c;将它转换成一个字节(变为-1)&#xff0c;然后使用魔术公式将其转换成…

(3.4)HarmonyOS鸿蒙滑动事件三个动作

接口名&#xff1a;TouchEventListener 滑动事件里面分为三个动作&#xff1a;按下&#xff0c;移动&#xff0c;抬起 PRIMARY_POINT_DOWN&#xff1a;按下 POINT_MOVE&#xff1a;移动 PRIMARY_POINT_UP&#xff1a;抬起 手机坐标&#xff1a; 手机左上角的点为原点。向右为…

计算机二级web题目(8.3)--简单应用题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web3目录中&#xff0c;存有3.htm文件&#xff0c;该文件不完…

计算机二级web题目(8.4)--综合应用题2

前些天发现了一个巨牛的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;无广告&#xff0c;忍不住分享一下给大家。&#xff08;点击跳转人工智能学习资料&#xff09; 1.在考生文件夹下的Web5目录中&#xff0c;存有5.htm文件&#xff0c;该文件不完…