Java通過注解或攔截器實現(xiàn)出入?yún)Ⅰ劮迮c蛇式互轉(zhuǎn)
一個努力中的公眾號
長的好看的人都關(guān)注了

Java語言遵循的開發(fā)規(guī)范為使用駝峰式命名,如columnA,然而數(shù)據(jù)庫表字段一般使用蛇式命名,如column_a,且前端一般也是使用數(shù)據(jù)庫的字段格式進行交互。因此參數(shù)傳遞和返回就需要對駝峰和蛇式的參數(shù)進行轉(zhuǎn)化。
一:注解式
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的數(shù)據(jù)
@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;}
上面注解就可以實現(xiàn)輸入與輸出都為蛇式,但是這種情況不能滿足自定義開關(guān),以及同時兼容駝峰與蛇式(因為第三方接口交互時有些要求采用駝峰,有的又要求蛇式)
所以還有另外一種方式
二:自定義攔截器統(tǒng)一處理
替換過濾器內(nèi)request,防止參數(shù)丟失
SpringBoot也是通過獲取request的輸入流來獲取參數(shù),如果不替換過濾 器來到Controller請求參數(shù)就沒了,這是因為 InputStream read方法 內(nèi)部有一個,postion,標志當前流讀取到的位置,每讀取一次,位置就 會移動一次,如果讀到最后,InputStream.read方法會返回-1,標志已 經(jīng)讀取完了,如果想再次讀取,可以調(diào)用inputstream.reset方法, position就會移動到上次調(diào)用mark的位置,mark默認是0,所以就能從頭 再讀了。但是呢是否能reset又是由markSupported決定的,為true能 reset,為false就不能reset,從源碼可以看到,markSupported是為 false的,而且一調(diào)用reset就是直接異常所以這也就代表,InpuStream 只能被讀取一次,后面就讀取不到了。因此我們在過濾器的時候,已經(jīng)將 InputStream讀取過了一次,當來到Controller,SpringBoot讀取 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{public void destroy() {}/*** @description: 替換過濾器內(nèi)request,防止參數(shù)丟失* @author: bigearchart* @date: 2023/2/22 14:50* @param: [request, response, chain]* @return: void**/public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {ServletRequest requestWrapper = null;if (request instanceof HttpServletRequest) {requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request);}//獲取請求中的流如何,將取出來的字符串,再次轉(zhuǎn)換成流,然后把它放入到新request對象中。// 在chain.doFiler方法中傳遞新的request對象if (requestWrapper == null) {chain.doFilter(request, response);} else {chain.doFilter(requestWrapper, response);}}public void init(FilterConfig arg0) throws ServletException {}}
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: 獲取所有請求參數(shù)執(zhí)行蛇形轉(zhuǎn)駝峰* @Author: bigearchart* @CreateTime: 2023-02-22* @Version: 1.0*/4jpublic class RequestReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {private String body = null;("${open_camel}")private boolean openCamel;/*** @description: 從request中獲取所有請求參數(shù)將蛇形命名轉(zhuǎn)為駝峰* @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();//獲取請求ipString ip = JudgeUtils.getIpAddrByRequest (request);//獲取請求內(nèi)容String bodyOld = getBodyStr(request);//如果開啟 蛇形命名轉(zhuǎn)駝峰-將請求內(nèi)容按要求轉(zhuǎn)換if(openCamel && (url.contains ("third/") || url.contains ("api/third")|| url.contains ("web/api"))){//如果請求是jsonObjtry {JSONObject jsonObject = JSONObject.parseObject (bodyOld);//如果開啟 蛇形命名轉(zhuǎn)駝峰-將請求內(nèi)容按要求轉(zhuǎn)換if(openCamel){log.info ("================開啟蛇形命名轉(zhuǎn)駝峰");jsonObject = JsonObjectUtil.humpConvertJSONObject (JSONObject.parseObject (bodyOld));}if (jsonObject != null) {js = jsonObject;}//重構(gòu)入?yún)?/span>body = js.toJSONString();//將ip塞入請求參數(shù)內(nèi)js.put("ip", ip);} catch (Exception e) {//否則為arraylog.info ("=======array=========開啟蛇形命名轉(zhuǎn)駝峰");JSONArray jsonArray = JSONObject.parseArray (bodyOld);JSONArray valArray = new JSONArray ();JSONObject jsonObject ;//數(shù)組長度大于1才執(zhí)行轉(zhuǎn)換if (jsonArray != null && jsonArray.size () > 0) {for(int i = 0;i < jsonArray.size(); i++){valArray.set (i, JsonObjectUtil.humpConvertJSONObject (jsonArray.getJSONObject (i)));}//重構(gòu)入?yún)?/span>body = valArray.toJSONString();}else{body = bodyOld;}//將ip塞入請求參數(shù)內(nèi)js.put("ip", ip);}}else {body = bodyOld;}}public BufferedReader getReader() throws IOException {return new BufferedReader(new InputStreamReader(getInputStream()));}public ServletInputStream getInputStream() throws IOException {final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes(Charset.forName("UTF-8")));return new ServletInputStream() {public int read() throws IOException {return bais.read();}public boolean isFinished() {return false;}public boolean isReady() {return false;}public void setReadListener(ReadListener readListener) {}};}/*** 獲取post請求body參數(shù)* @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();}}
下劃線轉(zhuǎn)駝峰或者駝峰轉(zhuǎn)下劃線
import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject;import java.util.*;import java.util.regex.Matcher;import java.util.regex.Pattern;/*** @Description: 駝峰轉(zhuǎn)換Util類* @Author: bigearchart* @CreateTime: 2023-02-22* @Version: 1.0*/public class JsonObjectUtil {private static Pattern humpPattern = Pattern.compile("[A-Z]");/*** @param json 下劃線轉(zhuǎn)駝峰* @Description 駝峰命名轉(zhuǎn)換* @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;}//得到所有待處理的keySet<String> keys = json.keySet ();//key轉(zhuǎn)數(shù)組String[] array = keys.toArray (new String[ 0 ]);//循環(huán)遍歷處理所有keyfor (String key : array) {//得到keyObject value = json.get (key);//根據(jù)_分割為數(shù)組String[] keyArray = key.toLowerCase ().split ("_");//定義接收處理好格式的ObjHashMap<String, Object> objMap;//如果是數(shù)組 進行數(shù)組轉(zhuǎn)換if(json.get (key) instanceof JSONArray){JSONArray vArray = (JSONArray) json.get (key);//數(shù)組長度大于1才執(zhí)行轉(zhuǎn)換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){//否則執(zhí)行obj轉(zhuǎn)換objMap = objToCamel(json.getJSONObject (key));json.put (key, objMap);value = objMap;}//如果含有蛇形命名執(zhí)行轉(zhuǎn)換if (isUpperCase (key) && ! key.contains ("_")) {json.remove (key);json.put (key.toLowerCase (), value);continue;}//如果含有多個蛇形命名執(zhí)行轉(zhuǎn)換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駝峰轉(zhuǎn)下劃線* @Description 駝峰轉(zhuǎn)換* @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駝峰轉(zhuǎn)下劃線* @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駝峰轉(zhuǎn)下劃線* @Description 駝峰轉(zhuǎn)換* @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;}//得到所有待處理的keySet<String> keys = json.keySet ();//key轉(zhuǎn)數(shù)組String[] array = keys.toArray (new String[ 0 ]);//循環(huán)遍歷處理所有keyfor (String key : array) {//根據(jù)_分割為數(shù)組String[] keyArray = key.toLowerCase ().split ("_");//定義接收處理好格式的ObjHashMap<String, Object> objMap;//如果是數(shù)組 進行數(shù)組轉(zhuǎn)換if(json.get (key) instanceof JSONArray){JSONArray vArray = (JSONArray) json.get (key);//數(shù)組長度大于1才執(zhí)行轉(zhuǎn)換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{//否則執(zhí)行obj轉(zhuǎn)換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: 駝峰轉(zhuǎn)下劃線,* @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 ();}/*** 功能:下劃線命名轉(zhuǎn)駝峰命名* 將下劃線替換為空格,將字符串根據(jù)空格分割成數(shù)組,再將每個單詞首字母大寫* @param s* @return*/private static String under2camel(String s){String separator = "_";String under = "";//判斷如果有蛇形命名才執(zhí)行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蛇形轉(zhuǎn)駝峰* @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;}}
/*** @description: 注冊過濾器到啟動類* @author: bigearchart* @date: 2023/2/22 14:54* @param: []* @return: org.springframework.boot.web.servlet.FilterRegistrationBean**/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;}
至此實現(xiàn)參數(shù)駝峰與蛇式的兩種方式到此結(jié)束,通過接口測試工具調(diào)用即可驗證。
如果對您有幫助 請點個關(guān)注,萬分感謝
(微信技術(shù)交流群 請加圖圖微信)
評論
圖片
表情
