Java通过注解或拦截器实现出入参驼峰与蛇式互转

Java学习栈

共 18416字,需浏览 37分钟

 · 2023-08-01



一个努力中的公众号

长的好看的人都关注了


    Java语言遵循的开发规范为使用驼峰式命名,如columnA,然而数据库表字段一般使用蛇式命名,如column_a,且前端一般也是使用数据库的字段格式进行交互。因此参数传递和返回就需要对驼峰和蛇式的参数进行转化。

一:注解式

最简单的一种方式就是采用注解直接进行驼峰转蛇形转换
引入Maven依赖com.fasterxml.jackson.core
<dependency>    <groupId>com.fasterxml.jackson.core</groupId>    <artifactId>jackson-core</artifactId>    <version>2.11.2</version></dependency>
在配置文件中声明
# application.propertiesspring.jackson.property-naming-strategy=SNAKE_CASE
在实体类添加注解
JsonInclude注解可以过滤为null的数据
@Data@JsonInclude(JsonInclude.Include.NON_NULL)public class TestDTO implements Serializable {    private static final long serialVersionUID = 1L;
private Integer id;
private String userName;
private Integer createTime;}

上面注解就可以实现输入与输出都为蛇式,但是这种情况不能满足自定义开关,以及同时兼容驼峰与蛇式(因为第三方接口交互时有些要求采用驼峰,有的又要求蛇式)

所以还有另外一种方式

二:自定义拦截器统一处理

2.1 新建过滤器 
   
替换过滤器内request,防止参数丢失
SpringBoot也是通过获取request的输入流来获取参数,如果不替换过滤
器来到Controller请求参数就没了,这是因为 InputStream read方法
内部有一个,postion,标志当前流读取到的位置,每读取一次,位置就
会移动一次,如果读到最后,InputStream.read方法会返回-1,标志已
经读取完了,如果想再次读取,可以调用inputstream.reset方法,
position就会移动到上次调用mark的位置,mark默认是0,所以就能从头
再读了。但是呢是否能reset又是由markSupported决定的,为true
reset,为false就不能reset,从源码可以看到,markSupported是为
false的,而且一调用reset就是直接异常所以这也就代表,InpuStream
只能被读取一次,后面就读取不到了。因此我们在过滤器的时候,已经将
InputStream读取过了一次,当来到ControllerSpringBoot读取
InputStream的时候自然是什么都读取不到了
import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;
/** * @Description: 重写过滤器Filter * @Author: bigearchart * @CreateTime: 2023-02-22 * @Version: 1.0 */public class HttpServletRequestReplacedFilter implements Filter{
@Override public void destroy() {
}
/** * @description: 替换过滤器内request,防止参数丢失 * @author: bigearchart * @date: 2023/2/22 14:50 * @param: [request, response, chain] * @return: void **/ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request); } //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。 // 在chain.doFiler方法中传递新的request对象 if (requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } }
@Override public void init(FilterConfig arg0) throws ServletException {
}
}


2.2 新建请求拦截器
request中获取所有请求参数、根据需求将特定请求中参数进行将蛇形
命名转为驼峰
import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import com.fz.common.util.JudgeUtils;import com.fz.common.util.sys.JsonObjectUtil;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Value;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.*;import java.nio.charset.Charset;
/** * @Description: 获取所有请求参数执行蛇形转驼峰 * @Author: bigearchart * @CreateTime: 2023-02-22 * @Version: 1.0 */@Slf4jpublic class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private String body = null;  @Value ("${open_camel}") private boolean openCamel;
/** * @description: 从request中获取所有请求参数将蛇形命名转为驼峰 * @author: bigearchart * @date: 2023/2/22 14:47 * @param: [request] * @return: **/ public RequestReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); JSONObject js = new JSONObject (); //获取请求路径 String url = request.getRequestURI(); //获取请求ip String ip = JudgeUtils.getIpAddrByRequest (request); //获取请求内容 String bodyOld = getBodyStr(request); //如果开启 蛇形命名转驼峰-将请求内容按要求转换    if(openCamel && (url.contains ("third/") || url.contains ("api/third")|| url.contains ("web/api"))){ //如果请求是jsonObj try { JSONObject jsonObject = JSONObject.parseObject (bodyOld); //如果开启 蛇形命名转驼峰-将请求内容按要求转换 if(openCamel){ log.info ("================开启蛇形命名转驼峰"); jsonObject = JsonObjectUtil.humpConvertJSONObject (JSONObject.parseObject (bodyOld)); } if (jsonObject != null) { js = jsonObject; } //重构入参 body = js.toJSONString(); //将ip塞入请求参数内 js.put("ip", ip); } catch (Exception e) { //否则为array log.info ("=======array=========开启蛇形命名转驼峰"); JSONArray jsonArray = JSONObject.parseArray (bodyOld); JSONArray valArray = new JSONArray (); JSONObject jsonObject ; //数组长度大于1才执行转换 if (jsonArray != null && jsonArray.size () > 0) { for(int i = 0;i < jsonArray.size(); i++){ valArray.set (i, JsonObjectUtil.humpConvertJSONObject (jsonArray.getJSONObject (i))); } //重构入参 body = valArray.toJSONString(); }else{ body = bodyOld; } //将ip塞入请求参数内 js.put("ip", ip); } }else { body = bodyOld; } } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8"))); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } /** * 获取post请求body参数 * @param request HttpServletRequest * @return String */ public static String getBodyStr(HttpServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = request.getInputStream(); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString();  } }

2.3 新建驼峰蛇式互转工具类

下划线转驼峰或者驼峰转下划线

import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import java.util.*;import java.util.regex.Matcher;import java.util.regex.Pattern;
/** * @Description: 驼峰转换Util类 * @Author: bigearchart * @CreateTime: 2023-02-22 * @Version: 1.0 */public class JsonObjectUtil { private static Pattern humpPattern = Pattern.compile("[A-Z]"); /** * @param json 下划线转驼峰 * @Description 驼峰命名转换 * @Throws * @Return com.alibaba.fastjson.JSONObject * @Date 2021-09-17 17:04:31 * @Author bigearchart **/ public static JSONObject humpConvertJSONObject (JSONObject json) { if (null == json) { return null; } //得到所有待处理的key Set<String> keys = json.keySet (); //key转数组 String[] array = keys.toArray (new String[ 0 ]); //循环遍历处理所有key for (String key : array) { //得到key Object value = json.get (key); //根据_分割为数组 String[] keyArray = key.toLowerCase ().split ("_"); //定义接收处理好格式的Obj HashMap<String, Object> objMap; //如果是数组 进行数组转换 if(json.get (key) instanceof JSONArray){ JSONArray vArray = (JSONArray) json.get (key); //数组长度大于1才执行转换 if (keyArray.length > 0) { JSONArray newArray = new JSONArray(); for(int i = 0;i < vArray.size(); i++){ objMap = objToCamel(vArray.getJSONObject (i));// vArray.remove (i); newArray.set (i, objMap); value = newArray; } } }else if(json.get (key) instanceof JSONObject){ //否则执行obj转换 objMap = objToCamel(json.getJSONObject (key)); json.put (key, objMap); value = objMap; } //如果含有蛇形命名执行转换 if (isUpperCase (key) && ! key.contains ("_")) { json.remove (key); json.put (key.toLowerCase (), value); continue; } //如果含有多个蛇形命名执行转换 if (keyArray.length > 1) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < keyArray.length; i++) { String ks = keyArray[ i ]; if (! "".equals (ks)){ if (i == 0) { sb.append (ks); } else { int c = ks.charAt (0); if (c >= 97 && c <= 122) { int v = c - 32; sb.append ((char) v); if (ks.length () > 1) { sb.append (ks.substring (1)); } } else { sb.append (ks); } } } } json.remove (key); json.put (sb.toString (), value); } } return json; } /** * @param objectList obj驼峰转下划线 * @Description 驼峰转换 * @Throws * @Return java.util.List<com.alibaba.fastjson.JSONObject> * @Date 2021-09-17 17:09:15 * @Author bigearchart **/ public static List<JSONObject> humpConvertListObject (List<JSONObject> objectList) { if (null == objectList || objectList.size () <= 0) { return null; } List<JSONObject> data = new ArrayList<> (); for (JSONObject object : objectList) { data.add (humpConvertJSONObject (object)); } return data; } /** * @param array * @Description array驼峰转下划线 * @Throws * @Return java.util.List<com.alibaba.fastjson.JSONObject> * @Date 2021-09-17 17:13:22 * @Author bigearchart **/ public static List<JSONObject> humpConvertJSONArray (JSONArray array) { if (null == array || array.size () <= 0) { return null; } List<JSONObject> data = new ArrayList<> (); for (int i = 0; i < array.size (); i++) { data.add (humpConvertJSONObject (array.getJSONObject (i))); } return data; } /** * @param str * @Description 判断字符串字母是否为大写 * @Throws * @Return boolean * @Date 2021-09-17 17:03:50 * @Author bigearchart **/ public static boolean isUpperCase (String str) { for (int i = 0; i < str.length (); i++) { char c = str.charAt (i); if (c >= 97 && c <= 122) { return false; } } return true; } /** * @param json obj驼峰转下划线 * @Description 驼峰转换 * @Throws * @Return java.util.List<com.alibaba.fastjson.JSONObject> * @Date 2021-09-17 17:09:15 * @Author bigearchart **/ public static JSONObject humpConvertJson (JSONObject json) { if (null == json || json.size () <= 0) { return null; } //得到所有待处理的key Set<String> keys = json.keySet (); //key转数组 String[] array = keys.toArray (new String[ 0 ]); //循环遍历处理所有key for (String key : array) {
//根据_分割为数组 String[] keyArray = key.toLowerCase ().split ("_"); //定义接收处理好格式的Obj HashMap<String, Object> objMap; //如果是数组 进行数组转换 if(json.get (key) instanceof JSONArray){ JSONArray vArray = (JSONArray) json.get (key); //数组长度大于1才执行转换 if (keyArray.length > 0) { for(int i = 0;i < vArray.size(); i++){ Set<Map.Entry<String, Object>> objEntry = vArray.getJSONObject (i).entrySet (); objMap = new HashMap<> (); for (Map.Entry<String, Object> entry : objEntry) { String oKey = entry.getKey (); Object oVal = entry.getValue (); objMap.put (humpToLine2 (oKey), oVal); } vArray.remove (i); vArray.set (i, objMap); } } }else{ //否则执行obj转换 Set<Map.Entry<String, Object>> objEntry = json.getJSONObject (key).entrySet (); objMap = new HashMap<> (); for (Map.Entry<String, Object> entry : objEntry) { String oKey = entry.getKey (); Object oVal = entry.getValue (); objMap.put (humpToLine2 (oKey), oVal); } json.put (key, objMap);
} } return json; } /** * @description: 驼峰转下划线, * @author: bigearchart * @date: 2023/2/22 16:41 * @param: [str] * @return: java.lang.String **/ public static String humpToLine2(String str){ Matcher matcher = humpPattern.matcher (str); StringBuffer sb = new StringBuffer (); while (matcher.find ()) { matcher.appendReplacement (sb, "_" + matcher.group (0).toLowerCase ()); } matcher.appendTail (sb);      return sb.toString ();   } /** * 功能:下划线命名转驼峰命名 * 将下划线替换为空格,将字符串根据空格分割成数组,再将每个单词首字母大写 * @param s * @return */ private static String under2camel(String s){ String separator = "_"; String under = ""; //判断如果有蛇形命名才执行 if (s.contains (separator)) { s = s.toLowerCase ().replace (separator, " "); String sarr[] = s.split (" "); for (int i = 0; i < sarr.length; i++) { if (i > 0) { String w = sarr[ i ].substring (0, 1).toUpperCase () + sarr[ i ].substring (1); under += w; } else { under = sarr[ i ]; } } } else { under = s; } return under; } /** * @description: obj蛇形转驼峰 * @author: bigearchart * @date: 2023/2/22 14:23 * @param: [] * @return: java.util.HashMap<java.lang.String,java.lang.Object> **/ private static HashMap<String, Object> objToCamel(JSONObject obj) { Set<Map.Entry<String, Object>> objEntry = obj.entrySet(); HashMap<String, Object> objMap = new HashMap<> (); for (Map.Entry<String, Object> entry : objEntry) { String oKey = entry.getKey (); Object oVal = entry.getValue (); objMap.put (under2camel (oKey), oVal); } return objMap;  } }

2.2 拦截器注入启动类
/**     * @description: 注册过滤器到启动类     * @author: bigearchart     * @date: 2023/2/22 14:54     * @param: []     * @return: org.springframework.boot.web.servlet.FilterRegistrationBean     **/    @Bean    public FilterRegistrationBean httpServletRequestReplacedRegistration() {        FilterRegistrationBean registration = new FilterRegistrationBean();        registration.setFilter(new HttpServletRequestReplacedFilter ());        registration.addUrlPatterns("/*");        registration.addInitParameter("paramName", "paramValue");        registration.setName("httpServletRequestReplacedFilter");        registration.setOrder(1);        return registration;    }


至此实现参数驼峰与蛇式的两种方式到此结束,通过接口测试工具调用即可验证。

如果对您有帮助 请点个关注,万分感谢

                                (微信技术交流群 请加图图微信)


浏览 106
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报