栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot+HttpPatch+JsonPatch实现Json文件的更新

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot+HttpPatch+JsonPatch实现Json文件的更新

引言

出于对Mysql数据库减负的想法,我们决定将一些经常读的数据放在自己的json文件服务器中,当然也可以选择redis,但是可能会有较多数据不会读到但必须要存的情况比较耗内存。这里对于json文件的更新就成了一种问题,这里我们介绍下我们使用的SpringBoot+HttpPatch+JsonPatch。

HttpPatch

Http的【RFC2616】原本定义用于上传数据的方法只有POST和PUT,但是考虑到两者的不足,就增加了PATCH方法。

用PATCH方法,默认是以x-www-form-urlencoded的contentType来发送信息,并且信息内容是放在request的body里。

PUT方法和PATCH方法的提交目的地都是直接指向资源,而POST方法提交的数据的目的地是一个行为处理器。

PUT方法用来替换资源,而patch方法用来更新部分资源,然而PATCH和POST都是非幂等的,POST请求服务器执行一个动作,多次请求会多次执行。PATCH提供的实体则需要根据程序或其它协议的定义,解析后在服务器上执行,以此来修改服务器上的数据。也就是说,PATCH请求是会执行某个程序的,如果重复提交,程序可能执行多次,对服务器上的资源就可能造成额外的影响POST方法和PATCH方法它们的实体部分都是结构化的数据,所以PAtch也是非幂等的。POST方法的实体结构一般是 multipart/form-data或 application/x-www-form-urlencoded而PATCH方法的实体结构则随其它规范定义。这和PUT方法的无结构实体相比就是最大的区别。

JsonPatch

JSON Patch是一种用于描述对JSON文档所做的更改的格式(JSON Patch本身也是JSON结构)。当只更改了一部分时,可用于避免发送整个文档。可以与HTTP PATCH方法结合使用时,它允许以符合标准的方式对HTTP API进行部分更新。

JSON Patch是在IETF的RFC 6902中指定的。如果了解过linux上的diff、patch,就非常容易理解JSON Patch了,前者是针对普通文本文件的,后者是指针对JSON结构。(前者更通用)

实战

1.首先来看看需要导入哪些依赖,为了方便直接贴出全部依赖直接复制即可

     
        
        UTF-8
        
        1.18.18
        27.1-jre
        1.3.0.Final
        2.9.8
        1.1.4
        2.1.5.RELEASE
        3.8.0
    

    
        
            
                org.springframework.boot
                spring-boot-dependencies
                ${spring-boot.version}
                pom
                import
            
        
    

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-devtools
            true
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            com.google.guava
            guava
            ${guava.version}
        
        
        
            org.mapstruct
            mapstruct
            ${mapstruct.version}
        
        
        
            org.projectlombok
            lombok
            ${lombok.version}
            provided
        
        
        
            javax.json
            javax.json-api
            ${javax-json.version}
        
        
        
            org.apache.johnzon
            johnzon-core
        
        
        
            com.fasterxml.jackson.datatype
            jackson-datatype-jsr353
            ${jackson.version}
        
        
        
            org.apache.httpcomponents
            httpclient
            test
        
        
        
            com.jayway.jsonpath
            json-path-assert
            test
        
    

    
        
            
            
                org.springframework.boot
                spring-boot-maven-plugin
                ${spring-boot.version}
                
                    
                        
                            repackage
                        
                    
                
            
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                ${maven-compiler-plugin.version}
                
                    11
                    
                        
                            org.projectlombok
                            lombok
                            ${lombok.version}
                        
                        
                            org.mapstruct
                            mapstruct-processor
                            ${mapstruct.version}
                        
                    
                    
                        
                            -Amapstruct.suppressGeneratorTimestamp=true
                        
                        
                            -Amapstruct.suppressGeneratorVersionInfoComment=true
                        
                        
                            -Amapstruct.defaultComponentModel=spring
                        
                    
                
            
        
    

2.准备一个实体类和一个请求信息类

实体类

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BookInput {
    private Long id;
    private String bookName;
    private String url;
}

请求信息类

public final class PatchMediaType {

    public static final String APPLICATION_JSON_PATCH_VALUE = "application/json-patch+json";

    public static final String APPLICATION_MERGE_PATCH_VALUE = "application/merge-patch+json";

    public static final MediaType APPLICATION_JSON_PATCH;

    public static final MediaType APPLICATION_MERGE_PATCH;

    static {
        APPLICATION_JSON_PATCH = MediaType.valueOf(APPLICATION_JSON_PATCH_VALUE);
        APPLICATION_MERGE_PATCH = MediaType.valueOf(APPLICATION_MERGE_PATCH_VALUE);
    }

    private PatchMediaType() {
        throw new AssertionError("No instances of PatchMediaType for you!");
    }
}

3.写一个配置类用来对json进行配置

@Configuration
public class JacksonConfig {

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .setDefaultPropertyInclusion(Include.NON_NULL)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .findAndRegisterModules();
    }
}

注:如果没有这个配置类会报错

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `javax.json.JsonStructure` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

4.这些准备好后重点来了

@Component
@RequiredArgsConstructor
public class PatchHelper {

    private final ObjectMapper mapper;

    private final Validator validator;

    
    public  T patch(JsonPatch patch, T targetBean, Class beanClass) {
        JsonStructure target = mapper.convertValue(targetBean, JsonStructure.class);
        JsonValue patched = applyPatch(patch, target);
        return convertAndValidate(patched, beanClass);
    }

    
    public  T mergePatch(JsonMergePatch mergePatch, T targetBean, Class beanClass) {
        JsonValue target = mapper.convertValue(targetBean, JsonValue.class);
        JsonValue patched = applyMergePatch(mergePatch, target);
        return convertAndValidate(patched, beanClass);
    }

    private JsonValue applyPatch(JsonPatch patch, JsonStructure target) {
        try {
            return patch.apply(target);
        } catch (Exception e) {
            throw new UnprocessableEntityException(e);
        }
    }

    private JsonValue applyMergePatch(JsonMergePatch mergePatch, JsonValue target) {
        try {
            return mergePatch.apply(target);
        } catch (Exception e) {
            throw new UnprocessableEntityException(e);
        }
    }

    private  T convertAndValidate(JsonValue jsonValue, Class beanClass) {
        T bean = mapper.convertValue(jsonValue, beanClass);
        validate(bean);
        return bean;
    }

    private  void validate(T bean) {
        Set> violations = validator.validate(bean);
        if (!violations.isEmpty()) {
            throw new ConstraintViolationException(violations);
        }
    }
}

这是封装好的JsonPatch方法直接调用就可以用了。另外两个异常处理类要放在下面

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {

}
@ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
public class UnprocessableEntityException extends RuntimeException {

    public UnprocessableEntityException(Throwable cause) {
        super(cause);
    }
    
}

5.测试

@RestController
@RequestMapping("/patch")
public class PatchController {

    private final PatchHelper patchHelper;
    public PatchController(PatchHelper patchHelper) {
        this.patchHelper = patchHelper;
    }

    @PatchMapping(consumes = PatchMediaType.APPLICATION_JSON_PATCH_VALUE)
    public void test() {
        
        JsonPatch patch = Json.createPatchBuilder()
                //将id替换为3
                .replace("/id",3)
                //将bookName替换为HAPPYBEAR
                .replace("/bookName", "HAPPYBEAR")
                //移除路径字段
                .remove("/url")
                //添加路径字段并赋值https://baike.baidu.com
                .add("/url", "https://baike.baidu.com")
                .build();
        //拿到的json转换为对象
        BookInput bookInput =new BookInput(2L,"大话设计模式","https://baike.baidu.com/item/%E5%A4%A7%E8%AF%9D%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/85262?fr=aladdin");
        
        BookInput input = patchHelper.patch(patch, bookInput, BookInput.class);
        System.out.println(input);
    }
}

6.运行结果

BookInput(id=3, bookName=HAPPYBEAR, url=https://baike.baidu.com)

获取或上传json文件这边就不阐述了,这边只提供SpringBoot+HttpPatch+JsonPatch的大概思路,希望对大家有帮助!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/678460.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号