<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                [TOC] # common-spring-boot-starter 回顧ocp代碼, [02.api-commons模塊](02.api-commons%E6%A8%A1%E5%9D%97.md),代碼耦合了dabsource處理代碼,耦合了log處理代碼 ![](https://img.kancloud.cn/2a/ec/2aecc2c5b9075c05d02a9adde8e5b069_1248x215.png) 在之前的章節總,我們已經將此部分拆解,做到功能職責單一,避免過度依賴,現在我們將api-commons重構,重構后的項目名稱為common-spring-boot-starter ## 功能 * 公用model類 * 菜單樹 * 通用工具類 * 通用異常類 * 通用攔截器 * 通用過濾器 * 通用線程池配置 ![](https://img.kancloud.cn/7d/01/7d01d0d3d93461f4856029c07f617538_1999x768.png) ``` package com.open.capacity.common.test; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import com.open.capacity.common.model.SysMenu; public class Test { public static void main(String[] args) throws JsonProcessingException { SysMenu root = new SysMenu(); root.setId(-1L); root.setParentId(0L); SysMenu child1 = new SysMenu(); child1.setId(1L); child1.setParentId(-1L); SysMenu child11 = new SysMenu(); child11.setId(11L); child11.setParentId(1L); SysMenu child111 = new SysMenu(); child111.setId(111L); child111.setParentId(11L); SysMenu child12 = new SysMenu(); child12.setId(12L); child12.setParentId(1L); SysMenu child2 = new SysMenu(); child2.setId(2L); child2.setParentId(-1L); SysMenu child21 = new SysMenu(); child21.setId(21L); child21.setParentId(2L); SysMenu child22 = new SysMenu(); child22.setId(22L); child22.setParentId(2L); //完整樹 List<SysMenu> list = Lists.newArrayList(); list.add(root); list.add(child1); list.add(child11); list.add(child12); list.add(child111); list.add(child2); list.add(child21); list.add(child22); //遞歸樹 List<SysMenu> menuTree = list.stream().filter(t -> t.getParentId() == -1L).map((menu) -> { menu.setSubMenus(treeChildren(menu, list)); return menu; }).collect(Collectors.toList()); System.out.println(new ObjectMapper().writeValueAsString(menuTree)); //扁平子節點列表 List<SysMenu> platChildList = Lists.newArrayList(); flatChildren(child1, list,platChildList) ; System.out.println(new ObjectMapper().writeValueAsString(platChildList)); //扁平父節點列表 List<SysMenu> platParentList = Lists.newArrayList(); flatParent(child111, list,platParentList) ; System.out.println(new ObjectMapper().writeValueAsString(platParentList)); } /** * 遞歸子節點樹 * @param root * @param all * @return */ private static List<SysMenu> treeChildren(SysMenu root, List<SysMenu> all) { return all.stream().filter(t -> root.getId().equals(t.getParentId())).map((g) -> { g.setSubMenus(treeChildren(g, all)); return g; }).collect(Collectors.toList()); } /** * 扁平子節點列表 * @param current * @param list * @param flatTree */ private static void flatChildren(SysMenu current, List<SysMenu> list , List<SysMenu> flatTree ) { if (current != null) { List<SysMenu> tempList = list.stream() .filter(t -> t.getParentId().equals(current.getId())) .collect(Collectors.toList()); flatTree.addAll(tempList); if (CollectionUtils.isNotEmpty(tempList)) { tempList.stream().forEach(item -> flatChildren(item, list , flatTree)); } } else { return; } } /** * 扁平父節點列表 * @param current * @param list * @param flatTree */ private static void flatParent(SysMenu current, List<SysMenu> list , List<SysMenu> flatTree ) { if (current != null) { List<SysMenu> tempList = list.stream() .filter(t -> t.getId().equals(current.getParentId())) .collect(Collectors.toList()); flatTree.addAll(tempList); if (CollectionUtils.isNotEmpty(tempList)) { tempList.stream().forEach(item -> flatParent(item, list , flatTree)); } } else { return; } } } ``` ## 代碼 * pom依賴 ![](https://img.kancloud.cn/88/6c/886c4a6128aa5f4e338bd21f1caf0533_1731x787.png) * 代碼重構 ![](https://img.kancloud.cn/07/8d/078d9d712b59db760530fc0838d40ad2_1395x616.png) ## hutool 工具類 文檔:[https://www.hutool.cn/docs/#/](https://www.hutool.cn/docs/#/) ### 類型轉化 ``` int a = 1 ; String aString = Convert.toStr(a) ;//整型轉String System.out.println(aString); long[] b = {1L,2L,3L,4L,5L} ; String bString = Convert.toStr(b) ;//long數組 轉String數組 System.out.println(bString); String[] c = {"1","2","3","4","5"}; Integer[] cArray = Convert.toIntArray(c) ;// String數組轉int數組 System.out.println(cArray); String dateString ="2018-05-22 14:09:33" ; Date date = Convert.toDate(dateString) ;//時間轉化 System.out.println(date); String quanjiao ="1234567" ; String banjiao =Convert.toSBC(quanjiao) ;//半角轉化 System.out.println(banjiao); System.out.println(Convert.toDBC(banjiao)) ;//全角轉化 String str = "明文字符串" ; String encodeString = Convert.toHex(str,CharsetUtil.CHARSET_UTF_8) ;//加密 System.out.println(encodeString); String decodeString = Convert.hexToStr(encodeString, CharsetUtil.CHARSET_UTF_8) ; //解密 System.out.println(decodeString); String unicode = Convert.strToUnicode(str) ; System.out.println(unicode); String raw = Convert.unicodeToStr(unicode); System.out.println(raw); String result = Convert.convertCharset(str, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1) ;//字符集轉化 System.out.println(result); String iso = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, CharsetUtil.UTF_8) ; //字符集轉化 System.out.println(iso); long date = 72 ; long day = Convert.convertTime(date, TimeUnit.HOURS, TimeUnit.DAYS);//時間轉化72小時3天 System.out.println(day); double price = 6449.89; System.out.println(Convert.digitToChinese(price)) ;//金錢轉化 ``` ### 時間 ``` Date date = DateUtil.date(); String format = DateUtil.format(date, "yyyy-MM-dd") ; System.out.println(format); Date beginOfDate = DateUtil.beginOfDay(date) ; Date endOfDate = DateUtil.endOfDay(date) ; System.out.println(beginOfDate); System.out.println(endOfDate); date = DateUtil.date(System.currentTimeMillis()); String now = DateUtil.now(); //yyyy-MM-dd HH:mm:ss String tody = DateUtil.today();//yyyy-MM-dd DateUtil.yesterday(); DateUtil.tomorrow(); DateUtil.lastWeek(); DateUtil.lastMonth(); int age = DateUtil.ageOfNow("1998-04-04" ) ; System.out.println(age); ``` ### excel ``` List<?> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd", DateUtil.date(), 3.22676575765); List<?> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1", DateUtil.date(), 250.7676); List<?> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2", DateUtil.date(), 0.111); List<?> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3", DateUtil.date(), 35); List<?> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4", DateUtil.date(), 28.00); List<List<?>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5); BigExcelWriter writer= ExcelUtil.getBigWriter("e:"+File.separator+"xxx.xlsx"); // 一次性寫出內容,使用默認樣式 writer.write(rows); // 關閉writer,釋放內存 writer.close(); ExcelReader reader = ExcelUtil.getReader("e:"+File.separator+"xxx.xlsx"); List<Map<String,Object>> readAll = reader.readAll(); readAll.forEach( item -> { System.out.println(item); }); ``` ### 二維碼 ``` @GetMapping("/test11") public void service(HttpServletResponse response) { try (ServletOutputStream out = response.getOutputStream()) { QrCodeUtil.generate("http://www.baidu.com", QrConfig.create().setImg("logo"), "png", out); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static void main(String[] args) { QrConfig config = new QrConfig(300, 300); config.setMargin(2); QrCodeUtil.generate("http://www.baidu.com", config, FileUtil.file("d:" + File.separator + "test.png")); } ``` ## 獲取用戶信息工具類 ![](https://img.kancloud.cn/9b/41/9b417ca45e96f5e2263aef521de08448_1645x688.png) ## BeanValidator參數校驗 ![](https://img.kancloud.cn/b8/06/b806aee9e7251ea92f7b3f3c90b15052_707x337.png) ![](https://img.kancloud.cn/d3/e7/d3e7fa5f37e8a435f0e993139745c788_1046x688.png) ## 認證授權白名單配置 ![](https://img.kancloud.cn/bf/1b/bf1b68daa879bc4a817ddee99e279ec8_1603x690.png) ## token傳遞 traceid傳遞 ![](https://img.kancloud.cn/39/ac/39ac2889c61518d9501c2e02a8b3ee85_1695x626.png) ![](https://img.kancloud.cn/7c/8d/7c8d84557b84a57e1708d5123f281aa9_1720x660.png) ## 分頁基礎類 ![](https://img.kancloud.cn/56/28/5628a5299c355cccfd3f40521fac69f9_1666x508.png) ## 簡單使用RestTemplate ``` RestTemplate template = new RestTemplate(); String uriTemplate = "http://www.baidu.com"; URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build().toUri(); String s ="{}"; RequestEntity<String> requestEntity = RequestEntity.post(uri) .accept(MediaType.APPLICATION_JSON) .header("Content-Type", "application/json") .body(s); ResponseEntity<String> exchange = template.exchange(requestEntity, String.class); String body = exchange.getBody(); System.out.println(body); ``` ## RestTemplate連接復用 ``` package com.open.capacity.common.rest; import java.util.Arrays; import org.apache.http.HttpResponse; import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; import com.open.capacity.common.util.StringUtil; import cn.hutool.core.convert.Convert; public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy { private final long DEFAULT_SECONDS = 30; private final String DEFAULT_HEAD = "timeout"; /** * 最大keep alive的時間(秒鐘) * 這里默認為30秒,可以根據實際情況設置。可以觀察客戶端機器狀態為TIME_WAIT的TCP連接數,如果太多,可以增大此值。 */ @Override public long getKeepAliveDuration(HttpResponse response, HttpContext context) { return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE)).stream() .filter(h -> StringUtil.equalsIgnoreCase(h.getName(), DEFAULT_HEAD) && StringUtil.isNumeric(h.getValue())) .findFirst().map(h -> Convert.toLong(h.getValue(), DEFAULT_SECONDS)).orElse(DEFAULT_SECONDS) * 1000; } } ``` ## 優化RestTemplateConfig ![](https://img.kancloud.cn/1b/24/1b24ad2e0cca7085129671a39d92027a_967x365.png) 由于RestTemplate默認并發數100(配置默認:org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerRequestExecutor),導致服務間調用阻塞,占用大量時間時間,需要按以下腳本優化, ![](https://img.kancloud.cn/94/08/94080a3a351a573d9136546376e8f543_1687x602.png) ## 實時獲取QPS ![](https://img.kancloud.cn/17/d5/17d580785f4e27b60ad022ea2f2d27c7_871x611.png) ``` @RestController @RequestMapping("/api/v1") @Slf4j public class DemoController { private FlowHelper flowHelper = new FlowHelper(FlowType.Minute); @GetMapping("/test") public Result<Flower> testApi() { try{ long startTime = TimeUtil.currentTimeMillis(); // 業務邏輯 Thread.sleep(1000); // 計算耗時 long rt = TimeUtil.currentTimeMillis() - startTime; flowHelper.incrSuccess(rt); Flower flower = flowHelper.getFlow(FlowType.Minute); System.out.println("總請求數:"+flower.total()); System.out.println("成功請求數:"+flower.totalSuccess()); System.out.println("異常請求數:"+flower.totalException()); System.out.println("平均請求耗時:"+flower.avgRt()); System.out.println("最大請求耗時:"+flower.maxRt()); System.out.println("最小請求耗時:"+flower.minRt()); System.out.println("平均請求成功數(每毫秒):"+flower.successAvg()); System.out.println("平均請求異常數(每毫秒):"+flower.exceptionAvg()); return Result.succeed("ok"); }catch (Exception e){ flowHelper.incrException(); return Result.failed("ko"); } } ``` ## 自定義異常 ![](https://img.kancloud.cn/c4/20/c4201d67cc62bd2e441f8345a2acf97f_1550x401.png) ## 統一異常處理 ![](https://img.kancloud.cn/7f/af/7faf91564b0277307f0315b8a1e3dc55_1606x474.png) [25.統一業務異常處理](27.%E7%BB%9F%E4%B8%80%E5%BC%82%E5%B8%B8.md) ## 父子線程異步傳遞問題 ![](https://img.kancloud.cn/97/7b/977b30c2be4c1d980243384b25eabea9_1730x744.png) ## DefaultClientDetails 應用信息基礎類 ![](https://img.kancloud.cn/5a/02/5a027273873e399c33090bf25ef4f282_984x591.png) #### uaa-server-spring-boot-starter 將DefaultClientDetails信息存儲到redis ![](https://img.kancloud.cn/b3/a8/b3a808a5770f2235cda0badfc6d8755e_1687x641.png) #### 網關利用DefaultClientDetails的clientid得到具體是否需要限制調用次數,以及限制次數限制調用次數 ![](https://img.kancloud.cn/05/82/058236930f69cd6b17d40932eb426845_1674x535.png) ## feign 業務異常處理 > OpenFeign 提供了這種簡單的方式來使用Restful服務,這大大降低了進行接口調用的復雜程度。 對于錯誤的處理, 對于客戶端我們實現了自己的 UserErrorDecoder 來將請求異常轉換為對于的異常類,示例如下 ![](https://img.kancloud.cn/35/d3/35d3888a1f5cdc512e30fe22a9d7ef08_1629x559.png) > 需要注意的是, 當業務返回{"resp_code":"","resp_msg":""}(新版本采用({"code" :"","msg":""}))時,異常應當是 HystrixBadRequestException 的子類對象,原因在于此類異常視作業務異常,而不是由于故障導致的異常,所以不應當被Hystrix計算為失敗請求,并引發斷路器動作,這一點**非常重要**。 SynchronousMethodHandler 處理 ![](https://img.kancloud.cn/5f/e1/5fe19c82db76ca3ea2c8a51fcf0ad9b9_1851x696.png) ## hystrix艙壁模式下RequestContextHolder的傳遞問題 > java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request ![](https://img.kancloud.cn/fe/2c/fe2c1a7db3bfa0aa665bbe82ff143573_1493x543.png) ![](https://img.kancloud.cn/87/18/8718189b1f3b41fac057b743720cea13_1679x615.png) ## 接口安全 > 前后端分離的開發方式,我們以接口為標準來進行推動,定義好接口,各自開發自己的功能,最后進行聯調整合。無論是開發原生的APP還是webapp還是PC端的軟件,只要是前后端分離的模式,就避免不了調用后端提供的接口來進行業務交互。網頁或者app,只要抓下包就可以清楚的知道這個請求獲取到的數據,這樣的接口對爬蟲工程師來說是一種福音,要抓你的數據簡直輕而易舉。數據的安全性非常重要,特別是用戶相關的信息,稍有不慎就會被不法分子盜用,所以我們對這塊要非常重視,容不得馬虎。 ![](https://img.kancloud.cn/a1/fd/a1fd70159d8f54f37a249fc2c147cf08_675x302.png) * 3DES 3DES,也稱為 3DESede 或 TripleDES,是三重數據加密算法,相當于是對每個數據庫應用三次DES的對稱加密算法。由于DES密碼長度容易被暴力破解,所以3DES算法通過對DES算法進行改進,增加DES的密鑰長度來避免類似的攻擊,針對每個數據塊進行三次DES加密;因此,3DES加密算法并非什么新的加密算法,是DES的一個更安全的變形,它以DES為基本模塊,通過組合分組方法設計出分組加密算法。3DES是DES向AES過渡的加密算法,它使用2個或者3個56位的密鑰對數據進行三次加密。相比DES,3DES因密鑰長度變長,安全性有所提高,但其處理速度不高。因此又出現了AES加密算法,AES較于3DES速度更快、安全性更高。 ![](https://img.kancloud.cn/1c/7f/1c7fc6a2140235e0c798481d736e4163_1769x887.png) ### 樣例 客戶端攜帶參數appId、timestamp、sign去調用服務器端的API token,其中sign=加密(appId + timestamp + signkey) ![](https://img.kancloud.cn/f5/40/f540eac5d57c4f2bfaf10d48edc7c830_1723x621.png) {"data":"atCwUKkP6CUpPoNX+fyWJVSq7GA4QDfPYthOKqICCsnlyCe4wW8JezWWaP3PtsqG9MvISylslnEo\\r\\nc7a8aSe1GAkDWNl4ejqlNpGeHQ3NG1WTNcwvx4XCaw==","sign":"328ed5b34824197047c286868cb79fdd","appId":"zwwtest","timestamp":"1591877695909"} ![](https://img.kancloud.cn/1b/9c/1b9c837e39ec377de5cc607c73b81886_692x540.png) ## 代碼安全掃描 ![](https://img.kancloud.cn/cf/58/cf58003de5ca3bfff8406a896c46e723_558x252.png) ![](https://img.kancloud.cn/f3/e4/f3e48d80b709e500cc42e4f3f8b07bdb_1958x806.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看