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 ...
随机推荐
- ElasticSearch之cat plugins API
命令样例如下: curl -X GET "https://localhost:9200/_cat/plugins?v=true&pretty" --cacert $ES_H ...
- Rocketmq学习1——Rocketmq架构&消息存储&刷盘机制
系列文章目录和关于我 一丶什么是Rocketmq RocketMQ是一款开源的分布式消息中间件,由阿里巴巴团队最初开发,并于2016年贡献给Apache软件基金会,后成为Apache顶级项目.Rock ...
- java获取包下所有java类
java获取包下所有java类 简单加载包下的类,注意简单编写非递归查找,自行实现递归查找即可 import java.io.File; import java.net.URL; import jav ...
- 6、Flutter 列表组件 滑动
列表有以下分类: 1.垂直列表 class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget bui ...
- 让“物”能说会道,揭晓华为云IOT黑科技
什么是物联网?如何让"物"说话? 如今是一个万物互联的时代,物联网已经成为一个高大上的名词,那什么是物联网呢?从人与人之间的连接来看,指的是人们之间的通话.视频.进入智能时代以后, ...
- CodeArts TestPlan:一站式测试管理平台
摘要:华为云正式发布CodeArts TestPlan,这是一款自主研发的一站式测试管理平台,沉淀了华为30多年高质量的软件测试工程方法与实践,覆盖测试计划.测试设计.测试执行和测试评估等全流程. 本 ...
- 总结MySQL 的一些知识点:MySQL 插入数据
MySQL 插入数据 MySQL 表中使用INSERT INTOSQL语句来插入数据. 你可以通过 mysql> 命令提示窗口中向数据表中插入数据,或者通过PHP脚本来插入数据. 语法 以下为向 ...
- 如何使用appuploader制作描述文件
如何使用appuploader制作描述文件 承接上文我们讲述了怎么制作证书,本文我们来看下怎么制作描述文件吧.制作描述文件前我们首先我们来添加一个测试设备,后面再制作描述文件. 1.添加测试设备 ...
- 围绕ChatGPT,做了点小事,赚了点小钱
大家好,我是章北海mlpy 作为 ChatGPT 日活用户,分享一下经验和用它做的一些小事吧. 经验不敢当,只是觉得大家把ChatGPT当成了高大上的黑科技,其实它就是个工具,就像你买了个新手机一样, ...
- BBS项目(一):BBS需求分析 数据表设计 注册登录功能实现
目录 BBS需求分析 数据表设计 注册页面前端 上传头像 提交数据 FormData 注册后端逻辑 接受参数 验证参数 数据入库 密码加盐操作 返回数据 登录页面前端 生成验证码 前端提交数据 登录后 ...