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 ...
随机推荐
- CentOS7,配置rsyslog客户端地址
在CentOS 7系统,将所有日志转发到 192.168.168.168 日志服务器,你可以按照以下步骤进行配置: 确保rsyslog已经被安装 rpm -qa|grep rsyslog 1.打开 r ...
- ubuntu安装mysql8,debian安装mysql8,linux安装mysql8,x86_64架构,deb包
作者主页:https://www.cnblogs.com/milkbox 参考: 修改大小写:MySQL8.0安装后更改不区分大小写!包你必生效!_mysql8.0不区分大小写-CSDN博客 整个安装 ...
- C#基于ScottPlot进行可视化
C#基于ScottPlot进行可视化 前言 上一篇文章跟大家分享了用NumSharp实现简单的线性回归,但是没有进行可视化,可能对拟合的过程没有直观的感受,因此今天跟大家介绍一下使用C#基于Scott ...
- 秋风到,ModelArts“ AI市场算法Fast-SCNN指南”秋膘贴起来
本文分享自华为云社区<带你来秋日尝鲜 | ModelArts AI市场算法Fast-SCNN使用指导>,作者:Tianyi_Li 摘要:送小伙伴们一份新鲜出炉的ModelArts AI市场 ...
- 遥居前列!华为云GaussDB再获行业权威验证
摘要:北京国家金融科技认证中心正式公布了2022年通过"分布式数据库金融标准验证"的数据库产品名单.华为云GaussDB金融级分布式数据库以突出的技术优势通过验证,跃然榜上,且测试 ...
- 华为云企业级Redis:助力VMALL打造先进特征平台
摘要:当电商平台对AI算法模型的需求越来越多,特征数据平台的统一建设是不少开发团队头疼的事情.因为只有通过统一的特征数据存储,才能改变原有的"数据孤岛",解决生产重复造轮子的窘境. ...
- 解放重复劳动丨华为云IoT API Explorer对接小程序实现系统化应用
摘要:<物联网平台接口调用实验>详细讲解了API Explorer的应用,根据提供的接口,结合真实案例,制作了一个小程序,真正的把它应用起来,解放重复劳动,小程序是一个很好的平台,作为应用 ...
- Apache Superset 1.2.0教程 (一)—— 安装(Windows版)
Apache Superset 是一款由 Airbnb 开源的"现代化的企业级 BI(商业智能) Web 应用程序",其通过创建和分享 dashboard,为数据分析提供了轻量级的 ...
- 在linux后台运行脚本的方法和命令
后台运行脚本 执行脚本test.sh:./test.sh 中断脚本test.sh:ctrl+c 在1的基础上将运行中的test.sh,切换到后台并暂停:ctrl+z 执行ctrl+z后,test.sh ...
- MongoDB 占用CPU资源过高
情况如下 db.currentOp() 发现有全表扫描 将 Collscan 对应的 Collection 建索引 db.Table1.createIndex({"DataTime" ...