[{"data":1,"prerenderedAt":11382},["ShallowReactive",2],{"post:\u002Ftags\u002F%E9%81%BF%E5%9D%91":3,"posts:all":4},null,[5,317,1808,2083,2473,3094,3319,3376,4092,5402,6675,7091,7837,8326,9269,9677,11239],{"id":6,"title":7,"body":8,"date":303,"description":304,"extension":305,"meta":306,"navigation":307,"path":308,"seo":309,"stem":310,"tags":311,"__hash__":316},"posts\u002Fposts\u002Fmx-player-eac3-custom-codec.md","解决MX Player不支持 EAC3 格式和找不到自定义编解码器的问题（提示 3.1.0 ARMv8 NEON）",{"type":9,"value":10,"toc":292},"minimark",[11,15,23,26,33,37,40,43,47,50,56,59,62,157,160,163,166,169,175,194,197,213,216,219,222,225,231,234,240,243,247,250,256,259,262],[12,13,14],"p",{},"最近看美剧换了一家字幕组，用电脑看没问题，但是在手机上用 MX Player 看视频，画面正常但没声音，提示「不支持此音频格式（EAC3）」。",[12,16,17],{},[18,19],"img",{"alt":20,"src":21,"width":22},"MX Player 播放界面提示「不支持此音频格式（EAC3）」","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F01-eac3-not-support.jpg",900,[12,24,25],{},"去搜解决办法，说要装自定义编解码器。跟着教程下了一个装上，结果又提示「找不到自定义编解码器，请使用 3.1.0 ARMv8 NEON 版编解码器」。",[12,27,28],{},[18,29],{"alt":30,"src":31,"width":32},"解码器设置页弹窗：找不到自定义编解码器，请使用 3.1.0 ARMv8 NEON 版编解码器","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F02-codec-not-found.jpg",360,[34,35,36],"h2",{"id":36},"为什么会没声音",[12,38,39],{},"EAC3（Dolby Digital Plus）是杜比的专利音频格式，常见于 MKV 电影和流媒体片源。MX Player 因为授权费的问题，从 1.7.32 版本开始把 AC3、EAC3、DTS 这些格式的解码能力移除了。所以视频能播，声音出不来。",[12,41,42],{},"MX Player 支持加载自定义编解码器。社区有人用官方开源的 FFmpeg 代码重新编译了一份，把被删掉的格式加了回来。",[34,44,46],{"id":45},"编解码器版本和-app-版本不是一回事","编解码器版本和 App 版本不是一回事",[12,48,49],{},"MX Player 的自定义编解码器版本号和 App 版本号是两套独立编号。关于页面里我的 App 是 3.2.5，要的编解码器却是 3.1.0，两个数字对不上很正常，不能拿 App 版本号去下编解码器。",[12,51,52],{},[18,53],{"alt":54,"src":55,"width":32},"关于页面，显示 MX 播放器 版本 3.2.5 (ARMv8 NEON)","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F03-about-version.jpg",[12,57,58],{},"具体用哪个版本，以 MX Player 自己提示的为准。打开 MX Player，点右上角三个点 → 设置 → 解码器，滑到底部找到「自定义编解码器」，点进去就会显示需要哪个版本。我的提示是「请使用 3.1.0 ARMv8 NEON 版编解码器」，其中的「ARMv8 NEON」就是 neon64 架构。",[12,60,61],{},"各版本对应关系：",[63,64,65,81],"table",{},[66,67,68],"thead",{},[69,70,71,75,78],"tr",{},[72,73,74],"th",{},"MX Player 版本",[72,76,77],{},"编解码器版本",[72,79,80],{},"下载地址",[82,83,84,101,115,129,143],"tbody",{},[69,85,86,90,93],{},[87,88,89],"td",{},"3.0.13 ~ 3.2.5",[87,91,92],{},"3.1.0",[87,94,95],{},[96,97,98],"a",{"href":98,"rel":99},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Ftag\u002Fv3.1.0_r1",[100],"nofollow",[69,102,103,106,109],{},[87,104,105],{},"2.7.x",[87,107,108],{},"2.7.0",[87,110,111],{},[96,112,113],{"href":113,"rel":114},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Ftag\u002Fv2.7.0_r0",[100],[69,116,117,120,123],{},[87,118,119],{},"2.6.x",[87,121,122],{},"2.5.0",[87,124,125],{},[96,126,127],{"href":127,"rel":128},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Ftag\u002Fv2.5.0_r0",[100],[69,130,131,134,137],{},[87,132,133],{},"2.5.x \u002F 2.1.x",[87,135,136],{},"1.87.0",[87,138,139],{},[96,140,141],{"href":141,"rel":142},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Ftag\u002Fv1.87.0_r6",[100],[69,144,145,148,151],{},[87,146,147],{},"1.93.3 Pro \u002F 1.96.x",[87,149,150],{},"1.87.0（文件标 1.90.1）",[87,152,153],{},[96,154,155],{"href":155,"rel":156},"https:\u002F\u002Fgithub.com\u002FUSBhost\u002FMX_FFmpeg\u002Freleases\u002Ftag\u002F1.90.1v2",[100],[12,158,159],{},"两个仓库的区别：USBhost 是原作者（XDA 论坛的），更新停在 1.90.1v2；iDNA420 是后来接棒维护的，2.x 和 3.x 的版本都在那边。用新版 MX Player 的直接去 iDNA420。",[12,161,162],{},"每个 release 一般有 5 个文件：aio（全量）、neon64、neon、x86、x86_64。懒得查架构就下 aio。",[34,164,165],{"id":165},"下载编解码器",[12,167,168],{},"进上表里的 release 页面，点开 Assets，找到你要的那个 zip：",[12,170,171],{},[18,172],{"alt":173,"src":174,"width":22},"GitHub 上 v3.1.0_r1 的 release 页面，Assets 里列出 5 个 zip 文件","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F04-github-release.jpg",[176,177,178,187],"ul",{},[179,180,181,182,186],"li",{},"不确定架构 → 下 ",[183,184,185],"strong",{},"aio-v3.1.0_r1.zip","（全量包，MX Player 自动选，25MB 左右）",[179,188,189,190,193],{},"ARMv8 NEON（现在几乎所有手机都是这个）→ 下 ",[183,191,192],{},"neon64-3.1.0-build_1.zip","（6MB 左右）",[12,195,196],{},"懒得点页面，直接用直链：",[176,198,199,206],{},[179,200,201,202],{},"全量包：",[96,203,204],{"href":204,"rel":205},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Fdownload\u002Fv3.1.0_r1\u002Faio-v3.1.0_r1.zip",[100],[179,207,208,209],{},"neon64：",[96,210,211],{"href":211,"rel":212},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases\u002Fdownload\u002Fv3.1.0_r1\u002Fneon64-3.1.0-build_1.zip",[100],[12,214,215],{},"zip 不用解压，原样放到手机里就行，建议放 Download 目录，MX Player 会自动扫描到。",[34,217,218],{"id":218},"安装",[12,220,221],{},"打开 MX Player → 设置 → 解码器 → 自定义编解码器，点进去选择你刚下载的 zip 文件。",[12,223,224],{},"选好之后会弹出确认框，显示文件名、路径、大小，点「确定」。",[12,226,227],{},[18,228],{"alt":229,"src":230,"width":32},"确认使用自定义编解码器，文件名 neon64-3.1.0-build_1.zip","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F05-codec-confirm.jpg",[12,232,233],{},"然后提示「重启应用以重新载入编解码器」，点确定，MX Player 会自动重启。",[12,235,236],{},[18,237],{"alt":238,"src":239,"width":32},"提示「重启应用以重新载入编解码器。」","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F06-restart.jpg",[12,241,242],{},"再打开之前没声音的那个视频，应该就正常了。",[34,244,246],{"id":245},"装了还是没声音","装了还是没声音？",[12,248,249],{},"可以试试在播放界面切换解码器。播放时点右上角的解码器图标，在「硬件解码器」「硬件解码器+」「软件解码器」之间切换试试，有时候换一个就出声了。",[12,251,252],{},[18,253],{"alt":254,"src":255,"width":22},"选择解码器弹窗：硬件解码器 \u002F 硬件解码器+ \u002F 软件解码器","\u002Fimages\u002Fmx-player-eac3-custom-codec\u002F07-decoder-select.jpg",[12,257,258],{},"如果是 Android TV 上用，记得给 MX Player 开存储权限，不然它可能读不到你放的 zip 文件。",[34,260,261],{"id":261},"相关文档",[176,263,264,271,278,285],{},[179,265,266,267],{},"MX Player 官方说明「Audio does not play」：",[96,268,269],{"href":269,"rel":270},"https:\u002F\u002Fsupport.mxplayer.in\u002Fsupport\u002Fsolutions\u002Farticles\u002F43000608838-audio-does-not-play-",[100],[179,272,273,274],{},"自定义编解码器原始帖（XDA 论坛，2013 年开帖至今仍在更新）：",[96,275,276],{"href":276,"rel":277},"https:\u002F\u002Fxdaforums.com\u002Ft\u002Fmx-player-custom-codec-ac3-dts-mlp-truehd-etc.2156254\u002F",[100],[179,279,280,281],{},"编解码器仓库 iDNA420\u002FMX-FFmpeg（含 2.x \u002F 3.x）：",[96,282,283],{"href":283,"rel":284},"https:\u002F\u002Fgithub.com\u002FiDNA420\u002FMX-FFmpeg\u002Freleases",[100],[179,286,287,288],{},"编解码器仓库 USBhost\u002FMX_FFmpeg（原维护者）：",[96,289,290],{"href":290,"rel":291},"https:\u002F\u002Fgithub.com\u002FUSBhost\u002FMX_FFmpeg\u002Freleases",[100],{"title":293,"searchDepth":294,"depth":294,"links":295},"",3,[296,298,299,300,301,302],{"id":36,"depth":297,"text":36},2,{"id":45,"depth":297,"text":46},{"id":165,"depth":297,"text":165},{"id":218,"depth":297,"text":218},{"id":245,"depth":297,"text":246},{"id":261,"depth":297,"text":261},"2026-10-24","手机上看 MKV 美剧，画面正常却没声音，MX Player 提示不支持 EAC3 格式；照着网上的教程装了自定义编解码器，又报「找不到自定义编解码器，请使用 3.1.0 ARMv8 NEON 版」。这篇把两个报错串成一条线讲清楚，附各版本对应关系和下载地址。","md",{},true,"\u002Fposts\u002Fmx-player-eac3-custom-codec",{"title":7,"description":304},"posts\u002Fmx-player-eac3-custom-codec",[312,313,314,315],"MXPlayer","Android","播放器","避坑","nXCIzcJte9ZMGzijbdBnYMA6_f7uv-0rMIGfmSM3Qc4",{"id":318,"title":319,"body":320,"date":1797,"description":1798,"extension":305,"meta":1799,"navigation":307,"path":1800,"seo":1801,"stem":1802,"tags":1803,"__hash__":1807},"posts\u002Fposts\u002Fnuxt-dynamic-import-prefetch.md","懒加载没懒成？Nuxt 动态 import 自动 prefetch 的坑",{"type":9,"value":321,"toc":1782},[322,337,340,343,397,400,407,410,424,431,438,512,517,522,531,534,545,579,582,585,685,744,750,753,756,761,767,773,776,781,857,860,863,869,885,891,894,900,918,921,926,929,935,973,988,991,997,1010,1013,1019,1044,1050,1060,1063,1066,1072,1078,1081,1084,1089,1139,1145,1148,1158,1162,1211,1217,1220,1233,1239,1243,1300,1303,1315,1320,1323,1468,1471,1482,1488,1495,1500,1506,1509,1512,1515,1587,1654,1657,1663,1666,1669,1675,1678,1716,1719,1722,1725,1728,1757,1760,1763,1766,1778],[12,323,324,325,330,331,336],{},"最近一直在做站点的性能优化。毕竟",[96,326,329],{"href":327,"rel":328},"https:\u002F\u002Fwww.easydebug.net",[100],"在线工具","和",[96,332,335],{"href":333,"rel":334},"https:\u002F\u002Fblog.easydebug.net",[100],"博客","都跑在阿里云的一台3M小水管机器上，换算下来理论峰值 384 KB\u002Fs，实际也就是 300 KB\u002Fs 的水平。",[12,338,339],{},"用户对速度的感知，几乎都集中在首次加载。所以重中之重是给它减负，把不需要执行的 JS 从这一步拿掉。毕竟首次加载多下 200 KB，用户就得多等大半秒。现在用不上，那就等真用到时再下。",[12,341,342],{},"标准操作就是：",[344,345,349],"pre",{"className":346,"code":347,"language":348,"meta":293,"style":293},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const { renderLua } = await import('~\u002Flib\u002Fformat-lua')\n","ts",[350,351,352],"code",{"__ignoreMap":293},[353,354,357,361,365,369,372,375,379,382,385,388,392,394],"span",{"class":355,"line":356},"line",1,[353,358,360],{"class":359},"spNyl","const",[353,362,364],{"class":363},"sMK4o"," {",[353,366,368],{"class":367},"sTEyZ"," renderLua ",[353,370,371],{"class":363},"}",[353,373,374],{"class":363}," =",[353,376,378],{"class":377},"s7zQu"," await",[353,380,381],{"class":363}," import",[353,383,384],{"class":367},"(",[353,386,387],{"class":363},"'",[353,389,391],{"class":390},"sfazB","~\u002Flib\u002Fformat-lua",[353,393,387],{"class":363},[353,395,396],{"class":367},")\n",[12,398,399],{},"改完后 F12 一看。不对劲。",[12,401,402,403,406],{},"我什么都没点，那个触发才下载的 JS 还是被下载了，只是 Priority = ",[350,404,405],{},"Lowest","。",[34,408,409],{"id":409},"背景",[12,411,412,413,416,417,420,421],{},"目前使用版本 Node ",[183,414,415],{},"v24.18.0","、Nuxt ",[183,418,419],{},"4.5.2"," 、pnpm ",[183,422,423],{},"11.15.1",[12,425,426,427,430],{},"Nuxt 项目打包之后，代码会被切成很多个 ",[350,428,429],{},".js"," 文件，也就是常说的 chunk。一个页面不会用到全部 chunk，所以打包器要在 HTML 里留几个标记，告诉浏览器「这个文件待会儿要用，先去拿来」。",[12,432,433,434,437],{},"负责留标记的是一类 ",[350,435,436],{},"\u003Clink>"," 标签，常用的有两种：",[344,439,443],{"className":440,"code":441,"language":442,"meta":293,"style":293},"language-html shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Clink rel=\"modulepreload\" href=\"\u002F_nuxt\u002Fxxx.js\">\n\u003Clink rel=\"prefetch\" href=\"\u002F_nuxt\u002Fxxx.js\">\n","html",[350,444,445,483],{"__ignoreMap":293},[353,446,447,450,454,457,460,463,466,468,471,473,475,478,480],{"class":355,"line":356},[353,448,449],{"class":363},"\u003C",[353,451,453],{"class":452},"swJcz","link",[353,455,456],{"class":359}," rel",[353,458,459],{"class":363},"=",[353,461,462],{"class":363},"\"",[353,464,465],{"class":390},"modulepreload",[353,467,462],{"class":363},[353,469,470],{"class":359}," href",[353,472,459],{"class":363},[353,474,462],{"class":363},[353,476,477],{"class":390},"\u002F_nuxt\u002Fxxx.js",[353,479,462],{"class":363},[353,481,482],{"class":363},">\n",[353,484,485,487,489,491,493,495,498,500,502,504,506,508,510],{"class":355,"line":297},[353,486,449],{"class":363},[353,488,453],{"class":452},[353,490,456],{"class":359},[353,492,459],{"class":363},[353,494,462],{"class":363},[353,496,497],{"class":390},"prefetch",[353,499,462],{"class":363},[353,501,470],{"class":359},[353,503,459],{"class":363},[353,505,462],{"class":363},[353,507,477],{"class":390},[353,509,462],{"class":363},[353,511,482],{"class":363},[12,513,514,516],{},[350,515,465],{}," 的意思是「这个文件我现在就要用」。浏览器解析到这一行，立刻用高优先级去下载，跟 CSS、字体抢带宽。",[12,518,519,521],{},[350,520,497],{}," 的意思是「这个文件以后可能会用」。浏览器先把当前页面的事干完，等网络闲下来，再用低优先级慢慢下。",[12,523,524,525,527,528,530],{},"两个标签的区别不在「下不下」，而在「什么时候下、抢不抢带宽」。两者最终都会把文件拿到本地，只是 ",[350,526,465],{}," 要跟首次加载抢带宽，",[350,529,497],{}," 排在队尾。",[12,532,533],{},"这两个标签基本不用手写。Nuxt 在构建时会读代码里的 import 关系，自己决定往 HTML 里塞哪几个。",[12,535,536,537,540,541,544],{},"而我在这个模块上写的是 ",[350,538,539],{},"await import()","：既不是静态导入，也没手写 prefetch，首次加载也用不到它。可 ",[350,542,543],{},"generate"," 之后，它还是变成了 prefetch：",[344,546,548],{"className":440,"code":547,"language":442,"meta":293,"style":293},"\u003Clink rel=\"prefetch\" href=\"\u002F_nuxt\u002FDxxxxxxx.js\">\n",[350,549,550],{"__ignoreMap":293},[353,551,552,554,556,558,560,562,564,566,568,570,572,575,577],{"class":355,"line":356},[353,553,449],{"class":363},[353,555,453],{"class":452},[353,557,456],{"class":359},[353,559,459],{"class":363},[353,561,462],{"class":363},[353,563,497],{"class":390},[353,565,462],{"class":363},[353,567,470],{"class":359},[353,569,459],{"class":363},[353,571,462],{"class":363},[353,573,574],{"class":390},"\u002F_nuxt\u002FDxxxxxxx.js",[353,576,462],{"class":363},[353,578,482],{"class":363},[34,580,581],{"id":581},"复现",[12,583,584],{},"我新建了一个 Nuxt 项目，分别把动态导入的几种写法拆成几个独立页面，每个页面都配了一个体积相同的200 KB载荷。项目代码放在文章末尾了。",[63,586,587,597],{},[66,588,589],{},[69,590,591,594],{},[72,592,593],{},"页面",[72,595,596],{},"写法",[82,598,599,609,622,634,647,657,670],{},[69,600,601,606],{},[87,602,603],{},[350,604,605],{},"\u002Fclean\u002F",[87,607,608],{},"什么都不导入，基线",[69,610,611,616],{},[87,612,613],{},[350,614,615],{},"\u002Flink-modulepreload\u002F",[87,617,618,619],{},"顶层静态 ",[350,620,621],{},"import",[69,623,624,629],{},[87,625,626],{},[350,627,628],{},"\u002Flink-prefetch\u002F",[87,630,631],{},[350,632,633],{},"\u003Clink rel=\"prefetch\">",[69,635,636,641],{},[87,637,638],{},[350,639,640],{},"\u002Fawait-import-prefetch\u002F",[87,642,643,644,646],{},"函数内 ",[350,645,539],{},"（一级）",[69,648,649,654],{},[87,650,651],{},[350,652,653],{},"\u002Fawait-import-nested\u002F",[87,655,656],{},"页面 → 一级 mid → 二级载荷",[69,658,659,664],{},[87,660,661],{},[350,662,663],{},"\u002Fasync-component\u002F",[87,665,666,669],{},[350,667,668],{},"defineAsyncComponent","，无条件渲染",[69,671,672,677],{},[87,673,674],{},[350,675,676],{},"\u002Fasync-component-conditional\u002F",[87,678,679,681,682],{},[350,680,668],{}," + ",[350,683,684],{},"v-if",[344,686,690],{"className":687,"code":688,"language":689,"meta":293,"style":293},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm gen        # 生成载荷，必须先跑\npnpm generate\npnpm analyze\nnpx --yes http-server .output\u002Fpublic -p 6521 -c-1\n","bash",[350,691,692,705,712,719],{"__ignoreMap":293},[353,693,694,698,701],{"class":355,"line":356},[353,695,697],{"class":696},"sBMFI","pnpm",[353,699,700],{"class":390}," gen",[353,702,704],{"class":703},"sHwdD","        # 生成载荷，必须先跑\n",[353,706,707,709],{"class":355,"line":297},[353,708,697],{"class":696},[353,710,711],{"class":390}," generate\n",[353,713,714,716],{"class":355,"line":294},[353,715,697],{"class":696},[353,717,718],{"class":390}," analyze\n",[353,720,722,725,728,731,734,737,741],{"class":355,"line":721},4,[353,723,724],{"class":696},"npx",[353,726,727],{"class":390}," --yes",[353,729,730],{"class":390}," http-server",[353,732,733],{"class":390}," .output\u002Fpublic",[353,735,736],{"class":390}," -p",[353,738,740],{"class":739},"sbssI"," 6521",[353,742,743],{"class":390}," -c-1\n",[12,745,746],{},[18,747],{"alt":748,"src":749,"width":22},"服务器启动","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F0-npx.png",[34,751,752],{"id":752},"实测",[12,754,755],{},"先看基线。",[12,757,758,760],{},[350,759,605],{}," 什么都没导入，理论上应该最干净。实测下来它仍然下了两个文件：",[12,762,763],{},[18,764],{"alt":765,"src":766,"width":22},"clean 基线","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F1-clean.png",[12,768,769,770,772],{},"4.0 KB 和 3.7 KB，Priority 都是 ",[350,771,405],{},"。这是 Nuxt 内置的 error-404 和 error-500，被 prefetch 到了每一个页面上，七个页面一个不落。它们是 Nuxt 的固定开销，后面所有页面的数字里都包含这 7.7 KB。",[12,774,775],{},"然后看关键的那一页。",[12,777,778,780],{},[350,779,640],{}," 里，那个 200 KB 的载荷是这样导入的：",[344,782,784],{"className":346,"code":783,"language":348,"meta":293,"style":293},"async function load() {\n  const mod = await import('~\u002Flib\u002Fpayload-dynamic')\n  output.value = mod.payloadRender()\n}\n",[350,785,786,804,829,852],{"__ignoreMap":293},[353,787,788,791,794,798,801],{"class":355,"line":356},[353,789,790],{"class":359},"async",[353,792,793],{"class":359}," function",[353,795,797],{"class":796},"s2Zo4"," load",[353,799,800],{"class":363},"()",[353,802,803],{"class":363}," {\n",[353,805,806,809,812,814,816,818,820,822,825,827],{"class":355,"line":297},[353,807,808],{"class":359},"  const",[353,810,811],{"class":367}," mod",[353,813,374],{"class":363},[353,815,378],{"class":377},[353,817,381],{"class":363},[353,819,384],{"class":452},[353,821,387],{"class":363},[353,823,824],{"class":390},"~\u002Flib\u002Fpayload-dynamic",[353,826,387],{"class":363},[353,828,396],{"class":452},[353,830,831,834,837,840,842,844,846,849],{"class":355,"line":294},[353,832,833],{"class":367},"  output",[353,835,836],{"class":363},".",[353,838,839],{"class":367},"value",[353,841,374],{"class":363},[353,843,811],{"class":367},[353,845,836],{"class":363},[353,847,848],{"class":796},"payloadRender",[353,850,851],{"class":452},"()\n",[353,853,854],{"class":355,"line":721},[353,855,856],{"class":363},"}\n",[12,858,859],{},"它挂在一个按钮上。用户不点，这段代码就不会执行。",[12,861,862],{},"打开页面，什么都不点，等三秒：",[12,864,865],{},[18,866],{"alt":867,"src":868,"width":22},"零交互，178 KB 已被下走","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F4-1-await-import-prefetch.png",[12,870,871,872,875,876,879,880,875,883,406],{},"那个 178 KB 的 chunk 已经在列表里了，",[350,873,874],{},"Type"," 是 ",[350,877,878],{},"javascript","，",[350,881,882],{},"Priority",[350,884,405],{},[12,886,887,888,890],{},"我用 ",[350,889,539],{}," 的本意是「用到才下」。但页面刚一空闲，浏览器就把它下完了。",[12,892,893],{},"点击按钮，同一个文件会以另一种身份再出现一次：",[12,895,896],{},[18,897],{"alt":898,"src":899,"width":22},"点击后，同一个文件变成 High","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F4-2-await-import-prefetch.png",[12,901,902,903,906,907,875,909,879,912,914,915,406],{},"同一个文件 ",[350,904,905],{},"Dxxxxxxx.js","，这次的 ",[350,908,874],{},[350,910,911],{},"script",[350,913,882],{}," 变成 ",[350,916,917],{},"High",[12,919,920],{},"这说明 prefetch 并未替代这次加载，它只是把文件提前放进了缓存。用户真正触发时，浏览器仍会走完整的加载流程。",[12,922,923],{},[183,924,925],{},"省下的是等待，没省下的是流量。",[34,927,928],{"id":928},"异步组件也绕不开",[12,930,931,932,934],{},"那不用 ",[350,933,539],{},"，改用异步组件呢？",[344,936,938],{"className":346,"code":937,"language":348,"meta":293,"style":293},"const PayloadAsync = defineAsyncComponent(() => import('~\u002Fcomponents\u002FPayloadAsync.vue'))\n",[350,939,940],{"__ignoreMap":293},[353,941,942,944,947,949,952,954,956,959,961,963,965,968,970],{"class":355,"line":356},[353,943,360],{"class":359},[353,945,946],{"class":367}," PayloadAsync ",[353,948,459],{"class":363},[353,950,951],{"class":796}," defineAsyncComponent",[353,953,384],{"class":367},[353,955,800],{"class":363},[353,957,958],{"class":359}," =>",[353,960,381],{"class":363},[353,962,384],{"class":367},[353,964,387],{"class":363},[353,966,967],{"class":390},"~\u002Fcomponents\u002FPayloadAsync.vue",[353,969,387],{"class":363},[353,971,972],{"class":367},"))\n",[344,974,976],{"className":440,"code":975,"language":442,"meta":293,"style":293},"\u003CPayloadAsync \u002F>\n",[350,977,978],{"__ignoreMap":293},[353,979,980,982,985],{"class":355,"line":356},[353,981,449],{"class":363},[353,983,984],{"class":452},"PayloadAsync",[353,986,987],{"class":363}," \u002F>\n",[12,989,990],{},"实测：",[12,992,993],{},[18,994],{"alt":995,"src":996,"width":22},"异步组件：直接 modulepreload","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F6-async-component.png",[12,998,999,1000,875,1002,879,1004,875,1006,406],{},"178 KB，",[350,1001,874],{},[350,1003,911],{},[350,1005,882],{},[183,1007,1008],{},[350,1009,917],{},[12,1011,1012],{},"比 prefetch 更狠。它不是等网络空闲，而是和 CSS、字体一起抢带宽。我的理解是：这个组件在服务端渲染时确实被渲染了，Nuxt 判断它「首次加载就要用」，于是用最高优先级预加载，省掉客户端水合时再等一次。",[12,1014,1015,1016,1018],{},"那给它加个 ",[350,1017,684],{},"，让它不参与初次渲染会怎样？",[344,1020,1022],{"className":440,"code":1021,"language":442,"meta":293,"style":293},"\u003CPayloadAsync v-if=\"show\" \u002F>\n",[350,1023,1024],{"__ignoreMap":293},[353,1025,1026,1028,1030,1033,1035,1037,1040,1042],{"class":355,"line":356},[353,1027,449],{"class":363},[353,1029,984],{"class":452},[353,1031,1032],{"class":359}," v-if",[353,1034,459],{"class":363},[353,1036,462],{"class":363},[353,1038,1039],{"class":390},"show",[353,1041,462],{"class":363},[353,1043,987],{"class":363},[12,1045,1046],{},[18,1047],{"alt":1048,"src":1049,"width":22},"v-if：降级为 prefetch，但流量没省","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F7-1-async-component-conditional.png",[12,1051,1052,1054,1055,1057,1058,406],{},[350,1053,882],{}," 从 ",[350,1056,917],{}," 降到了 ",[350,1059,405],{},[12,1061,1062],{},"但页面总传输量还是 373 KB，和上一个页面一模一样。我没点按钮，那 178 KB 已经下完了。",[12,1064,1065],{},"点一下按钮，它才真正被用上：",[12,1067,1068],{},[18,1069],{"alt":1070,"src":1071,"width":22},"点击后才渲染","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F7-2-async-component-conditional.png",[12,1073,1074,1075,1077],{},"所以 ",[350,1076,684],{}," 只解决了「抢首次加载的带宽」，没解决「白下」。异步组件这条路，绕不开。",[34,1079,1080],{"id":1080},"三组对照",[12,1082,1083],{},"七个页面里，有三组可以两两对比。对比出来的结论比单看一页更有意思。",[1085,1086,1088],"h3",{"id":1087},"一静态导入-vs-异步组件","一、静态导入 vs 异步组件",[63,1090,1091,1104],{},[66,1092,1093],{},[69,1094,1095,1097,1100,1102],{},[72,1096,593],{},[72,1098,1099],{},"载荷",[72,1101,874],{},[72,1103,882],{},[82,1105,1106,1123],{},[69,1107,1108,1112,1115,1119],{},[87,1109,1110],{},[350,1111,615],{},[87,1113,1114],{},"178 KB",[87,1116,1117],{},[350,1118,911],{},[87,1120,1121],{},[350,1122,917],{},[69,1124,1125,1129,1131,1135],{},[87,1126,1127],{},[350,1128,663],{},[87,1130,1114],{},[87,1132,1133],{},[350,1134,911],{},[87,1136,1137],{},[350,1138,917],{},[12,1140,1141],{},[18,1142],{"alt":1143,"src":1144,"width":22},"静态导入：modulepreload","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F2-link-modulepreload.png",[12,1146,1147],{},"两者情况一样。",[12,1149,1150,1151,1153,1154,1157],{},"静态导入走 ",[350,1152,465],{}," 理所当然。问题在于后面那一行：",[183,1155,1156],{},"一个叫「异步」的组件，只要它参与了初次渲染，Nuxt 就把它当首次加载的资源处理","，「异步」这两个字等于白叫。",[1085,1159,1161],{"id":1160},"二手写的-prefetch-vs-框架注入的-prefetch","二、手写的 prefetch vs 框架注入的 prefetch",[63,1163,1164,1176],{},[66,1165,1166],{},[69,1167,1168,1170,1172,1174],{},[72,1169,593],{},[72,1171,1099],{},[72,1173,874],{},[72,1175,882],{},[82,1177,1178,1195],{},[69,1179,1180,1184,1187,1191],{},[87,1181,1182],{},[350,1183,628],{},[87,1185,1186],{},"208 KB",[87,1188,1189],{},[350,1190,878],{},[87,1192,1193],{},[350,1194,405],{},[69,1196,1197,1201,1203,1207],{},[87,1198,1199],{},[350,1200,640],{},[87,1202,1114],{},[87,1204,1205],{},[350,1206,878],{},[87,1208,1209],{},[350,1210,405],{},[12,1212,1213],{},[18,1214],{"alt":1215,"src":1216,"width":22},"手写 prefetch","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F3-link-prefetch.png",[12,1218,1219],{},"这一组验证一件事：Nuxt 注入的 prefetch 标签，和手写的有没有区别。",[12,1221,1222,1223,1225,1226,879,1228,1225,1230,1232],{},"结论是没有。两者的 ",[350,1224,874],{}," 都是 ",[350,1227,878],{},[350,1229,882],{},[350,1231,405],{},"，加载时机也一致。",[12,1234,1235,1236,1238],{},"也就是说，Nuxt 注入的这一行，与手写的 ",[350,1237,633],{}," 等价，区别只在于前者由构建过程自动完成，后者由开发者显式声明。",[1085,1240,1242],{"id":1241},"三一级动态-import-vs-条件渲染的异步组件","三、一级动态 import vs 条件渲染的异步组件",[63,1244,1245,1260],{},[66,1246,1247],{},[69,1248,1249,1251,1253,1255,1257],{},[72,1250,593],{},[72,1252,1099],{},[72,1254,874],{},[72,1256,882],{},[72,1258,1259],{},"页面总传输",[82,1261,1262,1281],{},[69,1263,1264,1268,1270,1274,1278],{},[87,1265,1266],{},[350,1267,640],{},[87,1269,1114],{},[87,1271,1272],{},[350,1273,878],{},[87,1275,1276],{},[350,1277,405],{},[87,1279,1280],{},"372 KB",[69,1282,1283,1287,1289,1293,1297],{},[87,1284,1285],{},[350,1286,676],{},[87,1288,1114],{},[87,1290,1291],{},[350,1292,878],{},[87,1294,1295],{},[350,1296,405],{},[87,1298,1299],{},"373 KB",[12,1301,1302],{},"两条路的结果一致。",[12,1304,1305,1307,1308,681,1310,1312,1313,406],{},[350,1306,539],{}," 和 ",[350,1309,668],{},[350,1311,684],{}," 的区别只在语法层面。只要被导入的模块挂在「一级」，结果都是零交互下先下载 178 KB，仅优先级为 ",[350,1314,405],{},[12,1316,1317],{},[183,1318,1319],{},"更换写法并不能规避。",[34,1321,1322],{"id":1322},"七页放在一起看",[63,1324,1325,1339],{},[66,1326,1327],{},[69,1328,1329,1331,1333,1335,1337],{},[72,1330,593],{},[72,1332,1099],{},[72,1334,874],{},[72,1336,882],{},[72,1338,1259],{},[82,1340,1341,1357,1375,1394,1412,1432,1450],{},[69,1342,1343,1347,1350,1352,1354],{},[87,1344,1345],{},[350,1346,605],{},[87,1348,1349],{},"—",[87,1351,1349],{},[87,1353,1349],{},[87,1355,1356],{},"194 KB",[69,1358,1359,1363,1365,1369,1373],{},[87,1360,1361],{},[350,1362,615],{},[87,1364,1114],{},[87,1366,1367],{},[350,1368,911],{},[87,1370,1371],{},[350,1372,917],{},[87,1374,1280],{},[69,1376,1377,1381,1383,1387,1391],{},[87,1378,1379],{},[350,1380,628],{},[87,1382,1186],{},[87,1384,1385],{},[350,1386,878],{},[87,1388,1389],{},[350,1390,405],{},[87,1392,1393],{},"402 KB",[69,1395,1396,1400,1402,1406,1410],{},[87,1397,1398],{},[350,1399,640],{},[87,1401,1114],{},[87,1403,1404],{},[350,1405,878],{},[87,1407,1408],{},[350,1409,405],{},[87,1411,1280],{},[69,1413,1414,1418,1421,1425,1429],{},[87,1415,1416],{},[350,1417,653],{},[87,1419,1420],{},"0.6 KB",[87,1422,1423],{},[350,1424,878],{},[87,1426,1427],{},[350,1428,405],{},[87,1430,1431],{},"195 KB",[69,1433,1434,1438,1440,1444,1448],{},[87,1435,1436],{},[350,1437,663],{},[87,1439,1114],{},[87,1441,1442],{},[350,1443,911],{},[87,1445,1446],{},[350,1447,917],{},[87,1449,1299],{},[69,1451,1452,1456,1458,1462,1466],{},[87,1453,1454],{},[350,1455,676],{},[87,1457,1114],{},[87,1459,1460],{},[350,1461,878],{},[87,1463,1464],{},[350,1465,405],{},[87,1467,1299],{},[12,1469,1470],{},"几点结论：",[12,1472,1473,1479,1480,406],{},[183,1474,1475,1476,1478],{},"一级 ",[350,1477,539],{}," 的懒加载不成立。"," 零交互下 178 KB 即被下载，仅优先级为 ",[350,1481,405],{},[12,1483,1484,1487],{},[183,1485,1486],{},"二级动态导入成立。"," 页面总传输 195 KB，与基线基本持平。",[12,1489,1490],{},[183,1491,1492,1494],{},[350,1493,684],{}," 只改变优先级，不改变流量。",[12,1496,1497],{},[183,1498,1499],{},"异步组件无条件渲染时，行为等同于静态导入。",[12,1501,1502,1505],{},[183,1503,1504],{},"存在固定开销"," error-404 与 error-500 两个 chunk 被 prefetch 到全部七个页面，每页 7.7 KB。",[12,1507,1508],{},"对照引言中那台 3M 带宽的机器：178 KB 约合半秒以上的等待，7.7 KB 则是每个页面都要重复支付的一次成本。",[34,1510,1511],{"id":1511},"解决方案",[12,1513,1514],{},"页面不再直接导入那个 200 KB 的模块，而是导入一个很小的中间模块，中间模块内部再去导入载荷：",[344,1516,1518],{"className":346,"code":1517,"language":348,"meta":293,"style":293},"\u002F\u002F 页面\nasync function load() {\n  const mid = await import('~\u002Flib\u002Fnested-mid')\n  output.value = await mid.loadLeaf()\n}\n",[350,1519,1520,1525,1537,1561,1582],{"__ignoreMap":293},[353,1521,1522],{"class":355,"line":356},[353,1523,1524],{"class":703},"\u002F\u002F 页面\n",[353,1526,1527,1529,1531,1533,1535],{"class":355,"line":297},[353,1528,790],{"class":359},[353,1530,793],{"class":359},[353,1532,797],{"class":796},[353,1534,800],{"class":363},[353,1536,803],{"class":363},[353,1538,1539,1541,1544,1546,1548,1550,1552,1554,1557,1559],{"class":355,"line":294},[353,1540,808],{"class":359},[353,1542,1543],{"class":367}," mid",[353,1545,374],{"class":363},[353,1547,378],{"class":377},[353,1549,381],{"class":363},[353,1551,384],{"class":452},[353,1553,387],{"class":363},[353,1555,1556],{"class":390},"~\u002Flib\u002Fnested-mid",[353,1558,387],{"class":363},[353,1560,396],{"class":452},[353,1562,1563,1565,1567,1569,1571,1573,1575,1577,1580],{"class":355,"line":721},[353,1564,833],{"class":367},[353,1566,836],{"class":363},[353,1568,839],{"class":367},[353,1570,374],{"class":363},[353,1572,378],{"class":377},[353,1574,1543],{"class":367},[353,1576,836],{"class":363},[353,1578,1579],{"class":796},"loadLeaf",[353,1581,851],{"class":452},[353,1583,1585],{"class":355,"line":1584},5,[353,1586,856],{"class":363},[344,1588,1590],{"className":346,"code":1589,"language":348,"meta":293,"style":293},"\u002F\u002F nested-mid.ts\nexport async function loadLeaf() {\n  const mod = await import('.\u002Fpayload-nested')\n  return mod.payloadRender()\n}\n",[350,1591,1592,1597,1614,1637,1650],{"__ignoreMap":293},[353,1593,1594],{"class":355,"line":356},[353,1595,1596],{"class":703},"\u002F\u002F nested-mid.ts\n",[353,1598,1599,1602,1605,1607,1610,1612],{"class":355,"line":297},[353,1600,1601],{"class":377},"export",[353,1603,1604],{"class":359}," async",[353,1606,793],{"class":359},[353,1608,1609],{"class":796}," loadLeaf",[353,1611,800],{"class":363},[353,1613,803],{"class":363},[353,1615,1616,1618,1620,1622,1624,1626,1628,1630,1633,1635],{"class":355,"line":294},[353,1617,808],{"class":359},[353,1619,811],{"class":367},[353,1621,374],{"class":363},[353,1623,378],{"class":377},[353,1625,381],{"class":363},[353,1627,384],{"class":452},[353,1629,387],{"class":363},[353,1631,1632],{"class":390},".\u002Fpayload-nested",[353,1634,387],{"class":363},[353,1636,396],{"class":452},[353,1638,1639,1642,1644,1646,1648],{"class":355,"line":721},[353,1640,1641],{"class":377},"  return",[353,1643,811],{"class":367},[353,1645,836],{"class":363},[353,1647,848],{"class":796},[353,1649,851],{"class":452},[353,1651,1652],{"class":355,"line":1584},[353,1653,856],{"class":363},[12,1655,1656],{},"同样不做任何操作，等待三秒：",[12,1658,1659],{},[18,1660],{"alt":1661,"src":1662,"width":22},"二级：那个 178 KB 不出现","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F5-1-await-import-nested.png",[12,1664,1665],{},"一级那个中间模块（0.6 KB）仍被 prefetch，但二级的 178 KB 连请求都没有发出。",[12,1667,1668],{},"点击按钮后才会加载：",[12,1670,1671],{},[18,1672],{"alt":1673,"src":1674,"width":22},"点击后才加载","\u002Fimages\u002Fnuxt-dynamic-import-prefetch\u002F5-2-await-import-nested.png",[12,1676,1677],{},"再对比页面总传输量：",[63,1679,1680,1689],{},[66,1681,1682],{},[69,1683,1684,1686],{},[72,1685,593],{},[72,1687,1688],{},"总传输",[82,1690,1691,1700,1708],{},[69,1692,1693,1698],{},[87,1694,1695,1697],{},[350,1696,605],{},"（基线）",[87,1699,1356],{},[69,1701,1702,1706],{},[87,1703,1704],{},[350,1705,653],{},[87,1707,1431],{},[69,1709,1710,1714],{},[87,1711,1712],{},[350,1713,640],{},[87,1715,1280],{},[12,1717,1718],{},"二级嵌套的页面只比基线多出 1 KB，就是那个中转模块的体积。而一级动态导入的页面，多出 178 KB。",[12,1720,1721],{},"我目前的处理方式是把体积大的模块下移到二级。中间那层转发模块很小，即使被 prefetch 影响也有限。",[34,1723,1724],{"id":1724},"关于这个问题的记录",[12,1726,1727],{},"最后我查了一下 GitHub，发现这不是新问题：",[176,1729,1730,1741,1749],{},[179,1731,1732,1737,1738,1740],{},[96,1733,1736],{"href":1734,"rel":1735},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fissues\u002F18376",[100],"#18376"," Disable ",[350,1739,497],{}," for dynamic imports（2023-01-20 提出，2026-05-05 关闭）",[179,1742,1743,1748],{},[96,1744,1747],{"href":1745,"rel":1746},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fissues\u002F14584",[100],"#14584"," optimisations for prefetching chunks（2022-08-15 提出，2026-09-06 关闭）",[179,1750,1751,1756],{},[96,1752,1755],{"href":1753,"rel":1754},"https:\u002F\u002Fgithub.com\u002Fnuxt\u002Fnuxt\u002Fpull\u002F36391",[100],"#36391"," unified client prefetch scheduler（2026-09-23 合并，目标版本 5.x）",[12,1758,1759],{},"#18376 描述的场景和本文遇到的一模一样。上游近期把客户端预取的调度统一到了一套队列（#36391），但它调整的是预取的秩序，不是「要不要预取动态 import」，是否影响本文描述的现象尚不确定，需要持续观察。",[12,1761,1762],{},"在此之前，可行的做法仍是自行处理：把大体积模块放到第二层动态 import，第一层只保留一个转发用的空壳。",[34,1764,1765],{"id":1765},"相关代码",[12,1767,1768,1769,1773,1774,1777],{},"相关代码在 ",[96,1770,1771],{"href":1771,"rel":1772},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002Fblog-code-pool",[100]," 的 ",[350,1775,1776],{},"nuxt-dynamic-import-prefetch\u002F"," 目录下。",[1779,1780,1781],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":293,"searchDepth":294,"depth":294,"links":1783},[1784,1785,1786,1787,1788,1793,1794,1795,1796],{"id":409,"depth":297,"text":409},{"id":581,"depth":297,"text":581},{"id":752,"depth":297,"text":752},{"id":928,"depth":297,"text":928},{"id":1080,"depth":297,"text":1080,"children":1789},[1790,1791,1792],{"id":1087,"depth":294,"text":1088},{"id":1160,"depth":294,"text":1161},{"id":1241,"depth":294,"text":1242},{"id":1322,"depth":297,"text":1322},{"id":1511,"depth":297,"text":1511},{"id":1724,"depth":297,"text":1724},{"id":1765,"depth":297,"text":1765},"2026-10-03","给 Nuxt 页面做首次加载减负时，发现它会在构建时给一级动态 import 注入 prefetch 标签。用户零交互，整个 chunk 就已经下走了，await import 也就失效了。这篇用七个页面的实测把这个机制拆开，并给出一个真能省下流量的写法。",{},"\u002Fposts\u002Fnuxt-dynamic-import-prefetch",{"title":319,"description":1798},"posts\u002Fnuxt-dynamic-import-prefetch",[1804,1805,1806],"Nuxt","性能优化","前端","mqDD5y_LQyuy938Ubfgm_XRIUCnM_f5SOTgkZ2qFsY8",{"id":1809,"title":1810,"body":1811,"date":2071,"description":2072,"extension":305,"meta":2073,"navigation":307,"path":2074,"seo":2075,"stem":2076,"tags":2077,"__hash__":2082},"posts\u002Fposts\u002Feasyauth-2fa-webdav-s3-backup-client.md","换完手机，GitHub 把我挡在了门外",{"type":9,"value":1812,"toc":2059},[1813,1816,1819,1822,1825,1829,1832,1835,1861,1864,1867,1870,1902,1905,1908,1912,1915,1918,1925,1932,1938,1941,1944,1947,1951,1954,1968,1975,1978,1981,1984,1987,1994,2000,2003,2010,2013,2016,2019,2056],[12,1814,1815],{},"换完手机那天，GitHub 把我挡在了门外。",[12,1817,1818],{},"那天我坐在电脑前，屏幕上弹出来的还是那行熟悉的提示——请输入两步验证代码。我掏出手机打开验证器，列表是空的，一条都没有。换机之前我以为它会跟着微软账号一起同步回来，结果并没有。中间到底卡在哪一步断的，我到现在也说不清。",[12,1820,1821],{},"先翻恢复码，没存；翻邮箱，没有；翻笔记，还是没有。最后只能走申诉：填表、等回复、再补材料，一个账号折腾了好几天才算有个说法。",[12,1823,1824],{},"那几天我一直在想一件事：我的密码一个都没丢，锁是我自己加的，可钥匙不知道被我放哪儿去了。",[34,1826,1828],{"id":1827},"那些验证器本来也没打算让你把数据拿走","那些验证器，本来也没打算让你把数据拿走",[12,1830,1831],{},"先说清楚，把验证码放在手机上没有任何问题。Microsoft Authenticator 我用了很多年，平时很顺手，它也确实尽职。",[12,1833,1834],{},"问题是，一直到出事那天我才发现，我从来没搞清楚过几件事：我的数据存在哪里、上一次同步是什么时候成功的、以及万一要用的时候，我能不能把它拿出来。",[176,1836,1837,1843,1849,1855],{},[179,1838,1839,1842],{},[183,1840,1841],{},"Google Authenticator","：同步要连 Google 的服务。在国内能不能连上、什么时候能连上，基本看运气。它可以把账号扫码迁到另一个 App，但不会给你一份能自己保管的备份文件。",[179,1844,1845,1848],{},[183,1846,1847],{},"Microsoft Authenticator","：备份锁在微软账号里，跨系统恢复限制不少——在安卓上备份的，往 iPhone 上恢复往往就不行。我这次就是栽在这儿：换完机打开，一条都没有。",[179,1850,1851,1854],{},[183,1852,1853],{},"Authy","：注册要手机号，数据在它自己的云上。想手动导出一份，它不给这个选项。",[179,1856,1857,1860],{},[183,1858,1859],{},"把 2FA 顺手塞进密码管理器","（1Password、Bitwarden 之类）：确实方便，但等于把密码和验证码放进同一个篮子。篮子漏了一次，二次验证也就白开了——它的全部意义本来就在于\"再多一道锁\"。",[12,1862,1863],{},"绕一圈你会发现，这些方案都在回答同一个问题：\"我的验证码存在谁那儿？\" 而答案基本都是\"存我这儿就行，你不用管\"。",[34,1865,1866],{"id":1866},"我想要的东西其实很朴素",[12,1868,1869],{},"列出来就五条：",[1871,1872,1873,1879,1885,1891,1897],"ol",{},[179,1874,1875,1878],{},[183,1876,1877],{},"数据存在本地","，最好能用上系统的加密存储；",[179,1880,1881,1884],{},[183,1882,1883],{},"能备份到我本来就有的地方","——坚果云、自己的 NAS、对象存储，这些我早就在用了，不想再为它单独开个账号；",[179,1886,1887,1890],{},[183,1888,1889],{},"备份必须是加密的","，网盘服务商拿到也看不懂；",[179,1892,1893,1896],{},[183,1894,1895],{},"兼容标准","，能从别家导进来，也能导出去，别再添一个孤岛；",[179,1898,1899,406],{},[183,1900,1901],{},"换手机的时候，别再让我把几十个账号一个个重新扫一遍",[12,1903,1904],{},"按这几条筛，能同时满足的其实不多：有些方案得自己搭服务、平时开着浏览器用，而我想要的只是在手机上点一下。",[12,1906,1907],{},"后来我用的是 EasyAuth。",[34,1909,1911],{"id":1910},"easyauth-是什么","EasyAuth 是什么",[12,1913,1914],{},"一句话：一个开源的 2FA 验证器 App，本地存储、离线可用，并且支持把数据加密备份到你自己的 WebDAV 或 S3 存储。",[12,1916,1917],{},"它是 Flutter 写的，Apache 2.0 协议完全开源，代码公开可审计，没有账号体系、没有遥测、没有广告，也不需要 Google 服务框架。",[12,1919,1920,1921,1924],{},"目前能直接下载安装的是 ",[183,1922,1923],{},"Android 版 APK","（GitHub \u002F Gitee 上都有）。iOS、Windows、Linux 还没有预编译版本，源码是公开的，可以自己编译。",[12,1926,1927,1928,1931],{},"算法上是 TOTP（RFC 6238）和 HOTP（RFC 4226）两种标准，兼容 Google Authenticator 那套 ",[350,1929,1930],{},"otpauth:\u002F\u002F"," 协议和迁移二维码——意味着它能跟别家互相搬家，不是又一个只能进不能出的孤岛。",[12,1933,1934],{},[18,1935],{"alt":1936,"src":1937,"width":32},"EasyAuth 主界面：口令按发行方分卡片，右侧是倒计时环","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F01-home-list.jpg",[12,1939,1940],{},"界面很朴素：顶上一行搜索框，下面是口令卡片，每张卡片三行——口令名、发行方、当前六位数字，右边一圈倒计时。没有花活，也没有让我盯着看的动画。",[34,1942,1943],{"id":1943},"它把备份这件事做对了",[12,1945,1946],{},"如果只让我说一个推荐理由，就是备份。",[1085,1948,1950],{"id":1949},"备份存哪儿你说了算","备份存哪儿，你说了算",[12,1952,1953],{},"支持两类：",[176,1955,1956,1962],{},[179,1957,1958,1961],{},[183,1959,1960],{},"WebDAV","：坚果云、Nextcloud，以及群晖、威联通这些自建 NAS 基本都自带；",[179,1963,1964,1967],{},[183,1965,1966],{},"S3 兼容","：AWS S3、阿里云 OSS、腾讯云 COS、七牛云、MinIO、Cloudflare R2 这类对象存储。",[12,1969,1970],{},[18,1971],{"alt":1972,"src":1973,"width":1974},"备份参数配置","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F02-03-backup.jpg",750,[12,1976,1977],{},"关键在于\"你自己的\"这四个字：填的是你自己服务器的地址、你自己的密钥，备份文件进的是你自己的空间。哪天不想用了，文件也还在你自己的空间里，不会因为某个服务关停就跟着消失。",[1085,1979,1980],{"id":1980},"备份本身是加密的",[12,1982,1983],{},"备份文件用 AES-256-GCM 加密，密钥由你设置的备份密码经 PBKDF2-HMAC-SHA256 迭代 60 万次派生。换句话说，你的网盘账号就算被别人拿到了，他下载走那个 zip 也只是一堆乱码。",[1085,1985,1986],{"id":1986},"多版本可回退",[12,1988,1989,1990,1993],{},"备份文件名带时间戳，形如 ",[350,1991,1992],{},"backup_20260527_120413.zip","，默认在远端保留最近 10 份，超出的自动清理。也可以在 App 里直接看到远端有哪些备份、手动删掉不要的，不用专门登录服务器去收拾。",[12,1995,1996],{},[18,1997],{"alt":1998,"src":1999,"width":1974},"管理远端备份：直接在 App 里查看和删除","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F04-05-backup.jpg",[1085,2001,2002],{"id":2002},"恢复不会手滑",[12,2004,2005,2006,2009],{},"恢复是覆盖式的，所以它一定会先弹一次确认。密码错了、或者备份文件损坏，它会直接报错，",[183,2007,2008],{},"不会","动你已经存在的数据。这个细节挺重要——恢复本来就是出事的时候才会做的事，那个时刻最不该再出岔子。",[34,2011,2012],{"id":2012},"说在后面",[12,2014,2015],{},"2FA 的意义本来就是把钥匙多放一把在自己手里。既然如此，这把钥匙最好真的在自己手里。",[12,2017,2018],{},"对了，还得交代一句：EasyAuth 是我自己写的，起因就是开头那件事。它完全开源，用得上的话自取：",[176,2020,2021,2028,2035,2042,2049],{},[179,2022,2023,2024],{},"官网：",[96,2025,2026],{"href":2026,"rel":2027},"https:\u002F\u002Feasyauth.easydebug.net\u002F",[100],[179,2029,2030,2031],{},"GitHub 仓库：",[96,2032,2033],{"href":2033,"rel":2034},"https:\u002F\u002Fgithub.com\u002FEasyDebug-NET\u002FEasyAuth",[100],[179,2036,2037,2038],{},"GitHub 下载：",[96,2039,2040],{"href":2040,"rel":2041},"https:\u002F\u002Fgithub.com\u002FEasyDebug-NET\u002FEasyAuth\u002Freleases\u002Flatest",[100],[179,2043,2044,2045],{},"Gitee 仓库：",[96,2046,2047],{"href":2047,"rel":2048},"https:\u002F\u002Fgitee.com\u002FEasyDebug-NET\u002FEasyAuth",[100],[179,2050,2051,2052],{},"Gitee 下载：",[96,2053,2054],{"href":2054,"rel":2055},"https:\u002F\u002Fgitee.com\u002FEasyDebug-NET\u002FEasyAuth\u002Freleases\u002Flatest",[100],[12,2057,2058],{},"有问题欢迎在仓库里提 Issue。",{"title":293,"searchDepth":294,"depth":294,"links":2060},[2061,2062,2063,2064,2070],{"id":1827,"depth":297,"text":1828},{"id":1866,"depth":297,"text":1866},{"id":1910,"depth":297,"text":1911},{"id":1943,"depth":297,"text":1943,"children":2065},[2066,2067,2068,2069],{"id":1949,"depth":294,"text":1950},{"id":1980,"depth":294,"text":1980},{"id":1986,"depth":294,"text":1986},{"id":2002,"depth":294,"text":2002},{"id":2012,"depth":297,"text":2012},"2026-09-16","换完手机，验证器的备份没把数据带回来，验证码一条没剩，我被自己的 GitHub 挡在门外好几天。这篇讲清 2FA 的备份困境，以及我最后换上的开源方案 EasyAuth。",{},"\u002Fposts\u002Feasyauth-2fa-webdav-s3-backup-client",{"title":1810,"description":2072},"posts\u002Feasyauth-2fa-webdav-s3-backup-client",[2078,2079,2080,2081],"2FA","安全","开源","工具","H1ikHm1mlGKvt9T3Yc6ujXWITzfPwDp8GYNmVpwLD74",{"id":2084,"title":2085,"body":2086,"date":2462,"description":2463,"extension":305,"meta":2464,"navigation":307,"path":2465,"seo":2466,"stem":2467,"tags":2468,"__hash__":2472},"posts\u002Fposts\u002Fcentos7-firewalld-common-commands.md","CentOS7 Firewalld 防火墙常用命令",{"type":9,"value":2087,"toc":2449},[2088,2091,2107,2110,2124,2127,2141,2144,2158,2161,2175,2179,2212,2215,2251,2254,2388,2392,2414,2417,2431,2434,2446],[34,2089,2090],{"id":2090},"开启防火墙",[344,2092,2094],{"className":687,"code":2093,"language":689,"meta":293,"style":293},"systemctl start firewalld.service\n",[350,2095,2096],{"__ignoreMap":293},[353,2097,2098,2101,2104],{"class":355,"line":356},[353,2099,2100],{"class":696},"systemctl",[353,2102,2103],{"class":390}," start",[353,2105,2106],{"class":390}," firewalld.service\n",[34,2108,2109],{"id":2109},"关闭防火墙",[344,2111,2113],{"className":687,"code":2112,"language":689,"meta":293,"style":293},"systemctl stop firewalld.service\n",[350,2114,2115],{"__ignoreMap":293},[353,2116,2117,2119,2122],{"class":355,"line":356},[353,2118,2100],{"class":696},[353,2120,2121],{"class":390}," stop",[353,2123,2106],{"class":390},[34,2125,2126],{"id":2126},"查看防火墙状态",[344,2128,2130],{"className":687,"code":2129,"language":689,"meta":293,"style":293},"systemctl status firewalld.service\n",[350,2131,2132],{"__ignoreMap":293},[353,2133,2134,2136,2139],{"class":355,"line":356},[353,2135,2100],{"class":696},[353,2137,2138],{"class":390}," status",[353,2140,2106],{"class":390},[34,2142,2143],{"id":2143},"开启开机启动防火墙",[344,2145,2147],{"className":687,"code":2146,"language":689,"meta":293,"style":293},"systemctl enable firewalld.service\n",[350,2148,2149],{"__ignoreMap":293},[353,2150,2151,2153,2156],{"class":355,"line":356},[353,2152,2100],{"class":696},[353,2154,2155],{"class":390}," enable",[353,2157,2106],{"class":390},[34,2159,2160],{"id":2160},"关闭开机启动防火墙",[344,2162,2164],{"className":687,"code":2163,"language":689,"meta":293,"style":293},"systemctl disable firewalld.service\n",[350,2165,2166],{"__ignoreMap":293},[353,2167,2168,2170,2173],{"class":355,"line":356},[353,2169,2100],{"class":696},[353,2171,2172],{"class":390}," disable",[353,2174,2106],{"class":390},[34,2176,2178],{"id":2177},"开启某个端口80","开启某个端口（80）",[344,2180,2182],{"className":687,"code":2181,"language":689,"meta":293,"style":293},"firewall-cmd --zone=public --add-port=80\u002Ftcp --permanent   \u002F\u002F永久\nfirewall-cmd --zone=public --add-port=80\u002Ftcp               \u002F\u002F临时\n",[350,2183,2184,2201],{"__ignoreMap":293},[353,2185,2186,2189,2192,2195,2198],{"class":355,"line":356},[353,2187,2188],{"class":696},"firewall-cmd",[353,2190,2191],{"class":390}," --zone=public",[353,2193,2194],{"class":390}," --add-port=80\u002Ftcp",[353,2196,2197],{"class":390}," --permanent",[353,2199,2200],{"class":390},"   \u002F\u002F永久\n",[353,2202,2203,2205,2207,2209],{"class":355,"line":297},[353,2204,2188],{"class":696},[353,2206,2191],{"class":390},[353,2208,2194],{"class":390},[353,2210,2211],{"class":390},"               \u002F\u002F临时\n",[34,2213,2214],{"id":2214},"端口转发",[344,2216,2218],{"className":687,"code":2217,"language":689,"meta":293,"style":293},"firewall-cmd --zone=public --add-masquerade --permanent    \u002F\u002F打开IP地址伪装\n\u002F\u002F将8080转发到80\nfirewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080 --permanent\n",[350,2219,2220,2234,2239],{"__ignoreMap":293},[353,2221,2222,2224,2226,2229,2231],{"class":355,"line":356},[353,2223,2188],{"class":696},[353,2225,2191],{"class":390},[353,2227,2228],{"class":390}," --add-masquerade",[353,2230,2197],{"class":390},[353,2232,2233],{"class":390},"    \u002F\u002F打开IP地址伪装\n",[353,2235,2236],{"class":355,"line":297},[353,2237,2238],{"class":696},"\u002F\u002F将8080转发到80\n",[353,2240,2241,2243,2245,2248],{"class":355,"line":294},[353,2242,2188],{"class":696},[353,2244,2191],{"class":390},[353,2246,2247],{"class":390}," --add-forward-port=port=80:proto=tcp:toport=8080",[353,2249,2250],{"class":390}," --permanent\n",[34,2252,2253],{"id":2253},"创建黑名单",[344,2255,2257],{"className":687,"code":2256,"language":689,"meta":293,"style":293},"\u002F\u002F创建blacklist ipset\nfirewall-cmd --permanent --zone=public --new-ipset=blacklist --type=hash:ip\n\u002F\u002F封禁 blacklist\nfirewall-cmd --permanent --zone=public --add-rich-rule='rule source ipset=blacklist drop'\n\u002F\u002F查看 blacklist\nfirewall-cmd --ipset=blacklist --get-entries\n\u002F\u002F添加IP到黑名单\nfirewall-cmd --permanent --zone=public --ipset=blacklist --add-entry=212.237.51.36\nfirewall-cmd --permanent --zone=public --ipset=blacklist --add-entry=188.226.191.66\nfirewall-cmd --permanent --zone=public --ipset=blacklist --add-entry=80.211.137.182\nfirewall-cmd --permanent --zone=public --ipset=blacklist --add-entry=60.191.66.226\n",[350,2258,2259,2267,2281,2289,2308,2315,2326,2332,2346,2360,2374],{"__ignoreMap":293},[353,2260,2261,2264],{"class":355,"line":356},[353,2262,2263],{"class":696},"\u002F\u002F创建blacklist",[353,2265,2266],{"class":390}," ipset\n",[353,2268,2269,2271,2273,2275,2278],{"class":355,"line":297},[353,2270,2188],{"class":696},[353,2272,2197],{"class":390},[353,2274,2191],{"class":390},[353,2276,2277],{"class":390}," --new-ipset=blacklist",[353,2279,2280],{"class":390}," --type=hash:ip\n",[353,2282,2283,2286],{"class":355,"line":294},[353,2284,2285],{"class":696},"\u002F\u002F封禁",[353,2287,2288],{"class":390}," blacklist\n",[353,2290,2291,2293,2295,2297,2300,2302,2305],{"class":355,"line":721},[353,2292,2188],{"class":696},[353,2294,2197],{"class":390},[353,2296,2191],{"class":390},[353,2298,2299],{"class":390}," --add-rich-rule=",[353,2301,387],{"class":363},[353,2303,2304],{"class":390},"rule source ipset=blacklist drop",[353,2306,2307],{"class":363},"'\n",[353,2309,2310,2313],{"class":355,"line":1584},[353,2311,2312],{"class":696},"\u002F\u002F查看",[353,2314,2288],{"class":390},[353,2316,2318,2320,2323],{"class":355,"line":2317},6,[353,2319,2188],{"class":696},[353,2321,2322],{"class":390}," --ipset=blacklist",[353,2324,2325],{"class":390}," --get-entries\n",[353,2327,2329],{"class":355,"line":2328},7,[353,2330,2331],{"class":696},"\u002F\u002F添加IP到黑名单\n",[353,2333,2335,2337,2339,2341,2343],{"class":355,"line":2334},8,[353,2336,2188],{"class":696},[353,2338,2197],{"class":390},[353,2340,2191],{"class":390},[353,2342,2322],{"class":390},[353,2344,2345],{"class":390}," --add-entry=212.237.51.36\n",[353,2347,2349,2351,2353,2355,2357],{"class":355,"line":2348},9,[353,2350,2188],{"class":696},[353,2352,2197],{"class":390},[353,2354,2191],{"class":390},[353,2356,2322],{"class":390},[353,2358,2359],{"class":390}," --add-entry=188.226.191.66\n",[353,2361,2363,2365,2367,2369,2371],{"class":355,"line":2362},10,[353,2364,2188],{"class":696},[353,2366,2197],{"class":390},[353,2368,2191],{"class":390},[353,2370,2322],{"class":390},[353,2372,2373],{"class":390}," --add-entry=80.211.137.182\n",[353,2375,2377,2379,2381,2383,2385],{"class":355,"line":2376},11,[353,2378,2188],{"class":696},[353,2380,2197],{"class":390},[353,2382,2191],{"class":390},[353,2384,2322],{"class":390},[353,2386,2387],{"class":390}," --add-entry=60.191.66.226\n",[34,2389,2391],{"id":2390},"禁止被-ping丢弃-icmp-包","禁止被 PING（丢弃 ICMP 包）",[344,2393,2395],{"className":687,"code":2394,"language":689,"meta":293,"style":293},"firewall-cmd --permanent --zone=public --add-rich-rule='rule protocol value=icmp drop'  \n",[350,2396,2397],{"__ignoreMap":293},[353,2398,2399,2401,2403,2405,2407,2409,2412],{"class":355,"line":356},[353,2400,2188],{"class":696},[353,2402,2197],{"class":390},[353,2404,2191],{"class":390},[353,2406,2299],{"class":390},[353,2408,387],{"class":363},[353,2410,2411],{"class":390},"rule protocol value=icmp drop",[353,2413,2307],{"class":363},[34,2415,2416],{"id":2416},"查看所有规则",[344,2418,2420],{"className":687,"code":2419,"language":689,"meta":293,"style":293},"firewall-cmd --zone=public --list-all\n",[350,2421,2422],{"__ignoreMap":293},[353,2423,2424,2426,2428],{"class":355,"line":356},[353,2425,2188],{"class":696},[353,2427,2191],{"class":390},[353,2429,2430],{"class":390}," --list-all\n",[34,2432,2433],{"id":2433},"重载防火墙配置",[344,2435,2437],{"className":687,"code":2436,"language":689,"meta":293,"style":293},"firewall-cmd --reload\n",[350,2438,2439],{"__ignoreMap":293},[353,2440,2441,2443],{"class":355,"line":356},[353,2442,2188],{"class":696},[353,2444,2445],{"class":390}," --reload\n",[1779,2447,2448],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}",{"title":293,"searchDepth":294,"depth":294,"links":2450},[2451,2452,2453,2454,2455,2456,2457,2458,2459,2460,2461],{"id":2090,"depth":297,"text":2090},{"id":2109,"depth":297,"text":2109},{"id":2126,"depth":297,"text":2126},{"id":2143,"depth":297,"text":2143},{"id":2160,"depth":297,"text":2160},{"id":2177,"depth":297,"text":2178},{"id":2214,"depth":297,"text":2214},{"id":2253,"depth":297,"text":2253},{"id":2390,"depth":297,"text":2391},{"id":2416,"depth":297,"text":2416},{"id":2433,"depth":297,"text":2433},"2025-01-24","firewalld 的日常操作速查：开关服务、放行端口、端口转发、ipset 黑名单、丢弃 ICMP、重载配置。",{},"\u002Fposts\u002Fcentos7-firewalld-common-commands",{"title":2085,"description":2463},"posts\u002Fcentos7-firewalld-common-commands",[2469,2470,2471],"CentOS","运维","防火墙","XjNJknbfYQqHxi8T6AI6ILwW7bCMzps4rKUK1ej2haI",{"id":2474,"title":2475,"body":2476,"date":3082,"description":3083,"extension":305,"meta":3084,"navigation":307,"path":3085,"seo":3086,"stem":3087,"tags":3088,"__hash__":3093},"posts\u002Fposts\u002Fdelayq-redis-delay-queue.md","DelayQ：用 Redis 和数据库做一个延时队列",{"type":9,"value":2477,"toc":3068},[2478,2481,2484,2487,2490,2493,2504,2507,2510,2513,2516,2522,2525,2531,2534,2560,2563,2567,2570,2576,2594,2597,2601,2616,2620,2626,2629,2671,2674,2677,2683,2686,2689,2692,2698,2760,2770,2775,2784,2787,2806,2816,2819,2826,2834,2837,2960,2963,3004,3010,3017,3021,3024,3044,3047,3050,3059,3062,3065],[12,2479,2480],{},"业务里总有一类需求，叫“过一会儿再做”。",[12,2482,2483],{},"订单创建后 30 分钟没付款就自动关单；下单 15 分钟后推一条提醒；接口调失败了，等 5 分钟再重试一次；会员到期前三天发一封续费通知。",[12,2485,2486],{},"这类需求拆开看，目标都很朴素：到点执行、失败了要能重试、最后还得看得见状态。难点从来不在“延”，而在“时”—— 谁来记着这件事，以及进程重启之后它还记得吗。",[12,2488,2489],{},"DelayQ 就是我为这件事写的一个中间件。",[34,2491,2492],{"id":2492},"先说为什么不用现成的",[12,2494,2495,2496,2499,2500,2503],{},"最省事的做法是在业务代码里 ",[350,2497,2498],{},"Thread.sleep()","，或者丢给 ",[350,2501,2502],{},"ScheduledExecutorService","。单机跑个小脚本没问题，可它撑不住两件事：进程一重启，内存里的任务就全没了；多起一个实例，两边各算各的。",[12,2505,2506],{},"换成定时任务扫库呢？那得先回答两个问题：多久扫一次 —— 扫得越勤精度越高、数据库压力也越大；以及怎么保证几个实例不会同时抢到同一个任务。这两个问题不难，但每次都要重新想一遍。",[12,2508,2509],{},"那上 MQ 呢？RabbitMQ 用 TTL + 死信队列能做延时，RocketMQ 有自带的延时消息。都是成熟方案，但它们的延时级别往往是固定的几档，而且通常还附带一整套运维成本。我需要的是“任意秒数 + 到点调一个 HTTP 接口”，为这一件事养一个 MQ，不太划算。",[12,2511,2512],{},"DelayQ 的设计参考了有赞延迟队列的思路：把“任务的元信息”和“待触发的时间线”拆开存，中间用一条扫描线连接。",[34,2514,2515],{"id":2515},"它是什么",[12,2517,2518,2519],{},"一句话：",[183,2520,2521],{},"基于 Redis 和数据库的延时队列中间件，Java 开发，到点之后去调用一个你指定的 RESTful 接口。",[12,2523,2524],{},"跑起来之后是这样的：",[12,2526,2527],{},[18,2528],{"alt":2529,"src":2530},"DelayQ 架构：Job Pool 与 Delay Bucket 在 Redis，Timer 和 Runner 是两个 Java 线程池","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Farchitecture.png",[12,2532,2533],{},"四块职责：",[1871,2535,2536,2542,2548,2554],{},[179,2537,2538,2541],{},[183,2539,2540],{},"Job Pool"," —— 存放所有 Job 的元信息，落在 Redis Hash 和数据库里；",[179,2543,2544,2547],{},[183,2545,2546],{},"Delay Bucket"," —— 十组以时间为维度的有序队列（Redis ZSet），按 Job Id 判定存进哪个 Bucket，里面只放 Job Id；",[179,2549,2550,2553],{},[183,2551,2552],{},"Timer"," —— 实时扫描各个 Bucket，把 delay 时间已经到期的 Job 丢进对应的 Ready Queue；",[179,2555,2556,2559],{},[183,2557,2558],{},"Ready Queue"," —— 按任务类型（Topic）执行，执行完把任务状态回写进 Job Pool。它对应架构图右侧那个 Runner。",[12,2561,2562],{},"这里有个刻意的分工：用 Redis ZSet 存时间线，“找下一个该执行的任务”就是一次有序查询，不用把整个队列翻一遍；而真正的任务体（要调的 URL、header、body）放在 Job Pool 里，Bucket 里只留一个 Id。高频变动的那个结构因此始终很轻。",[34,2564,2566],{"id":2565},"它不假装自己是通用-mq","它不假装自己是通用 MQ",[12,2568,2569],{},"先把边界说清楚，省得你跑起来才发现不对路。",[12,2571,2572,2573],{},"DelayQ 只做一件事：",[183,2574,2575],{},"到点了，替你去调一个 HTTP 接口。",[176,2577,2578,2585,2588,2591],{},[179,2579,2580,2581,2584],{},"目前",[183,2582,2583],{},"只支持 Post 请求","，其他请求方式还在计划里；",[179,2586,2587],{},"数据库是用 PostgreSQL 开发的，理论上兼容 Oracle、MySQL、MariaDB，但这个“理论上”需要你自己验一遍；",[179,2589,2590],{},"它依赖 Redis 和一个数据库，不是一个零依赖的独立进程；",[179,2592,2593],{},"它不做消息的广播、分区、顺序保证，那些是 MQ 的活儿。",[34,2595,2596],{"id":2596},"三个真正用得上的细节",[1085,2598,2600],{"id":2599},"delay-和-ttr","delay 和 ttr",[12,2602,2603,2604,2607,2608,2611,2612,2615],{},"创建任务时有三个参数：",[350,2605,2606],{},"topic"," 是任务类型，",[350,2609,2610],{},"delay"," 是从现在起等多少秒再执行，",[350,2613,2614],{},"ttr"," 是超时时间，单位都是秒。",[1085,2617,2619],{"id":2618},"passrule怎么判断成功了","passrule：怎么判断“成功了”",[12,2621,2622,2623,406],{},"调远端接口最麻烦的是“它到底成没成”。HTTP 200 不代表业务成功，返回体里可能明明白白写着 ",[350,2624,2625],{},"\"code\": 0",[12,2627,2628],{},"DelayQ 的做法是让你给一条通过规则：",[344,2630,2634],{"className":2631,"code":2632,"language":2633,"meta":293,"style":293},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"passrule\": { \"code\": \"1\" }\n","json",[350,2635,2636],{"__ignoreMap":293},[353,2637,2638,2640,2643,2645,2648,2651,2654,2656,2658,2661,2663,2666,2668],{"class":355,"line":356},[353,2639,462],{"class":363},[353,2641,2642],{"class":390},"passrule",[353,2644,462],{"class":363},[353,2646,2647],{"class":367},": ",[353,2649,2650],{"class":363},"{",[353,2652,2653],{"class":363}," \"",[353,2655,350],{"class":359},[353,2657,462],{"class":363},[353,2659,2660],{"class":363},":",[353,2662,2653],{"class":363},[353,2664,2665],{"class":390},"1",[353,2667,462],{"class":363},[353,2669,2670],{"class":363}," }\n",[12,2672,2673],{},"它拿远端服务返回的报文去比这条规则，对上了才算任务成功。比只看 HTTP 状态码靠谱得多 —— 任务状态是 success 还是 error，得由业务结果说了算。",[1085,2675,2676],{"id":2676},"任务是看得见的",[12,2678,2679],{},[18,2680],{"alt":2681,"src":2682},"任务列表：ID、Job 类型、延迟时间、超时时间、状态、预计执行时间、创建时间","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Ftask-list.png",[12,2684,2685],{},"列表页把每个 Job 的类型、delay、ttr、状态（success \u002F error）、预计执行时间和创建时间都摆了出来，顶部可以按 ID、Job 类型、状态筛选。排查的时候不至于去翻日志猜 —— 这一点在我自己的使用里比想象中重要。",[34,2687,2688],{"id":2688},"跑起来",[12,2690,2691],{},"环境只要三样：Java 1.8+、Redis、一个数据库。",[12,2693,2694,2697],{},[183,2695,2696],{},"1. 建表。"," 仓库里给了 PostgreSQL 和 Oracle 两份 DDL，PostgreSQL 这份是：",[344,2699,2703],{"className":2700,"code":2701,"language":2702,"meta":293,"style":293},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE TABLE tb_delayq_job (\n    id int8 NOT NULL,\n    topic varchar(50) NULL,\n    delay int4 NULL,\n    ttr int4 NULL,\n    body varchar(1000) NULL,\n    status varchar(10) NULL,\n    execution_time int8 NULL,\n    create_time int8 NULL,\n    CONSTRAINT pk_tb_delayq_job_id PRIMARY KEY (id)\n);\n","sql",[350,2704,2705,2710,2715,2720,2725,2730,2735,2740,2745,2750,2755],{"__ignoreMap":293},[353,2706,2707],{"class":355,"line":356},[353,2708,2709],{},"CREATE TABLE tb_delayq_job (\n",[353,2711,2712],{"class":355,"line":297},[353,2713,2714],{},"    id int8 NOT NULL,\n",[353,2716,2717],{"class":355,"line":294},[353,2718,2719],{},"    topic varchar(50) NULL,\n",[353,2721,2722],{"class":355,"line":721},[353,2723,2724],{},"    delay int4 NULL,\n",[353,2726,2727],{"class":355,"line":1584},[353,2728,2729],{},"    ttr int4 NULL,\n",[353,2731,2732],{"class":355,"line":2317},[353,2733,2734],{},"    body varchar(1000) NULL,\n",[353,2736,2737],{"class":355,"line":2328},[353,2738,2739],{},"    status varchar(10) NULL,\n",[353,2741,2742],{"class":355,"line":2334},[353,2743,2744],{},"    execution_time int8 NULL,\n",[353,2746,2747],{"class":355,"line":2348},[353,2748,2749],{},"    create_time int8 NULL,\n",[353,2751,2752],{"class":355,"line":2362},[353,2753,2754],{},"    CONSTRAINT pk_tb_delayq_job_id PRIMARY KEY (id)\n",[353,2756,2757],{"class":355,"line":2376},[353,2758,2759],{},");\n",[12,2761,2762,2765,2766,2769],{},[183,2763,2764],{},"2. 改配置。"," 编辑 ",[350,2767,2768],{},"application-dev.yml","，填上 Redis 和数据库的连接信息。",[12,2771,2772],{},[183,2773,2774],{},"3. 启动。",[344,2776,2778],{"className":687,"code":2777,"language":689,"meta":293,"style":293},".\u002Fstartup.sh\n",[350,2779,2780],{"__ignoreMap":293},[353,2781,2782],{"class":355,"line":356},[353,2783,2777],{"class":696},[12,2785,2786],{},"或者直接跑 jar：",[344,2788,2790],{"className":687,"code":2789,"language":689,"meta":293,"style":293},"java -jar DelayQ.jar --spring.profiles.active=dev\n",[350,2791,2792],{"__ignoreMap":293},[353,2793,2794,2797,2800,2803],{"class":355,"line":356},[353,2795,2796],{"class":696},"java",[353,2798,2799],{"class":390}," -jar",[353,2801,2802],{"class":390}," DelayQ.jar",[353,2804,2805],{"class":390}," --spring.profiles.active=dev\n",[12,2807,2808,2811,2812,2815],{},[183,2809,2810],{},"4. 打开界面。"," 访问 ",[350,2813,2814],{},"http:\u002F\u002Flocalhost:16996\u002Fdelay-q\u002Findex","，就是上面那个任务列表。",[34,2817,2818],{"id":2818},"加一个任务",[12,2820,2821,2822,2825],{},"向 ",[350,2823,2824],{},"add"," 接口发一个 Post，查询参数就是前面说的三个：",[344,2827,2832],{"className":2828,"code":2830,"language":2831},[2829],"language-text","POST http:\u002F\u002Flocalhost:16996\u002Fdelay-q\u002Fadd?topic=HttpPostTask&delay=60&ttr=10\n","text",[350,2833,2830],{"__ignoreMap":293},[12,2835,2836],{},"请求体里写清楚“到点之后要干什么”：",[344,2838,2840],{"className":2631,"code":2839,"language":2633,"meta":293,"style":293},"{\n  \"url\": \"http:\u002F\u002F172.16.6.202:16996\u002Fdelay-q\u002Fadd?topic=PrintTask&delay=10&ttr=10\",\n  \"headers\": {\n    \"Content-Type\": \"application\u002Fjson\"\n  },\n  \"body\": \"\",\n  \"passrule\": {\n    \"code\": \"1\"\n  }\n}\n",[350,2841,2842,2847,2869,2882,2902,2907,2923,2935,2951,2956],{"__ignoreMap":293},[353,2843,2844],{"class":355,"line":356},[353,2845,2846],{"class":363},"{\n",[353,2848,2849,2852,2855,2857,2859,2861,2864,2866],{"class":355,"line":297},[353,2850,2851],{"class":363},"  \"",[353,2853,2854],{"class":359},"url",[353,2856,462],{"class":363},[353,2858,2660],{"class":363},[353,2860,2653],{"class":363},[353,2862,2863],{"class":390},"http:\u002F\u002F172.16.6.202:16996\u002Fdelay-q\u002Fadd?topic=PrintTask&delay=10&ttr=10",[353,2865,462],{"class":363},[353,2867,2868],{"class":363},",\n",[353,2870,2871,2873,2876,2878,2880],{"class":355,"line":294},[353,2872,2851],{"class":363},[353,2874,2875],{"class":359},"headers",[353,2877,462],{"class":363},[353,2879,2660],{"class":363},[353,2881,803],{"class":363},[353,2883,2884,2887,2890,2892,2894,2896,2899],{"class":355,"line":721},[353,2885,2886],{"class":363},"    \"",[353,2888,2889],{"class":696},"Content-Type",[353,2891,462],{"class":363},[353,2893,2660],{"class":363},[353,2895,2653],{"class":363},[353,2897,2898],{"class":390},"application\u002Fjson",[353,2900,2901],{"class":363},"\"\n",[353,2903,2904],{"class":355,"line":1584},[353,2905,2906],{"class":363},"  },\n",[353,2908,2909,2911,2914,2916,2918,2921],{"class":355,"line":2317},[353,2910,2851],{"class":363},[353,2912,2913],{"class":359},"body",[353,2915,462],{"class":363},[353,2917,2660],{"class":363},[353,2919,2920],{"class":363}," \"\"",[353,2922,2868],{"class":363},[353,2924,2925,2927,2929,2931,2933],{"class":355,"line":2328},[353,2926,2851],{"class":363},[353,2928,2642],{"class":359},[353,2930,462],{"class":363},[353,2932,2660],{"class":363},[353,2934,803],{"class":363},[353,2936,2937,2939,2941,2943,2945,2947,2949],{"class":355,"line":2334},[353,2938,2886],{"class":363},[353,2940,350],{"class":696},[353,2942,462],{"class":363},[353,2944,2660],{"class":363},[353,2946,2653],{"class":363},[353,2948,2665],{"class":390},[353,2950,2901],{"class":363},[353,2952,2953],{"class":355,"line":2348},[353,2954,2955],{"class":363},"  }\n",[353,2957,2958],{"class":355,"line":2362},[353,2959,856],{"class":363},[12,2961,2962],{},"参数逐个说：",[176,2964,2965,2974,2979,2984,2989,2994,2999],{},[179,2966,2967,2969,2970,2973],{},[350,2968,2606],{},"（必填）：任务类型，",[350,2971,2972],{},"HttpPostTask"," 是内置的那一种；",[179,2975,2976,2978],{},[350,2977,2610],{},"（必填）：等待秒数；",[179,2980,2981,2983],{},[350,2982,2614],{},"（必填）：超时秒数；",[179,2985,2986,2988],{},[350,2987,2854],{},"（必填）：远端服务地址；",[179,2990,2991,2993],{},[350,2992,2875],{},"（可选）：请求头；",[179,2995,2996,2998],{},[350,2997,2913],{},"（可选）：POST 的报文；",[179,3000,3001,3003],{},[350,3002,2642],{},"（可选）：上面那条通过规则。",[12,3005,3006],{},[18,3007],{"alt":3008,"src":3009},"用 Postman 发一个 add 请求，响应里的 data 就是新 Job 的 ID","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Fpostman-add-task.png",[12,3011,3012,3013,3016],{},"返回体里的 ",[350,3014,3015],{},"data"," 就是新建 Job 的 ID，拿它去列表页就能查到这条任务后面执行成什么样了。",[34,3018,3020],{"id":3019},"现在的样子和下一步","现在的样子，和下一步",[12,3022,3023],{},"它还算年轻，有几件事我自己清楚没做好，一并写在这里：",[1871,3025,3026,3032,3038],{},[179,3027,3028,3031],{},[183,3029,3030],{},"多实例部署时，多个 Timer 会同时扫描。"," 同一批 Bucket 被重复扫，白白消耗资源 —— 这是最该先解决的问题；",[179,3033,3034,3037],{},[183,3035,3036],{},"只支持 Post。"," 后续想加上更多请求方式；",[179,3039,3040,3043],{},[183,3041,3042],{},"界面功能还薄。"," 列表、筛选、删除够用，但离完善还有距离。",[34,3045,3046],{"id":3046},"最后",[12,3048,3049],{},"仓库在这里，Apache License 2.0，代码随便看、随便用：",[176,3051,3052],{},[179,3053,3054,3055],{},"Gitee：",[96,3056,3057],{"href":3057,"rel":3058},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002FDelayQ",[100],[12,3060,3061],{},"如果你也在纠结“这几万个到点要执行的任务该放哪儿”，可以先 clone 下来跑一遍 —— 建一张表、连上 Redis，就能看到任务在列表里一条条变成 success。",[12,3063,3064],{},"用着有问题或者有想法，欢迎直接提 Issue。",[1779,3066,3067],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":293,"searchDepth":294,"depth":294,"links":3069},[3070,3071,3072,3073,3078,3079,3080,3081],{"id":2492,"depth":297,"text":2492},{"id":2515,"depth":297,"text":2515},{"id":2565,"depth":297,"text":2566},{"id":2596,"depth":297,"text":2596,"children":3074},[3075,3076,3077],{"id":2599,"depth":294,"text":2600},{"id":2618,"depth":294,"text":2619},{"id":2676,"depth":294,"text":2676},{"id":2688,"depth":297,"text":2688},{"id":2818,"depth":297,"text":2818},{"id":3019,"depth":297,"text":3020},{"id":3046,"depth":297,"text":3046},"2022-02-17","一个基于 Redis 和数据库的延时队列中间件，Java 开发，到点之后替你调用一个 RESTful 接口。这篇讲清它的四块架构、设计取舍、已知短板，以及怎么跑起来。",{},"\u002Fposts\u002Fdelayq-redis-delay-queue",{"title":2475,"description":3083},"posts\u002Fdelayq-redis-delay-queue",[3089,3090,3091,2080,3092],"Java","Redis","消息队列","中间件","KyPhn29RAViYkNckjQzeXVv3VUQrM_4dQMlhMd249ZA",{"id":3095,"title":3096,"body":3097,"date":3309,"description":3310,"extension":305,"meta":3311,"navigation":307,"path":3312,"seo":3313,"stem":3314,"tags":3315,"__hash__":3318},"posts\u002Fposts\u002Fmysql-batch-rename-table-column.md","MySQL 批量修改表名列名大小写",{"type":9,"value":3098,"toc":3305},[3099,3106,3110,3176,3180,3295,3302],[12,3100,3101,3102,3105],{},"接手老库时经常会碰到表名列名大小写混乱的情况。手写 rename 语句太累，不如查 ",[350,3103,3104],{},"information_schema"," 让数据库自己生成一批 SQL，复制出来跑就行。",[34,3107,3109],{"id":3108},"批量表名大写改小写","批量表名：大写改小写",[344,3111,3113],{"className":2700,"code":3112,"language":2702,"meta":293,"style":293},"SELECT\n concat(\n     'rename table  '\n     , TABLE_NAME\n     , ' to '\n     , LOWER(TABLE_NAME)\n     ,' ;'\n ) AS 'SQL'\nFROM\n information_schema.TABLES t \nWHERE\n TABLE_SCHEMA = 'xxxxxx';\n",[350,3114,3115,3120,3125,3130,3135,3140,3145,3150,3155,3160,3165,3170],{"__ignoreMap":293},[353,3116,3117],{"class":355,"line":356},[353,3118,3119],{},"SELECT\n",[353,3121,3122],{"class":355,"line":297},[353,3123,3124],{}," concat(\n",[353,3126,3127],{"class":355,"line":294},[353,3128,3129],{},"     'rename table  '\n",[353,3131,3132],{"class":355,"line":721},[353,3133,3134],{},"     , TABLE_NAME\n",[353,3136,3137],{"class":355,"line":1584},[353,3138,3139],{},"     , ' to '\n",[353,3141,3142],{"class":355,"line":2317},[353,3143,3144],{},"     , LOWER(TABLE_NAME)\n",[353,3146,3147],{"class":355,"line":2328},[353,3148,3149],{},"     ,' ;'\n",[353,3151,3152],{"class":355,"line":2334},[353,3153,3154],{}," ) AS 'SQL'\n",[353,3156,3157],{"class":355,"line":2348},[353,3158,3159],{},"FROM\n",[353,3161,3162],{"class":355,"line":2362},[353,3163,3164],{}," information_schema.TABLES t \n",[353,3166,3167],{"class":355,"line":2376},[353,3168,3169],{},"WHERE\n",[353,3171,3173],{"class":355,"line":3172},12,[353,3174,3175],{}," TABLE_SCHEMA = 'xxxxxx';\n",[34,3177,3179],{"id":3178},"批量列名大写改小写","批量列名：大写改小写",[344,3181,3183],{"className":2700,"code":3182,"language":2702,"meta":293,"style":293},"SELECT\nconcat(\n    'alter table '\n    , TABLE_NAME\n    , ' change column '\n    , COLUMN_NAME\n    , ' '\n    , LOWER(COLUMN_NAME)\n    , ' '\n    , COLUMN_TYPE\n    , ' comment \\''\n    , TRIM(REPLACE(REPLACE(REPLACE(REPLACE(COLUMN_COMMENT,',',':'),'\"',''),CHAR(10),''),CHAR(13),''))\n     , '\\''\n     , ' '\n     , IF(COLUMN_DEFAULT IS NULL, '', concat(' default \\'',TRIM(COLUMN_DEFAULT),'\\'')) \n     , ';' \n) AS 'SQL'\nFROM\n    information_schema.COLUMNS t\nWHERE\n    TABLE_SCHEMA = 'xxxxxx';\n",[350,3184,3185,3189,3194,3199,3204,3209,3214,3219,3224,3228,3233,3238,3243,3249,3255,3261,3267,3273,3278,3284,3289],{"__ignoreMap":293},[353,3186,3187],{"class":355,"line":356},[353,3188,3119],{},[353,3190,3191],{"class":355,"line":297},[353,3192,3193],{},"concat(\n",[353,3195,3196],{"class":355,"line":294},[353,3197,3198],{},"    'alter table '\n",[353,3200,3201],{"class":355,"line":721},[353,3202,3203],{},"    , TABLE_NAME\n",[353,3205,3206],{"class":355,"line":1584},[353,3207,3208],{},"    , ' change column '\n",[353,3210,3211],{"class":355,"line":2317},[353,3212,3213],{},"    , COLUMN_NAME\n",[353,3215,3216],{"class":355,"line":2328},[353,3217,3218],{},"    , ' '\n",[353,3220,3221],{"class":355,"line":2334},[353,3222,3223],{},"    , LOWER(COLUMN_NAME)\n",[353,3225,3226],{"class":355,"line":2348},[353,3227,3218],{},[353,3229,3230],{"class":355,"line":2362},[353,3231,3232],{},"    , COLUMN_TYPE\n",[353,3234,3235],{"class":355,"line":2376},[353,3236,3237],{},"    , ' comment \\''\n",[353,3239,3240],{"class":355,"line":3172},[353,3241,3242],{},"    , TRIM(REPLACE(REPLACE(REPLACE(REPLACE(COLUMN_COMMENT,',',':'),'\"',''),CHAR(10),''),CHAR(13),''))\n",[353,3244,3246],{"class":355,"line":3245},13,[353,3247,3248],{},"     , '\\''\n",[353,3250,3252],{"class":355,"line":3251},14,[353,3253,3254],{},"     , ' '\n",[353,3256,3258],{"class":355,"line":3257},15,[353,3259,3260],{},"     , IF(COLUMN_DEFAULT IS NULL, '', concat(' default \\'',TRIM(COLUMN_DEFAULT),'\\'')) \n",[353,3262,3264],{"class":355,"line":3263},16,[353,3265,3266],{},"     , ';' \n",[353,3268,3270],{"class":355,"line":3269},17,[353,3271,3272],{},") AS 'SQL'\n",[353,3274,3276],{"class":355,"line":3275},18,[353,3277,3159],{},[353,3279,3281],{"class":355,"line":3280},19,[353,3282,3283],{},"    information_schema.COLUMNS t\n",[353,3285,3287],{"class":355,"line":3286},20,[353,3288,3169],{},[353,3290,3292],{"class":355,"line":3291},21,[353,3293,3294],{},"    TABLE_SCHEMA = 'xxxxxx';\n",[12,3296,3297,3298,3301],{},"把 ",[350,3299,3300],{},"xxxxxx"," 换成你的库名，执行一遍拿到生成的 SQL，再贴到客户端里跑。",[1779,3303,3304],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":293,"searchDepth":294,"depth":294,"links":3306},[3307,3308],{"id":3108,"depth":297,"text":3109},{"id":3178,"depth":297,"text":3179},"2021-10-24","用 information_schema 生成批量 rename table \u002F change column 语句，把大写的表名列名一次性改成小写。",{},"\u002Fposts\u002Fmysql-batch-rename-table-column",{"title":3096,"description":3310},"posts\u002Fmysql-batch-rename-table-column",[3316,3317],"MySQL","数据库","-CV8-Yzpnbia5MLvz84obkND3gxhEiqFrHloxkl01uU",{"id":3320,"title":3321,"body":3322,"date":3367,"description":3368,"extension":305,"meta":3369,"navigation":307,"path":3370,"seo":3371,"stem":3372,"tags":3373,"__hash__":3375},"posts\u002Fposts\u002Fwin7-windows-update-error-80072ee2.md","新装 Win7 后 Windows Update 报 80072EE2 \u002F 80072EFE",{"type":9,"value":3323,"toc":3363},[3324,3327,3330,3336,3339,3342,3358],[34,3325,3326],{"id":3326},"故障场景",[12,3328,3329],{},"最近有台老电脑重装 Win7 系统，装完以后无法安装补丁，要么就报错 80072EE2，要么就报 80072EFE。",[12,3331,3332],{},[18,3333],{"alt":3334,"src":3335},"Windows Update 报错 80072EE2","\u002Fimages\u002Fwin7-windows-update\u002Ferror-80072ee2.png",[34,3337,3338],{"id":3338},"解决方法",[12,3340,3341],{},"安装补丁：",[1871,3343,3344,3351],{},[179,3345,3346],{},[96,3347,3350],{"href":3348,"rel":3349},"https:\u002F\u002Fwww.catalog.update.microsoft.com\u002FSearch.aspx?q=KB3020369",[100],"Windows6.1-KB3020369",[179,3352,3353],{},[96,3354,3357],{"href":3355,"rel":3356},"https:\u002F\u002Fwww.catalog.update.microsoft.com\u002FSearch.aspx?q=KB3125574",[100],"Windows6.1-KB3125574",[12,3359,3360],{},[183,3361,3362],{},"一定要注意顺序：先安装 KB3020369，后安装 KB3125574。",{"title":293,"searchDepth":294,"depth":294,"links":3364},[3365,3366],{"id":3326,"depth":297,"text":3326},{"id":3338,"depth":297,"text":3338},"2021-07-31","老电脑重装 Win7 后装不上补丁，报这两个错误码。按顺序打两个补丁就能救回来。",{},"\u002Fposts\u002Fwin7-windows-update-error-80072ee2",{"title":3321,"description":3368},"posts\u002Fwin7-windows-update-error-80072ee2",[3374,2470],"Windows","h8Ykzh6MWVdSZDFJA2VzFukeIUACGG0_SBjSotldcTY",{"id":3377,"title":3378,"body":3379,"date":4081,"description":4082,"extension":305,"meta":4083,"navigation":307,"path":4084,"seo":4085,"stem":4086,"tags":4087,"__hash__":4091},"posts\u002Fposts\u002Fnacos-snowflake-worker-id.md","用 Nacos 分配 Snowflake 的 Worker ID",{"type":9,"value":3380,"toc":4075},[3381,3383,3386,3389,3397,3400,3406,3413,4058,4061,4073],[34,3382,409],{"id":409},[12,3384,3385],{},"Snowflake 唯一 ID 算法大家都很熟悉，他是 Twitter 公司提出来的算法。但是对于 workerId 和 datacenterId 的维护往往需要各项目自行设计。\n基本都是基于 zookeeper or 数据库 or Redis 的。\n本例就是用 Nacos 分配 worker id。",[34,3387,3388],{"id":3388},"源码",[12,3390,3391,3392],{},"仓库地址：",[96,3393,3396],{"href":3394,"rel":3395},"https:\u002F\u002Fgitee.com\u002FJiaXiaohei\u002Fsnowflake-nacos",[100],"gitee.com\u002FJiaXiaohei\u002Fsnowflake-nacos",[34,3398,3399],{"id":3399},"原理",[12,3401,3402,3403],{},"核心类：",[350,3404,3405],{},"SnowflakeIdGenerator.class",[12,3407,3408,3409,3412],{},"基本原理：基于 Nacos 的监听服务 ",[350,3410,3411],{},"namingService.subscribe","，监听服务下的实例列表变化。\n注册一个服务到 Nacos，如果服务列表发生变化，获取服务所有实例的 Ip 地址和端口，用本机 Ip 地址和端口判断本机在实例列表的 index。",[344,3414,3417],{"className":3415,"code":3416,"language":2796,"meta":293,"style":293},"language-java shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import com.alibaba.cloud.nacos.NacosDiscoveryProperties;\nimport com.alibaba.cloud.nacos.NacosServiceManager;\nimport com.alibaba.nacos.api.exception.NacosException;\nimport com.alibaba.nacos.api.naming.NamingService;\nimport com.alibaba.nacos.api.naming.listener.AbstractEventListener;\nimport com.alibaba.nacos.api.naming.listener.Event;\nimport com.alibaba.nacos.api.naming.listener.NamingEvent;\nimport com.alibaba.nacos.api.naming.pojo.Instance;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.PostConstruct;\nimport java.text.DecimalFormat;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\n\u002F**\n * SnowflakeId + Nacos\n *\u002F\n@Component\npublic class SnowflakeIdGenerator {\n\n    protected final Logger logger = LoggerFactory.getLogger(this.getClass());\n\n    @Autowired\n    private NacosServiceManager nacosServiceManager;\n\n    @Autowired\n    private NacosDiscoveryProperties nacosDiscoveryProperties;\n\n    private static SnowflakeIdWorker snowflakeIdWorker;\n\n    private static int nodeId;\n\n    @PostConstruct\n    public void run() throws Exception {\n        init();\n    }\n\n    \u002F**\n     * 获取雪花Id\n     *\n     * @return\n     *\u002F\n    public static long nextId() {\n        return snowflakeIdWorker.nextId();\n    }\n\n    \u002F**\n     * 获取当前节点Id\n     *\n     * @return\n     *\u002F\n    public static int nodeId() {\n        return nodeId;\n    }\n\n    \u002F**\n     * 获取当前服务所有节点 + 增加服务监听\n     *\n     * @throws NacosException\n     *\u002F\n    private void init() throws NacosException {\n        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());\n        namingService.subscribe(nacosDiscoveryProperties.getService(), new AbstractEventListener() {\n            @Override\n            public void onEvent(Event event) {\n                if (-1 == nacosDiscoveryProperties.getPort()) {\n                    return;\n                }\n                nodeId = calcNodeId(((NamingEvent) event).getInstances());\n                if (nodeId > 1024) {\n                    throw new IllegalArgumentException(\"Worker & Datacenter Id calc results exceed 1024\");\n                }\n                long workerId = nodeId % 31;\n                long datacenterId = (long) Math.floor((float) nodeId \u002F 31);\n                logger.info(\"nodeId:\" + nodeId + \" workerId:\" + workerId + \" datacenterId:\" + datacenterId);\n                snowflakeIdWorker = new SnowflakeIdWorker(workerId, datacenterId);\n            }\n        });\n    }\n\n    \u002F**\n     * 用ip+port计算服务列表的索引\n     *\n     * @param instanceList\n     * @return\n     *\u002F\n    private int calcNodeId(List\u003CInstance> instanceList) {\n        List\u003CLong> ipPosrList = instanceList.stream()\n                .map(x -> dealIpPort(x.getIp(), x.getPort()))\n                .sorted(Comparator.naturalOrder())\n                .collect(Collectors.toList());\n        return ipPosrList.indexOf(dealIpPort(nacosDiscoveryProperties.getIp(), nacosDiscoveryProperties.getPort()));\n    }\n\n    \u002F**\n     * ip补0 + 端口号\n     *\n     * @param ip\n     * @param port\n     * @return\n     *\u002F\n    private static Long dealIpPort(String ip, int port) {\n        String[] ips = ip.split(\"\\\\.\");\n        StringBuilder sbr = new StringBuilder();\n        for (int i = 0; i \u003C ips.length; i++) {\n            sbr.append(new DecimalFormat(\"000\").format(Integer.parseInt(ips[i])));\n        }\n        return Long.parseLong(sbr.toString() + port);\n    }\n\n}\n",[350,3418,3419,3424,3429,3434,3439,3444,3449,3454,3459,3464,3469,3474,3479,3484,3489,3494,3499,3504,3509,3513,3518,3523,3529,3535,3541,3546,3552,3557,3563,3569,3574,3579,3585,3590,3596,3601,3607,3612,3618,3624,3630,3636,3641,3647,3653,3659,3665,3671,3677,3683,3688,3693,3698,3704,3709,3714,3719,3725,3731,3736,3741,3746,3752,3757,3763,3768,3774,3780,3786,3792,3798,3804,3810,3816,3822,3828,3834,3839,3845,3851,3857,3863,3869,3875,3880,3885,3890,3896,3901,3907,3912,3917,3923,3929,3935,3941,3947,3953,3958,3963,3968,3974,3979,3985,3991,3996,4001,4007,4013,4019,4025,4031,4037,4043,4048,4053],{"__ignoreMap":293},[353,3420,3421],{"class":355,"line":356},[353,3422,3423],{},"import com.alibaba.cloud.nacos.NacosDiscoveryProperties;\n",[353,3425,3426],{"class":355,"line":297},[353,3427,3428],{},"import com.alibaba.cloud.nacos.NacosServiceManager;\n",[353,3430,3431],{"class":355,"line":294},[353,3432,3433],{},"import com.alibaba.nacos.api.exception.NacosException;\n",[353,3435,3436],{"class":355,"line":721},[353,3437,3438],{},"import com.alibaba.nacos.api.naming.NamingService;\n",[353,3440,3441],{"class":355,"line":1584},[353,3442,3443],{},"import com.alibaba.nacos.api.naming.listener.AbstractEventListener;\n",[353,3445,3446],{"class":355,"line":2317},[353,3447,3448],{},"import com.alibaba.nacos.api.naming.listener.Event;\n",[353,3450,3451],{"class":355,"line":2328},[353,3452,3453],{},"import com.alibaba.nacos.api.naming.listener.NamingEvent;\n",[353,3455,3456],{"class":355,"line":2334},[353,3457,3458],{},"import com.alibaba.nacos.api.naming.pojo.Instance;\n",[353,3460,3461],{"class":355,"line":2348},[353,3462,3463],{},"import org.slf4j.Logger;\n",[353,3465,3466],{"class":355,"line":2362},[353,3467,3468],{},"import org.slf4j.LoggerFactory;\n",[353,3470,3471],{"class":355,"line":2376},[353,3472,3473],{},"import org.springframework.beans.factory.annotation.Autowired;\n",[353,3475,3476],{"class":355,"line":3172},[353,3477,3478],{},"import org.springframework.stereotype.Component;\n",[353,3480,3481],{"class":355,"line":3245},[353,3482,3483],{"emptyLinePlaceholder":307},"\n",[353,3485,3486],{"class":355,"line":3251},[353,3487,3488],{},"import javax.annotation.PostConstruct;\n",[353,3490,3491],{"class":355,"line":3257},[353,3492,3493],{},"import java.text.DecimalFormat;\n",[353,3495,3496],{"class":355,"line":3263},[353,3497,3498],{},"import java.util.Comparator;\n",[353,3500,3501],{"class":355,"line":3269},[353,3502,3503],{},"import java.util.List;\n",[353,3505,3506],{"class":355,"line":3275},[353,3507,3508],{},"import java.util.stream.Collectors;\n",[353,3510,3511],{"class":355,"line":3280},[353,3512,3483],{"emptyLinePlaceholder":307},[353,3514,3515],{"class":355,"line":3286},[353,3516,3517],{},"\u002F**\n",[353,3519,3520],{"class":355,"line":3291},[353,3521,3522],{}," * SnowflakeId + Nacos\n",[353,3524,3526],{"class":355,"line":3525},22,[353,3527,3528],{}," *\u002F\n",[353,3530,3532],{"class":355,"line":3531},23,[353,3533,3534],{},"@Component\n",[353,3536,3538],{"class":355,"line":3537},24,[353,3539,3540],{},"public class SnowflakeIdGenerator {\n",[353,3542,3544],{"class":355,"line":3543},25,[353,3545,3483],{"emptyLinePlaceholder":307},[353,3547,3549],{"class":355,"line":3548},26,[353,3550,3551],{},"    protected final Logger logger = LoggerFactory.getLogger(this.getClass());\n",[353,3553,3555],{"class":355,"line":3554},27,[353,3556,3483],{"emptyLinePlaceholder":307},[353,3558,3560],{"class":355,"line":3559},28,[353,3561,3562],{},"    @Autowired\n",[353,3564,3566],{"class":355,"line":3565},29,[353,3567,3568],{},"    private NacosServiceManager nacosServiceManager;\n",[353,3570,3572],{"class":355,"line":3571},30,[353,3573,3483],{"emptyLinePlaceholder":307},[353,3575,3577],{"class":355,"line":3576},31,[353,3578,3562],{},[353,3580,3582],{"class":355,"line":3581},32,[353,3583,3584],{},"    private NacosDiscoveryProperties nacosDiscoveryProperties;\n",[353,3586,3588],{"class":355,"line":3587},33,[353,3589,3483],{"emptyLinePlaceholder":307},[353,3591,3593],{"class":355,"line":3592},34,[353,3594,3595],{},"    private static SnowflakeIdWorker snowflakeIdWorker;\n",[353,3597,3599],{"class":355,"line":3598},35,[353,3600,3483],{"emptyLinePlaceholder":307},[353,3602,3604],{"class":355,"line":3603},36,[353,3605,3606],{},"    private static int nodeId;\n",[353,3608,3610],{"class":355,"line":3609},37,[353,3611,3483],{"emptyLinePlaceholder":307},[353,3613,3615],{"class":355,"line":3614},38,[353,3616,3617],{},"    @PostConstruct\n",[353,3619,3621],{"class":355,"line":3620},39,[353,3622,3623],{},"    public void run() throws Exception {\n",[353,3625,3627],{"class":355,"line":3626},40,[353,3628,3629],{},"        init();\n",[353,3631,3633],{"class":355,"line":3632},41,[353,3634,3635],{},"    }\n",[353,3637,3639],{"class":355,"line":3638},42,[353,3640,3483],{"emptyLinePlaceholder":307},[353,3642,3644],{"class":355,"line":3643},43,[353,3645,3646],{},"    \u002F**\n",[353,3648,3650],{"class":355,"line":3649},44,[353,3651,3652],{},"     * 获取雪花Id\n",[353,3654,3656],{"class":355,"line":3655},45,[353,3657,3658],{},"     *\n",[353,3660,3662],{"class":355,"line":3661},46,[353,3663,3664],{},"     * @return\n",[353,3666,3668],{"class":355,"line":3667},47,[353,3669,3670],{},"     *\u002F\n",[353,3672,3674],{"class":355,"line":3673},48,[353,3675,3676],{},"    public static long nextId() {\n",[353,3678,3680],{"class":355,"line":3679},49,[353,3681,3682],{},"        return snowflakeIdWorker.nextId();\n",[353,3684,3686],{"class":355,"line":3685},50,[353,3687,3635],{},[353,3689,3691],{"class":355,"line":3690},51,[353,3692,3483],{"emptyLinePlaceholder":307},[353,3694,3696],{"class":355,"line":3695},52,[353,3697,3646],{},[353,3699,3701],{"class":355,"line":3700},53,[353,3702,3703],{},"     * 获取当前节点Id\n",[353,3705,3707],{"class":355,"line":3706},54,[353,3708,3658],{},[353,3710,3712],{"class":355,"line":3711},55,[353,3713,3664],{},[353,3715,3717],{"class":355,"line":3716},56,[353,3718,3670],{},[353,3720,3722],{"class":355,"line":3721},57,[353,3723,3724],{},"    public static int nodeId() {\n",[353,3726,3728],{"class":355,"line":3727},58,[353,3729,3730],{},"        return nodeId;\n",[353,3732,3734],{"class":355,"line":3733},59,[353,3735,3635],{},[353,3737,3739],{"class":355,"line":3738},60,[353,3740,3483],{"emptyLinePlaceholder":307},[353,3742,3744],{"class":355,"line":3743},61,[353,3745,3646],{},[353,3747,3749],{"class":355,"line":3748},62,[353,3750,3751],{},"     * 获取当前服务所有节点 + 增加服务监听\n",[353,3753,3755],{"class":355,"line":3754},63,[353,3756,3658],{},[353,3758,3760],{"class":355,"line":3759},64,[353,3761,3762],{},"     * @throws NacosException\n",[353,3764,3766],{"class":355,"line":3765},65,[353,3767,3670],{},[353,3769,3771],{"class":355,"line":3770},66,[353,3772,3773],{},"    private void init() throws NacosException {\n",[353,3775,3777],{"class":355,"line":3776},67,[353,3778,3779],{},"        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());\n",[353,3781,3783],{"class":355,"line":3782},68,[353,3784,3785],{},"        namingService.subscribe(nacosDiscoveryProperties.getService(), new AbstractEventListener() {\n",[353,3787,3789],{"class":355,"line":3788},69,[353,3790,3791],{},"            @Override\n",[353,3793,3795],{"class":355,"line":3794},70,[353,3796,3797],{},"            public void onEvent(Event event) {\n",[353,3799,3801],{"class":355,"line":3800},71,[353,3802,3803],{},"                if (-1 == nacosDiscoveryProperties.getPort()) {\n",[353,3805,3807],{"class":355,"line":3806},72,[353,3808,3809],{},"                    return;\n",[353,3811,3813],{"class":355,"line":3812},73,[353,3814,3815],{},"                }\n",[353,3817,3819],{"class":355,"line":3818},74,[353,3820,3821],{},"                nodeId = calcNodeId(((NamingEvent) event).getInstances());\n",[353,3823,3825],{"class":355,"line":3824},75,[353,3826,3827],{},"                if (nodeId > 1024) {\n",[353,3829,3831],{"class":355,"line":3830},76,[353,3832,3833],{},"                    throw new IllegalArgumentException(\"Worker & Datacenter Id calc results exceed 1024\");\n",[353,3835,3837],{"class":355,"line":3836},77,[353,3838,3815],{},[353,3840,3842],{"class":355,"line":3841},78,[353,3843,3844],{},"                long workerId = nodeId % 31;\n",[353,3846,3848],{"class":355,"line":3847},79,[353,3849,3850],{},"                long datacenterId = (long) Math.floor((float) nodeId \u002F 31);\n",[353,3852,3854],{"class":355,"line":3853},80,[353,3855,3856],{},"                logger.info(\"nodeId:\" + nodeId + \" workerId:\" + workerId + \" datacenterId:\" + datacenterId);\n",[353,3858,3860],{"class":355,"line":3859},81,[353,3861,3862],{},"                snowflakeIdWorker = new SnowflakeIdWorker(workerId, datacenterId);\n",[353,3864,3866],{"class":355,"line":3865},82,[353,3867,3868],{},"            }\n",[353,3870,3872],{"class":355,"line":3871},83,[353,3873,3874],{},"        });\n",[353,3876,3878],{"class":355,"line":3877},84,[353,3879,3635],{},[353,3881,3883],{"class":355,"line":3882},85,[353,3884,3483],{"emptyLinePlaceholder":307},[353,3886,3888],{"class":355,"line":3887},86,[353,3889,3646],{},[353,3891,3893],{"class":355,"line":3892},87,[353,3894,3895],{},"     * 用ip+port计算服务列表的索引\n",[353,3897,3899],{"class":355,"line":3898},88,[353,3900,3658],{},[353,3902,3904],{"class":355,"line":3903},89,[353,3905,3906],{},"     * @param instanceList\n",[353,3908,3910],{"class":355,"line":3909},90,[353,3911,3664],{},[353,3913,3915],{"class":355,"line":3914},91,[353,3916,3670],{},[353,3918,3920],{"class":355,"line":3919},92,[353,3921,3922],{},"    private int calcNodeId(List\u003CInstance> instanceList) {\n",[353,3924,3926],{"class":355,"line":3925},93,[353,3927,3928],{},"        List\u003CLong> ipPosrList = instanceList.stream()\n",[353,3930,3932],{"class":355,"line":3931},94,[353,3933,3934],{},"                .map(x -> dealIpPort(x.getIp(), x.getPort()))\n",[353,3936,3938],{"class":355,"line":3937},95,[353,3939,3940],{},"                .sorted(Comparator.naturalOrder())\n",[353,3942,3944],{"class":355,"line":3943},96,[353,3945,3946],{},"                .collect(Collectors.toList());\n",[353,3948,3950],{"class":355,"line":3949},97,[353,3951,3952],{},"        return ipPosrList.indexOf(dealIpPort(nacosDiscoveryProperties.getIp(), nacosDiscoveryProperties.getPort()));\n",[353,3954,3956],{"class":355,"line":3955},98,[353,3957,3635],{},[353,3959,3961],{"class":355,"line":3960},99,[353,3962,3483],{"emptyLinePlaceholder":307},[353,3964,3966],{"class":355,"line":3965},100,[353,3967,3646],{},[353,3969,3971],{"class":355,"line":3970},101,[353,3972,3973],{},"     * ip补0 + 端口号\n",[353,3975,3977],{"class":355,"line":3976},102,[353,3978,3658],{},[353,3980,3982],{"class":355,"line":3981},103,[353,3983,3984],{},"     * @param ip\n",[353,3986,3988],{"class":355,"line":3987},104,[353,3989,3990],{},"     * @param port\n",[353,3992,3994],{"class":355,"line":3993},105,[353,3995,3664],{},[353,3997,3999],{"class":355,"line":3998},106,[353,4000,3670],{},[353,4002,4004],{"class":355,"line":4003},107,[353,4005,4006],{},"    private static Long dealIpPort(String ip, int port) {\n",[353,4008,4010],{"class":355,"line":4009},108,[353,4011,4012],{},"        String[] ips = ip.split(\"\\\\.\");\n",[353,4014,4016],{"class":355,"line":4015},109,[353,4017,4018],{},"        StringBuilder sbr = new StringBuilder();\n",[353,4020,4022],{"class":355,"line":4021},110,[353,4023,4024],{},"        for (int i = 0; i \u003C ips.length; i++) {\n",[353,4026,4028],{"class":355,"line":4027},111,[353,4029,4030],{},"            sbr.append(new DecimalFormat(\"000\").format(Integer.parseInt(ips[i])));\n",[353,4032,4034],{"class":355,"line":4033},112,[353,4035,4036],{},"        }\n",[353,4038,4040],{"class":355,"line":4039},113,[353,4041,4042],{},"        return Long.parseLong(sbr.toString() + port);\n",[353,4044,4046],{"class":355,"line":4045},114,[353,4047,3635],{},[353,4049,4051],{"class":355,"line":4050},115,[353,4052,3483],{"emptyLinePlaceholder":307},[353,4054,4056],{"class":355,"line":4055},116,[353,4057,856],{},[34,4059,4060],{"id":4060},"参考",[12,4062,4063,4064,4067,4068],{},"雪花生成类 ",[350,4065,4066],{},"SnowflakeIdWorker.class"," 参考：\n",[96,4069,4072],{"href":4070,"rel":4071},"https:\u002F\u002Fblog.csdn.net\u002Flq18050010830\u002Farticle\u002Fdetails\u002F89845790",[100],"blog.csdn.net\u002Flq18050010830\u002Farticle\u002Fdetails\u002F89845790",[1779,4074,3304],{},{"title":293,"searchDepth":294,"depth":294,"links":4076},[4077,4078,4079,4080],{"id":409,"depth":297,"text":409},{"id":3388,"depth":297,"text":3388},{"id":3399,"depth":297,"text":3399},{"id":4060,"depth":297,"text":4060},"2021-07-27","借 Nacos 的服务实例列表动态算出 workerId 和 datacenterId，不用自己维护 zookeeper 或数据库。",{},"\u002Fposts\u002Fnacos-snowflake-worker-id",{"title":3378,"description":4082},"posts\u002Fnacos-snowflake-worker-id",[4088,4089,4090,3089],"Nacos","Snowflake","分布式","q6O68lgetHxAC0gydMk10d90i9PDmzbCotgRtwvrCXw",{"id":4093,"title":4094,"body":4095,"date":4189,"description":5394,"extension":305,"meta":5395,"navigation":307,"path":5396,"seo":5397,"stem":5398,"tags":5399,"__hash__":5401},"posts\u002Fposts\u002Fgitlab-ce-upgrade-11-to-13.md","记一次 GitLab-CE 跨版本从 11 升级到 13 踩的坑",{"type":9,"value":4096,"toc":5388},[4097,4100,4106,4109,4113,4122,4128,4130,4134,4137,4300,4303,4394,4396,4400,4403,4750,4753,4877,4880,5168,5171,5367,5370,5385],[1085,4098,4099],{"id":4099},"环境",[344,4101,4104],{"className":4102,"code":4103,"language":2831},[2829],"OS:CentOS 8\nHostname:HyperV-GitLab\n",[350,4105,4103],{"__ignoreMap":293},[4107,4108],"hr",{},[1085,4110,4112],{"id":4111},"_1不可跨大版本升级","1.不可跨大版本升级",[12,4114,4115,4116,4121],{},"必须先升级到当前大版本的最新版 在升级到下一个大版本\n参考",[96,4117,4120],{"href":4118,"rel":4119},"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fpolicy\u002Fmaintenance.html#upgrade-recommendations",[100],"官方网站","对于版本升级的说明",[12,4123,4124],{},[18,4125],{"alt":4126,"src":4127},"GitLab 版本升级路径","\u002Fimages\u002Fgitlab-ce-upgrade\u002Fupgrade-path.png",[4107,4129],{},[1085,4131,4133],{"id":4132},"_2pg_dump-aborting-because-of-server-version-mismatch","2.pg_dump: aborting because of server version mismatch",[12,4135,4136],{},"因为使用了外部数据源（PG），而且是 12 的高版本，GitLab 自带 pg_dump 版本只到 10 或者 11。在升级的备份部分，就备份失败，报错如下：",[344,4138,4140],{"className":687,"code":4139,"language":689,"meta":293,"style":293},"gitlab preinstall: Automatically backing up only the GitLab SQL database (excluding everything else!)\n2020-10-01 21:47:39 +0800 -- Dumping database ... \nDumping PostgreSQL database db_gitlab ... pg_dump: server version: 12.4; pg_dump version: 11.7\npg_dump: aborting because of server version mismatch\n[FAILED]\nrake aborted!\nBackup::Error: Backup failed\n",[350,4141,4142,4185,4210,4248,4270,4281,4289],{"__ignoreMap":293},[353,4143,4144,4147,4150,4153,4156,4159,4162,4165,4168,4171,4174,4177,4180,4183],{"class":355,"line":356},[353,4145,4146],{"class":696},"gitlab",[353,4148,4149],{"class":390}," preinstall:",[353,4151,4152],{"class":390}," Automatically",[353,4154,4155],{"class":390}," backing",[353,4157,4158],{"class":390}," up",[353,4160,4161],{"class":390}," only",[353,4163,4164],{"class":390}," the",[353,4166,4167],{"class":390}," GitLab",[353,4169,4170],{"class":390}," SQL",[353,4172,4173],{"class":390}," database",[353,4175,4176],{"class":367}," (excluding ",[353,4178,4179],{"class":390},"everything",[353,4181,4182],{"class":390}," else!",[353,4184,396],{"class":367},[353,4186,4187,4190,4193,4196,4199,4202,4204,4207],{"class":355,"line":297},[353,4188,4189],{"class":696},"2020-10-01",[353,4191,4192],{"class":390}," 21:47:39",[353,4194,4195],{"class":390}," +0800",[353,4197,4198],{"class":390}," --",[353,4200,4201],{"class":390}," Dumping",[353,4203,4173],{"class":390},[353,4205,4206],{"class":390}," ...",[353,4208,4209],{"class":367}," \n",[353,4211,4212,4215,4218,4220,4223,4225,4228,4231,4234,4237,4240,4243,4245],{"class":355,"line":294},[353,4213,4214],{"class":696},"Dumping",[353,4216,4217],{"class":390}," PostgreSQL",[353,4219,4173],{"class":390},[353,4221,4222],{"class":390}," db_gitlab",[353,4224,4206],{"class":390},[353,4226,4227],{"class":390}," pg_dump:",[353,4229,4230],{"class":390}," server",[353,4232,4233],{"class":390}," version:",[353,4235,4236],{"class":739}," 12.4",[353,4238,4239],{"class":363},";",[353,4241,4242],{"class":696}," pg_dump",[353,4244,4233],{"class":390},[353,4246,4247],{"class":739}," 11.7\n",[353,4249,4250,4253,4256,4259,4262,4264,4267],{"class":355,"line":721},[353,4251,4252],{"class":696},"pg_dump:",[353,4254,4255],{"class":390}," aborting",[353,4257,4258],{"class":390}," because",[353,4260,4261],{"class":390}," of",[353,4263,4230],{"class":390},[353,4265,4266],{"class":390}," version",[353,4268,4269],{"class":390}," mismatch\n",[353,4271,4272,4275,4278],{"class":355,"line":1584},[353,4273,4274],{"class":363},"[",[353,4276,4277],{"class":367},"FAILED",[353,4279,4280],{"class":363},"]\n",[353,4282,4283,4286],{"class":355,"line":2317},[353,4284,4285],{"class":696},"rake",[353,4287,4288],{"class":390}," aborted!\n",[353,4290,4291,4294,4297],{"class":355,"line":2328},[353,4292,4293],{"class":696},"Backup::Error:",[353,4295,4296],{"class":390}," Backup",[353,4298,4299],{"class":390}," failed\n",[12,4301,4302],{},"解决方法：",[344,4304,4306],{"className":687,"code":4305,"language":689,"meta":293,"style":293},"1.安装postgresql12的客户端\ndnf install -y https:\u002F\u002Fdownload.postgresql.org\u002Fpub\u002Frepos\u002Fyum\u002Freporpms\u002FEL-8-x86_64\u002Fpgdg-redhat-repo-latest.noarch.rpm\ndnf -qy module disable postgresql\ndnf install -y postgresql12\n\n2.重新建立pg_dump的软连接\ncd \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\nmv pg_dump pg_dump.bak\nln -s \u002Fusr\u002Fbin\u002Fpg_dump \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\u002Fpg_dump\n",[350,4307,4308,4313,4327,4342,4353,4357,4362,4370,4380],{"__ignoreMap":293},[353,4309,4310],{"class":355,"line":356},[353,4311,4312],{"class":696},"1.安装postgresql12的客户端\n",[353,4314,4315,4318,4321,4324],{"class":355,"line":297},[353,4316,4317],{"class":696},"dnf",[353,4319,4320],{"class":390}," install",[353,4322,4323],{"class":390}," -y",[353,4325,4326],{"class":390}," https:\u002F\u002Fdownload.postgresql.org\u002Fpub\u002Frepos\u002Fyum\u002Freporpms\u002FEL-8-x86_64\u002Fpgdg-redhat-repo-latest.noarch.rpm\n",[353,4328,4329,4331,4334,4337,4339],{"class":355,"line":294},[353,4330,4317],{"class":696},[353,4332,4333],{"class":390}," -qy",[353,4335,4336],{"class":390}," module",[353,4338,2172],{"class":390},[353,4340,4341],{"class":390}," postgresql\n",[353,4343,4344,4346,4348,4350],{"class":355,"line":721},[353,4345,4317],{"class":696},[353,4347,4320],{"class":390},[353,4349,4323],{"class":390},[353,4351,4352],{"class":390}," postgresql12\n",[353,4354,4355],{"class":355,"line":1584},[353,4356,3483],{"emptyLinePlaceholder":307},[353,4358,4359],{"class":355,"line":2317},[353,4360,4361],{"class":696},"2.重新建立pg_dump的软连接\n",[353,4363,4364,4367],{"class":355,"line":2328},[353,4365,4366],{"class":796},"cd",[353,4368,4369],{"class":390}," \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\n",[353,4371,4372,4375,4377],{"class":355,"line":2334},[353,4373,4374],{"class":696},"mv",[353,4376,4242],{"class":390},[353,4378,4379],{"class":390}," pg_dump.bak\n",[353,4381,4382,4385,4388,4391],{"class":355,"line":2348},[353,4383,4384],{"class":696},"ln",[353,4386,4387],{"class":390}," -s",[353,4389,4390],{"class":390}," \u002Fusr\u002Fbin\u002Fpg_dump",[353,4392,4393],{"class":390}," \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\u002Fpg_dump\n",[4107,4395],{},[1085,4397,4399],{"id":4398},"_3error-preingitlab-ce-13111-ce0el8x86_64-scriptlet-failed-exit-status-1","3.error: %prein(gitlab-ce-13.1.11-ce.0.el8.x86_64) scriptlet failed, exit status 1",[12,4401,4402],{},"GitLab 一开始就用 Yum\u002Fdnf 安装，后面升级自然也一直用 Yum 命令升级；只到从 13.1.4 升级到 13.1.11 版本时，一直提示",[344,4404,4406],{"className":687,"code":4405,"language":689,"meta":293,"style":293},"[root@HyperV-GitLab opt]# yum update gitlab-ce-13.1.11\n上次元数据过期检查：6:53:15 前，执行于 2020年10月01日 星期四 15时40分48秒。\n依赖关系解决。\n==================================================================================================================================\n 软件包                       架构                      版本                                   仓库                          大小\n==================================================================================================================================\n升级:\n gitlab-ce                    x86_64                    13.1.11-ce.0.el8                       gitlab-ce                    716 M\n\n事务概要\n==================================================================================================================================\n升级  1 软件包\n\n总下载：716 M\n确定吗？[y\u002FN]： y\n下载软件包：\ngitlab-ce-13.1.11-ce.0.el8.x86_64.rpm                                                             3.7 MB\u002Fs | 716 MB     03:13    \n----------------------------------------------------------------------------------------------------------------------------------\n总计                                                                                              3.7 MB\u002Fs | 716 MB     03:13     \n运行事务检查\n事务检查成功。\n运行事务测试\n事务测试成功。\n运行事务\n  准备中  :                                                                                                                   1\u002F1 \n  运行脚本: gitlab-ce-13.1.11-ce.0.el8.x86_64                                                                                 1\u002F2 \n错误：%prein(gitlab-ce-13.1.11-ce.0.el8.x86_64) 脚本执行失败，退出状态码为 1\n\nError in PREIN scriptlet in rpm package gitlab-ce\n  验证    : gitlab-ce-13.1.11-ce.0.el8.x86_64                                                                                 1\u002F2 \n  验证    : gitlab-ce-13.1.4-ce.0.el8.x86_64                                                                                  2\u002F2 \n\n失败:\n  gitlab-ce-13.1.4-ce.0.el8.x86_64                                gitlab-ce-13.1.11-ce.0.el8.x86_64                               \n\n错误：事务失败\n[root@HyperV-GitLab opt]# \n",[350,4407,4408,4421,4438,4443,4448,4465,4469,4474,4494,4498,4503,4507,4518,4522,4529,4537,4542,4568,4573,4594,4599,4604,4609,4614,4619,4632,4645,4653,4657,4682,4696,4710,4714,4719,4730,4734,4739],{"__ignoreMap":293},[353,4409,4410,4412,4415,4418],{"class":355,"line":356},[353,4411,4274],{"class":363},[353,4413,4414],{"class":367},"root@HyperV-GitLab opt",[353,4416,4417],{"class":363},"]",[353,4419,4420],{"class":367},"# yum update gitlab-ce-13.1.11\n",[353,4422,4423,4426,4429,4432,4435],{"class":355,"line":297},[353,4424,4425],{"class":696},"上次元数据过期检查：6:53:15",[353,4427,4428],{"class":390}," 前，执行于",[353,4430,4431],{"class":390}," 2020年10月01日",[353,4433,4434],{"class":390}," 星期四",[353,4436,4437],{"class":390}," 15时40分48秒。\n",[353,4439,4440],{"class":355,"line":294},[353,4441,4442],{"class":696},"依赖关系解决。\n",[353,4444,4445],{"class":355,"line":721},[353,4446,4447],{"class":390},"==================================================================================================================================\n",[353,4449,4450,4453,4456,4459,4462],{"class":355,"line":1584},[353,4451,4452],{"class":696}," 软件包",[353,4454,4455],{"class":390},"                       架构",[353,4457,4458],{"class":390},"                      版本",[353,4460,4461],{"class":390},"                                   仓库",[353,4463,4464],{"class":390},"                          大小\n",[353,4466,4467],{"class":355,"line":2317},[353,4468,4447],{"class":390},[353,4470,4471],{"class":355,"line":2328},[353,4472,4473],{"class":696},"升级:\n",[353,4475,4476,4479,4482,4485,4488,4491],{"class":355,"line":2334},[353,4477,4478],{"class":696}," gitlab-ce",[353,4480,4481],{"class":390},"                    x86_64",[353,4483,4484],{"class":390},"                    13.1.11-ce.0.el8",[353,4486,4487],{"class":390},"                       gitlab-ce",[353,4489,4490],{"class":739},"                    716",[353,4492,4493],{"class":390}," M\n",[353,4495,4496],{"class":355,"line":2348},[353,4497,3483],{"emptyLinePlaceholder":307},[353,4499,4500],{"class":355,"line":2362},[353,4501,4502],{"class":696},"事务概要\n",[353,4504,4505],{"class":355,"line":2376},[353,4506,4447],{"class":390},[353,4508,4509,4512,4515],{"class":355,"line":3172},[353,4510,4511],{"class":696},"升级",[353,4513,4514],{"class":739},"  1",[353,4516,4517],{"class":390}," 软件包\n",[353,4519,4520],{"class":355,"line":3245},[353,4521,3483],{"emptyLinePlaceholder":307},[353,4523,4524,4527],{"class":355,"line":3251},[353,4525,4526],{"class":696},"总下载：716",[353,4528,4493],{"class":390},[353,4530,4531,4534],{"class":355,"line":3257},[353,4532,4533],{"class":696},"确定吗？[y\u002FN]：",[353,4535,4536],{"class":390}," y\n",[353,4538,4539],{"class":355,"line":3263},[353,4540,4541],{"class":696},"下载软件包：\n",[353,4543,4544,4547,4550,4553,4556,4559,4562,4565],{"class":355,"line":3269},[353,4545,4546],{"class":696},"gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm",[353,4548,4549],{"class":739},"                                                             3.7",[353,4551,4552],{"class":390}," MB\u002Fs",[353,4554,4555],{"class":363}," |",[353,4557,4558],{"class":696}," 716",[353,4560,4561],{"class":390}," MB",[353,4563,4564],{"class":390},"     03:13",[353,4566,4567],{"class":367},"    \n",[353,4569,4570],{"class":355,"line":3275},[353,4571,4572],{"class":696},"----------------------------------------------------------------------------------------------------------------------------------\n",[353,4574,4575,4578,4581,4583,4585,4587,4589,4591],{"class":355,"line":3280},[353,4576,4577],{"class":696},"总计",[353,4579,4580],{"class":739},"                                                                                              3.7",[353,4582,4552],{"class":390},[353,4584,4555],{"class":363},[353,4586,4558],{"class":696},[353,4588,4561],{"class":390},[353,4590,4564],{"class":390},[353,4592,4593],{"class":367},"     \n",[353,4595,4596],{"class":355,"line":3286},[353,4597,4598],{"class":696},"运行事务检查\n",[353,4600,4601],{"class":355,"line":3291},[353,4602,4603],{"class":696},"事务检查成功。\n",[353,4605,4606],{"class":355,"line":3525},[353,4607,4608],{"class":696},"运行事务测试\n",[353,4610,4611],{"class":355,"line":3531},[353,4612,4613],{"class":696},"事务测试成功。\n",[353,4615,4616],{"class":355,"line":3537},[353,4617,4618],{"class":696},"运行事务\n",[353,4620,4621,4624,4627,4630],{"class":355,"line":3543},[353,4622,4623],{"class":696},"  准备中",[353,4625,4626],{"class":390},"  :",[353,4628,4629],{"class":390},"                                                                                                                   1\u002F1",[353,4631,4209],{"class":367},[353,4633,4634,4637,4640,4643],{"class":355,"line":3548},[353,4635,4636],{"class":696},"  运行脚本:",[353,4638,4639],{"class":390}," gitlab-ce-13.1.11-ce.0.el8.x86_64",[353,4641,4642],{"class":390},"                                                                                 1\u002F2",[353,4644,4209],{"class":367},[353,4646,4647,4650],{"class":355,"line":3554},[353,4648,4649],{"class":696},"错误：%prein(gitlab-ce-13.1.11-ce.0.el8.x86_64",[353,4651,4652],{"class":367},") 脚本执行失败，退出状态码为 1\n",[353,4654,4655],{"class":355,"line":3559},[353,4656,3483],{"emptyLinePlaceholder":307},[353,4658,4659,4662,4665,4668,4671,4673,4676,4679],{"class":355,"line":3565},[353,4660,4661],{"class":696},"Error",[353,4663,4664],{"class":390}," in",[353,4666,4667],{"class":390}," PREIN",[353,4669,4670],{"class":390}," scriptlet",[353,4672,4664],{"class":390},[353,4674,4675],{"class":390}," rpm",[353,4677,4678],{"class":390}," package",[353,4680,4681],{"class":390}," gitlab-ce\n",[353,4683,4684,4687,4690,4692,4694],{"class":355,"line":3571},[353,4685,4686],{"class":696},"  验证",[353,4688,4689],{"class":390},"    :",[353,4691,4639],{"class":390},[353,4693,4642],{"class":390},[353,4695,4209],{"class":367},[353,4697,4698,4700,4702,4705,4708],{"class":355,"line":3576},[353,4699,4686],{"class":696},[353,4701,4689],{"class":390},[353,4703,4704],{"class":390}," gitlab-ce-13.1.4-ce.0.el8.x86_64",[353,4706,4707],{"class":390},"                                                                                  2\u002F2",[353,4709,4209],{"class":367},[353,4711,4712],{"class":355,"line":3581},[353,4713,3483],{"emptyLinePlaceholder":307},[353,4715,4716],{"class":355,"line":3587},[353,4717,4718],{"class":696},"失败:\n",[353,4720,4721,4724,4727],{"class":355,"line":3592},[353,4722,4723],{"class":696},"  gitlab-ce-13.1.4-ce.0.el8.x86_64",[353,4725,4726],{"class":390},"                                gitlab-ce-13.1.11-ce.0.el8.x86_64",[353,4728,4729],{"class":367},"                               \n",[353,4731,4732],{"class":355,"line":3598},[353,4733,3483],{"emptyLinePlaceholder":307},[353,4735,4736],{"class":355,"line":3603},[353,4737,4738],{"class":696},"错误：事务失败\n",[353,4740,4741,4743,4745,4747],{"class":355,"line":3609},[353,4742,4274],{"class":363},[353,4744,4414],{"class":367},[353,4746,4417],{"class":363},[353,4748,4749],{"class":367},"#\n",[12,4751,4752],{},"手动下载 rpm 包安装，也有相同的报错信息：",[344,4754,4756],{"className":687,"code":4755,"language":689,"meta":293,"style":293},"[root@HyperV-GitLab opt]# rpm -Uvh gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm \n警告：gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm: 头V4 RSA\u002FSHA256 Signature, 密钥 ID f27eab47: NOKEY\nVerifying...                          ################################# [100%]\n准备中...                          ################################# [100%]\n错误：%prein(gitlab-ce-13.1.11-ce.0.el8.x86_64) 脚本执行失败，退出状态码为 1\n错误：gitlab-ce-13.1.11-ce.0.el8.x86_64: 安裝 已失败\n错误：gitlab-ce-13.1.4-ce.0.el8.x86_64: 删除 已跳过\n\nOR\nerror: prein(gitlab-ce-13.1.11-ce.0.el8.x86_64)scriptlet failed, exit status 1\n",[350,4757,4758,4769,4795,4803,4810,4816,4827,4838,4842,4847],{"__ignoreMap":293},[353,4759,4760,4762,4764,4766],{"class":355,"line":356},[353,4761,4274],{"class":363},[353,4763,4414],{"class":367},[353,4765,4417],{"class":363},[353,4767,4768],{"class":367},"# rpm -Uvh gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm \n",[353,4770,4771,4774,4777,4780,4783,4786,4789,4792],{"class":355,"line":297},[353,4772,4773],{"class":696},"警告：gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm:",[353,4775,4776],{"class":390}," 头V4",[353,4778,4779],{"class":390}," RSA\u002FSHA256",[353,4781,4782],{"class":390}," Signature,",[353,4784,4785],{"class":390}," 密钥",[353,4787,4788],{"class":390}," ID",[353,4790,4791],{"class":390}," f27eab47:",[353,4793,4794],{"class":390}," NOKEY\n",[353,4796,4797,4800],{"class":355,"line":294},[353,4798,4799],{"class":696},"Verifying...",[353,4801,4802],{"class":703},"                          ################################# [100%]\n",[353,4804,4805,4808],{"class":355,"line":721},[353,4806,4807],{"class":696},"准备中...",[353,4809,4802],{"class":703},[353,4811,4812,4814],{"class":355,"line":1584},[353,4813,4649],{"class":696},[353,4815,4652],{"class":367},[353,4817,4818,4821,4824],{"class":355,"line":2317},[353,4819,4820],{"class":696},"错误：gitlab-ce-13.1.11-ce.0.el8.x86_64:",[353,4822,4823],{"class":390}," 安裝",[353,4825,4826],{"class":390}," 已失败\n",[353,4828,4829,4832,4835],{"class":355,"line":2328},[353,4830,4831],{"class":696},"错误：gitlab-ce-13.1.4-ce.0.el8.x86_64:",[353,4833,4834],{"class":390}," 删除",[353,4836,4837],{"class":390}," 已跳过\n",[353,4839,4840],{"class":355,"line":2334},[353,4841,3483],{"emptyLinePlaceholder":307},[353,4843,4844],{"class":355,"line":2348},[353,4845,4846],{"class":696},"OR\n",[353,4848,4849,4852,4855,4857,4860,4863,4866,4869,4872,4874],{"class":355,"line":2362},[353,4850,4851],{"class":696},"error:",[353,4853,4854],{"class":390}," prein",[353,4856,384],{"class":363},[353,4858,4859],{"class":696},"gitlab-ce-13.1.11-ce.0.el8.x86_64",[353,4861,4862],{"class":363},")",[353,4864,4865],{"class":390},"scriptlet",[353,4867,4868],{"class":390}," failed,",[353,4870,4871],{"class":390}," exit",[353,4873,2138],{"class":390},[353,4875,4876],{"class":739}," 1\n",[12,4878,4879],{},"用 rpm -Uvvh 查看安装详情，发现错误如下：",[344,4881,4883],{"className":687,"code":4882,"language":689,"meta":293,"style":293},"+ upgrade_check\n++ gitlab-ctl upgrade-check 13.1.4 13.13.1\n\u002Fbin\u002Fbash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)\n+ ctl_results='[2020-10-01T21:17:45+08:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.\nI don'\\''t know that command.\nomnibus-ctl: command (subcommand)\ncheck-config\n\n.........\n\nContainer Registry Commands:\n  registry-garbage-collect\n    Run Container Registry garbage collection.'\n+ found='[2020-10-01T21:17:45+08:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.'\n+ '[' '[2020-10-01T21:17:45+08:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.' '!=' 'I don'\\''t know that command.' ']'\n+ exit 1\nD: %prein(gitlab-ce-13.1.11-ce.0.el8.x86_64): waitpid(35960) rc 35960 status 100\nerror: %prein(gitlab-ce-13.1.11-ce.0.el8.x86_64) scriptlet failed, exit status 1\nufdio:       6 reads,  8219028 total bytes in 0.001505 secs\nerror: gitlab-ce-13.1.11-ce.0.el8.x86_64: install failed\n",[350,4884,4885,4893,4910,4936,4948,4963,4968,4973,4977,4982,4986,4991,4996,5003,5017,5062,5070,5107,5129,5157],{"__ignoreMap":293},[353,4886,4887,4890],{"class":355,"line":356},[353,4888,4889],{"class":696},"+",[353,4891,4892],{"class":390}," upgrade_check\n",[353,4894,4895,4898,4901,4904,4907],{"class":355,"line":297},[353,4896,4897],{"class":696},"++",[353,4899,4900],{"class":390}," gitlab-ctl",[353,4902,4903],{"class":390}," upgrade-check",[353,4905,4906],{"class":739}," 13.1.4",[353,4908,4909],{"class":739}," 13.13.1\n",[353,4911,4912,4915,4918,4921,4924,4927,4930,4933],{"class":355,"line":294},[353,4913,4914],{"class":696},"\u002Fbin\u002Fbash:",[353,4916,4917],{"class":390}," warning:",[353,4919,4920],{"class":390}," setlocale:",[353,4922,4923],{"class":390}," LC_ALL:",[353,4925,4926],{"class":390}," cannot",[353,4928,4929],{"class":390}," change",[353,4931,4932],{"class":390}," locale",[353,4934,4935],{"class":367}," (en_US.UTF-8)\n",[353,4937,4938,4940,4943,4945],{"class":355,"line":721},[353,4939,4889],{"class":696},[353,4941,4942],{"class":390}," ctl_results=",[353,4944,387],{"class":363},[353,4946,4947],{"class":390},"[2020-10-01T21:17:45+08:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.\n",[353,4949,4950,4953,4955,4958,4960],{"class":355,"line":1584},[353,4951,4952],{"class":390},"I don",[353,4954,387],{"class":363},[353,4956,4957],{"class":367},"\\'",[353,4959,387],{"class":363},[353,4961,4962],{"class":390},"t know that command.\n",[353,4964,4965],{"class":355,"line":2317},[353,4966,4967],{"class":390},"omnibus-ctl: command (subcommand)\n",[353,4969,4970],{"class":355,"line":2328},[353,4971,4972],{"class":390},"check-config\n",[353,4974,4975],{"class":355,"line":2334},[353,4976,3483],{"emptyLinePlaceholder":307},[353,4978,4979],{"class":355,"line":2348},[353,4980,4981],{"class":390},".........\n",[353,4983,4984],{"class":355,"line":2362},[353,4985,3483],{"emptyLinePlaceholder":307},[353,4987,4988],{"class":355,"line":2376},[353,4989,4990],{"class":390},"Container Registry Commands:\n",[353,4992,4993],{"class":355,"line":3172},[353,4994,4995],{"class":390},"  registry-garbage-collect\n",[353,4997,4998,5001],{"class":355,"line":3245},[353,4999,5000],{"class":390},"    Run Container Registry garbage collection.",[353,5002,2307],{"class":363},[353,5004,5005,5007,5010,5012,5015],{"class":355,"line":3251},[353,5006,4889],{"class":696},[353,5008,5009],{"class":390}," found=",[353,5011,387],{"class":363},[353,5013,5014],{"class":390},"[2020-10-01T21:17:45+08:00] WARN: Please install an English UTF-8 locale for Chef to use, falling back to C locale and disabling UTF-8 support.",[353,5016,2307],{"class":363},[353,5018,5019,5021,5024,5026,5028,5030,5032,5034,5036,5039,5041,5043,5045,5047,5049,5051,5054,5056,5058,5060],{"class":355,"line":3257},[353,5020,4889],{"class":696},[353,5022,5023],{"class":363}," '",[353,5025,4274],{"class":390},[353,5027,387],{"class":363},[353,5029,5023],{"class":363},[353,5031,5014],{"class":390},[353,5033,387],{"class":363},[353,5035,5023],{"class":363},[353,5037,5038],{"class":390},"!=",[353,5040,387],{"class":363},[353,5042,5023],{"class":363},[353,5044,4952],{"class":390},[353,5046,387],{"class":363},[353,5048,4957],{"class":367},[353,5050,387],{"class":363},[353,5052,5053],{"class":390},"t know that command.",[353,5055,387],{"class":363},[353,5057,5023],{"class":363},[353,5059,4417],{"class":390},[353,5061,2307],{"class":363},[353,5063,5064,5066,5068],{"class":355,"line":3263},[353,5065,4889],{"class":696},[353,5067,4871],{"class":390},[353,5069,4876],{"class":739},[353,5071,5072,5075,5078,5080,5082,5084,5086,5089,5091,5094,5096,5099,5102,5104],{"class":355,"line":3269},[353,5073,5074],{"class":696},"D:",[353,5076,5077],{"class":390}," %prein",[353,5079,384],{"class":363},[353,5081,4859],{"class":696},[353,5083,4862],{"class":363},[353,5085,2660],{"class":390},[353,5087,5088],{"class":390}," waitpid",[353,5090,384],{"class":363},[353,5092,5093],{"class":696},"35960",[353,5095,4862],{"class":363},[353,5097,5098],{"class":390}," rc",[353,5100,5101],{"class":739}," 35960",[353,5103,2138],{"class":390},[353,5105,5106],{"class":739}," 100\n",[353,5108,5109,5111,5113,5115,5117,5119,5121,5123,5125,5127],{"class":355,"line":3275},[353,5110,4851],{"class":696},[353,5112,5077],{"class":390},[353,5114,384],{"class":363},[353,5116,4859],{"class":696},[353,5118,4862],{"class":363},[353,5120,4670],{"class":390},[353,5122,4868],{"class":390},[353,5124,4871],{"class":390},[353,5126,2138],{"class":390},[353,5128,4876],{"class":739},[353,5130,5131,5134,5137,5140,5143,5146,5149,5151,5154],{"class":355,"line":3280},[353,5132,5133],{"class":696},"ufdio:",[353,5135,5136],{"class":739},"       6",[353,5138,5139],{"class":390}," reads,",[353,5141,5142],{"class":739},"  8219028",[353,5144,5145],{"class":390}," total",[353,5147,5148],{"class":390}," bytes",[353,5150,4664],{"class":390},[353,5152,5153],{"class":739}," 0.001505",[353,5155,5156],{"class":390}," secs\n",[353,5158,5159,5161,5164,5166],{"class":355,"line":3286},[353,5160,4851],{"class":696},[353,5162,5163],{"class":390}," gitlab-ce-13.1.11-ce.0.el8.x86_64:",[353,5165,4320],{"class":390},[353,5167,4299],{"class":390},[12,5169,5170],{},"可能是因为我安装系统的时候选择了中文，系统里竟然没有英文语言包？！\nlocale -a 如下：",[344,5172,5174],{"className":687,"code":5173,"language":689,"meta":293,"style":293},"[root@HyperV-GitLab ~]# vi \u002Fetc\u002Fenvironment\n[root@HyperV-GitLab ~]# locale -a\nlocale: Cannot set LC_CTYPE to default locale: No such file or directory\nlocale: Cannot set LC_MESSAGES to default locale: No such file or directory\nlocale: Cannot set LC_COLLATE to default locale: No such file or directory\nC\nC.utf8\nPOSIX\nzh_CN\nzh_CN.gb18030\nzh_CN.gbk\nzh_CN.utf8\nzh_HK\nzh_HK.utf8\nzh_SG\nzh_SG.gbk\nzh_SG.utf8\nzh_TW\nzh_TW.euctw\nzh_TW.utf8\n",[350,5175,5176,5189,5200,5238,5265,5292,5297,5302,5307,5312,5317,5322,5327,5332,5337,5342,5347,5352,5357,5362],{"__ignoreMap":293},[353,5177,5178,5180,5183,5186],{"class":355,"line":356},[353,5179,4274],{"class":363},[353,5181,5182],{"class":367},"root@HyperV-GitLab ",[353,5184,5185],{"class":363},"~]",[353,5187,5188],{"class":367},"# vi \u002Fetc\u002Fenvironment\n",[353,5190,5191,5193,5195,5197],{"class":355,"line":297},[353,5192,4274],{"class":363},[353,5194,5182],{"class":367},[353,5196,5185],{"class":363},[353,5198,5199],{"class":367},"# locale -a\n",[353,5201,5202,5205,5208,5211,5214,5217,5220,5223,5226,5229,5232,5235],{"class":355,"line":294},[353,5203,5204],{"class":696},"locale:",[353,5206,5207],{"class":390}," Cannot",[353,5209,5210],{"class":390}," set",[353,5212,5213],{"class":390}," LC_CTYPE",[353,5215,5216],{"class":390}," to",[353,5218,5219],{"class":390}," default",[353,5221,5222],{"class":390}," locale:",[353,5224,5225],{"class":390}," No",[353,5227,5228],{"class":390}," such",[353,5230,5231],{"class":390}," file",[353,5233,5234],{"class":390}," or",[353,5236,5237],{"class":390}," directory\n",[353,5239,5240,5242,5244,5246,5249,5251,5253,5255,5257,5259,5261,5263],{"class":355,"line":721},[353,5241,5204],{"class":696},[353,5243,5207],{"class":390},[353,5245,5210],{"class":390},[353,5247,5248],{"class":390}," LC_MESSAGES",[353,5250,5216],{"class":390},[353,5252,5219],{"class":390},[353,5254,5222],{"class":390},[353,5256,5225],{"class":390},[353,5258,5228],{"class":390},[353,5260,5231],{"class":390},[353,5262,5234],{"class":390},[353,5264,5237],{"class":390},[353,5266,5267,5269,5271,5273,5276,5278,5280,5282,5284,5286,5288,5290],{"class":355,"line":1584},[353,5268,5204],{"class":696},[353,5270,5207],{"class":390},[353,5272,5210],{"class":390},[353,5274,5275],{"class":390}," LC_COLLATE",[353,5277,5216],{"class":390},[353,5279,5219],{"class":390},[353,5281,5222],{"class":390},[353,5283,5225],{"class":390},[353,5285,5228],{"class":390},[353,5287,5231],{"class":390},[353,5289,5234],{"class":390},[353,5291,5237],{"class":390},[353,5293,5294],{"class":355,"line":2317},[353,5295,5296],{"class":696},"C\n",[353,5298,5299],{"class":355,"line":2328},[353,5300,5301],{"class":696},"C.utf8\n",[353,5303,5304],{"class":355,"line":2334},[353,5305,5306],{"class":696},"POSIX\n",[353,5308,5309],{"class":355,"line":2348},[353,5310,5311],{"class":696},"zh_CN\n",[353,5313,5314],{"class":355,"line":2362},[353,5315,5316],{"class":696},"zh_CN.gb18030\n",[353,5318,5319],{"class":355,"line":2376},[353,5320,5321],{"class":696},"zh_CN.gbk\n",[353,5323,5324],{"class":355,"line":3172},[353,5325,5326],{"class":696},"zh_CN.utf8\n",[353,5328,5329],{"class":355,"line":3245},[353,5330,5331],{"class":696},"zh_HK\n",[353,5333,5334],{"class":355,"line":3251},[353,5335,5336],{"class":696},"zh_HK.utf8\n",[353,5338,5339],{"class":355,"line":3257},[353,5340,5341],{"class":696},"zh_SG\n",[353,5343,5344],{"class":355,"line":3263},[353,5345,5346],{"class":696},"zh_SG.gbk\n",[353,5348,5349],{"class":355,"line":3269},[353,5350,5351],{"class":696},"zh_SG.utf8\n",[353,5353,5354],{"class":355,"line":3275},[353,5355,5356],{"class":696},"zh_TW\n",[353,5358,5359],{"class":355,"line":3280},[353,5360,5361],{"class":696},"zh_TW.euctw\n",[353,5363,5364],{"class":355,"line":3286},[353,5365,5366],{"class":696},"zh_TW.utf8\n",[12,5368,5369],{},"解决方法：\n安装英文语言包",[344,5371,5373],{"className":687,"code":5372,"language":689,"meta":293,"style":293},"yum install langpacks-en.noarch\n",[350,5374,5375],{"__ignoreMap":293},[353,5376,5377,5380,5382],{"class":355,"line":356},[353,5378,5379],{"class":696},"yum",[353,5381,4320],{"class":390},[353,5383,5384],{"class":390}," langpacks-en.noarch\n",[1779,5386,5387],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":293,"searchDepth":294,"depth":294,"links":5389},[5390,5391,5392,5393],{"id":4099,"depth":294,"text":4099},{"id":4111,"depth":294,"text":4112},{"id":4132,"depth":294,"text":4133},{"id":4398,"depth":294,"text":4399},"从 11 升到 13 的路上踩了三个坑：不能跨大版本、pg_dump 版本不匹配，以及系统没装英文语言包导致 rpm 安装脚本失败。",{},"\u002Fposts\u002Fgitlab-ce-upgrade-11-to-13",{"title":4094,"description":5394},"posts\u002Fgitlab-ce-upgrade-11-to-13",[5400,2470,2469],"GitLab","7OR6js5u1xKuSqCjnlh6LVlCEpRSzWCW0urRoqaJ980",{"id":5403,"title":5404,"body":5405,"date":6666,"description":6667,"extension":305,"meta":6668,"navigation":307,"path":6669,"seo":6670,"stem":6671,"tags":6672,"__hash__":6674},"posts\u002Fposts\u002Fjar2pom-maven-dependency.md","基于 Maven 中心库，通过 Jar 包生成 POM 的 dependency",{"type":9,"value":5406,"toc":6658},[5407,5409,5428,5431,5434,5440,5459,5462,6281,6285,6292,6301,6304,6472,6479,6499,6527,6533,6536,6539,6626,6628,6645,6656],[34,5408,409],{"id":409},[12,5410,5411,5412,5417,5418,5423,5424,406],{},"之前写过一篇",[96,5413,5416],{"href":5414,"rel":5415},"https:\u002F\u002Fblog.csdn.net\u002FJustinJia91\u002Farticle\u002Fdetails\u002F79605682",[100],"通过 Jar 包生成 Maven POM.xml 的 dependency","，方便将非 Maven 项目转换为 Maven 项目。\n原项目对 Jar 的搜索基于 Nexus2 的相关接口开发，随着很多仓库从 Nexus2 升级到 Nexus3 或者其他服务，原项目渐渐不可用了。\n新代码将 Nexus2 接口改为对接 ",[96,5419,5422],{"href":5420,"rel":5421},"https:\u002F\u002Fsearch.maven.org\u002F",[100],"Maven 中心库","。站内另留了一份 ",[96,5425,5427],{"href":5426},"\u002Fposts\u002Fjar2pom-nexus2-dependency","Nexus2 版的代码",[34,5429,5430],{"id":5430},"项目结构",[12,5432,5433],{},"整个项目只有 6 个 Java 文件 —— 一个主类，加上五个用来接中心库返回值的实体类：",[344,5435,5438],{"className":5436,"code":5437,"language":2831},[2829],"jar2pom\n├── pom.xml\n└── src\u002Fmain\u002Fjava\u002Fcom\u002Fjxh\u002Ftool\n    ├── Jar2pom.java              # 主类：遍历目录里的 jar、查坐标、打印 dependency\n    └── entity\n        ├── SolrSearch.java       # 响应根节点\n        ├── ResponseHeader.java   # 状态码与耗时\n        ├── Response.java         # 结果集\n        ├── Docs.java             # 单条坐标\n        └── Spellcheck.java       # 拼写建议\n",[350,5439,5437],{"__ignoreMap":293},[12,5441,5442,5443,5446,5447,5450,5451,5454,5455,5458],{},"Maven 坐标是 ",[350,5444,5445],{},"cn.jxh.tool:jar2pom:2.0-SNAPSHOT","，依赖只有三个：",[350,5448,5449],{},"httpclient"," 4.5.5 负责发请求，",[350,5452,5453],{},"fastjson"," 1.2.68 负责解 JSON，",[350,5456,5457],{},"dom4j"," 负责拼 XML。README 里记的开发环境是 JDK 1.7 + Maven 3.5 + IDEA 社区版。",[34,5460,5461],{"id":5461},"核心代码",[344,5463,5465],{"className":3415,"code":5464,"language":2796,"meta":293,"style":293},"    public static void main(String[] args) {\n        \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n        File libs = new File(\"D:\\\\lib\");\n        for (File jar : libs.listFiles()) {\n\n            System.out.println(\"\u003C!--  \" + jar.getName() + \" -->\");\n\n            Docs doc = getPomByChecksum(jar);\n            if (null != doc) {\n                System.out.println(\"\u003C!--  Search by Checksum -->\");\n                System.out.println(assemblePomElement(doc).asXML());\n                continue;\n            }\n\n            doc = getPomByManifest(jar);\n            if (null != doc) {\n                System.out.println(\"\u003C!--  Search by Manifest -->\");\n                System.out.println(assemblePomElement(doc).asXML());\n                continue;\n            }\n\n            System.out.println(\"\u003C!--  No data was found -->\");\n\n            System.out.println();\n        }\n\n    }\n\n    \u002F**\n     * 通过Jar SHA1返回Pom dependency\n     *\n     * @param file\n     * @return\n     *\u002F\n    public static Docs getPomByChecksum(File file) {\n        Docs docs = null;\n\n        String checkSum = getCheckSum(file, \"SHA1\");\n        String jsonString = doGet(nexusUrl + \"&q=1:\" + checkSum);\n        SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n\n        if (solrSearch.getResponseHeader().getStatus() == 0 && solrSearch.getResponse().getDocs().size() > 0) {\n            docs = solrSearch.getResponse().getDocs().get(0);\n        }\n        return docs;\n    }\n\n\n    \u002F**\n     * 通过Jar Manifest返回Pom dependency\n     *\n     * @param file\n     * @return\n     *\u002F\n    public static Docs getPomByManifest(File file) {\n        Docs docs = null;\n\n        try {\n            JarFile jarfile = new JarFile(file);\n            Manifest mainmanifest = jarfile.getManifest();\n            jarfile.close();\n            if (null == mainmanifest) {\n                return null;\n            }\n            String a = null, v = null;\n            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Extension-Name\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Extension-Name\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Title\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Title\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Title\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Title\"));\n            }\n            if (a != null && a.length() != 0) {\n                a = a.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n            }\n            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Bundle-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Bundle-Version\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Version\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Version\"));\n            }\n            if (v != null && v.length() != 0) {\n                v = v.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n            }\n            String jsonString = doGet(nexusUrl + \"&q=a:\" + a + \"%20v:\" + v);\n            SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n\n            if (solrSearch.getResponseHeader().getStatus() == 0) {\n                docs = solrSearch.getResponse().getDocs().get(0);\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return docs;\n    }\n\n    \u002F**\n     * 组装 dependency\n     *\n     * @param docs\n     * @return\n     *\u002F\n    public static Element assemblePomElement(Docs docs) {\n        Element dependency = new DOMElement(\"dependency\");\n        if (docs != null) {\n            dependency.addAttribute(\"groupId\", docs.getG());\n            dependency.addAttribute(\"artifactId\", docs.getA());\n            dependency.addAttribute(\"version\", docs.getV());\n        }\n        return dependency;\n    }\n\n    \u002F**\n     * 发起Get请求\n     *\n     * @param url\n     * @return\n     *\u002F\n    public static String doGet(String url) {\n        String srtResult = null;\n        CloseableHttpClient httpCilent = HttpClients.createDefault();\n        HttpGet httpGet = new HttpGet(url);\n        try {\n            HttpResponse httpResponse = httpCilent.execute(httpGet);\n            srtResult = EntityUtils.toString(httpResponse.getEntity());\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                httpCilent.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return srtResult;\n    }\n\n    \u002F**\n     * 计算CheckSum\n     *\n     * @param file\n     * @param algorithm SHA1 or MD5\n     * @return\n     *\u002F\n    public static String getCheckSum(File file, String algorithm) {\n        if (!file.isFile()) {\n            return null;\n        }\n        MessageDigest digest = null;\n        FileInputStream in = null;\n        byte buffer[] = new byte[1024];\n        int len;\n        try {\n            digest = MessageDigest.getInstance(algorithm);\n            in = new FileInputStream(file);\n            while ((len = in.read(buffer, 0, 1024)) != -1) {\n                digest.update(buffer, 0, len);\n            }\n            in.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n        BigInteger bigInt = new BigInteger(1, digest.digest());\n        return bigInt.toString(16);\n    }\n",[350,5466,5467,5472,5477,5482,5487,5491,5496,5500,5505,5510,5515,5520,5525,5529,5533,5538,5542,5547,5551,5555,5559,5563,5568,5572,5577,5581,5585,5589,5593,5597,5602,5606,5611,5615,5619,5624,5629,5633,5638,5643,5648,5652,5657,5662,5666,5671,5675,5679,5683,5687,5692,5696,5700,5704,5708,5713,5717,5721,5726,5731,5736,5741,5746,5751,5755,5760,5765,5770,5775,5780,5785,5790,5794,5799,5804,5808,5813,5818,5823,5828,5833,5838,5842,5847,5852,5856,5861,5866,5870,5875,5880,5884,5889,5894,5898,5902,5906,5910,5914,5919,5923,5928,5932,5936,5941,5946,5951,5956,5961,5966,5970,5975,5979,5983,5987,5992,5996,6002,6007,6012,6018,6024,6030,6036,6041,6047,6053,6058,6063,6069,6075,6081,6087,6093,6098,6103,6109,6114,6119,6124,6130,6135,6140,6146,6151,6156,6162,6168,6174,6179,6185,6191,6197,6203,6208,6214,6220,6226,6232,6237,6243,6249,6254,6259,6264,6270,6276],{"__ignoreMap":293},[353,5468,5469],{"class":355,"line":356},[353,5470,5471],{},"    public static void main(String[] args) {\n",[353,5473,5474],{"class":355,"line":297},[353,5475,5476],{},"        \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n",[353,5478,5479],{"class":355,"line":294},[353,5480,5481],{},"        File libs = new File(\"D:\\\\lib\");\n",[353,5483,5484],{"class":355,"line":721},[353,5485,5486],{},"        for (File jar : libs.listFiles()) {\n",[353,5488,5489],{"class":355,"line":1584},[353,5490,3483],{"emptyLinePlaceholder":307},[353,5492,5493],{"class":355,"line":2317},[353,5494,5495],{},"            System.out.println(\"\u003C!--  \" + jar.getName() + \" -->\");\n",[353,5497,5498],{"class":355,"line":2328},[353,5499,3483],{"emptyLinePlaceholder":307},[353,5501,5502],{"class":355,"line":2334},[353,5503,5504],{},"            Docs doc = getPomByChecksum(jar);\n",[353,5506,5507],{"class":355,"line":2348},[353,5508,5509],{},"            if (null != doc) {\n",[353,5511,5512],{"class":355,"line":2362},[353,5513,5514],{},"                System.out.println(\"\u003C!--  Search by Checksum -->\");\n",[353,5516,5517],{"class":355,"line":2376},[353,5518,5519],{},"                System.out.println(assemblePomElement(doc).asXML());\n",[353,5521,5522],{"class":355,"line":3172},[353,5523,5524],{},"                continue;\n",[353,5526,5527],{"class":355,"line":3245},[353,5528,3868],{},[353,5530,5531],{"class":355,"line":3251},[353,5532,3483],{"emptyLinePlaceholder":307},[353,5534,5535],{"class":355,"line":3257},[353,5536,5537],{},"            doc = getPomByManifest(jar);\n",[353,5539,5540],{"class":355,"line":3263},[353,5541,5509],{},[353,5543,5544],{"class":355,"line":3269},[353,5545,5546],{},"                System.out.println(\"\u003C!--  Search by Manifest -->\");\n",[353,5548,5549],{"class":355,"line":3275},[353,5550,5519],{},[353,5552,5553],{"class":355,"line":3280},[353,5554,5524],{},[353,5556,5557],{"class":355,"line":3286},[353,5558,3868],{},[353,5560,5561],{"class":355,"line":3291},[353,5562,3483],{"emptyLinePlaceholder":307},[353,5564,5565],{"class":355,"line":3525},[353,5566,5567],{},"            System.out.println(\"\u003C!--  No data was found -->\");\n",[353,5569,5570],{"class":355,"line":3531},[353,5571,3483],{"emptyLinePlaceholder":307},[353,5573,5574],{"class":355,"line":3537},[353,5575,5576],{},"            System.out.println();\n",[353,5578,5579],{"class":355,"line":3543},[353,5580,4036],{},[353,5582,5583],{"class":355,"line":3548},[353,5584,3483],{"emptyLinePlaceholder":307},[353,5586,5587],{"class":355,"line":3554},[353,5588,3635],{},[353,5590,5591],{"class":355,"line":3559},[353,5592,3483],{"emptyLinePlaceholder":307},[353,5594,5595],{"class":355,"line":3565},[353,5596,3646],{},[353,5598,5599],{"class":355,"line":3571},[353,5600,5601],{},"     * 通过Jar SHA1返回Pom dependency\n",[353,5603,5604],{"class":355,"line":3576},[353,5605,3658],{},[353,5607,5608],{"class":355,"line":3581},[353,5609,5610],{},"     * @param file\n",[353,5612,5613],{"class":355,"line":3587},[353,5614,3664],{},[353,5616,5617],{"class":355,"line":3592},[353,5618,3670],{},[353,5620,5621],{"class":355,"line":3598},[353,5622,5623],{},"    public static Docs getPomByChecksum(File file) {\n",[353,5625,5626],{"class":355,"line":3603},[353,5627,5628],{},"        Docs docs = null;\n",[353,5630,5631],{"class":355,"line":3609},[353,5632,3483],{"emptyLinePlaceholder":307},[353,5634,5635],{"class":355,"line":3614},[353,5636,5637],{},"        String checkSum = getCheckSum(file, \"SHA1\");\n",[353,5639,5640],{"class":355,"line":3620},[353,5641,5642],{},"        String jsonString = doGet(nexusUrl + \"&q=1:\" + checkSum);\n",[353,5644,5645],{"class":355,"line":3626},[353,5646,5647],{},"        SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[353,5649,5650],{"class":355,"line":3632},[353,5651,3483],{"emptyLinePlaceholder":307},[353,5653,5654],{"class":355,"line":3638},[353,5655,5656],{},"        if (solrSearch.getResponseHeader().getStatus() == 0 && solrSearch.getResponse().getDocs().size() > 0) {\n",[353,5658,5659],{"class":355,"line":3643},[353,5660,5661],{},"            docs = solrSearch.getResponse().getDocs().get(0);\n",[353,5663,5664],{"class":355,"line":3649},[353,5665,4036],{},[353,5667,5668],{"class":355,"line":3655},[353,5669,5670],{},"        return docs;\n",[353,5672,5673],{"class":355,"line":3661},[353,5674,3635],{},[353,5676,5677],{"class":355,"line":3667},[353,5678,3483],{"emptyLinePlaceholder":307},[353,5680,5681],{"class":355,"line":3673},[353,5682,3483],{"emptyLinePlaceholder":307},[353,5684,5685],{"class":355,"line":3679},[353,5686,3646],{},[353,5688,5689],{"class":355,"line":3685},[353,5690,5691],{},"     * 通过Jar Manifest返回Pom dependency\n",[353,5693,5694],{"class":355,"line":3690},[353,5695,3658],{},[353,5697,5698],{"class":355,"line":3695},[353,5699,5610],{},[353,5701,5702],{"class":355,"line":3700},[353,5703,3664],{},[353,5705,5706],{"class":355,"line":3706},[353,5707,3670],{},[353,5709,5710],{"class":355,"line":3711},[353,5711,5712],{},"    public static Docs getPomByManifest(File file) {\n",[353,5714,5715],{"class":355,"line":3716},[353,5716,5628],{},[353,5718,5719],{"class":355,"line":3721},[353,5720,3483],{"emptyLinePlaceholder":307},[353,5722,5723],{"class":355,"line":3727},[353,5724,5725],{},"        try {\n",[353,5727,5728],{"class":355,"line":3733},[353,5729,5730],{},"            JarFile jarfile = new JarFile(file);\n",[353,5732,5733],{"class":355,"line":3738},[353,5734,5735],{},"            Manifest mainmanifest = jarfile.getManifest();\n",[353,5737,5738],{"class":355,"line":3743},[353,5739,5740],{},"            jarfile.close();\n",[353,5742,5743],{"class":355,"line":3748},[353,5744,5745],{},"            if (null == mainmanifest) {\n",[353,5747,5748],{"class":355,"line":3754},[353,5749,5750],{},"                return null;\n",[353,5752,5753],{"class":355,"line":3759},[353,5754,3868],{},[353,5756,5757],{"class":355,"line":3765},[353,5758,5759],{},"            String a = null, v = null;\n",[353,5761,5762],{"class":355,"line":3770},[353,5763,5764],{},"            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Extension-Name\"))) {\n",[353,5766,5767],{"class":355,"line":3776},[353,5768,5769],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Extension-Name\"));\n",[353,5771,5772],{"class":355,"line":3782},[353,5773,5774],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Title\"))) {\n",[353,5776,5777],{"class":355,"line":3788},[353,5778,5779],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Title\"));\n",[353,5781,5782],{"class":355,"line":3794},[353,5783,5784],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Title\"))) {\n",[353,5786,5787],{"class":355,"line":3800},[353,5788,5789],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Title\"));\n",[353,5791,5792],{"class":355,"line":3806},[353,5793,3868],{},[353,5795,5796],{"class":355,"line":3812},[353,5797,5798],{},"            if (a != null && a.length() != 0) {\n",[353,5800,5801],{"class":355,"line":3818},[353,5802,5803],{},"                a = a.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n",[353,5805,5806],{"class":355,"line":3824},[353,5807,3868],{},[353,5809,5810],{"class":355,"line":3830},[353,5811,5812],{},"            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Bundle-Version\"))) {\n",[353,5814,5815],{"class":355,"line":3836},[353,5816,5817],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Bundle-Version\"));\n",[353,5819,5820],{"class":355,"line":3841},[353,5821,5822],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Version\"))) {\n",[353,5824,5825],{"class":355,"line":3847},[353,5826,5827],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Version\"));\n",[353,5829,5830],{"class":355,"line":3853},[353,5831,5832],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Version\"))) {\n",[353,5834,5835],{"class":355,"line":3859},[353,5836,5837],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Version\"));\n",[353,5839,5840],{"class":355,"line":3865},[353,5841,3868],{},[353,5843,5844],{"class":355,"line":3871},[353,5845,5846],{},"            if (v != null && v.length() != 0) {\n",[353,5848,5849],{"class":355,"line":3877},[353,5850,5851],{},"                v = v.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n",[353,5853,5854],{"class":355,"line":3882},[353,5855,3868],{},[353,5857,5858],{"class":355,"line":3887},[353,5859,5860],{},"            String jsonString = doGet(nexusUrl + \"&q=a:\" + a + \"%20v:\" + v);\n",[353,5862,5863],{"class":355,"line":3892},[353,5864,5865],{},"            SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[353,5867,5868],{"class":355,"line":3898},[353,5869,3483],{"emptyLinePlaceholder":307},[353,5871,5872],{"class":355,"line":3903},[353,5873,5874],{},"            if (solrSearch.getResponseHeader().getStatus() == 0) {\n",[353,5876,5877],{"class":355,"line":3909},[353,5878,5879],{},"                docs = solrSearch.getResponse().getDocs().get(0);\n",[353,5881,5882],{"class":355,"line":3914},[353,5883,3868],{},[353,5885,5886],{"class":355,"line":3919},[353,5887,5888],{},"        } catch (IOException e) {\n",[353,5890,5891],{"class":355,"line":3925},[353,5892,5893],{},"            e.printStackTrace();\n",[353,5895,5896],{"class":355,"line":3931},[353,5897,4036],{},[353,5899,5900],{"class":355,"line":3937},[353,5901,5670],{},[353,5903,5904],{"class":355,"line":3943},[353,5905,3635],{},[353,5907,5908],{"class":355,"line":3949},[353,5909,3483],{"emptyLinePlaceholder":307},[353,5911,5912],{"class":355,"line":3955},[353,5913,3646],{},[353,5915,5916],{"class":355,"line":3960},[353,5917,5918],{},"     * 组装 dependency\n",[353,5920,5921],{"class":355,"line":3965},[353,5922,3658],{},[353,5924,5925],{"class":355,"line":3970},[353,5926,5927],{},"     * @param docs\n",[353,5929,5930],{"class":355,"line":3976},[353,5931,3664],{},[353,5933,5934],{"class":355,"line":3981},[353,5935,3670],{},[353,5937,5938],{"class":355,"line":3987},[353,5939,5940],{},"    public static Element assemblePomElement(Docs docs) {\n",[353,5942,5943],{"class":355,"line":3993},[353,5944,5945],{},"        Element dependency = new DOMElement(\"dependency\");\n",[353,5947,5948],{"class":355,"line":3998},[353,5949,5950],{},"        if (docs != null) {\n",[353,5952,5953],{"class":355,"line":4003},[353,5954,5955],{},"            dependency.addAttribute(\"groupId\", docs.getG());\n",[353,5957,5958],{"class":355,"line":4009},[353,5959,5960],{},"            dependency.addAttribute(\"artifactId\", docs.getA());\n",[353,5962,5963],{"class":355,"line":4015},[353,5964,5965],{},"            dependency.addAttribute(\"version\", docs.getV());\n",[353,5967,5968],{"class":355,"line":4021},[353,5969,4036],{},[353,5971,5972],{"class":355,"line":4027},[353,5973,5974],{},"        return dependency;\n",[353,5976,5977],{"class":355,"line":4033},[353,5978,3635],{},[353,5980,5981],{"class":355,"line":4039},[353,5982,3483],{"emptyLinePlaceholder":307},[353,5984,5985],{"class":355,"line":4045},[353,5986,3646],{},[353,5988,5989],{"class":355,"line":4050},[353,5990,5991],{},"     * 发起Get请求\n",[353,5993,5994],{"class":355,"line":4055},[353,5995,3658],{},[353,5997,5999],{"class":355,"line":5998},117,[353,6000,6001],{},"     * @param url\n",[353,6003,6005],{"class":355,"line":6004},118,[353,6006,3664],{},[353,6008,6010],{"class":355,"line":6009},119,[353,6011,3670],{},[353,6013,6015],{"class":355,"line":6014},120,[353,6016,6017],{},"    public static String doGet(String url) {\n",[353,6019,6021],{"class":355,"line":6020},121,[353,6022,6023],{},"        String srtResult = null;\n",[353,6025,6027],{"class":355,"line":6026},122,[353,6028,6029],{},"        CloseableHttpClient httpCilent = HttpClients.createDefault();\n",[353,6031,6033],{"class":355,"line":6032},123,[353,6034,6035],{},"        HttpGet httpGet = new HttpGet(url);\n",[353,6037,6039],{"class":355,"line":6038},124,[353,6040,5725],{},[353,6042,6044],{"class":355,"line":6043},125,[353,6045,6046],{},"            HttpResponse httpResponse = httpCilent.execute(httpGet);\n",[353,6048,6050],{"class":355,"line":6049},126,[353,6051,6052],{},"            srtResult = EntityUtils.toString(httpResponse.getEntity());\n",[353,6054,6056],{"class":355,"line":6055},127,[353,6057,5888],{},[353,6059,6061],{"class":355,"line":6060},128,[353,6062,5893],{},[353,6064,6066],{"class":355,"line":6065},129,[353,6067,6068],{},"        } finally {\n",[353,6070,6072],{"class":355,"line":6071},130,[353,6073,6074],{},"            try {\n",[353,6076,6078],{"class":355,"line":6077},131,[353,6079,6080],{},"                httpCilent.close();\n",[353,6082,6084],{"class":355,"line":6083},132,[353,6085,6086],{},"            } catch (IOException e) {\n",[353,6088,6090],{"class":355,"line":6089},133,[353,6091,6092],{},"                e.printStackTrace();\n",[353,6094,6096],{"class":355,"line":6095},134,[353,6097,3868],{},[353,6099,6101],{"class":355,"line":6100},135,[353,6102,4036],{},[353,6104,6106],{"class":355,"line":6105},136,[353,6107,6108],{},"        return srtResult;\n",[353,6110,6112],{"class":355,"line":6111},137,[353,6113,3635],{},[353,6115,6117],{"class":355,"line":6116},138,[353,6118,3483],{"emptyLinePlaceholder":307},[353,6120,6122],{"class":355,"line":6121},139,[353,6123,3646],{},[353,6125,6127],{"class":355,"line":6126},140,[353,6128,6129],{},"     * 计算CheckSum\n",[353,6131,6133],{"class":355,"line":6132},141,[353,6134,3658],{},[353,6136,6138],{"class":355,"line":6137},142,[353,6139,5610],{},[353,6141,6143],{"class":355,"line":6142},143,[353,6144,6145],{},"     * @param algorithm SHA1 or MD5\n",[353,6147,6149],{"class":355,"line":6148},144,[353,6150,3664],{},[353,6152,6154],{"class":355,"line":6153},145,[353,6155,3670],{},[353,6157,6159],{"class":355,"line":6158},146,[353,6160,6161],{},"    public static String getCheckSum(File file, String algorithm) {\n",[353,6163,6165],{"class":355,"line":6164},147,[353,6166,6167],{},"        if (!file.isFile()) {\n",[353,6169,6171],{"class":355,"line":6170},148,[353,6172,6173],{},"            return null;\n",[353,6175,6177],{"class":355,"line":6176},149,[353,6178,4036],{},[353,6180,6182],{"class":355,"line":6181},150,[353,6183,6184],{},"        MessageDigest digest = null;\n",[353,6186,6188],{"class":355,"line":6187},151,[353,6189,6190],{},"        FileInputStream in = null;\n",[353,6192,6194],{"class":355,"line":6193},152,[353,6195,6196],{},"        byte buffer[] = new byte[1024];\n",[353,6198,6200],{"class":355,"line":6199},153,[353,6201,6202],{},"        int len;\n",[353,6204,6206],{"class":355,"line":6205},154,[353,6207,5725],{},[353,6209,6211],{"class":355,"line":6210},155,[353,6212,6213],{},"            digest = MessageDigest.getInstance(algorithm);\n",[353,6215,6217],{"class":355,"line":6216},156,[353,6218,6219],{},"            in = new FileInputStream(file);\n",[353,6221,6223],{"class":355,"line":6222},157,[353,6224,6225],{},"            while ((len = in.read(buffer, 0, 1024)) != -1) {\n",[353,6227,6229],{"class":355,"line":6228},158,[353,6230,6231],{},"                digest.update(buffer, 0, len);\n",[353,6233,6235],{"class":355,"line":6234},159,[353,6236,3868],{},[353,6238,6240],{"class":355,"line":6239},160,[353,6241,6242],{},"            in.close();\n",[353,6244,6246],{"class":355,"line":6245},161,[353,6247,6248],{},"        } catch (Exception e) {\n",[353,6250,6252],{"class":355,"line":6251},162,[353,6253,5893],{},[353,6255,6257],{"class":355,"line":6256},163,[353,6258,6173],{},[353,6260,6262],{"class":355,"line":6261},164,[353,6263,4036],{},[353,6265,6267],{"class":355,"line":6266},165,[353,6268,6269],{},"        BigInteger bigInt = new BigInteger(1, digest.digest());\n",[353,6271,6273],{"class":355,"line":6272},166,[353,6274,6275],{},"        return bigInt.toString(16);\n",[353,6277,6279],{"class":355,"line":6278},167,[353,6280,3635],{},[34,6282,6284],{"id":6283},"solr-的响应是怎么变成对象的","Solr 的响应是怎么变成对象的",[12,6286,6287,6288,6291],{},"中心库这套接口底下是 Solr，回给你的是一坨嵌套 JSON。代码没有一层层 ",[350,6289,6290],{},"getJSONObject()"," 去抠字段，而是让 fastjson 直接把整段响应收进对象：",[344,6293,6295],{"className":3415,"code":6294,"language":2796,"meta":293,"style":293},"SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[350,6296,6297],{"__ignoreMap":293},[353,6298,6299],{"class":355,"line":356},[353,6300,6294],{},[12,6302,6303],{},"映射规则就是「字段名对上即可」，所以五个实体类都很薄：",[63,6305,6306,6322],{},[66,6307,6308],{},[69,6309,6310,6313,6316,6319],{},[72,6311,6312],{},"类",[72,6314,6315],{},"对应节点",[72,6317,6318],{},"字段",[72,6320,6321],{},"实际用到",[82,6323,6324,6349,6374,6400,6453],{},[69,6325,6326,6331,6334,6346],{},[87,6327,6328],{},[350,6329,6330],{},"SolrSearch",[87,6332,6333],{},"根节点",[87,6335,6336,6339,6340,6339,6343],{},[350,6337,6338],{},"responseHeader"," \u002F ",[350,6341,6342],{},"response",[350,6344,6345],{},"spellcheck",[87,6347,6348],{},"三个容器",[69,6350,6351,6356,6360,6368],{},[87,6352,6353],{},[350,6354,6355],{},"ResponseHeader",[87,6357,6358],{},[350,6359,6338],{},[87,6361,6362,6339,6365],{},[350,6363,6364],{},"status",[350,6366,6367],{},"QTime",[87,6369,6370,6373],{},[350,6371,6372],{},"status == 0"," 即查询成功",[69,6375,6376,6381,6385,6396],{},[87,6377,6378],{},[350,6379,6380],{},"Response",[87,6382,6383],{},[350,6384,6342],{},[87,6386,6387,6339,6390,6339,6393],{},[350,6388,6389],{},"numFound",[350,6391,6392],{},"start",[350,6394,6395],{},"docs",[87,6397,6398],{},[350,6399,6395],{},[69,6401,6402,6407,6413,6445],{},[87,6403,6404],{},[350,6405,6406],{},"Docs",[87,6408,6409,6412],{},[350,6410,6411],{},"docs[]"," 的每一项",[87,6414,6415,6339,6418,6339,6421,6339,6423,6339,6426,6339,6428,6339,6431,6339,6434,6339,6437,6339,6439,6339,6442],{},[350,6416,6417],{},"id",[350,6419,6420],{},"g",[350,6422,96],{},[350,6424,6425],{},"v",[350,6427,12],{},[350,6429,6430],{},"latestVersion",[350,6432,6433],{},"versionCount",[350,6435,6436],{},"timestamp",[350,6438,2831],{},[350,6440,6441],{},"ec",[350,6443,6444],{},"repositoryId",[87,6446,6447,6339,6449,6339,6451],{},[350,6448,6420],{},[350,6450,96],{},[350,6452,6425],{},[69,6454,6455,6460,6464,6469],{},[87,6456,6457],{},[350,6458,6459],{},"Spellcheck",[87,6461,6462],{},[350,6463,6345],{},[87,6465,6466],{},[350,6467,6468],{},"suggestions",[87,6470,6471],{},"没用上",[12,6473,6474,6475,6478],{},"能落进 ",[350,6476,6477],{},"dependency"," 的只有三个字段，正好是 Solr 那份命名里的单字母缩写：",[344,6480,6482],{"className":3415,"code":6481,"language":2796,"meta":293,"style":293},"dependency.addAttribute(\"groupId\", docs.getG());\ndependency.addAttribute(\"artifactId\", docs.getA());\ndependency.addAttribute(\"version\", docs.getV());\n",[350,6483,6484,6489,6494],{"__ignoreMap":293},[353,6485,6486],{"class":355,"line":356},[353,6487,6488],{},"dependency.addAttribute(\"groupId\", docs.getG());\n",[353,6490,6491],{"class":355,"line":297},[353,6492,6493],{},"dependency.addAttribute(\"artifactId\", docs.getA());\n",[353,6495,6496],{"class":355,"line":294},[353,6497,6498],{},"dependency.addAttribute(\"version\", docs.getV());\n",[12,6500,6501,6339,6503,6339,6505,6507,6508,6510,6511,6513,6514,6516,6517,6519,6520,6522,6523,6526],{},[350,6502,6420],{},[350,6504,96],{},[350,6506,6425],{}," 之外的那些 —— ",[350,6509,6430],{},"（最新版本）、",[350,6512,12],{},"（打包类型）、",[350,6515,6441],{},"（该版本下有哪些文件）、",[350,6518,6433],{},"（版本总数）、",[350,6521,6444],{},"（命中哪个仓库）、",[350,6524,6525],{},"Spellcheck.suggestions","（拼写建议）—— 都解析了但没用。类的骨架留在那里，将来想加「取最新版」或者「提示拼写」，字段是现成的。",[12,6528,6529,6530,406],{},"用实体类而不是手写 JSON 路径，好处很直白：解析一行就完成，后面取值都是 getter，字段名写错了编译器直接报，而不是运行时静默接到一个 ",[350,6531,6532],{},"null",[34,6534,6535],{"id":6535},"它什么时候查不出结果",[12,6537,6538],{},"这个工具解决的是「一批本地 jar，不知道 Maven 坐标」。但它依赖两个前提：jar 公开发布过，且 Manifest 没被改过。下面这几种情况它就交不出来，用之前心里有个数：",[1871,6540,6541,6551,6561,6592,6606],{},[179,6542,6543,6546,6547,6550],{},[183,6544,6545],{},"jar 压根不在 Maven 中心库。"," 中心库只收公开发布过的构件。国内厂商私服的包、公司内部工具包，以及因为授权原因不能上中心库的（典型是 Oracle 的 JDBC 驱动），SHA1 查不到，Manifest 也拼不出可用坐标，最后只打印一行 ",[350,6548,6549],{},"No data was found","，得自己手写。",[179,6552,6553,6556,6557,6560],{},[183,6554,6555],{},"只查中心库一个源。"," ",[350,6558,6559],{},"nexusUrl"," 是写死的中心库地址，查不了公司私服（Nexus3、Artifactory）。要换成自家仓库，改这个常量和对应的查询参数即可 —— 2018 那版就是从 Nexus2 这么换过来的，前提是私服也提供可搜索接口。",[179,6562,6563,6566,6567,6570,6571,6570,6574,6577,6578,6570,6581,6570,6584,6587,6588,6591],{},[183,6564,6565],{},"Manifest 里的名字不等于 Maven 坐标。"," 回退这条路，artifactId 是拿 ",[350,6568,6569],{},"Extension-Name"," → ",[350,6572,6573],{},"Implementation-Title",[350,6575,6576],{},"Specification-Title"," 依次取的，version 取 ",[350,6579,6580],{},"Bundle-Version",[350,6582,6583],{},"Implementation-Version",[350,6585,6586],{},"Specification-Version","。很多 jar 这几个字段是空的，或者写的是「XXX SDK」这种给人看的名字，搜出来的结果就不保证对；被改过包名、重新打过的 jar，SHA1 也会落空，最后都只能走到这条「猜」的路上。所以输出里标着 ",[350,6589,6590],{},"Search by Manifest"," 的那几条，建议开 Maven 仓库页面核一眼。",[179,6593,6594,6597,6598,6601,6602,6605],{},[183,6595,6596],{},"命中多条时只取第一条。"," 无论走哪条路，最后都是 ",[350,6599,6600],{},"getDocs().get(0)","，没有按版本排序再挑这类逻辑 —— 查询串里本来就带了 ",[350,6603,6604],{},"rows=1","，只打算要一条。",[179,6607,6608,6556,6611,6614,6615,879,6618,6621,6622,6625],{},[183,6609,6610],{},"用法上的硬编码。",[350,6612,6613],{},"main()"," 里待处理目录写死成 ",[350,6616,6617],{},"D:\\lib",[350,6619,6620],{},"libs.listFiles()"," 只扫一层、也不筛后缀，换成别的路径、或者 ",[350,6623,6624],{},"lib"," 下面还有子目录，都得先改代码；结果是打在标准输出里的，得自己从控制台复制出来。",[34,6627,80],{"id":80},[176,6629,6630,6637],{},[179,6631,3054,6632],{},[96,6633,6636],{"href":6634,"rel":6635},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002Fjar2pom",[100],"gitee.com\u002FMegawatt\u002Fjar2pom",[179,6638,6639,6640],{},"CSDN：",[96,6641,6644],{"href":6642,"rel":6643},"https:\u002F\u002Fdownload.csdn.net\u002Fdownload\u002FJustinJia91\u002F12427956",[100],"download.csdn.net\u002Fdownload\u002FJustinJia91\u002F12427956",[12,6646,6647,6648,6651,6652,6655],{},"早年的仓库链接挂在 ",[350,6649,6650],{},"JiaXiaohei"," 这个账号名下，后来改成了 ",[350,6653,6654],{},"Megawatt","，老链接会自动跳过去，外部引用不用改。",[1779,6657,3304],{},{"title":293,"searchDepth":294,"depth":294,"links":6659},[6660,6661,6662,6663,6664,6665],{"id":409,"depth":297,"text":409},{"id":5430,"depth":297,"text":5430},{"id":5461,"depth":297,"text":5461},{"id":6283,"depth":297,"text":6284},{"id":6535,"depth":297,"text":6535},{"id":80,"depth":297,"text":80},"2020-05-16","把非 Maven 项目转成 Maven 时，得给一堆本地 jar 补 dependency。这个工具先用 jar 的 SHA1 去 Maven 中心库反查坐标，查不到再退回解析 Manifest。这篇带上项目结构、响应映射，以及它查不出结果的几种情况。",{},"\u002Fposts\u002Fjar2pom-maven-dependency",{"title":5404,"description":6667},"posts\u002Fjar2pom-maven-dependency",[6673,3089,2081],"Maven","My_pim5hwWNwMx0ud2asveYDDFzIcbblQ3loiVpZU38",{"id":6676,"title":6677,"body":6678,"date":7082,"description":7083,"extension":305,"meta":7084,"navigation":307,"path":7085,"seo":7086,"stem":7087,"tags":7088,"__hash__":7090},"posts\u002Fposts\u002Fflutter-android-sdkmanager-not-found.md","解决 Flutter 的 Android sdkmanager tool not found",{"type":9,"value":6679,"toc":7076},[6680,6682,6688,6691,6694,6700,7020,7022,7033,7038,7044,7049,7055,7060,7063,7066,7073],[34,6681,4099],{"id":4099},[344,6683,6686],{"className":6684,"code":6685,"language":2831},[2829],"Win10\nFlutter 1.12.13+hotfix.8\nAndroid Studio 3.6.1\n",[350,6687,6685],{"__ignoreMap":293},[34,6689,6690],{"id":6690},"问题描述",[12,6692,6693],{},"最近因为显卡 Boom 了，索性重装了系统。\n装完 Flutter 以后 doctor 通不过，一直找不到 sdkmanager。",[12,6695,6696],{},[18,6697],{"alt":6698,"src":6699},"flutter doctor 输出","\u002Fimages\u002Fflutter-android-sdkmanager\u002F01-flutter-doctor.png",[344,6701,6703],{"className":687,"code":6702,"language":689,"meta":293,"style":293},"> flutter doctor\nDoctor summary (to see all details, run flutter doctor -v):\n[√] Flutter (Channel stable, v1.12.13+hotfix.8, on Microsoft Windows [Version 10.0.18363.720], locale\n    zh-CN)\n[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)\n    X Android license status unknown.\n      Try re-installing or updating your Android SDK Manager.\n      See https:\u002F\u002Fdeveloper.android.com\u002Fstudio\u002F#downloads or visit https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup\n      for detailed instructions.\n[√] Android Studio (version 3.6)\n[√] Connected device (1 available)\n\n! Doctor found issues in 1 category.\n\n> flutter doctor --android-licenses\nAndroid sdkmanager tool not found (D:\\Android\\Sdk\\tools\\bin\\sdkmanager).\nTry re-installing or updating your Android SDK,\nvisit https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup for detailed instructions.\n\n> \n",[350,6704,6705,6713,6748,6787,6794,6822,6838,6861,6877,6885,6904,6922,6926,6948,6952,6959,6977,6995,7012,7016],{"__ignoreMap":293},[353,6706,6707,6710],{"class":355,"line":356},[353,6708,6709],{"class":363},">",[353,6711,6712],{"class":367}," flutter doctor\n",[353,6714,6715,6718,6721,6724,6727,6730,6733,6736,6739,6742,6745],{"class":355,"line":297},[353,6716,6717],{"class":696},"Doctor",[353,6719,6720],{"class":390}," summary",[353,6722,6723],{"class":367}," (to ",[353,6725,6726],{"class":390},"see",[353,6728,6729],{"class":390}," all",[353,6731,6732],{"class":390}," details,",[353,6734,6735],{"class":390}," run",[353,6737,6738],{"class":390}," flutter",[353,6740,6741],{"class":390}," doctor",[353,6743,6744],{"class":390}," -v",[353,6746,6747],{"class":367},"):\n",[353,6749,6750,6752,6755,6757,6760,6763,6766,6769,6772,6775,6778,6781,6784],{"class":355,"line":294},[353,6751,4274],{"class":363},[353,6753,6754],{"class":367},"√",[353,6756,4417],{"class":363},[353,6758,6759],{"class":367}," Flutter (",[353,6761,6762],{"class":696},"Channel",[353,6764,6765],{"class":390}," stable,",[353,6767,6768],{"class":390}," v1.12.13+hotfix.8,",[353,6770,6771],{"class":390}," on",[353,6773,6774],{"class":390}," Microsoft",[353,6776,6777],{"class":390}," Windows",[353,6779,6780],{"class":367}," [Version ",[353,6782,6783],{"class":390},"10.0.18363.720],",[353,6785,6786],{"class":390}," locale\n",[353,6788,6789,6792],{"class":355,"line":721},[353,6790,6791],{"class":696},"    zh-CN",[353,6793,396],{"class":367},[353,6795,6796,6799,6802,6805,6808,6810,6812,6815,6817,6820],{"class":355,"line":1584},[353,6797,6798],{"class":363},"[!]",[353,6800,6801],{"class":367}," Android toolchain - develop ",[353,6803,6804],{"class":377},"for",[353,6806,6807],{"class":367}," Android devices ",[353,6809,384],{"class":363},[353,6811,313],{"class":696},[353,6813,6814],{"class":390}," SDK",[353,6816,4266],{"class":390},[353,6818,6819],{"class":739}," 29.0.3",[353,6821,396],{"class":363},[353,6823,6824,6827,6830,6833,6835],{"class":355,"line":2317},[353,6825,6826],{"class":696},"    X",[353,6828,6829],{"class":390}," Android",[353,6831,6832],{"class":390}," license",[353,6834,2138],{"class":390},[353,6836,6837],{"class":390}," unknown.\n",[353,6839,6840,6843,6846,6848,6851,6854,6856,6858],{"class":355,"line":2328},[353,6841,6842],{"class":696},"      Try",[353,6844,6845],{"class":390}," re-installing",[353,6847,5234],{"class":390},[353,6849,6850],{"class":390}," updating",[353,6852,6853],{"class":390}," your",[353,6855,6829],{"class":390},[353,6857,6814],{"class":390},[353,6859,6860],{"class":390}," Manager.\n",[353,6862,6863,6866,6869,6871,6874],{"class":355,"line":2334},[353,6864,6865],{"class":696},"      See",[353,6867,6868],{"class":390}," https:\u002F\u002Fdeveloper.android.com\u002Fstudio\u002F#downloads",[353,6870,5234],{"class":390},[353,6872,6873],{"class":390}," visit",[353,6875,6876],{"class":390}," https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup\n",[353,6878,6879,6882],{"class":355,"line":2348},[353,6880,6881],{"class":377},"      for",[353,6883,6884],{"class":367}," detailed instructions.\n",[353,6886,6887,6889,6891,6893,6896,6899,6902],{"class":355,"line":2362},[353,6888,4274],{"class":363},[353,6890,6754],{"class":367},[353,6892,4417],{"class":363},[353,6894,6895],{"class":367}," Android Studio (",[353,6897,6898],{"class":696},"version",[353,6900,6901],{"class":739}," 3.6",[353,6903,396],{"class":367},[353,6905,6906,6908,6910,6912,6915,6917,6920],{"class":355,"line":2376},[353,6907,4274],{"class":363},[353,6909,6754],{"class":367},[353,6911,4417],{"class":363},[353,6913,6914],{"class":367}," Connected device (",[353,6916,2665],{"class":696},[353,6918,6919],{"class":390}," available",[353,6921,396],{"class":367},[353,6923,6924],{"class":355,"line":3172},[353,6925,3483],{"emptyLinePlaceholder":307},[353,6927,6928,6931,6934,6937,6940,6942,6945],{"class":355,"line":3245},[353,6929,6930],{"class":363},"!",[353,6932,6933],{"class":696}," Doctor",[353,6935,6936],{"class":390}," found",[353,6938,6939],{"class":390}," issues",[353,6941,4664],{"class":390},[353,6943,6944],{"class":739}," 1",[353,6946,6947],{"class":390}," category.\n",[353,6949,6950],{"class":355,"line":3251},[353,6951,3483],{"emptyLinePlaceholder":307},[353,6953,6954,6956],{"class":355,"line":3257},[353,6955,6709],{"class":363},[353,6957,6958],{"class":367}," flutter doctor --android-licenses\n",[353,6960,6961,6963,6966,6969,6972,6974],{"class":355,"line":3263},[353,6962,313],{"class":696},[353,6964,6965],{"class":390}," sdkmanager",[353,6967,6968],{"class":390}," tool",[353,6970,6971],{"class":390}," not",[353,6973,6936],{"class":390},[353,6975,6976],{"class":367}," (D:\\Android\\Sdk\\tools\\bin\\sdkmanager).\n",[353,6978,6979,6982,6984,6986,6988,6990,6992],{"class":355,"line":3269},[353,6980,6981],{"class":696},"Try",[353,6983,6845],{"class":390},[353,6985,5234],{"class":390},[353,6987,6850],{"class":390},[353,6989,6853],{"class":390},[353,6991,6829],{"class":390},[353,6993,6994],{"class":390}," SDK,\n",[353,6996,6997,7000,7003,7006,7009],{"class":355,"line":3275},[353,6998,6999],{"class":696},"visit",[353,7001,7002],{"class":390}," https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup",[353,7004,7005],{"class":390}," for",[353,7007,7008],{"class":390}," detailed",[353,7010,7011],{"class":390}," instructions.\n",[353,7013,7014],{"class":355,"line":3280},[353,7015,3483],{"emptyLinePlaceholder":307},[353,7017,7018],{"class":355,"line":3286},[353,7019,482],{"class":363},[34,7021,3338],{"id":3338},[12,7023,7024,7025,7028,7029,7032],{},"在 Android Studio 中启动 ",[183,7026,7027],{},"SDK Manager","，去掉选项 ",[183,7030,7031],{},"Hide Obsolete Packages","：",[12,7034,7035],{},[18,7036],{"alt":7027,"src":7037},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F02-sdk-manager.png",[12,7039,7040,7041,7032],{},"选择安装 ",[183,7042,7043],{},"Android SDK Tools (Obsolete)",[12,7045,7046],{},[18,7047],{"alt":7043,"src":7048},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F03-sdk-tools-obsolete.png",[12,7050,7051,7052,7032],{},"点击 ",[183,7053,7054],{},"Apply",[12,7056,7057],{},[18,7058],{"alt":7054,"src":7059},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F04-apply.png",[12,7061,7062],{},"安装完成。",[34,7064,7065],{"id":7065},"原因",[12,7067,7068,7069,7072],{},"不知道为啥 ",[183,7070,7071],{},"Android SDK Tools"," 被废弃了，但是好像 Flutter 还需要其提供支持。",[1779,7074,7075],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":293,"searchDepth":294,"depth":294,"links":7077},[7078,7079,7080,7081],{"id":4099,"depth":297,"text":4099},{"id":6690,"depth":297,"text":6690},{"id":3338,"depth":297,"text":3338},{"id":7065,"depth":297,"text":7065},"2020-03-30","重装系统后 flutter doctor 一直报 Android license status unknown，找不到 sdkmanager。根因是被废弃的 Android SDK Tools 没装。",{},"\u002Fposts\u002Fflutter-android-sdkmanager-not-found",{"title":6677,"description":7083},"posts\u002Fflutter-android-sdkmanager-not-found",[7089,313],"Flutter","89rDwOF_d8Tw5wvZBBPNTmf8oT3xfyx82CIoQ11E9Dw",{"id":7092,"title":7093,"body":7094,"date":7828,"description":7829,"extension":305,"meta":7830,"navigation":307,"path":7831,"seo":7832,"stem":7833,"tags":7834,"__hash__":7836},"posts\u002Fposts\u002Fcentos-yum-pgadmin4-python3-missing.md","解决 CentOS yum 安装 pgadmin4 报 nothing provides python3-*** 的问题",{"type":9,"value":7095,"toc":7822},[7096,7098,7104,7106,7109,7115,7789,7791,7794,7796,7802,7819],[34,7097,4099],{"id":4099},[344,7099,7102],{"className":7100,"code":7101,"language":2831},[2829],"CentOS8 (最小安装)\nPython3 (yum\u002Fdnf安装)\n",[350,7103,7101],{"__ignoreMap":293},[34,7105,6690],{"id":6690},[12,7107,7108],{},"安装时提示缺少 python3-alembic 等包，\n但是安装了 python3 仍然提示找不到包。",[12,7110,7111],{},[18,7112],{"alt":7113,"src":7114},"yum 安装报错","\u002Fimages\u002Fcentos-yum-pgadmin4\u002Ferror.png",[344,7116,7118],{"className":687,"code":7117,"language":689,"meta":293,"style":293},"[root@HyperV-PSQL ~]# yum -y install pgadmin4\n上次元数据过期检查：0:11:32 前，执行于 2020年03月10日 星期二 11时35分24秒。\n错误：\n 问题: package pgadmin4-4.19-1.rhel8.x86_64 requires pgadmin4-web, but none of the providers can be installed\n  - cannot install the best candidate for the job\n  - nothing provides python3-alembic needed by pgadmin4-web-4.16-1.rhel8.noarch\n  - nothing provides pgadmin4-python3-unittest2 needed by pgadmin4-web-4.16-1.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.16-1.rhel8.noarch\n  - nothing provides python3-beautifulsoup4 >= 4.4.1 needed by pgadmin4-web-4.16-1.rhel8.noarch\n  - nothing provides python3-flask-sqlalchemy >= 2.3.2 needed by pgadmin4-web-4.16-1.rhel8.noarch\n  - nothing provides python3-alembic needed by pgadmin4-web-4.16-2.rhel8.noarch\n  - nothing provides python3-unittest2 needed by pgadmin4-web-4.16-2.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.16-2.rhel8.noarch\n  - nothing provides python3-beautifulsoup4 >= 4.4.1 needed by pgadmin4-web-4.16-2.rhel8.noarch\n  - nothing provides python3-alembic needed by pgadmin4-web-4.17-1.rhel8.noarch\n  - nothing provides python3-unittest2 needed by pgadmin4-web-4.17-1.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.17-1.rhel8.noarch\n  - nothing provides python3-beautifulsoup4 >= 4.4.1 needed by pgadmin4-web-4.17-1.rhel8.noarch\n  - nothing provides python3-alembic needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-unittest2 needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-bcrypt needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-pynacl needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-beautifulsoup4 >= 4.4.1 needed by pgadmin4-web-4.17-2.rhel8.noarch\n  - nothing provides python3-alembic needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-unittest2 needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-bcrypt needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-pynacl needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-beautifulsoup4 >= 4.4.1 needed by pgadmin4-web-4.18-1.rhel8.noarch\n  - nothing provides python3-bcrypt needed by pgadmin4-web-4.19-1.rhel8.noarch\n  - nothing provides python3-pynacl needed by pgadmin4-web-4.19-1.rhel8.noarch\n  - nothing provides python3-blinker >= 1.4 needed by pgadmin4-web-4.19-1.rhel8.noarch\n(尝试添加 '--skip-broken' 来跳过无法安装的软件包 或 '--nobest' 来不只使用最佳选择的软件包)\n",[350,7119,7120,7132,7148,7153,7191,7215,7237,7254,7279,7303,7327,7344,7361,7383,7405,7422,7438,7460,7482,7499,7515,7532,7549,7571,7593,7610,7626,7642,7658,7680,7702,7719,7735,7757],{"__ignoreMap":293},[353,7121,7122,7124,7127,7129],{"class":355,"line":356},[353,7123,4274],{"class":363},[353,7125,7126],{"class":367},"root@HyperV-PSQL ",[353,7128,5185],{"class":363},[353,7130,7131],{"class":367},"# yum -y install pgadmin4\n",[353,7133,7134,7137,7139,7142,7145],{"class":355,"line":297},[353,7135,7136],{"class":696},"上次元数据过期检查：0:11:32",[353,7138,4428],{"class":390},[353,7140,7141],{"class":390}," 2020年03月10日",[353,7143,7144],{"class":390}," 星期二",[353,7146,7147],{"class":390}," 11时35分24秒。\n",[353,7149,7150],{"class":355,"line":294},[353,7151,7152],{"class":696},"错误：\n",[353,7154,7155,7158,7160,7163,7166,7169,7172,7175,7177,7179,7182,7185,7188],{"class":355,"line":721},[353,7156,7157],{"class":696}," 问题:",[353,7159,4678],{"class":390},[353,7161,7162],{"class":390}," pgadmin4-4.19-1.rhel8.x86_64",[353,7164,7165],{"class":390}," requires",[353,7167,7168],{"class":390}," pgadmin4-web,",[353,7170,7171],{"class":390}," but",[353,7173,7174],{"class":390}," none",[353,7176,4261],{"class":390},[353,7178,4164],{"class":390},[353,7180,7181],{"class":390}," providers",[353,7183,7184],{"class":390}," can",[353,7186,7187],{"class":390}," be",[353,7189,7190],{"class":390}," installed\n",[353,7192,7193,7196,7198,7200,7202,7205,7208,7210,7212],{"class":355,"line":1584},[353,7194,7195],{"class":696},"  -",[353,7197,4926],{"class":390},[353,7199,4320],{"class":390},[353,7201,4164],{"class":390},[353,7203,7204],{"class":390}," best",[353,7206,7207],{"class":390}," candidate",[353,7209,7005],{"class":390},[353,7211,4164],{"class":390},[353,7213,7214],{"class":390}," job\n",[353,7216,7217,7219,7222,7225,7228,7231,7234],{"class":355,"line":2317},[353,7218,7195],{"class":696},[353,7220,7221],{"class":390}," nothing",[353,7223,7224],{"class":390}," provides",[353,7226,7227],{"class":390}," python3-alembic",[353,7229,7230],{"class":390}," needed",[353,7232,7233],{"class":390}," by",[353,7235,7236],{"class":390}," pgadmin4-web-4.16-1.rhel8.noarch\n",[353,7238,7239,7241,7243,7245,7248,7250,7252],{"class":355,"line":2328},[353,7240,7195],{"class":696},[353,7242,7221],{"class":390},[353,7244,7224],{"class":390},[353,7246,7247],{"class":390}," pgadmin4-python3-unittest2",[353,7249,7230],{"class":390},[353,7251,7233],{"class":390},[353,7253,7236],{"class":390},[353,7255,7256,7258,7260,7262,7265,7268,7270,7273,7275,7277],{"class":355,"line":2334},[353,7257,7195],{"class":696},[353,7259,7221],{"class":390},[353,7261,7224],{"class":390},[353,7263,7264],{"class":390}," python3-blinker",[353,7266,7267],{"class":363}," >",[353,7269,459],{"class":390},[353,7271,7272],{"class":739}," 1.4",[353,7274,7230],{"class":390},[353,7276,7233],{"class":390},[353,7278,7236],{"class":390},[353,7280,7281,7283,7285,7287,7290,7292,7294,7297,7299,7301],{"class":355,"line":2348},[353,7282,7195],{"class":696},[353,7284,7221],{"class":390},[353,7286,7224],{"class":390},[353,7288,7289],{"class":390}," python3-beautifulsoup4",[353,7291,7267],{"class":363},[353,7293,459],{"class":390},[353,7295,7296],{"class":739}," 4.4.1",[353,7298,7230],{"class":390},[353,7300,7233],{"class":390},[353,7302,7236],{"class":390},[353,7304,7305,7307,7309,7311,7314,7316,7318,7321,7323,7325],{"class":355,"line":2362},[353,7306,7195],{"class":696},[353,7308,7221],{"class":390},[353,7310,7224],{"class":390},[353,7312,7313],{"class":390}," python3-flask-sqlalchemy",[353,7315,7267],{"class":363},[353,7317,459],{"class":390},[353,7319,7320],{"class":739}," 2.3.2",[353,7322,7230],{"class":390},[353,7324,7233],{"class":390},[353,7326,7236],{"class":390},[353,7328,7329,7331,7333,7335,7337,7339,7341],{"class":355,"line":2376},[353,7330,7195],{"class":696},[353,7332,7221],{"class":390},[353,7334,7224],{"class":390},[353,7336,7227],{"class":390},[353,7338,7230],{"class":390},[353,7340,7233],{"class":390},[353,7342,7343],{"class":390}," pgadmin4-web-4.16-2.rhel8.noarch\n",[353,7345,7346,7348,7350,7352,7355,7357,7359],{"class":355,"line":3172},[353,7347,7195],{"class":696},[353,7349,7221],{"class":390},[353,7351,7224],{"class":390},[353,7353,7354],{"class":390}," python3-unittest2",[353,7356,7230],{"class":390},[353,7358,7233],{"class":390},[353,7360,7343],{"class":390},[353,7362,7363,7365,7367,7369,7371,7373,7375,7377,7379,7381],{"class":355,"line":3245},[353,7364,7195],{"class":696},[353,7366,7221],{"class":390},[353,7368,7224],{"class":390},[353,7370,7264],{"class":390},[353,7372,7267],{"class":363},[353,7374,459],{"class":390},[353,7376,7272],{"class":739},[353,7378,7230],{"class":390},[353,7380,7233],{"class":390},[353,7382,7343],{"class":390},[353,7384,7385,7387,7389,7391,7393,7395,7397,7399,7401,7403],{"class":355,"line":3251},[353,7386,7195],{"class":696},[353,7388,7221],{"class":390},[353,7390,7224],{"class":390},[353,7392,7289],{"class":390},[353,7394,7267],{"class":363},[353,7396,459],{"class":390},[353,7398,7296],{"class":739},[353,7400,7230],{"class":390},[353,7402,7233],{"class":390},[353,7404,7343],{"class":390},[353,7406,7407,7409,7411,7413,7415,7417,7419],{"class":355,"line":3257},[353,7408,7195],{"class":696},[353,7410,7221],{"class":390},[353,7412,7224],{"class":390},[353,7414,7227],{"class":390},[353,7416,7230],{"class":390},[353,7418,7233],{"class":390},[353,7420,7421],{"class":390}," pgadmin4-web-4.17-1.rhel8.noarch\n",[353,7423,7424,7426,7428,7430,7432,7434,7436],{"class":355,"line":3263},[353,7425,7195],{"class":696},[353,7427,7221],{"class":390},[353,7429,7224],{"class":390},[353,7431,7354],{"class":390},[353,7433,7230],{"class":390},[353,7435,7233],{"class":390},[353,7437,7421],{"class":390},[353,7439,7440,7442,7444,7446,7448,7450,7452,7454,7456,7458],{"class":355,"line":3269},[353,7441,7195],{"class":696},[353,7443,7221],{"class":390},[353,7445,7224],{"class":390},[353,7447,7264],{"class":390},[353,7449,7267],{"class":363},[353,7451,459],{"class":390},[353,7453,7272],{"class":739},[353,7455,7230],{"class":390},[353,7457,7233],{"class":390},[353,7459,7421],{"class":390},[353,7461,7462,7464,7466,7468,7470,7472,7474,7476,7478,7480],{"class":355,"line":3275},[353,7463,7195],{"class":696},[353,7465,7221],{"class":390},[353,7467,7224],{"class":390},[353,7469,7289],{"class":390},[353,7471,7267],{"class":363},[353,7473,459],{"class":390},[353,7475,7296],{"class":739},[353,7477,7230],{"class":390},[353,7479,7233],{"class":390},[353,7481,7421],{"class":390},[353,7483,7484,7486,7488,7490,7492,7494,7496],{"class":355,"line":3280},[353,7485,7195],{"class":696},[353,7487,7221],{"class":390},[353,7489,7224],{"class":390},[353,7491,7227],{"class":390},[353,7493,7230],{"class":390},[353,7495,7233],{"class":390},[353,7497,7498],{"class":390}," pgadmin4-web-4.17-2.rhel8.noarch\n",[353,7500,7501,7503,7505,7507,7509,7511,7513],{"class":355,"line":3286},[353,7502,7195],{"class":696},[353,7504,7221],{"class":390},[353,7506,7224],{"class":390},[353,7508,7354],{"class":390},[353,7510,7230],{"class":390},[353,7512,7233],{"class":390},[353,7514,7498],{"class":390},[353,7516,7517,7519,7521,7523,7526,7528,7530],{"class":355,"line":3291},[353,7518,7195],{"class":696},[353,7520,7221],{"class":390},[353,7522,7224],{"class":390},[353,7524,7525],{"class":390}," python3-bcrypt",[353,7527,7230],{"class":390},[353,7529,7233],{"class":390},[353,7531,7498],{"class":390},[353,7533,7534,7536,7538,7540,7543,7545,7547],{"class":355,"line":3525},[353,7535,7195],{"class":696},[353,7537,7221],{"class":390},[353,7539,7224],{"class":390},[353,7541,7542],{"class":390}," python3-pynacl",[353,7544,7230],{"class":390},[353,7546,7233],{"class":390},[353,7548,7498],{"class":390},[353,7550,7551,7553,7555,7557,7559,7561,7563,7565,7567,7569],{"class":355,"line":3531},[353,7552,7195],{"class":696},[353,7554,7221],{"class":390},[353,7556,7224],{"class":390},[353,7558,7264],{"class":390},[353,7560,7267],{"class":363},[353,7562,459],{"class":390},[353,7564,7272],{"class":739},[353,7566,7230],{"class":390},[353,7568,7233],{"class":390},[353,7570,7498],{"class":390},[353,7572,7573,7575,7577,7579,7581,7583,7585,7587,7589,7591],{"class":355,"line":3537},[353,7574,7195],{"class":696},[353,7576,7221],{"class":390},[353,7578,7224],{"class":390},[353,7580,7289],{"class":390},[353,7582,7267],{"class":363},[353,7584,459],{"class":390},[353,7586,7296],{"class":739},[353,7588,7230],{"class":390},[353,7590,7233],{"class":390},[353,7592,7498],{"class":390},[353,7594,7595,7597,7599,7601,7603,7605,7607],{"class":355,"line":3543},[353,7596,7195],{"class":696},[353,7598,7221],{"class":390},[353,7600,7224],{"class":390},[353,7602,7227],{"class":390},[353,7604,7230],{"class":390},[353,7606,7233],{"class":390},[353,7608,7609],{"class":390}," pgadmin4-web-4.18-1.rhel8.noarch\n",[353,7611,7612,7614,7616,7618,7620,7622,7624],{"class":355,"line":3548},[353,7613,7195],{"class":696},[353,7615,7221],{"class":390},[353,7617,7224],{"class":390},[353,7619,7354],{"class":390},[353,7621,7230],{"class":390},[353,7623,7233],{"class":390},[353,7625,7609],{"class":390},[353,7627,7628,7630,7632,7634,7636,7638,7640],{"class":355,"line":3554},[353,7629,7195],{"class":696},[353,7631,7221],{"class":390},[353,7633,7224],{"class":390},[353,7635,7525],{"class":390},[353,7637,7230],{"class":390},[353,7639,7233],{"class":390},[353,7641,7609],{"class":390},[353,7643,7644,7646,7648,7650,7652,7654,7656],{"class":355,"line":3559},[353,7645,7195],{"class":696},[353,7647,7221],{"class":390},[353,7649,7224],{"class":390},[353,7651,7542],{"class":390},[353,7653,7230],{"class":390},[353,7655,7233],{"class":390},[353,7657,7609],{"class":390},[353,7659,7660,7662,7664,7666,7668,7670,7672,7674,7676,7678],{"class":355,"line":3565},[353,7661,7195],{"class":696},[353,7663,7221],{"class":390},[353,7665,7224],{"class":390},[353,7667,7264],{"class":390},[353,7669,7267],{"class":363},[353,7671,459],{"class":390},[353,7673,7272],{"class":739},[353,7675,7230],{"class":390},[353,7677,7233],{"class":390},[353,7679,7609],{"class":390},[353,7681,7682,7684,7686,7688,7690,7692,7694,7696,7698,7700],{"class":355,"line":3571},[353,7683,7195],{"class":696},[353,7685,7221],{"class":390},[353,7687,7224],{"class":390},[353,7689,7289],{"class":390},[353,7691,7267],{"class":363},[353,7693,459],{"class":390},[353,7695,7296],{"class":739},[353,7697,7230],{"class":390},[353,7699,7233],{"class":390},[353,7701,7609],{"class":390},[353,7703,7704,7706,7708,7710,7712,7714,7716],{"class":355,"line":3576},[353,7705,7195],{"class":696},[353,7707,7221],{"class":390},[353,7709,7224],{"class":390},[353,7711,7525],{"class":390},[353,7713,7230],{"class":390},[353,7715,7233],{"class":390},[353,7717,7718],{"class":390}," pgadmin4-web-4.19-1.rhel8.noarch\n",[353,7720,7721,7723,7725,7727,7729,7731,7733],{"class":355,"line":3581},[353,7722,7195],{"class":696},[353,7724,7221],{"class":390},[353,7726,7224],{"class":390},[353,7728,7542],{"class":390},[353,7730,7230],{"class":390},[353,7732,7233],{"class":390},[353,7734,7718],{"class":390},[353,7736,7737,7739,7741,7743,7745,7747,7749,7751,7753,7755],{"class":355,"line":3587},[353,7738,7195],{"class":696},[353,7740,7221],{"class":390},[353,7742,7224],{"class":390},[353,7744,7264],{"class":390},[353,7746,7267],{"class":363},[353,7748,459],{"class":390},[353,7750,7272],{"class":739},[353,7752,7230],{"class":390},[353,7754,7233],{"class":390},[353,7756,7718],{"class":390},[353,7758,7759,7761,7764,7766,7769,7771,7774,7777,7779,7782,7784,7787],{"class":355,"line":3592},[353,7760,384],{"class":363},[353,7762,7763],{"class":696},"尝试添加",[353,7765,5023],{"class":363},[353,7767,7768],{"class":390},"--skip-broken",[353,7770,387],{"class":363},[353,7772,7773],{"class":390}," 来跳过无法安装的软件包",[353,7775,7776],{"class":390}," 或",[353,7778,5023],{"class":363},[353,7780,7781],{"class":390},"--nobest",[353,7783,387],{"class":363},[353,7785,7786],{"class":390}," 来不只使用最佳选择的软件包",[353,7788,396],{"class":363},[34,7790,7065],{"id":7065},[12,7792,7793],{},"官方的 rpm repository 没有提供对应的包。",[34,7795,3338],{"id":3338},[12,7797,7798,7799,7032],{},"安装 ",[183,7800,7801],{},"EPEL",[344,7803,7805],{"className":687,"code":7804,"language":689,"meta":293,"style":293},"yum install epel-release -y\n",[350,7806,7807],{"__ignoreMap":293},[353,7808,7809,7811,7813,7816],{"class":355,"line":356},[353,7810,5379],{"class":696},[353,7812,4320],{"class":390},[353,7814,7815],{"class":390}," epel-release",[353,7817,7818],{"class":390}," -y\n",[1779,7820,7821],{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":293,"searchDepth":294,"depth":294,"links":7823},[7824,7825,7826,7827],{"id":4099,"depth":297,"text":4099},{"id":6690,"depth":297,"text":6690},{"id":7065,"depth":297,"text":7065},{"id":3338,"depth":297,"text":3338},"2020-03-13","CentOS 8 上装 pgadmin4 一直缺 python3-alembic 之类的包，但 python3 明明装了。原因是官方 rpm 仓库没提供这些包，得先装 EPEL。",{},"\u002Fposts\u002Fcentos-yum-pgadmin4-python3-missing",{"title":7093,"description":7829},"posts\u002Fcentos-yum-pgadmin4-python3-missing",[2469,7835,2470],"PostgreSQL","aVJQ5MrUa_hpNZ0bTIwLxk-DJDKyebCmCM9GG4FrjaA",{"id":7838,"title":7839,"body":7840,"date":8316,"description":8317,"extension":305,"meta":8318,"navigation":307,"path":8319,"seo":8320,"stem":8321,"tags":8322,"__hash__":8325},"posts\u002Fposts\u002Fmacpro-gpu-switch.md","MacPro GPU Switch：用 JavaFX 做一个 macOS 显卡切换工具",{"type":9,"value":7841,"toc":8301},[7842,7845,7848,7851,7907,7910,7913,7916,7922,7925,7928,7931,7934,7941,7961,7964,7967,7971,7977,7983,7993,8030,8033,8037,8052,8059,8063,8066,8080,8091,8105,8123,8126,8148,8152,8158,8183,8186,8192,8196,8228,8230,8233,8236,8247,8262,8265,8279,8282,8284,8287,8295,8298],[12,7843,7844],{},"MacBook Pro 15 寸是台双显卡的机器：一块 Intel 核显，一块 Radeon 独显。",[12,7846,7847],{},"用久了会撞上一个很具体的烦恼 —— 你没法决定现在用哪块。",[12,7849,7850],{},"macOS 的系统设置里，关于显卡只有「自动切换图形卡模式」这一个勾选框，它管的是“要不要自动切”，管不了“现在锁在哪一块”。真正能决定这件事的，是一条电源管理命令：",[344,7852,7854],{"className":687,"code":7853,"language":689,"meta":293,"style":293},"sudo pmset -a GPUSwitch 0   # 整合（只用核显）\nsudo pmset -a GPUSwitch 1   # 高性能（只用独显）\nsudo pmset -a GPUSwitch 2   # 自动\n",[350,7855,7856,7876,7891],{"__ignoreMap":293},[353,7857,7858,7861,7864,7867,7870,7873],{"class":355,"line":356},[353,7859,7860],{"class":696},"sudo",[353,7862,7863],{"class":390}," pmset",[353,7865,7866],{"class":390}," -a",[353,7868,7869],{"class":390}," GPUSwitch",[353,7871,7872],{"class":739}," 0",[353,7874,7875],{"class":703},"   # 整合（只用核显）\n",[353,7877,7878,7880,7882,7884,7886,7888],{"class":355,"line":297},[353,7879,7860],{"class":696},[353,7881,7863],{"class":390},[353,7883,7866],{"class":390},[353,7885,7869],{"class":390},[353,7887,6944],{"class":739},[353,7889,7890],{"class":703},"   # 高性能（只用独显）\n",[353,7892,7893,7895,7897,7899,7901,7904],{"class":355,"line":294},[353,7894,7860],{"class":696},[353,7896,7863],{"class":390},[353,7898,7866],{"class":390},[353,7900,7869],{"class":390},[353,7902,7903],{"class":739}," 2",[353,7905,7906],{"class":703},"   # 自动\n",[12,7908,7909],{},"能用，但每次都得开终端、敲一遍、输一次密码。为了两秒钟的切换走完这一套，太长了。",[12,7911,7912],{},"MacPro GPU Switch 就是把这条命令包进一个窗口：选核显就一直用核显，选独显就一直用独显，选自动就交回给系统。",[34,7914,7915],{"id":7915},"它长这样",[12,7917,7918],{},[18,7919],{"alt":7920,"src":7921},"MacPro GPU Switch 主界面：左侧大字显示当前模式，右侧填 Root 密码并选择模式","\u002Fimages\u002Fmacpro-gpu-switch\u002Fmain-window.png",[12,7923,7924],{},"界面很直白：左边大字写着当前处于哪个模式，颜色也跟着变（整合是青色，高性能是橙色，自动是蓝色）；右边填 Root 密码，下面三个单选框对应三种模式；底部是「关于」「应用」「关闭」。",[12,7926,7927],{},"勾上「记住密码」，下次打开就不用再输。",[12,7929,7930],{},"它做的事就四步：读当前状态 → 你选一个新模式 → 点「应用」→ 它替你跑那条 sudo 命令，再把新状态读回来显示。",[34,7932,7933],{"id":7933},"三种模式",[12,7935,7936,7937,7940],{},"对应 ",[350,7938,7939],{},"GPUSwitch"," 的三个值：",[1871,7942,7943,7949,7955],{},[179,7944,7945,7948],{},[183,7946,7947],{},"整合","（0）—— 只用核显，最省电最凉快，重活干不了；",[179,7950,7951,7954],{},[183,7952,7953],{},"高性能","（1）—— 只用独显，性能拉满，代价是发热和续航；",[179,7956,7957,7960],{},[183,7958,7959],{},"自动","（2）—— 交给系统判断，也就是 macOS 默认的那套逻辑。",[34,7962,7963],{"id":7963},"实现上其实只有三件事",[12,7965,7966],{},"代码量很小，核心就是三次 Shell 调用。",[1085,7968,7970],{"id":7969},"一读懂当前状态","一、读懂当前状态",[12,7972,7973,7976],{},[350,7974,7975],{},"pmset -g"," 会打印一大串电源管理配置，显卡那一行长这样：",[344,7978,7981],{"className":7979,"code":7980,"language":2831},[2829],"gpuswitch             0\n",[350,7982,7980],{"__ignoreMap":293},[12,7984,7985,7986,7988,7989,7992],{},"所以读状态的逻辑就是：跑一遍 ",[350,7987,7975],{},"，逐行找以 ",[350,7990,7991],{},"gpuswitch"," 开头的那行，把数字抠出来。",[344,7994,7996],{"className":3415,"code":7995,"language":2796,"meta":293,"style":293},"String[] command = {\"\u002Fbin\u002Fsh\", \"-c\", \"pmset -g\"};\n\nfor (String process : processList) {\n    if (process.startsWith(\"gpuswitch\")) {\n        i = Integer.parseInt(process.replaceAll(\"gpuswitch| \", \"\"));\n    }\n}\n",[350,7997,7998,8003,8007,8012,8017,8022,8026],{"__ignoreMap":293},[353,7999,8000],{"class":355,"line":356},[353,8001,8002],{},"String[] command = {\"\u002Fbin\u002Fsh\", \"-c\", \"pmset -g\"};\n",[353,8004,8005],{"class":355,"line":297},[353,8006,3483],{"emptyLinePlaceholder":307},[353,8008,8009],{"class":355,"line":294},[353,8010,8011],{},"for (String process : processList) {\n",[353,8013,8014],{"class":355,"line":721},[353,8015,8016],{},"    if (process.startsWith(\"gpuswitch\")) {\n",[353,8018,8019],{"class":355,"line":1584},[353,8020,8021],{},"        i = Integer.parseInt(process.replaceAll(\"gpuswitch| \", \"\"));\n",[353,8023,8024],{"class":355,"line":2317},[353,8025,3635],{},[353,8027,8028],{"class":355,"line":2328},[353,8029,856],{},[12,8031,8032],{},"拿到 0 \u002F 1 \u002F 2，再去点亮界面上对应的那个单选框。",[1085,8034,8036],{"id":8035},"二切换","二、切换",[344,8038,8040],{"className":3415,"code":8039,"language":2796,"meta":293,"style":293},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n    \"echo \\\"\" + password + \"\\\" | sudo -S pmset -a GPUSwitch \" + status};\n",[350,8041,8042,8047],{"__ignoreMap":293},[353,8043,8044],{"class":355,"line":356},[353,8045,8046],{},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n",[353,8048,8049],{"class":355,"line":297},[353,8050,8051],{},"    \"echo \\\"\" + password + \"\\\" | sudo -S pmset -a GPUSwitch \" + status};\n",[12,8053,8054,8055,8058],{},"关键在 ",[350,8056,8057],{},"sudo -S"," 这个参数。它让 sudo 从标准输入读密码 —— 不加它，sudo 会去找终端要密码，而一个图形界面程序没有终端，命令会直接卡在那里。把密码 echo 进去、管道喂给 sudo，就能在没有终端的环境里把这条命令跑完。",[1085,8060,8062],{"id":8061},"三验证密码","三、验证密码",[12,8064,8065],{},"切显卡之前得先知道密码对不对，否则用户点「应用」只会撞上一个莫名其妙的失败。",[344,8067,8069],{"className":3415,"code":8068,"language":2796,"meta":293,"style":293},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n    \"echo \\\"\" + password + \"\\\" | sudo -S whoami\"};\n",[350,8070,8071,8075],{"__ignoreMap":293},[353,8072,8073],{"class":355,"line":356},[353,8074,8046],{},[353,8076,8077],{"class":355,"line":297},[353,8078,8079],{},"    \"echo \\\"\" + password + \"\\\" | sudo -S whoami\"};\n",[12,8081,8082,8083,8086,8087,8090],{},"跑一次 ",[350,8084,8085],{},"whoami","，输出的第一行是 ",[350,8088,8089],{},"root","，就说明密码正确。",[12,8092,8093,8094,8096,8097,8100,8101,8104],{},"用 ",[350,8095,8085],{}," 而不是 ",[350,8098,8099],{},"sudo -v","，好处是它验证权限的方式和后面那条 ",[350,8102,8103],{},"pmset"," 完全一致，同时又没有任何副作用 —— 密码错了也不会误伤配置。",[12,8106,8107,8108,8111,8112,8115,8116,1307,8119,8122],{},"写正式代码之前，我先在 ",[350,8109,8110],{},"src\u002Ftest"," 下扔了两个带 ",[350,8113,8114],{},"main"," 的小类，把命令单独跑通再搬进工具类。目录里留下的 ",[350,8117,8118],{},"CheckPassword",[350,8120,8121],{},"RunPmset"," 就是当时的验证代码。",[1085,8124,8125],{"id":8125},"界面部分",[12,8127,8128,8129,1773,8132,8135,8136,8139,8140,8143,8144,8147],{},"JavaFX + FXML，没什么花活。三个 ",[350,8130,8131],{},"RadioButton",[350,8133,8134],{},"userData"," 里分别挂着 0 \u002F 1 \u002F 2，用 ",[350,8137,8138],{},"ToggleGroup"," 保证互斥；窗口初始化时先读一次当前状态，用 ",[350,8141,8142],{},"fire()"," 把对应的那个点亮。为了避免用户还没选模式就点「应用」，",[350,8145,8146],{},"applyApp()"," 里也做了一次空判断。",[34,8149,8151],{"id":8150},"记住密码是怎么存的","「记住密码」是怎么存的",[12,8153,8154,8155,7032],{},"勾上「记住密码」之后，密码不会明文落盘，而是先加密再写进程序目录下的 ",[350,8156,8157],{},"conf.properties",[1871,8159,8160,8169],{},[179,8161,8162,7032,8165,8168],{},[183,8163,8164],{},"算法",[350,8166,8167],{},"AES\u002FECB\u002FPKCS5Padding","，密文再转成 URL-safe 的 Base64 保存；",[179,8170,8171,8174,8175,8178,8179,8182],{},[183,8172,8173],{},"密钥不是写死的常量","，而是每台机器独有的一个标识 —— 跑一遍 ",[350,8176,8177],{},"system_profiler SPHardwareDataType","，抓 ",[350,8180,8181],{},"Hardware UUID:"," 那一行，去掉空格和连字符，正好 32 位十六进制，直接拿来当 AES-256 的密钥。",[12,8184,8185],{},"配置文件里只存两样东西：一个「是否记住密码」的开关，和密文本身。",[12,8187,8188,8189,8191],{},"取 Hardware UUID 而不是写死一个字符串，好处是凭据跟机器绑在一起 —— 把 ",[350,8190,8157],{}," 拷到别的机器上，密文就解不开了。反过来，换机器或者重装系统之后，之前记住的密码会失效，重新输一次就行。",[34,8193,8195],{"id":8194},"支持范围和一句要紧的警告","支持范围，和一句要紧的警告",[176,8197,8198,8205,8212,8219],{},[179,8199,8200,8201,8204],{},"实际验证过的只有一台：",[183,8202,8203],{},"MacBook Pro（15-inch，2018）+ macOS Mojave 10.14.3","；",[179,8206,8207,8208,8211],{},"理论上所有能用 ",[350,8209,8210],{},"sudo pmset -a GPUSwitch"," 切换显卡的型号都能用，欢迎大家补充自己的型号；",[179,8213,8214,8215,8218],{},"⚠️ ",[183,8216,8217],{},"只有核显的机器切勿尝试。"," 这是 README 里唯一用感叹号写的一句，我原样搬过来 —— 没有独显的机器上执行这条命令没有意义，也没人验证过会发生什么；",[179,8220,8221,8222,1307,8224,8227],{},"它只在 macOS 上有意义，依赖 ",[350,8223,8103],{},[350,8225,8226],{},"system_profiler"," 这两个系统命令。",[34,8229,2688],{"id":2688},[12,8231,8232],{},"开发环境是当年的那一套：Apache Maven 3.6、JDK 8、IntelliJ IDEA 2018.3。",[12,8234,8235],{},"当年 Oracle JDK 8 自带 JavaFX，不用另外下 SDK —— 这也是我选 JavaFX 而不是拉一堆第三方 UI 库的原因：对一个这么小的工具来说，零额外依赖比什么都重要。",[12,8237,8238,8239,8242,8243,8246],{},"跑起来很简单：clone 下来用 IDEA 打开，运行 ",[350,8240,8241],{},"cn.jxh.switcher.Main"," 就行。想打包成 macOS 的原生应用，pom 里已经配好了 JavaFX 的 Maven 插件（zenjava 8.8.3，应用名 ",[350,8244,8245],{},"MacProGPUSwitch","）。",[12,8248,8249,8250,8253,8254,8257,8258,8261],{},"版本号那处设计顺带提一句：",[350,8251,8252],{},"app.properties"," 里放的不是写死的数字，而是 ",[350,8255,8256],{},"${project.version}","，打包时由 Maven 的 resource filtering 替换成真实版本。改 pom 里的 ",[350,8259,8260],{},"\u003Cversion>"," 一处，界面「关于」里显示的版本号就跟着走。",[34,8263,8264],{"id":8264},"版本",[176,8266,8267,8273],{},[179,8268,8269,8272],{},[183,8270,8271],{},"1.0.0","（2019-02-10）：第一个版本，能读状态、能切换；",[179,8274,8275,8278],{},[183,8276,8277],{},"1.0.1","（2019-02-12）：加上 Root 密码验证，以及「记住密码」。",[12,8280,8281],{},"写完这篇的时候，正好是 1.0.1。",[34,8283,3046],{"id":3046},[12,8285,8286],{},"仓库在这里，Apache License 2.0：",[176,8288,8289],{},[179,8290,3054,8291],{},[96,8292,8293],{"href":8293,"rel":8294},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002FMacProGPUSwitch",[100],[12,8296,8297],{},"这是个很小的工具，解决的问题也很窄。但如果你也是 2018 款 MacBook Pro 的用户，被那块随时会醒过来的独显烦过，它可能正好是你要的那个开关。",[1779,8299,8300],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":293,"searchDepth":294,"depth":294,"links":8302},[8303,8304,8305,8311,8312,8313,8314,8315],{"id":7915,"depth":297,"text":7915},{"id":7933,"depth":297,"text":7933},{"id":7963,"depth":297,"text":7963,"children":8306},[8307,8308,8309,8310],{"id":7969,"depth":294,"text":7970},{"id":8035,"depth":294,"text":8036},{"id":8061,"depth":294,"text":8062},{"id":8125,"depth":294,"text":8125},{"id":8150,"depth":297,"text":8151},{"id":8194,"depth":297,"text":8195},{"id":2688,"depth":297,"text":2688},{"id":8264,"depth":297,"text":8264},{"id":3046,"depth":297,"text":3046},"2019-02-12","一个 JavaFX 写的小工具，把 macOS 里只能靠 sudo pmset 切换的显卡模式搬进了图形界面。这篇讲清它解决什么问题、三行核心代码怎么调 pmset，以及「记住密码」是怎么存下来的。",{},"\u002Fposts\u002Fmacpro-gpu-switch",{"title":7839,"description":8317},"posts\u002Fmacpro-gpu-switch",[3089,8323,8324,2080,2081],"JavaFX","macOS","U6I7kwzEWkjBx0gtZXPbqcmzLWn3SmGI4ZAHFQMmdgY",{"id":8327,"title":5416,"body":8328,"date":9262,"description":9263,"extension":305,"meta":9264,"navigation":307,"path":5426,"seo":9265,"stem":9266,"tags":9267,"__hash__":9268},"posts\u002Fposts\u002Fjar2pom-nexus2-dependency.md",{"type":9,"value":8329,"toc":9258},[8330,8339,9184,9188,9247,9250,9256],[8331,8332,8333],"blockquote",{},[12,8334,8335,8336,406],{},"此版本基于 Nexus OSS 2 相关接口。\n基于 Maven 中心库的版本请",[96,8337,8338],{"href":6669},"点这里",[344,8340,8342],{"className":3415,"code":8341,"language":2796,"meta":293,"style":293},"package com.jxh.tool;\n\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.util.EntityUtils;\nimport org.dom4j.Document;\nimport org.dom4j.DocumentException;\nimport org.dom4j.DocumentHelper;\nimport org.dom4j.Element;\nimport org.dom4j.dom.DOMElement;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.security.MessageDigest;\nimport java.util.jar.*;\n\n\u002F**\n * 通过Jar包SHA1或MD5生成Pom文件\n *\n * @author JiaXiaohei\n * @date 2018-03-16\n *\u002F\npublic class Jar2pom {\n\n    \u002F**\n     * Maven库\n     *\u002F\n    \u002F\u002Fpublic static final String nexusUrl = \"http:\u002F\u002Fmaven.aliyun.com\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n    public static final String nexusUrl = \"http:\u002F\u002F59.110.144.164\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n\n\n    public static void main(String[] args) {\n    \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n        File libs = new File(\"D:\\\\lib\");\n        for (File jar : libs.listFiles()) {\n            System.out.println(\"\u003C!--  \" + jar.getName() + \" -->\");\n            if (!getPomByChecksum(jar).isTextOnly()) {\n                System.out.println(\"\u003C!--  Search by Checksum -->\");\n                System.out.println(getPomByChecksum(jar).asXML());\n            } else if (!getPomByManifest(jar).isTextOnly()) {\n                System.out.println(\"\u003C!--  Search by Manifest -->\");\n                System.out.println(getPomByManifest(jar).asXML());\n            } else {\n                System.out.println(\"\u003C!--  No data was found -->\");\n            }\n            System.out.println();\n        }\n\n    }\n\n    \u002F**\n     * 通过Jar SHA1返回Pom dependency\n     *\n     * @param file\n     * @return\n     *\u002F\n    public static Element getPomByChecksum(File file) {\n        String checkSum = getCheckSum(file, \"SHA1\");\n        String xml = doGet(nexusUrl + \"?sha1=\" + checkSum);\n        return assemblePomElement(xml);\n    }\n\n    \u002F**\n     * 通过Jar Manifest返回Pom dependency\n     *\n     * @param file\n     * @return\n     *\u002F\n    public static Element getPomByManifest(File file) {\n        try {\n            JarFile jarfile = new JarFile(file);\n            Manifest mainmanifest = jarfile.getManifest();\n            jarfile.close();\n            if (null == mainmanifest) {\n                return new DOMElement(\"dependency\");\n            }\n            String a = null, v = null;\n            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Extension-Name\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Extension-Name\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Title\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Title\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Title\"))) {\n                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Title\"));\n            }\n            if (a != null && a.length() != 0) {\n                a = a.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n            }\n            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Bundle-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Bundle-Version\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Version\"));\n            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Version\"))) {\n                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Version\"));\n            }\n            if (v != null && v.length() != 0) {\n                v = v.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n            }\n            String xml = doGet(nexusUrl + \"?a=\" + a + \"&v=\" + v);\n            return assemblePomElement(xml);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return new DOMElement(\"dependency\");\n    }\n\n    \u002F**\n     * 解析获取的XML 组装dependency\n     *\n     * @param xml\n     * @return\n     *\u002F\n    public static Element assemblePomElement(String xml) {\n        Element dependency = new DOMElement(\"dependency\");\n\n        if (xml != null && xml.length() != 0) {\n            try {\n                Document document = DocumentHelper.parseText(xml);\n                Element dataElement = document.getRootElement().element(\"data\");\n                if (dataElement.getText() != null && dataElement.getText().length() != 0) {\n                    Element artifactElement = dataElement.element(\"artifact\");\n                    dependency.add((Element) artifactElement.element(\"groupId\").clone());\n                    dependency.add((Element) artifactElement.element(\"artifactId\").clone());\n                    dependency.add((Element) artifactElement.element(\"version\").clone());\n                }\n            } catch (DocumentException e) {\n                e.printStackTrace();\n            }\n        }\n        return dependency;\n    }\n\n    \u002F**\n     * 发起Get请求\n     *\n     * @param url\n     * @return\n     *\u002F\n    public static String doGet(String url) {\n        String srtResult = null;\n        CloseableHttpClient httpCilent = HttpClients.createDefault();\n        HttpGet httpGet = new HttpGet(url);\n        try {\n            HttpResponse httpResponse = httpCilent.execute(httpGet);\n            srtResult = EntityUtils.toString(httpResponse.getEntity());\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                httpCilent.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return srtResult;\n    }\n\n    \u002F**\n     * 计算CheckSum\n     *\n     * @param file\n     * @param algorithm SHA1 or MD5\n     * @return\n     *\u002F\n    public static String getCheckSum(File file, String algorithm) {\n        if (!file.isFile()) {\n            return null;\n        }\n        MessageDigest digest = null;\n        FileInputStream in = null;\n        byte buffer[] = new byte[1024];\n        int len;\n        try {\n            digest = MessageDigest.getInstance(algorithm);\n            in = new FileInputStream(file);\n            while ((len = in.read(buffer, 0, 1024)) != -1) {\n                digest.update(buffer, 0, len);\n            }\n            in.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n        BigInteger bigInt = new BigInteger(1, digest.digest());\n        return bigInt.toString(16);\n    }\n\n}\n",[350,8343,8344,8349,8353,8358,8363,8368,8373,8378,8383,8388,8393,8398,8403,8407,8412,8417,8422,8427,8432,8437,8441,8445,8450,8455,8460,8465,8469,8474,8478,8482,8487,8491,8496,8501,8505,8509,8513,8518,8522,8526,8530,8535,8539,8544,8549,8553,8558,8563,8568,8572,8576,8580,8584,8588,8592,8596,8600,8604,8608,8612,8616,8621,8625,8630,8635,8639,8643,8647,8651,8655,8659,8663,8667,8672,8676,8680,8684,8688,8692,8697,8701,8705,8709,8713,8717,8721,8725,8729,8733,8737,8741,8745,8749,8753,8757,8761,8765,8769,8773,8777,8781,8785,8790,8795,8799,8803,8807,8812,8816,8820,8824,8829,8833,8838,8842,8846,8851,8855,8859,8864,8868,8873,8878,8883,8888,8893,8898,8903,8907,8912,8916,8920,8924,8928,8932,8936,8940,8944,8948,8952,8956,8960,8964,8968,8972,8976,8980,8984,8988,8992,8996,9000,9004,9008,9012,9016,9020,9024,9028,9032,9036,9040,9044,9048,9052,9056,9060,9064,9069,9074,9079,9084,9089,9094,9099,9104,9109,9114,9119,9124,9129,9134,9139,9144,9149,9154,9159,9164,9169,9174,9179],{"__ignoreMap":293},[353,8345,8346],{"class":355,"line":356},[353,8347,8348],{},"package com.jxh.tool;\n",[353,8350,8351],{"class":355,"line":297},[353,8352,3483],{"emptyLinePlaceholder":307},[353,8354,8355],{"class":355,"line":294},[353,8356,8357],{},"import org.apache.http.HttpResponse;\n",[353,8359,8360],{"class":355,"line":721},[353,8361,8362],{},"import org.apache.http.client.methods.HttpGet;\n",[353,8364,8365],{"class":355,"line":1584},[353,8366,8367],{},"import org.apache.http.impl.client.CloseableHttpClient;\n",[353,8369,8370],{"class":355,"line":2317},[353,8371,8372],{},"import org.apache.http.impl.client.HttpClients;\n",[353,8374,8375],{"class":355,"line":2328},[353,8376,8377],{},"import org.apache.http.util.EntityUtils;\n",[353,8379,8380],{"class":355,"line":2334},[353,8381,8382],{},"import org.dom4j.Document;\n",[353,8384,8385],{"class":355,"line":2348},[353,8386,8387],{},"import org.dom4j.DocumentException;\n",[353,8389,8390],{"class":355,"line":2362},[353,8391,8392],{},"import org.dom4j.DocumentHelper;\n",[353,8394,8395],{"class":355,"line":2376},[353,8396,8397],{},"import org.dom4j.Element;\n",[353,8399,8400],{"class":355,"line":3172},[353,8401,8402],{},"import org.dom4j.dom.DOMElement;\n",[353,8404,8405],{"class":355,"line":3245},[353,8406,3483],{"emptyLinePlaceholder":307},[353,8408,8409],{"class":355,"line":3251},[353,8410,8411],{},"import java.io.File;\n",[353,8413,8414],{"class":355,"line":3257},[353,8415,8416],{},"import java.io.FileInputStream;\n",[353,8418,8419],{"class":355,"line":3263},[353,8420,8421],{},"import java.io.IOException;\n",[353,8423,8424],{"class":355,"line":3269},[353,8425,8426],{},"import java.math.BigInteger;\n",[353,8428,8429],{"class":355,"line":3275},[353,8430,8431],{},"import java.security.MessageDigest;\n",[353,8433,8434],{"class":355,"line":3280},[353,8435,8436],{},"import java.util.jar.*;\n",[353,8438,8439],{"class":355,"line":3286},[353,8440,3483],{"emptyLinePlaceholder":307},[353,8442,8443],{"class":355,"line":3291},[353,8444,3517],{},[353,8446,8447],{"class":355,"line":3525},[353,8448,8449],{}," * 通过Jar包SHA1或MD5生成Pom文件\n",[353,8451,8452],{"class":355,"line":3531},[353,8453,8454],{}," *\n",[353,8456,8457],{"class":355,"line":3537},[353,8458,8459],{}," * @author JiaXiaohei\n",[353,8461,8462],{"class":355,"line":3543},[353,8463,8464],{}," * @date 2018-03-16\n",[353,8466,8467],{"class":355,"line":3548},[353,8468,3528],{},[353,8470,8471],{"class":355,"line":3554},[353,8472,8473],{},"public class Jar2pom {\n",[353,8475,8476],{"class":355,"line":3559},[353,8477,3483],{"emptyLinePlaceholder":307},[353,8479,8480],{"class":355,"line":3565},[353,8481,3646],{},[353,8483,8484],{"class":355,"line":3571},[353,8485,8486],{},"     * Maven库\n",[353,8488,8489],{"class":355,"line":3576},[353,8490,3670],{},[353,8492,8493],{"class":355,"line":3581},[353,8494,8495],{},"    \u002F\u002Fpublic static final String nexusUrl = \"http:\u002F\u002Fmaven.aliyun.com\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n",[353,8497,8498],{"class":355,"line":3587},[353,8499,8500],{},"    public static final String nexusUrl = \"http:\u002F\u002F59.110.144.164\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n",[353,8502,8503],{"class":355,"line":3592},[353,8504,3483],{"emptyLinePlaceholder":307},[353,8506,8507],{"class":355,"line":3598},[353,8508,3483],{"emptyLinePlaceholder":307},[353,8510,8511],{"class":355,"line":3603},[353,8512,5471],{},[353,8514,8515],{"class":355,"line":3609},[353,8516,8517],{},"    \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n",[353,8519,8520],{"class":355,"line":3614},[353,8521,5481],{},[353,8523,8524],{"class":355,"line":3620},[353,8525,5486],{},[353,8527,8528],{"class":355,"line":3626},[353,8529,5495],{},[353,8531,8532],{"class":355,"line":3632},[353,8533,8534],{},"            if (!getPomByChecksum(jar).isTextOnly()) {\n",[353,8536,8537],{"class":355,"line":3638},[353,8538,5514],{},[353,8540,8541],{"class":355,"line":3643},[353,8542,8543],{},"                System.out.println(getPomByChecksum(jar).asXML());\n",[353,8545,8546],{"class":355,"line":3649},[353,8547,8548],{},"            } else if (!getPomByManifest(jar).isTextOnly()) {\n",[353,8550,8551],{"class":355,"line":3655},[353,8552,5546],{},[353,8554,8555],{"class":355,"line":3661},[353,8556,8557],{},"                System.out.println(getPomByManifest(jar).asXML());\n",[353,8559,8560],{"class":355,"line":3667},[353,8561,8562],{},"            } else {\n",[353,8564,8565],{"class":355,"line":3673},[353,8566,8567],{},"                System.out.println(\"\u003C!--  No data was found -->\");\n",[353,8569,8570],{"class":355,"line":3679},[353,8571,3868],{},[353,8573,8574],{"class":355,"line":3685},[353,8575,5576],{},[353,8577,8578],{"class":355,"line":3690},[353,8579,4036],{},[353,8581,8582],{"class":355,"line":3695},[353,8583,3483],{"emptyLinePlaceholder":307},[353,8585,8586],{"class":355,"line":3700},[353,8587,3635],{},[353,8589,8590],{"class":355,"line":3706},[353,8591,3483],{"emptyLinePlaceholder":307},[353,8593,8594],{"class":355,"line":3711},[353,8595,3646],{},[353,8597,8598],{"class":355,"line":3716},[353,8599,5601],{},[353,8601,8602],{"class":355,"line":3721},[353,8603,3658],{},[353,8605,8606],{"class":355,"line":3727},[353,8607,5610],{},[353,8609,8610],{"class":355,"line":3733},[353,8611,3664],{},[353,8613,8614],{"class":355,"line":3738},[353,8615,3670],{},[353,8617,8618],{"class":355,"line":3743},[353,8619,8620],{},"    public static Element getPomByChecksum(File file) {\n",[353,8622,8623],{"class":355,"line":3748},[353,8624,5637],{},[353,8626,8627],{"class":355,"line":3754},[353,8628,8629],{},"        String xml = doGet(nexusUrl + \"?sha1=\" + checkSum);\n",[353,8631,8632],{"class":355,"line":3759},[353,8633,8634],{},"        return assemblePomElement(xml);\n",[353,8636,8637],{"class":355,"line":3765},[353,8638,3635],{},[353,8640,8641],{"class":355,"line":3770},[353,8642,3483],{"emptyLinePlaceholder":307},[353,8644,8645],{"class":355,"line":3776},[353,8646,3646],{},[353,8648,8649],{"class":355,"line":3782},[353,8650,5691],{},[353,8652,8653],{"class":355,"line":3788},[353,8654,3658],{},[353,8656,8657],{"class":355,"line":3794},[353,8658,5610],{},[353,8660,8661],{"class":355,"line":3800},[353,8662,3664],{},[353,8664,8665],{"class":355,"line":3806},[353,8666,3670],{},[353,8668,8669],{"class":355,"line":3812},[353,8670,8671],{},"    public static Element getPomByManifest(File file) {\n",[353,8673,8674],{"class":355,"line":3818},[353,8675,5725],{},[353,8677,8678],{"class":355,"line":3824},[353,8679,5730],{},[353,8681,8682],{"class":355,"line":3830},[353,8683,5735],{},[353,8685,8686],{"class":355,"line":3836},[353,8687,5740],{},[353,8689,8690],{"class":355,"line":3841},[353,8691,5745],{},[353,8693,8694],{"class":355,"line":3847},[353,8695,8696],{},"                return new DOMElement(\"dependency\");\n",[353,8698,8699],{"class":355,"line":3853},[353,8700,3868],{},[353,8702,8703],{"class":355,"line":3859},[353,8704,5759],{},[353,8706,8707],{"class":355,"line":3865},[353,8708,5764],{},[353,8710,8711],{"class":355,"line":3871},[353,8712,5769],{},[353,8714,8715],{"class":355,"line":3877},[353,8716,5774],{},[353,8718,8719],{"class":355,"line":3882},[353,8720,5779],{},[353,8722,8723],{"class":355,"line":3887},[353,8724,5784],{},[353,8726,8727],{"class":355,"line":3892},[353,8728,5789],{},[353,8730,8731],{"class":355,"line":3898},[353,8732,3868],{},[353,8734,8735],{"class":355,"line":3903},[353,8736,5798],{},[353,8738,8739],{"class":355,"line":3909},[353,8740,5803],{},[353,8742,8743],{"class":355,"line":3914},[353,8744,3868],{},[353,8746,8747],{"class":355,"line":3919},[353,8748,5812],{},[353,8750,8751],{"class":355,"line":3925},[353,8752,5817],{},[353,8754,8755],{"class":355,"line":3931},[353,8756,5822],{},[353,8758,8759],{"class":355,"line":3937},[353,8760,5827],{},[353,8762,8763],{"class":355,"line":3943},[353,8764,5832],{},[353,8766,8767],{"class":355,"line":3949},[353,8768,5837],{},[353,8770,8771],{"class":355,"line":3955},[353,8772,3868],{},[353,8774,8775],{"class":355,"line":3960},[353,8776,5846],{},[353,8778,8779],{"class":355,"line":3965},[353,8780,5851],{},[353,8782,8783],{"class":355,"line":3970},[353,8784,3868],{},[353,8786,8787],{"class":355,"line":3976},[353,8788,8789],{},"            String xml = doGet(nexusUrl + \"?a=\" + a + \"&v=\" + v);\n",[353,8791,8792],{"class":355,"line":3981},[353,8793,8794],{},"            return assemblePomElement(xml);\n",[353,8796,8797],{"class":355,"line":3987},[353,8798,5888],{},[353,8800,8801],{"class":355,"line":3993},[353,8802,5893],{},[353,8804,8805],{"class":355,"line":3998},[353,8806,4036],{},[353,8808,8809],{"class":355,"line":4003},[353,8810,8811],{},"        return new DOMElement(\"dependency\");\n",[353,8813,8814],{"class":355,"line":4009},[353,8815,3635],{},[353,8817,8818],{"class":355,"line":4015},[353,8819,3483],{"emptyLinePlaceholder":307},[353,8821,8822],{"class":355,"line":4021},[353,8823,3646],{},[353,8825,8826],{"class":355,"line":4027},[353,8827,8828],{},"     * 解析获取的XML 组装dependency\n",[353,8830,8831],{"class":355,"line":4033},[353,8832,3658],{},[353,8834,8835],{"class":355,"line":4039},[353,8836,8837],{},"     * @param xml\n",[353,8839,8840],{"class":355,"line":4045},[353,8841,3664],{},[353,8843,8844],{"class":355,"line":4050},[353,8845,3670],{},[353,8847,8848],{"class":355,"line":4055},[353,8849,8850],{},"    public static Element assemblePomElement(String xml) {\n",[353,8852,8853],{"class":355,"line":5998},[353,8854,5945],{},[353,8856,8857],{"class":355,"line":6004},[353,8858,3483],{"emptyLinePlaceholder":307},[353,8860,8861],{"class":355,"line":6009},[353,8862,8863],{},"        if (xml != null && xml.length() != 0) {\n",[353,8865,8866],{"class":355,"line":6014},[353,8867,6074],{},[353,8869,8870],{"class":355,"line":6020},[353,8871,8872],{},"                Document document = DocumentHelper.parseText(xml);\n",[353,8874,8875],{"class":355,"line":6026},[353,8876,8877],{},"                Element dataElement = document.getRootElement().element(\"data\");\n",[353,8879,8880],{"class":355,"line":6032},[353,8881,8882],{},"                if (dataElement.getText() != null && dataElement.getText().length() != 0) {\n",[353,8884,8885],{"class":355,"line":6038},[353,8886,8887],{},"                    Element artifactElement = dataElement.element(\"artifact\");\n",[353,8889,8890],{"class":355,"line":6043},[353,8891,8892],{},"                    dependency.add((Element) artifactElement.element(\"groupId\").clone());\n",[353,8894,8895],{"class":355,"line":6049},[353,8896,8897],{},"                    dependency.add((Element) artifactElement.element(\"artifactId\").clone());\n",[353,8899,8900],{"class":355,"line":6055},[353,8901,8902],{},"                    dependency.add((Element) artifactElement.element(\"version\").clone());\n",[353,8904,8905],{"class":355,"line":6060},[353,8906,3815],{},[353,8908,8909],{"class":355,"line":6065},[353,8910,8911],{},"            } catch (DocumentException e) {\n",[353,8913,8914],{"class":355,"line":6071},[353,8915,6092],{},[353,8917,8918],{"class":355,"line":6077},[353,8919,3868],{},[353,8921,8922],{"class":355,"line":6083},[353,8923,4036],{},[353,8925,8926],{"class":355,"line":6089},[353,8927,5974],{},[353,8929,8930],{"class":355,"line":6095},[353,8931,3635],{},[353,8933,8934],{"class":355,"line":6100},[353,8935,3483],{"emptyLinePlaceholder":307},[353,8937,8938],{"class":355,"line":6105},[353,8939,3646],{},[353,8941,8942],{"class":355,"line":6111},[353,8943,5991],{},[353,8945,8946],{"class":355,"line":6116},[353,8947,3658],{},[353,8949,8950],{"class":355,"line":6121},[353,8951,6001],{},[353,8953,8954],{"class":355,"line":6126},[353,8955,3664],{},[353,8957,8958],{"class":355,"line":6132},[353,8959,3670],{},[353,8961,8962],{"class":355,"line":6137},[353,8963,6017],{},[353,8965,8966],{"class":355,"line":6142},[353,8967,6023],{},[353,8969,8970],{"class":355,"line":6148},[353,8971,6029],{},[353,8973,8974],{"class":355,"line":6153},[353,8975,6035],{},[353,8977,8978],{"class":355,"line":6158},[353,8979,5725],{},[353,8981,8982],{"class":355,"line":6164},[353,8983,6046],{},[353,8985,8986],{"class":355,"line":6170},[353,8987,6052],{},[353,8989,8990],{"class":355,"line":6176},[353,8991,5888],{},[353,8993,8994],{"class":355,"line":6181},[353,8995,5893],{},[353,8997,8998],{"class":355,"line":6187},[353,8999,6068],{},[353,9001,9002],{"class":355,"line":6193},[353,9003,6074],{},[353,9005,9006],{"class":355,"line":6199},[353,9007,6080],{},[353,9009,9010],{"class":355,"line":6205},[353,9011,6086],{},[353,9013,9014],{"class":355,"line":6210},[353,9015,6092],{},[353,9017,9018],{"class":355,"line":6216},[353,9019,3868],{},[353,9021,9022],{"class":355,"line":6222},[353,9023,4036],{},[353,9025,9026],{"class":355,"line":6228},[353,9027,6108],{},[353,9029,9030],{"class":355,"line":6234},[353,9031,3635],{},[353,9033,9034],{"class":355,"line":6239},[353,9035,3483],{"emptyLinePlaceholder":307},[353,9037,9038],{"class":355,"line":6245},[353,9039,3646],{},[353,9041,9042],{"class":355,"line":6251},[353,9043,6129],{},[353,9045,9046],{"class":355,"line":6256},[353,9047,3658],{},[353,9049,9050],{"class":355,"line":6261},[353,9051,5610],{},[353,9053,9054],{"class":355,"line":6266},[353,9055,6145],{},[353,9057,9058],{"class":355,"line":6272},[353,9059,3664],{},[353,9061,9062],{"class":355,"line":6278},[353,9063,3670],{},[353,9065,9067],{"class":355,"line":9066},168,[353,9068,6161],{},[353,9070,9072],{"class":355,"line":9071},169,[353,9073,6167],{},[353,9075,9077],{"class":355,"line":9076},170,[353,9078,6173],{},[353,9080,9082],{"class":355,"line":9081},171,[353,9083,4036],{},[353,9085,9087],{"class":355,"line":9086},172,[353,9088,6184],{},[353,9090,9092],{"class":355,"line":9091},173,[353,9093,6190],{},[353,9095,9097],{"class":355,"line":9096},174,[353,9098,6196],{},[353,9100,9102],{"class":355,"line":9101},175,[353,9103,6202],{},[353,9105,9107],{"class":355,"line":9106},176,[353,9108,5725],{},[353,9110,9112],{"class":355,"line":9111},177,[353,9113,6213],{},[353,9115,9117],{"class":355,"line":9116},178,[353,9118,6219],{},[353,9120,9122],{"class":355,"line":9121},179,[353,9123,6225],{},[353,9125,9127],{"class":355,"line":9126},180,[353,9128,6231],{},[353,9130,9132],{"class":355,"line":9131},181,[353,9133,3868],{},[353,9135,9137],{"class":355,"line":9136},182,[353,9138,6242],{},[353,9140,9142],{"class":355,"line":9141},183,[353,9143,6248],{},[353,9145,9147],{"class":355,"line":9146},184,[353,9148,5893],{},[353,9150,9152],{"class":355,"line":9151},185,[353,9153,6173],{},[353,9155,9157],{"class":355,"line":9156},186,[353,9158,4036],{},[353,9160,9162],{"class":355,"line":9161},187,[353,9163,6269],{},[353,9165,9167],{"class":355,"line":9166},188,[353,9168,6275],{},[353,9170,9172],{"class":355,"line":9171},189,[353,9173,3635],{},[353,9175,9177],{"class":355,"line":9176},190,[353,9178,3483],{"emptyLinePlaceholder":307},[353,9180,9182],{"class":355,"line":9181},191,[353,9183,856],{},[34,9185,9187],{"id":9186},"依赖-jar","依赖 Jar",[344,9189,9193],{"className":9190,"code":9191,"language":9192,"meta":293,"style":293},"language-xml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","        \u003Cdependency>\n            \u003CgroupId>org.apache.httpcomponents\u003C\u002FgroupId>\n            \u003CartifactId>httpclient\u003C\u002FartifactId>\n            \u003Cversion>4.5.5\u003C\u002Fversion>\n        \u003C\u002Fdependency>\n\n        \u003Cdependency>\n            \u003CgroupId>org.dom4j\u003C\u002FgroupId>\n            \u003CartifactId>dom4j\u003C\u002FartifactId>\n            \u003Cversion>[2.1.1,)\u003C\u002Fversion>\n        \u003C\u002Fdependency>\n","xml",[350,9194,9195,9200,9205,9210,9215,9220,9224,9228,9233,9238,9243],{"__ignoreMap":293},[353,9196,9197],{"class":355,"line":356},[353,9198,9199],{},"        \u003Cdependency>\n",[353,9201,9202],{"class":355,"line":297},[353,9203,9204],{},"            \u003CgroupId>org.apache.httpcomponents\u003C\u002FgroupId>\n",[353,9206,9207],{"class":355,"line":294},[353,9208,9209],{},"            \u003CartifactId>httpclient\u003C\u002FartifactId>\n",[353,9211,9212],{"class":355,"line":721},[353,9213,9214],{},"            \u003Cversion>4.5.5\u003C\u002Fversion>\n",[353,9216,9217],{"class":355,"line":1584},[353,9218,9219],{},"        \u003C\u002Fdependency>\n",[353,9221,9222],{"class":355,"line":2317},[353,9223,3483],{"emptyLinePlaceholder":307},[353,9225,9226],{"class":355,"line":2328},[353,9227,9199],{},[353,9229,9230],{"class":355,"line":2334},[353,9231,9232],{},"            \u003CgroupId>org.dom4j\u003C\u002FgroupId>\n",[353,9234,9235],{"class":355,"line":2348},[353,9236,9237],{},"            \u003CartifactId>dom4j\u003C\u002FartifactId>\n",[353,9239,9240],{"class":355,"line":2362},[353,9241,9242],{},"            \u003Cversion>[2.1.1,)\u003C\u002Fversion>\n",[353,9244,9245],{"class":355,"line":2376},[353,9246,9219],{},[34,9248,9249],{"id":9249},"开发环境",[344,9251,9254],{"className":9252,"code":9253,"language":2831},[2829],"jdk1.7.0_80\napache-maven-3.5.0\nIntelliJ IDEA Community Edition 2017.1.4 x64\n",[350,9255,9253],{"__ignoreMap":293},[1779,9257,3304],{},{"title":293,"searchDepth":294,"depth":294,"links":9259},[9260,9261],{"id":9186,"depth":297,"text":9187},{"id":9249,"depth":297,"text":9249},"2018-03-18","给非 Maven 项目的一堆本地 jar 生成 dependency。用 jar 的 SHA1 去 Nexus OSS 2 的 lucene 接口反查坐标，查不到再退回解析 Manifest。",{},{"title":5416,"description":9263},"posts\u002Fjar2pom-nexus2-dependency",[6673,3089,2081],"N6S1Bh1OtcM7yjACIQns3iLoKMfkeLyq1DuPPB856kg",{"id":9270,"title":9271,"body":9272,"date":9667,"description":9668,"extension":305,"meta":9669,"navigation":307,"path":9670,"seo":9671,"stem":9672,"tags":9673,"__hash__":9676},"posts\u002Fposts\u002Foracle-sort-positive-negative.md","ORACLE 正负数分开排序 SQL",{"type":9,"value":9273,"toc":9661},[9274,9277,9306,9309,9349,9419,9423,9443,9468,9545,9549,9567,9589,9659],[34,9275,9276],{"id":9276},"表结构",[344,9278,9280],{"className":2700,"code":9279,"language":2702,"meta":293,"style":293},"create table TEST_ORDER\n(\n  t_name  VARCHAR2(5),\n  t_value NUMBER(3)\n);\n",[350,9281,9282,9287,9292,9297,9302],{"__ignoreMap":293},[353,9283,9284],{"class":355,"line":356},[353,9285,9286],{},"create table TEST_ORDER\n",[353,9288,9289],{"class":355,"line":297},[353,9290,9291],{},"(\n",[353,9293,9294],{"class":355,"line":294},[353,9295,9296],{},"  t_name  VARCHAR2(5),\n",[353,9298,9299],{"class":355,"line":721},[353,9300,9301],{},"  t_value NUMBER(3)\n",[353,9303,9304],{"class":355,"line":1584},[353,9305,2759],{},[34,9307,9308],{"id":9308},"表数据",[344,9310,9312],{"className":2700,"code":9311,"language":2702,"meta":293,"style":293},"insert into TEST_ORDER (t_name, t_value) values ('A', 10);\ninsert into TEST_ORDER (t_name, t_value) values ('B', 30);\ninsert into TEST_ORDER (t_name, t_value) values ('C', 20);\ninsert into TEST_ORDER (t_name, t_value) values ('D', 40);\ninsert into TEST_ORDER (t_name, t_value) values ('E', -10);\ninsert into TEST_ORDER (t_name, t_value) values ('F', -30);\ninsert into TEST_ORDER (t_name, t_value) values ('G', -20);\n",[350,9313,9314,9319,9324,9329,9334,9339,9344],{"__ignoreMap":293},[353,9315,9316],{"class":355,"line":356},[353,9317,9318],{},"insert into TEST_ORDER (t_name, t_value) values ('A', 10);\n",[353,9320,9321],{"class":355,"line":297},[353,9322,9323],{},"insert into TEST_ORDER (t_name, t_value) values ('B', 30);\n",[353,9325,9326],{"class":355,"line":294},[353,9327,9328],{},"insert into TEST_ORDER (t_name, t_value) values ('C', 20);\n",[353,9330,9331],{"class":355,"line":721},[353,9332,9333],{},"insert into TEST_ORDER (t_name, t_value) values ('D', 40);\n",[353,9335,9336],{"class":355,"line":1584},[353,9337,9338],{},"insert into TEST_ORDER (t_name, t_value) values ('E', -10);\n",[353,9340,9341],{"class":355,"line":2317},[353,9342,9343],{},"insert into TEST_ORDER (t_name, t_value) values ('F', -30);\n",[353,9345,9346],{"class":355,"line":2328},[353,9347,9348],{},"insert into TEST_ORDER (t_name, t_value) values ('G', -20);\n",[63,9350,9351,9361],{},[66,9352,9353],{},[69,9354,9355,9358],{},[72,9356,9357],{},"T_NAME",[72,9359,9360],{},"T_VALUE",[82,9362,9363,9371,9379,9387,9395,9403,9411],{},[69,9364,9365,9368],{},[87,9366,9367],{},"A",[87,9369,9370],{},"10",[69,9372,9373,9376],{},[87,9374,9375],{},"B",[87,9377,9378],{},"30",[69,9380,9381,9384],{},[87,9382,9383],{},"C",[87,9385,9386],{},"20",[69,9388,9389,9392],{},[87,9390,9391],{},"D",[87,9393,9394],{},"40",[69,9396,9397,9400],{},[87,9398,9399],{},"E",[87,9401,9402],{},"-10",[69,9404,9405,9408],{},[87,9406,9407],{},"F",[87,9409,9410],{},"-30",[69,9412,9413,9416],{},[87,9414,9415],{},"G",[87,9417,9418],{},"-20",[34,9420,9422],{"id":9421},"先正后负-正数升序-负数降序","先正后负 正数升序 负数降序",[344,9424,9426],{"className":2700,"code":9425,"language":2702,"meta":293,"style":293},"SELECT T_NAME, T_VALUE\n  FROM TEST_ORDER\n ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC;\n",[350,9427,9428,9433,9438],{"__ignoreMap":293},[353,9429,9430],{"class":355,"line":356},[353,9431,9432],{},"SELECT T_NAME, T_VALUE\n",[353,9434,9435],{"class":355,"line":297},[353,9436,9437],{},"  FROM TEST_ORDER\n",[353,9439,9440],{"class":355,"line":294},[353,9441,9442],{}," ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC;\n",[344,9444,9446],{"className":2700,"code":9445,"language":2702,"meta":293,"style":293},"SELECT T_NAME,\n       T_VALUE,\n       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC) AS RANKING\n  FROM TEST_ORDER;\n",[350,9447,9448,9453,9458,9463],{"__ignoreMap":293},[353,9449,9450],{"class":355,"line":356},[353,9451,9452],{},"SELECT T_NAME,\n",[353,9454,9455],{"class":355,"line":297},[353,9456,9457],{},"       T_VALUE,\n",[353,9459,9460],{"class":355,"line":294},[353,9461,9462],{},"       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC) AS RANKING\n",[353,9464,9465],{"class":355,"line":721},[353,9466,9467],{},"  FROM TEST_ORDER;\n",[63,9469,9470,9481],{},[66,9471,9472],{},[69,9473,9474,9476,9478],{},[72,9475,9357],{},[72,9477,9360],{},[72,9479,9480],{},"RANKING",[82,9482,9483,9491,9500,9509,9518,9527,9536],{},[69,9484,9485,9487,9489],{},[87,9486,9367],{},[87,9488,9370],{},[87,9490,2665],{},[69,9492,9493,9495,9497],{},[87,9494,9383],{},[87,9496,9386],{},[87,9498,9499],{},"2",[69,9501,9502,9504,9506],{},[87,9503,9375],{},[87,9505,9378],{},[87,9507,9508],{},"3",[69,9510,9511,9513,9515],{},[87,9512,9391],{},[87,9514,9394],{},[87,9516,9517],{},"4",[69,9519,9520,9522,9524],{},[87,9521,9399],{},[87,9523,9402],{},[87,9525,9526],{},"5",[69,9528,9529,9531,9533],{},[87,9530,9415],{},[87,9532,9418],{},[87,9534,9535],{},"6",[69,9537,9538,9540,9542],{},[87,9539,9407],{},[87,9541,9410],{},[87,9543,9544],{},"7",[34,9546,9548],{"id":9547},"先正后负-正数降序-负数升序","先正后负 正数降序 负数升序",[344,9550,9552],{"className":2700,"code":9551,"language":2702,"meta":293,"style":293},"SELECT T_NAME, T_VALUE\n  FROM TEST_ORDER\n ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC;\n",[350,9553,9554,9558,9562],{"__ignoreMap":293},[353,9555,9556],{"class":355,"line":356},[353,9557,9432],{},[353,9559,9560],{"class":355,"line":297},[353,9561,9437],{},[353,9563,9564],{"class":355,"line":294},[353,9565,9566],{}," ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC;\n",[344,9568,9570],{"className":2700,"code":9569,"language":2702,"meta":293,"style":293},"SELECT T_NAME,\n       T_VALUE,\n       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC) AS RANKING\n  FROM TEST_ORDER;\n",[350,9571,9572,9576,9580,9585],{"__ignoreMap":293},[353,9573,9574],{"class":355,"line":356},[353,9575,9452],{},[353,9577,9578],{"class":355,"line":297},[353,9579,9457],{},[353,9581,9582],{"class":355,"line":294},[353,9583,9584],{},"       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC) AS RANKING\n",[353,9586,9587],{"class":355,"line":721},[353,9588,9467],{},[63,9590,9591,9601],{},[66,9592,9593],{},[69,9594,9595,9597,9599],{},[72,9596,9357],{},[72,9598,9360],{},[72,9600,9480],{},[82,9602,9603,9611,9619,9627,9635,9643,9651],{},[69,9604,9605,9607,9609],{},[87,9606,9391],{},[87,9608,9394],{},[87,9610,2665],{},[69,9612,9613,9615,9617],{},[87,9614,9375],{},[87,9616,9378],{},[87,9618,9499],{},[69,9620,9621,9623,9625],{},[87,9622,9383],{},[87,9624,9386],{},[87,9626,9508],{},[69,9628,9629,9631,9633],{},[87,9630,9367],{},[87,9632,9370],{},[87,9634,9517],{},[69,9636,9637,9639,9641],{},[87,9638,9407],{},[87,9640,9410],{},[87,9642,9526],{},[69,9644,9645,9647,9649],{},[87,9646,9415],{},[87,9648,9418],{},[87,9650,9535],{},[69,9652,9653,9655,9657],{},[87,9654,9399],{},[87,9656,9402],{},[87,9658,9544],{},[1779,9660,3304],{},{"title":293,"searchDepth":294,"depth":294,"links":9662},[9663,9664,9665,9666],{"id":9276,"depth":297,"text":9276},{"id":9308,"depth":297,"text":9308},{"id":9421,"depth":297,"text":9422},{"id":9547,"depth":297,"text":9548},"2017-09-12","用 SIGN() 把正数和负数分成两组，再各自按绝对值升序或降序排。附 RANK() 版本。",{},"\u002Fposts\u002Foracle-sort-positive-negative",{"title":9271,"description":9668},"posts\u002Foracle-sort-positive-negative",[9674,9675],"Oracle","SQL","M56SlfAqK0uBBScuf5UIwsQ--405GEtCa-zRbdbpBfo",{"id":9678,"title":9679,"body":9680,"date":11228,"description":11229,"extension":305,"meta":11230,"navigation":307,"path":11231,"seo":11232,"stem":11233,"tags":11234,"__hash__":11238},"posts\u002Fposts\u002Fcentos7-hadoop-spark-cluster-setup.md","CentOS7 下 Hadoop 2.7.3 + Spark 2.1.0 集群环境搭建",{"type":9,"value":9681,"toc":11191},[9682,9684,9733,9737,9793,9795,9816,9820,9833,9898,9902,9906,9926,9930,9933,9946,9955,9958,9970,9974,10017,10021,10052,10056,10076,10079,10083,10086,10102,10105,10139,10143,10146,10172,10176,10188,10191,10215,10219,10224,10319,10324,10339,10344,10371,10376,10429,10434,10519,10524,10540,10607,10612,10684,10688,10704,10708,10711,10715,10724,10728,10737,10741,10756,10760,10763,10775,10779,10791,10794,10817,10820,10824,10862,10867,10882,10946,10950,10962,10966,10969,10973,10982,10986,10988,10992,10995,11157,11159,11188],[34,9683,4099],{"id":4099},[63,9685,9686,9699],{},[66,9687,9688],{},[69,9689,9690,9693,9696],{},[72,9691,9692],{},"主机名",[72,9694,9695],{},"ip",[72,9697,9698],{},"进程",[82,9700,9701,9712,9723],{},[69,9702,9703,9706,9709],{},[87,9704,9705],{},"nn.hadoop.data.example.net",[87,9707,9708],{},"172.16.156.220",[87,9710,9711],{},"NameNode、Master、ResourceManager、SecondaryNameNode、JobHistoryServer",[69,9713,9714,9717,9720],{},[87,9715,9716],{},"dn1.hadoop.data.example.net",[87,9718,9719],{},"172.16.156.221",[87,9721,9722],{},"NodeManager、DataNode、Worker",[69,9724,9725,9728,9731],{},[87,9726,9727],{},"dn2.hadoop.data.example.net",[87,9729,9730],{},"172.16.156.222",[87,9732,9722],{},[1085,9734,9736],{"id":9735},"yum-安装如下包可能有部分包用不到","yum 安装如下包（可能有部分包用不到）",[344,9738,9740],{"className":687,"code":9739,"language":689,"meta":293,"style":293},"yum install pcre-devel openssl openssl-devel openssh-clients htop gcc zlib lrzsz zip unzip vim telnet-server ncurses wget net-tools\n",[350,9741,9742],{"__ignoreMap":293},[353,9743,9744,9746,9748,9751,9754,9757,9760,9763,9766,9769,9772,9775,9778,9781,9784,9787,9790],{"class":355,"line":356},[353,9745,5379],{"class":696},[353,9747,4320],{"class":390},[353,9749,9750],{"class":390}," pcre-devel",[353,9752,9753],{"class":390}," openssl",[353,9755,9756],{"class":390}," openssl-devel",[353,9758,9759],{"class":390}," openssh-clients",[353,9761,9762],{"class":390}," htop",[353,9764,9765],{"class":390}," gcc",[353,9767,9768],{"class":390}," zlib",[353,9770,9771],{"class":390}," lrzsz",[353,9773,9774],{"class":390}," zip",[353,9776,9777],{"class":390}," unzip",[353,9779,9780],{"class":390}," vim",[353,9782,9783],{"class":390}," telnet-server",[353,9785,9786],{"class":390}," ncurses",[353,9788,9789],{"class":390}," wget",[353,9791,9792],{"class":390}," net-tools\n",[1085,9794,2109],{"id":2109},[344,9796,9798],{"className":687,"code":9797,"language":689,"meta":293,"style":293},"systemctl stop firewalld.service\nsystemctl disable firewalld.service\n",[350,9799,9800,9808],{"__ignoreMap":293},[353,9801,9802,9804,9806],{"class":355,"line":356},[353,9803,2100],{"class":696},[353,9805,2121],{"class":390},[353,9807,2106],{"class":390},[353,9809,9810,9812,9814],{"class":355,"line":297},[353,9811,2100],{"class":696},[353,9813,2172],{"class":390},[353,9815,2106],{"class":390},[1085,9817,9819],{"id":9818},"配置-hosts-文件","配置 hosts 文件",[344,9821,9823],{"className":687,"code":9822,"language":689,"meta":293,"style":293},"vi \u002Fetc\u002Fhosts\n",[350,9824,9825],{"__ignoreMap":293},[353,9826,9827,9830],{"class":355,"line":356},[353,9828,9829],{"class":696},"vi",[353,9831,9832],{"class":390}," \u002Fetc\u002Fhosts\n",[344,9834,9836],{"className":687,"code":9835,"language":689,"meta":293,"style":293},"127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n::1         localhost localhost.localdomain localhost6 localhost6.localdomain6\n\n172.16.156.220  nn.hadoop.data.example.net\n172.16.156.221  dn1.hadoop.data.example.net\n172.16.156.222  dn2.hadoop.data.example.net\n",[350,9837,9838,9855,9873,9877,9884,9891],{"__ignoreMap":293},[353,9839,9840,9843,9846,9849,9852],{"class":355,"line":356},[353,9841,9842],{"class":696},"127.0.0.1",[353,9844,9845],{"class":390},"   localhost",[353,9847,9848],{"class":390}," localhost.localdomain",[353,9850,9851],{"class":390}," localhost4",[353,9853,9854],{"class":390}," localhost4.localdomain4\n",[353,9856,9857,9859,9862,9865,9867,9870],{"class":355,"line":297},[353,9858,2660],{"class":796},[353,9860,9861],{"class":390},":1",[353,9863,9864],{"class":390},"         localhost",[353,9866,9848],{"class":390},[353,9868,9869],{"class":390}," localhost6",[353,9871,9872],{"class":390}," localhost6.localdomain6\n",[353,9874,9875],{"class":355,"line":294},[353,9876,3483],{"emptyLinePlaceholder":307},[353,9878,9879,9881],{"class":355,"line":721},[353,9880,9708],{"class":696},[353,9882,9883],{"class":390},"  nn.hadoop.data.example.net\n",[353,9885,9886,9888],{"class":355,"line":1584},[353,9887,9719],{"class":696},[353,9889,9890],{"class":390},"  dn1.hadoop.data.example.net\n",[353,9892,9893,9895],{"class":355,"line":2317},[353,9894,9730],{"class":696},[353,9896,9897],{"class":390},"  dn2.hadoop.data.example.net\n",[34,9899,9901],{"id":9900},"安装-jdk-和-scala","安装 JDK 和 Scala",[1085,9903,9905],{"id":9904},"_0创建文件夹","0.创建文件夹",[344,9907,9909],{"className":687,"code":9908,"language":689,"meta":293,"style":293},"mkdir \u002Fapp\u002Fjava\nmkdir \u002Fapp\u002Fscala\n",[350,9910,9911,9919],{"__ignoreMap":293},[353,9912,9913,9916],{"class":355,"line":356},[353,9914,9915],{"class":696},"mkdir",[353,9917,9918],{"class":390}," \u002Fapp\u002Fjava\n",[353,9920,9921,9923],{"class":355,"line":297},[353,9922,9915],{"class":696},[353,9924,9925],{"class":390}," \u002Fapp\u002Fscala\n",[1085,9927,9929],{"id":9928},"_1下载","1.下载",[12,9931,9932],{},"下载 JDK",[344,9934,9936],{"className":687,"code":9935,"language":689,"meta":293,"style":293},"wget http:\u002F\u002Fdownload.oracle.com\u002Fotn-pub\u002Fjava\u002Fjdk\u002F8u121-b13\u002Fe9e7ea248e2c4826b92b3f075a80e441\u002Fjdk-8u121-linux-x64.tar.gz\n",[350,9937,9938],{"__ignoreMap":293},[353,9939,9940,9943],{"class":355,"line":356},[353,9941,9942],{"class":696},"wget",[353,9944,9945],{"class":390}," http:\u002F\u002Fdownload.oracle.com\u002Fotn-pub\u002Fjava\u002Fjdk\u002F8u121-b13\u002Fe9e7ea248e2c4826b92b3f075a80e441\u002Fjdk-8u121-linux-x64.tar.gz\n",[12,9947,9948,9949,9954],{},"如果失效，",[96,9950,9953],{"href":9951,"rel":9952},"http:\u002F\u002Fwww.oracle.com\u002Ftechnetwork\u002Fjava\u002Fjavase\u002Fdownloads\u002Findex.html",[100],"点这里下载"," 并上传至服务器",[12,9956,9957],{},"下载 Scala",[344,9959,9961],{"className":687,"code":9960,"language":689,"meta":293,"style":293},"wget http:\u002F\u002Fdownloads.lightbend.com\u002Fscala\u002F2.12.1\u002Fscala-2.12.1.tgz\n",[350,9962,9963],{"__ignoreMap":293},[353,9964,9965,9967],{"class":355,"line":356},[353,9966,9942],{"class":696},[353,9968,9969],{"class":390}," http:\u002F\u002Fdownloads.lightbend.com\u002Fscala\u002F2.12.1\u002Fscala-2.12.1.tgz\n",[1085,9971,9973],{"id":9972},"_2移动解压","2.移动&解压",[344,9975,9977],{"className":687,"code":9976,"language":689,"meta":293,"style":293},"mv jdk-8u121-linux-x64.tar.gz \u002Fapp\u002Fjava\ntar -zxvf jdk-8u121-linux-x64.tar.gz\nmv scala-2.12.1.tgz \u002Fapp\u002Fscala\ntar -zxvf scala-2.12.1.tgz\n",[350,9978,9979,9988,9999,10008],{"__ignoreMap":293},[353,9980,9981,9983,9986],{"class":355,"line":356},[353,9982,4374],{"class":696},[353,9984,9985],{"class":390}," jdk-8u121-linux-x64.tar.gz",[353,9987,9918],{"class":390},[353,9989,9990,9993,9996],{"class":355,"line":297},[353,9991,9992],{"class":696},"tar",[353,9994,9995],{"class":390}," -zxvf",[353,9997,9998],{"class":390}," jdk-8u121-linux-x64.tar.gz\n",[353,10000,10001,10003,10006],{"class":355,"line":294},[353,10002,4374],{"class":696},[353,10004,10005],{"class":390}," scala-2.12.1.tgz",[353,10007,9925],{"class":390},[353,10009,10010,10012,10014],{"class":355,"line":721},[353,10011,9992],{"class":696},[353,10013,9995],{"class":390},[353,10015,10016],{"class":390}," scala-2.12.1.tgz\n",[1085,10018,10020],{"id":10019},"_3授权","3.授权",[344,10022,10024],{"className":687,"code":10023,"language":689,"meta":293,"style":293},"chmod -R 775 \u002Fapp\u002F\nchown -R hadoop \u002Fapp\u002F\n",[350,10025,10026,10040],{"__ignoreMap":293},[353,10027,10028,10031,10034,10037],{"class":355,"line":356},[353,10029,10030],{"class":696},"chmod",[353,10032,10033],{"class":390}," -R",[353,10035,10036],{"class":739}," 775",[353,10038,10039],{"class":390}," \u002Fapp\u002F\n",[353,10041,10042,10045,10047,10050],{"class":355,"line":297},[353,10043,10044],{"class":696},"chown",[353,10046,10033],{"class":390},[353,10048,10049],{"class":390}," hadoop",[353,10051,10039],{"class":390},[34,10053,10055],{"id":10054},"创建-hadoop-用户","创建 hadoop 用户",[344,10057,10059],{"className":687,"code":10058,"language":689,"meta":293,"style":293},"useradd hadoop\npasswd hadoop\n",[350,10060,10061,10069],{"__ignoreMap":293},[353,10062,10063,10066],{"class":355,"line":356},[353,10064,10065],{"class":696},"useradd",[353,10067,10068],{"class":390}," hadoop\n",[353,10070,10071,10074],{"class":355,"line":297},[353,10072,10073],{"class":696},"passwd",[353,10075,10068],{"class":390},[12,10077,10078],{},"如无特殊说明 以后均为 hadoop 用户操作",[34,10080,10082],{"id":10081},"ssh-免密登录","SSH 免密登录",[12,10084,10085],{},"生成秘钥：~\u002F.ssh\u002Fid_rsa 和 ~\u002F.ssh\u002Fid_rsa.pub",[344,10087,10089],{"className":687,"code":10088,"language":689,"meta":293,"style":293},"ssh-keygen -t rsa \n",[350,10090,10091],{"__ignoreMap":293},[353,10092,10093,10096,10099],{"class":355,"line":356},[353,10094,10095],{"class":696},"ssh-keygen",[353,10097,10098],{"class":390}," -t",[353,10100,10101],{"class":390}," rsa\n",[12,10103,10104],{},"拷贝公钥到其他机器上",[344,10106,10108],{"className":687,"code":10107,"language":689,"meta":293,"style":293},"ssh-copy-id -i nn.hadoop.data.example.net\nssh-copy-id -i dn1.hadoop.data.example.net\nssh-copy-id -i dn2.hadoop.data.example.net\n",[350,10109,10110,10121,10130],{"__ignoreMap":293},[353,10111,10112,10115,10118],{"class":355,"line":356},[353,10113,10114],{"class":696},"ssh-copy-id",[353,10116,10117],{"class":390}," -i",[353,10119,10120],{"class":390}," nn.hadoop.data.example.net\n",[353,10122,10123,10125,10127],{"class":355,"line":297},[353,10124,10114],{"class":696},[353,10126,10117],{"class":390},[353,10128,10129],{"class":390}," dn1.hadoop.data.example.net\n",[353,10131,10132,10134,10136],{"class":355,"line":294},[353,10133,10114],{"class":696},[353,10135,10117],{"class":390},[353,10137,10138],{"class":390}," dn2.hadoop.data.example.net\n",[34,10140,10142],{"id":10141},"安装-hadoop","安装 Hadoop",[1085,10144,9905],{"id":10145},"_0创建文件夹-1",[344,10147,10149],{"className":687,"code":10148,"language":689,"meta":293,"style":293},"mkdir \u002Fapp\u002Fhadoop\u002Fdata\nmkdir \u002Fapp\u002Fhadoop\u002Fname\nmkdir \u002Fapp\u002Fhadoop\u002Ftmp\n",[350,10150,10151,10158,10165],{"__ignoreMap":293},[353,10152,10153,10155],{"class":355,"line":356},[353,10154,9915],{"class":696},[353,10156,10157],{"class":390}," \u002Fapp\u002Fhadoop\u002Fdata\n",[353,10159,10160,10162],{"class":355,"line":297},[353,10161,9915],{"class":696},[353,10163,10164],{"class":390}," \u002Fapp\u002Fhadoop\u002Fname\n",[353,10166,10167,10169],{"class":355,"line":294},[353,10168,9915],{"class":696},[353,10170,10171],{"class":390}," \u002Fapp\u002Fhadoop\u002Ftmp\n",[1085,10173,10175],{"id":10174},"_1下载-hadoop","1.下载 hadoop",[344,10177,10179],{"className":687,"code":10178,"language":689,"meta":293,"style":293},"wget http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.cgi\u002Fhadoop\u002Fcommon\u002Fhadoop-2.7.3\u002Fhadoop-2.7.3.tar.gz\n",[350,10180,10181],{"__ignoreMap":293},[353,10182,10183,10185],{"class":355,"line":356},[353,10184,9942],{"class":696},[353,10186,10187],{"class":390}," http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.cgi\u002Fhadoop\u002Fcommon\u002Fhadoop-2.7.3\u002Fhadoop-2.7.3.tar.gz\n",[1085,10189,9973],{"id":10190},"_2移动解压-1",[344,10192,10194],{"className":687,"code":10193,"language":689,"meta":293,"style":293},"mv hadoop-2.7.3.tar.gz \u002Fapp\u002Fhadoop\ntar -zxvf hadoop-2.7.3.tar.gz\n",[350,10195,10196,10206],{"__ignoreMap":293},[353,10197,10198,10200,10203],{"class":355,"line":356},[353,10199,4374],{"class":696},[353,10201,10202],{"class":390}," hadoop-2.7.3.tar.gz",[353,10204,10205],{"class":390}," \u002Fapp\u002Fhadoop\n",[353,10207,10208,10210,10212],{"class":355,"line":297},[353,10209,9992],{"class":696},[353,10211,9995],{"class":390},[353,10213,10214],{"class":390}," hadoop-2.7.3.tar.gz\n",[1085,10216,10218],{"id":10217},"_3修改配置文件","3.修改配置文件",[12,10220,10221],{},[183,10222,10223],{},"\u002Fetc\u002Fprofile（root 权限）",[344,10225,10227],{"className":687,"code":10226,"language":689,"meta":293,"style":293},"HADOOP_HOME=\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\nexport HADOOP_INSTALL=$HADOOP_HOME\nexport HADOOP_MAPRED_HOME=$HADOOP_HOME\nexport HADOOP_COMMON_HOME=$HADOOP_HOME\nexport HADOOP_HDFS_HOME=$HADOOP_HOME\nexport YARN_HOME=$HADOOP_HOME\nexport HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME\u002Flib\u002Fnative\nexport PATH=$PATH:$HADOOP_HOME\u002Fsbin:$HADOOP_HOME\u002Fbin\n",[350,10228,10229,10239,10251,10262,10273,10284,10295,10307],{"__ignoreMap":293},[353,10230,10231,10234,10236],{"class":355,"line":356},[353,10232,10233],{"class":367},"HADOOP_HOME",[353,10235,459],{"class":363},[353,10237,10238],{"class":390},"\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\n",[353,10240,10241,10243,10246,10248],{"class":355,"line":297},[353,10242,1601],{"class":359},[353,10244,10245],{"class":367}," HADOOP_INSTALL",[353,10247,459],{"class":363},[353,10249,10250],{"class":367},"$HADOOP_HOME\n",[353,10252,10253,10255,10258,10260],{"class":355,"line":294},[353,10254,1601],{"class":359},[353,10256,10257],{"class":367}," HADOOP_MAPRED_HOME",[353,10259,459],{"class":363},[353,10261,10250],{"class":367},[353,10263,10264,10266,10269,10271],{"class":355,"line":721},[353,10265,1601],{"class":359},[353,10267,10268],{"class":367}," HADOOP_COMMON_HOME",[353,10270,459],{"class":363},[353,10272,10250],{"class":367},[353,10274,10275,10277,10280,10282],{"class":355,"line":1584},[353,10276,1601],{"class":359},[353,10278,10279],{"class":367}," HADOOP_HDFS_HOME",[353,10281,459],{"class":363},[353,10283,10250],{"class":367},[353,10285,10286,10288,10291,10293],{"class":355,"line":2317},[353,10287,1601],{"class":359},[353,10289,10290],{"class":367}," YARN_HOME",[353,10292,459],{"class":363},[353,10294,10250],{"class":367},[353,10296,10297,10299,10302,10304],{"class":355,"line":2328},[353,10298,1601],{"class":359},[353,10300,10301],{"class":367}," HADOOP_COMMON_LIB_NATIVE_DIR",[353,10303,459],{"class":363},[353,10305,10306],{"class":367},"$HADOOP_HOME\u002Flib\u002Fnative\n",[353,10308,10309,10311,10314,10316],{"class":355,"line":2334},[353,10310,1601],{"class":359},[353,10312,10313],{"class":367}," PATH",[353,10315,459],{"class":363},[353,10317,10318],{"class":367},"$PATH:$HADOOP_HOME\u002Fsbin:$HADOOP_HOME\u002Fbin\n",[12,10320,10321],{},[183,10322,10323],{},"slaves",[344,10325,10327],{"className":687,"code":10326,"language":689,"meta":293,"style":293},"dn1.hadoop.data.example.net\ndn2.hadoop.data.example.net\n",[350,10328,10329,10334],{"__ignoreMap":293},[353,10330,10331],{"class":355,"line":356},[353,10332,10333],{"class":696},"dn1.hadoop.data.example.net\n",[353,10335,10336],{"class":355,"line":297},[353,10337,10338],{"class":696},"dn2.hadoop.data.example.net\n",[12,10340,10341],{},[183,10342,10343],{},"hadoop-env.sh",[344,10345,10347],{"className":687,"code":10346,"language":689,"meta":293,"style":293},"# export JAVA_HOME=${JAVA_HOME}\n改为\nexport JAVA_HOME=\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\u002F\n",[350,10348,10349,10354,10359],{"__ignoreMap":293},[353,10350,10351],{"class":355,"line":356},[353,10352,10353],{"class":703},"# export JAVA_HOME=${JAVA_HOME}\n",[353,10355,10356],{"class":355,"line":297},[353,10357,10358],{"class":696},"改为\n",[353,10360,10361,10363,10366,10368],{"class":355,"line":294},[353,10362,1601],{"class":359},[353,10364,10365],{"class":367}," JAVA_HOME",[353,10367,459],{"class":363},[353,10369,10370],{"class":367},"\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\u002F\n",[12,10372,10373],{},[183,10374,10375],{},"core-site.xml",[344,10377,10379],{"className":9190,"code":10378,"language":9192,"meta":293,"style":293},"\u003Cconfiguration>\n    \u003Cproperty>\n    \u003Cname>fs.defaultFS\u003C\u002Fname>\n    \u003Cvalue>hdfs:\u002F\u002Fnn.hadoop.data.example.net:9000\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n    \u003Cname>hadoop.tmp.dir\u003C\u002Fname>\n    \u003Cvalue>\u002Fapp\u002Fhadoop\u002Ftmp\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n\u003C\u002Fconfiguration>\n",[350,10380,10381,10386,10391,10396,10401,10406,10410,10415,10420,10424],{"__ignoreMap":293},[353,10382,10383],{"class":355,"line":356},[353,10384,10385],{},"\u003Cconfiguration>\n",[353,10387,10388],{"class":355,"line":297},[353,10389,10390],{},"    \u003Cproperty>\n",[353,10392,10393],{"class":355,"line":294},[353,10394,10395],{},"    \u003Cname>fs.defaultFS\u003C\u002Fname>\n",[353,10397,10398],{"class":355,"line":721},[353,10399,10400],{},"    \u003Cvalue>hdfs:\u002F\u002Fnn.hadoop.data.example.net:9000\u003C\u002Fvalue>\n",[353,10402,10403],{"class":355,"line":1584},[353,10404,10405],{},"    \u003C\u002Fproperty>\n",[353,10407,10408],{"class":355,"line":2317},[353,10409,10390],{},[353,10411,10412],{"class":355,"line":2328},[353,10413,10414],{},"    \u003Cname>hadoop.tmp.dir\u003C\u002Fname>\n",[353,10416,10417],{"class":355,"line":2334},[353,10418,10419],{},"    \u003Cvalue>\u002Fapp\u002Fhadoop\u002Ftmp\u003C\u002Fvalue>\n",[353,10421,10422],{"class":355,"line":2348},[353,10423,10405],{},[353,10425,10426],{"class":355,"line":2362},[353,10427,10428],{},"\u003C\u002Fconfiguration>\n",[12,10430,10431],{},[183,10432,10433],{},"hdfs-site.xml",[344,10435,10437],{"className":9190,"code":10436,"language":9192,"meta":293,"style":293},"\u003Cconfiguration>\n    \u003Cproperty>\n        \u003Cname>dfs.namenode.secondary.http-address\u003C\u002Fname>\n        \u003Cvalue>nn.hadoop.data.example.net:50090\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>dfs.namenode.name.dir\u003C\u002Fname>\n        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fname\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>dfs.replication\u003C\u002Fname>\n        \u003Cvalue>1\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>dfs.datanode.data.dir\u003C\u002Fname>\n        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fdata\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n\u003C\u002Fconfiguration>\n",[350,10438,10439,10443,10447,10452,10457,10461,10465,10470,10475,10479,10483,10488,10493,10497,10501,10506,10511,10515],{"__ignoreMap":293},[353,10440,10441],{"class":355,"line":356},[353,10442,10385],{},[353,10444,10445],{"class":355,"line":297},[353,10446,10390],{},[353,10448,10449],{"class":355,"line":294},[353,10450,10451],{},"        \u003Cname>dfs.namenode.secondary.http-address\u003C\u002Fname>\n",[353,10453,10454],{"class":355,"line":721},[353,10455,10456],{},"        \u003Cvalue>nn.hadoop.data.example.net:50090\u003C\u002Fvalue>\n",[353,10458,10459],{"class":355,"line":1584},[353,10460,10405],{},[353,10462,10463],{"class":355,"line":2317},[353,10464,10390],{},[353,10466,10467],{"class":355,"line":2328},[353,10468,10469],{},"        \u003Cname>dfs.namenode.name.dir\u003C\u002Fname>\n",[353,10471,10472],{"class":355,"line":2334},[353,10473,10474],{},"        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fname\u003C\u002Fvalue>\n",[353,10476,10477],{"class":355,"line":2348},[353,10478,10405],{},[353,10480,10481],{"class":355,"line":2362},[353,10482,10390],{},[353,10484,10485],{"class":355,"line":2376},[353,10486,10487],{},"        \u003Cname>dfs.replication\u003C\u002Fname>\n",[353,10489,10490],{"class":355,"line":3172},[353,10491,10492],{},"        \u003Cvalue>1\u003C\u002Fvalue>\n",[353,10494,10495],{"class":355,"line":3245},[353,10496,10405],{},[353,10498,10499],{"class":355,"line":3251},[353,10500,10390],{},[353,10502,10503],{"class":355,"line":3257},[353,10504,10505],{},"        \u003Cname>dfs.datanode.data.dir\u003C\u002Fname>\n",[353,10507,10508],{"class":355,"line":3263},[353,10509,10510],{},"        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fdata\u003C\u002Fvalue>\n",[353,10512,10513],{"class":355,"line":3269},[353,10514,10405],{},[353,10516,10517],{"class":355,"line":3275},[353,10518,10428],{},[12,10520,10521],{},[183,10522,10523],{},"mapred-site.xml",[344,10525,10527],{"className":687,"code":10526,"language":689,"meta":293,"style":293},"cp mapred-site.xml.template mapred-site.xml\n",[350,10528,10529],{"__ignoreMap":293},[353,10530,10531,10534,10537],{"class":355,"line":356},[353,10532,10533],{"class":696},"cp",[353,10535,10536],{"class":390}," mapred-site.xml.template",[353,10538,10539],{"class":390}," mapred-site.xml\n",[344,10541,10543],{"className":9190,"code":10542,"language":9192,"meta":293,"style":293},"\u003Cconfiguration>\n    \u003Cproperty>\n        \u003Cname>mapreduce.framework.name\u003C\u002Fname>\n        \u003Cvalue>yarn\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>mapreduce.jobhistory.address\u003C\u002Fname>\n        \u003Cvalue>nn.hadoop.data.example.net:10020\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>mapreduce.jobhistory.webapp.address\u003C\u002Fname>\n        \u003Cvalue>nn.hadoop.data.example.net:19888\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n\u003C\u002Fconfiguration>\n",[350,10544,10545,10549,10553,10558,10563,10567,10571,10576,10581,10585,10589,10594,10599,10603],{"__ignoreMap":293},[353,10546,10547],{"class":355,"line":356},[353,10548,10385],{},[353,10550,10551],{"class":355,"line":297},[353,10552,10390],{},[353,10554,10555],{"class":355,"line":294},[353,10556,10557],{},"        \u003Cname>mapreduce.framework.name\u003C\u002Fname>\n",[353,10559,10560],{"class":355,"line":721},[353,10561,10562],{},"        \u003Cvalue>yarn\u003C\u002Fvalue>\n",[353,10564,10565],{"class":355,"line":1584},[353,10566,10405],{},[353,10568,10569],{"class":355,"line":2317},[353,10570,10390],{},[353,10572,10573],{"class":355,"line":2328},[353,10574,10575],{},"        \u003Cname>mapreduce.jobhistory.address\u003C\u002Fname>\n",[353,10577,10578],{"class":355,"line":2334},[353,10579,10580],{},"        \u003Cvalue>nn.hadoop.data.example.net:10020\u003C\u002Fvalue>\n",[353,10582,10583],{"class":355,"line":2348},[353,10584,10405],{},[353,10586,10587],{"class":355,"line":2362},[353,10588,10390],{},[353,10590,10591],{"class":355,"line":2376},[353,10592,10593],{},"        \u003Cname>mapreduce.jobhistory.webapp.address\u003C\u002Fname>\n",[353,10595,10596],{"class":355,"line":3172},[353,10597,10598],{},"        \u003Cvalue>nn.hadoop.data.example.net:19888\u003C\u002Fvalue>\n",[353,10600,10601],{"class":355,"line":3245},[353,10602,10405],{},[353,10604,10605],{"class":355,"line":3251},[353,10606,10428],{},[12,10608,10609],{},[183,10610,10611],{},"yarn-site.xml",[344,10613,10615],{"className":9190,"code":10614,"language":9192,"meta":293,"style":293},"\u003Cconfiguration>\n\u003C!-- Site specific YARN configuration properties -->\n    \u003Cproperty>\n        \u003Cname>yarn.resourcemanager.hostname\u003C\u002Fname>\n        \u003Cvalue>nn.hadoop.data.example.net\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n        \u003Cname>yarn.nodemanager.aux-services\u003C\u002Fname>\n        \u003Cvalue>mapreduce_shuffle\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n    \u003Cproperty>\n         \u003Cname>yarn.nodemanager.aux-services.mapreduce.shuffle.class\u003C\u002Fname>\n         \u003Cvalue>org.apache.hadoop.mapred.ShuffleHandler\u003C\u002Fvalue>\n    \u003C\u002Fproperty>\n\u003C\u002Fconfiguration>\n",[350,10616,10617,10621,10626,10630,10635,10640,10644,10648,10653,10658,10662,10666,10671,10676,10680],{"__ignoreMap":293},[353,10618,10619],{"class":355,"line":356},[353,10620,10385],{},[353,10622,10623],{"class":355,"line":297},[353,10624,10625],{},"\u003C!-- Site specific YARN configuration properties -->\n",[353,10627,10628],{"class":355,"line":294},[353,10629,10390],{},[353,10631,10632],{"class":355,"line":721},[353,10633,10634],{},"        \u003Cname>yarn.resourcemanager.hostname\u003C\u002Fname>\n",[353,10636,10637],{"class":355,"line":1584},[353,10638,10639],{},"        \u003Cvalue>nn.hadoop.data.example.net\u003C\u002Fvalue>\n",[353,10641,10642],{"class":355,"line":2317},[353,10643,10405],{},[353,10645,10646],{"class":355,"line":2328},[353,10647,10390],{},[353,10649,10650],{"class":355,"line":2334},[353,10651,10652],{},"        \u003Cname>yarn.nodemanager.aux-services\u003C\u002Fname>\n",[353,10654,10655],{"class":355,"line":2348},[353,10656,10657],{},"        \u003Cvalue>mapreduce_shuffle\u003C\u002Fvalue>\n",[353,10659,10660],{"class":355,"line":2362},[353,10661,10405],{},[353,10663,10664],{"class":355,"line":2376},[353,10665,10390],{},[353,10667,10668],{"class":355,"line":3172},[353,10669,10670],{},"         \u003Cname>yarn.nodemanager.aux-services.mapreduce.shuffle.class\u003C\u002Fname>\n",[353,10672,10673],{"class":355,"line":3245},[353,10674,10675],{},"         \u003Cvalue>org.apache.hadoop.mapred.ShuffleHandler\u003C\u002Fvalue>\n",[353,10677,10678],{"class":355,"line":3251},[353,10679,10405],{},[353,10681,10682],{"class":355,"line":3257},[353,10683,10428],{},[1085,10685,10687],{"id":10686},"_4格式化-namenode","4.格式化 namenode",[344,10689,10691],{"className":687,"code":10690,"language":689,"meta":293,"style":293},"hadoop namenode -format\n",[350,10692,10693],{"__ignoreMap":293},[353,10694,10695,10698,10701],{"class":355,"line":356},[353,10696,10697],{"class":696},"hadoop",[353,10699,10700],{"class":390}," namenode",[353,10702,10703],{"class":390}," -format\n",[1085,10705,10707],{"id":10706},"_5复制文件到其他机器","5.复制文件到其他机器",[12,10709,10710],{},"将 \u002Fapp\u002Fhadoop（包括 data、name、tmp 和配置好的 hadoop）复制到其他机器。",[1085,10712,10714],{"id":10713},"_6启动-dfs","6.启动 dfs",[344,10716,10718],{"className":687,"code":10717,"language":689,"meta":293,"style":293},"start-dfs.sh\n",[350,10719,10720],{"__ignoreMap":293},[353,10721,10722],{"class":355,"line":356},[353,10723,10717],{"class":696},[1085,10725,10727],{"id":10726},"_7启动-yarn","7.启动 yarn",[344,10729,10731],{"className":687,"code":10730,"language":689,"meta":293,"style":293},"start-yarn.sh\n",[350,10732,10733],{"__ignoreMap":293},[353,10734,10735],{"class":355,"line":356},[353,10736,10730],{"class":696},[1085,10738,10740],{"id":10739},"_8启动-jobhistory","8.启动 jobhistory",[344,10742,10744],{"className":687,"code":10743,"language":689,"meta":293,"style":293},"mr-jobhistory-daemon.sh start historyserver\n",[350,10745,10746],{"__ignoreMap":293},[353,10747,10748,10751,10753],{"class":355,"line":356},[353,10749,10750],{"class":696},"mr-jobhistory-daemon.sh",[353,10752,2103],{"class":390},[353,10754,10755],{"class":390}," historyserver\n",[34,10757,10759],{"id":10758},"安装-spark2","安装 Spark2",[1085,10761,9905],{"id":10762},"_0创建文件夹-2",[344,10764,10766],{"className":687,"code":10765,"language":689,"meta":293,"style":293},"mkdir \u002Fapp\u002Fspark\n",[350,10767,10768],{"__ignoreMap":293},[353,10769,10770,10772],{"class":355,"line":356},[353,10771,9915],{"class":696},[353,10773,10774],{"class":390}," \u002Fapp\u002Fspark\n",[1085,10776,10778],{"id":10777},"_1下载-spark2","1.下载 Spark2",[344,10780,10782],{"className":687,"code":10781,"language":689,"meta":293,"style":293},"wget http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.lua\u002Fspark\u002Fspark-2.1.0\u002Fspark-2.1.0-bin-hadoop2.7.tgz\n",[350,10783,10784],{"__ignoreMap":293},[353,10785,10786,10788],{"class":355,"line":356},[353,10787,9942],{"class":696},[353,10789,10790],{"class":390}," http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.lua\u002Fspark\u002Fspark-2.1.0\u002Fspark-2.1.0-bin-hadoop2.7.tgz\n",[1085,10792,9973],{"id":10793},"_2移动解压-2",[344,10795,10797],{"className":687,"code":10796,"language":689,"meta":293,"style":293},"mv spark-2.1.0-bin-hadoop2.7.tgz \u002Fapp\u002Fspark\ntar -zxvf spark-2.1.0-bin-hadoop2.7.tgz\n",[350,10798,10799,10808],{"__ignoreMap":293},[353,10800,10801,10803,10806],{"class":355,"line":356},[353,10802,4374],{"class":696},[353,10804,10805],{"class":390}," spark-2.1.0-bin-hadoop2.7.tgz",[353,10807,10774],{"class":390},[353,10809,10810,10812,10814],{"class":355,"line":297},[353,10811,9992],{"class":696},[353,10813,9995],{"class":390},[353,10815,10816],{"class":390}," spark-2.1.0-bin-hadoop2.7.tgz\n",[1085,10818,10218],{"id":10819},"_3修改配置文件-1",[12,10821,10822],{},[183,10823,10223],{},[344,10825,10827],{"className":687,"code":10826,"language":689,"meta":293,"style":293},"export SPARK_HOME=\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\nexport PATH=\"$SPARK_HOME\u002Fbin:$PATH\"\n",[350,10828,10829,10841],{"__ignoreMap":293},[353,10830,10831,10833,10836,10838],{"class":355,"line":356},[353,10832,1601],{"class":359},[353,10834,10835],{"class":367}," SPARK_HOME",[353,10837,459],{"class":363},[353,10839,10840],{"class":367},"\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\n",[353,10842,10843,10845,10847,10849,10851,10854,10857,10860],{"class":355,"line":297},[353,10844,1601],{"class":359},[353,10846,10313],{"class":367},[353,10848,459],{"class":363},[353,10850,462],{"class":363},[353,10852,10853],{"class":367},"$SPARK_HOME",[353,10855,10856],{"class":390},"\u002Fbin:",[353,10858,10859],{"class":367},"$PATH",[353,10861,2901],{"class":363},[12,10863,10864],{},[183,10865,10866],{},"spark-env.sh",[344,10868,10870],{"className":687,"code":10869,"language":689,"meta":293,"style":293},"cp spark-env.sh.template spark-env.sh\n",[350,10871,10872],{"__ignoreMap":293},[353,10873,10874,10876,10879],{"class":355,"line":356},[353,10875,10533],{"class":696},[353,10877,10878],{"class":390}," spark-env.sh.template",[353,10880,10881],{"class":390}," spark-env.sh\n",[344,10883,10885],{"className":687,"code":10884,"language":689,"meta":293,"style":293},"export SCALA_HOME=\u002Fapp\u002Fscala\u002Fscala-2.12.1\nexport JAVA_HOME=\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\nexport SPARK_MASTER_IP=nn.hadoop.data.easydebug.net\nexport SPARK_WORKER_MEMORY=1g\nexport HADOOP_CONF_DIR=\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\u002Fetc\u002Fhadoop\n",[350,10886,10887,10899,10910,10922,10934],{"__ignoreMap":293},[353,10888,10889,10891,10894,10896],{"class":355,"line":356},[353,10890,1601],{"class":359},[353,10892,10893],{"class":367}," SCALA_HOME",[353,10895,459],{"class":363},[353,10897,10898],{"class":367},"\u002Fapp\u002Fscala\u002Fscala-2.12.1\n",[353,10900,10901,10903,10905,10907],{"class":355,"line":297},[353,10902,1601],{"class":359},[353,10904,10365],{"class":367},[353,10906,459],{"class":363},[353,10908,10909],{"class":367},"\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\n",[353,10911,10912,10914,10917,10919],{"class":355,"line":294},[353,10913,1601],{"class":359},[353,10915,10916],{"class":367}," SPARK_MASTER_IP",[353,10918,459],{"class":363},[353,10920,10921],{"class":367},"nn.hadoop.data.easydebug.net\n",[353,10923,10924,10926,10929,10931],{"class":355,"line":721},[353,10925,1601],{"class":359},[353,10927,10928],{"class":367}," SPARK_WORKER_MEMORY",[353,10930,459],{"class":363},[353,10932,10933],{"class":367},"1g\n",[353,10935,10936,10938,10941,10943],{"class":355,"line":1584},[353,10937,1601],{"class":359},[353,10939,10940],{"class":367}," HADOOP_CONF_DIR",[353,10942,459],{"class":363},[353,10944,10945],{"class":367},"\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\u002Fetc\u002Fhadoop\n",[12,10947,10948],{},[183,10949,10323],{},[344,10951,10952],{"className":687,"code":10326,"language":689,"meta":293,"style":293},[350,10953,10954,10958],{"__ignoreMap":293},[353,10955,10956],{"class":355,"line":356},[353,10957,10333],{"class":696},[353,10959,10960],{"class":355,"line":297},[353,10961,10338],{"class":696},[1085,10963,10965],{"id":10964},"_4复制文件到其他机器","4.复制文件到其他机器",[12,10967,10968],{},"将 \u002Fapp\u002Fspark 复制到其他机器。",[1085,10970,10972],{"id":10971},"_5启动-spark","5.启动 Spark",[344,10974,10976],{"className":687,"code":10975,"language":689,"meta":293,"style":293},"\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\u002Fsbin\u002Fstart-all.sh\n",[350,10977,10978],{"__ignoreMap":293},[353,10979,10980],{"class":355,"line":356},[353,10981,10975],{"class":696},[34,10983,10985],{"id":10984},"安装完成-_","安装完成 ^_^",[4107,10987],{},[1085,10989,10991],{"id":10990},"因为系统变量改了几次最后贴一下完整的","因为系统变量改了几次，最后贴一下完整的",[12,10993,10994],{},"其实可以在配置前直接贴进去。",[344,10996,10998],{"className":687,"code":10997,"language":689,"meta":293,"style":293},"export JAVA_HOME=\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\nexport SCALA_HOME=\u002Fapp\u002Fscala\u002Fscala-2.12.1\nexport PATH=$JAVA_HOME\u002Fbin:$SCALA_HOME\u002Fbin:$PATH\nexport CLASSPATH=.:$JAVA_HOME\u002Flib\u002Fdt.jar:$JAVA_HOME\u002Flib\u002Ftools.jar\n\nHADOOP_HOME=\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\nexport HADOOP_INSTALL=$HADOOP_HOME\nexport HADOOP_MAPRED_HOME=$HADOOP_HOME\nexport HADOOP_COMMON_HOME=$HADOOP_HOME\nexport HADOOP_HDFS_HOME=$HADOOP_HOME\nexport YARN_HOME=$HADOOP_HOME\nexport HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME\u002Flib\u002Fnative\nexport PATH=$PATH:$HADOOP_HOME\u002Fsbin:$HADOOP_HOME\u002Fbin\n\nexport SPARK_HOME=\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\nexport PATH=\"$SPARK_HOME\u002Fbin:$PATH\"\n",[350,10999,11000,11010,11020,11031,11043,11047,11055,11065,11075,11085,11095,11105,11115,11125,11129,11139],{"__ignoreMap":293},[353,11001,11002,11004,11006,11008],{"class":355,"line":356},[353,11003,1601],{"class":359},[353,11005,10365],{"class":367},[353,11007,459],{"class":363},[353,11009,10909],{"class":367},[353,11011,11012,11014,11016,11018],{"class":355,"line":297},[353,11013,1601],{"class":359},[353,11015,10893],{"class":367},[353,11017,459],{"class":363},[353,11019,10898],{"class":367},[353,11021,11022,11024,11026,11028],{"class":355,"line":294},[353,11023,1601],{"class":359},[353,11025,10313],{"class":367},[353,11027,459],{"class":363},[353,11029,11030],{"class":367},"$JAVA_HOME\u002Fbin:$SCALA_HOME\u002Fbin:$PATH\n",[353,11032,11033,11035,11038,11040],{"class":355,"line":721},[353,11034,1601],{"class":359},[353,11036,11037],{"class":367}," CLASSPATH",[353,11039,459],{"class":363},[353,11041,11042],{"class":367},".:$JAVA_HOME\u002Flib\u002Fdt.jar:$JAVA_HOME\u002Flib\u002Ftools.jar\n",[353,11044,11045],{"class":355,"line":1584},[353,11046,3483],{"emptyLinePlaceholder":307},[353,11048,11049,11051,11053],{"class":355,"line":2317},[353,11050,10233],{"class":367},[353,11052,459],{"class":363},[353,11054,10238],{"class":390},[353,11056,11057,11059,11061,11063],{"class":355,"line":2328},[353,11058,1601],{"class":359},[353,11060,10245],{"class":367},[353,11062,459],{"class":363},[353,11064,10250],{"class":367},[353,11066,11067,11069,11071,11073],{"class":355,"line":2334},[353,11068,1601],{"class":359},[353,11070,10257],{"class":367},[353,11072,459],{"class":363},[353,11074,10250],{"class":367},[353,11076,11077,11079,11081,11083],{"class":355,"line":2348},[353,11078,1601],{"class":359},[353,11080,10268],{"class":367},[353,11082,459],{"class":363},[353,11084,10250],{"class":367},[353,11086,11087,11089,11091,11093],{"class":355,"line":2362},[353,11088,1601],{"class":359},[353,11090,10279],{"class":367},[353,11092,459],{"class":363},[353,11094,10250],{"class":367},[353,11096,11097,11099,11101,11103],{"class":355,"line":2376},[353,11098,1601],{"class":359},[353,11100,10290],{"class":367},[353,11102,459],{"class":363},[353,11104,10250],{"class":367},[353,11106,11107,11109,11111,11113],{"class":355,"line":3172},[353,11108,1601],{"class":359},[353,11110,10301],{"class":367},[353,11112,459],{"class":363},[353,11114,10306],{"class":367},[353,11116,11117,11119,11121,11123],{"class":355,"line":3245},[353,11118,1601],{"class":359},[353,11120,10313],{"class":367},[353,11122,459],{"class":363},[353,11124,10318],{"class":367},[353,11126,11127],{"class":355,"line":3251},[353,11128,3483],{"emptyLinePlaceholder":307},[353,11130,11131,11133,11135,11137],{"class":355,"line":3257},[353,11132,1601],{"class":359},[353,11134,10835],{"class":367},[353,11136,459],{"class":363},[353,11138,10840],{"class":367},[353,11140,11141,11143,11145,11147,11149,11151,11153,11155],{"class":355,"line":3263},[353,11142,1601],{"class":359},[353,11144,10313],{"class":367},[353,11146,459],{"class":363},[353,11148,462],{"class":363},[353,11150,10853],{"class":367},[353,11152,10856],{"class":390},[353,11154,10859],{"class":367},[353,11156,2901],{"class":363},[4107,11158],{},[8331,11160,11161,11164,11172,11180],{},[12,11162,11163],{},"参考文章",[12,11165,11166,11167],{},"CentOS 6.5 hadoop 2.7.3 集群环境搭建\n",[96,11168,11171],{"href":11169,"rel":11170},"http:\u002F\u002Fblog.csdn.net\u002Fmxxlevel\u002Farticle\u002Fdetails\u002F52653086",[100],"blog.csdn.net\u002Fmxxlevel\u002Farticle\u002Fdetails\u002F52653086",[12,11173,11174,11175],{},"Spark修炼之道（进阶篇）——Spark 入门到精通：第一节 Spark 1.5.0 集群搭建\n",[96,11176,11179],{"href":11177,"rel":11178},"https:\u002F\u002Fyq.aliyun.com\u002Farticles\u002F60309?spm=5176.8251999.569296.66.0H8Bal",[100],"yq.aliyun.com\u002Farticles\u002F60309",[12,11181,11182,11183],{},"Hadoop2.7.3+Spark2.1.0 完全分布式环境 搭建全过程\n",[96,11184,11187],{"href":11185,"rel":11186},"http:\u002F\u002Fwww.cnblogs.com\u002Fpurstar\u002Fp\u002F6293605.html",[100],"cnblogs.com\u002Fpurstar\u002Fp\u002F6293605.html",[1779,11189,11190],{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":293,"searchDepth":294,"depth":294,"links":11192},[11193,11198,11204,11205,11206,11217,11225],{"id":4099,"depth":297,"text":4099,"children":11194},[11195,11196,11197],{"id":9735,"depth":294,"text":9736},{"id":2109,"depth":294,"text":2109},{"id":9818,"depth":294,"text":9819},{"id":9900,"depth":297,"text":9901,"children":11199},[11200,11201,11202,11203],{"id":9904,"depth":294,"text":9905},{"id":9928,"depth":294,"text":9929},{"id":9972,"depth":294,"text":9973},{"id":10019,"depth":294,"text":10020},{"id":10054,"depth":297,"text":10055},{"id":10081,"depth":297,"text":10082},{"id":10141,"depth":297,"text":10142,"children":11207},[11208,11209,11210,11211,11212,11213,11214,11215,11216],{"id":10145,"depth":294,"text":9905},{"id":10174,"depth":294,"text":10175},{"id":10190,"depth":294,"text":9973},{"id":10217,"depth":294,"text":10218},{"id":10686,"depth":294,"text":10687},{"id":10706,"depth":294,"text":10707},{"id":10713,"depth":294,"text":10714},{"id":10726,"depth":294,"text":10727},{"id":10739,"depth":294,"text":10740},{"id":10758,"depth":297,"text":10759,"children":11218},[11219,11220,11221,11222,11223,11224],{"id":10762,"depth":294,"text":9905},{"id":10777,"depth":294,"text":10778},{"id":10793,"depth":294,"text":9973},{"id":10819,"depth":294,"text":10218},{"id":10964,"depth":294,"text":10965},{"id":10971,"depth":294,"text":10972},{"id":10984,"depth":297,"text":10985,"children":11226},[11227],{"id":10990,"depth":294,"text":10991},"2017-04-03","1 个 NameNode + 2 个 DataNode 的最小集群从零搭起：装 JDK\u002FScala、配 SSH 免密、改 Hadoop 和 Spark 的各个配置文件，到启动 dfs \u002F yarn \u002F jobhistory \u002F spark。",{},"\u002Fposts\u002Fcentos7-hadoop-spark-cluster-setup",{"title":9679,"description":11229},"posts\u002Fcentos7-hadoop-spark-cluster-setup",[11235,11236,11237,2469],"Hadoop","Spark","大数据","Ff8cmlBkw4INxrPXQKkg9_Y5j43JB-fhk5e15w3XDvI",{"id":11240,"title":11241,"body":11242,"date":11371,"description":11372,"extension":305,"meta":11373,"navigation":307,"path":11374,"seo":11375,"stem":11376,"tags":11377,"__hash__":11381},"posts\u002Fposts\u002Fwindows-install-facebook-prophet.md","Facebook 开源预测工具 Prophet 安装方法",{"type":9,"value":11243,"toc":11363},[11244,11253,11255,11257,11267,11271,11281,11285,11293,11297,11327,11330,11332,11335,11340,11345,11350,11361],[12,11245,11246,11247,11252],{},"最近研究看到一篇介绍 ",[96,11248,11251],{"href":11249,"rel":11250},"http:\u002F\u002Fmp.weixin.qq.com\u002Fs\u002F6yZRKbH0GYvqHwCDmpL-Uw",[100],"facebook 开源的大规模预测框架 Prophet"," 的文章，折腾了两个晚上终于在 Win 环境下安装成功，把结果分享下。",[4107,11254],{},[34,11256,4099],{"id":4099},[8331,11258,11259],{},[176,11260,11261,11264],{},[179,11262,11263],{},"Windows 7 x64",[179,11265,11266],{},"Anaconda3-4.2.0-Windows-x86 (Python 3.5)",[34,11268,11270],{"id":11269},"安装-visual-c-2015-build-tools","安装 Visual C++ 2015 Build Tools",[8331,11272,11273],{},[12,11274,11275,11276],{},"Prophet 需要 C 语言编译，在 Win 环境下需要先安装 ",[96,11277,11280],{"href":11278,"rel":11279},"http:\u002F\u002Flandinghub.visualstudio.com\u002Fvisual-cpp-build-tools",[100],"Visual C++ 2015 Build Tools",[34,11282,11284],{"id":11283},"安装-pystan","安装 pystan",[8331,11286,11287],{},[12,11288,11289,11290],{},"Prophet 依赖 pystan 包所以也需要安装 pystan\n",[350,11291,11292],{},"pip install pystan",[34,11294,11296],{"id":11295},"安装-prophet","安装 Prophet",[8331,11298,11299,11307,11318],{},[12,11300,11301],{},[183,11302,11303,11304],{},"不要用 ",[350,11305,11306],{},"pip install fbprophet",[12,11308,11309,11314,11315],{},[96,11310,11313],{"href":11311,"rel":11312},"https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet",[100],"下载"," prophet 最新源码。\n或者 ",[350,11316,11317],{},"git clone https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet",[12,11319,11320,11321,11324],{},"解压到指定目录，例如 D:\\Anaconda3\\prophet\nCMD:\n",[350,11322,11323],{},"cd D:\\Anaconda3\\prophet\\python",[350,11325,11326],{},"pip install -e .",[34,11328,11329],{"id":11329},"安装完成",[4107,11331],{},[34,11333,11334],{"id":11334},"踩过的坑",[12,11336,11337],{},[183,11338,11339],{},"1. error: command ‘C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\cl.exe’ failed with exit status 2",[8331,11341,11342],{},[12,11343,11344],{},"先确认 Visual C++ 2015 Build Tools 是否安装；如果已经安装，请放弃使用 pip 安装 Prophet。下载源码安装 Prophet 无问题。",[12,11346,11347],{},[183,11348,11349],{},"2. No such file or directory: u’fbprophet\u002Fstan_models\u002Flinear_growth.pkl’",[8331,11351,11352],{},[12,11353,11354,11355,11360],{},"目测是一个",[96,11356,11359],{"href":11357,"rel":11358},"https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet\u002Fpull\u002F100",[100],"已知 BUG","，已经修复。但好像 Release 的 v0.1 源码未更新。直接下载最新源码编译无报错。",[4107,11362],{},{"title":293,"searchDepth":294,"depth":294,"links":11364},[11365,11366,11367,11368,11369,11370],{"id":4099,"depth":297,"text":4099},{"id":11269,"depth":297,"text":11270},{"id":11283,"depth":297,"text":11284},{"id":11295,"depth":297,"text":11296},{"id":11329,"depth":297,"text":11329},{"id":11334,"depth":297,"text":11334},"2017-03-16","Win 下装 Prophet 不能用 pip install fbprophet，得先装 VC++ 2015 Build Tools 和 pystan，再从源码装。附两个踩坑记录。",{},"\u002Fposts\u002Fwindows-install-facebook-prophet",{"title":11241,"description":11372},"posts\u002Fwindows-install-facebook-prophet",[11378,11379,11380],"Python","Prophet","环境配置","VK4ZuyOpB9fUYEAljxs5oK8VsKbdxBhURT9c3OLmCAM",1792585396851]