1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問(wèn)題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
      SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳

      這篇文章主要介紹“SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳”,在日常操作中,相信很多人在SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

      創(chuàng)新互聯(lián)是一家專注于網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),定安網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:定安等地區(qū)。定安做網(wǎng)站價(jià)格咨詢:028-86922220

      背景介紹

      SpringMVC搭建的微服務(wù)系統(tǒng),后端數(shù)據(jù)庫(kù)對(duì)時(shí)間類型的存儲(chǔ)使用的是Long類型,而前端框架傾向于使用yyyy-MM-dd HH:mm:ss這種標(biāo)準(zhǔn)顯示格式,前端JSON格式的請(qǐng)求報(bào)文與后臺(tái)的接口交互都需要進(jìn)行格式轉(zhuǎn)換,這部分轉(zhuǎn)換功能由后臺(tái)實(shí)現(xiàn)。

      使用時(shí)我們發(fā)現(xiàn),前端定義的JSON請(qǐng)求,時(shí)間格式為yyyy-MM-dd HH:mm:ss,如果后臺(tái)定義的POJO相應(yīng)的屬性為L(zhǎng)ong類型,可以自動(dòng)轉(zhuǎn)換為時(shí)間戳,對(duì)此非常好奇,框架是如何實(shí)現(xiàn)這一功能的?

      框架選型、版本及主要功能
      1. spring boot 2.1.6.RELEASE

      2. spring cloud Greenwich.SR3

      3. alibaba fastjson 1.2.60

      注意json框架使用的是fastjson

      代碼演示

      為了方便演示,定義一個(gè)特別簡(jiǎn)單的POJO類:

      public class DateReq {
      
      	private String dateFormat;
      	private Long timestamp;
      
          // 省略getter/setter/toString方法
      }

      再定義一個(gè)簡(jiǎn)單的Controller方法:

      @RestController
      public class DemoController {
      
      	@PostMapping(value = "/json/demo/info")
      	public ApiResponse dateJson(@RequestBody DateReq request) {
      		System.out.println(request);
      	}
      }

      請(qǐng)求報(bào)文如下:

      {
          "dateFormat": "2020-08-07 18:50:00",
          "timestamp": "2020-08-07 18:50:00"
      }

      響應(yīng)的結(jié)果:DateReq{dateFormat='2020-08-07 18:50:00', timestamp=1596797400000}

      從結(jié)果可以發(fā)現(xiàn),dateFormat字段我們定義的是String類型,timestamp定義的是Long類型,請(qǐng)求報(bào)文兩個(gè)字段使用相同的值,但是到了Controller方法里,timestamp自動(dòng)變成Long類型的時(shí)間戳了,并且是按東8區(qū)轉(zhuǎn)換的。

      在這里我們可以得到一個(gè)使用經(jīng)驗(yàn):POJO的時(shí)間格式是可以自動(dòng)轉(zhuǎn)換成Long類型時(shí)間戳的,默認(rèn)時(shí)區(qū)取操作系統(tǒng)的時(shí)區(qū),或者通過(guò)jvm參數(shù)-Duser.timezone=GMT+08設(shè)置。

      源碼閱讀

      既然看到了自動(dòng)轉(zhuǎn)換的效果,非常好奇框架是怎么實(shí)現(xiàn)的,我們通過(guò)斷點(diǎn)查找堆棧:

      deserialze:79, LongCodec (com.alibaba.fastjson.serializer)
      parseField:85, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
      parseField:1224, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
      deserialze:850, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
      parseRest:1538, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
      deserialze:-1, FastjsonASMDeserializer_3_DateReq (com.alibaba.fastjson.parser.deserializer)
      deserialze:284, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
      parseObject:692, DefaultJSONParser (com.alibaba.fastjson.parser)
      parseObject:383, JSON (com.alibaba.fastjson)
      parseObject:448, JSON (com.alibaba.fastjson)
      parseObject:556, JSON (com.alibaba.fastjson)
      readType:263, FastJsonHttpMessageConverter (com.alibaba.fastjson.support.spring)
      read:237, FastJsonHttpMessageConverter (com.alibaba.fastjson.support.spring)
      readWithMessageConverters:204, AbstractMessageConverterMethodArgumentResolver (org.springframework.web.servlet.mvc.method.annotation)
      readWithMessageConverters:157, RequestResponseBodyMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
      resolveArgument:130, RequestResponseBodyMethodProcessor (org.springframework.web.servlet.mvc.method.annotation)
      resolveArgument:124, HandlerMethodArgumentResolverComposite (org.springframework.web.method.support)

      發(fā)現(xiàn)了兩處有價(jià)值的信息:

      1. 觸發(fā)消息類型轉(zhuǎn)換類是FastJsonHttpMessageConverter

      2. 真正完成類型映射是fastjson框架

      有這個(gè)思路,閱讀源碼時(shí)可以把重點(diǎn)放在fastjson上,從JSON反序列化為POJO,Long類型字段處理,找到這段代碼:

      public  T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
              JSONLexer lexer = parser.lexer;
      
              Long longObject;
              try {
                  int token = lexer.token();
                  if (token == 2) {
                      long longValue = lexer.longValue();
                      lexer.nextToken(16);
                      longObject = longValue;
                  } else if (token == 3) {
                      BigDecimal number = lexer.decimalValue();
                      longObject = TypeUtils.longValue(number);
                      lexer.nextToken(16);
                  } else {
                      if (token == 12) {
                          JSONObject jsonObject = new JSONObject(true);
                          parser.parseObject(jsonObject);
                          longObject = TypeUtils.castToLong(jsonObject);
                      } else {
                          Object value = parser.parse();
                          // 關(guān)注這一行,yyyy-MM-dd HH:mm:ss會(huì)執(zhí)行這一行代碼
                          longObject = TypeUtils.castToLong(value);
                      }
      
                      if (longObject == null) {
                          return null;
                      }
                  }
              } catch (Exception var9) {
                  throw new JSONException("parseLong error, field : " + fieldName, var9);
              }
      
              return clazz == AtomicLong.class ? new AtomicLong(longObject) : longObject;
          }

      重點(diǎn)關(guān)注longObject = TypeUtils.castToLong(value);yyyy-MM-dd HH:mm:ss格式的數(shù)據(jù)會(huì)執(zhí)行這一行代碼,跟進(jìn)去查看源碼:

      public static Long castToLong(Object value) {
              if (value == null) {
                  return null;
              } else if (value instanceof BigDecimal) {
                  return longValue((BigDecimal)value);
              } else if (value instanceof Number) {
                  return ((Number)value).longValue();
              } else {
                  if (value instanceof String) {
                      String strVal = (String)value;
                      if (strVal.length() == 0 || "null".equals(strVal) || "NULL".equals(strVal)) {
                          return null;
                      }
      
                      if (strVal.indexOf(44) != 0) {
                          strVal = strVal.replaceAll(",", "");
                      }
      
                      try {
                          return Long.parseLong(strVal);
                      } catch (NumberFormatException var4) {
                          // 在異常里做最后的掙扎,今天的案例是執(zhí)行到這里的
                          JSONScanner dateParser = new JSONScanner(strVal);
                          Calendar calendar = null;
                          if (dateParser.scanISO8601DateIfMatch(false)) {
                              calendar = dateParser.getCalendar();
                          }
      
                          dateParser.close();
                          if (calendar != null) {
                              return calendar.getTimeInMillis();
                          }
                      }
                  }
      
                  if (value instanceof Map) {
                      Map map = (Map)value;
                      if (map.size() == 2 && map.containsKey("andIncrement") && map.containsKey("andDecrement")) {
                          Iterator iter = map.values().iterator();
                          iter.next();
                          Object value2 = iter.next();
                          return castToLong(value2);
                      }
                  }
      
                  throw new JSONException("can not cast to long, value : " + value);
              }
          }

      可以看到在castToLong方法里,對(duì)假想的數(shù)據(jù)類型做各種假設(shè)處理,很不幸的是我們?cè)囼?yàn)的數(shù)據(jù)格式,是在NumberFormatException異常里完成的最后掙扎,使用JSONScanner類接收的請(qǐng)求數(shù)據(jù)。

      可以看到在這里通過(guò)調(diào)用dateParser.scanISO8601DateIfMatch對(duì)數(shù)據(jù)進(jìn)行解析,得到calendar對(duì)象實(shí)例,最終通過(guò)calendar獲取時(shí)間戳,scanISO8601DateIfMatch方法邏輯很復(fù)雜,總共有450多行,這里截取了其中一部分展現(xiàn)一下:

      private boolean scanISO8601DateIfMatch(boolean strict, int rest) {
              if (rest < 8) {
                  return false;
              }
      
              char c0 = charAt(bp);
              char c1 = charAt(bp + 1);
              char c2 = charAt(bp + 2);
              char c3 = charAt(bp + 3);
              char c4 = charAt(bp + 4);
              char c5 = charAt(bp + 5);
              char c6 = charAt(bp + 6);
              char c7 = charAt(bp + 7);
      
              if ((!strict) && rest > 13) {
                  char c_r0 = charAt(bp + rest - 1);
                  char c_r1 = charAt(bp + rest - 2);
              }
      
              char c10;
             
      
              if (rest < 9) {
                  return false;
              }
      
              char c8 = charAt(bp + 8);
              char c9 = charAt(bp + 9);
      
              int date_len = 10;
              char y0, y1, y2, y3, M0, M1, d0, d1;
              if ((c4 == '-' && c7 == '-') // cn
                      ||  (c4 == '/' && c7 == '/') // tw yyyy/mm/dd
              ) {
                  y0 = c0;
                  y1 = c1;
                  y2 = c2;
                  y3 = c3;
                  M0 = c5;
                  M1 = c6;
                  d0 = c8;
                  d1 = c9;
              } else if ((c4 == '-' && c6 == '-') // cn yyyy-m-dd
              ) {
                  y0 = c0;
                  y1 = c1;
                  y2 = c2;
                  y3 = c3;
                  M0 = '0';
                  M1 = c5;
      
                  if (c8 == ' ') {
                      d0 = '0';
                      d1 = c7;
                      date_len = 8;
                  } else {
                      d0 = c7;
                      d1 = c8;
                      date_len = 9;
                  }
              } else if ((c2 == '.' && c5 == '.') // de dd.mm.yyyy
                      || (c2 == '-' && c5 == '-') // in dd-mm-yyyy
              ) {
                  d0 = c0;
                  d1 = c1;
                  M0 = c3;
                  M1 = c4;
                  y0 = c6;
                  y1 = c7;
                  y2 = c8;
                  y3 = c9;
              } else if (c8 == 'T') {
                  y0 = c0;
                  y1 = c1;
                  y2 = c2;
                  y3 = c3;
                  M0 = c4;
                  M1 = c5;
                  d0 = c6;
                  d1 = c7;
                  date_len = 8;
              } else {
                  if (c4 == '年' || c4 == '?') {
                      y0 = c0;
                      y1 = c1;
                      y2 = c2;
                      y3 = c3;
      
                      if (c7 == '月' || c7 == '?') {
                          M0 = c5;
                          M1 = c6;
                          if (c9 == '日' || c9 == '?') {
                              d0 = '0';
                              d1 = c8;
                          } else if (charAt(bp + 10) == '日' || charAt(bp + 10) == '?'){
                              d0 = c8;
                              d1 = c9;
                              date_len = 11;
                          } else {
                              return false;
                          }
                      } else if (c6 == '月' || c6 == '?') {
                          M0 = '0';
                          M1 = c5;
                          if (c8 == '日' || c8 == '?') {
                              d0 = '0';
                              d1 = c7;
                          } else if (c9 == '日' || c9 == '?'){
                              d0 = c7;
                              d1 = c8;
                          } else {
                              return false;
                          }
                      } else {
                          return false;
                      }
                  } else {
                      return false;
                  }
              }
      
              if (!checkDate(y0, y1, y2, y3, M0, M1, d0, d1)) {
                  return false;
              }
      
              setCalendar(y0, y1, y2, y3, M0, M1, d0, d1);
      
              char t = charAt(bp + date_len);
             
      
              if (charAt(bp + date_len + 3) != ':') {
                  return false;
              }
              if (charAt(bp + date_len + 6) != ':') {
                  return false;
              }
      
              char h0 = charAt(bp + date_len + 1);
              char h2 = charAt(bp + date_len + 2);
              char m0 = charAt(bp + date_len + 4);
              char m1 = charAt(bp + date_len + 5);
              char s0 = charAt(bp + date_len + 7);
              char s1 = charAt(bp + date_len + 8);
      
              if (!checkTime(h0, h2, m0, m1, s0, s1)) {
                  return false;
              }
      
              setTime(h0, h2, m0, m1, s0, s1);
      
              char dot = charAt(bp + date_len + 9);
              int millisLen = -1; // 有可能沒(méi)有毫秒?yún)^(qū)域,沒(méi)有毫秒?yún)^(qū)域的時(shí)候下一個(gè)字符位置有可能是'Z'、'+'、'-'
              int millis = 0;
             
              calendar.set(Calendar.MILLISECOND, millis);
      
              int timzeZoneLength = 0;
              char timeZoneFlag = charAt(bp + date_len + 10 + millisLen);
      
              if (timeZoneFlag == ' ') {
                  millisLen++;
                  timeZoneFlag = charAt(bp + date_len + 10 + millisLen);
              }
      
              char end = charAt(bp + (date_len + 10 + millisLen + timzeZoneLength));
              if (end != EOI && end != '"') {
                  return false;
              }
              ch = charAt(bp += (date_len + 10 + millisLen + timzeZoneLength));
      
              token = JSONToken.LITERAL_ISO8601_DATE;
              return true;
          }

      支持的格式還是挺多,不過(guò)基本上符合國(guó)內(nèi)的日期使用習(xí)慣,像2020-08-08和2020/08/08,甚至2020年08月08日都行,解析的思路是按位截取判斷,然后作為Calendar的參數(shù),上述節(jié)選的代碼有刪節(jié),有興趣可以查看原代碼。

      到此,關(guān)于“SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!


      本文題目:SpringMVC實(shí)現(xiàn)日期格式屬性自動(dòng)轉(zhuǎn)成時(shí)間戳
      網(wǎng)站鏈接:http://www.ef60e0e.cn/article/pgoogg.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        和政县| 辽中县| 隆安县| 牟定县| 成都市| 屏东市| 德庆县| 东乡| 南通市| 民和| 建平县| 射洪县| 江陵县| 伊川县| 抚州市| 竹北市| 朝阳市| 休宁县| 盖州市| 拉孜县| 清新县| 乌苏市| 峨山| 睢宁县| 扎囊县| 浦县| 湖北省| 苍山县| 萍乡市| 绥化市| 朝阳县| 博白县| 米林县| 历史| 商河县| 武义县| 苗栗县| 花莲县| 六枝特区| 潮州市| 乡城县|