[{"data":1,"prerenderedAt":9635},["ShallowReactive",2],{"posts:all":3},[4,297,700,1326,1551,1608,2325,3640,4921,5340,6087,6578,7521,7929,9492],{"id":5,"title":6,"body":7,"date":283,"description":284,"extension":285,"meta":286,"navigation":287,"path":288,"seo":289,"stem":290,"tags":291,"__hash__":296},"posts\u002Fposts\u002Feasyauth-2fa-webdav-s3-backup-client.md","换完手机，GitHub 把我挡在了门外",{"type":8,"value":9,"toc":268},"minimark",[10,14,17,20,23,28,31,34,63,66,69,72,105,108,111,115,118,121,128,136,144,147,150,153,158,161,175,182,185,188,191,194,201,207,210,217,220,223,226,265],[11,12,13],"p",{},"换完手机那天，GitHub 把我挡在了门外。",[11,15,16],{},"那天我坐在电脑前，屏幕上弹出来的还是那行熟悉的提示——请输入两步验证代码。我掏出手机打开验证器，列表是空的，一条都没有。换机之前我以为它会跟着微软账号一起同步回来，结果并没有。中间到底卡在哪一步断的，我到现在也说不清。",[11,18,19],{},"先翻恢复码，没存；翻邮箱，没有；翻笔记，还是没有。最后只能走申诉：填表、等回复、再补材料，一个账号折腾了好几天才算有个说法。",[11,21,22],{},"那几天我一直在想一件事：我的密码一个都没丢，锁是我自己加的，可钥匙不知道被我放哪儿去了。",[24,25,27],"h2",{"id":26},"那些验证器本来也没打算让你把数据拿走","那些验证器，本来也没打算让你把数据拿走",[11,29,30],{},"先说清楚，把验证码放在手机上没有任何问题。Microsoft Authenticator 我用了很多年，平时很顺手，它也确实尽职。",[11,32,33],{},"问题是，一直到出事那天我才发现，我从来没搞清楚过几件事：我的数据存在哪里、上一次同步是什么时候成功的、以及万一要用的时候，我能不能把它拿出来。",[35,36,37,45,51,57],"ul",{},[38,39,40,44],"li",{},[41,42,43],"strong",{},"Google Authenticator","：同步要连 Google 的服务。在国内能不能连上、什么时候能连上，基本看运气。它可以把账号扫码迁到另一个 App，但不会给你一份能自己保管的备份文件。",[38,46,47,50],{},[41,48,49],{},"Microsoft Authenticator","：备份锁在微软账号里，跨系统恢复限制不少——在安卓上备份的，往 iPhone 上恢复往往就不行。我这次就是栽在这儿：换完机打开，一条都没有。",[38,52,53,56],{},[41,54,55],{},"Authy","：注册要手机号，数据在它自己的云上。想手动导出一份，它不给这个选项。",[38,58,59,62],{},[41,60,61],{},"把 2FA 顺手塞进密码管理器","（1Password、Bitwarden 之类）：确实方便，但等于把密码和验证码放进同一个篮子。篮子漏了一次，二次验证也就白开了——它的全部意义本来就在于\"再多一道锁\"。",[11,64,65],{},"绕一圈你会发现，这些方案都在回答同一个问题：\"我的验证码存在谁那儿？\" 而答案基本都是\"存我这儿就行，你不用管\"。",[24,67,68],{"id":68},"我想要的东西其实很朴素",[11,70,71],{},"列出来就五条：",[73,74,75,81,87,93,99],"ol",{},[38,76,77,80],{},[41,78,79],{},"数据存在本地","，最好能用上系统的加密存储；",[38,82,83,86],{},[41,84,85],{},"能备份到我本来就有的地方","——坚果云、自己的 NAS、对象存储，这些我早就在用了，不想再为它单独开个账号；",[38,88,89,92],{},[41,90,91],{},"备份必须是加密的","，网盘服务商拿到也看不懂；",[38,94,95,98],{},[41,96,97],{},"兼容标准","，能从别家导进来，也能导出去，别再添一个孤岛；",[38,100,101,104],{},[41,102,103],{},"换手机的时候，别再让我把几十个账号一个个重新扫一遍","。",[11,106,107],{},"按这几条筛，能同时满足的其实不多：有些方案得自己搭服务、平时开着浏览器用，而我想要的只是在手机上点一下。",[11,109,110],{},"后来我用的是 EasyAuth。",[24,112,114],{"id":113},"easyauth-是什么","EasyAuth 是什么",[11,116,117],{},"一句话：一个开源的 2FA 验证器 App，本地存储、离线可用，并且支持把数据加密备份到你自己的 WebDAV 或 S3 存储。",[11,119,120],{},"它是 Flutter 写的，Apache 2.0 协议完全开源，代码公开可审计，没有账号体系、没有遥测、没有广告，也不需要 Google 服务框架。",[11,122,123,124,127],{},"目前能直接下载安装的是 ",[41,125,126],{},"Android 版 APK","（GitHub \u002F Gitee 上都有）。iOS、Windows、Linux 还没有预编译版本，源码是公开的，可以自己编译。",[11,129,130,131,135],{},"算法上是 TOTP（RFC 6238）和 HOTP（RFC 4226）两种标准，兼容 Google Authenticator 那套 ",[132,133,134],"code",{},"otpauth:\u002F\u002F"," 协议和迁移二维码——意味着它能跟别家互相搬家，不是又一个只能进不能出的孤岛。",[11,137,138],{},[139,140],"img",{"alt":141,"src":142,"width":143},"EasyAuth 主界面：口令按发行方分卡片，右侧是倒计时环","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F01-home-list.jpg",360,[11,145,146],{},"界面很朴素：顶上一行搜索框，下面是口令卡片，每张卡片三行——口令名、发行方、当前六位数字，右边一圈倒计时。没有花活，也没有让我盯着看的动画。",[24,148,149],{"id":149},"它把备份这件事做对了",[11,151,152],{},"如果只让我说一个推荐理由，就是备份。",[154,155,157],"h3",{"id":156},"备份存哪儿你说了算","备份存哪儿，你说了算",[11,159,160],{},"支持两类：",[35,162,163,169],{},[38,164,165,168],{},[41,166,167],{},"WebDAV","：坚果云、Nextcloud，以及群晖、威联通这些自建 NAS 基本都自带；",[38,170,171,174],{},[41,172,173],{},"S3 兼容","：AWS S3、阿里云 OSS、腾讯云 COS、七牛云、MinIO、Cloudflare R2 这类对象存储。",[11,176,177],{},[139,178],{"alt":179,"src":180,"width":181},"备份参数配置","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F02-03-backup.jpg",750,[11,183,184],{},"关键在于\"你自己的\"这四个字：填的是你自己服务器的地址、你自己的密钥，备份文件进的是你自己的空间。哪天不想用了，文件也还在你自己的空间里，不会因为某个服务关停就跟着消失。",[154,186,187],{"id":187},"备份本身是加密的",[11,189,190],{},"备份文件用 AES-256-GCM 加密，密钥由你设置的备份密码经 PBKDF2-HMAC-SHA256 迭代 60 万次派生。换句话说，你的网盘账号就算被别人拿到了，他下载走那个 zip 也只是一堆乱码。",[154,192,193],{"id":193},"多版本可回退",[11,195,196,197,200],{},"备份文件名带时间戳，形如 ",[132,198,199],{},"backup_20260527_120413.zip","，默认在远端保留最近 10 份，超出的自动清理。也可以在 App 里直接看到远端有哪些备份、手动删掉不要的，不用专门登录服务器去收拾。",[11,202,203],{},[139,204],{"alt":205,"src":206,"width":181},"管理远端备份：直接在 App 里查看和删除","\u002Fimages\u002Feasyauth-2fa-webdav-s3-backup-client\u002F04-05-backup.jpg",[154,208,209],{"id":209},"恢复不会手滑",[11,211,212,213,216],{},"恢复是覆盖式的，所以它一定会先弹一次确认。密码错了、或者备份文件损坏，它会直接报错，",[41,214,215],{},"不会","动你已经存在的数据。这个细节挺重要——恢复本来就是出事的时候才会做的事，那个时刻最不该再出岔子。",[24,218,219],{"id":219},"说在后面",[11,221,222],{},"2FA 的意义本来就是把钥匙多放一把在自己手里。既然如此，这把钥匙最好真的在自己手里。",[11,224,225],{},"对了，还得交代一句：EasyAuth 是我自己写的，起因就是开头那件事。它完全开源，用得上的话自取：",[35,227,228,237,244,251,258],{},[38,229,230,231],{},"官网：",[232,233,234],"a",{"href":234,"rel":235},"https:\u002F\u002Feasyauth.easydebug.net\u002F",[236],"nofollow",[38,238,239,240],{},"GitHub 仓库：",[232,241,242],{"href":242,"rel":243},"https:\u002F\u002Fgithub.com\u002FEasyDebug-NET\u002FEasyAuth",[236],[38,245,246,247],{},"GitHub 下载：",[232,248,249],{"href":249,"rel":250},"https:\u002F\u002Fgithub.com\u002FEasyDebug-NET\u002FEasyAuth\u002Freleases\u002Flatest",[236],[38,252,253,254],{},"Gitee 仓库：",[232,255,256],{"href":256,"rel":257},"https:\u002F\u002Fgitee.com\u002FEasyDebug-NET\u002FEasyAuth",[236],[38,259,260,261],{},"Gitee 下载：",[232,262,263],{"href":263,"rel":264},"https:\u002F\u002Fgitee.com\u002FEasyDebug-NET\u002FEasyAuth\u002Freleases\u002Flatest",[236],[11,266,267],{},"有问题欢迎在仓库里提 Issue。",{"title":269,"searchDepth":270,"depth":270,"links":271},"",2,[272,273,274,275,282],{"id":26,"depth":270,"text":27},{"id":68,"depth":270,"text":68},{"id":113,"depth":270,"text":114},{"id":149,"depth":270,"text":149,"children":276},[277,279,280,281],{"id":156,"depth":278,"text":157},3,{"id":187,"depth":278,"text":187},{"id":193,"depth":278,"text":193},{"id":209,"depth":278,"text":209},{"id":219,"depth":270,"text":219},"2026-09-16","换完手机，验证器的备份没把数据带回来，验证码一条没剩，我被自己的 GitHub 挡在门外好几天。这篇讲清 2FA 的备份困境，以及我最后换上的开源方案 EasyAuth。","md",{},true,"\u002Fposts\u002Feasyauth-2fa-webdav-s3-backup-client",{"title":6,"description":284},"posts\u002Feasyauth-2fa-webdav-s3-backup-client",[292,293,294,295],"2FA","安全","开源","工具","ErycfAcXQtinKViH5aJAQ5tjU_pW4zNL68_NWXVM7ro",{"id":298,"title":299,"body":300,"date":689,"description":690,"extension":285,"meta":691,"navigation":287,"path":692,"seo":693,"stem":694,"tags":695,"__hash__":699},"posts\u002Fposts\u002Fcentos7-firewalld-common-commands.md","CentOS7 Firewalld 防火墙常用命令",{"type":8,"value":301,"toc":676},[302,305,329,332,346,349,363,366,380,383,397,401,434,437,473,476,614,618,640,643,657,660,672],[24,303,304],{"id":304},"开启防火墙",[306,307,311],"pre",{"className":308,"code":309,"language":310,"meta":269,"style":269},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","systemctl start firewalld.service\n","bash",[132,312,313],{"__ignoreMap":269},[314,315,318,322,326],"span",{"class":316,"line":317},"line",1,[314,319,321],{"class":320},"sBMFI","systemctl",[314,323,325],{"class":324},"sfazB"," start",[314,327,328],{"class":324}," firewalld.service\n",[24,330,331],{"id":331},"关闭防火墙",[306,333,335],{"className":308,"code":334,"language":310,"meta":269,"style":269},"systemctl stop firewalld.service\n",[132,336,337],{"__ignoreMap":269},[314,338,339,341,344],{"class":316,"line":317},[314,340,321],{"class":320},[314,342,343],{"class":324}," stop",[314,345,328],{"class":324},[24,347,348],{"id":348},"查看防火墙状态",[306,350,352],{"className":308,"code":351,"language":310,"meta":269,"style":269},"systemctl status firewalld.service\n",[132,353,354],{"__ignoreMap":269},[314,355,356,358,361],{"class":316,"line":317},[314,357,321],{"class":320},[314,359,360],{"class":324}," status",[314,362,328],{"class":324},[24,364,365],{"id":365},"开启开机启动防火墙",[306,367,369],{"className":308,"code":368,"language":310,"meta":269,"style":269},"systemctl enable firewalld.service\n",[132,370,371],{"__ignoreMap":269},[314,372,373,375,378],{"class":316,"line":317},[314,374,321],{"class":320},[314,376,377],{"class":324}," enable",[314,379,328],{"class":324},[24,381,382],{"id":382},"关闭开机启动防火墙",[306,384,386],{"className":308,"code":385,"language":310,"meta":269,"style":269},"systemctl disable firewalld.service\n",[132,387,388],{"__ignoreMap":269},[314,389,390,392,395],{"class":316,"line":317},[314,391,321],{"class":320},[314,393,394],{"class":324}," disable",[314,396,328],{"class":324},[24,398,400],{"id":399},"开启某个端口80","开启某个端口（80）",[306,402,404],{"className":308,"code":403,"language":310,"meta":269,"style":269},"firewall-cmd --zone=public --add-port=80\u002Ftcp --permanent   \u002F\u002F永久\nfirewall-cmd --zone=public --add-port=80\u002Ftcp               \u002F\u002F临时\n",[132,405,406,423],{"__ignoreMap":269},[314,407,408,411,414,417,420],{"class":316,"line":317},[314,409,410],{"class":320},"firewall-cmd",[314,412,413],{"class":324}," --zone=public",[314,415,416],{"class":324}," --add-port=80\u002Ftcp",[314,418,419],{"class":324}," --permanent",[314,421,422],{"class":324},"   \u002F\u002F永久\n",[314,424,425,427,429,431],{"class":316,"line":270},[314,426,410],{"class":320},[314,428,413],{"class":324},[314,430,416],{"class":324},[314,432,433],{"class":324},"               \u002F\u002F临时\n",[24,435,436],{"id":436},"端口转发",[306,438,440],{"className":308,"code":439,"language":310,"meta":269,"style":269},"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",[132,441,442,456,461],{"__ignoreMap":269},[314,443,444,446,448,451,453],{"class":316,"line":317},[314,445,410],{"class":320},[314,447,413],{"class":324},[314,449,450],{"class":324}," --add-masquerade",[314,452,419],{"class":324},[314,454,455],{"class":324},"    \u002F\u002F打开IP地址伪装\n",[314,457,458],{"class":316,"line":270},[314,459,460],{"class":320},"\u002F\u002F将8080转发到80\n",[314,462,463,465,467,470],{"class":316,"line":278},[314,464,410],{"class":320},[314,466,413],{"class":324},[314,468,469],{"class":324}," --add-forward-port=port=80:proto=tcp:toport=8080",[314,471,472],{"class":324}," --permanent\n",[24,474,475],{"id":475},"创建黑名单",[306,477,479],{"className":308,"code":478,"language":310,"meta":269,"style":269},"\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",[132,480,481,489,503,511,533,541,552,558,572,586,600],{"__ignoreMap":269},[314,482,483,486],{"class":316,"line":317},[314,484,485],{"class":320},"\u002F\u002F创建blacklist",[314,487,488],{"class":324}," ipset\n",[314,490,491,493,495,497,500],{"class":316,"line":270},[314,492,410],{"class":320},[314,494,419],{"class":324},[314,496,413],{"class":324},[314,498,499],{"class":324}," --new-ipset=blacklist",[314,501,502],{"class":324}," --type=hash:ip\n",[314,504,505,508],{"class":316,"line":278},[314,506,507],{"class":320},"\u002F\u002F封禁",[314,509,510],{"class":324}," blacklist\n",[314,512,514,516,518,520,523,527,530],{"class":316,"line":513},4,[314,515,410],{"class":320},[314,517,419],{"class":324},[314,519,413],{"class":324},[314,521,522],{"class":324}," --add-rich-rule=",[314,524,526],{"class":525},"sMK4o","'",[314,528,529],{"class":324},"rule source ipset=blacklist drop",[314,531,532],{"class":525},"'\n",[314,534,536,539],{"class":316,"line":535},5,[314,537,538],{"class":320},"\u002F\u002F查看",[314,540,510],{"class":324},[314,542,544,546,549],{"class":316,"line":543},6,[314,545,410],{"class":320},[314,547,548],{"class":324}," --ipset=blacklist",[314,550,551],{"class":324}," --get-entries\n",[314,553,555],{"class":316,"line":554},7,[314,556,557],{"class":320},"\u002F\u002F添加IP到黑名单\n",[314,559,561,563,565,567,569],{"class":316,"line":560},8,[314,562,410],{"class":320},[314,564,419],{"class":324},[314,566,413],{"class":324},[314,568,548],{"class":324},[314,570,571],{"class":324}," --add-entry=212.237.51.36\n",[314,573,575,577,579,581,583],{"class":316,"line":574},9,[314,576,410],{"class":320},[314,578,419],{"class":324},[314,580,413],{"class":324},[314,582,548],{"class":324},[314,584,585],{"class":324}," --add-entry=188.226.191.66\n",[314,587,589,591,593,595,597],{"class":316,"line":588},10,[314,590,410],{"class":320},[314,592,419],{"class":324},[314,594,413],{"class":324},[314,596,548],{"class":324},[314,598,599],{"class":324}," --add-entry=80.211.137.182\n",[314,601,603,605,607,609,611],{"class":316,"line":602},11,[314,604,410],{"class":320},[314,606,419],{"class":324},[314,608,413],{"class":324},[314,610,548],{"class":324},[314,612,613],{"class":324}," --add-entry=60.191.66.226\n",[24,615,617],{"id":616},"禁止被-ping丢弃-icmp-包","禁止被 PING（丢弃 ICMP 包）",[306,619,621],{"className":308,"code":620,"language":310,"meta":269,"style":269},"firewall-cmd --permanent --zone=public --add-rich-rule='rule protocol value=icmp drop'  \n",[132,622,623],{"__ignoreMap":269},[314,624,625,627,629,631,633,635,638],{"class":316,"line":317},[314,626,410],{"class":320},[314,628,419],{"class":324},[314,630,413],{"class":324},[314,632,522],{"class":324},[314,634,526],{"class":525},[314,636,637],{"class":324},"rule protocol value=icmp drop",[314,639,532],{"class":525},[24,641,642],{"id":642},"查看所有规则",[306,644,646],{"className":308,"code":645,"language":310,"meta":269,"style":269},"firewall-cmd --zone=public --list-all\n",[132,647,648],{"__ignoreMap":269},[314,649,650,652,654],{"class":316,"line":317},[314,651,410],{"class":320},[314,653,413],{"class":324},[314,655,656],{"class":324}," --list-all\n",[24,658,659],{"id":659},"重载防火墙配置",[306,661,663],{"className":308,"code":662,"language":310,"meta":269,"style":269},"firewall-cmd --reload\n",[132,664,665],{"__ignoreMap":269},[314,666,667,669],{"class":316,"line":317},[314,668,410],{"class":320},[314,670,671],{"class":324}," --reload\n",[673,674,675],"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 .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":269,"searchDepth":270,"depth":270,"links":677},[678,679,680,681,682,683,684,685,686,687,688],{"id":304,"depth":270,"text":304},{"id":331,"depth":270,"text":331},{"id":348,"depth":270,"text":348},{"id":365,"depth":270,"text":365},{"id":382,"depth":270,"text":382},{"id":399,"depth":270,"text":400},{"id":436,"depth":270,"text":436},{"id":475,"depth":270,"text":475},{"id":616,"depth":270,"text":617},{"id":642,"depth":270,"text":642},{"id":659,"depth":270,"text":659},"2025-01-24","firewalld 的日常操作速查：开关服务、放行端口、端口转发、ipset 黑名单、丢弃 ICMP、重载配置。",{},"\u002Fposts\u002Fcentos7-firewalld-common-commands",{"title":299,"description":690},"posts\u002Fcentos7-firewalld-common-commands",[696,697,698],"CentOS","运维","防火墙","UCJp32SdIZih_LOwZd24fMb5Be7CTSvhNDdHcTNgHRU",{"id":701,"title":702,"body":703,"date":1314,"description":1315,"extension":285,"meta":1316,"navigation":287,"path":1317,"seo":1318,"stem":1319,"tags":1320,"__hash__":1325},"posts\u002Fposts\u002Fdelayq-redis-delay-queue.md","DelayQ：用 Redis 和数据库做一个延时队列",{"type":8,"value":704,"toc":1300},[705,708,711,714,717,720,731,734,737,740,743,749,752,758,761,787,790,794,797,803,821,824,828,843,847,853,856,901,904,907,913,916,919,922,928,990,1000,1005,1014,1017,1036,1046,1049,1056,1064,1067,1192,1195,1236,1242,1249,1253,1256,1276,1279,1282,1291,1294,1297],[11,706,707],{},"业务里总有一类需求，叫“过一会儿再做”。",[11,709,710],{},"订单创建后 30 分钟没付款就自动关单；下单 15 分钟后推一条提醒；接口调失败了，等 5 分钟再重试一次；会员到期前三天发一封续费通知。",[11,712,713],{},"这类需求拆开看，目标都很朴素：到点执行、失败了要能重试、最后还得看得见状态。难点从来不在“延”，而在“时”—— 谁来记着这件事，以及进程重启之后它还记得吗。",[11,715,716],{},"DelayQ 就是我为这件事写的一个中间件。",[24,718,719],{"id":719},"先说为什么不用现成的",[11,721,722,723,726,727,730],{},"最省事的做法是在业务代码里 ",[132,724,725],{},"Thread.sleep()","，或者丢给 ",[132,728,729],{},"ScheduledExecutorService","。单机跑个小脚本没问题，可它撑不住两件事：进程一重启，内存里的任务就全没了；多起一个实例，两边各算各的。",[11,732,733],{},"换成定时任务扫库呢？那得先回答两个问题：多久扫一次 —— 扫得越勤精度越高、数据库压力也越大；以及怎么保证几个实例不会同时抢到同一个任务。这两个问题不难，但每次都要重新想一遍。",[11,735,736],{},"那上 MQ 呢？RabbitMQ 用 TTL + 死信队列能做延时，RocketMQ 有自带的延时消息。都是成熟方案，但它们的延时级别往往是固定的几档，而且通常还附带一整套运维成本。我需要的是“任意秒数 + 到点调一个 HTTP 接口”，为这一件事养一个 MQ，不太划算。",[11,738,739],{},"DelayQ 的设计参考了有赞延迟队列的思路：把“任务的元信息”和“待触发的时间线”拆开存，中间用一条扫描线连接。",[24,741,742],{"id":742},"它是什么",[11,744,745,746],{},"一句话：",[41,747,748],{},"基于 Redis 和数据库的延时队列中间件，Java 开发，到点之后去调用一个你指定的 RESTful 接口。",[11,750,751],{},"跑起来之后是这样的：",[11,753,754],{},[139,755],{"alt":756,"src":757},"DelayQ 架构：Job Pool 与 Delay Bucket 在 Redis，Timer 和 Runner 是两个 Java 线程池","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Farchitecture.png",[11,759,760],{},"四块职责：",[73,762,763,769,775,781],{},[38,764,765,768],{},[41,766,767],{},"Job Pool"," —— 存放所有 Job 的元信息，落在 Redis Hash 和数据库里；",[38,770,771,774],{},[41,772,773],{},"Delay Bucket"," —— 十组以时间为维度的有序队列（Redis ZSet），按 Job Id 判定存进哪个 Bucket，里面只放 Job Id；",[38,776,777,780],{},[41,778,779],{},"Timer"," —— 实时扫描各个 Bucket，把 delay 时间已经到期的 Job 丢进对应的 Ready Queue；",[38,782,783,786],{},[41,784,785],{},"Ready Queue"," —— 按任务类型（Topic）执行，执行完把任务状态回写进 Job Pool。它对应架构图右侧那个 Runner。",[11,788,789],{},"这里有个刻意的分工：用 Redis ZSet 存时间线，“找下一个该执行的任务”就是一次有序查询，不用把整个队列翻一遍；而真正的任务体（要调的 URL、header、body）放在 Job Pool 里，Bucket 里只留一个 Id。高频变动的那个结构因此始终很轻。",[24,791,793],{"id":792},"它不假装自己是通用-mq","它不假装自己是通用 MQ",[11,795,796],{},"先把边界说清楚，省得你跑起来才发现不对路。",[11,798,799,800],{},"DelayQ 只做一件事：",[41,801,802],{},"到点了，替你去调一个 HTTP 接口。",[35,804,805,812,815,818],{},[38,806,807,808,811],{},"目前",[41,809,810],{},"只支持 Post 请求","，其他请求方式还在计划里；",[38,813,814],{},"数据库是用 PostgreSQL 开发的，理论上兼容 Oracle、MySQL、MariaDB，但这个“理论上”需要你自己验一遍；",[38,816,817],{},"它依赖 Redis 和一个数据库，不是一个零依赖的独立进程；",[38,819,820],{},"它不做消息的广播、分区、顺序保证，那些是 MQ 的活儿。",[24,822,823],{"id":823},"三个真正用得上的细节",[154,825,827],{"id":826},"delay-和-ttr","delay 和 ttr",[11,829,830,831,834,835,838,839,842],{},"创建任务时有三个参数：",[132,832,833],{},"topic"," 是任务类型，",[132,836,837],{},"delay"," 是从现在起等多少秒再执行，",[132,840,841],{},"ttr"," 是超时时间，单位都是秒。",[154,844,846],{"id":845},"passrule怎么判断成功了","passrule：怎么判断“成功了”",[11,848,849,850,104],{},"调远端接口最麻烦的是“它到底成没成”。HTTP 200 不代表业务成功，返回体里可能明明白白写着 ",[132,851,852],{},"\"code\": 0",[11,854,855],{},"DelayQ 的做法是让你给一条通过规则：",[306,857,861],{"className":858,"code":859,"language":860,"meta":269,"style":269},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"passrule\": { \"code\": \"1\" }\n","json",[132,862,863],{"__ignoreMap":269},[314,864,865,868,871,873,877,880,883,886,888,891,893,896,898],{"class":316,"line":317},[314,866,867],{"class":525},"\"",[314,869,870],{"class":324},"passrule",[314,872,867],{"class":525},[314,874,876],{"class":875},"sTEyZ",": ",[314,878,879],{"class":525},"{",[314,881,882],{"class":525}," \"",[314,884,132],{"class":885},"spNyl",[314,887,867],{"class":525},[314,889,890],{"class":525},":",[314,892,882],{"class":525},[314,894,895],{"class":324},"1",[314,897,867],{"class":525},[314,899,900],{"class":525}," }\n",[11,902,903],{},"它拿远端服务返回的报文去比这条规则，对上了才算任务成功。比只看 HTTP 状态码靠谱得多 —— 任务状态是 success 还是 error，得由业务结果说了算。",[154,905,906],{"id":906},"任务是看得见的",[11,908,909],{},[139,910],{"alt":911,"src":912},"任务列表：ID、Job 类型、延迟时间、超时时间、状态、预计执行时间、创建时间","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Ftask-list.png",[11,914,915],{},"列表页把每个 Job 的类型、delay、ttr、状态（success \u002F error）、预计执行时间和创建时间都摆了出来，顶部可以按 ID、Job 类型、状态筛选。排查的时候不至于去翻日志猜 —— 这一点在我自己的使用里比想象中重要。",[24,917,918],{"id":918},"跑起来",[11,920,921],{},"环境只要三样：Java 1.8+、Redis、一个数据库。",[11,923,924,927],{},[41,925,926],{},"1. 建表。"," 仓库里给了 PostgreSQL 和 Oracle 两份 DDL，PostgreSQL 这份是：",[306,929,933],{"className":930,"code":931,"language":932,"meta":269,"style":269},"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",[132,934,935,940,945,950,955,960,965,970,975,980,985],{"__ignoreMap":269},[314,936,937],{"class":316,"line":317},[314,938,939],{},"CREATE TABLE tb_delayq_job (\n",[314,941,942],{"class":316,"line":270},[314,943,944],{},"    id int8 NOT NULL,\n",[314,946,947],{"class":316,"line":278},[314,948,949],{},"    topic varchar(50) NULL,\n",[314,951,952],{"class":316,"line":513},[314,953,954],{},"    delay int4 NULL,\n",[314,956,957],{"class":316,"line":535},[314,958,959],{},"    ttr int4 NULL,\n",[314,961,962],{"class":316,"line":543},[314,963,964],{},"    body varchar(1000) NULL,\n",[314,966,967],{"class":316,"line":554},[314,968,969],{},"    status varchar(10) NULL,\n",[314,971,972],{"class":316,"line":560},[314,973,974],{},"    execution_time int8 NULL,\n",[314,976,977],{"class":316,"line":574},[314,978,979],{},"    create_time int8 NULL,\n",[314,981,982],{"class":316,"line":588},[314,983,984],{},"    CONSTRAINT pk_tb_delayq_job_id PRIMARY KEY (id)\n",[314,986,987],{"class":316,"line":602},[314,988,989],{},");\n",[11,991,992,995,996,999],{},[41,993,994],{},"2. 改配置。"," 编辑 ",[132,997,998],{},"application-dev.yml","，填上 Redis 和数据库的连接信息。",[11,1001,1002],{},[41,1003,1004],{},"3. 启动。",[306,1006,1008],{"className":308,"code":1007,"language":310,"meta":269,"style":269},".\u002Fstartup.sh\n",[132,1009,1010],{"__ignoreMap":269},[314,1011,1012],{"class":316,"line":317},[314,1013,1007],{"class":320},[11,1015,1016],{},"或者直接跑 jar：",[306,1018,1020],{"className":308,"code":1019,"language":310,"meta":269,"style":269},"java -jar DelayQ.jar --spring.profiles.active=dev\n",[132,1021,1022],{"__ignoreMap":269},[314,1023,1024,1027,1030,1033],{"class":316,"line":317},[314,1025,1026],{"class":320},"java",[314,1028,1029],{"class":324}," -jar",[314,1031,1032],{"class":324}," DelayQ.jar",[314,1034,1035],{"class":324}," --spring.profiles.active=dev\n",[11,1037,1038,1041,1042,1045],{},[41,1039,1040],{},"4. 打开界面。"," 访问 ",[132,1043,1044],{},"http:\u002F\u002Flocalhost:16996\u002Fdelay-q\u002Findex","，就是上面那个任务列表。",[24,1047,1048],{"id":1048},"加一个任务",[11,1050,1051,1052,1055],{},"向 ",[132,1053,1054],{},"add"," 接口发一个 Post，查询参数就是前面说的三个：",[306,1057,1062],{"className":1058,"code":1060,"language":1061},[1059],"language-text","POST http:\u002F\u002Flocalhost:16996\u002Fdelay-q\u002Fadd?topic=HttpPostTask&delay=60&ttr=10\n","text",[132,1063,1060],{"__ignoreMap":269},[11,1065,1066],{},"请求体里写清楚“到点之后要干什么”：",[306,1068,1070],{"className":858,"code":1069,"language":860,"meta":269,"style":269},"{\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",[132,1071,1072,1077,1099,1113,1133,1138,1154,1166,1182,1187],{"__ignoreMap":269},[314,1073,1074],{"class":316,"line":317},[314,1075,1076],{"class":525},"{\n",[314,1078,1079,1082,1085,1087,1089,1091,1094,1096],{"class":316,"line":270},[314,1080,1081],{"class":525},"  \"",[314,1083,1084],{"class":885},"url",[314,1086,867],{"class":525},[314,1088,890],{"class":525},[314,1090,882],{"class":525},[314,1092,1093],{"class":324},"http:\u002F\u002F172.16.6.202:16996\u002Fdelay-q\u002Fadd?topic=PrintTask&delay=10&ttr=10",[314,1095,867],{"class":525},[314,1097,1098],{"class":525},",\n",[314,1100,1101,1103,1106,1108,1110],{"class":316,"line":278},[314,1102,1081],{"class":525},[314,1104,1105],{"class":885},"headers",[314,1107,867],{"class":525},[314,1109,890],{"class":525},[314,1111,1112],{"class":525}," {\n",[314,1114,1115,1118,1121,1123,1125,1127,1130],{"class":316,"line":513},[314,1116,1117],{"class":525},"    \"",[314,1119,1120],{"class":320},"Content-Type",[314,1122,867],{"class":525},[314,1124,890],{"class":525},[314,1126,882],{"class":525},[314,1128,1129],{"class":324},"application\u002Fjson",[314,1131,1132],{"class":525},"\"\n",[314,1134,1135],{"class":316,"line":535},[314,1136,1137],{"class":525},"  },\n",[314,1139,1140,1142,1145,1147,1149,1152],{"class":316,"line":543},[314,1141,1081],{"class":525},[314,1143,1144],{"class":885},"body",[314,1146,867],{"class":525},[314,1148,890],{"class":525},[314,1150,1151],{"class":525}," \"\"",[314,1153,1098],{"class":525},[314,1155,1156,1158,1160,1162,1164],{"class":316,"line":554},[314,1157,1081],{"class":525},[314,1159,870],{"class":885},[314,1161,867],{"class":525},[314,1163,890],{"class":525},[314,1165,1112],{"class":525},[314,1167,1168,1170,1172,1174,1176,1178,1180],{"class":316,"line":560},[314,1169,1117],{"class":525},[314,1171,132],{"class":320},[314,1173,867],{"class":525},[314,1175,890],{"class":525},[314,1177,882],{"class":525},[314,1179,895],{"class":324},[314,1181,1132],{"class":525},[314,1183,1184],{"class":316,"line":574},[314,1185,1186],{"class":525},"  }\n",[314,1188,1189],{"class":316,"line":588},[314,1190,1191],{"class":525},"}\n",[11,1193,1194],{},"参数逐个说：",[35,1196,1197,1206,1211,1216,1221,1226,1231],{},[38,1198,1199,1201,1202,1205],{},[132,1200,833],{},"（必填）：任务类型，",[132,1203,1204],{},"HttpPostTask"," 是内置的那一种；",[38,1207,1208,1210],{},[132,1209,837],{},"（必填）：等待秒数；",[38,1212,1213,1215],{},[132,1214,841],{},"（必填）：超时秒数；",[38,1217,1218,1220],{},[132,1219,1084],{},"（必填）：远端服务地址；",[38,1222,1223,1225],{},[132,1224,1105],{},"（可选）：请求头；",[38,1227,1228,1230],{},[132,1229,1144],{},"（可选）：POST 的报文；",[38,1232,1233,1235],{},[132,1234,870],{},"（可选）：上面那条通过规则。",[11,1237,1238],{},[139,1239],{"alt":1240,"src":1241},"用 Postman 发一个 add 请求，响应里的 data 就是新 Job 的 ID","\u002Fimages\u002Fdelayq-redis-delay-queue\u002Fpostman-add-task.png",[11,1243,1244,1245,1248],{},"返回体里的 ",[132,1246,1247],{},"data"," 就是新建 Job 的 ID，拿它去列表页就能查到这条任务后面执行成什么样了。",[24,1250,1252],{"id":1251},"现在的样子和下一步","现在的样子，和下一步",[11,1254,1255],{},"它还算年轻，有几件事我自己清楚没做好，一并写在这里：",[73,1257,1258,1264,1270],{},[38,1259,1260,1263],{},[41,1261,1262],{},"多实例部署时，多个 Timer 会同时扫描。"," 同一批 Bucket 被重复扫，白白消耗资源 —— 这是最该先解决的问题；",[38,1265,1266,1269],{},[41,1267,1268],{},"只支持 Post。"," 后续想加上更多请求方式；",[38,1271,1272,1275],{},[41,1273,1274],{},"界面功能还薄。"," 列表、筛选、删除够用，但离完善还有距离。",[24,1277,1278],{"id":1278},"最后",[11,1280,1281],{},"仓库在这里，Apache License 2.0，代码随便看、随便用：",[35,1283,1284],{},[38,1285,1286,1287],{},"Gitee：",[232,1288,1289],{"href":1289,"rel":1290},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002FDelayQ",[236],[11,1292,1293],{},"如果你也在纠结“这几万个到点要执行的任务该放哪儿”，可以先 clone 下来跑一遍 —— 建一张表、连上 Redis，就能看到任务在列表里一条条变成 success。",[11,1295,1296],{},"用着有问题或者有想法，欢迎直接提 Issue。",[673,1298,1299],{},"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":269,"searchDepth":270,"depth":270,"links":1301},[1302,1303,1304,1305,1310,1311,1312,1313],{"id":719,"depth":270,"text":719},{"id":742,"depth":270,"text":742},{"id":792,"depth":270,"text":793},{"id":823,"depth":270,"text":823,"children":1306},[1307,1308,1309],{"id":826,"depth":278,"text":827},{"id":845,"depth":278,"text":846},{"id":906,"depth":278,"text":906},{"id":918,"depth":270,"text":918},{"id":1048,"depth":270,"text":1048},{"id":1251,"depth":270,"text":1252},{"id":1278,"depth":270,"text":1278},"2022-02-17","一个基于 Redis 和数据库的延时队列中间件，Java 开发，到点之后替你调用一个 RESTful 接口。这篇讲清它的四块架构、设计取舍、已知短板，以及怎么跑起来。",{},"\u002Fposts\u002Fdelayq-redis-delay-queue",{"title":702,"description":1315},"posts\u002Fdelayq-redis-delay-queue",[1321,1322,1323,294,1324],"Java","Redis","消息队列","中间件","qFydD73LTlomELfwW8Ptc7IUnd1O_iwTqM-VEb0PDj4",{"id":1327,"title":1328,"body":1329,"date":1541,"description":1542,"extension":285,"meta":1543,"navigation":287,"path":1544,"seo":1545,"stem":1546,"tags":1547,"__hash__":1550},"posts\u002Fposts\u002Fmysql-batch-rename-table-column.md","MySQL 批量修改表名列名大小写",{"type":8,"value":1330,"toc":1537},[1331,1338,1342,1408,1412,1527,1534],[11,1332,1333,1334,1337],{},"接手老库时经常会碰到表名列名大小写混乱的情况。手写 rename 语句太累，不如查 ",[132,1335,1336],{},"information_schema"," 让数据库自己生成一批 SQL，复制出来跑就行。",[24,1339,1341],{"id":1340},"批量表名大写改小写","批量表名：大写改小写",[306,1343,1345],{"className":930,"code":1344,"language":932,"meta":269,"style":269},"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",[132,1346,1347,1352,1357,1362,1367,1372,1377,1382,1387,1392,1397,1402],{"__ignoreMap":269},[314,1348,1349],{"class":316,"line":317},[314,1350,1351],{},"SELECT\n",[314,1353,1354],{"class":316,"line":270},[314,1355,1356],{}," concat(\n",[314,1358,1359],{"class":316,"line":278},[314,1360,1361],{},"     'rename table  '\n",[314,1363,1364],{"class":316,"line":513},[314,1365,1366],{},"     , TABLE_NAME\n",[314,1368,1369],{"class":316,"line":535},[314,1370,1371],{},"     , ' to '\n",[314,1373,1374],{"class":316,"line":543},[314,1375,1376],{},"     , LOWER(TABLE_NAME)\n",[314,1378,1379],{"class":316,"line":554},[314,1380,1381],{},"     ,' ;'\n",[314,1383,1384],{"class":316,"line":560},[314,1385,1386],{}," ) AS 'SQL'\n",[314,1388,1389],{"class":316,"line":574},[314,1390,1391],{},"FROM\n",[314,1393,1394],{"class":316,"line":588},[314,1395,1396],{}," information_schema.TABLES t \n",[314,1398,1399],{"class":316,"line":602},[314,1400,1401],{},"WHERE\n",[314,1403,1405],{"class":316,"line":1404},12,[314,1406,1407],{}," TABLE_SCHEMA = 'xxxxxx';\n",[24,1409,1411],{"id":1410},"批量列名大写改小写","批量列名：大写改小写",[306,1413,1415],{"className":930,"code":1414,"language":932,"meta":269,"style":269},"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",[132,1416,1417,1421,1426,1431,1436,1441,1446,1451,1456,1460,1465,1470,1475,1481,1487,1493,1499,1505,1510,1516,1521],{"__ignoreMap":269},[314,1418,1419],{"class":316,"line":317},[314,1420,1351],{},[314,1422,1423],{"class":316,"line":270},[314,1424,1425],{},"concat(\n",[314,1427,1428],{"class":316,"line":278},[314,1429,1430],{},"    'alter table '\n",[314,1432,1433],{"class":316,"line":513},[314,1434,1435],{},"    , TABLE_NAME\n",[314,1437,1438],{"class":316,"line":535},[314,1439,1440],{},"    , ' change column '\n",[314,1442,1443],{"class":316,"line":543},[314,1444,1445],{},"    , COLUMN_NAME\n",[314,1447,1448],{"class":316,"line":554},[314,1449,1450],{},"    , ' '\n",[314,1452,1453],{"class":316,"line":560},[314,1454,1455],{},"    , LOWER(COLUMN_NAME)\n",[314,1457,1458],{"class":316,"line":574},[314,1459,1450],{},[314,1461,1462],{"class":316,"line":588},[314,1463,1464],{},"    , COLUMN_TYPE\n",[314,1466,1467],{"class":316,"line":602},[314,1468,1469],{},"    , ' comment \\''\n",[314,1471,1472],{"class":316,"line":1404},[314,1473,1474],{},"    , TRIM(REPLACE(REPLACE(REPLACE(REPLACE(COLUMN_COMMENT,',',':'),'\"',''),CHAR(10),''),CHAR(13),''))\n",[314,1476,1478],{"class":316,"line":1477},13,[314,1479,1480],{},"     , '\\''\n",[314,1482,1484],{"class":316,"line":1483},14,[314,1485,1486],{},"     , ' '\n",[314,1488,1490],{"class":316,"line":1489},15,[314,1491,1492],{},"     , IF(COLUMN_DEFAULT IS NULL, '', concat(' default \\'',TRIM(COLUMN_DEFAULT),'\\'')) \n",[314,1494,1496],{"class":316,"line":1495},16,[314,1497,1498],{},"     , ';' \n",[314,1500,1502],{"class":316,"line":1501},17,[314,1503,1504],{},") AS 'SQL'\n",[314,1506,1508],{"class":316,"line":1507},18,[314,1509,1391],{},[314,1511,1513],{"class":316,"line":1512},19,[314,1514,1515],{},"    information_schema.COLUMNS t\n",[314,1517,1519],{"class":316,"line":1518},20,[314,1520,1401],{},[314,1522,1524],{"class":316,"line":1523},21,[314,1525,1526],{},"    TABLE_SCHEMA = 'xxxxxx';\n",[11,1528,1529,1530,1533],{},"把 ",[132,1531,1532],{},"xxxxxx"," 换成你的库名，执行一遍拿到生成的 SQL，再贴到客户端里跑。",[673,1535,1536],{},"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":269,"searchDepth":270,"depth":270,"links":1538},[1539,1540],{"id":1340,"depth":270,"text":1341},{"id":1410,"depth":270,"text":1411},"2021-10-24","用 information_schema 生成批量 rename table \u002F change column 语句，把大写的表名列名一次性改成小写。",{},"\u002Fposts\u002Fmysql-batch-rename-table-column",{"title":1328,"description":1542},"posts\u002Fmysql-batch-rename-table-column",[1548,1549],"MySQL","数据库","kQ0Q8KVGIqox_MqjbX0RkuflyO9Psmo12rnvlY0jrzA",{"id":1552,"title":1553,"body":1554,"date":1599,"description":1600,"extension":285,"meta":1601,"navigation":287,"path":1602,"seo":1603,"stem":1604,"tags":1605,"__hash__":1607},"posts\u002Fposts\u002Fwin7-windows-update-error-80072ee2.md","新装 Win7 后 Windows Update 报 80072EE2 \u002F 80072EFE",{"type":8,"value":1555,"toc":1595},[1556,1559,1562,1568,1571,1574,1590],[24,1557,1558],{"id":1558},"故障场景",[11,1560,1561],{},"最近有台老电脑重装 Win7 系统，装完以后无法安装补丁，要么就报错 80072EE2，要么就报 80072EFE。",[11,1563,1564],{},[139,1565],{"alt":1566,"src":1567},"Windows Update 报错 80072EE2","\u002Fimages\u002Fwin7-windows-update\u002Ferror-80072ee2.png",[24,1569,1570],{"id":1570},"解决方法",[11,1572,1573],{},"安装补丁：",[73,1575,1576,1583],{},[38,1577,1578],{},[232,1579,1582],{"href":1580,"rel":1581},"https:\u002F\u002Fwww.catalog.update.microsoft.com\u002FSearch.aspx?q=KB3020369",[236],"Windows6.1-KB3020369",[38,1584,1585],{},[232,1586,1589],{"href":1587,"rel":1588},"https:\u002F\u002Fwww.catalog.update.microsoft.com\u002FSearch.aspx?q=KB3125574",[236],"Windows6.1-KB3125574",[11,1591,1592],{},[41,1593,1594],{},"一定要注意顺序：先安装 KB3020369，后安装 KB3125574。",{"title":269,"searchDepth":270,"depth":270,"links":1596},[1597,1598],{"id":1558,"depth":270,"text":1558},{"id":1570,"depth":270,"text":1570},"2021-07-31","老电脑重装 Win7 后装不上补丁，报这两个错误码。按顺序打两个补丁就能救回来。",{},"\u002Fposts\u002Fwin7-windows-update-error-80072ee2",{"title":1553,"description":1600},"posts\u002Fwin7-windows-update-error-80072ee2",[1606,697],"Windows","O1JcuhOCG-hIb4YmRAwmWs2mXMhR0gsCrjgHbP5fjRE",{"id":1609,"title":1610,"body":1611,"date":2314,"description":2315,"extension":285,"meta":2316,"navigation":287,"path":2317,"seo":2318,"stem":2319,"tags":2320,"__hash__":2324},"posts\u002Fposts\u002Fnacos-snowflake-worker-id.md","用 Nacos 分配 Snowflake 的 Worker ID",{"type":8,"value":1612,"toc":2308},[1613,1616,1619,1622,1630,1633,1639,1646,2291,2294,2306],[24,1614,1615],{"id":1615},"背景",[11,1617,1618],{},"Snowflake 唯一 ID 算法大家都很熟悉，他是 Twitter 公司提出来的算法。但是对于 workerId 和 datacenterId 的维护往往需要各项目自行设计。\n基本都是基于 zookeeper or 数据库 or Redis 的。\n本例就是用 Nacos 分配 worker id。",[24,1620,1621],{"id":1621},"源码",[11,1623,1624,1625],{},"仓库地址：",[232,1626,1629],{"href":1627,"rel":1628},"https:\u002F\u002Fgitee.com\u002FJiaXiaohei\u002Fsnowflake-nacos",[236],"gitee.com\u002FJiaXiaohei\u002Fsnowflake-nacos",[24,1631,1632],{"id":1632},"原理",[11,1634,1635,1636],{},"核心类：",[132,1637,1638],{},"SnowflakeIdGenerator.class",[11,1640,1641,1642,1645],{},"基本原理：基于 Nacos 的监听服务 ",[132,1643,1644],{},"namingService.subscribe","，监听服务下的实例列表变化。\n注册一个服务到 Nacos，如果服务列表发生变化，获取服务所有实例的 Ip 地址和端口，用本机 Ip 地址和端口判断本机在实例列表的 index。",[306,1647,1650],{"className":1648,"code":1649,"language":1026,"meta":269,"style":269},"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",[132,1651,1652,1657,1662,1667,1672,1677,1682,1687,1692,1697,1702,1707,1712,1717,1722,1727,1732,1737,1742,1746,1751,1756,1762,1768,1774,1779,1785,1790,1796,1802,1807,1812,1818,1823,1829,1834,1840,1845,1851,1857,1863,1869,1874,1880,1886,1892,1898,1904,1910,1916,1921,1926,1931,1937,1942,1947,1952,1958,1964,1969,1974,1979,1985,1990,1996,2001,2007,2013,2019,2025,2031,2037,2043,2049,2055,2061,2067,2072,2078,2084,2090,2096,2102,2108,2113,2118,2123,2129,2134,2140,2145,2150,2156,2162,2168,2174,2180,2186,2191,2196,2201,2207,2212,2218,2224,2229,2234,2240,2246,2252,2258,2264,2270,2276,2281,2286],{"__ignoreMap":269},[314,1653,1654],{"class":316,"line":317},[314,1655,1656],{},"import com.alibaba.cloud.nacos.NacosDiscoveryProperties;\n",[314,1658,1659],{"class":316,"line":270},[314,1660,1661],{},"import com.alibaba.cloud.nacos.NacosServiceManager;\n",[314,1663,1664],{"class":316,"line":278},[314,1665,1666],{},"import com.alibaba.nacos.api.exception.NacosException;\n",[314,1668,1669],{"class":316,"line":513},[314,1670,1671],{},"import com.alibaba.nacos.api.naming.NamingService;\n",[314,1673,1674],{"class":316,"line":535},[314,1675,1676],{},"import com.alibaba.nacos.api.naming.listener.AbstractEventListener;\n",[314,1678,1679],{"class":316,"line":543},[314,1680,1681],{},"import com.alibaba.nacos.api.naming.listener.Event;\n",[314,1683,1684],{"class":316,"line":554},[314,1685,1686],{},"import com.alibaba.nacos.api.naming.listener.NamingEvent;\n",[314,1688,1689],{"class":316,"line":560},[314,1690,1691],{},"import com.alibaba.nacos.api.naming.pojo.Instance;\n",[314,1693,1694],{"class":316,"line":574},[314,1695,1696],{},"import org.slf4j.Logger;\n",[314,1698,1699],{"class":316,"line":588},[314,1700,1701],{},"import org.slf4j.LoggerFactory;\n",[314,1703,1704],{"class":316,"line":602},[314,1705,1706],{},"import org.springframework.beans.factory.annotation.Autowired;\n",[314,1708,1709],{"class":316,"line":1404},[314,1710,1711],{},"import org.springframework.stereotype.Component;\n",[314,1713,1714],{"class":316,"line":1477},[314,1715,1716],{"emptyLinePlaceholder":287},"\n",[314,1718,1719],{"class":316,"line":1483},[314,1720,1721],{},"import javax.annotation.PostConstruct;\n",[314,1723,1724],{"class":316,"line":1489},[314,1725,1726],{},"import java.text.DecimalFormat;\n",[314,1728,1729],{"class":316,"line":1495},[314,1730,1731],{},"import java.util.Comparator;\n",[314,1733,1734],{"class":316,"line":1501},[314,1735,1736],{},"import java.util.List;\n",[314,1738,1739],{"class":316,"line":1507},[314,1740,1741],{},"import java.util.stream.Collectors;\n",[314,1743,1744],{"class":316,"line":1512},[314,1745,1716],{"emptyLinePlaceholder":287},[314,1747,1748],{"class":316,"line":1518},[314,1749,1750],{},"\u002F**\n",[314,1752,1753],{"class":316,"line":1523},[314,1754,1755],{}," * SnowflakeId + Nacos\n",[314,1757,1759],{"class":316,"line":1758},22,[314,1760,1761],{}," *\u002F\n",[314,1763,1765],{"class":316,"line":1764},23,[314,1766,1767],{},"@Component\n",[314,1769,1771],{"class":316,"line":1770},24,[314,1772,1773],{},"public class SnowflakeIdGenerator {\n",[314,1775,1777],{"class":316,"line":1776},25,[314,1778,1716],{"emptyLinePlaceholder":287},[314,1780,1782],{"class":316,"line":1781},26,[314,1783,1784],{},"    protected final Logger logger = LoggerFactory.getLogger(this.getClass());\n",[314,1786,1788],{"class":316,"line":1787},27,[314,1789,1716],{"emptyLinePlaceholder":287},[314,1791,1793],{"class":316,"line":1792},28,[314,1794,1795],{},"    @Autowired\n",[314,1797,1799],{"class":316,"line":1798},29,[314,1800,1801],{},"    private NacosServiceManager nacosServiceManager;\n",[314,1803,1805],{"class":316,"line":1804},30,[314,1806,1716],{"emptyLinePlaceholder":287},[314,1808,1810],{"class":316,"line":1809},31,[314,1811,1795],{},[314,1813,1815],{"class":316,"line":1814},32,[314,1816,1817],{},"    private NacosDiscoveryProperties nacosDiscoveryProperties;\n",[314,1819,1821],{"class":316,"line":1820},33,[314,1822,1716],{"emptyLinePlaceholder":287},[314,1824,1826],{"class":316,"line":1825},34,[314,1827,1828],{},"    private static SnowflakeIdWorker snowflakeIdWorker;\n",[314,1830,1832],{"class":316,"line":1831},35,[314,1833,1716],{"emptyLinePlaceholder":287},[314,1835,1837],{"class":316,"line":1836},36,[314,1838,1839],{},"    private static int nodeId;\n",[314,1841,1843],{"class":316,"line":1842},37,[314,1844,1716],{"emptyLinePlaceholder":287},[314,1846,1848],{"class":316,"line":1847},38,[314,1849,1850],{},"    @PostConstruct\n",[314,1852,1854],{"class":316,"line":1853},39,[314,1855,1856],{},"    public void run() throws Exception {\n",[314,1858,1860],{"class":316,"line":1859},40,[314,1861,1862],{},"        init();\n",[314,1864,1866],{"class":316,"line":1865},41,[314,1867,1868],{},"    }\n",[314,1870,1872],{"class":316,"line":1871},42,[314,1873,1716],{"emptyLinePlaceholder":287},[314,1875,1877],{"class":316,"line":1876},43,[314,1878,1879],{},"    \u002F**\n",[314,1881,1883],{"class":316,"line":1882},44,[314,1884,1885],{},"     * 获取雪花Id\n",[314,1887,1889],{"class":316,"line":1888},45,[314,1890,1891],{},"     *\n",[314,1893,1895],{"class":316,"line":1894},46,[314,1896,1897],{},"     * @return\n",[314,1899,1901],{"class":316,"line":1900},47,[314,1902,1903],{},"     *\u002F\n",[314,1905,1907],{"class":316,"line":1906},48,[314,1908,1909],{},"    public static long nextId() {\n",[314,1911,1913],{"class":316,"line":1912},49,[314,1914,1915],{},"        return snowflakeIdWorker.nextId();\n",[314,1917,1919],{"class":316,"line":1918},50,[314,1920,1868],{},[314,1922,1924],{"class":316,"line":1923},51,[314,1925,1716],{"emptyLinePlaceholder":287},[314,1927,1929],{"class":316,"line":1928},52,[314,1930,1879],{},[314,1932,1934],{"class":316,"line":1933},53,[314,1935,1936],{},"     * 获取当前节点Id\n",[314,1938,1940],{"class":316,"line":1939},54,[314,1941,1891],{},[314,1943,1945],{"class":316,"line":1944},55,[314,1946,1897],{},[314,1948,1950],{"class":316,"line":1949},56,[314,1951,1903],{},[314,1953,1955],{"class":316,"line":1954},57,[314,1956,1957],{},"    public static int nodeId() {\n",[314,1959,1961],{"class":316,"line":1960},58,[314,1962,1963],{},"        return nodeId;\n",[314,1965,1967],{"class":316,"line":1966},59,[314,1968,1868],{},[314,1970,1972],{"class":316,"line":1971},60,[314,1973,1716],{"emptyLinePlaceholder":287},[314,1975,1977],{"class":316,"line":1976},61,[314,1978,1879],{},[314,1980,1982],{"class":316,"line":1981},62,[314,1983,1984],{},"     * 获取当前服务所有节点 + 增加服务监听\n",[314,1986,1988],{"class":316,"line":1987},63,[314,1989,1891],{},[314,1991,1993],{"class":316,"line":1992},64,[314,1994,1995],{},"     * @throws NacosException\n",[314,1997,1999],{"class":316,"line":1998},65,[314,2000,1903],{},[314,2002,2004],{"class":316,"line":2003},66,[314,2005,2006],{},"    private void init() throws NacosException {\n",[314,2008,2010],{"class":316,"line":2009},67,[314,2011,2012],{},"        NamingService namingService = nacosServiceManager.getNamingService(nacosDiscoveryProperties.getNacosProperties());\n",[314,2014,2016],{"class":316,"line":2015},68,[314,2017,2018],{},"        namingService.subscribe(nacosDiscoveryProperties.getService(), new AbstractEventListener() {\n",[314,2020,2022],{"class":316,"line":2021},69,[314,2023,2024],{},"            @Override\n",[314,2026,2028],{"class":316,"line":2027},70,[314,2029,2030],{},"            public void onEvent(Event event) {\n",[314,2032,2034],{"class":316,"line":2033},71,[314,2035,2036],{},"                if (-1 == nacosDiscoveryProperties.getPort()) {\n",[314,2038,2040],{"class":316,"line":2039},72,[314,2041,2042],{},"                    return;\n",[314,2044,2046],{"class":316,"line":2045},73,[314,2047,2048],{},"                }\n",[314,2050,2052],{"class":316,"line":2051},74,[314,2053,2054],{},"                nodeId = calcNodeId(((NamingEvent) event).getInstances());\n",[314,2056,2058],{"class":316,"line":2057},75,[314,2059,2060],{},"                if (nodeId > 1024) {\n",[314,2062,2064],{"class":316,"line":2063},76,[314,2065,2066],{},"                    throw new IllegalArgumentException(\"Worker & Datacenter Id calc results exceed 1024\");\n",[314,2068,2070],{"class":316,"line":2069},77,[314,2071,2048],{},[314,2073,2075],{"class":316,"line":2074},78,[314,2076,2077],{},"                long workerId = nodeId % 31;\n",[314,2079,2081],{"class":316,"line":2080},79,[314,2082,2083],{},"                long datacenterId = (long) Math.floor((float) nodeId \u002F 31);\n",[314,2085,2087],{"class":316,"line":2086},80,[314,2088,2089],{},"                logger.info(\"nodeId:\" + nodeId + \" workerId:\" + workerId + \" datacenterId:\" + datacenterId);\n",[314,2091,2093],{"class":316,"line":2092},81,[314,2094,2095],{},"                snowflakeIdWorker = new SnowflakeIdWorker(workerId, datacenterId);\n",[314,2097,2099],{"class":316,"line":2098},82,[314,2100,2101],{},"            }\n",[314,2103,2105],{"class":316,"line":2104},83,[314,2106,2107],{},"        });\n",[314,2109,2111],{"class":316,"line":2110},84,[314,2112,1868],{},[314,2114,2116],{"class":316,"line":2115},85,[314,2117,1716],{"emptyLinePlaceholder":287},[314,2119,2121],{"class":316,"line":2120},86,[314,2122,1879],{},[314,2124,2126],{"class":316,"line":2125},87,[314,2127,2128],{},"     * 用ip+port计算服务列表的索引\n",[314,2130,2132],{"class":316,"line":2131},88,[314,2133,1891],{},[314,2135,2137],{"class":316,"line":2136},89,[314,2138,2139],{},"     * @param instanceList\n",[314,2141,2143],{"class":316,"line":2142},90,[314,2144,1897],{},[314,2146,2148],{"class":316,"line":2147},91,[314,2149,1903],{},[314,2151,2153],{"class":316,"line":2152},92,[314,2154,2155],{},"    private int calcNodeId(List\u003CInstance> instanceList) {\n",[314,2157,2159],{"class":316,"line":2158},93,[314,2160,2161],{},"        List\u003CLong> ipPosrList = instanceList.stream()\n",[314,2163,2165],{"class":316,"line":2164},94,[314,2166,2167],{},"                .map(x -> dealIpPort(x.getIp(), x.getPort()))\n",[314,2169,2171],{"class":316,"line":2170},95,[314,2172,2173],{},"                .sorted(Comparator.naturalOrder())\n",[314,2175,2177],{"class":316,"line":2176},96,[314,2178,2179],{},"                .collect(Collectors.toList());\n",[314,2181,2183],{"class":316,"line":2182},97,[314,2184,2185],{},"        return ipPosrList.indexOf(dealIpPort(nacosDiscoveryProperties.getIp(), nacosDiscoveryProperties.getPort()));\n",[314,2187,2189],{"class":316,"line":2188},98,[314,2190,1868],{},[314,2192,2194],{"class":316,"line":2193},99,[314,2195,1716],{"emptyLinePlaceholder":287},[314,2197,2199],{"class":316,"line":2198},100,[314,2200,1879],{},[314,2202,2204],{"class":316,"line":2203},101,[314,2205,2206],{},"     * ip补0 + 端口号\n",[314,2208,2210],{"class":316,"line":2209},102,[314,2211,1891],{},[314,2213,2215],{"class":316,"line":2214},103,[314,2216,2217],{},"     * @param ip\n",[314,2219,2221],{"class":316,"line":2220},104,[314,2222,2223],{},"     * @param port\n",[314,2225,2227],{"class":316,"line":2226},105,[314,2228,1897],{},[314,2230,2232],{"class":316,"line":2231},106,[314,2233,1903],{},[314,2235,2237],{"class":316,"line":2236},107,[314,2238,2239],{},"    private static Long dealIpPort(String ip, int port) {\n",[314,2241,2243],{"class":316,"line":2242},108,[314,2244,2245],{},"        String[] ips = ip.split(\"\\\\.\");\n",[314,2247,2249],{"class":316,"line":2248},109,[314,2250,2251],{},"        StringBuilder sbr = new StringBuilder();\n",[314,2253,2255],{"class":316,"line":2254},110,[314,2256,2257],{},"        for (int i = 0; i \u003C ips.length; i++) {\n",[314,2259,2261],{"class":316,"line":2260},111,[314,2262,2263],{},"            sbr.append(new DecimalFormat(\"000\").format(Integer.parseInt(ips[i])));\n",[314,2265,2267],{"class":316,"line":2266},112,[314,2268,2269],{},"        }\n",[314,2271,2273],{"class":316,"line":2272},113,[314,2274,2275],{},"        return Long.parseLong(sbr.toString() + port);\n",[314,2277,2279],{"class":316,"line":2278},114,[314,2280,1868],{},[314,2282,2284],{"class":316,"line":2283},115,[314,2285,1716],{"emptyLinePlaceholder":287},[314,2287,2289],{"class":316,"line":2288},116,[314,2290,1191],{},[24,2292,2293],{"id":2293},"参考",[11,2295,2296,2297,2300,2301],{},"雪花生成类 ",[132,2298,2299],{},"SnowflakeIdWorker.class"," 参考：\n",[232,2302,2305],{"href":2303,"rel":2304},"https:\u002F\u002Fblog.csdn.net\u002Flq18050010830\u002Farticle\u002Fdetails\u002F89845790",[236],"blog.csdn.net\u002Flq18050010830\u002Farticle\u002Fdetails\u002F89845790",[673,2307,1536],{},{"title":269,"searchDepth":270,"depth":270,"links":2309},[2310,2311,2312,2313],{"id":1615,"depth":270,"text":1615},{"id":1621,"depth":270,"text":1621},{"id":1632,"depth":270,"text":1632},{"id":2293,"depth":270,"text":2293},"2021-07-27","借 Nacos 的服务实例列表动态算出 workerId 和 datacenterId，不用自己维护 zookeeper 或数据库。",{},"\u002Fposts\u002Fnacos-snowflake-worker-id",{"title":1610,"description":2315},"posts\u002Fnacos-snowflake-worker-id",[2321,2322,2323,1321],"Nacos","Snowflake","分布式","1n0hBraNNaP-3M4VTWnepV6xrtPntl_nyzhKqdkPPyc",{"id":2326,"title":2327,"body":2328,"date":2423,"description":3632,"extension":285,"meta":3633,"navigation":287,"path":3634,"seo":3635,"stem":3636,"tags":3637,"__hash__":3639},"posts\u002Fposts\u002Fgitlab-ce-upgrade-11-to-13.md","记一次 GitLab-CE 跨版本从 11 升级到 13 踩的坑",{"type":8,"value":2329,"toc":3626},[2330,2333,2339,2342,2346,2355,2361,2363,2367,2370,2535,2538,2630,2632,2636,2639,2986,2989,3115,3118,3406,3409,3605,3608,3623],[154,2331,2332],{"id":2332},"环境",[306,2334,2337],{"className":2335,"code":2336,"language":1061},[1059],"OS:CentOS 8\nHostname:HyperV-GitLab\n",[132,2338,2336],{"__ignoreMap":269},[2340,2341],"hr",{},[154,2343,2345],{"id":2344},"_1不可跨大版本升级","1.不可跨大版本升级",[11,2347,2348,2349,2354],{},"必须先升级到当前大版本的最新版 在升级到下一个大版本\n参考",[232,2350,2353],{"href":2351,"rel":2352},"https:\u002F\u002Fdocs.gitlab.com\u002Fee\u002Fpolicy\u002Fmaintenance.html#upgrade-recommendations",[236],"官方网站","对于版本升级的说明",[11,2356,2357],{},[139,2358],{"alt":2359,"src":2360},"GitLab 版本升级路径","\u002Fimages\u002Fgitlab-ce-upgrade\u002Fupgrade-path.png",[2340,2362],{},[154,2364,2366],{"id":2365},"_2pg_dump-aborting-because-of-server-version-mismatch","2.pg_dump: aborting because of server version mismatch",[11,2368,2369],{},"因为使用了外部数据源（PG），而且是 12 的高版本，GitLab 自带 pg_dump 版本只到 10 或者 11。在升级的备份部分，就备份失败，报错如下：",[306,2371,2373],{"className":308,"code":2372,"language":310,"meta":269,"style":269},"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",[132,2374,2375,2419,2444,2483,2505,2516,2524],{"__ignoreMap":269},[314,2376,2377,2380,2383,2386,2389,2392,2395,2398,2401,2404,2407,2410,2413,2416],{"class":316,"line":317},[314,2378,2379],{"class":320},"gitlab",[314,2381,2382],{"class":324}," preinstall:",[314,2384,2385],{"class":324}," Automatically",[314,2387,2388],{"class":324}," backing",[314,2390,2391],{"class":324}," up",[314,2393,2394],{"class":324}," only",[314,2396,2397],{"class":324}," the",[314,2399,2400],{"class":324}," GitLab",[314,2402,2403],{"class":324}," SQL",[314,2405,2406],{"class":324}," database",[314,2408,2409],{"class":875}," (excluding ",[314,2411,2412],{"class":324},"everything",[314,2414,2415],{"class":324}," else!",[314,2417,2418],{"class":875},")\n",[314,2420,2421,2424,2427,2430,2433,2436,2438,2441],{"class":316,"line":270},[314,2422,2423],{"class":320},"2020-10-01",[314,2425,2426],{"class":324}," 21:47:39",[314,2428,2429],{"class":324}," +0800",[314,2431,2432],{"class":324}," --",[314,2434,2435],{"class":324}," Dumping",[314,2437,2406],{"class":324},[314,2439,2440],{"class":324}," ...",[314,2442,2443],{"class":875}," \n",[314,2445,2446,2449,2452,2454,2457,2459,2462,2465,2468,2472,2475,2478,2480],{"class":316,"line":278},[314,2447,2448],{"class":320},"Dumping",[314,2450,2451],{"class":324}," PostgreSQL",[314,2453,2406],{"class":324},[314,2455,2456],{"class":324}," db_gitlab",[314,2458,2440],{"class":324},[314,2460,2461],{"class":324}," pg_dump:",[314,2463,2464],{"class":324}," server",[314,2466,2467],{"class":324}," version:",[314,2469,2471],{"class":2470},"sbssI"," 12.4",[314,2473,2474],{"class":525},";",[314,2476,2477],{"class":320}," pg_dump",[314,2479,2467],{"class":324},[314,2481,2482],{"class":2470}," 11.7\n",[314,2484,2485,2488,2491,2494,2497,2499,2502],{"class":316,"line":513},[314,2486,2487],{"class":320},"pg_dump:",[314,2489,2490],{"class":324}," aborting",[314,2492,2493],{"class":324}," because",[314,2495,2496],{"class":324}," of",[314,2498,2464],{"class":324},[314,2500,2501],{"class":324}," version",[314,2503,2504],{"class":324}," mismatch\n",[314,2506,2507,2510,2513],{"class":316,"line":535},[314,2508,2509],{"class":525},"[",[314,2511,2512],{"class":875},"FAILED",[314,2514,2515],{"class":525},"]\n",[314,2517,2518,2521],{"class":316,"line":543},[314,2519,2520],{"class":320},"rake",[314,2522,2523],{"class":324}," aborted!\n",[314,2525,2526,2529,2532],{"class":316,"line":554},[314,2527,2528],{"class":320},"Backup::Error:",[314,2530,2531],{"class":324}," Backup",[314,2533,2534],{"class":324}," failed\n",[11,2536,2537],{},"解决方法：",[306,2539,2541],{"className":308,"code":2540,"language":310,"meta":269,"style":269},"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",[132,2542,2543,2548,2562,2577,2588,2592,2597,2606,2616],{"__ignoreMap":269},[314,2544,2545],{"class":316,"line":317},[314,2546,2547],{"class":320},"1.安装postgresql12的客户端\n",[314,2549,2550,2553,2556,2559],{"class":316,"line":270},[314,2551,2552],{"class":320},"dnf",[314,2554,2555],{"class":324}," install",[314,2557,2558],{"class":324}," -y",[314,2560,2561],{"class":324}," https:\u002F\u002Fdownload.postgresql.org\u002Fpub\u002Frepos\u002Fyum\u002Freporpms\u002FEL-8-x86_64\u002Fpgdg-redhat-repo-latest.noarch.rpm\n",[314,2563,2564,2566,2569,2572,2574],{"class":316,"line":278},[314,2565,2552],{"class":320},[314,2567,2568],{"class":324}," -qy",[314,2570,2571],{"class":324}," module",[314,2573,394],{"class":324},[314,2575,2576],{"class":324}," postgresql\n",[314,2578,2579,2581,2583,2585],{"class":316,"line":513},[314,2580,2552],{"class":320},[314,2582,2555],{"class":324},[314,2584,2558],{"class":324},[314,2586,2587],{"class":324}," postgresql12\n",[314,2589,2590],{"class":316,"line":535},[314,2591,1716],{"emptyLinePlaceholder":287},[314,2593,2594],{"class":316,"line":543},[314,2595,2596],{"class":320},"2.重新建立pg_dump的软连接\n",[314,2598,2599,2603],{"class":316,"line":554},[314,2600,2602],{"class":2601},"s2Zo4","cd",[314,2604,2605],{"class":324}," \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\n",[314,2607,2608,2611,2613],{"class":316,"line":560},[314,2609,2610],{"class":320},"mv",[314,2612,2477],{"class":324},[314,2614,2615],{"class":324}," pg_dump.bak\n",[314,2617,2618,2621,2624,2627],{"class":316,"line":574},[314,2619,2620],{"class":320},"ln",[314,2622,2623],{"class":324}," -s",[314,2625,2626],{"class":324}," \u002Fusr\u002Fbin\u002Fpg_dump",[314,2628,2629],{"class":324}," \u002Fopt\u002Fgitlab\u002Fembedded\u002Fbin\u002Fpg_dump\n",[2340,2631],{},[154,2633,2635],{"id":2634},"_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",[11,2637,2638],{},"GitLab 一开始就用 Yum\u002Fdnf 安装，后面升级自然也一直用 Yum 命令升级；只到从 13.1.4 升级到 13.1.11 版本时，一直提示",[306,2640,2642],{"className":308,"code":2641,"language":310,"meta":269,"style":269},"[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",[132,2643,2644,2657,2674,2679,2684,2701,2705,2710,2730,2734,2739,2743,2754,2758,2765,2773,2778,2804,2809,2830,2835,2840,2845,2850,2855,2868,2881,2889,2893,2918,2932,2946,2950,2955,2966,2970,2975],{"__ignoreMap":269},[314,2645,2646,2648,2651,2654],{"class":316,"line":317},[314,2647,2509],{"class":525},[314,2649,2650],{"class":875},"root@HyperV-GitLab opt",[314,2652,2653],{"class":525},"]",[314,2655,2656],{"class":875},"# yum update gitlab-ce-13.1.11\n",[314,2658,2659,2662,2665,2668,2671],{"class":316,"line":270},[314,2660,2661],{"class":320},"上次元数据过期检查：6:53:15",[314,2663,2664],{"class":324}," 前，执行于",[314,2666,2667],{"class":324}," 2020年10月01日",[314,2669,2670],{"class":324}," 星期四",[314,2672,2673],{"class":324}," 15时40分48秒。\n",[314,2675,2676],{"class":316,"line":278},[314,2677,2678],{"class":320},"依赖关系解决。\n",[314,2680,2681],{"class":316,"line":513},[314,2682,2683],{"class":324},"==================================================================================================================================\n",[314,2685,2686,2689,2692,2695,2698],{"class":316,"line":535},[314,2687,2688],{"class":320}," 软件包",[314,2690,2691],{"class":324},"                       架构",[314,2693,2694],{"class":324},"                      版本",[314,2696,2697],{"class":324},"                                   仓库",[314,2699,2700],{"class":324},"                          大小\n",[314,2702,2703],{"class":316,"line":543},[314,2704,2683],{"class":324},[314,2706,2707],{"class":316,"line":554},[314,2708,2709],{"class":320},"升级:\n",[314,2711,2712,2715,2718,2721,2724,2727],{"class":316,"line":560},[314,2713,2714],{"class":320}," gitlab-ce",[314,2716,2717],{"class":324},"                    x86_64",[314,2719,2720],{"class":324},"                    13.1.11-ce.0.el8",[314,2722,2723],{"class":324},"                       gitlab-ce",[314,2725,2726],{"class":2470},"                    716",[314,2728,2729],{"class":324}," M\n",[314,2731,2732],{"class":316,"line":574},[314,2733,1716],{"emptyLinePlaceholder":287},[314,2735,2736],{"class":316,"line":588},[314,2737,2738],{"class":320},"事务概要\n",[314,2740,2741],{"class":316,"line":602},[314,2742,2683],{"class":324},[314,2744,2745,2748,2751],{"class":316,"line":1404},[314,2746,2747],{"class":320},"升级",[314,2749,2750],{"class":2470},"  1",[314,2752,2753],{"class":324}," 软件包\n",[314,2755,2756],{"class":316,"line":1477},[314,2757,1716],{"emptyLinePlaceholder":287},[314,2759,2760,2763],{"class":316,"line":1483},[314,2761,2762],{"class":320},"总下载：716",[314,2764,2729],{"class":324},[314,2766,2767,2770],{"class":316,"line":1489},[314,2768,2769],{"class":320},"确定吗？[y\u002FN]：",[314,2771,2772],{"class":324}," y\n",[314,2774,2775],{"class":316,"line":1495},[314,2776,2777],{"class":320},"下载软件包：\n",[314,2779,2780,2783,2786,2789,2792,2795,2798,2801],{"class":316,"line":1501},[314,2781,2782],{"class":320},"gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm",[314,2784,2785],{"class":2470},"                                                             3.7",[314,2787,2788],{"class":324}," MB\u002Fs",[314,2790,2791],{"class":525}," |",[314,2793,2794],{"class":320}," 716",[314,2796,2797],{"class":324}," MB",[314,2799,2800],{"class":324},"     03:13",[314,2802,2803],{"class":875},"    \n",[314,2805,2806],{"class":316,"line":1507},[314,2807,2808],{"class":320},"----------------------------------------------------------------------------------------------------------------------------------\n",[314,2810,2811,2814,2817,2819,2821,2823,2825,2827],{"class":316,"line":1512},[314,2812,2813],{"class":320},"总计",[314,2815,2816],{"class":2470},"                                                                                              3.7",[314,2818,2788],{"class":324},[314,2820,2791],{"class":525},[314,2822,2794],{"class":320},[314,2824,2797],{"class":324},[314,2826,2800],{"class":324},[314,2828,2829],{"class":875},"     \n",[314,2831,2832],{"class":316,"line":1518},[314,2833,2834],{"class":320},"运行事务检查\n",[314,2836,2837],{"class":316,"line":1523},[314,2838,2839],{"class":320},"事务检查成功。\n",[314,2841,2842],{"class":316,"line":1758},[314,2843,2844],{"class":320},"运行事务测试\n",[314,2846,2847],{"class":316,"line":1764},[314,2848,2849],{"class":320},"事务测试成功。\n",[314,2851,2852],{"class":316,"line":1770},[314,2853,2854],{"class":320},"运行事务\n",[314,2856,2857,2860,2863,2866],{"class":316,"line":1776},[314,2858,2859],{"class":320},"  准备中",[314,2861,2862],{"class":324},"  :",[314,2864,2865],{"class":324},"                                                                                                                   1\u002F1",[314,2867,2443],{"class":875},[314,2869,2870,2873,2876,2879],{"class":316,"line":1781},[314,2871,2872],{"class":320},"  运行脚本:",[314,2874,2875],{"class":324}," gitlab-ce-13.1.11-ce.0.el8.x86_64",[314,2877,2878],{"class":324},"                                                                                 1\u002F2",[314,2880,2443],{"class":875},[314,2882,2883,2886],{"class":316,"line":1787},[314,2884,2885],{"class":320},"错误：%prein(gitlab-ce-13.1.11-ce.0.el8.x86_64",[314,2887,2888],{"class":875},") 脚本执行失败，退出状态码为 1\n",[314,2890,2891],{"class":316,"line":1792},[314,2892,1716],{"emptyLinePlaceholder":287},[314,2894,2895,2898,2901,2904,2907,2909,2912,2915],{"class":316,"line":1798},[314,2896,2897],{"class":320},"Error",[314,2899,2900],{"class":324}," in",[314,2902,2903],{"class":324}," PREIN",[314,2905,2906],{"class":324}," scriptlet",[314,2908,2900],{"class":324},[314,2910,2911],{"class":324}," rpm",[314,2913,2914],{"class":324}," package",[314,2916,2917],{"class":324}," gitlab-ce\n",[314,2919,2920,2923,2926,2928,2930],{"class":316,"line":1804},[314,2921,2922],{"class":320},"  验证",[314,2924,2925],{"class":324},"    :",[314,2927,2875],{"class":324},[314,2929,2878],{"class":324},[314,2931,2443],{"class":875},[314,2933,2934,2936,2938,2941,2944],{"class":316,"line":1809},[314,2935,2922],{"class":320},[314,2937,2925],{"class":324},[314,2939,2940],{"class":324}," gitlab-ce-13.1.4-ce.0.el8.x86_64",[314,2942,2943],{"class":324},"                                                                                  2\u002F2",[314,2945,2443],{"class":875},[314,2947,2948],{"class":316,"line":1814},[314,2949,1716],{"emptyLinePlaceholder":287},[314,2951,2952],{"class":316,"line":1820},[314,2953,2954],{"class":320},"失败:\n",[314,2956,2957,2960,2963],{"class":316,"line":1825},[314,2958,2959],{"class":320},"  gitlab-ce-13.1.4-ce.0.el8.x86_64",[314,2961,2962],{"class":324},"                                gitlab-ce-13.1.11-ce.0.el8.x86_64",[314,2964,2965],{"class":875},"                               \n",[314,2967,2968],{"class":316,"line":1831},[314,2969,1716],{"emptyLinePlaceholder":287},[314,2971,2972],{"class":316,"line":1836},[314,2973,2974],{"class":320},"错误：事务失败\n",[314,2976,2977,2979,2981,2983],{"class":316,"line":1842},[314,2978,2509],{"class":525},[314,2980,2650],{"class":875},[314,2982,2653],{"class":525},[314,2984,2985],{"class":875},"#\n",[11,2987,2988],{},"手动下载 rpm 包安装，也有相同的报错信息：",[306,2990,2992],{"className":308,"code":2991,"language":310,"meta":269,"style":269},"[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",[132,2993,2994,3005,3031,3040,3047,3053,3064,3075,3079,3084],{"__ignoreMap":269},[314,2995,2996,2998,3000,3002],{"class":316,"line":317},[314,2997,2509],{"class":525},[314,2999,2650],{"class":875},[314,3001,2653],{"class":525},[314,3003,3004],{"class":875},"# rpm -Uvh gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm \n",[314,3006,3007,3010,3013,3016,3019,3022,3025,3028],{"class":316,"line":270},[314,3008,3009],{"class":320},"警告：gitlab-ce-13.1.11-ce.0.el8.x86_64.rpm:",[314,3011,3012],{"class":324}," 头V4",[314,3014,3015],{"class":324}," RSA\u002FSHA256",[314,3017,3018],{"class":324}," Signature,",[314,3020,3021],{"class":324}," 密钥",[314,3023,3024],{"class":324}," ID",[314,3026,3027],{"class":324}," f27eab47:",[314,3029,3030],{"class":324}," NOKEY\n",[314,3032,3033,3036],{"class":316,"line":278},[314,3034,3035],{"class":320},"Verifying...",[314,3037,3039],{"class":3038},"sHwdD","                          ################################# [100%]\n",[314,3041,3042,3045],{"class":316,"line":513},[314,3043,3044],{"class":320},"准备中...",[314,3046,3039],{"class":3038},[314,3048,3049,3051],{"class":316,"line":535},[314,3050,2885],{"class":320},[314,3052,2888],{"class":875},[314,3054,3055,3058,3061],{"class":316,"line":543},[314,3056,3057],{"class":320},"错误：gitlab-ce-13.1.11-ce.0.el8.x86_64:",[314,3059,3060],{"class":324}," 安裝",[314,3062,3063],{"class":324}," 已失败\n",[314,3065,3066,3069,3072],{"class":316,"line":554},[314,3067,3068],{"class":320},"错误：gitlab-ce-13.1.4-ce.0.el8.x86_64:",[314,3070,3071],{"class":324}," 删除",[314,3073,3074],{"class":324}," 已跳过\n",[314,3076,3077],{"class":316,"line":560},[314,3078,1716],{"emptyLinePlaceholder":287},[314,3080,3081],{"class":316,"line":574},[314,3082,3083],{"class":320},"OR\n",[314,3085,3086,3089,3092,3095,3098,3101,3104,3107,3110,3112],{"class":316,"line":588},[314,3087,3088],{"class":320},"error:",[314,3090,3091],{"class":324}," prein",[314,3093,3094],{"class":525},"(",[314,3096,3097],{"class":320},"gitlab-ce-13.1.11-ce.0.el8.x86_64",[314,3099,3100],{"class":525},")",[314,3102,3103],{"class":324},"scriptlet",[314,3105,3106],{"class":324}," failed,",[314,3108,3109],{"class":324}," exit",[314,3111,360],{"class":324},[314,3113,3114],{"class":2470}," 1\n",[11,3116,3117],{},"用 rpm -Uvvh 查看安装详情，发现错误如下：",[306,3119,3121],{"className":308,"code":3120,"language":310,"meta":269,"style":269},"+ 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",[132,3122,3123,3131,3148,3174,3186,3201,3206,3211,3215,3220,3224,3229,3234,3241,3255,3300,3308,3345,3367,3395],{"__ignoreMap":269},[314,3124,3125,3128],{"class":316,"line":317},[314,3126,3127],{"class":320},"+",[314,3129,3130],{"class":324}," upgrade_check\n",[314,3132,3133,3136,3139,3142,3145],{"class":316,"line":270},[314,3134,3135],{"class":320},"++",[314,3137,3138],{"class":324}," gitlab-ctl",[314,3140,3141],{"class":324}," upgrade-check",[314,3143,3144],{"class":2470}," 13.1.4",[314,3146,3147],{"class":2470}," 13.13.1\n",[314,3149,3150,3153,3156,3159,3162,3165,3168,3171],{"class":316,"line":278},[314,3151,3152],{"class":320},"\u002Fbin\u002Fbash:",[314,3154,3155],{"class":324}," warning:",[314,3157,3158],{"class":324}," setlocale:",[314,3160,3161],{"class":324}," LC_ALL:",[314,3163,3164],{"class":324}," cannot",[314,3166,3167],{"class":324}," change",[314,3169,3170],{"class":324}," locale",[314,3172,3173],{"class":875}," (en_US.UTF-8)\n",[314,3175,3176,3178,3181,3183],{"class":316,"line":513},[314,3177,3127],{"class":320},[314,3179,3180],{"class":324}," ctl_results=",[314,3182,526],{"class":525},[314,3184,3185],{"class":324},"[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",[314,3187,3188,3191,3193,3196,3198],{"class":316,"line":535},[314,3189,3190],{"class":324},"I don",[314,3192,526],{"class":525},[314,3194,3195],{"class":875},"\\'",[314,3197,526],{"class":525},[314,3199,3200],{"class":324},"t know that command.\n",[314,3202,3203],{"class":316,"line":543},[314,3204,3205],{"class":324},"omnibus-ctl: command (subcommand)\n",[314,3207,3208],{"class":316,"line":554},[314,3209,3210],{"class":324},"check-config\n",[314,3212,3213],{"class":316,"line":560},[314,3214,1716],{"emptyLinePlaceholder":287},[314,3216,3217],{"class":316,"line":574},[314,3218,3219],{"class":324},".........\n",[314,3221,3222],{"class":316,"line":588},[314,3223,1716],{"emptyLinePlaceholder":287},[314,3225,3226],{"class":316,"line":602},[314,3227,3228],{"class":324},"Container Registry Commands:\n",[314,3230,3231],{"class":316,"line":1404},[314,3232,3233],{"class":324},"  registry-garbage-collect\n",[314,3235,3236,3239],{"class":316,"line":1477},[314,3237,3238],{"class":324},"    Run Container Registry garbage collection.",[314,3240,532],{"class":525},[314,3242,3243,3245,3248,3250,3253],{"class":316,"line":1483},[314,3244,3127],{"class":320},[314,3246,3247],{"class":324}," found=",[314,3249,526],{"class":525},[314,3251,3252],{"class":324},"[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.",[314,3254,532],{"class":525},[314,3256,3257,3259,3262,3264,3266,3268,3270,3272,3274,3277,3279,3281,3283,3285,3287,3289,3292,3294,3296,3298],{"class":316,"line":1489},[314,3258,3127],{"class":320},[314,3260,3261],{"class":525}," '",[314,3263,2509],{"class":324},[314,3265,526],{"class":525},[314,3267,3261],{"class":525},[314,3269,3252],{"class":324},[314,3271,526],{"class":525},[314,3273,3261],{"class":525},[314,3275,3276],{"class":324},"!=",[314,3278,526],{"class":525},[314,3280,3261],{"class":525},[314,3282,3190],{"class":324},[314,3284,526],{"class":525},[314,3286,3195],{"class":875},[314,3288,526],{"class":525},[314,3290,3291],{"class":324},"t know that command.",[314,3293,526],{"class":525},[314,3295,3261],{"class":525},[314,3297,2653],{"class":324},[314,3299,532],{"class":525},[314,3301,3302,3304,3306],{"class":316,"line":1495},[314,3303,3127],{"class":320},[314,3305,3109],{"class":324},[314,3307,3114],{"class":2470},[314,3309,3310,3313,3316,3318,3320,3322,3324,3327,3329,3332,3334,3337,3340,3342],{"class":316,"line":1501},[314,3311,3312],{"class":320},"D:",[314,3314,3315],{"class":324}," %prein",[314,3317,3094],{"class":525},[314,3319,3097],{"class":320},[314,3321,3100],{"class":525},[314,3323,890],{"class":324},[314,3325,3326],{"class":324}," waitpid",[314,3328,3094],{"class":525},[314,3330,3331],{"class":320},"35960",[314,3333,3100],{"class":525},[314,3335,3336],{"class":324}," rc",[314,3338,3339],{"class":2470}," 35960",[314,3341,360],{"class":324},[314,3343,3344],{"class":2470}," 100\n",[314,3346,3347,3349,3351,3353,3355,3357,3359,3361,3363,3365],{"class":316,"line":1507},[314,3348,3088],{"class":320},[314,3350,3315],{"class":324},[314,3352,3094],{"class":525},[314,3354,3097],{"class":320},[314,3356,3100],{"class":525},[314,3358,2906],{"class":324},[314,3360,3106],{"class":324},[314,3362,3109],{"class":324},[314,3364,360],{"class":324},[314,3366,3114],{"class":2470},[314,3368,3369,3372,3375,3378,3381,3384,3387,3389,3392],{"class":316,"line":1512},[314,3370,3371],{"class":320},"ufdio:",[314,3373,3374],{"class":2470},"       6",[314,3376,3377],{"class":324}," reads,",[314,3379,3380],{"class":2470},"  8219028",[314,3382,3383],{"class":324}," total",[314,3385,3386],{"class":324}," bytes",[314,3388,2900],{"class":324},[314,3390,3391],{"class":2470}," 0.001505",[314,3393,3394],{"class":324}," secs\n",[314,3396,3397,3399,3402,3404],{"class":316,"line":1518},[314,3398,3088],{"class":320},[314,3400,3401],{"class":324}," gitlab-ce-13.1.11-ce.0.el8.x86_64:",[314,3403,2555],{"class":324},[314,3405,2534],{"class":324},[11,3407,3408],{},"可能是因为我安装系统的时候选择了中文，系统里竟然没有英文语言包？！\nlocale -a 如下：",[306,3410,3412],{"className":308,"code":3411,"language":310,"meta":269,"style":269},"[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",[132,3413,3414,3427,3438,3476,3503,3530,3535,3540,3545,3550,3555,3560,3565,3570,3575,3580,3585,3590,3595,3600],{"__ignoreMap":269},[314,3415,3416,3418,3421,3424],{"class":316,"line":317},[314,3417,2509],{"class":525},[314,3419,3420],{"class":875},"root@HyperV-GitLab ",[314,3422,3423],{"class":525},"~]",[314,3425,3426],{"class":875},"# vi \u002Fetc\u002Fenvironment\n",[314,3428,3429,3431,3433,3435],{"class":316,"line":270},[314,3430,2509],{"class":525},[314,3432,3420],{"class":875},[314,3434,3423],{"class":525},[314,3436,3437],{"class":875},"# locale -a\n",[314,3439,3440,3443,3446,3449,3452,3455,3458,3461,3464,3467,3470,3473],{"class":316,"line":278},[314,3441,3442],{"class":320},"locale:",[314,3444,3445],{"class":324}," Cannot",[314,3447,3448],{"class":324}," set",[314,3450,3451],{"class":324}," LC_CTYPE",[314,3453,3454],{"class":324}," to",[314,3456,3457],{"class":324}," default",[314,3459,3460],{"class":324}," locale:",[314,3462,3463],{"class":324}," No",[314,3465,3466],{"class":324}," such",[314,3468,3469],{"class":324}," file",[314,3471,3472],{"class":324}," or",[314,3474,3475],{"class":324}," directory\n",[314,3477,3478,3480,3482,3484,3487,3489,3491,3493,3495,3497,3499,3501],{"class":316,"line":513},[314,3479,3442],{"class":320},[314,3481,3445],{"class":324},[314,3483,3448],{"class":324},[314,3485,3486],{"class":324}," LC_MESSAGES",[314,3488,3454],{"class":324},[314,3490,3457],{"class":324},[314,3492,3460],{"class":324},[314,3494,3463],{"class":324},[314,3496,3466],{"class":324},[314,3498,3469],{"class":324},[314,3500,3472],{"class":324},[314,3502,3475],{"class":324},[314,3504,3505,3507,3509,3511,3514,3516,3518,3520,3522,3524,3526,3528],{"class":316,"line":535},[314,3506,3442],{"class":320},[314,3508,3445],{"class":324},[314,3510,3448],{"class":324},[314,3512,3513],{"class":324}," LC_COLLATE",[314,3515,3454],{"class":324},[314,3517,3457],{"class":324},[314,3519,3460],{"class":324},[314,3521,3463],{"class":324},[314,3523,3466],{"class":324},[314,3525,3469],{"class":324},[314,3527,3472],{"class":324},[314,3529,3475],{"class":324},[314,3531,3532],{"class":316,"line":543},[314,3533,3534],{"class":320},"C\n",[314,3536,3537],{"class":316,"line":554},[314,3538,3539],{"class":320},"C.utf8\n",[314,3541,3542],{"class":316,"line":560},[314,3543,3544],{"class":320},"POSIX\n",[314,3546,3547],{"class":316,"line":574},[314,3548,3549],{"class":320},"zh_CN\n",[314,3551,3552],{"class":316,"line":588},[314,3553,3554],{"class":320},"zh_CN.gb18030\n",[314,3556,3557],{"class":316,"line":602},[314,3558,3559],{"class":320},"zh_CN.gbk\n",[314,3561,3562],{"class":316,"line":1404},[314,3563,3564],{"class":320},"zh_CN.utf8\n",[314,3566,3567],{"class":316,"line":1477},[314,3568,3569],{"class":320},"zh_HK\n",[314,3571,3572],{"class":316,"line":1483},[314,3573,3574],{"class":320},"zh_HK.utf8\n",[314,3576,3577],{"class":316,"line":1489},[314,3578,3579],{"class":320},"zh_SG\n",[314,3581,3582],{"class":316,"line":1495},[314,3583,3584],{"class":320},"zh_SG.gbk\n",[314,3586,3587],{"class":316,"line":1501},[314,3588,3589],{"class":320},"zh_SG.utf8\n",[314,3591,3592],{"class":316,"line":1507},[314,3593,3594],{"class":320},"zh_TW\n",[314,3596,3597],{"class":316,"line":1512},[314,3598,3599],{"class":320},"zh_TW.euctw\n",[314,3601,3602],{"class":316,"line":1518},[314,3603,3604],{"class":320},"zh_TW.utf8\n",[11,3606,3607],{},"解决方法：\n安装英文语言包",[306,3609,3611],{"className":308,"code":3610,"language":310,"meta":269,"style":269},"yum install langpacks-en.noarch\n",[132,3612,3613],{"__ignoreMap":269},[314,3614,3615,3618,3620],{"class":316,"line":317},[314,3616,3617],{"class":320},"yum",[314,3619,2555],{"class":324},[314,3621,3622],{"class":324}," langpacks-en.noarch\n",[673,3624,3625],{},"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":269,"searchDepth":270,"depth":270,"links":3627},[3628,3629,3630,3631],{"id":2332,"depth":278,"text":2332},{"id":2344,"depth":278,"text":2345},{"id":2365,"depth":278,"text":2366},{"id":2634,"depth":278,"text":2635},"从 11 升到 13 的路上踩了三个坑：不能跨大版本、pg_dump 版本不匹配，以及系统没装英文语言包导致 rpm 安装脚本失败。",{},"\u002Fposts\u002Fgitlab-ce-upgrade-11-to-13",{"title":2327,"description":3632},"posts\u002Fgitlab-ce-upgrade-11-to-13",[3638,697,696],"GitLab","nnFc8mJVonUKcYjTZFb618eeRy0IZQpUDEcefyCsPhU",{"id":3641,"title":3642,"body":3643,"date":4912,"description":4913,"extension":285,"meta":4914,"navigation":287,"path":4915,"seo":4916,"stem":4917,"tags":4918,"__hash__":4920},"posts\u002Fposts\u002Fjar2pom-maven-dependency.md","基于 Maven 中心库，通过 Jar 包生成 POM 的 dependency",{"type":8,"value":3644,"toc":4904},[3645,3647,3666,3669,3672,3678,3697,3700,4519,4523,4530,4539,4542,4716,4723,4743,4771,4777,4780,4783,4871,4874,4891,4902],[24,3646,1615],{"id":1615},[11,3648,3649,3650,3655,3656,3661,3662,104],{},"之前写过一篇",[232,3651,3654],{"href":3652,"rel":3653},"https:\u002F\u002Fblog.csdn.net\u002FJustinJia91\u002Farticle\u002Fdetails\u002F79605682",[236],"通过 Jar 包生成 Maven POM.xml 的 dependency","，方便将非 Maven 项目转换为 Maven 项目。\n原项目对 Jar 的搜索基于 Nexus2 的相关接口开发，随着很多仓库从 Nexus2 升级到 Nexus3 或者其他服务，原项目渐渐不可用了。\n新代码将 Nexus2 接口改为对接 ",[232,3657,3660],{"href":3658,"rel":3659},"https:\u002F\u002Fsearch.maven.org\u002F",[236],"Maven 中心库","。站内另留了一份 ",[232,3663,3665],{"href":3664},"\u002Fposts\u002Fjar2pom-nexus2-dependency","Nexus2 版的代码",[24,3667,3668],{"id":3668},"项目结构",[11,3670,3671],{},"整个项目只有 6 个 Java 文件 —— 一个主类，加上五个用来接中心库返回值的实体类：",[306,3673,3676],{"className":3674,"code":3675,"language":1061},[1059],"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",[132,3677,3675],{"__ignoreMap":269},[11,3679,3680,3681,3684,3685,3688,3689,3692,3693,3696],{},"Maven 坐标是 ",[132,3682,3683],{},"cn.jxh.tool:jar2pom:2.0-SNAPSHOT","，依赖只有三个：",[132,3686,3687],{},"httpclient"," 4.5.5 负责发请求，",[132,3690,3691],{},"fastjson"," 1.2.68 负责解 JSON，",[132,3694,3695],{},"dom4j"," 负责拼 XML。README 里记的开发环境是 JDK 1.7 + Maven 3.5 + IDEA 社区版。",[24,3698,3699],{"id":3699},"核心代码",[306,3701,3703],{"className":1648,"code":3702,"language":1026,"meta":269,"style":269},"    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",[132,3704,3705,3710,3715,3720,3725,3729,3734,3738,3743,3748,3753,3758,3763,3767,3771,3776,3780,3785,3789,3793,3797,3801,3806,3810,3815,3819,3823,3827,3831,3835,3840,3844,3849,3853,3857,3862,3867,3871,3876,3881,3886,3890,3895,3900,3904,3909,3913,3917,3921,3925,3930,3934,3938,3942,3946,3951,3955,3959,3964,3969,3974,3979,3984,3989,3993,3998,4003,4008,4013,4018,4023,4028,4032,4037,4042,4046,4051,4056,4061,4066,4071,4076,4080,4085,4090,4094,4099,4104,4108,4113,4118,4122,4127,4132,4136,4140,4144,4148,4152,4157,4161,4166,4170,4174,4179,4184,4189,4194,4199,4204,4208,4213,4217,4221,4225,4230,4234,4240,4245,4250,4256,4262,4268,4274,4279,4285,4291,4296,4301,4307,4313,4319,4325,4331,4336,4341,4347,4352,4357,4362,4368,4373,4378,4384,4389,4394,4400,4406,4412,4417,4423,4429,4435,4441,4446,4452,4458,4464,4470,4475,4481,4487,4492,4497,4502,4508,4514],{"__ignoreMap":269},[314,3706,3707],{"class":316,"line":317},[314,3708,3709],{},"    public static void main(String[] args) {\n",[314,3711,3712],{"class":316,"line":270},[314,3713,3714],{},"        \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n",[314,3716,3717],{"class":316,"line":278},[314,3718,3719],{},"        File libs = new File(\"D:\\\\lib\");\n",[314,3721,3722],{"class":316,"line":513},[314,3723,3724],{},"        for (File jar : libs.listFiles()) {\n",[314,3726,3727],{"class":316,"line":535},[314,3728,1716],{"emptyLinePlaceholder":287},[314,3730,3731],{"class":316,"line":543},[314,3732,3733],{},"            System.out.println(\"\u003C!--  \" + jar.getName() + \" -->\");\n",[314,3735,3736],{"class":316,"line":554},[314,3737,1716],{"emptyLinePlaceholder":287},[314,3739,3740],{"class":316,"line":560},[314,3741,3742],{},"            Docs doc = getPomByChecksum(jar);\n",[314,3744,3745],{"class":316,"line":574},[314,3746,3747],{},"            if (null != doc) {\n",[314,3749,3750],{"class":316,"line":588},[314,3751,3752],{},"                System.out.println(\"\u003C!--  Search by Checksum -->\");\n",[314,3754,3755],{"class":316,"line":602},[314,3756,3757],{},"                System.out.println(assemblePomElement(doc).asXML());\n",[314,3759,3760],{"class":316,"line":1404},[314,3761,3762],{},"                continue;\n",[314,3764,3765],{"class":316,"line":1477},[314,3766,2101],{},[314,3768,3769],{"class":316,"line":1483},[314,3770,1716],{"emptyLinePlaceholder":287},[314,3772,3773],{"class":316,"line":1489},[314,3774,3775],{},"            doc = getPomByManifest(jar);\n",[314,3777,3778],{"class":316,"line":1495},[314,3779,3747],{},[314,3781,3782],{"class":316,"line":1501},[314,3783,3784],{},"                System.out.println(\"\u003C!--  Search by Manifest -->\");\n",[314,3786,3787],{"class":316,"line":1507},[314,3788,3757],{},[314,3790,3791],{"class":316,"line":1512},[314,3792,3762],{},[314,3794,3795],{"class":316,"line":1518},[314,3796,2101],{},[314,3798,3799],{"class":316,"line":1523},[314,3800,1716],{"emptyLinePlaceholder":287},[314,3802,3803],{"class":316,"line":1758},[314,3804,3805],{},"            System.out.println(\"\u003C!--  No data was found -->\");\n",[314,3807,3808],{"class":316,"line":1764},[314,3809,1716],{"emptyLinePlaceholder":287},[314,3811,3812],{"class":316,"line":1770},[314,3813,3814],{},"            System.out.println();\n",[314,3816,3817],{"class":316,"line":1776},[314,3818,2269],{},[314,3820,3821],{"class":316,"line":1781},[314,3822,1716],{"emptyLinePlaceholder":287},[314,3824,3825],{"class":316,"line":1787},[314,3826,1868],{},[314,3828,3829],{"class":316,"line":1792},[314,3830,1716],{"emptyLinePlaceholder":287},[314,3832,3833],{"class":316,"line":1798},[314,3834,1879],{},[314,3836,3837],{"class":316,"line":1804},[314,3838,3839],{},"     * 通过Jar SHA1返回Pom dependency\n",[314,3841,3842],{"class":316,"line":1809},[314,3843,1891],{},[314,3845,3846],{"class":316,"line":1814},[314,3847,3848],{},"     * @param file\n",[314,3850,3851],{"class":316,"line":1820},[314,3852,1897],{},[314,3854,3855],{"class":316,"line":1825},[314,3856,1903],{},[314,3858,3859],{"class":316,"line":1831},[314,3860,3861],{},"    public static Docs getPomByChecksum(File file) {\n",[314,3863,3864],{"class":316,"line":1836},[314,3865,3866],{},"        Docs docs = null;\n",[314,3868,3869],{"class":316,"line":1842},[314,3870,1716],{"emptyLinePlaceholder":287},[314,3872,3873],{"class":316,"line":1847},[314,3874,3875],{},"        String checkSum = getCheckSum(file, \"SHA1\");\n",[314,3877,3878],{"class":316,"line":1853},[314,3879,3880],{},"        String jsonString = doGet(nexusUrl + \"&q=1:\" + checkSum);\n",[314,3882,3883],{"class":316,"line":1859},[314,3884,3885],{},"        SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[314,3887,3888],{"class":316,"line":1865},[314,3889,1716],{"emptyLinePlaceholder":287},[314,3891,3892],{"class":316,"line":1871},[314,3893,3894],{},"        if (solrSearch.getResponseHeader().getStatus() == 0 && solrSearch.getResponse().getDocs().size() > 0) {\n",[314,3896,3897],{"class":316,"line":1876},[314,3898,3899],{},"            docs = solrSearch.getResponse().getDocs().get(0);\n",[314,3901,3902],{"class":316,"line":1882},[314,3903,2269],{},[314,3905,3906],{"class":316,"line":1888},[314,3907,3908],{},"        return docs;\n",[314,3910,3911],{"class":316,"line":1894},[314,3912,1868],{},[314,3914,3915],{"class":316,"line":1900},[314,3916,1716],{"emptyLinePlaceholder":287},[314,3918,3919],{"class":316,"line":1906},[314,3920,1716],{"emptyLinePlaceholder":287},[314,3922,3923],{"class":316,"line":1912},[314,3924,1879],{},[314,3926,3927],{"class":316,"line":1918},[314,3928,3929],{},"     * 通过Jar Manifest返回Pom dependency\n",[314,3931,3932],{"class":316,"line":1923},[314,3933,1891],{},[314,3935,3936],{"class":316,"line":1928},[314,3937,3848],{},[314,3939,3940],{"class":316,"line":1933},[314,3941,1897],{},[314,3943,3944],{"class":316,"line":1939},[314,3945,1903],{},[314,3947,3948],{"class":316,"line":1944},[314,3949,3950],{},"    public static Docs getPomByManifest(File file) {\n",[314,3952,3953],{"class":316,"line":1949},[314,3954,3866],{},[314,3956,3957],{"class":316,"line":1954},[314,3958,1716],{"emptyLinePlaceholder":287},[314,3960,3961],{"class":316,"line":1960},[314,3962,3963],{},"        try {\n",[314,3965,3966],{"class":316,"line":1966},[314,3967,3968],{},"            JarFile jarfile = new JarFile(file);\n",[314,3970,3971],{"class":316,"line":1971},[314,3972,3973],{},"            Manifest mainmanifest = jarfile.getManifest();\n",[314,3975,3976],{"class":316,"line":1976},[314,3977,3978],{},"            jarfile.close();\n",[314,3980,3981],{"class":316,"line":1981},[314,3982,3983],{},"            if (null == mainmanifest) {\n",[314,3985,3986],{"class":316,"line":1987},[314,3987,3988],{},"                return null;\n",[314,3990,3991],{"class":316,"line":1992},[314,3992,2101],{},[314,3994,3995],{"class":316,"line":1998},[314,3996,3997],{},"            String a = null, v = null;\n",[314,3999,4000],{"class":316,"line":2003},[314,4001,4002],{},"            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Extension-Name\"))) {\n",[314,4004,4005],{"class":316,"line":2009},[314,4006,4007],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Extension-Name\"));\n",[314,4009,4010],{"class":316,"line":2015},[314,4011,4012],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Title\"))) {\n",[314,4014,4015],{"class":316,"line":2021},[314,4016,4017],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Title\"));\n",[314,4019,4020],{"class":316,"line":2027},[314,4021,4022],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Title\"))) {\n",[314,4024,4025],{"class":316,"line":2033},[314,4026,4027],{},"                a = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Title\"));\n",[314,4029,4030],{"class":316,"line":2039},[314,4031,2101],{},[314,4033,4034],{"class":316,"line":2045},[314,4035,4036],{},"            if (a != null && a.length() != 0) {\n",[314,4038,4039],{"class":316,"line":2051},[314,4040,4041],{},"                a = a.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n",[314,4043,4044],{"class":316,"line":2057},[314,4045,2101],{},[314,4047,4048],{"class":316,"line":2063},[314,4049,4050],{},"            if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Bundle-Version\"))) {\n",[314,4052,4053],{"class":316,"line":2069},[314,4054,4055],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Bundle-Version\"));\n",[314,4057,4058],{"class":316,"line":2074},[314,4059,4060],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Implementation-Version\"))) {\n",[314,4062,4063],{"class":316,"line":2080},[314,4064,4065],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Implementation-Version\"));\n",[314,4067,4068],{"class":316,"line":2086},[314,4069,4070],{},"            } else if (mainmanifest.getMainAttributes().containsKey(new Attributes.Name(\"Specification-Version\"))) {\n",[314,4072,4073],{"class":316,"line":2092},[314,4074,4075],{},"                v = mainmanifest.getMainAttributes().getValue(new Attributes.Name(\"Specification-Version\"));\n",[314,4077,4078],{"class":316,"line":2098},[314,4079,2101],{},[314,4081,4082],{"class":316,"line":2104},[314,4083,4084],{},"            if (v != null && v.length() != 0) {\n",[314,4086,4087],{"class":316,"line":2110},[314,4088,4089],{},"                v = v.replace(\"\\\"\", \"\").replace(\" \", \"-\");\n",[314,4091,4092],{"class":316,"line":2115},[314,4093,2101],{},[314,4095,4096],{"class":316,"line":2120},[314,4097,4098],{},"            String jsonString = doGet(nexusUrl + \"&q=a:\" + a + \"%20v:\" + v);\n",[314,4100,4101],{"class":316,"line":2125},[314,4102,4103],{},"            SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[314,4105,4106],{"class":316,"line":2131},[314,4107,1716],{"emptyLinePlaceholder":287},[314,4109,4110],{"class":316,"line":2136},[314,4111,4112],{},"            if (solrSearch.getResponseHeader().getStatus() == 0) {\n",[314,4114,4115],{"class":316,"line":2142},[314,4116,4117],{},"                docs = solrSearch.getResponse().getDocs().get(0);\n",[314,4119,4120],{"class":316,"line":2147},[314,4121,2101],{},[314,4123,4124],{"class":316,"line":2152},[314,4125,4126],{},"        } catch (IOException e) {\n",[314,4128,4129],{"class":316,"line":2158},[314,4130,4131],{},"            e.printStackTrace();\n",[314,4133,4134],{"class":316,"line":2164},[314,4135,2269],{},[314,4137,4138],{"class":316,"line":2170},[314,4139,3908],{},[314,4141,4142],{"class":316,"line":2176},[314,4143,1868],{},[314,4145,4146],{"class":316,"line":2182},[314,4147,1716],{"emptyLinePlaceholder":287},[314,4149,4150],{"class":316,"line":2188},[314,4151,1879],{},[314,4153,4154],{"class":316,"line":2193},[314,4155,4156],{},"     * 组装 dependency\n",[314,4158,4159],{"class":316,"line":2198},[314,4160,1891],{},[314,4162,4163],{"class":316,"line":2203},[314,4164,4165],{},"     * @param docs\n",[314,4167,4168],{"class":316,"line":2209},[314,4169,1897],{},[314,4171,4172],{"class":316,"line":2214},[314,4173,1903],{},[314,4175,4176],{"class":316,"line":2220},[314,4177,4178],{},"    public static Element assemblePomElement(Docs docs) {\n",[314,4180,4181],{"class":316,"line":2226},[314,4182,4183],{},"        Element dependency = new DOMElement(\"dependency\");\n",[314,4185,4186],{"class":316,"line":2231},[314,4187,4188],{},"        if (docs != null) {\n",[314,4190,4191],{"class":316,"line":2236},[314,4192,4193],{},"            dependency.addAttribute(\"groupId\", docs.getG());\n",[314,4195,4196],{"class":316,"line":2242},[314,4197,4198],{},"            dependency.addAttribute(\"artifactId\", docs.getA());\n",[314,4200,4201],{"class":316,"line":2248},[314,4202,4203],{},"            dependency.addAttribute(\"version\", docs.getV());\n",[314,4205,4206],{"class":316,"line":2254},[314,4207,2269],{},[314,4209,4210],{"class":316,"line":2260},[314,4211,4212],{},"        return dependency;\n",[314,4214,4215],{"class":316,"line":2266},[314,4216,1868],{},[314,4218,4219],{"class":316,"line":2272},[314,4220,1716],{"emptyLinePlaceholder":287},[314,4222,4223],{"class":316,"line":2278},[314,4224,1879],{},[314,4226,4227],{"class":316,"line":2283},[314,4228,4229],{},"     * 发起Get请求\n",[314,4231,4232],{"class":316,"line":2288},[314,4233,1891],{},[314,4235,4237],{"class":316,"line":4236},117,[314,4238,4239],{},"     * @param url\n",[314,4241,4243],{"class":316,"line":4242},118,[314,4244,1897],{},[314,4246,4248],{"class":316,"line":4247},119,[314,4249,1903],{},[314,4251,4253],{"class":316,"line":4252},120,[314,4254,4255],{},"    public static String doGet(String url) {\n",[314,4257,4259],{"class":316,"line":4258},121,[314,4260,4261],{},"        String srtResult = null;\n",[314,4263,4265],{"class":316,"line":4264},122,[314,4266,4267],{},"        CloseableHttpClient httpCilent = HttpClients.createDefault();\n",[314,4269,4271],{"class":316,"line":4270},123,[314,4272,4273],{},"        HttpGet httpGet = new HttpGet(url);\n",[314,4275,4277],{"class":316,"line":4276},124,[314,4278,3963],{},[314,4280,4282],{"class":316,"line":4281},125,[314,4283,4284],{},"            HttpResponse httpResponse = httpCilent.execute(httpGet);\n",[314,4286,4288],{"class":316,"line":4287},126,[314,4289,4290],{},"            srtResult = EntityUtils.toString(httpResponse.getEntity());\n",[314,4292,4294],{"class":316,"line":4293},127,[314,4295,4126],{},[314,4297,4299],{"class":316,"line":4298},128,[314,4300,4131],{},[314,4302,4304],{"class":316,"line":4303},129,[314,4305,4306],{},"        } finally {\n",[314,4308,4310],{"class":316,"line":4309},130,[314,4311,4312],{},"            try {\n",[314,4314,4316],{"class":316,"line":4315},131,[314,4317,4318],{},"                httpCilent.close();\n",[314,4320,4322],{"class":316,"line":4321},132,[314,4323,4324],{},"            } catch (IOException e) {\n",[314,4326,4328],{"class":316,"line":4327},133,[314,4329,4330],{},"                e.printStackTrace();\n",[314,4332,4334],{"class":316,"line":4333},134,[314,4335,2101],{},[314,4337,4339],{"class":316,"line":4338},135,[314,4340,2269],{},[314,4342,4344],{"class":316,"line":4343},136,[314,4345,4346],{},"        return srtResult;\n",[314,4348,4350],{"class":316,"line":4349},137,[314,4351,1868],{},[314,4353,4355],{"class":316,"line":4354},138,[314,4356,1716],{"emptyLinePlaceholder":287},[314,4358,4360],{"class":316,"line":4359},139,[314,4361,1879],{},[314,4363,4365],{"class":316,"line":4364},140,[314,4366,4367],{},"     * 计算CheckSum\n",[314,4369,4371],{"class":316,"line":4370},141,[314,4372,1891],{},[314,4374,4376],{"class":316,"line":4375},142,[314,4377,3848],{},[314,4379,4381],{"class":316,"line":4380},143,[314,4382,4383],{},"     * @param algorithm SHA1 or MD5\n",[314,4385,4387],{"class":316,"line":4386},144,[314,4388,1897],{},[314,4390,4392],{"class":316,"line":4391},145,[314,4393,1903],{},[314,4395,4397],{"class":316,"line":4396},146,[314,4398,4399],{},"    public static String getCheckSum(File file, String algorithm) {\n",[314,4401,4403],{"class":316,"line":4402},147,[314,4404,4405],{},"        if (!file.isFile()) {\n",[314,4407,4409],{"class":316,"line":4408},148,[314,4410,4411],{},"            return null;\n",[314,4413,4415],{"class":316,"line":4414},149,[314,4416,2269],{},[314,4418,4420],{"class":316,"line":4419},150,[314,4421,4422],{},"        MessageDigest digest = null;\n",[314,4424,4426],{"class":316,"line":4425},151,[314,4427,4428],{},"        FileInputStream in = null;\n",[314,4430,4432],{"class":316,"line":4431},152,[314,4433,4434],{},"        byte buffer[] = new byte[1024];\n",[314,4436,4438],{"class":316,"line":4437},153,[314,4439,4440],{},"        int len;\n",[314,4442,4444],{"class":316,"line":4443},154,[314,4445,3963],{},[314,4447,4449],{"class":316,"line":4448},155,[314,4450,4451],{},"            digest = MessageDigest.getInstance(algorithm);\n",[314,4453,4455],{"class":316,"line":4454},156,[314,4456,4457],{},"            in = new FileInputStream(file);\n",[314,4459,4461],{"class":316,"line":4460},157,[314,4462,4463],{},"            while ((len = in.read(buffer, 0, 1024)) != -1) {\n",[314,4465,4467],{"class":316,"line":4466},158,[314,4468,4469],{},"                digest.update(buffer, 0, len);\n",[314,4471,4473],{"class":316,"line":4472},159,[314,4474,2101],{},[314,4476,4478],{"class":316,"line":4477},160,[314,4479,4480],{},"            in.close();\n",[314,4482,4484],{"class":316,"line":4483},161,[314,4485,4486],{},"        } catch (Exception e) {\n",[314,4488,4490],{"class":316,"line":4489},162,[314,4491,4131],{},[314,4493,4495],{"class":316,"line":4494},163,[314,4496,4411],{},[314,4498,4500],{"class":316,"line":4499},164,[314,4501,2269],{},[314,4503,4505],{"class":316,"line":4504},165,[314,4506,4507],{},"        BigInteger bigInt = new BigInteger(1, digest.digest());\n",[314,4509,4511],{"class":316,"line":4510},166,[314,4512,4513],{},"        return bigInt.toString(16);\n",[314,4515,4517],{"class":316,"line":4516},167,[314,4518,1868],{},[24,4520,4522],{"id":4521},"solr-的响应是怎么变成对象的","Solr 的响应是怎么变成对象的",[11,4524,4525,4526,4529],{},"中心库这套接口底下是 Solr，回给你的是一坨嵌套 JSON。代码没有一层层 ",[132,4527,4528],{},"getJSONObject()"," 去抠字段，而是让 fastjson 直接把整段响应收进对象：",[306,4531,4533],{"className":1648,"code":4532,"language":1026,"meta":269,"style":269},"SolrSearch solrSearch = JSONObject.parseObject(jsonString, SolrSearch.class);\n",[132,4534,4535],{"__ignoreMap":269},[314,4536,4537],{"class":316,"line":317},[314,4538,4532],{},[11,4540,4541],{},"映射规则就是「字段名对上即可」，所以五个实体类都很薄：",[4543,4544,4545,4564],"table",{},[4546,4547,4548],"thead",{},[4549,4550,4551,4555,4558,4561],"tr",{},[4552,4553,4554],"th",{},"类",[4552,4556,4557],{},"对应节点",[4552,4559,4560],{},"字段",[4552,4562,4563],{},"实际用到",[4565,4566,4567,4593,4618,4644,4697],"tbody",{},[4549,4568,4569,4575,4578,4590],{},[4570,4571,4572],"td",{},[132,4573,4574],{},"SolrSearch",[4570,4576,4577],{},"根节点",[4570,4579,4580,4583,4584,4583,4587],{},[132,4581,4582],{},"responseHeader"," \u002F ",[132,4585,4586],{},"response",[132,4588,4589],{},"spellcheck",[4570,4591,4592],{},"三个容器",[4549,4594,4595,4600,4604,4612],{},[4570,4596,4597],{},[132,4598,4599],{},"ResponseHeader",[4570,4601,4602],{},[132,4603,4582],{},[4570,4605,4606,4583,4609],{},[132,4607,4608],{},"status",[132,4610,4611],{},"QTime",[4570,4613,4614,4617],{},[132,4615,4616],{},"status == 0"," 即查询成功",[4549,4619,4620,4625,4629,4640],{},[4570,4621,4622],{},[132,4623,4624],{},"Response",[4570,4626,4627],{},[132,4628,4586],{},[4570,4630,4631,4583,4634,4583,4637],{},[132,4632,4633],{},"numFound",[132,4635,4636],{},"start",[132,4638,4639],{},"docs",[4570,4641,4642],{},[132,4643,4639],{},[4549,4645,4646,4651,4657,4689],{},[4570,4647,4648],{},[132,4649,4650],{},"Docs",[4570,4652,4653,4656],{},[132,4654,4655],{},"docs[]"," 的每一项",[4570,4658,4659,4583,4662,4583,4665,4583,4667,4583,4670,4583,4672,4583,4675,4583,4678,4583,4681,4583,4683,4583,4686],{},[132,4660,4661],{},"id",[132,4663,4664],{},"g",[132,4666,232],{},[132,4668,4669],{},"v",[132,4671,11],{},[132,4673,4674],{},"latestVersion",[132,4676,4677],{},"versionCount",[132,4679,4680],{},"timestamp",[132,4682,1061],{},[132,4684,4685],{},"ec",[132,4687,4688],{},"repositoryId",[4570,4690,4691,4583,4693,4583,4695],{},[132,4692,4664],{},[132,4694,232],{},[132,4696,4669],{},[4549,4698,4699,4704,4708,4713],{},[4570,4700,4701],{},[132,4702,4703],{},"Spellcheck",[4570,4705,4706],{},[132,4707,4589],{},[4570,4709,4710],{},[132,4711,4712],{},"suggestions",[4570,4714,4715],{},"没用上",[11,4717,4718,4719,4722],{},"能落进 ",[132,4720,4721],{},"dependency"," 的只有三个字段，正好是 Solr 那份命名里的单字母缩写：",[306,4724,4726],{"className":1648,"code":4725,"language":1026,"meta":269,"style":269},"dependency.addAttribute(\"groupId\", docs.getG());\ndependency.addAttribute(\"artifactId\", docs.getA());\ndependency.addAttribute(\"version\", docs.getV());\n",[132,4727,4728,4733,4738],{"__ignoreMap":269},[314,4729,4730],{"class":316,"line":317},[314,4731,4732],{},"dependency.addAttribute(\"groupId\", docs.getG());\n",[314,4734,4735],{"class":316,"line":270},[314,4736,4737],{},"dependency.addAttribute(\"artifactId\", docs.getA());\n",[314,4739,4740],{"class":316,"line":278},[314,4741,4742],{},"dependency.addAttribute(\"version\", docs.getV());\n",[11,4744,4745,4583,4747,4583,4749,4751,4752,4754,4755,4757,4758,4760,4761,4763,4764,4766,4767,4770],{},[132,4746,4664],{},[132,4748,232],{},[132,4750,4669],{}," 之外的那些 —— ",[132,4753,4674],{},"（最新版本）、",[132,4756,11],{},"（打包类型）、",[132,4759,4685],{},"（该版本下有哪些文件）、",[132,4762,4677],{},"（版本总数）、",[132,4765,4688],{},"（命中哪个仓库）、",[132,4768,4769],{},"Spellcheck.suggestions","（拼写建议）—— 都解析了但没用。类的骨架留在那里，将来想加「取最新版」或者「提示拼写」，字段是现成的。",[11,4772,4773,4774,104],{},"用实体类而不是手写 JSON 路径，好处很直白：解析一行就完成，后面取值都是 getter，字段名写错了编译器直接报，而不是运行时静默接到一个 ",[132,4775,4776],{},"null",[24,4778,4779],{"id":4779},"它什么时候查不出结果",[11,4781,4782],{},"这个工具解决的是「一批本地 jar，不知道 Maven 坐标」。但它依赖两个前提：jar 公开发布过，且 Manifest 没被改过。下面这几种情况它就交不出来，用之前心里有个数：",[73,4784,4785,4795,4805,4836,4850],{},[38,4786,4787,4790,4791,4794],{},[41,4788,4789],{},"jar 压根不在 Maven 中心库。"," 中心库只收公开发布过的构件。国内厂商私服的包、公司内部工具包，以及因为授权原因不能上中心库的（典型是 Oracle 的 JDBC 驱动），SHA1 查不到，Manifest 也拼不出可用坐标，最后只打印一行 ",[132,4792,4793],{},"No data was found","，得自己手写。",[38,4796,4797,4800,4801,4804],{},[41,4798,4799],{},"只查中心库一个源。"," ",[132,4802,4803],{},"nexusUrl"," 是写死的中心库地址，查不了公司私服（Nexus3、Artifactory）。要换成自家仓库，改这个常量和对应的查询参数即可 —— 2018 那版就是从 Nexus2 这么换过来的，前提是私服也提供可搜索接口。",[38,4806,4807,4810,4811,4814,4815,4814,4818,4821,4822,4814,4825,4814,4828,4831,4832,4835],{},[41,4808,4809],{},"Manifest 里的名字不等于 Maven 坐标。"," 回退这条路，artifactId 是拿 ",[132,4812,4813],{},"Extension-Name"," → ",[132,4816,4817],{},"Implementation-Title",[132,4819,4820],{},"Specification-Title"," 依次取的，version 取 ",[132,4823,4824],{},"Bundle-Version",[132,4826,4827],{},"Implementation-Version",[132,4829,4830],{},"Specification-Version","。很多 jar 这几个字段是空的，或者写的是「XXX SDK」这种给人看的名字，搜出来的结果就不保证对；被改过包名、重新打过的 jar，SHA1 也会落空，最后都只能走到这条「猜」的路上。所以输出里标着 ",[132,4833,4834],{},"Search by Manifest"," 的那几条，建议开 Maven 仓库页面核一眼。",[38,4837,4838,4841,4842,4845,4846,4849],{},[41,4839,4840],{},"命中多条时只取第一条。"," 无论走哪条路，最后都是 ",[132,4843,4844],{},"getDocs().get(0)","，没有按版本排序再挑这类逻辑 —— 查询串里本来就带了 ",[132,4847,4848],{},"rows=1","，只打算要一条。",[38,4851,4852,4800,4855,4858,4859,4862,4863,4866,4867,4870],{},[41,4853,4854],{},"用法上的硬编码。",[132,4856,4857],{},"main()"," 里待处理目录写死成 ",[132,4860,4861],{},"D:\\lib","，",[132,4864,4865],{},"libs.listFiles()"," 只扫一层、也不筛后缀，换成别的路径、或者 ",[132,4868,4869],{},"lib"," 下面还有子目录，都得先改代码；结果是打在标准输出里的，得自己从控制台复制出来。",[24,4872,4873],{"id":4873},"下载地址",[35,4875,4876,4883],{},[38,4877,1286,4878],{},[232,4879,4882],{"href":4880,"rel":4881},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002Fjar2pom",[236],"gitee.com\u002FMegawatt\u002Fjar2pom",[38,4884,4885,4886],{},"CSDN：",[232,4887,4890],{"href":4888,"rel":4889},"https:\u002F\u002Fdownload.csdn.net\u002Fdownload\u002FJustinJia91\u002F12427956",[236],"download.csdn.net\u002Fdownload\u002FJustinJia91\u002F12427956",[11,4892,4893,4894,4897,4898,4901],{},"早年的仓库链接挂在 ",[132,4895,4896],{},"JiaXiaohei"," 这个账号名下，后来改成了 ",[132,4899,4900],{},"Megawatt","，老链接会自动跳过去，外部引用不用改。",[673,4903,1536],{},{"title":269,"searchDepth":270,"depth":270,"links":4905},[4906,4907,4908,4909,4910,4911],{"id":1615,"depth":270,"text":1615},{"id":3668,"depth":270,"text":3668},{"id":3699,"depth":270,"text":3699},{"id":4521,"depth":270,"text":4522},{"id":4779,"depth":270,"text":4779},{"id":4873,"depth":270,"text":4873},"2020-05-16","把非 Maven 项目转成 Maven 时，得给一堆本地 jar 补 dependency。这个工具先用 jar 的 SHA1 去 Maven 中心库反查坐标，查不到再退回解析 Manifest。这篇带上项目结构、响应映射，以及它查不出结果的几种情况。",{},"\u002Fposts\u002Fjar2pom-maven-dependency",{"title":3642,"description":4913},"posts\u002Fjar2pom-maven-dependency",[4919,1321,295],"Maven","7qQvEHaeu_Zv1Jdgu5cgjaj0f_murSgSjVcFWhE2zPE",{"id":4922,"title":4923,"body":4924,"date":5331,"description":5332,"extension":285,"meta":5333,"navigation":287,"path":5334,"seo":5335,"stem":5336,"tags":5337,"__hash__":5339},"posts\u002Fposts\u002Fflutter-android-sdkmanager-not-found.md","解决 Flutter 的 Android sdkmanager tool not found",{"type":8,"value":4925,"toc":5325},[4926,4928,4934,4937,4940,4946,5269,5271,5282,5287,5293,5298,5304,5309,5312,5315,5322],[24,4927,2332],{"id":2332},[306,4929,4932],{"className":4930,"code":4931,"language":1061},[1059],"Win10\nFlutter 1.12.13+hotfix.8\nAndroid Studio 3.6.1\n",[132,4933,4931],{"__ignoreMap":269},[24,4935,4936],{"id":4936},"问题描述",[11,4938,4939],{},"最近因为显卡 Boom 了，索性重装了系统。\n装完 Flutter 以后 doctor 通不过，一直找不到 sdkmanager。",[11,4941,4942],{},[139,4943],{"alt":4944,"src":4945},"flutter doctor 输出","\u002Fimages\u002Fflutter-android-sdkmanager\u002F01-flutter-doctor.png",[306,4947,4949],{"className":308,"code":4948,"language":310,"meta":269,"style":269},"> 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",[132,4950,4951,4959,4994,5033,5040,5070,5086,5109,5125,5133,5152,5170,5174,5196,5200,5207,5225,5243,5260,5264],{"__ignoreMap":269},[314,4952,4953,4956],{"class":316,"line":317},[314,4954,4955],{"class":525},">",[314,4957,4958],{"class":875}," flutter doctor\n",[314,4960,4961,4964,4967,4970,4973,4976,4979,4982,4985,4988,4991],{"class":316,"line":270},[314,4962,4963],{"class":320},"Doctor",[314,4965,4966],{"class":324}," summary",[314,4968,4969],{"class":875}," (to ",[314,4971,4972],{"class":324},"see",[314,4974,4975],{"class":324}," all",[314,4977,4978],{"class":324}," details,",[314,4980,4981],{"class":324}," run",[314,4983,4984],{"class":324}," flutter",[314,4986,4987],{"class":324}," doctor",[314,4989,4990],{"class":324}," -v",[314,4992,4993],{"class":875},"):\n",[314,4995,4996,4998,5001,5003,5006,5009,5012,5015,5018,5021,5024,5027,5030],{"class":316,"line":278},[314,4997,2509],{"class":525},[314,4999,5000],{"class":875},"√",[314,5002,2653],{"class":525},[314,5004,5005],{"class":875}," Flutter (",[314,5007,5008],{"class":320},"Channel",[314,5010,5011],{"class":324}," stable,",[314,5013,5014],{"class":324}," v1.12.13+hotfix.8,",[314,5016,5017],{"class":324}," on",[314,5019,5020],{"class":324}," Microsoft",[314,5022,5023],{"class":324}," Windows",[314,5025,5026],{"class":875}," [Version ",[314,5028,5029],{"class":324},"10.0.18363.720],",[314,5031,5032],{"class":324}," locale\n",[314,5034,5035,5038],{"class":316,"line":513},[314,5036,5037],{"class":320},"    zh-CN",[314,5039,2418],{"class":875},[314,5041,5042,5045,5048,5052,5055,5057,5060,5063,5065,5068],{"class":316,"line":535},[314,5043,5044],{"class":525},"[!]",[314,5046,5047],{"class":875}," Android toolchain - develop ",[314,5049,5051],{"class":5050},"s7zQu","for",[314,5053,5054],{"class":875}," Android devices ",[314,5056,3094],{"class":525},[314,5058,5059],{"class":320},"Android",[314,5061,5062],{"class":324}," SDK",[314,5064,2501],{"class":324},[314,5066,5067],{"class":2470}," 29.0.3",[314,5069,2418],{"class":525},[314,5071,5072,5075,5078,5081,5083],{"class":316,"line":543},[314,5073,5074],{"class":320},"    X",[314,5076,5077],{"class":324}," Android",[314,5079,5080],{"class":324}," license",[314,5082,360],{"class":324},[314,5084,5085],{"class":324}," unknown.\n",[314,5087,5088,5091,5094,5096,5099,5102,5104,5106],{"class":316,"line":554},[314,5089,5090],{"class":320},"      Try",[314,5092,5093],{"class":324}," re-installing",[314,5095,3472],{"class":324},[314,5097,5098],{"class":324}," updating",[314,5100,5101],{"class":324}," your",[314,5103,5077],{"class":324},[314,5105,5062],{"class":324},[314,5107,5108],{"class":324}," Manager.\n",[314,5110,5111,5114,5117,5119,5122],{"class":316,"line":560},[314,5112,5113],{"class":320},"      See",[314,5115,5116],{"class":324}," https:\u002F\u002Fdeveloper.android.com\u002Fstudio\u002F#downloads",[314,5118,3472],{"class":324},[314,5120,5121],{"class":324}," visit",[314,5123,5124],{"class":324}," https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup\n",[314,5126,5127,5130],{"class":316,"line":574},[314,5128,5129],{"class":5050},"      for",[314,5131,5132],{"class":875}," detailed instructions.\n",[314,5134,5135,5137,5139,5141,5144,5147,5150],{"class":316,"line":588},[314,5136,2509],{"class":525},[314,5138,5000],{"class":875},[314,5140,2653],{"class":525},[314,5142,5143],{"class":875}," Android Studio (",[314,5145,5146],{"class":320},"version",[314,5148,5149],{"class":2470}," 3.6",[314,5151,2418],{"class":875},[314,5153,5154,5156,5158,5160,5163,5165,5168],{"class":316,"line":602},[314,5155,2509],{"class":525},[314,5157,5000],{"class":875},[314,5159,2653],{"class":525},[314,5161,5162],{"class":875}," Connected device (",[314,5164,895],{"class":320},[314,5166,5167],{"class":324}," available",[314,5169,2418],{"class":875},[314,5171,5172],{"class":316,"line":1404},[314,5173,1716],{"emptyLinePlaceholder":287},[314,5175,5176,5179,5182,5185,5188,5190,5193],{"class":316,"line":1477},[314,5177,5178],{"class":525},"!",[314,5180,5181],{"class":320}," Doctor",[314,5183,5184],{"class":324}," found",[314,5186,5187],{"class":324}," issues",[314,5189,2900],{"class":324},[314,5191,5192],{"class":2470}," 1",[314,5194,5195],{"class":324}," category.\n",[314,5197,5198],{"class":316,"line":1483},[314,5199,1716],{"emptyLinePlaceholder":287},[314,5201,5202,5204],{"class":316,"line":1489},[314,5203,4955],{"class":525},[314,5205,5206],{"class":875}," flutter doctor --android-licenses\n",[314,5208,5209,5211,5214,5217,5220,5222],{"class":316,"line":1495},[314,5210,5059],{"class":320},[314,5212,5213],{"class":324}," sdkmanager",[314,5215,5216],{"class":324}," tool",[314,5218,5219],{"class":324}," not",[314,5221,5184],{"class":324},[314,5223,5224],{"class":875}," (D:\\Android\\Sdk\\tools\\bin\\sdkmanager).\n",[314,5226,5227,5230,5232,5234,5236,5238,5240],{"class":316,"line":1501},[314,5228,5229],{"class":320},"Try",[314,5231,5093],{"class":324},[314,5233,3472],{"class":324},[314,5235,5098],{"class":324},[314,5237,5101],{"class":324},[314,5239,5077],{"class":324},[314,5241,5242],{"class":324}," SDK,\n",[314,5244,5245,5248,5251,5254,5257],{"class":316,"line":1507},[314,5246,5247],{"class":320},"visit",[314,5249,5250],{"class":324}," https:\u002F\u002Fflutter.dev\u002Fsetup\u002F#android-setup",[314,5252,5253],{"class":324}," for",[314,5255,5256],{"class":324}," detailed",[314,5258,5259],{"class":324}," instructions.\n",[314,5261,5262],{"class":316,"line":1512},[314,5263,1716],{"emptyLinePlaceholder":287},[314,5265,5266],{"class":316,"line":1518},[314,5267,5268],{"class":525},">\n",[24,5270,1570],{"id":1570},[11,5272,5273,5274,5277,5278,5281],{},"在 Android Studio 中启动 ",[41,5275,5276],{},"SDK Manager","，去掉选项 ",[41,5279,5280],{},"Hide Obsolete Packages","：",[11,5283,5284],{},[139,5285],{"alt":5276,"src":5286},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F02-sdk-manager.png",[11,5288,5289,5290,5281],{},"选择安装 ",[41,5291,5292],{},"Android SDK Tools (Obsolete)",[11,5294,5295],{},[139,5296],{"alt":5292,"src":5297},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F03-sdk-tools-obsolete.png",[11,5299,5300,5301,5281],{},"点击 ",[41,5302,5303],{},"Apply",[11,5305,5306],{},[139,5307],{"alt":5303,"src":5308},"\u002Fimages\u002Fflutter-android-sdkmanager\u002F04-apply.png",[11,5310,5311],{},"安装完成。",[24,5313,5314],{"id":5314},"原因",[11,5316,5317,5318,5321],{},"不知道为啥 ",[41,5319,5320],{},"Android SDK Tools"," 被废弃了，但是好像 Flutter 还需要其提供支持。",[673,5323,5324],{},"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":269,"searchDepth":270,"depth":270,"links":5326},[5327,5328,5329,5330],{"id":2332,"depth":270,"text":2332},{"id":4936,"depth":270,"text":4936},{"id":1570,"depth":270,"text":1570},{"id":5314,"depth":270,"text":5314},"2020-03-30","重装系统后 flutter doctor 一直报 Android license status unknown，找不到 sdkmanager。根因是被废弃的 Android SDK Tools 没装。",{},"\u002Fposts\u002Fflutter-android-sdkmanager-not-found",{"title":4923,"description":5332},"posts\u002Fflutter-android-sdkmanager-not-found",[5338,5059],"Flutter","GiT5gHSSUrSXafs-nkG3w45OUYqiQiNCK5LT3EeUBBg",{"id":5341,"title":5342,"body":5343,"date":6078,"description":6079,"extension":285,"meta":6080,"navigation":287,"path":6081,"seo":6082,"stem":6083,"tags":6084,"__hash__":6086},"posts\u002Fposts\u002Fcentos-yum-pgadmin4-python3-missing.md","解决 CentOS yum 安装 pgadmin4 报 nothing provides python3-*** 的问题",{"type":8,"value":5344,"toc":6072},[5345,5347,5353,5355,5358,5364,6039,6041,6044,6046,6052,6069],[24,5346,2332],{"id":2332},[306,5348,5351],{"className":5349,"code":5350,"language":1061},[1059],"CentOS8 (最小安装)\nPython3 (yum\u002Fdnf安装)\n",[132,5352,5350],{"__ignoreMap":269},[24,5354,4936],{"id":4936},[11,5356,5357],{},"安装时提示缺少 python3-alembic 等包，\n但是安装了 python3 仍然提示找不到包。",[11,5359,5360],{},[139,5361],{"alt":5362,"src":5363},"yum 安装报错","\u002Fimages\u002Fcentos-yum-pgadmin4\u002Ferror.png",[306,5365,5367],{"className":308,"code":5366,"language":310,"meta":269,"style":269},"[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",[132,5368,5369,5381,5397,5402,5440,5464,5486,5503,5529,5553,5577,5594,5611,5633,5655,5672,5688,5710,5732,5749,5765,5782,5799,5821,5843,5860,5876,5892,5908,5930,5952,5969,5985,6007],{"__ignoreMap":269},[314,5370,5371,5373,5376,5378],{"class":316,"line":317},[314,5372,2509],{"class":525},[314,5374,5375],{"class":875},"root@HyperV-PSQL ",[314,5377,3423],{"class":525},[314,5379,5380],{"class":875},"# yum -y install pgadmin4\n",[314,5382,5383,5386,5388,5391,5394],{"class":316,"line":270},[314,5384,5385],{"class":320},"上次元数据过期检查：0:11:32",[314,5387,2664],{"class":324},[314,5389,5390],{"class":324}," 2020年03月10日",[314,5392,5393],{"class":324}," 星期二",[314,5395,5396],{"class":324}," 11时35分24秒。\n",[314,5398,5399],{"class":316,"line":278},[314,5400,5401],{"class":320},"错误：\n",[314,5403,5404,5407,5409,5412,5415,5418,5421,5424,5426,5428,5431,5434,5437],{"class":316,"line":513},[314,5405,5406],{"class":320}," 问题:",[314,5408,2914],{"class":324},[314,5410,5411],{"class":324}," pgadmin4-4.19-1.rhel8.x86_64",[314,5413,5414],{"class":324}," requires",[314,5416,5417],{"class":324}," pgadmin4-web,",[314,5419,5420],{"class":324}," but",[314,5422,5423],{"class":324}," none",[314,5425,2496],{"class":324},[314,5427,2397],{"class":324},[314,5429,5430],{"class":324}," providers",[314,5432,5433],{"class":324}," can",[314,5435,5436],{"class":324}," be",[314,5438,5439],{"class":324}," installed\n",[314,5441,5442,5445,5447,5449,5451,5454,5457,5459,5461],{"class":316,"line":535},[314,5443,5444],{"class":320},"  -",[314,5446,3164],{"class":324},[314,5448,2555],{"class":324},[314,5450,2397],{"class":324},[314,5452,5453],{"class":324}," best",[314,5455,5456],{"class":324}," candidate",[314,5458,5253],{"class":324},[314,5460,2397],{"class":324},[314,5462,5463],{"class":324}," job\n",[314,5465,5466,5468,5471,5474,5477,5480,5483],{"class":316,"line":543},[314,5467,5444],{"class":320},[314,5469,5470],{"class":324}," nothing",[314,5472,5473],{"class":324}," provides",[314,5475,5476],{"class":324}," python3-alembic",[314,5478,5479],{"class":324}," needed",[314,5481,5482],{"class":324}," by",[314,5484,5485],{"class":324}," pgadmin4-web-4.16-1.rhel8.noarch\n",[314,5487,5488,5490,5492,5494,5497,5499,5501],{"class":316,"line":554},[314,5489,5444],{"class":320},[314,5491,5470],{"class":324},[314,5493,5473],{"class":324},[314,5495,5496],{"class":324}," pgadmin4-python3-unittest2",[314,5498,5479],{"class":324},[314,5500,5482],{"class":324},[314,5502,5485],{"class":324},[314,5504,5505,5507,5509,5511,5514,5517,5520,5523,5525,5527],{"class":316,"line":560},[314,5506,5444],{"class":320},[314,5508,5470],{"class":324},[314,5510,5473],{"class":324},[314,5512,5513],{"class":324}," python3-blinker",[314,5515,5516],{"class":525}," >",[314,5518,5519],{"class":324},"=",[314,5521,5522],{"class":2470}," 1.4",[314,5524,5479],{"class":324},[314,5526,5482],{"class":324},[314,5528,5485],{"class":324},[314,5530,5531,5533,5535,5537,5540,5542,5544,5547,5549,5551],{"class":316,"line":574},[314,5532,5444],{"class":320},[314,5534,5470],{"class":324},[314,5536,5473],{"class":324},[314,5538,5539],{"class":324}," python3-beautifulsoup4",[314,5541,5516],{"class":525},[314,5543,5519],{"class":324},[314,5545,5546],{"class":2470}," 4.4.1",[314,5548,5479],{"class":324},[314,5550,5482],{"class":324},[314,5552,5485],{"class":324},[314,5554,5555,5557,5559,5561,5564,5566,5568,5571,5573,5575],{"class":316,"line":588},[314,5556,5444],{"class":320},[314,5558,5470],{"class":324},[314,5560,5473],{"class":324},[314,5562,5563],{"class":324}," python3-flask-sqlalchemy",[314,5565,5516],{"class":525},[314,5567,5519],{"class":324},[314,5569,5570],{"class":2470}," 2.3.2",[314,5572,5479],{"class":324},[314,5574,5482],{"class":324},[314,5576,5485],{"class":324},[314,5578,5579,5581,5583,5585,5587,5589,5591],{"class":316,"line":602},[314,5580,5444],{"class":320},[314,5582,5470],{"class":324},[314,5584,5473],{"class":324},[314,5586,5476],{"class":324},[314,5588,5479],{"class":324},[314,5590,5482],{"class":324},[314,5592,5593],{"class":324}," pgadmin4-web-4.16-2.rhel8.noarch\n",[314,5595,5596,5598,5600,5602,5605,5607,5609],{"class":316,"line":1404},[314,5597,5444],{"class":320},[314,5599,5470],{"class":324},[314,5601,5473],{"class":324},[314,5603,5604],{"class":324}," python3-unittest2",[314,5606,5479],{"class":324},[314,5608,5482],{"class":324},[314,5610,5593],{"class":324},[314,5612,5613,5615,5617,5619,5621,5623,5625,5627,5629,5631],{"class":316,"line":1477},[314,5614,5444],{"class":320},[314,5616,5470],{"class":324},[314,5618,5473],{"class":324},[314,5620,5513],{"class":324},[314,5622,5516],{"class":525},[314,5624,5519],{"class":324},[314,5626,5522],{"class":2470},[314,5628,5479],{"class":324},[314,5630,5482],{"class":324},[314,5632,5593],{"class":324},[314,5634,5635,5637,5639,5641,5643,5645,5647,5649,5651,5653],{"class":316,"line":1483},[314,5636,5444],{"class":320},[314,5638,5470],{"class":324},[314,5640,5473],{"class":324},[314,5642,5539],{"class":324},[314,5644,5516],{"class":525},[314,5646,5519],{"class":324},[314,5648,5546],{"class":2470},[314,5650,5479],{"class":324},[314,5652,5482],{"class":324},[314,5654,5593],{"class":324},[314,5656,5657,5659,5661,5663,5665,5667,5669],{"class":316,"line":1489},[314,5658,5444],{"class":320},[314,5660,5470],{"class":324},[314,5662,5473],{"class":324},[314,5664,5476],{"class":324},[314,5666,5479],{"class":324},[314,5668,5482],{"class":324},[314,5670,5671],{"class":324}," pgadmin4-web-4.17-1.rhel8.noarch\n",[314,5673,5674,5676,5678,5680,5682,5684,5686],{"class":316,"line":1495},[314,5675,5444],{"class":320},[314,5677,5470],{"class":324},[314,5679,5473],{"class":324},[314,5681,5604],{"class":324},[314,5683,5479],{"class":324},[314,5685,5482],{"class":324},[314,5687,5671],{"class":324},[314,5689,5690,5692,5694,5696,5698,5700,5702,5704,5706,5708],{"class":316,"line":1501},[314,5691,5444],{"class":320},[314,5693,5470],{"class":324},[314,5695,5473],{"class":324},[314,5697,5513],{"class":324},[314,5699,5516],{"class":525},[314,5701,5519],{"class":324},[314,5703,5522],{"class":2470},[314,5705,5479],{"class":324},[314,5707,5482],{"class":324},[314,5709,5671],{"class":324},[314,5711,5712,5714,5716,5718,5720,5722,5724,5726,5728,5730],{"class":316,"line":1507},[314,5713,5444],{"class":320},[314,5715,5470],{"class":324},[314,5717,5473],{"class":324},[314,5719,5539],{"class":324},[314,5721,5516],{"class":525},[314,5723,5519],{"class":324},[314,5725,5546],{"class":2470},[314,5727,5479],{"class":324},[314,5729,5482],{"class":324},[314,5731,5671],{"class":324},[314,5733,5734,5736,5738,5740,5742,5744,5746],{"class":316,"line":1512},[314,5735,5444],{"class":320},[314,5737,5470],{"class":324},[314,5739,5473],{"class":324},[314,5741,5476],{"class":324},[314,5743,5479],{"class":324},[314,5745,5482],{"class":324},[314,5747,5748],{"class":324}," pgadmin4-web-4.17-2.rhel8.noarch\n",[314,5750,5751,5753,5755,5757,5759,5761,5763],{"class":316,"line":1518},[314,5752,5444],{"class":320},[314,5754,5470],{"class":324},[314,5756,5473],{"class":324},[314,5758,5604],{"class":324},[314,5760,5479],{"class":324},[314,5762,5482],{"class":324},[314,5764,5748],{"class":324},[314,5766,5767,5769,5771,5773,5776,5778,5780],{"class":316,"line":1523},[314,5768,5444],{"class":320},[314,5770,5470],{"class":324},[314,5772,5473],{"class":324},[314,5774,5775],{"class":324}," python3-bcrypt",[314,5777,5479],{"class":324},[314,5779,5482],{"class":324},[314,5781,5748],{"class":324},[314,5783,5784,5786,5788,5790,5793,5795,5797],{"class":316,"line":1758},[314,5785,5444],{"class":320},[314,5787,5470],{"class":324},[314,5789,5473],{"class":324},[314,5791,5792],{"class":324}," python3-pynacl",[314,5794,5479],{"class":324},[314,5796,5482],{"class":324},[314,5798,5748],{"class":324},[314,5800,5801,5803,5805,5807,5809,5811,5813,5815,5817,5819],{"class":316,"line":1764},[314,5802,5444],{"class":320},[314,5804,5470],{"class":324},[314,5806,5473],{"class":324},[314,5808,5513],{"class":324},[314,5810,5516],{"class":525},[314,5812,5519],{"class":324},[314,5814,5522],{"class":2470},[314,5816,5479],{"class":324},[314,5818,5482],{"class":324},[314,5820,5748],{"class":324},[314,5822,5823,5825,5827,5829,5831,5833,5835,5837,5839,5841],{"class":316,"line":1770},[314,5824,5444],{"class":320},[314,5826,5470],{"class":324},[314,5828,5473],{"class":324},[314,5830,5539],{"class":324},[314,5832,5516],{"class":525},[314,5834,5519],{"class":324},[314,5836,5546],{"class":2470},[314,5838,5479],{"class":324},[314,5840,5482],{"class":324},[314,5842,5748],{"class":324},[314,5844,5845,5847,5849,5851,5853,5855,5857],{"class":316,"line":1776},[314,5846,5444],{"class":320},[314,5848,5470],{"class":324},[314,5850,5473],{"class":324},[314,5852,5476],{"class":324},[314,5854,5479],{"class":324},[314,5856,5482],{"class":324},[314,5858,5859],{"class":324}," pgadmin4-web-4.18-1.rhel8.noarch\n",[314,5861,5862,5864,5866,5868,5870,5872,5874],{"class":316,"line":1781},[314,5863,5444],{"class":320},[314,5865,5470],{"class":324},[314,5867,5473],{"class":324},[314,5869,5604],{"class":324},[314,5871,5479],{"class":324},[314,5873,5482],{"class":324},[314,5875,5859],{"class":324},[314,5877,5878,5880,5882,5884,5886,5888,5890],{"class":316,"line":1787},[314,5879,5444],{"class":320},[314,5881,5470],{"class":324},[314,5883,5473],{"class":324},[314,5885,5775],{"class":324},[314,5887,5479],{"class":324},[314,5889,5482],{"class":324},[314,5891,5859],{"class":324},[314,5893,5894,5896,5898,5900,5902,5904,5906],{"class":316,"line":1792},[314,5895,5444],{"class":320},[314,5897,5470],{"class":324},[314,5899,5473],{"class":324},[314,5901,5792],{"class":324},[314,5903,5479],{"class":324},[314,5905,5482],{"class":324},[314,5907,5859],{"class":324},[314,5909,5910,5912,5914,5916,5918,5920,5922,5924,5926,5928],{"class":316,"line":1798},[314,5911,5444],{"class":320},[314,5913,5470],{"class":324},[314,5915,5473],{"class":324},[314,5917,5513],{"class":324},[314,5919,5516],{"class":525},[314,5921,5519],{"class":324},[314,5923,5522],{"class":2470},[314,5925,5479],{"class":324},[314,5927,5482],{"class":324},[314,5929,5859],{"class":324},[314,5931,5932,5934,5936,5938,5940,5942,5944,5946,5948,5950],{"class":316,"line":1804},[314,5933,5444],{"class":320},[314,5935,5470],{"class":324},[314,5937,5473],{"class":324},[314,5939,5539],{"class":324},[314,5941,5516],{"class":525},[314,5943,5519],{"class":324},[314,5945,5546],{"class":2470},[314,5947,5479],{"class":324},[314,5949,5482],{"class":324},[314,5951,5859],{"class":324},[314,5953,5954,5956,5958,5960,5962,5964,5966],{"class":316,"line":1809},[314,5955,5444],{"class":320},[314,5957,5470],{"class":324},[314,5959,5473],{"class":324},[314,5961,5775],{"class":324},[314,5963,5479],{"class":324},[314,5965,5482],{"class":324},[314,5967,5968],{"class":324}," pgadmin4-web-4.19-1.rhel8.noarch\n",[314,5970,5971,5973,5975,5977,5979,5981,5983],{"class":316,"line":1814},[314,5972,5444],{"class":320},[314,5974,5470],{"class":324},[314,5976,5473],{"class":324},[314,5978,5792],{"class":324},[314,5980,5479],{"class":324},[314,5982,5482],{"class":324},[314,5984,5968],{"class":324},[314,5986,5987,5989,5991,5993,5995,5997,5999,6001,6003,6005],{"class":316,"line":1820},[314,5988,5444],{"class":320},[314,5990,5470],{"class":324},[314,5992,5473],{"class":324},[314,5994,5513],{"class":324},[314,5996,5516],{"class":525},[314,5998,5519],{"class":324},[314,6000,5522],{"class":2470},[314,6002,5479],{"class":324},[314,6004,5482],{"class":324},[314,6006,5968],{"class":324},[314,6008,6009,6011,6014,6016,6019,6021,6024,6027,6029,6032,6034,6037],{"class":316,"line":1825},[314,6010,3094],{"class":525},[314,6012,6013],{"class":320},"尝试添加",[314,6015,3261],{"class":525},[314,6017,6018],{"class":324},"--skip-broken",[314,6020,526],{"class":525},[314,6022,6023],{"class":324}," 来跳过无法安装的软件包",[314,6025,6026],{"class":324}," 或",[314,6028,3261],{"class":525},[314,6030,6031],{"class":324},"--nobest",[314,6033,526],{"class":525},[314,6035,6036],{"class":324}," 来不只使用最佳选择的软件包",[314,6038,2418],{"class":525},[24,6040,5314],{"id":5314},[11,6042,6043],{},"官方的 rpm repository 没有提供对应的包。",[24,6045,1570],{"id":1570},[11,6047,6048,6049,5281],{},"安装 ",[41,6050,6051],{},"EPEL",[306,6053,6055],{"className":308,"code":6054,"language":310,"meta":269,"style":269},"yum install epel-release -y\n",[132,6056,6057],{"__ignoreMap":269},[314,6058,6059,6061,6063,6066],{"class":316,"line":317},[314,6060,3617],{"class":320},[314,6062,2555],{"class":324},[314,6064,6065],{"class":324}," epel-release",[314,6067,6068],{"class":324}," -y\n",[673,6070,6071],{},"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":269,"searchDepth":270,"depth":270,"links":6073},[6074,6075,6076,6077],{"id":2332,"depth":270,"text":2332},{"id":4936,"depth":270,"text":4936},{"id":5314,"depth":270,"text":5314},{"id":1570,"depth":270,"text":1570},"2020-03-13","CentOS 8 上装 pgadmin4 一直缺 python3-alembic 之类的包，但 python3 明明装了。原因是官方 rpm 仓库没提供这些包，得先装 EPEL。",{},"\u002Fposts\u002Fcentos-yum-pgadmin4-python3-missing",{"title":5342,"description":6079},"posts\u002Fcentos-yum-pgadmin4-python3-missing",[696,6085,697],"PostgreSQL","m8HlbPTWcENXN-aO3c9aheDUKgp-zFDXfe9aG1lKEXI",{"id":6088,"title":6089,"body":6090,"date":6568,"description":6569,"extension":285,"meta":6570,"navigation":287,"path":6571,"seo":6572,"stem":6573,"tags":6574,"__hash__":6577},"posts\u002Fposts\u002Fmacpro-gpu-switch.md","MacPro GPU Switch：用 JavaFX 做一个 macOS 显卡切换工具",{"type":8,"value":6091,"toc":6553},[6092,6095,6098,6101,6157,6160,6163,6166,6172,6175,6178,6181,6184,6191,6211,6214,6217,6221,6227,6233,6243,6280,6283,6287,6302,6309,6313,6316,6330,6341,6355,6374,6377,6400,6404,6410,6435,6438,6444,6448,6480,6482,6485,6488,6499,6514,6517,6531,6534,6536,6539,6547,6550],[11,6093,6094],{},"MacBook Pro 15 寸是台双显卡的机器：一块 Intel 核显，一块 Radeon 独显。",[11,6096,6097],{},"用久了会撞上一个很具体的烦恼 —— 你没法决定现在用哪块。",[11,6099,6100],{},"macOS 的系统设置里，关于显卡只有「自动切换图形卡模式」这一个勾选框，它管的是“要不要自动切”，管不了“现在锁在哪一块”。真正能决定这件事的，是一条电源管理命令：",[306,6102,6104],{"className":308,"code":6103,"language":310,"meta":269,"style":269},"sudo pmset -a GPUSwitch 0   # 整合（只用核显）\nsudo pmset -a GPUSwitch 1   # 高性能（只用独显）\nsudo pmset -a GPUSwitch 2   # 自动\n",[132,6105,6106,6126,6141],{"__ignoreMap":269},[314,6107,6108,6111,6114,6117,6120,6123],{"class":316,"line":317},[314,6109,6110],{"class":320},"sudo",[314,6112,6113],{"class":324}," pmset",[314,6115,6116],{"class":324}," -a",[314,6118,6119],{"class":324}," GPUSwitch",[314,6121,6122],{"class":2470}," 0",[314,6124,6125],{"class":3038},"   # 整合（只用核显）\n",[314,6127,6128,6130,6132,6134,6136,6138],{"class":316,"line":270},[314,6129,6110],{"class":320},[314,6131,6113],{"class":324},[314,6133,6116],{"class":324},[314,6135,6119],{"class":324},[314,6137,5192],{"class":2470},[314,6139,6140],{"class":3038},"   # 高性能（只用独显）\n",[314,6142,6143,6145,6147,6149,6151,6154],{"class":316,"line":278},[314,6144,6110],{"class":320},[314,6146,6113],{"class":324},[314,6148,6116],{"class":324},[314,6150,6119],{"class":324},[314,6152,6153],{"class":2470}," 2",[314,6155,6156],{"class":3038},"   # 自动\n",[11,6158,6159],{},"能用，但每次都得开终端、敲一遍、输一次密码。为了两秒钟的切换走完这一套，太长了。",[11,6161,6162],{},"MacPro GPU Switch 就是把这条命令包进一个窗口：选核显就一直用核显，选独显就一直用独显，选自动就交回给系统。",[24,6164,6165],{"id":6165},"它长这样",[11,6167,6168],{},[139,6169],{"alt":6170,"src":6171},"MacPro GPU Switch 主界面：左侧大字显示当前模式，右侧填 Root 密码并选择模式","\u002Fimages\u002Fmacpro-gpu-switch\u002Fmain-window.png",[11,6173,6174],{},"界面很直白：左边大字写着当前处于哪个模式，颜色也跟着变（整合是青色，高性能是橙色，自动是蓝色）；右边填 Root 密码，下面三个单选框对应三种模式；底部是「关于」「应用」「关闭」。",[11,6176,6177],{},"勾上「记住密码」，下次打开就不用再输。",[11,6179,6180],{},"它做的事就四步：读当前状态 → 你选一个新模式 → 点「应用」→ 它替你跑那条 sudo 命令，再把新状态读回来显示。",[24,6182,6183],{"id":6183},"三种模式",[11,6185,6186,6187,6190],{},"对应 ",[132,6188,6189],{},"GPUSwitch"," 的三个值：",[73,6192,6193,6199,6205],{},[38,6194,6195,6198],{},[41,6196,6197],{},"整合","（0）—— 只用核显，最省电最凉快，重活干不了；",[38,6200,6201,6204],{},[41,6202,6203],{},"高性能","（1）—— 只用独显，性能拉满，代价是发热和续航；",[38,6206,6207,6210],{},[41,6208,6209],{},"自动","（2）—— 交给系统判断，也就是 macOS 默认的那套逻辑。",[24,6212,6213],{"id":6213},"实现上其实只有三件事",[11,6215,6216],{},"代码量很小，核心就是三次 Shell 调用。",[154,6218,6220],{"id":6219},"一读懂当前状态","一、读懂当前状态",[11,6222,6223,6226],{},[132,6224,6225],{},"pmset -g"," 会打印一大串电源管理配置，显卡那一行长这样：",[306,6228,6231],{"className":6229,"code":6230,"language":1061},[1059],"gpuswitch             0\n",[132,6232,6230],{"__ignoreMap":269},[11,6234,6235,6236,6238,6239,6242],{},"所以读状态的逻辑就是：跑一遍 ",[132,6237,6225],{},"，逐行找以 ",[132,6240,6241],{},"gpuswitch"," 开头的那行，把数字抠出来。",[306,6244,6246],{"className":1648,"code":6245,"language":1026,"meta":269,"style":269},"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",[132,6247,6248,6253,6257,6262,6267,6272,6276],{"__ignoreMap":269},[314,6249,6250],{"class":316,"line":317},[314,6251,6252],{},"String[] command = {\"\u002Fbin\u002Fsh\", \"-c\", \"pmset -g\"};\n",[314,6254,6255],{"class":316,"line":270},[314,6256,1716],{"emptyLinePlaceholder":287},[314,6258,6259],{"class":316,"line":278},[314,6260,6261],{},"for (String process : processList) {\n",[314,6263,6264],{"class":316,"line":513},[314,6265,6266],{},"    if (process.startsWith(\"gpuswitch\")) {\n",[314,6268,6269],{"class":316,"line":535},[314,6270,6271],{},"        i = Integer.parseInt(process.replaceAll(\"gpuswitch| \", \"\"));\n",[314,6273,6274],{"class":316,"line":543},[314,6275,1868],{},[314,6277,6278],{"class":316,"line":554},[314,6279,1191],{},[11,6281,6282],{},"拿到 0 \u002F 1 \u002F 2，再去点亮界面上对应的那个单选框。",[154,6284,6286],{"id":6285},"二切换","二、切换",[306,6288,6290],{"className":1648,"code":6289,"language":1026,"meta":269,"style":269},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n    \"echo \\\"\" + password + \"\\\" | sudo -S pmset -a GPUSwitch \" + status};\n",[132,6291,6292,6297],{"__ignoreMap":269},[314,6293,6294],{"class":316,"line":317},[314,6295,6296],{},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n",[314,6298,6299],{"class":316,"line":270},[314,6300,6301],{},"    \"echo \\\"\" + password + \"\\\" | sudo -S pmset -a GPUSwitch \" + status};\n",[11,6303,6304,6305,6308],{},"关键在 ",[132,6306,6307],{},"sudo -S"," 这个参数。它让 sudo 从标准输入读密码 —— 不加它，sudo 会去找终端要密码，而一个图形界面程序没有终端，命令会直接卡在那里。把密码 echo 进去、管道喂给 sudo，就能在没有终端的环境里把这条命令跑完。",[154,6310,6312],{"id":6311},"三验证密码","三、验证密码",[11,6314,6315],{},"切显卡之前得先知道密码对不对，否则用户点「应用」只会撞上一个莫名其妙的失败。",[306,6317,6319],{"className":1648,"code":6318,"language":1026,"meta":269,"style":269},"String[] command = {\"\u002Fbin\u002Fbash\", \"-c\",\n    \"echo \\\"\" + password + \"\\\" | sudo -S whoami\"};\n",[132,6320,6321,6325],{"__ignoreMap":269},[314,6322,6323],{"class":316,"line":317},[314,6324,6296],{},[314,6326,6327],{"class":316,"line":270},[314,6328,6329],{},"    \"echo \\\"\" + password + \"\\\" | sudo -S whoami\"};\n",[11,6331,6332,6333,6336,6337,6340],{},"跑一次 ",[132,6334,6335],{},"whoami","，输出的第一行是 ",[132,6338,6339],{},"root","，就说明密码正确。",[11,6342,6343,6344,6346,6347,6350,6351,6354],{},"用 ",[132,6345,6335],{}," 而不是 ",[132,6348,6349],{},"sudo -v","，好处是它验证权限的方式和后面那条 ",[132,6352,6353],{},"pmset"," 完全一致，同时又没有任何副作用 —— 密码错了也不会误伤配置。",[11,6356,6357,6358,6361,6362,6365,6366,6369,6370,6373],{},"写正式代码之前，我先在 ",[132,6359,6360],{},"src\u002Ftest"," 下扔了两个带 ",[132,6363,6364],{},"main"," 的小类，把命令单独跑通再搬进工具类。目录里留下的 ",[132,6367,6368],{},"CheckPassword"," 和 ",[132,6371,6372],{},"RunPmset"," 就是当时的验证代码。",[154,6375,6376],{"id":6376},"界面部分",[11,6378,6379,6380,6383,6384,6387,6388,6391,6392,6395,6396,6399],{},"JavaFX + FXML，没什么花活。三个 ",[132,6381,6382],{},"RadioButton"," 的 ",[132,6385,6386],{},"userData"," 里分别挂着 0 \u002F 1 \u002F 2，用 ",[132,6389,6390],{},"ToggleGroup"," 保证互斥；窗口初始化时先读一次当前状态，用 ",[132,6393,6394],{},"fire()"," 把对应的那个点亮。为了避免用户还没选模式就点「应用」，",[132,6397,6398],{},"applyApp()"," 里也做了一次空判断。",[24,6401,6403],{"id":6402},"记住密码是怎么存的","「记住密码」是怎么存的",[11,6405,6406,6407,5281],{},"勾上「记住密码」之后，密码不会明文落盘，而是先加密再写进程序目录下的 ",[132,6408,6409],{},"conf.properties",[73,6411,6412,6421],{},[38,6413,6414,5281,6417,6420],{},[41,6415,6416],{},"算法",[132,6418,6419],{},"AES\u002FECB\u002FPKCS5Padding","，密文再转成 URL-safe 的 Base64 保存；",[38,6422,6423,6426,6427,6430,6431,6434],{},[41,6424,6425],{},"密钥不是写死的常量","，而是每台机器独有的一个标识 —— 跑一遍 ",[132,6428,6429],{},"system_profiler SPHardwareDataType","，抓 ",[132,6432,6433],{},"Hardware UUID:"," 那一行，去掉空格和连字符，正好 32 位十六进制，直接拿来当 AES-256 的密钥。",[11,6436,6437],{},"配置文件里只存两样东西：一个「是否记住密码」的开关，和密文本身。",[11,6439,6440,6441,6443],{},"取 Hardware UUID 而不是写死一个字符串，好处是凭据跟机器绑在一起 —— 把 ",[132,6442,6409],{}," 拷到别的机器上，密文就解不开了。反过来，换机器或者重装系统之后，之前记住的密码会失效，重新输一次就行。",[24,6445,6447],{"id":6446},"支持范围和一句要紧的警告","支持范围，和一句要紧的警告",[35,6449,6450,6457,6464,6471],{},[38,6451,6452,6453,6456],{},"实际验证过的只有一台：",[41,6454,6455],{},"MacBook Pro（15-inch，2018）+ macOS Mojave 10.14.3","；",[38,6458,6459,6460,6463],{},"理论上所有能用 ",[132,6461,6462],{},"sudo pmset -a GPUSwitch"," 切换显卡的型号都能用，欢迎大家补充自己的型号；",[38,6465,6466,6467,6470],{},"⚠️ ",[41,6468,6469],{},"只有核显的机器切勿尝试。"," 这是 README 里唯一用感叹号写的一句，我原样搬过来 —— 没有独显的机器上执行这条命令没有意义，也没人验证过会发生什么；",[38,6472,6473,6474,6369,6476,6479],{},"它只在 macOS 上有意义，依赖 ",[132,6475,6353],{},[132,6477,6478],{},"system_profiler"," 这两个系统命令。",[24,6481,918],{"id":918},[11,6483,6484],{},"开发环境是当年的那一套：Apache Maven 3.6、JDK 8、IntelliJ IDEA 2018.3。",[11,6486,6487],{},"当年 Oracle JDK 8 自带 JavaFX，不用另外下 SDK —— 这也是我选 JavaFX 而不是拉一堆第三方 UI 库的原因：对一个这么小的工具来说，零额外依赖比什么都重要。",[11,6489,6490,6491,6494,6495,6498],{},"跑起来很简单：clone 下来用 IDEA 打开，运行 ",[132,6492,6493],{},"cn.jxh.switcher.Main"," 就行。想打包成 macOS 的原生应用，pom 里已经配好了 JavaFX 的 Maven 插件（zenjava 8.8.3，应用名 ",[132,6496,6497],{},"MacProGPUSwitch","）。",[11,6500,6501,6502,6505,6506,6509,6510,6513],{},"版本号那处设计顺带提一句：",[132,6503,6504],{},"app.properties"," 里放的不是写死的数字，而是 ",[132,6507,6508],{},"${project.version}","，打包时由 Maven 的 resource filtering 替换成真实版本。改 pom 里的 ",[132,6511,6512],{},"\u003Cversion>"," 一处，界面「关于」里显示的版本号就跟着走。",[24,6515,6516],{"id":6516},"版本",[35,6518,6519,6525],{},[38,6520,6521,6524],{},[41,6522,6523],{},"1.0.0","（2019-02-10）：第一个版本，能读状态、能切换；",[38,6526,6527,6530],{},[41,6528,6529],{},"1.0.1","（2019-02-12）：加上 Root 密码验证，以及「记住密码」。",[11,6532,6533],{},"写完这篇的时候，正好是 1.0.1。",[24,6535,1278],{"id":1278},[11,6537,6538],{},"仓库在这里，Apache License 2.0：",[35,6540,6541],{},[38,6542,1286,6543],{},[232,6544,6545],{"href":6545,"rel":6546},"https:\u002F\u002Fgitee.com\u002FMegawatt\u002FMacProGPUSwitch",[236],[11,6548,6549],{},"这是个很小的工具，解决的问题也很窄。但如果你也是 2018 款 MacBook Pro 的用户，被那块随时会醒过来的独显烦过，它可能正好是你要的那个开关。",[673,6551,6552],{},"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":269,"searchDepth":270,"depth":270,"links":6554},[6555,6556,6557,6563,6564,6565,6566,6567],{"id":6165,"depth":270,"text":6165},{"id":6183,"depth":270,"text":6183},{"id":6213,"depth":270,"text":6213,"children":6558},[6559,6560,6561,6562],{"id":6219,"depth":278,"text":6220},{"id":6285,"depth":278,"text":6286},{"id":6311,"depth":278,"text":6312},{"id":6376,"depth":278,"text":6376},{"id":6402,"depth":270,"text":6403},{"id":6446,"depth":270,"text":6447},{"id":918,"depth":270,"text":918},{"id":6516,"depth":270,"text":6516},{"id":1278,"depth":270,"text":1278},"2019-02-12","一个 JavaFX 写的小工具，把 macOS 里只能靠 sudo pmset 切换的显卡模式搬进了图形界面。这篇讲清它解决什么问题、三行核心代码怎么调 pmset，以及「记住密码」是怎么存下来的。",{},"\u002Fposts\u002Fmacpro-gpu-switch",{"title":6089,"description":6569},"posts\u002Fmacpro-gpu-switch",[1321,6575,6576,294,295],"JavaFX","macOS","R7W1l20eNuApI0c5e887Q4zxAmcFjrquPAtbU78Vc_g",{"id":6579,"title":3654,"body":6580,"date":7514,"description":7515,"extension":285,"meta":7516,"navigation":287,"path":3664,"seo":7517,"stem":7518,"tags":7519,"__hash__":7520},"posts\u002Fposts\u002Fjar2pom-nexus2-dependency.md",{"type":8,"value":6581,"toc":7510},[6582,6591,7436,7440,7499,7502,7508],[6583,6584,6585],"blockquote",{},[11,6586,6587,6588,104],{},"此版本基于 Nexus OSS 2 相关接口。\n基于 Maven 中心库的版本请",[232,6589,6590],{"href":4915},"点这里",[306,6592,6594],{"className":1648,"code":6593,"language":1026,"meta":269,"style":269},"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",[132,6595,6596,6601,6605,6610,6615,6620,6625,6630,6635,6640,6645,6650,6655,6659,6664,6669,6674,6679,6684,6689,6693,6697,6702,6707,6712,6717,6721,6726,6730,6734,6739,6743,6748,6753,6757,6761,6765,6770,6774,6778,6782,6787,6791,6796,6801,6805,6810,6815,6820,6824,6828,6832,6836,6840,6844,6848,6852,6856,6860,6864,6868,6873,6877,6882,6887,6891,6895,6899,6903,6907,6911,6915,6919,6924,6928,6932,6936,6940,6944,6949,6953,6957,6961,6965,6969,6973,6977,6981,6985,6989,6993,6997,7001,7005,7009,7013,7017,7021,7025,7029,7033,7037,7042,7047,7051,7055,7059,7064,7068,7072,7076,7081,7085,7090,7094,7098,7103,7107,7111,7116,7120,7125,7130,7135,7140,7145,7150,7155,7159,7164,7168,7172,7176,7180,7184,7188,7192,7196,7200,7204,7208,7212,7216,7220,7224,7228,7232,7236,7240,7244,7248,7252,7256,7260,7264,7268,7272,7276,7280,7284,7288,7292,7296,7300,7304,7308,7312,7316,7321,7326,7331,7336,7341,7346,7351,7356,7361,7366,7371,7376,7381,7386,7391,7396,7401,7406,7411,7416,7421,7426,7431],{"__ignoreMap":269},[314,6597,6598],{"class":316,"line":317},[314,6599,6600],{},"package com.jxh.tool;\n",[314,6602,6603],{"class":316,"line":270},[314,6604,1716],{"emptyLinePlaceholder":287},[314,6606,6607],{"class":316,"line":278},[314,6608,6609],{},"import org.apache.http.HttpResponse;\n",[314,6611,6612],{"class":316,"line":513},[314,6613,6614],{},"import org.apache.http.client.methods.HttpGet;\n",[314,6616,6617],{"class":316,"line":535},[314,6618,6619],{},"import org.apache.http.impl.client.CloseableHttpClient;\n",[314,6621,6622],{"class":316,"line":543},[314,6623,6624],{},"import org.apache.http.impl.client.HttpClients;\n",[314,6626,6627],{"class":316,"line":554},[314,6628,6629],{},"import org.apache.http.util.EntityUtils;\n",[314,6631,6632],{"class":316,"line":560},[314,6633,6634],{},"import org.dom4j.Document;\n",[314,6636,6637],{"class":316,"line":574},[314,6638,6639],{},"import org.dom4j.DocumentException;\n",[314,6641,6642],{"class":316,"line":588},[314,6643,6644],{},"import org.dom4j.DocumentHelper;\n",[314,6646,6647],{"class":316,"line":602},[314,6648,6649],{},"import org.dom4j.Element;\n",[314,6651,6652],{"class":316,"line":1404},[314,6653,6654],{},"import org.dom4j.dom.DOMElement;\n",[314,6656,6657],{"class":316,"line":1477},[314,6658,1716],{"emptyLinePlaceholder":287},[314,6660,6661],{"class":316,"line":1483},[314,6662,6663],{},"import java.io.File;\n",[314,6665,6666],{"class":316,"line":1489},[314,6667,6668],{},"import java.io.FileInputStream;\n",[314,6670,6671],{"class":316,"line":1495},[314,6672,6673],{},"import java.io.IOException;\n",[314,6675,6676],{"class":316,"line":1501},[314,6677,6678],{},"import java.math.BigInteger;\n",[314,6680,6681],{"class":316,"line":1507},[314,6682,6683],{},"import java.security.MessageDigest;\n",[314,6685,6686],{"class":316,"line":1512},[314,6687,6688],{},"import java.util.jar.*;\n",[314,6690,6691],{"class":316,"line":1518},[314,6692,1716],{"emptyLinePlaceholder":287},[314,6694,6695],{"class":316,"line":1523},[314,6696,1750],{},[314,6698,6699],{"class":316,"line":1758},[314,6700,6701],{}," * 通过Jar包SHA1或MD5生成Pom文件\n",[314,6703,6704],{"class":316,"line":1764},[314,6705,6706],{}," *\n",[314,6708,6709],{"class":316,"line":1770},[314,6710,6711],{}," * @author JiaXiaohei\n",[314,6713,6714],{"class":316,"line":1776},[314,6715,6716],{}," * @date 2018-03-16\n",[314,6718,6719],{"class":316,"line":1781},[314,6720,1761],{},[314,6722,6723],{"class":316,"line":1787},[314,6724,6725],{},"public class Jar2pom {\n",[314,6727,6728],{"class":316,"line":1792},[314,6729,1716],{"emptyLinePlaceholder":287},[314,6731,6732],{"class":316,"line":1798},[314,6733,1879],{},[314,6735,6736],{"class":316,"line":1804},[314,6737,6738],{},"     * Maven库\n",[314,6740,6741],{"class":316,"line":1809},[314,6742,1903],{},[314,6744,6745],{"class":316,"line":1814},[314,6746,6747],{},"    \u002F\u002Fpublic static final String nexusUrl = \"http:\u002F\u002Fmaven.aliyun.com\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n",[314,6749,6750],{"class":316,"line":1820},[314,6751,6752],{},"    public static final String nexusUrl = \"http:\u002F\u002F59.110.144.164\u002Fnexus\u002Fservice\u002Flocal\u002Flucene\u002Fsearch\";\n",[314,6754,6755],{"class":316,"line":1825},[314,6756,1716],{"emptyLinePlaceholder":287},[314,6758,6759],{"class":316,"line":1831},[314,6760,1716],{"emptyLinePlaceholder":287},[314,6762,6763],{"class":316,"line":1836},[314,6764,3709],{},[314,6766,6767],{"class":316,"line":1842},[314,6768,6769],{},"    \u002F\u002F先通过Jar的SHA1查询 如果不存在则解析Manifest查询\n",[314,6771,6772],{"class":316,"line":1847},[314,6773,3719],{},[314,6775,6776],{"class":316,"line":1853},[314,6777,3724],{},[314,6779,6780],{"class":316,"line":1859},[314,6781,3733],{},[314,6783,6784],{"class":316,"line":1865},[314,6785,6786],{},"            if (!getPomByChecksum(jar).isTextOnly()) {\n",[314,6788,6789],{"class":316,"line":1871},[314,6790,3752],{},[314,6792,6793],{"class":316,"line":1876},[314,6794,6795],{},"                System.out.println(getPomByChecksum(jar).asXML());\n",[314,6797,6798],{"class":316,"line":1882},[314,6799,6800],{},"            } else if (!getPomByManifest(jar).isTextOnly()) {\n",[314,6802,6803],{"class":316,"line":1888},[314,6804,3784],{},[314,6806,6807],{"class":316,"line":1894},[314,6808,6809],{},"                System.out.println(getPomByManifest(jar).asXML());\n",[314,6811,6812],{"class":316,"line":1900},[314,6813,6814],{},"            } else {\n",[314,6816,6817],{"class":316,"line":1906},[314,6818,6819],{},"                System.out.println(\"\u003C!--  No data was found -->\");\n",[314,6821,6822],{"class":316,"line":1912},[314,6823,2101],{},[314,6825,6826],{"class":316,"line":1918},[314,6827,3814],{},[314,6829,6830],{"class":316,"line":1923},[314,6831,2269],{},[314,6833,6834],{"class":316,"line":1928},[314,6835,1716],{"emptyLinePlaceholder":287},[314,6837,6838],{"class":316,"line":1933},[314,6839,1868],{},[314,6841,6842],{"class":316,"line":1939},[314,6843,1716],{"emptyLinePlaceholder":287},[314,6845,6846],{"class":316,"line":1944},[314,6847,1879],{},[314,6849,6850],{"class":316,"line":1949},[314,6851,3839],{},[314,6853,6854],{"class":316,"line":1954},[314,6855,1891],{},[314,6857,6858],{"class":316,"line":1960},[314,6859,3848],{},[314,6861,6862],{"class":316,"line":1966},[314,6863,1897],{},[314,6865,6866],{"class":316,"line":1971},[314,6867,1903],{},[314,6869,6870],{"class":316,"line":1976},[314,6871,6872],{},"    public static Element getPomByChecksum(File file) {\n",[314,6874,6875],{"class":316,"line":1981},[314,6876,3875],{},[314,6878,6879],{"class":316,"line":1987},[314,6880,6881],{},"        String xml = doGet(nexusUrl + \"?sha1=\" + checkSum);\n",[314,6883,6884],{"class":316,"line":1992},[314,6885,6886],{},"        return assemblePomElement(xml);\n",[314,6888,6889],{"class":316,"line":1998},[314,6890,1868],{},[314,6892,6893],{"class":316,"line":2003},[314,6894,1716],{"emptyLinePlaceholder":287},[314,6896,6897],{"class":316,"line":2009},[314,6898,1879],{},[314,6900,6901],{"class":316,"line":2015},[314,6902,3929],{},[314,6904,6905],{"class":316,"line":2021},[314,6906,1891],{},[314,6908,6909],{"class":316,"line":2027},[314,6910,3848],{},[314,6912,6913],{"class":316,"line":2033},[314,6914,1897],{},[314,6916,6917],{"class":316,"line":2039},[314,6918,1903],{},[314,6920,6921],{"class":316,"line":2045},[314,6922,6923],{},"    public static Element getPomByManifest(File file) {\n",[314,6925,6926],{"class":316,"line":2051},[314,6927,3963],{},[314,6929,6930],{"class":316,"line":2057},[314,6931,3968],{},[314,6933,6934],{"class":316,"line":2063},[314,6935,3973],{},[314,6937,6938],{"class":316,"line":2069},[314,6939,3978],{},[314,6941,6942],{"class":316,"line":2074},[314,6943,3983],{},[314,6945,6946],{"class":316,"line":2080},[314,6947,6948],{},"                return new DOMElement(\"dependency\");\n",[314,6950,6951],{"class":316,"line":2086},[314,6952,2101],{},[314,6954,6955],{"class":316,"line":2092},[314,6956,3997],{},[314,6958,6959],{"class":316,"line":2098},[314,6960,4002],{},[314,6962,6963],{"class":316,"line":2104},[314,6964,4007],{},[314,6966,6967],{"class":316,"line":2110},[314,6968,4012],{},[314,6970,6971],{"class":316,"line":2115},[314,6972,4017],{},[314,6974,6975],{"class":316,"line":2120},[314,6976,4022],{},[314,6978,6979],{"class":316,"line":2125},[314,6980,4027],{},[314,6982,6983],{"class":316,"line":2131},[314,6984,2101],{},[314,6986,6987],{"class":316,"line":2136},[314,6988,4036],{},[314,6990,6991],{"class":316,"line":2142},[314,6992,4041],{},[314,6994,6995],{"class":316,"line":2147},[314,6996,2101],{},[314,6998,6999],{"class":316,"line":2152},[314,7000,4050],{},[314,7002,7003],{"class":316,"line":2158},[314,7004,4055],{},[314,7006,7007],{"class":316,"line":2164},[314,7008,4060],{},[314,7010,7011],{"class":316,"line":2170},[314,7012,4065],{},[314,7014,7015],{"class":316,"line":2176},[314,7016,4070],{},[314,7018,7019],{"class":316,"line":2182},[314,7020,4075],{},[314,7022,7023],{"class":316,"line":2188},[314,7024,2101],{},[314,7026,7027],{"class":316,"line":2193},[314,7028,4084],{},[314,7030,7031],{"class":316,"line":2198},[314,7032,4089],{},[314,7034,7035],{"class":316,"line":2203},[314,7036,2101],{},[314,7038,7039],{"class":316,"line":2209},[314,7040,7041],{},"            String xml = doGet(nexusUrl + \"?a=\" + a + \"&v=\" + v);\n",[314,7043,7044],{"class":316,"line":2214},[314,7045,7046],{},"            return assemblePomElement(xml);\n",[314,7048,7049],{"class":316,"line":2220},[314,7050,4126],{},[314,7052,7053],{"class":316,"line":2226},[314,7054,4131],{},[314,7056,7057],{"class":316,"line":2231},[314,7058,2269],{},[314,7060,7061],{"class":316,"line":2236},[314,7062,7063],{},"        return new DOMElement(\"dependency\");\n",[314,7065,7066],{"class":316,"line":2242},[314,7067,1868],{},[314,7069,7070],{"class":316,"line":2248},[314,7071,1716],{"emptyLinePlaceholder":287},[314,7073,7074],{"class":316,"line":2254},[314,7075,1879],{},[314,7077,7078],{"class":316,"line":2260},[314,7079,7080],{},"     * 解析获取的XML 组装dependency\n",[314,7082,7083],{"class":316,"line":2266},[314,7084,1891],{},[314,7086,7087],{"class":316,"line":2272},[314,7088,7089],{},"     * @param xml\n",[314,7091,7092],{"class":316,"line":2278},[314,7093,1897],{},[314,7095,7096],{"class":316,"line":2283},[314,7097,1903],{},[314,7099,7100],{"class":316,"line":2288},[314,7101,7102],{},"    public static Element assemblePomElement(String xml) {\n",[314,7104,7105],{"class":316,"line":4236},[314,7106,4183],{},[314,7108,7109],{"class":316,"line":4242},[314,7110,1716],{"emptyLinePlaceholder":287},[314,7112,7113],{"class":316,"line":4247},[314,7114,7115],{},"        if (xml != null && xml.length() != 0) {\n",[314,7117,7118],{"class":316,"line":4252},[314,7119,4312],{},[314,7121,7122],{"class":316,"line":4258},[314,7123,7124],{},"                Document document = DocumentHelper.parseText(xml);\n",[314,7126,7127],{"class":316,"line":4264},[314,7128,7129],{},"                Element dataElement = document.getRootElement().element(\"data\");\n",[314,7131,7132],{"class":316,"line":4270},[314,7133,7134],{},"                if (dataElement.getText() != null && dataElement.getText().length() != 0) {\n",[314,7136,7137],{"class":316,"line":4276},[314,7138,7139],{},"                    Element artifactElement = dataElement.element(\"artifact\");\n",[314,7141,7142],{"class":316,"line":4281},[314,7143,7144],{},"                    dependency.add((Element) artifactElement.element(\"groupId\").clone());\n",[314,7146,7147],{"class":316,"line":4287},[314,7148,7149],{},"                    dependency.add((Element) artifactElement.element(\"artifactId\").clone());\n",[314,7151,7152],{"class":316,"line":4293},[314,7153,7154],{},"                    dependency.add((Element) artifactElement.element(\"version\").clone());\n",[314,7156,7157],{"class":316,"line":4298},[314,7158,2048],{},[314,7160,7161],{"class":316,"line":4303},[314,7162,7163],{},"            } catch (DocumentException e) {\n",[314,7165,7166],{"class":316,"line":4309},[314,7167,4330],{},[314,7169,7170],{"class":316,"line":4315},[314,7171,2101],{},[314,7173,7174],{"class":316,"line":4321},[314,7175,2269],{},[314,7177,7178],{"class":316,"line":4327},[314,7179,4212],{},[314,7181,7182],{"class":316,"line":4333},[314,7183,1868],{},[314,7185,7186],{"class":316,"line":4338},[314,7187,1716],{"emptyLinePlaceholder":287},[314,7189,7190],{"class":316,"line":4343},[314,7191,1879],{},[314,7193,7194],{"class":316,"line":4349},[314,7195,4229],{},[314,7197,7198],{"class":316,"line":4354},[314,7199,1891],{},[314,7201,7202],{"class":316,"line":4359},[314,7203,4239],{},[314,7205,7206],{"class":316,"line":4364},[314,7207,1897],{},[314,7209,7210],{"class":316,"line":4370},[314,7211,1903],{},[314,7213,7214],{"class":316,"line":4375},[314,7215,4255],{},[314,7217,7218],{"class":316,"line":4380},[314,7219,4261],{},[314,7221,7222],{"class":316,"line":4386},[314,7223,4267],{},[314,7225,7226],{"class":316,"line":4391},[314,7227,4273],{},[314,7229,7230],{"class":316,"line":4396},[314,7231,3963],{},[314,7233,7234],{"class":316,"line":4402},[314,7235,4284],{},[314,7237,7238],{"class":316,"line":4408},[314,7239,4290],{},[314,7241,7242],{"class":316,"line":4414},[314,7243,4126],{},[314,7245,7246],{"class":316,"line":4419},[314,7247,4131],{},[314,7249,7250],{"class":316,"line":4425},[314,7251,4306],{},[314,7253,7254],{"class":316,"line":4431},[314,7255,4312],{},[314,7257,7258],{"class":316,"line":4437},[314,7259,4318],{},[314,7261,7262],{"class":316,"line":4443},[314,7263,4324],{},[314,7265,7266],{"class":316,"line":4448},[314,7267,4330],{},[314,7269,7270],{"class":316,"line":4454},[314,7271,2101],{},[314,7273,7274],{"class":316,"line":4460},[314,7275,2269],{},[314,7277,7278],{"class":316,"line":4466},[314,7279,4346],{},[314,7281,7282],{"class":316,"line":4472},[314,7283,1868],{},[314,7285,7286],{"class":316,"line":4477},[314,7287,1716],{"emptyLinePlaceholder":287},[314,7289,7290],{"class":316,"line":4483},[314,7291,1879],{},[314,7293,7294],{"class":316,"line":4489},[314,7295,4367],{},[314,7297,7298],{"class":316,"line":4494},[314,7299,1891],{},[314,7301,7302],{"class":316,"line":4499},[314,7303,3848],{},[314,7305,7306],{"class":316,"line":4504},[314,7307,4383],{},[314,7309,7310],{"class":316,"line":4510},[314,7311,1897],{},[314,7313,7314],{"class":316,"line":4516},[314,7315,1903],{},[314,7317,7319],{"class":316,"line":7318},168,[314,7320,4399],{},[314,7322,7324],{"class":316,"line":7323},169,[314,7325,4405],{},[314,7327,7329],{"class":316,"line":7328},170,[314,7330,4411],{},[314,7332,7334],{"class":316,"line":7333},171,[314,7335,2269],{},[314,7337,7339],{"class":316,"line":7338},172,[314,7340,4422],{},[314,7342,7344],{"class":316,"line":7343},173,[314,7345,4428],{},[314,7347,7349],{"class":316,"line":7348},174,[314,7350,4434],{},[314,7352,7354],{"class":316,"line":7353},175,[314,7355,4440],{},[314,7357,7359],{"class":316,"line":7358},176,[314,7360,3963],{},[314,7362,7364],{"class":316,"line":7363},177,[314,7365,4451],{},[314,7367,7369],{"class":316,"line":7368},178,[314,7370,4457],{},[314,7372,7374],{"class":316,"line":7373},179,[314,7375,4463],{},[314,7377,7379],{"class":316,"line":7378},180,[314,7380,4469],{},[314,7382,7384],{"class":316,"line":7383},181,[314,7385,2101],{},[314,7387,7389],{"class":316,"line":7388},182,[314,7390,4480],{},[314,7392,7394],{"class":316,"line":7393},183,[314,7395,4486],{},[314,7397,7399],{"class":316,"line":7398},184,[314,7400,4131],{},[314,7402,7404],{"class":316,"line":7403},185,[314,7405,4411],{},[314,7407,7409],{"class":316,"line":7408},186,[314,7410,2269],{},[314,7412,7414],{"class":316,"line":7413},187,[314,7415,4507],{},[314,7417,7419],{"class":316,"line":7418},188,[314,7420,4513],{},[314,7422,7424],{"class":316,"line":7423},189,[314,7425,1868],{},[314,7427,7429],{"class":316,"line":7428},190,[314,7430,1716],{"emptyLinePlaceholder":287},[314,7432,7434],{"class":316,"line":7433},191,[314,7435,1191],{},[24,7437,7439],{"id":7438},"依赖-jar","依赖 Jar",[306,7441,7445],{"className":7442,"code":7443,"language":7444,"meta":269,"style":269},"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",[132,7446,7447,7452,7457,7462,7467,7472,7476,7480,7485,7490,7495],{"__ignoreMap":269},[314,7448,7449],{"class":316,"line":317},[314,7450,7451],{},"        \u003Cdependency>\n",[314,7453,7454],{"class":316,"line":270},[314,7455,7456],{},"            \u003CgroupId>org.apache.httpcomponents\u003C\u002FgroupId>\n",[314,7458,7459],{"class":316,"line":278},[314,7460,7461],{},"            \u003CartifactId>httpclient\u003C\u002FartifactId>\n",[314,7463,7464],{"class":316,"line":513},[314,7465,7466],{},"            \u003Cversion>4.5.5\u003C\u002Fversion>\n",[314,7468,7469],{"class":316,"line":535},[314,7470,7471],{},"        \u003C\u002Fdependency>\n",[314,7473,7474],{"class":316,"line":543},[314,7475,1716],{"emptyLinePlaceholder":287},[314,7477,7478],{"class":316,"line":554},[314,7479,7451],{},[314,7481,7482],{"class":316,"line":560},[314,7483,7484],{},"            \u003CgroupId>org.dom4j\u003C\u002FgroupId>\n",[314,7486,7487],{"class":316,"line":574},[314,7488,7489],{},"            \u003CartifactId>dom4j\u003C\u002FartifactId>\n",[314,7491,7492],{"class":316,"line":588},[314,7493,7494],{},"            \u003Cversion>[2.1.1,)\u003C\u002Fversion>\n",[314,7496,7497],{"class":316,"line":602},[314,7498,7471],{},[24,7500,7501],{"id":7501},"开发环境",[306,7503,7506],{"className":7504,"code":7505,"language":1061},[1059],"jdk1.7.0_80\napache-maven-3.5.0\nIntelliJ IDEA Community Edition 2017.1.4 x64\n",[132,7507,7505],{"__ignoreMap":269},[673,7509,1536],{},{"title":269,"searchDepth":270,"depth":270,"links":7511},[7512,7513],{"id":7438,"depth":270,"text":7439},{"id":7501,"depth":270,"text":7501},"2018-03-18","给非 Maven 项目的一堆本地 jar 生成 dependency。用 jar 的 SHA1 去 Nexus OSS 2 的 lucene 接口反查坐标，查不到再退回解析 Manifest。",{},{"title":3654,"description":7515},"posts\u002Fjar2pom-nexus2-dependency",[4919,1321,295],"U-hZXreFP_8qOUmHlunA2VlS8As0p2eZxV55ZMOgpjc",{"id":7522,"title":7523,"body":7524,"date":7919,"description":7920,"extension":285,"meta":7921,"navigation":287,"path":7922,"seo":7923,"stem":7924,"tags":7925,"__hash__":7928},"posts\u002Fposts\u002Foracle-sort-positive-negative.md","ORACLE 正负数分开排序 SQL",{"type":8,"value":7525,"toc":7913},[7526,7529,7558,7561,7601,7671,7675,7695,7720,7797,7801,7819,7841,7911],[24,7527,7528],{"id":7528},"表结构",[306,7530,7532],{"className":930,"code":7531,"language":932,"meta":269,"style":269},"create table TEST_ORDER\n(\n  t_name  VARCHAR2(5),\n  t_value NUMBER(3)\n);\n",[132,7533,7534,7539,7544,7549,7554],{"__ignoreMap":269},[314,7535,7536],{"class":316,"line":317},[314,7537,7538],{},"create table TEST_ORDER\n",[314,7540,7541],{"class":316,"line":270},[314,7542,7543],{},"(\n",[314,7545,7546],{"class":316,"line":278},[314,7547,7548],{},"  t_name  VARCHAR2(5),\n",[314,7550,7551],{"class":316,"line":513},[314,7552,7553],{},"  t_value NUMBER(3)\n",[314,7555,7556],{"class":316,"line":535},[314,7557,989],{},[24,7559,7560],{"id":7560},"表数据",[306,7562,7564],{"className":930,"code":7563,"language":932,"meta":269,"style":269},"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",[132,7565,7566,7571,7576,7581,7586,7591,7596],{"__ignoreMap":269},[314,7567,7568],{"class":316,"line":317},[314,7569,7570],{},"insert into TEST_ORDER (t_name, t_value) values ('A', 10);\n",[314,7572,7573],{"class":316,"line":270},[314,7574,7575],{},"insert into TEST_ORDER (t_name, t_value) values ('B', 30);\n",[314,7577,7578],{"class":316,"line":278},[314,7579,7580],{},"insert into TEST_ORDER (t_name, t_value) values ('C', 20);\n",[314,7582,7583],{"class":316,"line":513},[314,7584,7585],{},"insert into TEST_ORDER (t_name, t_value) values ('D', 40);\n",[314,7587,7588],{"class":316,"line":535},[314,7589,7590],{},"insert into TEST_ORDER (t_name, t_value) values ('E', -10);\n",[314,7592,7593],{"class":316,"line":543},[314,7594,7595],{},"insert into TEST_ORDER (t_name, t_value) values ('F', -30);\n",[314,7597,7598],{"class":316,"line":554},[314,7599,7600],{},"insert into TEST_ORDER (t_name, t_value) values ('G', -20);\n",[4543,7602,7603,7613],{},[4546,7604,7605],{},[4549,7606,7607,7610],{},[4552,7608,7609],{},"T_NAME",[4552,7611,7612],{},"T_VALUE",[4565,7614,7615,7623,7631,7639,7647,7655,7663],{},[4549,7616,7617,7620],{},[4570,7618,7619],{},"A",[4570,7621,7622],{},"10",[4549,7624,7625,7628],{},[4570,7626,7627],{},"B",[4570,7629,7630],{},"30",[4549,7632,7633,7636],{},[4570,7634,7635],{},"C",[4570,7637,7638],{},"20",[4549,7640,7641,7644],{},[4570,7642,7643],{},"D",[4570,7645,7646],{},"40",[4549,7648,7649,7652],{},[4570,7650,7651],{},"E",[4570,7653,7654],{},"-10",[4549,7656,7657,7660],{},[4570,7658,7659],{},"F",[4570,7661,7662],{},"-30",[4549,7664,7665,7668],{},[4570,7666,7667],{},"G",[4570,7669,7670],{},"-20",[24,7672,7674],{"id":7673},"先正后负-正数升序-负数降序","先正后负 正数升序 负数降序",[306,7676,7678],{"className":930,"code":7677,"language":932,"meta":269,"style":269},"SELECT T_NAME, T_VALUE\n  FROM TEST_ORDER\n ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC;\n",[132,7679,7680,7685,7690],{"__ignoreMap":269},[314,7681,7682],{"class":316,"line":317},[314,7683,7684],{},"SELECT T_NAME, T_VALUE\n",[314,7686,7687],{"class":316,"line":270},[314,7688,7689],{},"  FROM TEST_ORDER\n",[314,7691,7692],{"class":316,"line":278},[314,7693,7694],{}," ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC;\n",[306,7696,7698],{"className":930,"code":7697,"language":932,"meta":269,"style":269},"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",[132,7699,7700,7705,7710,7715],{"__ignoreMap":269},[314,7701,7702],{"class":316,"line":317},[314,7703,7704],{},"SELECT T_NAME,\n",[314,7706,7707],{"class":316,"line":270},[314,7708,7709],{},"       T_VALUE,\n",[314,7711,7712],{"class":316,"line":278},[314,7713,7714],{},"       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) ASC) AS RANKING\n",[314,7716,7717],{"class":316,"line":513},[314,7718,7719],{},"  FROM TEST_ORDER;\n",[4543,7721,7722,7733],{},[4546,7723,7724],{},[4549,7725,7726,7728,7730],{},[4552,7727,7609],{},[4552,7729,7612],{},[4552,7731,7732],{},"RANKING",[4565,7734,7735,7743,7752,7761,7770,7779,7788],{},[4549,7736,7737,7739,7741],{},[4570,7738,7619],{},[4570,7740,7622],{},[4570,7742,895],{},[4549,7744,7745,7747,7749],{},[4570,7746,7635],{},[4570,7748,7638],{},[4570,7750,7751],{},"2",[4549,7753,7754,7756,7758],{},[4570,7755,7627],{},[4570,7757,7630],{},[4570,7759,7760],{},"3",[4549,7762,7763,7765,7767],{},[4570,7764,7643],{},[4570,7766,7646],{},[4570,7768,7769],{},"4",[4549,7771,7772,7774,7776],{},[4570,7773,7651],{},[4570,7775,7654],{},[4570,7777,7778],{},"5",[4549,7780,7781,7783,7785],{},[4570,7782,7667],{},[4570,7784,7670],{},[4570,7786,7787],{},"6",[4549,7789,7790,7792,7794],{},[4570,7791,7659],{},[4570,7793,7662],{},[4570,7795,7796],{},"7",[24,7798,7800],{"id":7799},"先正后负-正数降序-负数升序","先正后负 正数降序 负数升序",[306,7802,7804],{"className":930,"code":7803,"language":932,"meta":269,"style":269},"SELECT T_NAME, T_VALUE\n  FROM TEST_ORDER\n ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC;\n",[132,7805,7806,7810,7814],{"__ignoreMap":269},[314,7807,7808],{"class":316,"line":317},[314,7809,7684],{},[314,7811,7812],{"class":316,"line":270},[314,7813,7689],{},[314,7815,7816],{"class":316,"line":278},[314,7817,7818],{}," ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC;\n",[306,7820,7822],{"className":930,"code":7821,"language":932,"meta":269,"style":269},"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",[132,7823,7824,7828,7832,7837],{"__ignoreMap":269},[314,7825,7826],{"class":316,"line":317},[314,7827,7704],{},[314,7829,7830],{"class":316,"line":270},[314,7831,7709],{},[314,7833,7834],{"class":316,"line":278},[314,7835,7836],{},"       RANK() OVER(ORDER BY SIGN(T_VALUE) DESC, ABS(T_VALUE) DESC) AS RANKING\n",[314,7838,7839],{"class":316,"line":513},[314,7840,7719],{},[4543,7842,7843,7853],{},[4546,7844,7845],{},[4549,7846,7847,7849,7851],{},[4552,7848,7609],{},[4552,7850,7612],{},[4552,7852,7732],{},[4565,7854,7855,7863,7871,7879,7887,7895,7903],{},[4549,7856,7857,7859,7861],{},[4570,7858,7643],{},[4570,7860,7646],{},[4570,7862,895],{},[4549,7864,7865,7867,7869],{},[4570,7866,7627],{},[4570,7868,7630],{},[4570,7870,7751],{},[4549,7872,7873,7875,7877],{},[4570,7874,7635],{},[4570,7876,7638],{},[4570,7878,7760],{},[4549,7880,7881,7883,7885],{},[4570,7882,7619],{},[4570,7884,7622],{},[4570,7886,7769],{},[4549,7888,7889,7891,7893],{},[4570,7890,7659],{},[4570,7892,7662],{},[4570,7894,7778],{},[4549,7896,7897,7899,7901],{},[4570,7898,7667],{},[4570,7900,7670],{},[4570,7902,7787],{},[4549,7904,7905,7907,7909],{},[4570,7906,7651],{},[4570,7908,7654],{},[4570,7910,7796],{},[673,7912,1536],{},{"title":269,"searchDepth":270,"depth":270,"links":7914},[7915,7916,7917,7918],{"id":7528,"depth":270,"text":7528},{"id":7560,"depth":270,"text":7560},{"id":7673,"depth":270,"text":7674},{"id":7799,"depth":270,"text":7800},"2017-09-12","用 SIGN() 把正数和负数分成两组，再各自按绝对值升序或降序排。附 RANK() 版本。",{},"\u002Fposts\u002Foracle-sort-positive-negative",{"title":7523,"description":7920},"posts\u002Foracle-sort-positive-negative",[7926,7927],"Oracle","SQL","9V1MVwXuVwjJ4oNgm5p6skDOU5MF6ROWQUpk-Wwqlak",{"id":7930,"title":7931,"body":7932,"date":9481,"description":9482,"extension":285,"meta":9483,"navigation":287,"path":9484,"seo":9485,"stem":9486,"tags":9487,"__hash__":9491},"posts\u002Fposts\u002Fcentos7-hadoop-spark-cluster-setup.md","CentOS7 下 Hadoop 2.7.3 + Spark 2.1.0 集群环境搭建",{"type":8,"value":7933,"toc":9444},[7934,7936,7985,7989,8045,8047,8068,8072,8085,8150,8154,8158,8178,8182,8185,8198,8207,8210,8222,8226,8269,8273,8304,8308,8328,8331,8335,8338,8354,8357,8391,8395,8398,8424,8428,8440,8443,8467,8471,8476,8572,8577,8592,8597,8624,8629,8682,8687,8772,8777,8793,8860,8865,8937,8941,8957,8961,8964,8968,8977,8981,8990,8994,9009,9013,9016,9028,9032,9044,9047,9070,9073,9077,9115,9120,9135,9199,9203,9215,9219,9222,9226,9235,9239,9241,9245,9248,9410,9412,9441],[24,7935,2332],{"id":2332},[4543,7937,7938,7951],{},[4546,7939,7940],{},[4549,7941,7942,7945,7948],{},[4552,7943,7944],{},"主机名",[4552,7946,7947],{},"ip",[4552,7949,7950],{},"进程",[4565,7952,7953,7964,7975],{},[4549,7954,7955,7958,7961],{},[4570,7956,7957],{},"nn.hadoop.data.example.net",[4570,7959,7960],{},"172.16.156.220",[4570,7962,7963],{},"NameNode、Master、ResourceManager、SecondaryNameNode、JobHistoryServer",[4549,7965,7966,7969,7972],{},[4570,7967,7968],{},"dn1.hadoop.data.example.net",[4570,7970,7971],{},"172.16.156.221",[4570,7973,7974],{},"NodeManager、DataNode、Worker",[4549,7976,7977,7980,7983],{},[4570,7978,7979],{},"dn2.hadoop.data.example.net",[4570,7981,7982],{},"172.16.156.222",[4570,7984,7974],{},[154,7986,7988],{"id":7987},"yum-安装如下包可能有部分包用不到","yum 安装如下包（可能有部分包用不到）",[306,7990,7992],{"className":308,"code":7991,"language":310,"meta":269,"style":269},"yum install pcre-devel openssl openssl-devel openssh-clients htop gcc zlib lrzsz zip unzip vim telnet-server ncurses wget net-tools\n",[132,7993,7994],{"__ignoreMap":269},[314,7995,7996,7998,8000,8003,8006,8009,8012,8015,8018,8021,8024,8027,8030,8033,8036,8039,8042],{"class":316,"line":317},[314,7997,3617],{"class":320},[314,7999,2555],{"class":324},[314,8001,8002],{"class":324}," pcre-devel",[314,8004,8005],{"class":324}," openssl",[314,8007,8008],{"class":324}," openssl-devel",[314,8010,8011],{"class":324}," openssh-clients",[314,8013,8014],{"class":324}," htop",[314,8016,8017],{"class":324}," gcc",[314,8019,8020],{"class":324}," zlib",[314,8022,8023],{"class":324}," lrzsz",[314,8025,8026],{"class":324}," zip",[314,8028,8029],{"class":324}," unzip",[314,8031,8032],{"class":324}," vim",[314,8034,8035],{"class":324}," telnet-server",[314,8037,8038],{"class":324}," ncurses",[314,8040,8041],{"class":324}," wget",[314,8043,8044],{"class":324}," net-tools\n",[154,8046,331],{"id":331},[306,8048,8050],{"className":308,"code":8049,"language":310,"meta":269,"style":269},"systemctl stop firewalld.service\nsystemctl disable firewalld.service\n",[132,8051,8052,8060],{"__ignoreMap":269},[314,8053,8054,8056,8058],{"class":316,"line":317},[314,8055,321],{"class":320},[314,8057,343],{"class":324},[314,8059,328],{"class":324},[314,8061,8062,8064,8066],{"class":316,"line":270},[314,8063,321],{"class":320},[314,8065,394],{"class":324},[314,8067,328],{"class":324},[154,8069,8071],{"id":8070},"配置-hosts-文件","配置 hosts 文件",[306,8073,8075],{"className":308,"code":8074,"language":310,"meta":269,"style":269},"vi \u002Fetc\u002Fhosts\n",[132,8076,8077],{"__ignoreMap":269},[314,8078,8079,8082],{"class":316,"line":317},[314,8080,8081],{"class":320},"vi",[314,8083,8084],{"class":324}," \u002Fetc\u002Fhosts\n",[306,8086,8088],{"className":308,"code":8087,"language":310,"meta":269,"style":269},"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",[132,8089,8090,8107,8125,8129,8136,8143],{"__ignoreMap":269},[314,8091,8092,8095,8098,8101,8104],{"class":316,"line":317},[314,8093,8094],{"class":320},"127.0.0.1",[314,8096,8097],{"class":324},"   localhost",[314,8099,8100],{"class":324}," localhost.localdomain",[314,8102,8103],{"class":324}," localhost4",[314,8105,8106],{"class":324}," localhost4.localdomain4\n",[314,8108,8109,8111,8114,8117,8119,8122],{"class":316,"line":270},[314,8110,890],{"class":2601},[314,8112,8113],{"class":324},":1",[314,8115,8116],{"class":324},"         localhost",[314,8118,8100],{"class":324},[314,8120,8121],{"class":324}," localhost6",[314,8123,8124],{"class":324}," localhost6.localdomain6\n",[314,8126,8127],{"class":316,"line":278},[314,8128,1716],{"emptyLinePlaceholder":287},[314,8130,8131,8133],{"class":316,"line":513},[314,8132,7960],{"class":320},[314,8134,8135],{"class":324},"  nn.hadoop.data.example.net\n",[314,8137,8138,8140],{"class":316,"line":535},[314,8139,7971],{"class":320},[314,8141,8142],{"class":324},"  dn1.hadoop.data.example.net\n",[314,8144,8145,8147],{"class":316,"line":543},[314,8146,7982],{"class":320},[314,8148,8149],{"class":324},"  dn2.hadoop.data.example.net\n",[24,8151,8153],{"id":8152},"安装-jdk-和-scala","安装 JDK 和 Scala",[154,8155,8157],{"id":8156},"_0创建文件夹","0.创建文件夹",[306,8159,8161],{"className":308,"code":8160,"language":310,"meta":269,"style":269},"mkdir \u002Fapp\u002Fjava\nmkdir \u002Fapp\u002Fscala\n",[132,8162,8163,8171],{"__ignoreMap":269},[314,8164,8165,8168],{"class":316,"line":317},[314,8166,8167],{"class":320},"mkdir",[314,8169,8170],{"class":324}," \u002Fapp\u002Fjava\n",[314,8172,8173,8175],{"class":316,"line":270},[314,8174,8167],{"class":320},[314,8176,8177],{"class":324}," \u002Fapp\u002Fscala\n",[154,8179,8181],{"id":8180},"_1下载","1.下载",[11,8183,8184],{},"下载 JDK",[306,8186,8188],{"className":308,"code":8187,"language":310,"meta":269,"style":269},"wget http:\u002F\u002Fdownload.oracle.com\u002Fotn-pub\u002Fjava\u002Fjdk\u002F8u121-b13\u002Fe9e7ea248e2c4826b92b3f075a80e441\u002Fjdk-8u121-linux-x64.tar.gz\n",[132,8189,8190],{"__ignoreMap":269},[314,8191,8192,8195],{"class":316,"line":317},[314,8193,8194],{"class":320},"wget",[314,8196,8197],{"class":324}," http:\u002F\u002Fdownload.oracle.com\u002Fotn-pub\u002Fjava\u002Fjdk\u002F8u121-b13\u002Fe9e7ea248e2c4826b92b3f075a80e441\u002Fjdk-8u121-linux-x64.tar.gz\n",[11,8199,8200,8201,8206],{},"如果失效，",[232,8202,8205],{"href":8203,"rel":8204},"http:\u002F\u002Fwww.oracle.com\u002Ftechnetwork\u002Fjava\u002Fjavase\u002Fdownloads\u002Findex.html",[236],"点这里下载"," 并上传至服务器",[11,8208,8209],{},"下载 Scala",[306,8211,8213],{"className":308,"code":8212,"language":310,"meta":269,"style":269},"wget http:\u002F\u002Fdownloads.lightbend.com\u002Fscala\u002F2.12.1\u002Fscala-2.12.1.tgz\n",[132,8214,8215],{"__ignoreMap":269},[314,8216,8217,8219],{"class":316,"line":317},[314,8218,8194],{"class":320},[314,8220,8221],{"class":324}," http:\u002F\u002Fdownloads.lightbend.com\u002Fscala\u002F2.12.1\u002Fscala-2.12.1.tgz\n",[154,8223,8225],{"id":8224},"_2移动解压","2.移动&解压",[306,8227,8229],{"className":308,"code":8228,"language":310,"meta":269,"style":269},"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",[132,8230,8231,8240,8251,8260],{"__ignoreMap":269},[314,8232,8233,8235,8238],{"class":316,"line":317},[314,8234,2610],{"class":320},[314,8236,8237],{"class":324}," jdk-8u121-linux-x64.tar.gz",[314,8239,8170],{"class":324},[314,8241,8242,8245,8248],{"class":316,"line":270},[314,8243,8244],{"class":320},"tar",[314,8246,8247],{"class":324}," -zxvf",[314,8249,8250],{"class":324}," jdk-8u121-linux-x64.tar.gz\n",[314,8252,8253,8255,8258],{"class":316,"line":278},[314,8254,2610],{"class":320},[314,8256,8257],{"class":324}," scala-2.12.1.tgz",[314,8259,8177],{"class":324},[314,8261,8262,8264,8266],{"class":316,"line":513},[314,8263,8244],{"class":320},[314,8265,8247],{"class":324},[314,8267,8268],{"class":324}," scala-2.12.1.tgz\n",[154,8270,8272],{"id":8271},"_3授权","3.授权",[306,8274,8276],{"className":308,"code":8275,"language":310,"meta":269,"style":269},"chmod -R 775 \u002Fapp\u002F\nchown -R hadoop \u002Fapp\u002F\n",[132,8277,8278,8292],{"__ignoreMap":269},[314,8279,8280,8283,8286,8289],{"class":316,"line":317},[314,8281,8282],{"class":320},"chmod",[314,8284,8285],{"class":324}," -R",[314,8287,8288],{"class":2470}," 775",[314,8290,8291],{"class":324}," \u002Fapp\u002F\n",[314,8293,8294,8297,8299,8302],{"class":316,"line":270},[314,8295,8296],{"class":320},"chown",[314,8298,8285],{"class":324},[314,8300,8301],{"class":324}," hadoop",[314,8303,8291],{"class":324},[24,8305,8307],{"id":8306},"创建-hadoop-用户","创建 hadoop 用户",[306,8309,8311],{"className":308,"code":8310,"language":310,"meta":269,"style":269},"useradd hadoop\npasswd hadoop\n",[132,8312,8313,8321],{"__ignoreMap":269},[314,8314,8315,8318],{"class":316,"line":317},[314,8316,8317],{"class":320},"useradd",[314,8319,8320],{"class":324}," hadoop\n",[314,8322,8323,8326],{"class":316,"line":270},[314,8324,8325],{"class":320},"passwd",[314,8327,8320],{"class":324},[11,8329,8330],{},"如无特殊说明 以后均为 hadoop 用户操作",[24,8332,8334],{"id":8333},"ssh-免密登录","SSH 免密登录",[11,8336,8337],{},"生成秘钥：~\u002F.ssh\u002Fid_rsa 和 ~\u002F.ssh\u002Fid_rsa.pub",[306,8339,8341],{"className":308,"code":8340,"language":310,"meta":269,"style":269},"ssh-keygen -t rsa \n",[132,8342,8343],{"__ignoreMap":269},[314,8344,8345,8348,8351],{"class":316,"line":317},[314,8346,8347],{"class":320},"ssh-keygen",[314,8349,8350],{"class":324}," -t",[314,8352,8353],{"class":324}," rsa\n",[11,8355,8356],{},"拷贝公钥到其他机器上",[306,8358,8360],{"className":308,"code":8359,"language":310,"meta":269,"style":269},"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",[132,8361,8362,8373,8382],{"__ignoreMap":269},[314,8363,8364,8367,8370],{"class":316,"line":317},[314,8365,8366],{"class":320},"ssh-copy-id",[314,8368,8369],{"class":324}," -i",[314,8371,8372],{"class":324}," nn.hadoop.data.example.net\n",[314,8374,8375,8377,8379],{"class":316,"line":270},[314,8376,8366],{"class":320},[314,8378,8369],{"class":324},[314,8380,8381],{"class":324}," dn1.hadoop.data.example.net\n",[314,8383,8384,8386,8388],{"class":316,"line":278},[314,8385,8366],{"class":320},[314,8387,8369],{"class":324},[314,8389,8390],{"class":324}," dn2.hadoop.data.example.net\n",[24,8392,8394],{"id":8393},"安装-hadoop","安装 Hadoop",[154,8396,8157],{"id":8397},"_0创建文件夹-1",[306,8399,8401],{"className":308,"code":8400,"language":310,"meta":269,"style":269},"mkdir \u002Fapp\u002Fhadoop\u002Fdata\nmkdir \u002Fapp\u002Fhadoop\u002Fname\nmkdir \u002Fapp\u002Fhadoop\u002Ftmp\n",[132,8402,8403,8410,8417],{"__ignoreMap":269},[314,8404,8405,8407],{"class":316,"line":317},[314,8406,8167],{"class":320},[314,8408,8409],{"class":324}," \u002Fapp\u002Fhadoop\u002Fdata\n",[314,8411,8412,8414],{"class":316,"line":270},[314,8413,8167],{"class":320},[314,8415,8416],{"class":324}," \u002Fapp\u002Fhadoop\u002Fname\n",[314,8418,8419,8421],{"class":316,"line":278},[314,8420,8167],{"class":320},[314,8422,8423],{"class":324}," \u002Fapp\u002Fhadoop\u002Ftmp\n",[154,8425,8427],{"id":8426},"_1下载-hadoop","1.下载 hadoop",[306,8429,8431],{"className":308,"code":8430,"language":310,"meta":269,"style":269},"wget http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.cgi\u002Fhadoop\u002Fcommon\u002Fhadoop-2.7.3\u002Fhadoop-2.7.3.tar.gz\n",[132,8432,8433],{"__ignoreMap":269},[314,8434,8435,8437],{"class":316,"line":317},[314,8436,8194],{"class":320},[314,8438,8439],{"class":324}," http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.cgi\u002Fhadoop\u002Fcommon\u002Fhadoop-2.7.3\u002Fhadoop-2.7.3.tar.gz\n",[154,8441,8225],{"id":8442},"_2移动解压-1",[306,8444,8446],{"className":308,"code":8445,"language":310,"meta":269,"style":269},"mv hadoop-2.7.3.tar.gz \u002Fapp\u002Fhadoop\ntar -zxvf hadoop-2.7.3.tar.gz\n",[132,8447,8448,8458],{"__ignoreMap":269},[314,8449,8450,8452,8455],{"class":316,"line":317},[314,8451,2610],{"class":320},[314,8453,8454],{"class":324}," hadoop-2.7.3.tar.gz",[314,8456,8457],{"class":324}," \u002Fapp\u002Fhadoop\n",[314,8459,8460,8462,8464],{"class":316,"line":270},[314,8461,8244],{"class":320},[314,8463,8247],{"class":324},[314,8465,8466],{"class":324}," hadoop-2.7.3.tar.gz\n",[154,8468,8470],{"id":8469},"_3修改配置文件","3.修改配置文件",[11,8472,8473],{},[41,8474,8475],{},"\u002Fetc\u002Fprofile（root 权限）",[306,8477,8479],{"className":308,"code":8478,"language":310,"meta":269,"style":269},"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",[132,8480,8481,8491,8504,8515,8526,8537,8548,8560],{"__ignoreMap":269},[314,8482,8483,8486,8488],{"class":316,"line":317},[314,8484,8485],{"class":875},"HADOOP_HOME",[314,8487,5519],{"class":525},[314,8489,8490],{"class":324},"\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\n",[314,8492,8493,8496,8499,8501],{"class":316,"line":270},[314,8494,8495],{"class":885},"export",[314,8497,8498],{"class":875}," HADOOP_INSTALL",[314,8500,5519],{"class":525},[314,8502,8503],{"class":875},"$HADOOP_HOME\n",[314,8505,8506,8508,8511,8513],{"class":316,"line":278},[314,8507,8495],{"class":885},[314,8509,8510],{"class":875}," HADOOP_MAPRED_HOME",[314,8512,5519],{"class":525},[314,8514,8503],{"class":875},[314,8516,8517,8519,8522,8524],{"class":316,"line":513},[314,8518,8495],{"class":885},[314,8520,8521],{"class":875}," HADOOP_COMMON_HOME",[314,8523,5519],{"class":525},[314,8525,8503],{"class":875},[314,8527,8528,8530,8533,8535],{"class":316,"line":535},[314,8529,8495],{"class":885},[314,8531,8532],{"class":875}," HADOOP_HDFS_HOME",[314,8534,5519],{"class":525},[314,8536,8503],{"class":875},[314,8538,8539,8541,8544,8546],{"class":316,"line":543},[314,8540,8495],{"class":885},[314,8542,8543],{"class":875}," YARN_HOME",[314,8545,5519],{"class":525},[314,8547,8503],{"class":875},[314,8549,8550,8552,8555,8557],{"class":316,"line":554},[314,8551,8495],{"class":885},[314,8553,8554],{"class":875}," HADOOP_COMMON_LIB_NATIVE_DIR",[314,8556,5519],{"class":525},[314,8558,8559],{"class":875},"$HADOOP_HOME\u002Flib\u002Fnative\n",[314,8561,8562,8564,8567,8569],{"class":316,"line":560},[314,8563,8495],{"class":885},[314,8565,8566],{"class":875}," PATH",[314,8568,5519],{"class":525},[314,8570,8571],{"class":875},"$PATH:$HADOOP_HOME\u002Fsbin:$HADOOP_HOME\u002Fbin\n",[11,8573,8574],{},[41,8575,8576],{},"slaves",[306,8578,8580],{"className":308,"code":8579,"language":310,"meta":269,"style":269},"dn1.hadoop.data.example.net\ndn2.hadoop.data.example.net\n",[132,8581,8582,8587],{"__ignoreMap":269},[314,8583,8584],{"class":316,"line":317},[314,8585,8586],{"class":320},"dn1.hadoop.data.example.net\n",[314,8588,8589],{"class":316,"line":270},[314,8590,8591],{"class":320},"dn2.hadoop.data.example.net\n",[11,8593,8594],{},[41,8595,8596],{},"hadoop-env.sh",[306,8598,8600],{"className":308,"code":8599,"language":310,"meta":269,"style":269},"# export JAVA_HOME=${JAVA_HOME}\n改为\nexport JAVA_HOME=\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\u002F\n",[132,8601,8602,8607,8612],{"__ignoreMap":269},[314,8603,8604],{"class":316,"line":317},[314,8605,8606],{"class":3038},"# export JAVA_HOME=${JAVA_HOME}\n",[314,8608,8609],{"class":316,"line":270},[314,8610,8611],{"class":320},"改为\n",[314,8613,8614,8616,8619,8621],{"class":316,"line":278},[314,8615,8495],{"class":885},[314,8617,8618],{"class":875}," JAVA_HOME",[314,8620,5519],{"class":525},[314,8622,8623],{"class":875},"\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\u002F\n",[11,8625,8626],{},[41,8627,8628],{},"core-site.xml",[306,8630,8632],{"className":7442,"code":8631,"language":7444,"meta":269,"style":269},"\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",[132,8633,8634,8639,8644,8649,8654,8659,8663,8668,8673,8677],{"__ignoreMap":269},[314,8635,8636],{"class":316,"line":317},[314,8637,8638],{},"\u003Cconfiguration>\n",[314,8640,8641],{"class":316,"line":270},[314,8642,8643],{},"    \u003Cproperty>\n",[314,8645,8646],{"class":316,"line":278},[314,8647,8648],{},"    \u003Cname>fs.defaultFS\u003C\u002Fname>\n",[314,8650,8651],{"class":316,"line":513},[314,8652,8653],{},"    \u003Cvalue>hdfs:\u002F\u002Fnn.hadoop.data.example.net:9000\u003C\u002Fvalue>\n",[314,8655,8656],{"class":316,"line":535},[314,8657,8658],{},"    \u003C\u002Fproperty>\n",[314,8660,8661],{"class":316,"line":543},[314,8662,8643],{},[314,8664,8665],{"class":316,"line":554},[314,8666,8667],{},"    \u003Cname>hadoop.tmp.dir\u003C\u002Fname>\n",[314,8669,8670],{"class":316,"line":560},[314,8671,8672],{},"    \u003Cvalue>\u002Fapp\u002Fhadoop\u002Ftmp\u003C\u002Fvalue>\n",[314,8674,8675],{"class":316,"line":574},[314,8676,8658],{},[314,8678,8679],{"class":316,"line":588},[314,8680,8681],{},"\u003C\u002Fconfiguration>\n",[11,8683,8684],{},[41,8685,8686],{},"hdfs-site.xml",[306,8688,8690],{"className":7442,"code":8689,"language":7444,"meta":269,"style":269},"\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",[132,8691,8692,8696,8700,8705,8710,8714,8718,8723,8728,8732,8736,8741,8746,8750,8754,8759,8764,8768],{"__ignoreMap":269},[314,8693,8694],{"class":316,"line":317},[314,8695,8638],{},[314,8697,8698],{"class":316,"line":270},[314,8699,8643],{},[314,8701,8702],{"class":316,"line":278},[314,8703,8704],{},"        \u003Cname>dfs.namenode.secondary.http-address\u003C\u002Fname>\n",[314,8706,8707],{"class":316,"line":513},[314,8708,8709],{},"        \u003Cvalue>nn.hadoop.data.example.net:50090\u003C\u002Fvalue>\n",[314,8711,8712],{"class":316,"line":535},[314,8713,8658],{},[314,8715,8716],{"class":316,"line":543},[314,8717,8643],{},[314,8719,8720],{"class":316,"line":554},[314,8721,8722],{},"        \u003Cname>dfs.namenode.name.dir\u003C\u002Fname>\n",[314,8724,8725],{"class":316,"line":560},[314,8726,8727],{},"        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fname\u003C\u002Fvalue>\n",[314,8729,8730],{"class":316,"line":574},[314,8731,8658],{},[314,8733,8734],{"class":316,"line":588},[314,8735,8643],{},[314,8737,8738],{"class":316,"line":602},[314,8739,8740],{},"        \u003Cname>dfs.replication\u003C\u002Fname>\n",[314,8742,8743],{"class":316,"line":1404},[314,8744,8745],{},"        \u003Cvalue>1\u003C\u002Fvalue>\n",[314,8747,8748],{"class":316,"line":1477},[314,8749,8658],{},[314,8751,8752],{"class":316,"line":1483},[314,8753,8643],{},[314,8755,8756],{"class":316,"line":1489},[314,8757,8758],{},"        \u003Cname>dfs.datanode.data.dir\u003C\u002Fname>\n",[314,8760,8761],{"class":316,"line":1495},[314,8762,8763],{},"        \u003Cvalue>\u002Fapp\u002Fhadoop\u002Fdata\u003C\u002Fvalue>\n",[314,8765,8766],{"class":316,"line":1501},[314,8767,8658],{},[314,8769,8770],{"class":316,"line":1507},[314,8771,8681],{},[11,8773,8774],{},[41,8775,8776],{},"mapred-site.xml",[306,8778,8780],{"className":308,"code":8779,"language":310,"meta":269,"style":269},"cp mapred-site.xml.template mapred-site.xml\n",[132,8781,8782],{"__ignoreMap":269},[314,8783,8784,8787,8790],{"class":316,"line":317},[314,8785,8786],{"class":320},"cp",[314,8788,8789],{"class":324}," mapred-site.xml.template",[314,8791,8792],{"class":324}," mapred-site.xml\n",[306,8794,8796],{"className":7442,"code":8795,"language":7444,"meta":269,"style":269},"\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",[132,8797,8798,8802,8806,8811,8816,8820,8824,8829,8834,8838,8842,8847,8852,8856],{"__ignoreMap":269},[314,8799,8800],{"class":316,"line":317},[314,8801,8638],{},[314,8803,8804],{"class":316,"line":270},[314,8805,8643],{},[314,8807,8808],{"class":316,"line":278},[314,8809,8810],{},"        \u003Cname>mapreduce.framework.name\u003C\u002Fname>\n",[314,8812,8813],{"class":316,"line":513},[314,8814,8815],{},"        \u003Cvalue>yarn\u003C\u002Fvalue>\n",[314,8817,8818],{"class":316,"line":535},[314,8819,8658],{},[314,8821,8822],{"class":316,"line":543},[314,8823,8643],{},[314,8825,8826],{"class":316,"line":554},[314,8827,8828],{},"        \u003Cname>mapreduce.jobhistory.address\u003C\u002Fname>\n",[314,8830,8831],{"class":316,"line":560},[314,8832,8833],{},"        \u003Cvalue>nn.hadoop.data.example.net:10020\u003C\u002Fvalue>\n",[314,8835,8836],{"class":316,"line":574},[314,8837,8658],{},[314,8839,8840],{"class":316,"line":588},[314,8841,8643],{},[314,8843,8844],{"class":316,"line":602},[314,8845,8846],{},"        \u003Cname>mapreduce.jobhistory.webapp.address\u003C\u002Fname>\n",[314,8848,8849],{"class":316,"line":1404},[314,8850,8851],{},"        \u003Cvalue>nn.hadoop.data.example.net:19888\u003C\u002Fvalue>\n",[314,8853,8854],{"class":316,"line":1477},[314,8855,8658],{},[314,8857,8858],{"class":316,"line":1483},[314,8859,8681],{},[11,8861,8862],{},[41,8863,8864],{},"yarn-site.xml",[306,8866,8868],{"className":7442,"code":8867,"language":7444,"meta":269,"style":269},"\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",[132,8869,8870,8874,8879,8883,8888,8893,8897,8901,8906,8911,8915,8919,8924,8929,8933],{"__ignoreMap":269},[314,8871,8872],{"class":316,"line":317},[314,8873,8638],{},[314,8875,8876],{"class":316,"line":270},[314,8877,8878],{},"\u003C!-- Site specific YARN configuration properties -->\n",[314,8880,8881],{"class":316,"line":278},[314,8882,8643],{},[314,8884,8885],{"class":316,"line":513},[314,8886,8887],{},"        \u003Cname>yarn.resourcemanager.hostname\u003C\u002Fname>\n",[314,8889,8890],{"class":316,"line":535},[314,8891,8892],{},"        \u003Cvalue>nn.hadoop.data.example.net\u003C\u002Fvalue>\n",[314,8894,8895],{"class":316,"line":543},[314,8896,8658],{},[314,8898,8899],{"class":316,"line":554},[314,8900,8643],{},[314,8902,8903],{"class":316,"line":560},[314,8904,8905],{},"        \u003Cname>yarn.nodemanager.aux-services\u003C\u002Fname>\n",[314,8907,8908],{"class":316,"line":574},[314,8909,8910],{},"        \u003Cvalue>mapreduce_shuffle\u003C\u002Fvalue>\n",[314,8912,8913],{"class":316,"line":588},[314,8914,8658],{},[314,8916,8917],{"class":316,"line":602},[314,8918,8643],{},[314,8920,8921],{"class":316,"line":1404},[314,8922,8923],{},"         \u003Cname>yarn.nodemanager.aux-services.mapreduce.shuffle.class\u003C\u002Fname>\n",[314,8925,8926],{"class":316,"line":1477},[314,8927,8928],{},"         \u003Cvalue>org.apache.hadoop.mapred.ShuffleHandler\u003C\u002Fvalue>\n",[314,8930,8931],{"class":316,"line":1483},[314,8932,8658],{},[314,8934,8935],{"class":316,"line":1489},[314,8936,8681],{},[154,8938,8940],{"id":8939},"_4格式化-namenode","4.格式化 namenode",[306,8942,8944],{"className":308,"code":8943,"language":310,"meta":269,"style":269},"hadoop namenode -format\n",[132,8945,8946],{"__ignoreMap":269},[314,8947,8948,8951,8954],{"class":316,"line":317},[314,8949,8950],{"class":320},"hadoop",[314,8952,8953],{"class":324}," namenode",[314,8955,8956],{"class":324}," -format\n",[154,8958,8960],{"id":8959},"_5复制文件到其他机器","5.复制文件到其他机器",[11,8962,8963],{},"将 \u002Fapp\u002Fhadoop（包括 data、name、tmp 和配置好的 hadoop）复制到其他机器。",[154,8965,8967],{"id":8966},"_6启动-dfs","6.启动 dfs",[306,8969,8971],{"className":308,"code":8970,"language":310,"meta":269,"style":269},"start-dfs.sh\n",[132,8972,8973],{"__ignoreMap":269},[314,8974,8975],{"class":316,"line":317},[314,8976,8970],{"class":320},[154,8978,8980],{"id":8979},"_7启动-yarn","7.启动 yarn",[306,8982,8984],{"className":308,"code":8983,"language":310,"meta":269,"style":269},"start-yarn.sh\n",[132,8985,8986],{"__ignoreMap":269},[314,8987,8988],{"class":316,"line":317},[314,8989,8983],{"class":320},[154,8991,8993],{"id":8992},"_8启动-jobhistory","8.启动 jobhistory",[306,8995,8997],{"className":308,"code":8996,"language":310,"meta":269,"style":269},"mr-jobhistory-daemon.sh start historyserver\n",[132,8998,8999],{"__ignoreMap":269},[314,9000,9001,9004,9006],{"class":316,"line":317},[314,9002,9003],{"class":320},"mr-jobhistory-daemon.sh",[314,9005,325],{"class":324},[314,9007,9008],{"class":324}," historyserver\n",[24,9010,9012],{"id":9011},"安装-spark2","安装 Spark2",[154,9014,8157],{"id":9015},"_0创建文件夹-2",[306,9017,9019],{"className":308,"code":9018,"language":310,"meta":269,"style":269},"mkdir \u002Fapp\u002Fspark\n",[132,9020,9021],{"__ignoreMap":269},[314,9022,9023,9025],{"class":316,"line":317},[314,9024,8167],{"class":320},[314,9026,9027],{"class":324}," \u002Fapp\u002Fspark\n",[154,9029,9031],{"id":9030},"_1下载-spark2","1.下载 Spark2",[306,9033,9035],{"className":308,"code":9034,"language":310,"meta":269,"style":269},"wget http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.lua\u002Fspark\u002Fspark-2.1.0\u002Fspark-2.1.0-bin-hadoop2.7.tgz\n",[132,9036,9037],{"__ignoreMap":269},[314,9038,9039,9041],{"class":316,"line":317},[314,9040,8194],{"class":320},[314,9042,9043],{"class":324}," http:\u002F\u002Fwww.apache.org\u002Fdyn\u002Fcloser.lua\u002Fspark\u002Fspark-2.1.0\u002Fspark-2.1.0-bin-hadoop2.7.tgz\n",[154,9045,8225],{"id":9046},"_2移动解压-2",[306,9048,9050],{"className":308,"code":9049,"language":310,"meta":269,"style":269},"mv spark-2.1.0-bin-hadoop2.7.tgz \u002Fapp\u002Fspark\ntar -zxvf spark-2.1.0-bin-hadoop2.7.tgz\n",[132,9051,9052,9061],{"__ignoreMap":269},[314,9053,9054,9056,9059],{"class":316,"line":317},[314,9055,2610],{"class":320},[314,9057,9058],{"class":324}," spark-2.1.0-bin-hadoop2.7.tgz",[314,9060,9027],{"class":324},[314,9062,9063,9065,9067],{"class":316,"line":270},[314,9064,8244],{"class":320},[314,9066,8247],{"class":324},[314,9068,9069],{"class":324}," spark-2.1.0-bin-hadoop2.7.tgz\n",[154,9071,8470],{"id":9072},"_3修改配置文件-1",[11,9074,9075],{},[41,9076,8475],{},[306,9078,9080],{"className":308,"code":9079,"language":310,"meta":269,"style":269},"export SPARK_HOME=\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\nexport PATH=\"$SPARK_HOME\u002Fbin:$PATH\"\n",[132,9081,9082,9094],{"__ignoreMap":269},[314,9083,9084,9086,9089,9091],{"class":316,"line":317},[314,9085,8495],{"class":885},[314,9087,9088],{"class":875}," SPARK_HOME",[314,9090,5519],{"class":525},[314,9092,9093],{"class":875},"\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\n",[314,9095,9096,9098,9100,9102,9104,9107,9110,9113],{"class":316,"line":270},[314,9097,8495],{"class":885},[314,9099,8566],{"class":875},[314,9101,5519],{"class":525},[314,9103,867],{"class":525},[314,9105,9106],{"class":875},"$SPARK_HOME",[314,9108,9109],{"class":324},"\u002Fbin:",[314,9111,9112],{"class":875},"$PATH",[314,9114,1132],{"class":525},[11,9116,9117],{},[41,9118,9119],{},"spark-env.sh",[306,9121,9123],{"className":308,"code":9122,"language":310,"meta":269,"style":269},"cp spark-env.sh.template spark-env.sh\n",[132,9124,9125],{"__ignoreMap":269},[314,9126,9127,9129,9132],{"class":316,"line":317},[314,9128,8786],{"class":320},[314,9130,9131],{"class":324}," spark-env.sh.template",[314,9133,9134],{"class":324}," spark-env.sh\n",[306,9136,9138],{"className":308,"code":9137,"language":310,"meta":269,"style":269},"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",[132,9139,9140,9152,9163,9175,9187],{"__ignoreMap":269},[314,9141,9142,9144,9147,9149],{"class":316,"line":317},[314,9143,8495],{"class":885},[314,9145,9146],{"class":875}," SCALA_HOME",[314,9148,5519],{"class":525},[314,9150,9151],{"class":875},"\u002Fapp\u002Fscala\u002Fscala-2.12.1\n",[314,9153,9154,9156,9158,9160],{"class":316,"line":270},[314,9155,8495],{"class":885},[314,9157,8618],{"class":875},[314,9159,5519],{"class":525},[314,9161,9162],{"class":875},"\u002Fapp\u002Fjava\u002Fjdk1.8.0_121\n",[314,9164,9165,9167,9170,9172],{"class":316,"line":278},[314,9166,8495],{"class":885},[314,9168,9169],{"class":875}," SPARK_MASTER_IP",[314,9171,5519],{"class":525},[314,9173,9174],{"class":875},"nn.hadoop.data.easydebug.net\n",[314,9176,9177,9179,9182,9184],{"class":316,"line":513},[314,9178,8495],{"class":885},[314,9180,9181],{"class":875}," SPARK_WORKER_MEMORY",[314,9183,5519],{"class":525},[314,9185,9186],{"class":875},"1g\n",[314,9188,9189,9191,9194,9196],{"class":316,"line":535},[314,9190,8495],{"class":885},[314,9192,9193],{"class":875}," HADOOP_CONF_DIR",[314,9195,5519],{"class":525},[314,9197,9198],{"class":875},"\u002Fapp\u002Fhadoop\u002Fhadoop-2.7.3\u002Fetc\u002Fhadoop\n",[11,9200,9201],{},[41,9202,8576],{},[306,9204,9205],{"className":308,"code":8579,"language":310,"meta":269,"style":269},[132,9206,9207,9211],{"__ignoreMap":269},[314,9208,9209],{"class":316,"line":317},[314,9210,8586],{"class":320},[314,9212,9213],{"class":316,"line":270},[314,9214,8591],{"class":320},[154,9216,9218],{"id":9217},"_4复制文件到其他机器","4.复制文件到其他机器",[11,9220,9221],{},"将 \u002Fapp\u002Fspark 复制到其他机器。",[154,9223,9225],{"id":9224},"_5启动-spark","5.启动 Spark",[306,9227,9229],{"className":308,"code":9228,"language":310,"meta":269,"style":269},"\u002Fapp\u002Fspark\u002Fspark-2.1.0-bin-hadoop2.7\u002Fsbin\u002Fstart-all.sh\n",[132,9230,9231],{"__ignoreMap":269},[314,9232,9233],{"class":316,"line":317},[314,9234,9228],{"class":320},[24,9236,9238],{"id":9237},"安装完成-_","安装完成 ^_^",[2340,9240],{},[154,9242,9244],{"id":9243},"因为系统变量改了几次最后贴一下完整的","因为系统变量改了几次，最后贴一下完整的",[11,9246,9247],{},"其实可以在配置前直接贴进去。",[306,9249,9251],{"className":308,"code":9250,"language":310,"meta":269,"style":269},"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",[132,9252,9253,9263,9273,9284,9296,9300,9308,9318,9328,9338,9348,9358,9368,9378,9382,9392],{"__ignoreMap":269},[314,9254,9255,9257,9259,9261],{"class":316,"line":317},[314,9256,8495],{"class":885},[314,9258,8618],{"class":875},[314,9260,5519],{"class":525},[314,9262,9162],{"class":875},[314,9264,9265,9267,9269,9271],{"class":316,"line":270},[314,9266,8495],{"class":885},[314,9268,9146],{"class":875},[314,9270,5519],{"class":525},[314,9272,9151],{"class":875},[314,9274,9275,9277,9279,9281],{"class":316,"line":278},[314,9276,8495],{"class":885},[314,9278,8566],{"class":875},[314,9280,5519],{"class":525},[314,9282,9283],{"class":875},"$JAVA_HOME\u002Fbin:$SCALA_HOME\u002Fbin:$PATH\n",[314,9285,9286,9288,9291,9293],{"class":316,"line":513},[314,9287,8495],{"class":885},[314,9289,9290],{"class":875}," CLASSPATH",[314,9292,5519],{"class":525},[314,9294,9295],{"class":875},".:$JAVA_HOME\u002Flib\u002Fdt.jar:$JAVA_HOME\u002Flib\u002Ftools.jar\n",[314,9297,9298],{"class":316,"line":535},[314,9299,1716],{"emptyLinePlaceholder":287},[314,9301,9302,9304,9306],{"class":316,"line":543},[314,9303,8485],{"class":875},[314,9305,5519],{"class":525},[314,9307,8490],{"class":324},[314,9309,9310,9312,9314,9316],{"class":316,"line":554},[314,9311,8495],{"class":885},[314,9313,8498],{"class":875},[314,9315,5519],{"class":525},[314,9317,8503],{"class":875},[314,9319,9320,9322,9324,9326],{"class":316,"line":560},[314,9321,8495],{"class":885},[314,9323,8510],{"class":875},[314,9325,5519],{"class":525},[314,9327,8503],{"class":875},[314,9329,9330,9332,9334,9336],{"class":316,"line":574},[314,9331,8495],{"class":885},[314,9333,8521],{"class":875},[314,9335,5519],{"class":525},[314,9337,8503],{"class":875},[314,9339,9340,9342,9344,9346],{"class":316,"line":588},[314,9341,8495],{"class":885},[314,9343,8532],{"class":875},[314,9345,5519],{"class":525},[314,9347,8503],{"class":875},[314,9349,9350,9352,9354,9356],{"class":316,"line":602},[314,9351,8495],{"class":885},[314,9353,8543],{"class":875},[314,9355,5519],{"class":525},[314,9357,8503],{"class":875},[314,9359,9360,9362,9364,9366],{"class":316,"line":1404},[314,9361,8495],{"class":885},[314,9363,8554],{"class":875},[314,9365,5519],{"class":525},[314,9367,8559],{"class":875},[314,9369,9370,9372,9374,9376],{"class":316,"line":1477},[314,9371,8495],{"class":885},[314,9373,8566],{"class":875},[314,9375,5519],{"class":525},[314,9377,8571],{"class":875},[314,9379,9380],{"class":316,"line":1483},[314,9381,1716],{"emptyLinePlaceholder":287},[314,9383,9384,9386,9388,9390],{"class":316,"line":1489},[314,9385,8495],{"class":885},[314,9387,9088],{"class":875},[314,9389,5519],{"class":525},[314,9391,9093],{"class":875},[314,9393,9394,9396,9398,9400,9402,9404,9406,9408],{"class":316,"line":1495},[314,9395,8495],{"class":885},[314,9397,8566],{"class":875},[314,9399,5519],{"class":525},[314,9401,867],{"class":525},[314,9403,9106],{"class":875},[314,9405,9109],{"class":324},[314,9407,9112],{"class":875},[314,9409,1132],{"class":525},[2340,9411],{},[6583,9413,9414,9417,9425,9433],{},[11,9415,9416],{},"参考文章",[11,9418,9419,9420],{},"CentOS 6.5 hadoop 2.7.3 集群环境搭建\n",[232,9421,9424],{"href":9422,"rel":9423},"http:\u002F\u002Fblog.csdn.net\u002Fmxxlevel\u002Farticle\u002Fdetails\u002F52653086",[236],"blog.csdn.net\u002Fmxxlevel\u002Farticle\u002Fdetails\u002F52653086",[11,9426,9427,9428],{},"Spark修炼之道（进阶篇）——Spark 入门到精通：第一节 Spark 1.5.0 集群搭建\n",[232,9429,9432],{"href":9430,"rel":9431},"https:\u002F\u002Fyq.aliyun.com\u002Farticles\u002F60309?spm=5176.8251999.569296.66.0H8Bal",[236],"yq.aliyun.com\u002Farticles\u002F60309",[11,9434,9435,9436],{},"Hadoop2.7.3+Spark2.1.0 完全分布式环境 搭建全过程\n",[232,9437,9440],{"href":9438,"rel":9439},"http:\u002F\u002Fwww.cnblogs.com\u002Fpurstar\u002Fp\u002F6293605.html",[236],"cnblogs.com\u002Fpurstar\u002Fp\u002F6293605.html",[673,9442,9443],{},"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":269,"searchDepth":270,"depth":270,"links":9445},[9446,9451,9457,9458,9459,9470,9478],{"id":2332,"depth":270,"text":2332,"children":9447},[9448,9449,9450],{"id":7987,"depth":278,"text":7988},{"id":331,"depth":278,"text":331},{"id":8070,"depth":278,"text":8071},{"id":8152,"depth":270,"text":8153,"children":9452},[9453,9454,9455,9456],{"id":8156,"depth":278,"text":8157},{"id":8180,"depth":278,"text":8181},{"id":8224,"depth":278,"text":8225},{"id":8271,"depth":278,"text":8272},{"id":8306,"depth":270,"text":8307},{"id":8333,"depth":270,"text":8334},{"id":8393,"depth":270,"text":8394,"children":9460},[9461,9462,9463,9464,9465,9466,9467,9468,9469],{"id":8397,"depth":278,"text":8157},{"id":8426,"depth":278,"text":8427},{"id":8442,"depth":278,"text":8225},{"id":8469,"depth":278,"text":8470},{"id":8939,"depth":278,"text":8940},{"id":8959,"depth":278,"text":8960},{"id":8966,"depth":278,"text":8967},{"id":8979,"depth":278,"text":8980},{"id":8992,"depth":278,"text":8993},{"id":9011,"depth":270,"text":9012,"children":9471},[9472,9473,9474,9475,9476,9477],{"id":9015,"depth":278,"text":8157},{"id":9030,"depth":278,"text":9031},{"id":9046,"depth":278,"text":8225},{"id":9072,"depth":278,"text":8470},{"id":9217,"depth":278,"text":9218},{"id":9224,"depth":278,"text":9225},{"id":9237,"depth":270,"text":9238,"children":9479},[9480],{"id":9243,"depth":278,"text":9244},"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":7931,"description":9482},"posts\u002Fcentos7-hadoop-spark-cluster-setup",[9488,9489,9490,696],"Hadoop","Spark","大数据","l1G-4Zt0wIq9pgZ5Nnet1mvOeQBaa2Cqo3BLnROXsFQ",{"id":9493,"title":9494,"body":9495,"date":9624,"description":9625,"extension":285,"meta":9626,"navigation":287,"path":9627,"seo":9628,"stem":9629,"tags":9630,"__hash__":9634},"posts\u002Fposts\u002Fwindows-install-facebook-prophet.md","Facebook 开源预测工具 Prophet 安装方法",{"type":8,"value":9496,"toc":9616},[9497,9506,9508,9510,9520,9524,9534,9538,9546,9550,9580,9583,9585,9588,9593,9598,9603,9614],[11,9498,9499,9500,9505],{},"最近研究看到一篇介绍 ",[232,9501,9504],{"href":9502,"rel":9503},"http:\u002F\u002Fmp.weixin.qq.com\u002Fs\u002F6yZRKbH0GYvqHwCDmpL-Uw",[236],"facebook 开源的大规模预测框架 Prophet"," 的文章，折腾了两个晚上终于在 Win 环境下安装成功，把结果分享下。",[2340,9507],{},[24,9509,2332],{"id":2332},[6583,9511,9512],{},[35,9513,9514,9517],{},[38,9515,9516],{},"Windows 7 x64",[38,9518,9519],{},"Anaconda3-4.2.0-Windows-x86 (Python 3.5)",[24,9521,9523],{"id":9522},"安装-visual-c-2015-build-tools","安装 Visual C++ 2015 Build Tools",[6583,9525,9526],{},[11,9527,9528,9529],{},"Prophet 需要 C 语言编译，在 Win 环境下需要先安装 ",[232,9530,9533],{"href":9531,"rel":9532},"http:\u002F\u002Flandinghub.visualstudio.com\u002Fvisual-cpp-build-tools",[236],"Visual C++ 2015 Build Tools",[24,9535,9537],{"id":9536},"安装-pystan","安装 pystan",[6583,9539,9540],{},[11,9541,9542,9543],{},"Prophet 依赖 pystan 包所以也需要安装 pystan\n",[132,9544,9545],{},"pip install pystan",[24,9547,9549],{"id":9548},"安装-prophet","安装 Prophet",[6583,9551,9552,9560,9571],{},[11,9553,9554],{},[41,9555,9556,9557],{},"不要用 ",[132,9558,9559],{},"pip install fbprophet",[11,9561,9562,9567,9568],{},[232,9563,9566],{"href":9564,"rel":9565},"https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet",[236],"下载"," prophet 最新源码。\n或者 ",[132,9569,9570],{},"git clone https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet",[11,9572,9573,9574,9577],{},"解压到指定目录，例如 D:\\Anaconda3\\prophet\nCMD:\n",[132,9575,9576],{},"cd D:\\Anaconda3\\prophet\\python",[132,9578,9579],{},"pip install -e .",[24,9581,9582],{"id":9582},"安装完成",[2340,9584],{},[24,9586,9587],{"id":9587},"踩过的坑",[11,9589,9590],{},[41,9591,9592],{},"1. error: command ‘C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\cl.exe’ failed with exit status 2",[6583,9594,9595],{},[11,9596,9597],{},"先确认 Visual C++ 2015 Build Tools 是否安装；如果已经安装，请放弃使用 pip 安装 Prophet。下载源码安装 Prophet 无问题。",[11,9599,9600],{},[41,9601,9602],{},"2. No such file or directory: u’fbprophet\u002Fstan_models\u002Flinear_growth.pkl’",[6583,9604,9605],{},[11,9606,9607,9608,9613],{},"目测是一个",[232,9609,9612],{"href":9610,"rel":9611},"https:\u002F\u002Fgithub.com\u002Ffacebookincubator\u002Fprophet\u002Fpull\u002F100",[236],"已知 BUG","，已经修复。但好像 Release 的 v0.1 源码未更新。直接下载最新源码编译无报错。",[2340,9615],{},{"title":269,"searchDepth":270,"depth":270,"links":9617},[9618,9619,9620,9621,9622,9623],{"id":2332,"depth":270,"text":2332},{"id":9522,"depth":270,"text":9523},{"id":9536,"depth":270,"text":9537},{"id":9548,"depth":270,"text":9549},{"id":9582,"depth":270,"text":9582},{"id":9587,"depth":270,"text":9587},"2017-03-16","Win 下装 Prophet 不能用 pip install fbprophet，得先装 VC++ 2015 Build Tools 和 pystan，再从源码装。附两个踩坑记录。",{},"\u002Fposts\u002Fwindows-install-facebook-prophet",{"title":9494,"description":9625},"posts\u002Fwindows-install-facebook-prophet",[9631,9632,9633],"Python","Prophet","环境配置","yXvlR_ZI35tb-kDjwjaABLwx4Qxkwe20Ek459jNtV6c",1789491485613]