首页 > 其他分享 >springboot入参下划线转驼峰出参驼峰转下划线

springboot入参下划线转驼峰出参驼峰转下划线

时间:2023-12-20 13:34:13浏览次数:35  
标签:jsonNode return String 驼峰 出参 new public 下划线

springboot入参出参下划线转驼峰

前言

因为历史原因前端入参和出参都为下划线,下划线对有亿点强迫症的我来说是不可接受的。因此就有了下面这篇。

本篇基于之前的一篇springboot封装统一返回 - Scott_pb - 博客园 (cnblogs.com)

引入xml

因为是基于jackson而spring-boot-starter-web已经包含

<dependency>
	<groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

工具类

public class JsonUtils {

    private static final ObjectMapper objectMapper = new ObjectMapper();


    /**
     * json字符串转驼峰
     *
     * @param json String
     * @return String
     */
    public static String convertToCamelCaseJson(String json) throws JsonProcessingException {
        JsonNode jsonNode = objectMapper.readTree(json);

        jsonNode = convertKeysToCamelCase(jsonNode);

        return objectMapper.writeValueAsString(jsonNode);
    }


    /**
     * JsonNode的key转驼峰
     *
     * @param jsonNode JsonNode
     * @return JsonNode
     */
    public static JsonNode convertKeysToCamelCase(JsonNode jsonNode) {
        if (jsonNode.isObject()) {
            ObjectNode objectNode = objectMapper.createObjectNode();
            jsonNode.fields().forEachRemaining(entry -> {
                objectNode.set(snakeToCamel(entry.getKey()), convertKeysToCamelCase(entry.getValue()));
            });
            return objectNode;
        }

        if (jsonNode.isArray()) {
            ArrayNode arrayNode = objectMapper.createArrayNode();
            jsonNode.elements().forEachRemaining(entry -> {
                arrayNode.add(convertKeysToCamelCase(entry));
            });

            return arrayNode;
        }

        return jsonNode;
    }

    public static JsonNode convertKeysToSnake(JsonNode jsonNode) {
        if (jsonNode.isObject()) {
            ObjectNode objectNode = objectMapper.createObjectNode();
            jsonNode.fields().forEachRemaining(entry -> {
                objectNode.set(camelToSnake(entry.getKey()), convertKeysToCamelCase(entry.getValue()));
            });
            return objectNode;
        }

        if (jsonNode.isArray()) {
            ArrayNode arrayNode = objectMapper.createArrayNode();
            jsonNode.elements().forEachRemaining(entry -> {
                arrayNode.add(convertKeysToSnake(entry));
            });

            return arrayNode;
        }

        return jsonNode;
    }


    /**
     * 下划线转驼峰
     *
     * @param key String
     * @return String
     */
    public static String snakeToCamel(String key) {
        if (key.indexOf("_") != 0) {
            String[] s = key.split("_");
            StringBuilder stringBuilder = new StringBuilder(s[0]);
            for (int i = 1; i < s.length; i++) {
                stringBuilder.append(s[i].substring(0, 1).toUpperCase()).
                        append(s[i].substring(1));
            }
            return stringBuilder.toString();
        }

        return key;
    }


    /**
     * 驼峰转下划线
     * @param key String
     * @return String
     */
    public static String camelToSnake(String key) {
        int length = key.length();
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            char current = key.charAt(i);
            if (Character.isUpperCase(current)) {
                if (i > 0) {
                    sb.append('_');
                }
                sb.append(Character.toLowerCase(current));
                continue;
            }
            sb.append(current);
        }
        return sb.toString();
    }


}

ServletRequest定义

因为requestBody是流形式,所以转驼峰后,需要将转后的数据封装为流到requestBody中,我采用继承HttpServletRequestWrapper的方法重写HttpServletRequest

public class CamelKeyRequestWrapper extends HttpServletRequestWrapper {
  	//修改后的字节数组
    private final byte[] modifiedContent;

  	//json的key转为驼峰
    public CamelKeyRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.modifiedContent = camelCaseJson(request);
    }

  	//调用getInputStream时,返回转化后的驼峰json数据
    public ServletInputStream getInputStream() {
        return new ModifiedServletInputStream(new ByteArrayInputStream(modifiedContent));
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }


    /**
     * 下划线转驼峰
     * @param request HttpServletRequest
     * @return byte[]
     * @throws IOException e
     */
    private byte[] camelCaseJson(HttpServletRequest request) throws IOException {
        //没有requestBody
        if (request.getContentType() != null && !request.getContentType().contains("application/json")) {
            return null;
        }

        ServletInputStream inputStream = null;
        BufferedReader reader = null;
        String originalJsonBody, camelCaseJson = null;
        ContentCachingRequestWrapper requestWrapper;
        try {
            requestWrapper = new ContentCachingRequestWrapper(request);
          	//原来的InputStream流,因为是流,所以只能使用一次
            inputStream = requestWrapper.getInputStream();
          	//从流中按照UTF-8格式读取
            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
          	//定义StringBuilder
            StringBuilder stringBuilder = new StringBuilder();
            String line;
          	//按行读取
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line);
            }
          	//得到下划线的json字符串
            originalJsonBody = stringBuilder.toString();
          	//将下划线的json字符串转为驼峰的json字符串
            camelCaseJson = JsonUtils.convertToCamelCaseJson(originalJsonBody);


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
          	//不要忘了关闭链接
            assert inputStream != null;
            inputStream.close();
            assert reader != null;
            reader.close();
        }

        assert camelCaseJson != null;
        return camelCaseJson.getBytes();
    }
}

filter拦截器

@Component
@Order(1)
public class RequestBodyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

      	//判断有requestbody传入
        if (servletRequest.getContentType() == null || !servletRequest.getContentType().contains("application/json")) {
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }

        //下划线转驼峰requestBody
        filterChain.doFilter(new CamelKeyRequestWrapper((HttpServletRequest) servletRequest),servletResponse);

    }

}

修改ResponseResultHandler

修改上一篇中ResponseResultHandler

@ControllerAdvice
public class ResponseResultHandler<T> implements ResponseBodyAdvice<Object> {
    public static final String RESPONSE_RESULT_ANN = "RESPONSE-RESULT-ANN";

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (sra == null) {
            return false;
        }

        HttpServletRequest sraRequest = sra.getRequest();
        ResponseResult responseResult = (ResponseResult) sraRequest.getAttribute(RESPONSE_RESULT_ANN);
        return responseResult != null;
    }

    @SneakyThrows
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        
      
        if (body instanceof Response) {
            return body;
        }
      
        //List数组
        if (body instanceof List) {
            body = converSnakeList((List<T>) body);

        }

        //PageInfoVo
        if (body instanceof PageInfoVo) {
            List<? extends T> snakeList = converSnakeList((List<T>) ((PageInfoVo<?>) body).getData());
            ((PageInfoVo<T>) body).setData(snakeList);
        }

        //...其他类型...

         if (body instanceof String) {
            return Response.success(body);
         }
        
         return Response.success(body);
    }

    /**
     * 数组的key转为下划线
     * @param data List
     * @return List<? extends T>
     * @throws JsonProcessingException JsonProcessingException
     */
    private List<? extends T> converSnakeList(List<T> data) throws JsonProcessingException {
        int size = data.size();

        //list中有数据
        if (size > 0) {
            ObjectMapper objectMapper = new ObjectMapper();
            List<JsonNode> snakeList = new ArrayList<>(size);

            for (T datum : data) {
                //object转JsonNode
                JsonNode jsonNode = objectMapper.readTree(objectMapper.writeValueAsString(datum));
                //JsonNode的key转为蛇形
                JsonNode snakeJsonNode = JsonUtils.convertKeysToSnake(jsonNode);

                snakeList.add(snakeJsonNode);
            }

            return (List<? extends T>) snakeList;
        }
        return null;
    }
}

标签:jsonNode,return,String,驼峰,出参,new,public,下划线
From: https://www.cnblogs.com/pengb/p/17916309.html

相关文章

  • (MJ处理)第一个下划线转逗号,剩下的转空格
    在处理大量文件时,手动进行文件重命名和删除特定类型文件通常是耗时且易出错的。为了提高效率和准确性,我开发了一个Python脚本,这个脚本可以自动化执行这些常见的文件管理任务。以下是脚本的主要功能和操作流程:功能概述目录备份在进行任何文件操作之前,脚本会自动创建指定目录......
  • 关于DC电源模块有哪些常见的输入和输出参数?
    关于DC电源模块有哪些常见的输入和输出参数?BOSHIDADC电源模块是一种用于将交流电转换为直流电的设备,广泛应用于电子设备、通信设备、工业控制、仪器仪表等各个领域。在选择和使用DC电源模块时,了解其常见的输入和输出参数是很重要的。输入参数是指DC电源模块的工作电压范围和电流......
  • 关于DC电源模块有哪些常见的输入和输出参数?
    关于DC电源模块有哪些常见的输入和输出参数?BOSHIDADC电源模块是一种用于将交流电转换为直流电的设备,广泛应用于电子设备、通信设备、工业控制、仪器仪表等各个领域。在选择和使用DC电源模块时,了解其常见的输入和输出参数是很重要的。 输入参数是指DC电源模块的工作电压范围......
  • python在word文件指定的文字下划线
    #coding:utf-8importosfromwin32com.clientimportDispatchdefget_string_index(substring,string):"""获取同一字符串中的多个相同字符串的起始索引:paramsubstring:需查找的字符串:paramstring:被查找的字符串:return:"""in......
  • hutool 工具 map 转驼峰
    Map工具-MapUtilhttps://www.tabnine.com/code/java/methods/cn.hutool.core.map.MapUtil/toCamelCaseMapHowtousetoCamelCaseMapmethodincn.hutool.core.map.MapUtilBeanUtil.fillBeanWithMap(...)/***使用Map填充Bean对象**@param<T>Bean类型*@parammapMa......
  • Python 中的单下划线和双下划线
    哈喽大家好,我是咸鱼当我们在学习Python的时候,可能会经常遇到单下划线_和双下划线__这两种命名方式单下划线_和双下划线__不仅仅是只是一种简单的命名习惯,它们在Python中有着特殊的含义,对于代码的可读性和功能实现有着关键的作用。那么今天我们来看一看在Python......
  • 基于双下划线的跨表查询 进阶连续跨表查询
    基于双下划线的跨表查询:#连表查询#基于对象的跨表查询,先查对象,通过对象再去查另一个对象(正向:字段名,反向:表名小写/表名小写_set.all())#地址为山东的作者写的所有书#author_detail=models.AuthorDetail.objects.get(addr='山东')#author=author_detail.autho......
  • 基于双下划线的模糊查询
    #1价格在[100,200,300]这个范围内Book.objects.filter(price__in=[100,200,300])#2大于,小于,大于等于,小于等于Book.objects.filter(price__gt=100)Book.objects.filter(price__lt=100)Book.objects.filter(price__gte=100)Book.objects.filter(price__lte=100)#3范围Book.obje......
  • 详解Python单下划线和双下划线
    一、单下划线1.命名约定。在Python中,单下划线作为命名约定,用于表示某个变量、方法或属性是内部使用的或具有特定含义,但不希望在外部直接访问。2.临时变量。在一些情况下,我们可能只需要临时使用某个变量,而不关心它的具体值。此时,可以使用单下划线作为变量名,表示它是一个无关紧要......
  • 将实体类输出为指定格式(包含下划线,驼峰,大小写)
    一般的实体类字段命名规则基于驼峰命名规则,但是有时候需要调用实体类,需要返回指定的格式。如大小写、字母加下划线等格式。可以使用以下方法,快速生成指定的格式:(该项目为Springboot项目)准备一个实体类:@DatapublicclassTest{privateStringname;privateStri......