springboot入参下划线转驼峰出参驼峰转下划线
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;
}
}
springboot入参下划线转驼峰出参驼峰转下划线的更多相关文章
- 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...
- 使用filter获取http请求的出参以及入参
首先 我们的目的是做一个拦截器 能够对http请求做profiler,能够记录本次的调用情况,这里说下如何从http请求中获取到出参的问题. 方案一:参照http://blog.csdn.net/wu ...
- 关于用mybatis调用存储过程时的入参和出参的传递方法
一.问题描述 a) 目前调用读的存储过程的接口定义一般是:void ReadDatalogs(Map<String,Object> map);,入参和出参都在这个map里 ...
- mysql存储过程出参入参,sqlserver很熟悉的一件事到mysql,捣鼓了大半天。记录一下提醒自己。勿看
create PROCEDURE myTestProcname(in score int ,out result varchar(100))BEGINIF score>60 THENset re ...
- Spring AOP 自定义注解获取http接口及WebService接口入参和出参
注解方法实现过程中可以采用如下获取方式:—以下为例 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHo ...
- 先查询再插入,改为存储过程,java部分入参出参、mybatisxml【我】
先查询再插入,改为存储过程 create or replace procedure PRO_REVENUE_SI(l_p_cd in Varchar2, l_c_cd in Varchar2, l_p ...
- python调用c/c++ (入参出参为指针)
python可以使用ctypes库调用c++编译的so库函数 0x01 c/c++编译为so库文件 编译C文件 gcc -o libpycallfoo.so -shared -fPIC rsa.c ...
- Go语言json编码驼峰转下划线、下划线转驼峰
目录 一.需求 二.实现 三.使用 JsonSnakeCase统一转下划线json JsonSnakeCase统一转驼峰json 一.需求 golang默认的结构体json转码出来,都是大写驼峰的,并 ...
- XmlRpc.net 出参字符串还原为结构体
上一篇随笔写的是入参结构体转字符串,现在需要把保存到服务器的字符串还原为结构体,这里记录一下操作步骤: 1. 格式化字符串. XmlRpcDeserializer 支持反序列化<struct&g ...
- JDBC获取sql server存储过程查询结果集(没有出参)
对于一些较为复杂的统计条件查询,可以通过存储过程来实现,既可以提高效率,减少网络流量,也可以避免sql语句耦合在代码中.但是存储过程返回的结果集如何获取(类似表数据),却着实让我费劲心力. 如下: C ...
随机推荐
- Python——第四章:迭代器(Iterators)
迭代器iterator: 提到迭代器,最典型的就是for循环 for 变量 in 可迭代: pass 可迭代对象iterable: 是指可以使用 for 循环进行遍历的对象.除了字符串 (str).列 ...
- Pdfium.Net.Free 一个免费的Pdfium的 .net包装器--概述
PdfiumViewer 是一个伟大的项目,可惜仓库现已经归档,This repository has been archived by the owner on Aug 2, 2019. It is ...
- 在linux系统上怎么获取命令的帮助信息及man文档划分
如何在linux系统上获取命令的帮助信息及man文档的章节划分 1.命令 -- help 2.man 命令 后者更加详细 首先帮助中尖括号<>和方括号[]以及省略号...的含义, 在方括号 ...
- mysql的CRUD操作实现
插入语句(INSERT):一旦我们选择了要插入的字段, 我们就必须保证要插入的数值和选择的字段的个数,顺序,类型一致. 1:怎么插入一条数据: INSERT INTO 插入的表名称(列名1,列 ...
- javacv实现直播流
javacv实现直播流 javacv从入门到入土系列,音视频入门有一点门槛的延迟大概是2~4秒之间, 依赖 <!-- 需要注意,javacv主要是一组API为主,还需要加入对应的实现 --> ...
- 如何在IIS上部署docsify以及404问题
操作步骤 创建一个文件夹,在文件夹中新建2个文件 index.html:入口文件,整个网站只需要这个html文件,其他文件都是md文件 README.md:主页内容,如果没有这个文件,访问时提示404 ...
- GOF23--23种设计模式(三)
一.桥接模式 Java中的桥接模式(Bridge Pattern)是一种结构性设计模式,它将抽象部分和实现部分分离,使它们可以独立变化,同时通过桥接对象将它们连接起来. 这种模式将抽象与其实现解耦,使 ...
- ModelBox姿态匹配:抖抖手动动脚勤做深呼吸
摘要:本案例使用Windows版本的ModelBox SDK进行二次开发,主要是针对姿态匹配案例开发实践. 本文分享自华为云社区<姿态匹配:抖抖手动动脚勤做深呼吸>,作者:吴小鱼. 在之前 ...
- 告别数据开发中的人工审核!火山引擎 DataLeap 落地“自动校验开发规范”能力
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近期,火山引擎 DataLeap 智能市场上线"数仓建表规范"功能,该功能通过规范数仓场景下的 ...
- esp8266 水墨屏显示中文之大号字体
想要显示更大的字体,操作流程如下: 一.下载ESP8266文字显示相关库 链接: https://pan.baidu.com/s/1q9m0K2_egAmiMmD5IBfQ4Q 提取码: wtr2 二 ...