-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.json
1 lines (1 loc) · 772 KB
/
db.json
1
{"meta":{"version":1,"warehouse":"2.2.0"},"models":{"Asset":[{"_id":"source/favicon.ico","path":"favicon.ico","modified":1,"renderable":0},{"_id":"source/robots.txt","path":"robots.txt","modified":1,"renderable":0},{"_id":"themes/nextd/source/css/main.styl","path":"css/main.styl","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/algolia_logo.svg","path":"images/algolia_logo.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/avatar.gif","path":"images/avatar.gif","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/avatar.jpg","path":"images/avatar.jpg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by-nc-nd.svg","path":"images/cc-by-nc-nd.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by-nc-sa.svg","path":"images/cc-by-nc-sa.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by-nc.svg","path":"images/cc-by-nc.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by-nd.svg","path":"images/cc-by-nd.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by-sa.svg","path":"images/cc-by-sa.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-by.svg","path":"images/cc-by.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/cc-zero.svg","path":"images/cc-zero.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/loading.gif","path":"images/loading.gif","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/logo.png","path":"images/logo.png","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/placeholder.gif","path":"images/placeholder.gif","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/quote-l.svg","path":"images/quote-l.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/quote-r.svg","path":"images/quote-r.svg","modified":1,"renderable":1},{"_id":"themes/nextd/source/images/searchicon.png","path":"images/searchicon.png","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/algolia-search.js","path":"js/src/algolia-search.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/affix.js","path":"js/src/affix.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/bootstrap.js","path":"js/src/bootstrap.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/hook-duoshuo.js","path":"js/src/hook-duoshuo.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/motion.js","path":"js/src/motion.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/post-details.js","path":"js/src/post-details.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/scrollspy.js","path":"js/src/scrollspy.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/utils.js","path":"js/src/utils.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/algolia-instant-search/instantsearch.min.css","path":"lib/algolia-instant-search/instantsearch.min.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/canvas-nest/canvas-nest.min.js","path":"lib/canvas-nest/canvas-nest.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/canvas-ribbon/canvas-ribbon.js","path":"lib/canvas-ribbon/canvas-ribbon.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fastclick/LICENSE","path":"lib/fastclick/LICENSE","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fastclick/README.md","path":"lib/fastclick/README.md","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fastclick/bower.json","path":"lib/fastclick/bower.json","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/HELP-US-OUT.txt","path":"lib/font-awesome/HELP-US-OUT.txt","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/bower.json","path":"lib/font-awesome/bower.json","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery_lazyload/CONTRIBUTING.md","path":"lib/jquery_lazyload/CONTRIBUTING.md","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery_lazyload/README.md","path":"lib/jquery_lazyload/README.md","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery_lazyload/bower.json","path":"lib/jquery_lazyload/bower.json","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery_lazyload/jquery.lazyload.js","path":"lib/jquery_lazyload/jquery.lazyload.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery_lazyload/jquery.scrollstop.js","path":"lib/jquery_lazyload/jquery.scrollstop.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/velocity/bower.json","path":"lib/velocity/bower.json","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/velocity/velocity.min.js","path":"lib/velocity/velocity.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/velocity/velocity.ui.js","path":"lib/velocity/velocity.ui.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/velocity/velocity.ui.min.js","path":"lib/velocity/velocity.ui.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/jquery/index.js","path":"lib/jquery/index.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/js/src/schemes/pisces.js","path":"js/src/schemes/pisces.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/blank.gif","path":"lib/fancybox/source/blank.gif","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_loading.gif","path":"lib/fancybox/source/fancybox_loading.gif","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/[email protected]","path":"lib/fancybox/source/[email protected]","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_overlay.png","path":"lib/fancybox/source/fancybox_overlay.png","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_sprite.png","path":"lib/fancybox/source/fancybox_sprite.png","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/[email protected]","path":"lib/fancybox/source/[email protected]","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.css","path":"lib/fancybox/source/jquery.fancybox.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.js","path":"lib/fancybox/source/jquery.fancybox.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.pack.js","path":"lib/fancybox/source/jquery.fancybox.pack.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fastclick/lib/fastclick.js","path":"lib/fastclick/lib/fastclick.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fastclick/lib/fastclick.min.js","path":"lib/fastclick/lib/fastclick.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.css","path":"lib/font-awesome/css/font-awesome.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.css.map","path":"lib/font-awesome/css/font-awesome.css.map","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.min.css","path":"lib/font-awesome/css/font-awesome.min.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/ua-parser-js/dist/ua-parser.min.js","path":"lib/ua-parser-js/dist/ua-parser.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/ua-parser-js/dist/ua-parser.pack.js","path":"lib/ua-parser-js/dist/ua-parser.pack.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/FontAwesome.otf","path":"lib/font-awesome/fonts/FontAwesome.otf","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.eot","path":"lib/font-awesome/fonts/fontawesome-webfont.eot","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.woff2","path":"lib/font-awesome/fonts/fontawesome-webfont.woff2","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.woff","path":"lib/font-awesome/fonts/fontawesome-webfont.woff","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/velocity/velocity.js","path":"lib/velocity/velocity.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/fancybox_buttons.png","path":"lib/fancybox/source/helpers/fancybox_buttons.png","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-buttons.css","path":"lib/fancybox/source/helpers/jquery.fancybox-buttons.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-buttons.js","path":"lib/fancybox/source/helpers/jquery.fancybox-buttons.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-media.js","path":"lib/fancybox/source/helpers/jquery.fancybox-media.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-thumbs.css","path":"lib/fancybox/source/helpers/jquery.fancybox-thumbs.css","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-thumbs.js","path":"lib/fancybox/source/helpers/jquery.fancybox-thumbs.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.ttf","path":"lib/font-awesome/fonts/fontawesome-webfont.ttf","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/algolia-instant-search/instantsearch.min.js","path":"lib/algolia-instant-search/instantsearch.min.js","modified":1,"renderable":1},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.svg","path":"lib/font-awesome/fonts/fontawesome-webfont.svg","modified":1,"renderable":1}],"Cache":[{"_id":"source/favicon.ico","hash":"a7d047f0799c44e6dbdb0f6a35106b8aa027d7e2","modified":1495538973820},{"_id":"source/google091459981c22016a.html","hash":"85f4d2476dfdbf504e4122a9afcbae018f4d9cfe","modified":1494424475903},{"_id":"source/robots.txt","hash":"faf4a7dc40136be7a67d7fbf7f65873a6ceba30e","modified":1494424475952},{"_id":"themes/nextd/.bowerrc","hash":"20038353db532b4c40625419d396da7359f89cbe","modified":1491391835803},{"_id":"themes/nextd/.editorconfig","hash":"211d2c92bfdddb3e81ea946f4ca7a539f150f4da","modified":1491391835807},{"_id":"themes/nextd/.gitignore","hash":"80710b94ff2f6c013859ebffffe90f9295fc94ed","modified":1491391835818},{"_id":"themes/nextd/.hound.yml","hash":"289dcf5bfe92dbd680d54d6e0668f41c9c9c0c78","modified":1491391835823},{"_id":"themes/nextd/.javascript_ignore","hash":"beb0b95736650284ceb712a162cc033847a83cd3","modified":1491391835861},{"_id":"themes/nextd/.jshintrc","hash":"b7d23f2ce8d99fa073f22f9960605f318acd7710","modified":1491391835865},{"_id":"themes/nextd/README.en.md","hash":"f947d9a552da869f0dbef140ceeeb7b040b0f4a4","modified":1491391835870},{"_id":"themes/nextd/_config.yml","hash":"4d5fa21037dc8c4150299862334d436a8b5a3fa7","modified":1520781853047},{"_id":"themes/nextd/_config.yml.rej","hash":"4499e12ee7dade7cb7e9d6439ab1a205c5e709f3","modified":1491490357489},{"_id":"themes/nextd/bower.json","hash":"da39b00fcdf2e7a42af412de0a4d3617cc6d7084","modified":1491391835889},{"_id":"themes/nextd/gulpfile.coffee","hash":"4e8c1082fa82e383494ff5b5963b7936d9c7bb2e","modified":1491391835893},{"_id":"themes/nextd/package.json","hash":"dff2fe518f00fab2be59709bc9efdd1d01c73e5d","modified":1493881730500},{"_id":"source/_data/next.yml","hash":"2e5a91fba39373ec8dbc96559a1ba3a720e2b834","modified":1491391835710},{"_id":"source/_posts/HttpClient学习记录.md","hash":"48811fe9918f49485bfea138e942af8f0b7aee8b","modified":1507983912749},{"_id":"source/_posts/JsWeb框架手册.md","hash":"f5a77f7634b596a894240f257a1dd727379f4c07","modified":1520680530759},{"_id":"source/_posts/Web开发中前后端的模板引擎.md","hash":"d319dba5253e5f5995e947127f99faf0462f863d","modified":1507983912750},{"_id":"source/_posts/git bash修改主题配色.md","hash":"7319f6e89e88fe959e18ea1790bd11bec453ad45","modified":1507983912750},{"_id":"source/_posts/hello-world.md","hash":"5ece4dc640eadc296398657cba4c017e029fda3f","modified":1494505628337},{"_id":"source/_posts/java多线程编程(一).md","hash":"77e4c6a30f9c68b5fbbdebc490d6b72cf5acec25","modified":1509349369192},{"_id":"source/_posts/java多线程编程(二):CountDownLatch.md","hash":"f288242e2eba124e2bdb3ecaa94545a5f7dae8c8","modified":1509349419730},{"_id":"source/_posts/jsp页面中获取session对象.md","hash":"901f7406c17694b5327addc10799a08d04cd7002","modified":1507983912750},{"_id":"source/_posts/ngrok外网映射.md","hash":"f463c819f9fef3c3fa40e57c45d68de5e6d097c2","modified":1507983912751},{"_id":"source/_posts/为Next主题添加canvas-ribbon.md","hash":"59955093af96dce75969e74c1b5de8fa276d8479","modified":1507983912751},{"_id":"source/_posts/从0到有-如何搭建个人博客.md","hash":"90b5f8a284fc65465bb3eaa4393a8b2292d08815","modified":1507983912752},{"_id":"source/_posts/动手实现redis数据锁.md","hash":"8cfbba9291c07f16b6772893e40de52883158d3b","modified":1509348738492},{"_id":"source/_posts/微信开发模式接入.md","hash":"20436ef9f0a18713927c84c6cab852c1352af0ac","modified":1507983912753},{"_id":"source/_posts/计算丢失精度解决方法.md","hash":"7270736f44a5c180a13fb90e2d953c7d6bf23541","modified":1512961153992},{"_id":"source/_posts/记一次数据库查询优化.md","hash":"bd07028bd1f0ae1099dfaebc3645ce333e2e2390","modified":1512961153992},{"_id":"source/about/index.md","hash":"5abb284ae857e63120c7b819450b002c3b5d88ea","modified":1520781602123},{"_id":"source/project/README.md","hash":"e3636e84833e5b47452af07d4319668288e7dcb9","modified":1493881730417},{"_id":"source/project/index.html","hash":"c1ea8b7ccfef7735521c4b338c25b436aa6abb5f","modified":1493881730449},{"_id":"source/tags/index.md","hash":"e1956e163bd28298d969c0c0e986eace31761e1c","modified":1490886712543},{"_id":"themes/nextd/.github/CONTRIBUTING.md","hash":"4312fb37fa2b8663006be3c4fe01125ec01171c1","modified":1491391835811},{"_id":"themes/nextd/.github/ISSUE_TEMPLATE.md","hash":"2692e36cc35b1594530981e7727771f601720a43","modified":1491391835815},{"_id":"themes/nextd/.idea/encodings.xml","hash":"43122b4eae02776639c82397066ecd82aa4ca33a","modified":1494421898294},{"_id":"themes/nextd/.idea/modules.xml","hash":"e5e69be44641f37328f88505bd6b2221b45586fb","modified":1491391835830},{"_id":"themes/nextd/.idea/nextd.iml","hash":"402e38def734b476c4c697c9a36892567ab6af8b","modified":1491391835837},{"_id":"themes/nextd/languages/de.yml","hash":"4c3ffeb0d214c807a226dd98214958cb5483df1c","modified":1491391835898},{"_id":"themes/nextd/languages/default.yml","hash":"d2f6784b9c6567b64e58736e36025dbf96d863d4","modified":1491391835903},{"_id":"themes/nextd/languages/en.yml","hash":"df81ab6b1cf3c88ed053d3766381cd12eb659fe3","modified":1491391835907},{"_id":"themes/nextd/languages/fr-FR.yml","hash":"d8a40fe025fad6f42df0cf16d4be2d513769b062","modified":1491391835911},{"_id":"themes/nextd/languages/id.yml","hash":"19537c8bae42c4c2e7d06a64537e8dfd503b7e19","modified":1491391835915},{"_id":"themes/nextd/languages/ja.yml","hash":"e594aa42a33c489e4a65065659a01bb76c3c0cb5","modified":1491391835919},{"_id":"themes/nextd/languages/ko.yml","hash":"c59676f2af80c3c594c34c4a0fcbf65fd8864ff3","modified":1491391835924},{"_id":"themes/nextd/languages/pt-BR.yml","hash":"81498b783372f11b2149bd2b1731e78432760a0e","modified":1491391835930},{"_id":"themes/nextd/languages/pt.yml","hash":"4c64594f477905d5d2d9ca2422f03175b7b0c617","modified":1491391835934},{"_id":"themes/nextd/languages/ru.yml","hash":"c3aedb94decf05a301662afc3398ab563dd9995a","modified":1491391835939},{"_id":"themes/nextd/languages/zh-Hans.yml","hash":"80d460b59eded85995d16c69fb26a8547b2a27f0","modified":1491391835944},{"_id":"themes/nextd/languages/zh-hk.yml","hash":"88e603eb0f3fd25c35bb37bd30372fd77bba7c46","modified":1491391835948},{"_id":"themes/nextd/languages/zh-tw.yml","hash":"04479b419c72b71fd34046f3fc33ebda4fe8de84","modified":1491391835952},{"_id":"themes/nextd/layout/_layout.swig","hash":"cfc0ec5923c1ac74ec8c17184e454f3899ba7afe","modified":1491391835968},{"_id":"themes/nextd/layout/archive.swig","hash":"fec0d362cb78c4736e86a1bd12a09943b44c0c5a","modified":1491391836369},{"_id":"themes/nextd/layout/category.swig","hash":"f4f3988e9b927fb91c7fe54062c3fc8eaec884f2","modified":1491391836374},{"_id":"themes/nextd/layout/index.swig","hash":"f0ce3b57ef18a4434b128e5555f6e2d9612f8e34","modified":1494424476011},{"_id":"themes/nextd/layout/page.swig","hash":"0ec203e971c3cffba7f1d544ade434ad348c50f9","modified":1491391836382},{"_id":"themes/nextd/layout/post.swig","hash":"65f6f1b43abcd2ef56bb326485cbf759b6534c71","modified":1494504613528},{"_id":"themes/nextd/layout/schedule.swig","hash":"595013860078799d455af4965b3a7c5c4fd3923c","modified":1491391836390},{"_id":"themes/nextd/layout/tag.swig","hash":"8f2daf0e0460e7abb35db7b7d1865722607f1f90","modified":1491391836394},{"_id":"themes/nextd/scripts/merge-configs.js","hash":"f8cde6953939802f92da5b7a2458c6c539e9be69","modified":1491391836407},{"_id":"themes/nextd/test/.jshintrc","hash":"c9fca43ae0d99718e45a6f5ce736a18ba5fc8fb6","modified":1491391837852},{"_id":"themes/nextd/test/helpers.js","hash":"f25e7f3265eb5a6e1ccbb5e5012fa9bebf134105","modified":1491391837865},{"_id":"themes/nextd/test/intern.js","hash":"db90b1063356727d72be0d77054fdc32fa882a66","modified":1491391837878},{"_id":"themes/nextd/.idea/workspace.xml","hash":"03431f52f885a0d05d6e6fc8954c679075ed605e","modified":1495538973896},{"_id":"themes/nextd/source/fonts/.gitkeep","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836899},{"_id":"source/project/canvas-ribbon/canvas-ribbon.min.js","hash":"b69360968057c5a277152094978e9244cb05eeb0","modified":1493881730436},{"_id":"source/project/canvas-ribbon/index.html","hash":"19e3ed7f44969b07ed3519c2262f601a4c761a91","modified":1493881730448},{"_id":"source/project/stylesheets/style.css","hash":"343478bdb00cebd4fd86c4c7cd0d5aec11828686","modified":1493881730450},{"_id":"themes/nextd/.idea/inspectionProfiles/Project_Default.xml","hash":"62981ca258671eb2e922c824b39a75c2f000fa29","modified":1491391835827},{"_id":"themes/nextd/layout/_custom/header.swig","hash":"ba8ab5a0280b953aa97435ff8946cbcbb2755a27","modified":1491391835962},{"_id":"themes/nextd/layout/_custom/sidebar.swig","hash":"ba8ab5a0280b953aa97435ff8946cbcbb2755a27","modified":1491391835962},{"_id":"themes/nextd/layout/_macro/post-collapse.swig","hash":"b87a5122dbff1d5fccf8f3d09d1640bd4b01c4a0","modified":1491391835973},{"_id":"themes/nextd/layout/_macro/post-header.swig","hash":"7edad2781da755f61f2515d865563098f16ace86","modified":1491391835977},{"_id":"themes/nextd/layout/_macro/post.swig","hash":"7db6f52a8ebba07c9a98de3fa64fcc75122999b5","modified":1494424476004},{"_id":"themes/nextd/layout/_macro/reward.swig","hash":"b6cb171f0ed227b82b8f7601814af2df93f3a09a","modified":1491391835992},{"_id":"themes/nextd/layout/_macro/sidebar.swig","hash":"9fc9f89c169439d7584197930359b758eb198a1c","modified":1491391835996},{"_id":"themes/nextd/layout/_macro/wechat-subscriber.swig","hash":"c5cc0070ca7c9a8dbd4b09e0398db536c3cdbe8a","modified":1491391836001},{"_id":"themes/nextd/layout/_partials/comments.swig","hash":"9379d67b0df624c46d39c82577e15f6226df13c8","modified":1491391836006},{"_id":"themes/nextd/layout/_partials/duoshuo-hot-articles.swig","hash":"ba75672183d94f1de7c8bd0eeee497a58c70e889","modified":1491391836010},{"_id":"themes/nextd/layout/_partials/footer.swig","hash":"27e4b731c791a9db0822b5cfde81ef728ef9e273","modified":1491391836014},{"_id":"themes/nextd/layout/_partials/head.swig","hash":"881abebed3a7fa71827365b0ba0e84ec525eeb7f","modified":1491391836024},{"_id":"themes/nextd/layout/_partials/header.swig","hash":"03f166c75616952d4658493668ae5ad77943b051","modified":1493884531592},{"_id":"themes/nextd/layout/_partials/page-header.swig","hash":"dfbb6e9692333166aa78231ad12b2a40c153cbcb","modified":1491391836040},{"_id":"themes/nextd/layout/_partials/pagination.swig","hash":"1634fb887842698e01ff6e632597fe03c75d2d01","modified":1491391836044},{"_id":"themes/nextd/layout/_partials/search.swig","hash":"95b55fe35f2d2c22f2cc055d4379b5435314c7ec","modified":1491391836047},{"_id":"themes/nextd/layout/_scripts/baidu-push.swig","hash":"c5db707b46eac6a5df1d2a77f8556945a66fd181","modified":1491391836117},{"_id":"themes/nextd/layout/_scripts/boostrap.swig","hash":"c0f5a0955f69ca4ed9ee64a2d5f8aa75064935ad","modified":1491391836122},{"_id":"themes/nextd/layout/_scripts/commons.swig","hash":"931808ad9b8d8390c0dcf9bdeb0954eeb9185d68","modified":1491391836126},{"_id":"themes/nextd/layout/_scripts/vendors.swig","hash":"51292a6750ef9640027bfa31be75d911cae3287b","modified":1491391836360},{"_id":"themes/nextd/scripts/tags/button.js","hash":"aaf71be6b483fca7a65cd6296c2cf1c2271c26a6","modified":1491391836415},{"_id":"themes/nextd/scripts/tags/center-quote.js","hash":"99b66949f18398689b904907af23c013be1b978f","modified":1491391836422},{"_id":"themes/nextd/scripts/tags/full-image.js","hash":"86194a05a8c6499de0b2aaa525d6de135778c0ae","modified":1491391836430},{"_id":"themes/nextd/scripts/tags/group-pictures.js","hash":"ac681b0d0d8d39ba3817336c0270c6787c2b6b70","modified":1491391836445},{"_id":"themes/nextd/scripts/tags/note.js","hash":"7dc14db08f2c74f8f1952534b424f220f5c000c6","modified":1491391836452},{"_id":"themes/nextd/source/css/main.styl","hash":"a91dbb7ef799f0a171b5e726c801139efe545176","modified":1491391836898},{"_id":"themes/nextd/source/images/algolia_logo.svg","hash":"16505f61f19ba65f629dfd033f14ee9abcf18756","modified":1491391836903},{"_id":"themes/nextd/source/images/avatar.gif","hash":"264082bb3a1af70d5499c7d22b0902cb454b6d12","modified":1491391836905},{"_id":"themes/nextd/source/images/avatar.jpg","hash":"f1b5fb1cbe7ff1cfbbf2655cc74750d06aa43e0d","modified":1491391836910},{"_id":"themes/nextd/source/images/cc-by-nc-nd.svg","hash":"bc3588c9b2d7c68830524783120ff6cf957cf668","modified":1491391836914},{"_id":"themes/nextd/source/images/cc-by-nc-sa.svg","hash":"6f55543d1fb9cbc436c101d24f802dec7b41efc3","modified":1491391836919},{"_id":"themes/nextd/source/images/cc-by-nc.svg","hash":"6f076713fb9bf934aa2c1046bdf2cf2e37bc1eab","modified":1491391836925},{"_id":"themes/nextd/source/images/cc-by-nd.svg","hash":"42cd73da328077ccc92f859bb8f3cf621b3484f8","modified":1491391836929},{"_id":"themes/nextd/source/images/cc-by-sa.svg","hash":"70c1535f43e54e5ff35ca81419e77e4c0c301398","modified":1491391836934},{"_id":"themes/nextd/source/images/cc-by.svg","hash":"e92a33c32d1dac8ed94849b2b4e6456e887efe70","modified":1491391836938},{"_id":"themes/nextd/source/images/cc-zero.svg","hash":"9bfb52b2f63527a7049247bf00d44e6dc1170e7d","modified":1491391836940},{"_id":"themes/nextd/source/images/loading.gif","hash":"5fbd472222feb8a22cf5b8aa5dc5b8e13af88e2b","modified":1491391836952},{"_id":"themes/nextd/source/images/logo.png","hash":"6385f99b912ff8d4088bf14c984b31600a8870aa","modified":1491920941366},{"_id":"themes/nextd/source/images/placeholder.gif","hash":"5fbd472222feb8a22cf5b8aa5dc5b8e13af88e2b","modified":1491391836953},{"_id":"themes/nextd/source/images/quote-l.svg","hash":"cd108d6f44351cadf8e6742565217f88818a0458","modified":1491391836958},{"_id":"themes/nextd/source/images/quote-r.svg","hash":"2a2a250b32a87c69dcc1b1976c74b747bedbfb41","modified":1491391836962},{"_id":"themes/nextd/source/images/searchicon.png","hash":"67727a6a969be0b2659b908518fa6706eed307b8","modified":1491391836963},{"_id":"themes/nextd/test/nextd_home_preview.jpg","hash":"5330f0a0abc72d8b6fb6f22ff422854d9e59963b","modified":1491391837883},{"_id":"themes/nextd/test/nextd_post_preview.jpg","hash":"01a99326013f75a6f8980751c6c8ea322e890857","modified":1491391837889},{"_id":"themes/nextd/layout/_scripts/schemes/mist.swig","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836131},{"_id":"themes/nextd/layout/_scripts/schemes/muse.swig","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836131},{"_id":"themes/nextd/source/css/_mixins/Mist.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836761},{"_id":"themes/nextd/source/css/_mixins/Muse.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836762},{"_id":"themes/nextd/source/css/_mixins/custom.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836772},{"_id":"themes/nextd/source/css/_variables/Muse.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836876},{"_id":"themes/nextd/source/css/_variables/custom.styl","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1491391836892},{"_id":"themes/nextd/layout/_components/algolia-search/assets.swig","hash":"218cc936ba3518a3591b2c9eda46bc701edf7710","modified":1491391835957},{"_id":"themes/nextd/layout/_components/algolia-search/dom.swig","hash":"bb2c3a926bb7f8fea54d424882b25d93dfde7ae6","modified":1491391835961},{"_id":"themes/nextd/layout/_partials/head/custom-head.swig","hash":"a223919d2e1bf17ca4d6abb2c86f2efca9883dc1","modified":1491391836028},{"_id":"themes/nextd/layout/_partials/head/external-fonts.swig","hash":"f5e487b0d213ca0bd94aa30bc23b240d65081627","modified":1491391836032},{"_id":"themes/nextd/layout/_partials/search/swiftype.swig","hash":"a8c7f9ca7c605d039a1f3bf4e4d3183700a3dd62","modified":1491391836063},{"_id":"themes/nextd/layout/_partials/search/localsearch.swig","hash":"dec9045a65f0dc946157fa6adbf16bdaa70475fd","modified":1491391836051},{"_id":"themes/nextd/layout/_partials/search/tinysou.swig","hash":"b25002a83cbd2ca0c4a5df87ad5bff26477c0457","modified":1491391836066},{"_id":"themes/nextd/layout/_partials/share/add-this.swig","hash":"bf8e9223a40748b2e3ef77d753a8e1dbbce8095e","modified":1491391836071},{"_id":"themes/nextd/layout/_partials/share/baidushare.swig","hash":"3fdde03f45a80f7a85097a40b40358adde618fc7","modified":1491391836099},{"_id":"themes/nextd/layout/_partials/share/duoshuo_share.swig","hash":"d4fbffd7fa8f2090eb32a871872665d90a885fac","modified":1491391836103},{"_id":"themes/nextd/layout/_partials/share/jiathis.swig","hash":"12684840de632eb16e53ffa863166306a756fd4f","modified":1491391836114},{"_id":"themes/nextd/layout/_scripts/pages/post-details.swig","hash":"9b84ab576982b2c3bb0291da49143bc77fba3cc6","modified":1491391836130},{"_id":"themes/nextd/layout/_scripts/schemes/pisces.swig","hash":"a9a3995b9615adfb8d6b127c78c6771627bee19a","modified":1491391836135},{"_id":"themes/nextd/layout/_scripts/third-party/analytics.swig","hash":"91c5353fcb94cc3b3f265b06ad2341734bc4c826","modified":1491391836139},{"_id":"themes/nextd/layout/_scripts/third-party/comments.swig","hash":"7357167cc8004c90b6b6f60762d54d04b6ce8e0d","modified":1491391836210},{"_id":"themes/nextd/layout/_scripts/third-party/lean-analytics.swig","hash":"e495aed8fb36bf8015ddbd64366270a7debad2b0","modified":1491391836280},{"_id":"themes/nextd/layout/_scripts/third-party/localsearch.swig","hash":"a2b8c5a67f748b07395f6f630769df9d0f15c54e","modified":1491391836298},{"_id":"themes/nextd/layout/_scripts/third-party/mathjax.swig","hash":"4a5c6df1579a4ca72ed17f7dbd6d16a509aa7dc8","modified":1491391836322},{"_id":"themes/nextd/layout/_scripts/third-party/schedule.swig","hash":"db15d7e1552aa2d2386a6b8a33b3b3a40bf9e43d","modified":1491391836338},{"_id":"themes/nextd/layout/_scripts/third-party/tinysou.swig","hash":"fe95dd3d166634c466e19aa756e65ad6e8254d3e","modified":1491391836349},{"_id":"themes/nextd/source/css/_custom/custom.styl","hash":"a712321fa86c81305f39387488e1270a8da6931b","modified":1494504793726},{"_id":"themes/nextd/source/css/_mixins/Pisces.styl","hash":"a0f23e75a137d8c996c70e2059e0074f1e97a127","modified":1491391836765},{"_id":"themes/nextd/source/css/_mixins/base.styl","hash":"531934ea21ef4dc9f0978512050f54834f0a6cff","modified":1491391836772},{"_id":"themes/nextd/source/css/_variables/Mist.styl","hash":"e55265c8a8a6ae0c3c08e3509de92ee62c3cb5f6","modified":1491391836876},{"_id":"themes/nextd/source/css/_variables/Pisces.styl","hash":"27618ff30a6d34ef50312d6373fad144b70d14e8","modified":1491391836883},{"_id":"themes/nextd/source/css/_variables/base.styl","hash":"f44ef5ea3720d005aed6f68636a588c3119f4f72","modified":1491488155309},{"_id":"themes/nextd/source/js/src/algolia-search.js","hash":"84bdc8a4fe127849a5c99bdefe1d0b65ee1a4a0a","modified":1491391836994},{"_id":"themes/nextd/source/js/src/affix.js","hash":"1b509c3b5b290a6f4607f0f06461a0c33acb69b1","modified":1491391836982},{"_id":"themes/nextd/source/js/src/bootstrap.js","hash":"2d24c2137a9fe659b9912716e83880e0e699080c","modified":1491391837003},{"_id":"themes/nextd/source/js/src/hook-duoshuo.js","hash":"b35a7dc47b634197b93487cea8671a40a9fdffce","modified":1491391837014},{"_id":"themes/nextd/source/js/src/motion.js","hash":"7ce732f355674f62b90bad30cf1f56e3d8962f4c","modified":1491391837031},{"_id":"themes/nextd/source/js/src/post-details.js","hash":"37a641bd13231f2744074a27350ae784c4e42b89","modified":1491391837046},{"_id":"themes/nextd/source/js/src/scrollspy.js","hash":"b7657be25fc52ec67c75ab5481bdcb483573338b","modified":1491391837074},{"_id":"themes/nextd/source/js/src/utils.js","hash":"ee8290de70fb91a1b4d21435bbe91f5a79f4ed69","modified":1491391837090},{"_id":"themes/nextd/source/lib/algolia-instant-search/instantsearch.min.css","hash":"90ef19edc982645b118b095615838d9c5eaba0de","modified":1491391837096},{"_id":"themes/nextd/source/lib/canvas-nest/canvas-nest.min.js","hash":"0387e75e23b1db108a755073fe52a0d03eb391a7","modified":1491391837337},{"_id":"themes/nextd/source/lib/canvas-ribbon/canvas-ribbon.js","hash":"9df5547852e713fe018a58f99545629440898d4c","modified":1495538973898},{"_id":"themes/nextd/source/lib/fancybox/.bower.json","hash":"9be892a4e14e0da18ff9cb962c9ef71f163b1b22","modified":1491391837351},{"_id":"themes/nextd/source/lib/fancybox/.gitattributes","hash":"672d3b5767e0eacd83bb41b188c913f2cf754793","modified":1491391837357},{"_id":"themes/nextd/source/lib/fastclick/.bower.json","hash":"bf3eef9d647cd7c9b62feda3bc708c6cdd7c0877","modified":1491391837474},{"_id":"themes/nextd/source/lib/fastclick/LICENSE","hash":"6f474ea75c42442da7bbcf2e9143ce98258efd8d","modified":1491391837479},{"_id":"themes/nextd/source/lib/fastclick/README.md","hash":"68a9b9d53126405b0fa5f3324f1fb96dbcc547aa","modified":1491391837485},{"_id":"themes/nextd/source/lib/fastclick/bower.json","hash":"a9b3ee1e4db71a0e4ea6d5bed292d176dd68b261","modified":1491391837490},{"_id":"themes/nextd/source/lib/font-awesome/.bower.json","hash":"8868275e8b6340c87a81c69a54ed138d11fb3c3e","modified":1491391837541},{"_id":"themes/nextd/source/lib/font-awesome/.gitignore","hash":"03ddbf76c1dd1afb93eed0b670d2eee747472ef1","modified":1491391837542},{"_id":"themes/nextd/source/lib/font-awesome/.npmignore","hash":"c31ff06a740955e44edd4403902e653ccabfd4db","modified":1491391837545},{"_id":"themes/nextd/source/lib/font-awesome/HELP-US-OUT.txt","hash":"ee33b2798b1e714b904d663436c6b3521011d1fa","modified":1491391837549},{"_id":"themes/nextd/source/lib/font-awesome/bower.json","hash":"71e7183634dc1b9449f590f15ebd7201add22ca7","modified":1491391837553},{"_id":"themes/nextd/source/lib/jquery/.bower.json","hash":"865d6c1328ab209a4376b9d2b7a7824369565f28","modified":1491391837637},{"_id":"themes/nextd/source/lib/jquery_lazyload/.bower.json","hash":"90fa628f156d8045357ff11eaf32e61abacf10e8","modified":1491391837682},{"_id":"themes/nextd/source/lib/jquery_lazyload/CONTRIBUTING.md","hash":"4ded6fee668544778e97e38c2b211fc56c848e77","modified":1491391837691},{"_id":"themes/nextd/source/lib/jquery_lazyload/README.md","hash":"b930297cb98b8e1dbd5abe9bc1ed9d5935d18ce8","modified":1491391837696},{"_id":"themes/nextd/source/lib/jquery_lazyload/bower.json","hash":"e0acf1db27b0cc16128a59c46db1db406b5c4c58","modified":1491391837700},{"_id":"themes/nextd/source/lib/jquery_lazyload/jquery.lazyload.js","hash":"f4a570908f6c89c6edfb1c74959e733eaadea4f2","modified":1491391837715},{"_id":"themes/nextd/source/lib/jquery_lazyload/jquery.scrollstop.js","hash":"bf773ad48a0b9aa77681a89d7569eefc0f7b7b18","modified":1491391837726},{"_id":"themes/nextd/source/lib/velocity/.bower.json","hash":"63da5e80ebb61bb66a2794d5936315ca44231f0c","modified":1491391837760},{"_id":"themes/nextd/source/lib/velocity/bower.json","hash":"92d92860418c4216aa59eb4cb4a556290a7ad9c3","modified":1491391837765},{"_id":"themes/nextd/source/lib/velocity/velocity.min.js","hash":"bf172816a9c57f9040e3d19c24e181a142daf92b","modified":1491391837823},{"_id":"themes/nextd/source/lib/velocity/velocity.ui.js","hash":"dbbfb50f6502f6b81dcc9fee7b31f1e812da3464","modified":1491391837835},{"_id":"themes/nextd/source/lib/velocity/velocity.ui.min.js","hash":"dde584994ac13dc601836e86f4cf490e418d9723","modified":1491391837849},{"_id":"themes/nextd/source/lib/jquery/index.js","hash":"17a740d68a1c330876c198b6a4d9319f379f3af2","modified":1491391837677},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/baidu-analytics.swig","hash":"ae5b8597603d4e42ee66ed121544e7b1c644767e","modified":1491391836162},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/busuanzi-counter.swig","hash":"24105e62d7f26946907fa14cd02589f899bf8122","modified":1491391836166},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/application-insights.swig","hash":"71397a5823e8ec8aad3b68aace13150623b3e19d","modified":1491391836151},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/cnzz-analytics.swig","hash":"3931f9c3bac3970a3f54c9d0072ae4c950aa176c","modified":1491391836169},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/facebook-sdk.swig","hash":"a79e7e0d809fcf407593dd7ed9e023db21c3cbd6","modified":1491391836180},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/google-analytics.swig","hash":"1b6af02fd0ba3f729675cd95429a0cea4aebf358","modified":1491391836190},{"_id":"themes/nextd/layout/_scripts/third-party/analytics/tencent-analytics.swig","hash":"8a399df90dadba5ad4e781445b58f4765aeb701e","modified":1491391836206},{"_id":"themes/nextd/layout/_scripts/third-party/comments/duoshuo.swig","hash":"0a2f48971d86ea72e1a8fd1d8bbf2b7d423666b2","modified":1491391836231},{"_id":"themes/nextd/layout/_scripts/third-party/comments/gentie.swig","hash":"0f38f053841ef77cdce56a84cfbb4dd4c3329486","modified":1491391836241},{"_id":"themes/nextd/layout/_scripts/third-party/comments/disqus.swig","hash":"f8b6a3017ab79057ce99f1ccb512193d67f4a35f","modified":1491391836220},{"_id":"themes/nextd/layout/_scripts/third-party/comments/hypercomments.swig","hash":"af7f3e43cbdc4f88c13f101f0f341af96ace3383","modified":1491391836251},{"_id":"themes/nextd/layout/_scripts/third-party/comments/youyan.swig","hash":"f40a697fd046415924a142eec1effad70f3cb187","modified":1491391836257},{"_id":"themes/nextd/source/css/_common/components/back-to-top.styl","hash":"ad69cbf94eedacc27e756cdb9c7073416db697d0","modified":1491391836457},{"_id":"themes/nextd/source/css/_common/components/buttons.styl","hash":"22828f5141c0cecb9ef25a110e194cdfa3a36423","modified":1491391836461},{"_id":"themes/nextd/source/css/_common/components/comments.styl","hash":"ff4489cd582f518bba6909a301ac1292a38b4e96","modified":1491391836464},{"_id":"themes/nextd/source/css/_common/components/components.styl","hash":"b7d5cc29586ac796a50d90974ad99d24a5982137","modified":1491391836468},{"_id":"themes/nextd/source/css/_common/components/pagination.styl","hash":"88559b13ce94311405b170a0506ded91273beceb","modified":1491391836562},{"_id":"themes/nextd/source/css/_common/components/tag-cloud.styl","hash":"6eb4bcc3056bd279d000607e8b4dad50d368ca69","modified":1491391836664},{"_id":"themes/nextd/source/css/_common/outline/outline.styl","hash":"520159c2260d5af8dbcc4b710a99c0f8714c9b7d","modified":1491391836728},{"_id":"themes/nextd/source/css/_common/scaffolding/base.styl","hash":"ad887b394a41120d0a13f4977bd907ea1e6a0818","modified":1491488952462},{"_id":"themes/nextd/source/css/_common/scaffolding/helpers.styl","hash":"773ed7316ecde9616e28975b0ab004b143f87b48","modified":1491391836740},{"_id":"themes/nextd/source/css/_common/scaffolding/normalize.styl","hash":"3f40e8a9fe8e7bd5cfc4cf4cbbbcb9539462e973","modified":1491391836744},{"_id":"themes/nextd/source/css/_common/scaffolding/scaffolding.styl","hash":"c9218b48c56e52c06af9ce3cc8fbdae737cf16fe","modified":1491391836750},{"_id":"themes/nextd/source/css/_common/scaffolding/tables.styl","hash":"ea9069645696f86c5df64208490876fe150c8cae","modified":1491391836754},{"_id":"themes/nextd/source/css/_schemes/Mist/_base.styl","hash":"25d5e45a355ee2093f3b8b8eeac125ebf3905026","modified":1491391836779},{"_id":"themes/nextd/source/css/_schemes/Mist/_header.styl","hash":"d0bfd1bef988c76f7d7dd72d88af6f0908a8b0db","modified":1491391836786},{"_id":"themes/nextd/source/css/_schemes/Mist/_logo.styl","hash":"b1025c421406d2c24cc92a02ae28c1915b01e240","modified":1491391836789},{"_id":"themes/nextd/source/css/_schemes/Mist/_menu.styl","hash":"26666c1f472bf5f3fb9bc62081cca22b4de15ccb","modified":1491391836795},{"_id":"themes/nextd/source/css/_schemes/Mist/_posts-expanded.styl","hash":"ce272226a1570f5f7c70243b751a5b0fe1671a88","modified":1491391836802},{"_id":"themes/nextd/source/css/_schemes/Mist/_search.styl","hash":"09c965022c13b84ed8a661fee8ac2a6d550495ae","modified":1491391836808},{"_id":"themes/nextd/source/css/_schemes/Mist/index.styl","hash":"9b913b73d31d21f057f97115ffab93cfa578b884","modified":1491391836815},{"_id":"themes/nextd/source/css/_schemes/Muse/_layout.styl","hash":"124b540f059fd1ed13514362007cfc70355278c6","modified":1491391836827},{"_id":"themes/nextd/source/css/_schemes/Muse/_logo.styl","hash":"748dbfbf9c08e719ddc775958003c64b00d39dab","modified":1491391836830},{"_id":"themes/nextd/source/css/_schemes/Muse/_menu.styl","hash":"13af2fb21fabfc4df4b577ce5363e13d03daff71","modified":1491391836834},{"_id":"themes/nextd/source/css/_schemes/Muse/_search.styl","hash":"09c965022c13b84ed8a661fee8ac2a6d550495ae","modified":1491391836835},{"_id":"themes/nextd/source/css/_schemes/Muse/index.styl","hash":"5dbc0d0c897e46760e5dbee416530d485c747bba","modified":1491391836839},{"_id":"themes/nextd/source/css/_schemes/Pisces/_brand.styl","hash":"2a62281dedab5844b2e03cb73401591a54cf619e","modified":1494424476060},{"_id":"themes/nextd/source/css/_schemes/Pisces/_layout.styl","hash":"1ed0b17de59a30802169ba6f522a3d7d0f604ad8","modified":1494424476070},{"_id":"themes/nextd/source/css/_schemes/Pisces/_menu.styl","hash":"123737a165b10442a50ae7fc46669198955d6295","modified":1491391836855},{"_id":"themes/nextd/source/css/_schemes/Pisces/_sidebar.styl","hash":"983c0723e8cfd84b67c2e66da0c26425a8db06e0","modified":1491391836865},{"_id":"themes/nextd/source/css/_schemes/Pisces/index.styl","hash":"b9c02eb18bee6a1af281929d3a74446c84fba41c","modified":1491391836869},{"_id":"themes/nextd/source/css/_schemes/Pisces/_posts.styl","hash":"0303ea67f6de971ca26c8065d1839efeed2c6f4a","modified":1491391836859},{"_id":"themes/nextd/source/js/src/schemes/pisces.js","hash":"9890d95abfff0b4dcc55fbea3fa9d2c340486d8c","modified":1491391837054},{"_id":"themes/nextd/source/lib/fancybox/source/blank.gif","hash":"2daeaa8b5f19f0bc209d976c02bd6acb51b00b0a","modified":1491391837359},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_loading.gif","hash":"1a755fb2599f3a313cc6cfdb14df043f8c14a99c","modified":1491391837360},{"_id":"themes/nextd/source/lib/fancybox/source/[email protected]","hash":"273b123496a42ba45c3416adb027cd99745058b0","modified":1491391837361},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_overlay.png","hash":"b3a4ee645ba494f52840ef8412015ba0f465dbe0","modified":1491391837362},{"_id":"themes/nextd/source/lib/fancybox/source/fancybox_sprite.png","hash":"17df19f97628e77be09c352bf27425faea248251","modified":1491391837363},{"_id":"themes/nextd/source/lib/fancybox/source/[email protected]","hash":"30c58913f327e28f466a00f4c1ac8001b560aed8","modified":1491391837364},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.css","hash":"82f33ad0842aa9c154d029e0dada2497d4eb1d57","modified":1491391837431},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.js","hash":"d71602cbca33b9ecdb7ab291b7f86a49530f3601","modified":1491391837447},{"_id":"themes/nextd/source/lib/fancybox/source/jquery.fancybox.pack.js","hash":"ae6318aeb62ad4ce7a7e9a4cdacd93ffb004f0fb","modified":1491391837467},{"_id":"themes/nextd/source/lib/fastclick/lib/fastclick.js","hash":"1d6aeda0480d0e4cb6198edf7719d601d4ae2ccc","modified":1491391837505},{"_id":"themes/nextd/source/lib/fastclick/lib/fastclick.min.js","hash":"2cae0f5a6c5d6f3cb993015e6863f9483fc4de18","modified":1491391837536},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.css","hash":"a02674d823c7b577d38c3cdb91953993b6e4b3a0","modified":1491391837558},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.css.map","hash":"1573904b82807abbb32c97a3632c6c6808eaac50","modified":1491391837563},{"_id":"themes/nextd/source/lib/font-awesome/css/font-awesome.min.css","hash":"3c1d63dd1176c77f9f4cdb1616fbb08c31b9822f","modified":1491391837568},{"_id":"themes/nextd/source/lib/ua-parser-js/dist/ua-parser.min.js","hash":"41ea797c68dbcff2f6fb3aba1d1043a22e7cc0f6","modified":1491391837741},{"_id":"themes/nextd/source/lib/ua-parser-js/dist/ua-parser.pack.js","hash":"a817b6c158cbc5bab3582713de9fe18a18a80552","modified":1491391837755},{"_id":"themes/nextd/source/lib/font-awesome/fonts/FontAwesome.otf","hash":"1b22f17fdc38070de50e6d1ab3a32da71aa2d819","modified":1491391837577},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.eot","hash":"965ce8f688fedbeed504efd498bc9c1622d12362","modified":1491391837599},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.woff2","hash":"97e438cc545714309882fbceadbf344fcaddcec5","modified":1491391837633},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.woff","hash":"6d7e6a5fc802b13694d8820fc0138037c0977d2e","modified":1491391837628},{"_id":"themes/nextd/source/lib/velocity/velocity.js","hash":"4237c6e9d59da349639de20e559e87c2c0218cfd","modified":1491391837800},{"_id":"themes/nextd/source/css/_common/components/footer/footer.styl","hash":"4c4ef6e997d0c6e21de39c2daa0c768e12c8c6fa","modified":1491391836472},{"_id":"themes/nextd/source/css/_common/components/header/header.styl","hash":"90432053efe78bd7f6fa01528bff794a32dfa7c8","modified":1491391836476},{"_id":"themes/nextd/source/css/_common/components/header/headerband.styl","hash":"83796acbe29c71c7086d3b6505242202be692098","modified":1491391836480},{"_id":"themes/nextd/source/css/_common/components/header/menu.styl","hash":"139e71437d4bfbc06e0a79c2e262278a1ddf1adc","modified":1491391836486},{"_id":"themes/nextd/source/css/_common/components/header/site-home.styl","hash":"3b09712f29f8436ef319ab12117f2d299f0dacef","modified":1494424476018},{"_id":"themes/nextd/source/css/_common/components/header/site-meta.styl","hash":"767cfdcba8805202af717eb9b81113a7e85d7640","modified":1494424476029},{"_id":"themes/nextd/source/css/_common/components/header/site-nav.styl","hash":"c77481d05182a4b0e6b495e26222a3df51d3eb52","modified":1491391836521},{"_id":"themes/nextd/source/css/_common/components/highlight/diff.styl","hash":"167986d0f649516671ddf7193eebba7b421cd115","modified":1491391836525},{"_id":"themes/nextd/source/css/_common/components/highlight/highlight.styl","hash":"70ec8d38d2b3ee1906793d1dcb68032adfa65f03","modified":1491391836532},{"_id":"themes/nextd/source/css/_common/components/highlight/theme.styl","hash":"12e366f04497e3f44388fd40111a03e02f7c26af","modified":1491391836536},{"_id":"themes/nextd/source/css/_common/components/pages/archive.styl","hash":"104b5c79cd891506e0beaf938b083685f1da8637","modified":1491391836540},{"_id":"themes/nextd/source/css/_common/components/pages/categories.styl","hash":"7fb593f90d74a99c21840679933b9ef6fdc16a61","modified":1491391836543},{"_id":"themes/nextd/source/css/_common/components/pages/pages.styl","hash":"b8f9c95702e87fd0b170ab586c82c9718a245f8a","modified":1491391836550},{"_id":"themes/nextd/source/css/_common/components/pages/post-detail.styl","hash":"4e3838d7ac81d9ad133960f0f7ed58a44a015285","modified":1491391836554},{"_id":"themes/nextd/source/css/_common/components/pages/schedule.styl","hash":"8cf318644acc8b4978537c263290363e21c7f5af","modified":1491391836558},{"_id":"themes/nextd/source/css/_common/components/post/post-button.styl","hash":"595fa8fad7aa169db20ded00bdb2902eaefc07d8","modified":1494424476040},{"_id":"themes/nextd/source/css/_common/components/post/post-eof.styl","hash":"a200c0a1c5a895ac9dc41e0641a5dfcd766be99b","modified":1491391836577},{"_id":"themes/nextd/source/css/_common/components/post/post-collapse.styl","hash":"a45f5fce643eec4e1b927165229d560364bcace1","modified":1491391836573},{"_id":"themes/nextd/source/css/_common/components/post/post-expand.styl","hash":"1ff9cf4d3b45d7c95ffffc3c2a2bc8852a3443c1","modified":1491391836583},{"_id":"themes/nextd/source/css/_common/components/post/post-gallery.styl","hash":"cd9e214e502697f2f2db84eb721bac57a49b0fce","modified":1491391836587},{"_id":"themes/nextd/source/css/_common/components/post/post-header.styl","hash":"db22b474c9f0f8470e4039173ac53e9594d92ea5","modified":1491391836591},{"_id":"themes/nextd/source/css/_common/components/post/post-meta.styl","hash":"a3c73014859b1b2f1db04d384697702537a0a3c8","modified":1491391836595},{"_id":"themes/nextd/source/css/_common/components/post/post-nav.styl","hash":"929fac3a505bacbce6ba63009fd15851e2a8669d","modified":1491391836599},{"_id":"themes/nextd/source/css/_common/components/post/post-reward.styl","hash":"8355b0e9375b3245508efda0e18acd069c2aa767","modified":1491391836604},{"_id":"themes/nextd/source/css/_common/components/post/post-tags.styl","hash":"5a982d8ef3b3623ea5f59e63728990f5623c1b57","modified":1491391836608},{"_id":"themes/nextd/source/css/_common/components/post/post-title.styl","hash":"350469437b20ecfd6f3ca45e400478f8e3f71cfb","modified":1491391836612},{"_id":"themes/nextd/source/css/_common/components/post/post-type.styl","hash":"01567edaea6978628aa5521a122a85434c418bfd","modified":1491391836618},{"_id":"themes/nextd/source/css/_common/components/post/post.styl","hash":"1550390eee1de556118581d85e13dabdd169e732","modified":1491391836623},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-author-links.styl","hash":"7f2bdd6109614d35408ee5ac3335aad4464c69c7","modified":1491391836627},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-blogroll.styl","hash":"821991c0890966a512b43e8b1cf9537e738a09a0","modified":1491391836634},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-author.styl","hash":"761eba9811b050b25d548cc0854de4824b41eb08","modified":1491391836630},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-feed-link.styl","hash":"61f8cea3c01acd600e90e1bc2a07def405503748","modified":1491391836637},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-nav.styl","hash":"1153bb71edf253765145559674390e16dd67c633","modified":1491391836644},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-toc.styl","hash":"394888efec32749b353292a59ec7f1b609d6325e","modified":1491391836649},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar-toggle.styl","hash":"06b9a99d63b4d57fdbf70b88ab7036fbc47e3f52","modified":1491391836653},{"_id":"themes/nextd/source/css/_common/components/sidebar/sidebar.styl","hash":"702be9e57dd6ff5fa99642a1f6e3df26215b8805","modified":1491391836656},{"_id":"themes/nextd/source/css/_common/components/sidebar/site-state.styl","hash":"e71652d3216e289c8548b1ea2357822c1476a425","modified":1491391836660},{"_id":"themes/nextd/source/css/_common/components/tags/blockquote-center.styl","hash":"2fe76476432b31993338cb45cdb3b29a518b6379","modified":1491391836665},{"_id":"themes/nextd/source/css/_common/components/tags/full-image.styl","hash":"3159b55f35c40bd08e55b00148c523760a708c51","modified":1491391836671},{"_id":"themes/nextd/source/css/_common/components/tags/group-pictures.styl","hash":"2ad1a2a9bbf6742d1b0762c4c623b68113d1e0fe","modified":1491391836676},{"_id":"themes/nextd/source/css/_common/components/tags/note.styl","hash":"8420b4be386469337243336aee694297875bd439","modified":1491391836682},{"_id":"themes/nextd/source/css/_common/components/tags/tags.styl","hash":"a83f493e494f5c73fab8f6f5b686ef1670490095","modified":1491391836686},{"_id":"themes/nextd/source/css/_common/components/third-party/algolia-search.styl","hash":"3b1aabbab57b0b1fafa311feb1212f59e78e7928","modified":1491391836690},{"_id":"themes/nextd/source/css/_common/components/third-party/baidushare.styl","hash":"5dbeed535d63a50265d96b396a5440f9bb31e4ba","modified":1491391836694},{"_id":"themes/nextd/source/css/_common/components/third-party/busuanzi-counter.styl","hash":"7f7e9df15148608a9c29326dd880d8e8e8efc0ec","modified":1491391836697},{"_id":"themes/nextd/source/css/_common/components/third-party/duoshuo.styl","hash":"717cc7f82be9cc151e23a7678601ff2fd3a7fa1d","modified":1491391836702},{"_id":"themes/nextd/source/css/_common/components/third-party/gentie.styl","hash":"cd526e814f9323a79fe835085d64867d34b3715d","modified":1491391836706},{"_id":"themes/nextd/source/css/_common/components/third-party/jiathis.styl","hash":"15975ba7456b96916b1dbac448a1a0d2c38b8f3d","modified":1491391836710},{"_id":"themes/nextd/source/css/_common/components/third-party/localsearch.styl","hash":"f36316fb5b40cabde49c874db8ffe4166d49ee48","modified":1491391836717},{"_id":"themes/nextd/source/css/_common/components/third-party/third-party.styl","hash":"7bd182d918f3117335a5ee87a1b544e6d2b54d7d","modified":1491391836722},{"_id":"themes/nextd/source/css/_schemes/Mist/outline/outline.styl","hash":"a07aa12cc36ac5c819670c2a3c17d07ed7a08986","modified":1491391836819},{"_id":"themes/nextd/source/css/_schemes/Mist/sidebar/sidebar-blogroll.styl","hash":"cf900c5026ab36f31118317d0ae32a213e3ec2a9","modified":1491391836823},{"_id":"themes/nextd/source/css/_schemes/Muse/sidebar/sidebar-blogroll.styl","hash":"cf900c5026ab36f31118317d0ae32a213e3ec2a9","modified":1491391836840},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/fancybox_buttons.png","hash":"e385b139516c6813dcd64b8fc431c364ceafe5f3","modified":1491391837366},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-buttons.css","hash":"6394c48092085788a8c0ef72670b0652006231a1","modified":1491391837370},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-buttons.js","hash":"ee948b4489aedeb548a77c9e45d8c7c5732fd62d","modified":1491391837382},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-media.js","hash":"51139a4c79573d372a347ef01a493222a1eaf10a","modified":1491391837394},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-thumbs.css","hash":"b88b589f5f1aa1b3d87cc7eef34c281ff749b1ae","modified":1491391837398},{"_id":"themes/nextd/source/lib/fancybox/source/helpers/jquery.fancybox-thumbs.js","hash":"d22b1629cb23a6181bebb70d0cf653ffe4b835c8","modified":1491391837414},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.ttf","hash":"61d8d967807ef12598d81582fa95b9f600c3ee01","modified":1491391837623},{"_id":"themes/nextd/source/lib/algolia-instant-search/instantsearch.min.js","hash":"90a1b22129efc172e2dfcceeeb76bff58bc3192f","modified":1491391837319},{"_id":"themes/nextd/source/lib/font-awesome/fonts/fontawesome-webfont.svg","hash":"964e8dac2cee79c4b49b5bc300675773f6518812","modified":1491391837615},{"_id":"public/project/canvas-ribbon/canvas-ribbon.min.js","hash":"b04a1cef65c20df3d4b6d152c0add8e724bc2078","modified":1520781883328},{"_id":"public/project/stylesheets/style.css","hash":"fabc637b707a215b0794ee48c601c68e2ea8db70","modified":1520781883375},{"_id":"public/baidusitemap.xml","hash":"f0a52b2ab900722d0244b4ff63c54fe7e237d7a1","modified":1520781883375},{"_id":"public/sitemap.xml","hash":"20a77e4de27add7cc28dee0e3832c5643f3e13da","modified":1520781883375},{"_id":"public/google091459981c22016a.html","hash":"879ae86fd725a71989ff5fe4c8fa887ed950c248","modified":1520781883391},{"_id":"public/project/README.html","hash":"8bacd49b39e2f48794a1f6c7e95143842353060b","modified":1520781883406},{"_id":"public/project/index.html","hash":"d3b2a92cdf9d3cfea76ea3062a567a38cd1825b9","modified":1520781883406},{"_id":"public/archives/2017/05/index.html","hash":"7aa73b1243c9337e5d28a52edbe98cac7b07609a","modified":1520781883406},{"_id":"public/archives/2017/11/index.html","hash":"d241552e7c32c5c5977ea98f729fd40b18ce3fc4","modified":1520781883406},{"_id":"public/archives/2017/12/index.html","hash":"62cb7fb27ca6a0047f33b0c50a2516f238364f0b","modified":1520781883406},{"_id":"public/archives/2018/index.html","hash":"09e482a7c07799f93fa5542db384689fcb49f92b","modified":1520781883406},{"_id":"public/archives/2018/03/index.html","hash":"7322fb35857f9f574d5515d3c3258b8273011ac8","modified":1520781883406},{"_id":"public/tags/Java/page/2/index.html","hash":"6b1f2d1a78ec02f47dbe27ab7d3641e964c221aa","modified":1520781883406},{"_id":"public/tags/JavaWeb/index.html","hash":"30bf60982309e5b655f15ca1d622248c3b7feddf","modified":1520781883406},{"_id":"public/tags/JsWeb/index.html","hash":"8b222cbf0d1a5768eef1d0282785125c4dc327be","modified":1520781883406},{"_id":"public/tags/HttpClient/index.html","hash":"c85c8fa7a2f57340510244d0af99db2fcae2c89c","modified":1520781883406},{"_id":"public/tags/jade/index.html","hash":"fb1d56319703d5cb1cbd87bcb418c0ceb37ac76f","modified":1520781883406},{"_id":"public/tags/模板引擎/index.html","hash":"3ad7752805a2f3c574641a7ed754aae461da5192","modified":1520781883406},{"_id":"public/tags/angualr/index.html","hash":"3f5fab7b73d5e37477e245517694cee0bd7601b8","modified":1520781883406},{"_id":"public/tags/mvc/index.html","hash":"0960454539b7cf373352a0119002f05793291542","modified":1520781883406},{"_id":"public/tags/Nodejs/index.html","hash":"99fa61e11c875d692b382916428866d83ff7b2f2","modified":1520781883406},{"_id":"public/tags/Git-bash/index.html","hash":"b6081373e9ae7a8af6176948ed5bbf29fc07e9a1","modified":1520781883406},{"_id":"public/tags/Git/index.html","hash":"0b3cffc71481647746f5ad68ea64742cd19f5b11","modified":1520781883406},{"_id":"public/tags/Scheme/index.html","hash":"23ddba1f7d759bad343d436dd3d60330cb48f183","modified":1520781883406},{"_id":"public/tags/Shell/index.html","hash":"1b672d83aeb1a2f58f5e74ecf04d51798346de1a","modified":1520781883406},{"_id":"public/tags/Hexo/index.html","hash":"ae25448ced3700bbbe014a97f58aaa2ad882e723","modified":1520781883406},{"_id":"public/tags/GitHub/index.html","hash":"4db877deff025a424d57077601302247a90eaaad","modified":1520781883406},{"_id":"public/tags/多线程/index.html","hash":"73372eb0156b96882d4d099ef65475e5e99dcb4f","modified":1520781883406},{"_id":"public/tags/CountDownLatch/index.html","hash":"8af00c58fdcaa67b70057b2c1c78207db2f8df25","modified":1520781883406},{"_id":"public/tags/jsp/index.html","hash":"a965c4fe2b1285867341dc348a43a2446c03cb1d","modified":1520781883406},{"_id":"public/tags/session/index.html","hash":"320204a3e534213b5dc3f90ea615b5bb8ad6558b","modified":1520781883406},{"_id":"public/tags/el表达式/index.html","hash":"22dbe8693b3b68a4a76919df9bd48f0d94cbf347","modified":1520781883406},{"_id":"public/tags/ngrok/index.html","hash":"78ac6d255ec373a641ff045bdc9816d6b4424927","modified":1520781883406},{"_id":"public/tags/外网映射/index.html","hash":"2b7aac981671d0ce5bd6615f0b6e5a963b045a05","modified":1520781883406},{"_id":"public/tags/微信开发/index.html","hash":"f04edfe1085321cd24b07a23b8b627ef44a24002","modified":1520781883406},{"_id":"public/tags/Canvas/index.html","hash":"94e88762018854d6ab8b0d2102e4ef92343d6e8e","modified":1520781883406},{"_id":"public/tags/Next/index.html","hash":"6a8c15b75969fe73f443fcbb6de07c0a54a83030","modified":1520781883406},{"_id":"public/tags/JavaScript/index.html","hash":"e9319f4cad2020a1e0563a793be222eec51882c4","modified":1520781883406},{"_id":"public/tags/redis/index.html","hash":"cc85108d37a8feb14e4f09391637c5ab24d11b8f","modified":1520781883406},{"_id":"public/tags/Jedis/index.html","hash":"4de0240e866ee7312be32033d5d44af2e16c682d","modified":1520781883406},{"_id":"public/tags/事务/index.html","hash":"bab11645c6ddd962dbe831ff8fb9318a8f8bec4b","modified":1520781883406},{"_id":"public/tags/字段锁/index.html","hash":"d540b8060157506ac5239282315cd9c9d5924d8d","modified":1520781883406},{"_id":"public/tags/Servlet/index.html","hash":"5e31224296a3bf0a70e94e80828f81436d01e353","modified":1520781883406},{"_id":"public/tags/mysql/index.html","hash":"0f5c5caf4bb1d62f45bab0a1d5e7ded2899fd02a","modified":1520781883406},{"_id":"public/tags/B-树/index.html","hash":"5197be54fca45c97e169739194b9347cf099ade7","modified":1520781883406},{"_id":"public/tags/数据库索引/index.html","hash":"c5eb280102fd23d60702b1f83a2314b40be47c8e","modified":1520781883406},{"_id":"public/tags/浮点数计算精度/index.html","hash":"ad65154590175c81caae032375ebb420622c59d9","modified":1520781883406},{"_id":"public/tags/Javascript/index.html","hash":"9a92ad7c56fec3865da8f2bceb5544b320849c8c","modified":1520781883406},{"_id":"public/tags/BigDecimal/index.html","hash":"dd6ce89191b67b6877517f08b2827a2334da11d3","modified":1520781883406},{"_id":"public/about/index.html","hash":"0bf040871a36006d1d4c3b24d557ae9658905d04","modified":1520781883406},{"_id":"public/tags/index.html","hash":"7fbe4b26640258147b3cf20ac10550d1399ad024","modified":1520781883406},{"_id":"public/project/canvas-ribbon/index.html","hash":"c22eb1295adeff26d5dd32d75ef29c475688b99f","modified":1520781883406},{"_id":"public/2018/JsWeb框架手册/index.html","hash":"e2e6be49a5c9805d9f719bb5029934f613128b63","modified":1520781883406},{"_id":"public/2017/记一次数据库查询优化/index.html","hash":"1a8974d4d41703daea037b35d72f1732c24a15b1","modified":1520781883406},{"_id":"public/2017/计算丢失精度解决方法/index.html","hash":"5aaafd352f378e3a012edce901837a98499a59cd","modified":1520781883406},{"_id":"public/2017/java多线程编程(二):CountDownLatch/index.html","hash":"8a6cde4a17f4f79316319b3c3f5fdb0e92313add","modified":1520781883406},{"_id":"public/2017/java多线程编程(一)/index.html","hash":"0370db32a03c0efb17601a7c95894daad626d360","modified":1520781883406},{"_id":"public/2017/动手实现redis数据锁/index.html","hash":"30e1ef7fbe6e02080919601d5dde1fb89700a35c","modified":1520781883406},{"_id":"public/2017/HttpClient学习记录/index.html","hash":"b4ace62dc6911acf53dc2fdc6adb8a290c5f8213","modified":1520781883406},{"_id":"public/2017/微信开发模式接入/index.html","hash":"44fdc64eb14733f1d29069b1b6487f6ff89a2961","modified":1520781883406},{"_id":"public/2017/ngrok外网映射/index.html","hash":"0a83f7ecca5e86552a26fe1688d291102466bb3d","modified":1520781883406},{"_id":"public/2017/jsp页面中获取session对象/index.html","hash":"031bd2d52bc8e0a6c8dc322983ebf5310dbde59a","modified":1520781883406},{"_id":"public/2017/Web开发中前后端的模板引擎/index.html","hash":"7aa937de45fca28efe63a3593ad25c94305fb793","modified":1520781883406},{"_id":"public/2017/git bash修改主题配色/index.html","hash":"fb970426209ef3c0aa21a8e942f790c629f1eecc","modified":1520781883406},{"_id":"public/2017/为Next主题添加canvas-ribbon/index.html","hash":"4cc13959877dd1c7546842f0e1415b01b7fec059","modified":1520781883406},{"_id":"public/2017/从0到有-如何搭建个人博客/index.html","hash":"1732e4113a7b3559afb97fa7f89a31176b7c1aca","modified":1520781883406},{"_id":"public/2017/hello-world/index.html","hash":"ba74397f95c95cfc1e302fd296027071e9692790","modified":1520781883406},{"_id":"public/archives/index.html","hash":"3b4c54c12cd3ebd48fc335399be4f09060567e07","modified":1520781883406},{"_id":"public/archives/page/2/index.html","hash":"237e2240031b853945f290b71fc62e59d284b081","modified":1520781883406},{"_id":"public/archives/page/3/index.html","hash":"cb6f0185dd1da206388f758d19427a7e277e60cf","modified":1520781883406},{"_id":"public/archives/2017/index.html","hash":"85e5fdae71ef7874e6c6324701f99676adfef40d","modified":1520781883406},{"_id":"public/archives/2017/page/2/index.html","hash":"d38909c46c07e9989e8e9e572890195e6ffe7028","modified":1520781883406},{"_id":"public/archives/2017/page/3/index.html","hash":"08a7135b3d3ae379b42ad0d4106adaaa7e259f30","modified":1520781883406},{"_id":"public/archives/2017/04/index.html","hash":"30d8c276e5a42ce11aa96039002bde548d384a0b","modified":1520781883406},{"_id":"public/archives/2017/06/index.html","hash":"63c059958b6c4a7f59ca5cdaf685f866c45160c7","modified":1520781883406},{"_id":"public/archives/2017/10/index.html","hash":"1057a8afb28c13a6439a4649c069ae8b90caf847","modified":1520781883406},{"_id":"public/page/2/index.html","hash":"8471a6f2852167947536fd5149fdccaed88fc8f4","modified":1520781883406},{"_id":"public/page/3/index.html","hash":"7f302fec25538b977f3f29e4daca4c6106760dd3","modified":1520781883406},{"_id":"public/index.html","hash":"7641b5782f21578c98165d273a1e7104d04c1012","modified":1520781883406},{"_id":"public/tags/Java/index.html","hash":"01deb7b886140f765e7a83e6270e22cfb0aaf331","modified":1520781883406},{"_id":"public/images/algolia_logo.svg","hash":"16505f61f19ba65f629dfd033f14ee9abcf18756","modified":1520781883422},{"_id":"public/robots.txt","hash":"faf4a7dc40136be7a67d7fbf7f65873a6ceba30e","modified":1520781883422},{"_id":"public/favicon.ico","hash":"a7d047f0799c44e6dbdb0f6a35106b8aa027d7e2","modified":1520781883422},{"_id":"public/images/avatar.gif","hash":"264082bb3a1af70d5499c7d22b0902cb454b6d12","modified":1520781883422},{"_id":"public/images/avatar.jpg","hash":"f1b5fb1cbe7ff1cfbbf2655cc74750d06aa43e0d","modified":1520781883422},{"_id":"public/images/cc-by-nc-nd.svg","hash":"bc3588c9b2d7c68830524783120ff6cf957cf668","modified":1520781883422},{"_id":"public/images/cc-by-nc-sa.svg","hash":"6f55543d1fb9cbc436c101d24f802dec7b41efc3","modified":1520781883422},{"_id":"public/images/cc-by-nc.svg","hash":"6f076713fb9bf934aa2c1046bdf2cf2e37bc1eab","modified":1520781883422},{"_id":"public/images/cc-by-nd.svg","hash":"42cd73da328077ccc92f859bb8f3cf621b3484f8","modified":1520781883422},{"_id":"public/images/cc-by-sa.svg","hash":"70c1535f43e54e5ff35ca81419e77e4c0c301398","modified":1520781883422},{"_id":"public/images/cc-by.svg","hash":"e92a33c32d1dac8ed94849b2b4e6456e887efe70","modified":1520781883422},{"_id":"public/images/cc-zero.svg","hash":"9bfb52b2f63527a7049247bf00d44e6dc1170e7d","modified":1520781883422},{"_id":"public/images/loading.gif","hash":"5fbd472222feb8a22cf5b8aa5dc5b8e13af88e2b","modified":1520781883422},{"_id":"public/images/logo.png","hash":"6385f99b912ff8d4088bf14c984b31600a8870aa","modified":1520781883422},{"_id":"public/images/placeholder.gif","hash":"5fbd472222feb8a22cf5b8aa5dc5b8e13af88e2b","modified":1520781883422},{"_id":"public/images/quote-l.svg","hash":"cd108d6f44351cadf8e6742565217f88818a0458","modified":1520781883422},{"_id":"public/images/quote-r.svg","hash":"2a2a250b32a87c69dcc1b1976c74b747bedbfb41","modified":1520781883422},{"_id":"public/images/searchicon.png","hash":"67727a6a969be0b2659b908518fa6706eed307b8","modified":1520781883422},{"_id":"public/lib/fastclick/LICENSE","hash":"6f474ea75c42442da7bbcf2e9143ce98258efd8d","modified":1520781883422},{"_id":"public/lib/font-awesome/HELP-US-OUT.txt","hash":"ee33b2798b1e714b904d663436c6b3521011d1fa","modified":1520781883422},{"_id":"public/lib/fancybox/source/blank.gif","hash":"2daeaa8b5f19f0bc209d976c02bd6acb51b00b0a","modified":1520781883422},{"_id":"public/lib/fancybox/source/fancybox_loading.gif","hash":"1a755fb2599f3a313cc6cfdb14df043f8c14a99c","modified":1520781883422},{"_id":"public/lib/fancybox/source/[email protected]","hash":"273b123496a42ba45c3416adb027cd99745058b0","modified":1520781883422},{"_id":"public/lib/fancybox/source/fancybox_overlay.png","hash":"b3a4ee645ba494f52840ef8412015ba0f465dbe0","modified":1520781883422},{"_id":"public/lib/fancybox/source/fancybox_sprite.png","hash":"17df19f97628e77be09c352bf27425faea248251","modified":1520781883422},{"_id":"public/lib/fancybox/source/[email protected]","hash":"30c58913f327e28f466a00f4c1ac8001b560aed8","modified":1520781883422},{"_id":"public/lib/font-awesome/css/font-awesome.css.map","hash":"1573904b82807abbb32c97a3632c6c6808eaac50","modified":1520781883422},{"_id":"public/lib/fancybox/source/helpers/fancybox_buttons.png","hash":"e385b139516c6813dcd64b8fc431c364ceafe5f3","modified":1520781883422},{"_id":"public/lib/font-awesome/fonts/FontAwesome.otf","hash":"1b22f17fdc38070de50e6d1ab3a32da71aa2d819","modified":1520781884406},{"_id":"public/lib/font-awesome/fonts/fontawesome-webfont.eot","hash":"965ce8f688fedbeed504efd498bc9c1622d12362","modified":1520781884422},{"_id":"public/lib/font-awesome/fonts/fontawesome-webfont.woff2","hash":"97e438cc545714309882fbceadbf344fcaddcec5","modified":1520781884422},{"_id":"public/lib/font-awesome/fonts/fontawesome-webfont.woff","hash":"6d7e6a5fc802b13694d8820fc0138037c0977d2e","modified":1520781884422},{"_id":"public/js/src/algolia-search.js","hash":"96b29f69b8b916b22f62c9959a117b5a968200a5","modified":1520781884438},{"_id":"public/js/src/affix.js","hash":"978e0422b5bf1b560236d8d10ebc1adcf66392e3","modified":1520781884453},{"_id":"public/js/src/hook-duoshuo.js","hash":"a6119070c0119f33e08b29da7d2cce2635eb40a0","modified":1520781884453},{"_id":"public/js/src/bootstrap.js","hash":"6c9ac964b6d49629ec873c19b568bca6fdc50ab7","modified":1520781884453},{"_id":"public/js/src/motion.js","hash":"68b78d70d57e29e45df15439e3d82592df08adc0","modified":1520781884453},{"_id":"public/js/src/post-details.js","hash":"b4a1d9bff08d0d3fbc12ab955c5cfff1042e63ae","modified":1520781884453},{"_id":"public/js/src/scrollspy.js","hash":"fe4da1b9fe73518226446f5f27d2831e4426fc35","modified":1520781884453},{"_id":"public/js/src/utils.js","hash":"dc243a9202171ef938b3752e85c025127a3bead6","modified":1520781884453},{"_id":"public/lib/algolia-instant-search/instantsearch.min.css","hash":"90ef19edc982645b118b095615838d9c5eaba0de","modified":1520781884453},{"_id":"public/lib/canvas-nest/canvas-nest.min.js","hash":"0387e75e23b1db108a755073fe52a0d03eb391a7","modified":1520781884453},{"_id":"public/lib/fastclick/README.html","hash":"da3c74d484c73cc7df565e8abbfa4d6a5a18d4da","modified":1520781884453},{"_id":"public/lib/canvas-ribbon/canvas-ribbon.js","hash":"01847264e1bb1a9f635fd29ca0ebc1e44d233600","modified":1520781884453},{"_id":"public/lib/fastclick/bower.json","hash":"4dcecf83afddba148464d5339c93f6d0aa9f42e9","modified":1520781884453},{"_id":"public/lib/font-awesome/bower.json","hash":"64394a2a9aa00f8e321d8daa5e51a420f0e96dad","modified":1520781884453},{"_id":"public/lib/jquery_lazyload/CONTRIBUTING.html","hash":"a6358170d346af13b1452ac157b60505bec7015c","modified":1520781884453},{"_id":"public/lib/jquery_lazyload/README.html","hash":"bde24335f6bc09d8801c0dcd7274f71b466552bd","modified":1520781884453},{"_id":"public/lib/jquery_lazyload/bower.json","hash":"ae3c3b61e6e7f9e1d7e3585ad854380ecc04cf53","modified":1520781884453},{"_id":"public/lib/jquery_lazyload/jquery.lazyload.js","hash":"481fd478650e12b67c201a0ea41e92743f8b45a3","modified":1520781884453},{"_id":"public/lib/jquery_lazyload/jquery.scrollstop.js","hash":"0e9a81785a011c98be5ea821a8ed7d411818cfd1","modified":1520781884453},{"_id":"public/lib/velocity/bower.json","hash":"0ef14e7ccdfba5db6eb3f8fc6aa3b47282c36409","modified":1520781884453},{"_id":"public/lib/velocity/velocity.ui.min.js","hash":"ed5e534cd680a25d8d14429af824f38a2c7d9908","modified":1520781884453},{"_id":"public/js/src/schemes/pisces.js","hash":"72b3c235dee064500d6a2906cadf8ea898d3c05b","modified":1520781884453},{"_id":"public/lib/fancybox/source/jquery.fancybox.css","hash":"5f163444617b6cf267342f06ac166a237bb62df9","modified":1520781884453},{"_id":"public/lib/fastclick/lib/fastclick.min.js","hash":"2cae0f5a6c5d6f3cb993015e6863f9483fc4de18","modified":1520781884453},{"_id":"public/lib/ua-parser-js/dist/ua-parser.min.js","hash":"38628e75e4412cc6f11074e03e1c6d257aae495b","modified":1520781884453},{"_id":"public/lib/ua-parser-js/dist/ua-parser.pack.js","hash":"214dad442a92d36af77ed0ca1d9092b16687f02f","modified":1520781884453},{"_id":"public/lib/fancybox/source/helpers/jquery.fancybox-buttons.css","hash":"1a9d8e5c22b371fcc69d4dbbb823d9c39f04c0c8","modified":1520781884453},{"_id":"public/lib/fancybox/source/helpers/jquery.fancybox-thumbs.css","hash":"4ac329c16a5277592fc12a37cca3d72ca4ec292f","modified":1520781884453},{"_id":"public/lib/fancybox/source/helpers/jquery.fancybox-thumbs.js","hash":"53e194f4a72e649c04fb586dd57762b8c022800b","modified":1520781884453},{"_id":"public/lib/fancybox/source/helpers/jquery.fancybox-buttons.js","hash":"91e41741c2e93f732c82aaacec4cfc6e3f3ec876","modified":1520781884453},{"_id":"public/lib/fancybox/source/helpers/jquery.fancybox-media.js","hash":"3bdf69ed2469e4fb57f5a95f17300eef891ff90d","modified":1520781884453},{"_id":"public/css/main.css","hash":"920566ca813dc769694b9c90d5e03fa7256d630c","modified":1520781884453},{"_id":"public/lib/velocity/velocity.min.js","hash":"2f1afadc12e4cf59ef3b405308d21baa97e739c6","modified":1520781884453},{"_id":"public/lib/velocity/velocity.ui.js","hash":"6a1d101eab3de87527bb54fcc8c7b36b79d8f0df","modified":1520781884453},{"_id":"public/lib/jquery/index.js","hash":"41b4bfbaa96be6d1440db6e78004ade1c134e276","modified":1520781884453},{"_id":"public/lib/fancybox/source/jquery.fancybox.js","hash":"1cf3d47b5ccb7cb6e9019c64f2a88d03a64853e4","modified":1520781884453},{"_id":"public/lib/fastclick/lib/fastclick.js","hash":"06cef196733a710e77ad7e386ced6963f092dc55","modified":1520781884453},{"_id":"public/lib/fancybox/source/jquery.fancybox.pack.js","hash":"53360764b429c212f424399384417ccc233bb3be","modified":1520781884453},{"_id":"public/lib/font-awesome/css/font-awesome.min.css","hash":"fb5b49426dee7f1508500e698d1b3c6b04c8fcce","modified":1520781884453},{"_id":"public/lib/font-awesome/css/font-awesome.css","hash":"4eda182cbcc046dbf449aef97c02c230cf80a494","modified":1520781884453},{"_id":"public/lib/velocity/velocity.js","hash":"9f08181baea0cc0e906703b7e5df9111b9ef3373","modified":1520781884453},{"_id":"public/lib/algolia-instant-search/instantsearch.min.js","hash":"9ccc6f8144f54e86df9a3fd33a18368d81cf3a4f","modified":1520781884453},{"_id":"public/lib/font-awesome/fonts/fontawesome-webfont.ttf","hash":"61d8d967807ef12598d81582fa95b9f600c3ee01","modified":1520781884453},{"_id":"public/lib/font-awesome/fonts/fontawesome-webfont.svg","hash":"964e8dac2cee79c4b49b5bc300675773f6518812","modified":1520781884469}],"Category":[],"Data":[],"Page":[{"_content":"google-site-verification: google091459981c22016a.html","source":"google091459981c22016a.html","raw":"google-site-verification: google091459981c22016a.html","date":"2017-05-10T13:54:35.903Z","updated":"2017-05-10T13:54:35.903Z","path":"google091459981c22016a.html","title":"","comments":1,"layout":"page","_id":"cjemy9jx20000wsv7n3iew274","content":"google-site-verification: google091459981c22016a.html","excerpt":"","more":"google-site-verification: google091459981c22016a.html"},{"date":"2018-03-11T15:15:50.000Z","type":"about","comments":1,"_content":"\n# 1.个人信息\n\n\n\n### 基本信息\n\n- 姓名: 张健\n- 学历: 硕士\n- 身高/体重: 185cm/82kg\n- 坐标: 辽宁沈阳\n- 籍贯: 山东淄博\n- 邮箱: [email protected]\n\n### 相关链接\n\n- 网络ID: zproo\n- 博客: zproo.github.io\n- Github: github.com/zproo\n\n# 2.教育背景\n\n### 2016.9-至今-东北大学(硕士)-计算机应用技术 \n\n现担任副班长职务。研一加入博士师兄领导的创业团队,参与开发覆盖十几所高校的学生管理平台以及顺丰公司的选配电商平台外包项目。\n\n### 2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统\n\n在校期间担任静语计算机协会部长。专业主修课程:数据结构、操作系统、计算机网络、编译原理。毕设课题:在校二手书交易平台搭建。\n\n# 3.项目经验\n\n### 2017.1-2017.12-顺丰选配电商平台-主要参与者\n\n\n\n**项目描述:**此项目使用分布式系统架构,整个系统采用了”前后端分离“的思想,前端关注数据展现,后端关注数据生产,通过rest服务进行整合。使用SOA服务架构,将业务解耦成多个独立的模块,所有的应用都是无状态的,可以做到水平扩展。另外,系统使用redis集群做系统缓存,使用solrCloud实现搜索功能。\n\n**软件架构:**Spring+SpringMVC+Mybatis+Mysql+Redis+Solr+Maven\n\n**个人职责:**\n\n- 与顺丰公司进行需求对接,参与项目的功能模块分析与架构设计- \n- 使用Angular+ajax实现前台系统:首页、商品浏览、下单、支付等多个模块\n- 使用ssm框架实现后台管理系统:订单系统、搜索系统、单点登录系统\n- 在Linux环境下部署redis缓存、solr搜索等服务\n\n### 2016.8-2016.12-第二课堂成绩单-团队成员\n\n**项目描述:**基于ssm框架,整合自定义框架JsWeb进行搭建。JsWeb框架是一个可以使用Javascript脚本来开发服务端数据接口的框架 。本身依赖于Spring和Spring MVC,通过实现Controller接口获取Request、Repsonse等对象,然后调用编译后的JS对请求进行处理并返回数据。无model层,对于返回数据无需创建或修改大量的实体类。极大降低了对于开发人员的要求,让初学者也能快速的开发服务端接口。\n\n**软件架构:**Spring+SpringMVC+JsWeb(自定义)+Mybatis+Mysql\n\n**个人职责:**\n\n- 辅助博士师兄搭建JsWeb框架,为框架添加扩展功能\n- 第二课堂手机端的前后台编码工作:校园活动管理、新闻中心、用户管理\n\n# 4.专业技能\n\n### 前端\n\n- 能够编写语义化的HTML,模块化的CSS,实现较复杂页面布局\n- 熟悉Javascript语言,熟练使用JQuery、EasyUI、AngularJS等前端库和前端框架\n- 了解过Node.js,能够使用Node.js和Express搭建简单的后端程序,与\n- mongDB进行数据交互,使用模板引擎渲染前端页面。\n- 了解前端工程化实践,使用过Bower、Grunt的工具\n\n### 后端\n\n- 熟悉java语言开发,了解面向对象和常用设计模式\n- 熟悉JavaWeb,以及Spring、SpringMVC、Mybatis等后端框架,能够快速搭建Web应用\n- 熟悉关系型数据库Mysql和非关系型数据库Redis、MongoDB,了解内部基本原理,能够熟练编写SQL程序\n- 有使用nginx搭建反向代理、搭建redis集群、搭建solr搜索服务等经验,了解Http、Tcp/IP等协议\n\n### 其他\n\n- 外语水平CET-6,有良好的外文文献阅读能力\n- 日常Linux使用经验,熟悉常用命令与配置\n- 熟练使用Markdown编写格式规范的技术文档\n- 日常使用Git/SVN和Intellij Idea、SQLYog等工具进行开发,乐于尝试新的开发工具\n\n# 5.奖项荣誉\n\n### 本科\n\n- 校二等奖学金两次\n- 2015美国数学建模大赛三等奖\n- 第三界全国大学生网络安全竞赛三等奖\n- 静语计算机协会(部长)山东省十佳社团\n\n### 研究生\n\n- 2016.9 获东北大学研究生二等奖学金\n- 2017.9 获东北大学研究生二等奖学金\n\n\n\n\n","source":"about/index.md","raw":"---\ndate: 2018-03-11 23:15:50\ntype: \"about\"\ncomments: true\n---\n\n# 1.个人信息\n\n\n\n### 基本信息\n\n- 姓名: 张健\n- 学历: 硕士\n- 身高/体重: 185cm/82kg\n- 坐标: 辽宁沈阳\n- 籍贯: 山东淄博\n- 邮箱: [email protected]\n\n### 相关链接\n\n- 网络ID: zproo\n- 博客: zproo.github.io\n- Github: github.com/zproo\n\n# 2.教育背景\n\n### 2016.9-至今-东北大学(硕士)-计算机应用技术 \n\n现担任副班长职务。研一加入博士师兄领导的创业团队,参与开发覆盖十几所高校的学生管理平台以及顺丰公司的选配电商平台外包项目。\n\n### 2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统\n\n在校期间担任静语计算机协会部长。专业主修课程:数据结构、操作系统、计算机网络、编译原理。毕设课题:在校二手书交易平台搭建。\n\n# 3.项目经验\n\n### 2017.1-2017.12-顺丰选配电商平台-主要参与者\n\n\n\n**项目描述:**此项目使用分布式系统架构,整个系统采用了”前后端分离“的思想,前端关注数据展现,后端关注数据生产,通过rest服务进行整合。使用SOA服务架构,将业务解耦成多个独立的模块,所有的应用都是无状态的,可以做到水平扩展。另外,系统使用redis集群做系统缓存,使用solrCloud实现搜索功能。\n\n**软件架构:**Spring+SpringMVC+Mybatis+Mysql+Redis+Solr+Maven\n\n**个人职责:**\n\n- 与顺丰公司进行需求对接,参与项目的功能模块分析与架构设计- \n- 使用Angular+ajax实现前台系统:首页、商品浏览、下单、支付等多个模块\n- 使用ssm框架实现后台管理系统:订单系统、搜索系统、单点登录系统\n- 在Linux环境下部署redis缓存、solr搜索等服务\n\n### 2016.8-2016.12-第二课堂成绩单-团队成员\n\n**项目描述:**基于ssm框架,整合自定义框架JsWeb进行搭建。JsWeb框架是一个可以使用Javascript脚本来开发服务端数据接口的框架 。本身依赖于Spring和Spring MVC,通过实现Controller接口获取Request、Repsonse等对象,然后调用编译后的JS对请求进行处理并返回数据。无model层,对于返回数据无需创建或修改大量的实体类。极大降低了对于开发人员的要求,让初学者也能快速的开发服务端接口。\n\n**软件架构:**Spring+SpringMVC+JsWeb(自定义)+Mybatis+Mysql\n\n**个人职责:**\n\n- 辅助博士师兄搭建JsWeb框架,为框架添加扩展功能\n- 第二课堂手机端的前后台编码工作:校园活动管理、新闻中心、用户管理\n\n# 4.专业技能\n\n### 前端\n\n- 能够编写语义化的HTML,模块化的CSS,实现较复杂页面布局\n- 熟悉Javascript语言,熟练使用JQuery、EasyUI、AngularJS等前端库和前端框架\n- 了解过Node.js,能够使用Node.js和Express搭建简单的后端程序,与\n- mongDB进行数据交互,使用模板引擎渲染前端页面。\n- 了解前端工程化实践,使用过Bower、Grunt的工具\n\n### 后端\n\n- 熟悉java语言开发,了解面向对象和常用设计模式\n- 熟悉JavaWeb,以及Spring、SpringMVC、Mybatis等后端框架,能够快速搭建Web应用\n- 熟悉关系型数据库Mysql和非关系型数据库Redis、MongoDB,了解内部基本原理,能够熟练编写SQL程序\n- 有使用nginx搭建反向代理、搭建redis集群、搭建solr搜索服务等经验,了解Http、Tcp/IP等协议\n\n### 其他\n\n- 外语水平CET-6,有良好的外文文献阅读能力\n- 日常Linux使用经验,熟悉常用命令与配置\n- 熟练使用Markdown编写格式规范的技术文档\n- 日常使用Git/SVN和Intellij Idea、SQLYog等工具进行开发,乐于尝试新的开发工具\n\n# 5.奖项荣誉\n\n### 本科\n\n- 校二等奖学金两次\n- 2015美国数学建模大赛三等奖\n- 第三界全国大学生网络安全竞赛三等奖\n- 静语计算机协会(部长)山东省十佳社团\n\n### 研究生\n\n- 2016.9 获东北大学研究生二等奖学金\n- 2017.9 获东北大学研究生二等奖学金\n\n\n\n\n","updated":"2018-03-11T15:20:02.123Z","path":"about/index.html","title":"","layout":"page","_id":"cjemy9k5r0002wsv7sazp8xh1","content":"<h1 id=\"1-个人信息\"><a href=\"#1-个人信息\" class=\"headerlink\" title=\"1.个人信息\"></a>1.个人信息</h1><h3 id=\"基本信息\"><a href=\"#基本信息\" class=\"headerlink\" title=\"基本信息\"></a>基本信息</h3><ul>\n<li>姓名: 张健</li>\n<li>学历: 硕士</li>\n<li>身高/体重: 185cm/82kg</li>\n<li>坐标: 辽宁沈阳</li>\n<li>籍贯: 山东淄博</li>\n<li>邮箱: [email protected]</li>\n</ul>\n<h3 id=\"相关链接\"><a href=\"#相关链接\" class=\"headerlink\" title=\"相关链接\"></a>相关链接</h3><ul>\n<li>网络ID: zproo</li>\n<li>博客: zproo.github.io</li>\n<li>Github: github.com/zproo</li>\n</ul>\n<h1 id=\"2-教育背景\"><a href=\"#2-教育背景\" class=\"headerlink\" title=\"2.教育背景\"></a>2.教育背景</h1><h3 id=\"2016-9-至今-东北大学(硕士)-计算机应用技术\"><a href=\"#2016-9-至今-东北大学(硕士)-计算机应用技术\" class=\"headerlink\" title=\"2016.9-至今-东北大学(硕士)-计算机应用技术\"></a>2016.9-至今-东北大学(硕士)-计算机应用技术</h3><p>现担任副班长职务。研一加入博士师兄领导的创业团队,参与开发覆盖十几所高校的学生管理平台以及顺丰公司的选配电商平台外包项目。</p>\n<h3 id=\"2012-9-2016-7-山东科技大学(本科)-信息管理与信息系统\"><a href=\"#2012-9-2016-7-山东科技大学(本科)-信息管理与信息系统\" class=\"headerlink\" title=\"2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统\"></a>2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统</h3><p>在校期间担任静语计算机协会部长。专业主修课程:数据结构、操作系统、计算机网络、编译原理。毕设课题:在校二手书交易平台搭建。</p>\n<h1 id=\"3-项目经验\"><a href=\"#3-项目经验\" class=\"headerlink\" title=\"3.项目经验\"></a>3.项目经验</h1><h3 id=\"2017-1-2017-12-顺丰选配电商平台-主要参与者\"><a href=\"#2017-1-2017-12-顺丰选配电商平台-主要参与者\" class=\"headerlink\" title=\"2017.1-2017.12-顺丰选配电商平台-主要参与者\"></a>2017.1-2017.12-顺丰选配电商平台-主要参与者</h3><p><strong>项目描述:</strong>此项目使用分布式系统架构,整个系统采用了”前后端分离“的思想,前端关注数据展现,后端关注数据生产,通过rest服务进行整合。使用SOA服务架构,将业务解耦成多个独立的模块,所有的应用都是无状态的,可以做到水平扩展。另外,系统使用redis集群做系统缓存,使用solrCloud实现搜索功能。</p>\n<p><strong>软件架构:</strong>Spring+SpringMVC+Mybatis+Mysql+Redis+Solr+Maven</p>\n<p><strong>个人职责:</strong></p>\n<ul>\n<li>与顺丰公司进行需求对接,参与项目的功能模块分析与架构设计- </li>\n<li>使用Angular+ajax实现前台系统:首页、商品浏览、下单、支付等多个模块</li>\n<li>使用ssm框架实现后台管理系统:订单系统、搜索系统、单点登录系统</li>\n<li>在Linux环境下部署redis缓存、solr搜索等服务</li>\n</ul>\n<h3 id=\"2016-8-2016-12-第二课堂成绩单-团队成员\"><a href=\"#2016-8-2016-12-第二课堂成绩单-团队成员\" class=\"headerlink\" title=\"2016.8-2016.12-第二课堂成绩单-团队成员\"></a>2016.8-2016.12-第二课堂成绩单-团队成员</h3><p><strong>项目描述:</strong>基于ssm框架,整合自定义框架JsWeb进行搭建。JsWeb框架是一个可以使用Javascript脚本来开发服务端数据接口的框架 。本身依赖于Spring和Spring MVC,通过实现Controller接口获取Request、Repsonse等对象,然后调用编译后的JS对请求进行处理并返回数据。无model层,对于返回数据无需创建或修改大量的实体类。极大降低了对于开发人员的要求,让初学者也能快速的开发服务端接口。</p>\n<p><strong>软件架构:</strong>Spring+SpringMVC+JsWeb(自定义)+Mybatis+Mysql</p>\n<p><strong>个人职责:</strong></p>\n<ul>\n<li>辅助博士师兄搭建JsWeb框架,为框架添加扩展功能</li>\n<li>第二课堂手机端的前后台编码工作:校园活动管理、新闻中心、用户管理</li>\n</ul>\n<h1 id=\"4-专业技能\"><a href=\"#4-专业技能\" class=\"headerlink\" title=\"4.专业技能\"></a>4.专业技能</h1><h3 id=\"前端\"><a href=\"#前端\" class=\"headerlink\" title=\"前端\"></a>前端</h3><ul>\n<li>能够编写语义化的HTML,模块化的CSS,实现较复杂页面布局</li>\n<li>熟悉Javascript语言,熟练使用JQuery、EasyUI、AngularJS等前端库和前端框架</li>\n<li>了解过Node.js,能够使用Node.js和Express搭建简单的后端程序,与</li>\n<li>mongDB进行数据交互,使用模板引擎渲染前端页面。</li>\n<li>了解前端工程化实践,使用过Bower、Grunt的工具</li>\n</ul>\n<h3 id=\"后端\"><a href=\"#后端\" class=\"headerlink\" title=\"后端\"></a>后端</h3><ul>\n<li>熟悉java语言开发,了解面向对象和常用设计模式</li>\n<li>熟悉JavaWeb,以及Spring、SpringMVC、Mybatis等后端框架,能够快速搭建Web应用</li>\n<li>熟悉关系型数据库Mysql和非关系型数据库Redis、MongoDB,了解内部基本原理,能够熟练编写SQL程序</li>\n<li>有使用nginx搭建反向代理、搭建redis集群、搭建solr搜索服务等经验,了解Http、Tcp/IP等协议</li>\n</ul>\n<h3 id=\"其他\"><a href=\"#其他\" class=\"headerlink\" title=\"其他\"></a>其他</h3><ul>\n<li>外语水平CET-6,有良好的外文文献阅读能力</li>\n<li>日常Linux使用经验,熟悉常用命令与配置</li>\n<li>熟练使用Markdown编写格式规范的技术文档</li>\n<li>日常使用Git/SVN和Intellij Idea、SQLYog等工具进行开发,乐于尝试新的开发工具</li>\n</ul>\n<h1 id=\"5-奖项荣誉\"><a href=\"#5-奖项荣誉\" class=\"headerlink\" title=\"5.奖项荣誉\"></a>5.奖项荣誉</h1><h3 id=\"本科\"><a href=\"#本科\" class=\"headerlink\" title=\"本科\"></a>本科</h3><ul>\n<li>校二等奖学金两次</li>\n<li>2015美国数学建模大赛三等奖</li>\n<li>第三界全国大学生网络安全竞赛三等奖</li>\n<li>静语计算机协会(部长)山东省十佳社团</li>\n</ul>\n<h3 id=\"研究生\"><a href=\"#研究生\" class=\"headerlink\" title=\"研究生\"></a>研究生</h3><ul>\n<li>2016.9 获东北大学研究生二等奖学金</li>\n<li>2017.9 获东北大学研究生二等奖学金</li>\n</ul>\n","excerpt":"","more":"<h1 id=\"1-个人信息\"><a href=\"#1-个人信息\" class=\"headerlink\" title=\"1.个人信息\"></a>1.个人信息</h1><h3 id=\"基本信息\"><a href=\"#基本信息\" class=\"headerlink\" title=\"基本信息\"></a>基本信息</h3><ul>\n<li>姓名: 张健</li>\n<li>学历: 硕士</li>\n<li>身高/体重: 185cm/82kg</li>\n<li>坐标: 辽宁沈阳</li>\n<li>籍贯: 山东淄博</li>\n<li>邮箱: [email protected]</li>\n</ul>\n<h3 id=\"相关链接\"><a href=\"#相关链接\" class=\"headerlink\" title=\"相关链接\"></a>相关链接</h3><ul>\n<li>网络ID: zproo</li>\n<li>博客: zproo.github.io</li>\n<li>Github: github.com/zproo</li>\n</ul>\n<h1 id=\"2-教育背景\"><a href=\"#2-教育背景\" class=\"headerlink\" title=\"2.教育背景\"></a>2.教育背景</h1><h3 id=\"2016-9-至今-东北大学(硕士)-计算机应用技术\"><a href=\"#2016-9-至今-东北大学(硕士)-计算机应用技术\" class=\"headerlink\" title=\"2016.9-至今-东北大学(硕士)-计算机应用技术\"></a>2016.9-至今-东北大学(硕士)-计算机应用技术</h3><p>现担任副班长职务。研一加入博士师兄领导的创业团队,参与开发覆盖十几所高校的学生管理平台以及顺丰公司的选配电商平台外包项目。</p>\n<h3 id=\"2012-9-2016-7-山东科技大学(本科)-信息管理与信息系统\"><a href=\"#2012-9-2016-7-山东科技大学(本科)-信息管理与信息系统\" class=\"headerlink\" title=\"2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统\"></a>2012.9-2016.7-山东科技大学(本科)-信息管理与信息系统</h3><p>在校期间担任静语计算机协会部长。专业主修课程:数据结构、操作系统、计算机网络、编译原理。毕设课题:在校二手书交易平台搭建。</p>\n<h1 id=\"3-项目经验\"><a href=\"#3-项目经验\" class=\"headerlink\" title=\"3.项目经验\"></a>3.项目经验</h1><h3 id=\"2017-1-2017-12-顺丰选配电商平台-主要参与者\"><a href=\"#2017-1-2017-12-顺丰选配电商平台-主要参与者\" class=\"headerlink\" title=\"2017.1-2017.12-顺丰选配电商平台-主要参与者\"></a>2017.1-2017.12-顺丰选配电商平台-主要参与者</h3><p><strong>项目描述:</strong>此项目使用分布式系统架构,整个系统采用了”前后端分离“的思想,前端关注数据展现,后端关注数据生产,通过rest服务进行整合。使用SOA服务架构,将业务解耦成多个独立的模块,所有的应用都是无状态的,可以做到水平扩展。另外,系统使用redis集群做系统缓存,使用solrCloud实现搜索功能。</p>\n<p><strong>软件架构:</strong>Spring+SpringMVC+Mybatis+Mysql+Redis+Solr+Maven</p>\n<p><strong>个人职责:</strong></p>\n<ul>\n<li>与顺丰公司进行需求对接,参与项目的功能模块分析与架构设计- </li>\n<li>使用Angular+ajax实现前台系统:首页、商品浏览、下单、支付等多个模块</li>\n<li>使用ssm框架实现后台管理系统:订单系统、搜索系统、单点登录系统</li>\n<li>在Linux环境下部署redis缓存、solr搜索等服务</li>\n</ul>\n<h3 id=\"2016-8-2016-12-第二课堂成绩单-团队成员\"><a href=\"#2016-8-2016-12-第二课堂成绩单-团队成员\" class=\"headerlink\" title=\"2016.8-2016.12-第二课堂成绩单-团队成员\"></a>2016.8-2016.12-第二课堂成绩单-团队成员</h3><p><strong>项目描述:</strong>基于ssm框架,整合自定义框架JsWeb进行搭建。JsWeb框架是一个可以使用Javascript脚本来开发服务端数据接口的框架 。本身依赖于Spring和Spring MVC,通过实现Controller接口获取Request、Repsonse等对象,然后调用编译后的JS对请求进行处理并返回数据。无model层,对于返回数据无需创建或修改大量的实体类。极大降低了对于开发人员的要求,让初学者也能快速的开发服务端接口。</p>\n<p><strong>软件架构:</strong>Spring+SpringMVC+JsWeb(自定义)+Mybatis+Mysql</p>\n<p><strong>个人职责:</strong></p>\n<ul>\n<li>辅助博士师兄搭建JsWeb框架,为框架添加扩展功能</li>\n<li>第二课堂手机端的前后台编码工作:校园活动管理、新闻中心、用户管理</li>\n</ul>\n<h1 id=\"4-专业技能\"><a href=\"#4-专业技能\" class=\"headerlink\" title=\"4.专业技能\"></a>4.专业技能</h1><h3 id=\"前端\"><a href=\"#前端\" class=\"headerlink\" title=\"前端\"></a>前端</h3><ul>\n<li>能够编写语义化的HTML,模块化的CSS,实现较复杂页面布局</li>\n<li>熟悉Javascript语言,熟练使用JQuery、EasyUI、AngularJS等前端库和前端框架</li>\n<li>了解过Node.js,能够使用Node.js和Express搭建简单的后端程序,与</li>\n<li>mongDB进行数据交互,使用模板引擎渲染前端页面。</li>\n<li>了解前端工程化实践,使用过Bower、Grunt的工具</li>\n</ul>\n<h3 id=\"后端\"><a href=\"#后端\" class=\"headerlink\" title=\"后端\"></a>后端</h3><ul>\n<li>熟悉java语言开发,了解面向对象和常用设计模式</li>\n<li>熟悉JavaWeb,以及Spring、SpringMVC、Mybatis等后端框架,能够快速搭建Web应用</li>\n<li>熟悉关系型数据库Mysql和非关系型数据库Redis、MongoDB,了解内部基本原理,能够熟练编写SQL程序</li>\n<li>有使用nginx搭建反向代理、搭建redis集群、搭建solr搜索服务等经验,了解Http、Tcp/IP等协议</li>\n</ul>\n<h3 id=\"其他\"><a href=\"#其他\" class=\"headerlink\" title=\"其他\"></a>其他</h3><ul>\n<li>外语水平CET-6,有良好的外文文献阅读能力</li>\n<li>日常Linux使用经验,熟悉常用命令与配置</li>\n<li>熟练使用Markdown编写格式规范的技术文档</li>\n<li>日常使用Git/SVN和Intellij Idea、SQLYog等工具进行开发,乐于尝试新的开发工具</li>\n</ul>\n<h1 id=\"5-奖项荣誉\"><a href=\"#5-奖项荣誉\" class=\"headerlink\" title=\"5.奖项荣誉\"></a>5.奖项荣誉</h1><h3 id=\"本科\"><a href=\"#本科\" class=\"headerlink\" title=\"本科\"></a>本科</h3><ul>\n<li>校二等奖学金两次</li>\n<li>2015美国数学建模大赛三等奖</li>\n<li>第三界全国大学生网络安全竞赛三等奖</li>\n<li>静语计算机协会(部长)山东省十佳社团</li>\n</ul>\n<h3 id=\"研究生\"><a href=\"#研究生\" class=\"headerlink\" title=\"研究生\"></a>研究生</h3><ul>\n<li>2016.9 获东北大学研究生二等奖学金</li>\n<li>2017.9 获东北大学研究生二等奖学金</li>\n</ul>\n"},{"_content":"List my Github projects.\n\n```js\n/**\n * @author zproo\n * @email [email protected]\n * @github zproo@github\n * @comment list all the projects of zproo\n */\n```\n\nThe website theme from [tink.im](http://tink.im/).\n","source":"project/README.md","raw":"List my Github projects.\n\n```js\n/**\n * @author zproo\n * @email [email protected]\n * @github zproo@github\n * @comment list all the projects of zproo\n */\n```\n\nThe website theme from [tink.im](http://tink.im/).\n","date":"2017-05-04T07:08:50.417Z","updated":"2017-05-04T07:08:50.417Z","path":"project/README.html","title":"","comments":1,"layout":"page","_id":"cjemy9k5r0004wsv7424z0wk9","content":"<p>List my Github projects.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * @author zproo</div><div class=\"line\"> * @email [email protected]</div><div class=\"line\"> * @github zproo@github</div><div class=\"line\"> * @comment list all the projects of zproo</div><div class=\"line\"> */</div></pre></td></tr></table></figure>\n<p>The website theme from <a href=\"http://tink.im/\" target=\"_blank\" rel=\"external\">tink.im</a>.</p>\n","excerpt":"","more":"<p>List my Github projects.</p>\n<figure class=\"highlight js\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</div><div class=\"line\"> * @author zproo</div><div class=\"line\"> * @email [email protected]</div><div class=\"line\"> * @github zproo@github</div><div class=\"line\"> * @comment list all the projects of zproo</div><div class=\"line\"> */</span></div></pre></td></tr></table></figure>\n<p>The website theme from <a href=\"http://tink.im/\">tink.im</a>.</p>\n"},{"_content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta charset=\"utf-8\" />\n <title>zproo 's GitHub</title>\n <link rel=\"stylesheet\" href=\"stylesheets/style.css\" />\n <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico?v=5.0.1\" />\n</head>\n\n<body onselectstart=\"return false\">\n\n<div class=\"wrap\">\n\n <h1>/**\n * <b>@name</b> zproo\n * <b>@mail</b> [email protected]\n * <b>@github</b> <a href= \"https://github.com/zproo\" target=\"_blank\">zproo@github</a>\n * <b>@comment</b> list all the projects of zproo.\n */</h1>\n\n <br />\n {\n <ul>\n <li class=\"profile\">\n <a href=\"https://github.com/zproo/canvas-ribbon\" target=\"_blank\">\n <h3><b>canvas-ribbon.js:</b><span class=\"link\">网页背景彩带</span></h3>\n </a>\n </li>\n\n </ul>\n }\n\n <br />\n <h1 class=\"comment\">/** <b>@author</b> zproo */</h1>\n</div>\n\n<script type=\"text/javascript\">\n document.oncontextmenu=function(e){return false;}\n</script>\n<!--<span style=\"display:none\">\n <script src=\"http://s4.cnzz.com/stat.php?id=1257060683&web_id=1257060683\" language=\"JavaScript\"></script>\n</span>-->\n</body>\n</html>\n","source":"project/index.html","raw":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta charset=\"utf-8\" />\n <title>zproo 's GitHub</title>\n <link rel=\"stylesheet\" href=\"stylesheets/style.css\" />\n <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico?v=5.0.1\" />\n</head>\n\n<body onselectstart=\"return false\">\n\n<div class=\"wrap\">\n\n <h1>/**\n * <b>@name</b> zproo\n * <b>@mail</b> [email protected]\n * <b>@github</b> <a href= \"https://github.com/zproo\" target=\"_blank\">zproo@github</a>\n * <b>@comment</b> list all the projects of zproo.\n */</h1>\n\n <br />\n {\n <ul>\n <li class=\"profile\">\n <a href=\"https://github.com/zproo/canvas-ribbon\" target=\"_blank\">\n <h3><b>canvas-ribbon.js:</b><span class=\"link\">网页背景彩带</span></h3>\n </a>\n </li>\n\n </ul>\n }\n\n <br />\n <h1 class=\"comment\">/** <b>@author</b> zproo */</h1>\n</div>\n\n<script type=\"text/javascript\">\n document.oncontextmenu=function(e){return false;}\n</script>\n<!--<span style=\"display:none\">\n <script src=\"http://s4.cnzz.com/stat.php?id=1257060683&web_id=1257060683\" language=\"JavaScript\"></script>\n</span>-->\n</body>\n</html>\n","date":"2017-05-04T07:08:50.449Z","updated":"2017-05-04T07:08:50.449Z","path":"project/index.html","title":"","comments":1,"layout":"page","_id":"cjemy9k660007wsv7jbt4tsbw","content":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <meta charset=\"utf-8\">\n <title>zproo 's GitHub</title>\n <link rel=\"stylesheet\" href=\"stylesheets/style.css\">\n <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico?v=5.0.1\">\n</head>\n\n<body onselectstart=\"return false\">\n\n<div class=\"wrap\">\n\n <h1>/**\n * <b>@name</b> zproo\n * <b>@mail</b> [email protected]\n * <b>@github</b> <a href=\"https://github.com/zproo\" target=\"_blank\">zproo@github</a>\n * <b>@comment</b> list all the projects of zproo.\n */</h1>\n\n <br>\n {\n <ul>\n <li class=\"profile\">\n <a href=\"https://github.com/zproo/canvas-ribbon\" target=\"_blank\">\n <h3><b>canvas-ribbon.js:</b><span class=\"link\">网页背景彩带</span></h3>\n </a>\n </li>\n\n </ul>\n }\n\n <br>\n <h1 class=\"comment\">/** <b>@author</b> zproo */</h1>\n</div>\n\n<script type=\"text/javascript\">\n document.oncontextmenu=function(e){return false;}\n</script>\n<!--<span style=\"display:none\">\n <script src=\"http://s4.cnzz.com/stat.php?id=1257060683&web_id=1257060683\" language=\"JavaScript\"></script>\n</span>-->\n</body>\n</html>\n","excerpt":"","more":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n <meta charset=\"utf-8\" />\n <title>zproo 's GitHub</title>\n <link rel=\"stylesheet\" href=\"stylesheets/style.css\" />\n <link rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/favicon.ico?v=5.0.1\" />\n</head>\n\n<body onselectstart=\"return false\">\n\n<div class=\"wrap\">\n\n <h1>/**\n * <b>@name</b> zproo\n * <b>@mail</b> [email protected]\n * <b>@github</b> <a href= \"https://github.com/zproo\" target=\"_blank\">zproo@github</a>\n * <b>@comment</b> list all the projects of zproo.\n */</h1>\n\n <br />\n {\n <ul>\n <li class=\"profile\">\n <a href=\"https://github.com/zproo/canvas-ribbon\" target=\"_blank\">\n <h3><b>canvas-ribbon.js:</b><span class=\"link\">网页背景彩带</span></h3>\n </a>\n </li>\n\n </ul>\n }\n\n <br />\n <h1 class=\"comment\">/** <b>@author</b> zproo */</h1>\n</div>\n\n<script type=\"text/javascript\">\n document.oncontextmenu=function(e){return false;}\n</script>\n<!--<span style=\"display:none\">\n <script src=\"http://s4.cnzz.com/stat.php?id=1257060683&web_id=1257060683\" language=\"JavaScript\"></script>\n</span>-->\n</body>\n</html>\n"},{"date":"2017-03-28T13:23:03.000Z","type":"tags","comments":0,"_content":"","source":"tags/index.md","raw":"---\ndate: 2017-03-28 21:23:03\ntype: \"tags\"\ncomments: false\n---\n","updated":"2017-03-30T15:11:52.543Z","path":"tags/index.html","title":"","layout":"page","_id":"cjemy9k6m0009wsv7du4fkp9i","content":"","excerpt":"","more":""},{"_content":"<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n</head>\n<body>\n<a href=\"https://github.com/DIYgod/DPlayer\" target=\"_blank\" class=\"github-corner\">\n <svg width=\"80\" height=\"80\" viewBox=\"0 0 250 250\"\n style=\"fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\"\n fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\"\n fill=\"currentColor\" class=\"octo-body\"></path>\n </svg>\n</a>\n<style>.github-corner:hover .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n}\n\n@keyframes octocat-wave {\n 0%, 100% {\n transform: rotate(0)\n }\n 20%, 60% {\n transform: rotate(-25deg)\n }\n 40%, 80% {\n transform: rotate(10deg)\n }\n}\n\n@media (max-width: 500px) {\n .github-corner:hover .octo-arm {\n animation: none\n }\n\n .github-corner .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n }\n}</style>\n<script id=\"ribbon\" src=\"canvas-ribbon.min.js\" zIndex=\"-1\" alpha=\"0.6\" size=\"90\"></script>\n</body>\n</html>\n\n","source":"project/canvas-ribbon/index.html","raw":"<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n</head>\n<body>\n<a href=\"https://github.com/DIYgod/DPlayer\" target=\"_blank\" class=\"github-corner\">\n <svg width=\"80\" height=\"80\" viewBox=\"0 0 250 250\"\n style=\"fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\"\n fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\"\n fill=\"currentColor\" class=\"octo-body\"></path>\n </svg>\n</a>\n<style>.github-corner:hover .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n}\n\n@keyframes octocat-wave {\n 0%, 100% {\n transform: rotate(0)\n }\n 20%, 60% {\n transform: rotate(-25deg)\n }\n 40%, 80% {\n transform: rotate(10deg)\n }\n}\n\n@media (max-width: 500px) {\n .github-corner:hover .octo-arm {\n animation: none\n }\n\n .github-corner .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n }\n}</style>\n<script id=\"ribbon\" src=\"canvas-ribbon.min.js\" zIndex=\"-1\" alpha=\"0.6\" size=\"90\"></script>\n</body>\n</html>\n\n","date":"2017-05-04T07:08:50.448Z","updated":"2017-05-04T07:08:50.448Z","path":"project/canvas-ribbon/index.html","title":"","comments":1,"layout":"page","_id":"cjemy9kbt0037wsv760ag1pfl","content":"<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n</head>\n<body>\n<a href=\"https://github.com/DIYgod/DPlayer\" target=\"_blank\" class=\"github-corner\">\n <svg width=\"80\" height=\"80\" viewbox=\"0 0 250 250\" style=\"fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"/>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\" fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"/>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\" fill=\"currentColor\" class=\"octo-body\"/>\n </svg>\n</a>\n<style>.github-corner:hover .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n}\n\n@keyframes octocat-wave {\n 0%, 100% {\n transform: rotate(0)\n }\n 20%, 60% {\n transform: rotate(-25deg)\n }\n 40%, 80% {\n transform: rotate(10deg)\n }\n}\n\n@media (max-width: 500px) {\n .github-corner:hover .octo-arm {\n animation: none\n }\n\n .github-corner .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n }\n}</style>\n<script id=\"ribbon\" src=\"canvas-ribbon.min.js\" zindex=\"-1\" alpha=\"0.6\" size=\"90\"></script>\n</body>\n</html>\n\n","excerpt":"","more":"<html>\n<head>\n <meta charset=\"UTF-8\">\n <title>Document</title>\n</head>\n<body>\n<a href=\"https://github.com/DIYgod/DPlayer\" target=\"_blank\" class=\"github-corner\">\n <svg width=\"80\" height=\"80\" viewBox=\"0 0 250 250\"\n style=\"fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;\">\n <path d=\"M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z\"></path>\n <path d=\"M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2\"\n fill=\"currentColor\" style=\"transform-origin: 130px 106px;\" class=\"octo-arm\"></path>\n <path d=\"M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z\"\n fill=\"currentColor\" class=\"octo-body\"></path>\n </svg>\n</a>\n<style>.github-corner:hover .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n}\n\n@keyframes octocat-wave {\n 0%, 100% {\n transform: rotate(0)\n }\n 20%, 60% {\n transform: rotate(-25deg)\n }\n 40%, 80% {\n transform: rotate(10deg)\n }\n}\n\n@media (max-width: 500px) {\n .github-corner:hover .octo-arm {\n animation: none\n }\n\n .github-corner .octo-arm {\n animation: octocat-wave 560ms ease-in-out\n }\n}</style>\n<script id=\"ribbon\" src=\"canvas-ribbon.min.js\" zIndex=\"-1\" alpha=\"0.6\" size=\"90\"></script>\n</body>\n</html>\n\n"},{"_content":"/**\n * Created by zproo on 2017/4/8.\n */\n!function(){function a(a,b,c){return Number(a.getAttribute(b))||c}function p(){for(e.clearRect(0,0,g,h),j=[{x:0,y:.7*h+i},{x:0,y:.7*h-i}];j[1].x<g+i;)q(j[0],j[1])}function q(a,b){e.beginPath(),e.moveTo(a.x,a.y),e.lineTo(b.x,b.y);var c=b.x+(2*o()-.25)*i,d=r(b.y);e.lineTo(c,d),e.closePath(),l-=m/-50,e.fillStyle=\"#\"+(127*n(l)+128<<16|127*n(l+m/3)+128<<8|127*n(l+2*(m/3))+128).toString(16),e.fill(),j[0]=j[1],j[1]={x:c,y:d}}function r(a){var b=a+(2*o()-1.1)*i;return b>h||0>b?r(a):b}var b,c,j,d,e,f,g,h,i,k,l,m,n,o;document.addEventListener(\"touchmove\",function(a){a.preventDefault()}),b=document.getElementById(\"ribbon\"),config={zindex:a(b,\"zIndex\",-1),alpha:a(b,\"alpha\",.6),ribbon_width:a(b,\"size\",90)},c=document.createElement(\"canvas\"),c.style.cssText=\"position:fixed;top:0;left:0;z-index:\"+config.zindex,document.getElementsByTagName(\"body\")[0].appendChild(c),d=c,e=d.getContext(\"2d\"),f=window.devicePixelRatio||1,g=window.innerWidth,h=window.innerHeight,i=config.ribbon_width,k=Math,l=0,m=2*k.PI,n=k.cos,o=k.random,d.width=g*f,d.height=h*f,e.scale(f,f),e.globalAlpha=config.alpha,document.onclick=p,document.ontouchstart=p,p()}();","source":"project/canvas-ribbon/canvas-ribbon.min.js","raw":"/**\n * Created by zproo on 2017/4/8.\n */\n!function(){function a(a,b,c){return Number(a.getAttribute(b))||c}function p(){for(e.clearRect(0,0,g,h),j=[{x:0,y:.7*h+i},{x:0,y:.7*h-i}];j[1].x<g+i;)q(j[0],j[1])}function q(a,b){e.beginPath(),e.moveTo(a.x,a.y),e.lineTo(b.x,b.y);var c=b.x+(2*o()-.25)*i,d=r(b.y);e.lineTo(c,d),e.closePath(),l-=m/-50,e.fillStyle=\"#\"+(127*n(l)+128<<16|127*n(l+m/3)+128<<8|127*n(l+2*(m/3))+128).toString(16),e.fill(),j[0]=j[1],j[1]={x:c,y:d}}function r(a){var b=a+(2*o()-1.1)*i;return b>h||0>b?r(a):b}var b,c,j,d,e,f,g,h,i,k,l,m,n,o;document.addEventListener(\"touchmove\",function(a){a.preventDefault()}),b=document.getElementById(\"ribbon\"),config={zindex:a(b,\"zIndex\",-1),alpha:a(b,\"alpha\",.6),ribbon_width:a(b,\"size\",90)},c=document.createElement(\"canvas\"),c.style.cssText=\"position:fixed;top:0;left:0;z-index:\"+config.zindex,document.getElementsByTagName(\"body\")[0].appendChild(c),d=c,e=d.getContext(\"2d\"),f=window.devicePixelRatio||1,g=window.innerWidth,h=window.innerHeight,i=config.ribbon_width,k=Math,l=0,m=2*k.PI,n=k.cos,o=k.random,d.width=g*f,d.height=h*f,e.scale(f,f),e.globalAlpha=config.alpha,document.onclick=p,document.ontouchstart=p,p()}();","date":"2017-05-04T07:08:50.436Z","updated":"2017-05-04T07:08:50.436Z","path":"project/canvas-ribbon/canvas-ribbon.min.js","layout":"false","title":"","comments":1,"_id":"cjemy9kbt0038wsv7yq3mmb81","content":"/**\n * Created by zproo on 2017/4/8.\n */\n!function(){function a(a,b,c){return Number(a.getAttribute(b))||c}function p(){for(e.clearRect(0,0,g,h),j=[{x:0,y:.7*h+i},{x:0,y:.7*h-i}];j[1].x<g+i;)q(j[0],j[1])}function q(a,b){e.beginpath(),e.moveto(a.x,a.y),e.lineto(b.x,b.y);var=\"\" c=\"b.x+(2*o()-.25)*i,d=r(b.y);e.lineTo(c,d),e.closePath(),l-=m/-50,e.fillStyle=\"#\"+(127*n(l)+128<<16|127*n(l+m/3)+128<<8|127*n(l+2*(m/3))+128).toString(16),e.fill(),j[0]=j[1],j[1]={x:c,y:d}}function\" r(a){var=\"\" b=\"a+(2*o()-1.1)*i;return\">h||0>b?r(a):b}var b,c,j,d,e,f,g,h,i,k,l,m,n,o;document.addEventListener(\"touchmove\",function(a){a.preventDefault()}),b=document.getElementById(\"ribbon\"),config={zindex:a(b,\"zIndex\",-1),alpha:a(b,\"alpha\",.6),ribbon_width:a(b,\"size\",90)},c=document.createElement(\"canvas\"),c.style.cssText=\"position:fixed;top:0;left:0;z-index:\"+config.zindex,document.getElementsByTagName(\"body\")[0].appendChild(c),d=c,e=d.getContext(\"2d\"),f=window.devicePixelRatio||1,g=window.innerWidth,h=window.innerHeight,i=config.ribbon_width,k=Math,l=0,m=2*k.PI,n=k.cos,o=k.random,d.width=g*f,d.height=h*f,e.scale(f,f),e.globalAlpha=config.alpha,document.onclick=p,document.ontouchstart=p,p()}();</g+i;)q(j[0],j[1])}function>","excerpt":"","more":"/**\n * Created by zproo on 2017/4/8.\n */\n!function(){function a(a,b,c){return Number(a.getAttribute(b))||c}function p(){for(e.clearRect(0,0,g,h),j=[{x:0,y:.7*h+i},{x:0,y:.7*h-i}];j[1].x<g+i;)q(j[0],j[1])}function q(a,b){e.beginPath(),e.moveTo(a.x,a.y),e.lineTo(b.x,b.y);var c=b.x+(2*o()-.25)*i,d=r(b.y);e.lineTo(c,d),e.closePath(),l-=m/-50,e.fillStyle=\"#\"+(127*n(l)+128<<16|127*n(l+m/3)+128<<8|127*n(l+2*(m/3))+128).toString(16),e.fill(),j[0]=j[1],j[1]={x:c,y:d}}function r(a){var b=a+(2*o()-1.1)*i;return b>h||0>b?r(a):b}var b,c,j,d,e,f,g,h,i,k,l,m,n,o;document.addEventListener(\"touchmove\",function(a){a.preventDefault()}),b=document.getElementById(\"ribbon\"),config={zindex:a(b,\"zIndex\",-1),alpha:a(b,\"alpha\",.6),ribbon_width:a(b,\"size\",90)},c=document.createElement(\"canvas\"),c.style.cssText=\"position:fixed;top:0;left:0;z-index:\"+config.zindex,document.getElementsByTagName(\"body\")[0].appendChild(c),d=c,e=d.getContext(\"2d\"),f=window.devicePixelRatio||1,g=window.innerWidth,h=window.innerHeight,i=config.ribbon_width,k=Math,l=0,m=2*k.PI,n=k.cos,o=k.random,d.width=g*f,d.height=h*f,e.scale(f,f),e.globalAlpha=config.alpha,document.onclick=p,document.ontouchstart=p,p()}();"},{"_content":"* {\n margin: 0;\n padding: 0;\n \n /* Goin' all DOS-y */\n -webkit-font-smoothing: none;\n}\n\nbody {\n background: #111;\n font: 16px/18px \"Courier New\", Courier, mono;\n color: #fff;\n}\n\ndiv.wrap {\n max-width: 1100px;\n margin: 100px auto 0;\n}\n\na {\n text-decoration: none;\n color: #fff;\n}\n\nh1, h3 {\n font: bold 16px/18px \"Courier New\", Courier, mono;\n white-space: pre;\n color: #999;\n}\nh1 b {\n color: #ddd;\n}\n\n.comment {\n margin-top: 30px;\n}\n\nh3 b {\n display: inline-block;\n color: #fff;\n width: 200px;\n}\n\nh3 span {\n color: #aaa;\n font-style: normal;\n}\nh3 span.link:hover, a h3:hover span.link {\n -webkit-animation: blink .75s linear infinite;\n -moz-animation: blink .75s linear infinite;\n -ms-animation: blink .75s linear infinite;\n -o-animation: blink .75s linear infinite;\n animation: blink .75s linear infinite;\n}\n\nul {\n list-style: none;\n margin-left: 30px;\n}\nul li {\n margin-top: 3px;\n}\n\n@-webkit-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-moz-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-ms-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-o-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n[touch-action=\"none\"]{ -ms-touch-action: none; touch-action: none; }\n[touch-action=\"pan-x\"]{ -ms-touch-action: pan-x; touch-action: pan-x; }\n[touch-action=\"pan-y\"]{ -ms-touch-action: pan-y; touch-action: pan-y; }\n[touch-action=\"scroll\"],[touch-action=\"pan-x pan-y\"],[touch-action=\"pan-y pan-x\"]{ -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; }","source":"project/stylesheets/style.css","raw":"* {\n margin: 0;\n padding: 0;\n \n /* Goin' all DOS-y */\n -webkit-font-smoothing: none;\n}\n\nbody {\n background: #111;\n font: 16px/18px \"Courier New\", Courier, mono;\n color: #fff;\n}\n\ndiv.wrap {\n max-width: 1100px;\n margin: 100px auto 0;\n}\n\na {\n text-decoration: none;\n color: #fff;\n}\n\nh1, h3 {\n font: bold 16px/18px \"Courier New\", Courier, mono;\n white-space: pre;\n color: #999;\n}\nh1 b {\n color: #ddd;\n}\n\n.comment {\n margin-top: 30px;\n}\n\nh3 b {\n display: inline-block;\n color: #fff;\n width: 200px;\n}\n\nh3 span {\n color: #aaa;\n font-style: normal;\n}\nh3 span.link:hover, a h3:hover span.link {\n -webkit-animation: blink .75s linear infinite;\n -moz-animation: blink .75s linear infinite;\n -ms-animation: blink .75s linear infinite;\n -o-animation: blink .75s linear infinite;\n animation: blink .75s linear infinite;\n}\n\nul {\n list-style: none;\n margin-left: 30px;\n}\nul li {\n margin-top: 3px;\n}\n\n@-webkit-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-moz-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-ms-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-o-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n[touch-action=\"none\"]{ -ms-touch-action: none; touch-action: none; }\n[touch-action=\"pan-x\"]{ -ms-touch-action: pan-x; touch-action: pan-x; }\n[touch-action=\"pan-y\"]{ -ms-touch-action: pan-y; touch-action: pan-y; }\n[touch-action=\"scroll\"],[touch-action=\"pan-x pan-y\"],[touch-action=\"pan-y pan-x\"]{ -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; }","date":"2017-05-04T07:08:50.450Z","updated":"2017-05-04T07:08:50.450Z","path":"project/stylesheets/style.css","layout":"false","title":"","comments":1,"_id":"cjemy9kbt0039wsv7duxr6h9m","content":"* {\n margin: 0;\n padding: 0;\n \n /* Goin' all DOS-y */\n -webkit-font-smoothing: none;\n}\n\nbody {\n background: #111;\n font: 16px/18px \"Courier New\", Courier, mono;\n color: #fff;\n}\n\ndiv.wrap {\n max-width: 1100px;\n margin: 100px auto 0;\n}\n\na {\n text-decoration: none;\n color: #fff;\n}\n\nh1, h3 {\n font: bold 16px/18px \"Courier New\", Courier, mono;\n white-space: pre;\n color: #999;\n}\nh1 b {\n color: #ddd;\n}\n\n.comment {\n margin-top: 30px;\n}\n\nh3 b {\n display: inline-block;\n color: #fff;\n width: 200px;\n}\n\nh3 span {\n color: #aaa;\n font-style: normal;\n}\nh3 span.link:hover, a h3:hover span.link {\n -webkit-animation: blink .75s linear infinite;\n -moz-animation: blink .75s linear infinite;\n -ms-animation: blink .75s linear infinite;\n -o-animation: blink .75s linear infinite;\n animation: blink .75s linear infinite;\n}\n\nul {\n list-style: none;\n margin-left: 30px;\n}\nul li {\n margin-top: 3px;\n}\n\n@-webkit-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-moz-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-ms-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-o-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n[touch-action=\"none\"]{ -ms-touch-action: none; touch-action: none; }\n[touch-action=\"pan-x\"]{ -ms-touch-action: pan-x; touch-action: pan-x; }\n[touch-action=\"pan-y\"]{ -ms-touch-action: pan-y; touch-action: pan-y; }\n[touch-action=\"scroll\"],[touch-action=\"pan-x pan-y\"],[touch-action=\"pan-y pan-x\"]{ -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; }","excerpt":"","more":"* {\n margin: 0;\n padding: 0;\n \n /* Goin' all DOS-y */\n -webkit-font-smoothing: none;\n}\n\nbody {\n background: #111;\n font: 16px/18px \"Courier New\", Courier, mono;\n color: #fff;\n}\n\ndiv.wrap {\n max-width: 1100px;\n margin: 100px auto 0;\n}\n\na {\n text-decoration: none;\n color: #fff;\n}\n\nh1, h3 {\n font: bold 16px/18px \"Courier New\", Courier, mono;\n white-space: pre;\n color: #999;\n}\nh1 b {\n color: #ddd;\n}\n\n.comment {\n margin-top: 30px;\n}\n\nh3 b {\n display: inline-block;\n color: #fff;\n width: 200px;\n}\n\nh3 span {\n color: #aaa;\n font-style: normal;\n}\nh3 span.link:hover, a h3:hover span.link {\n -webkit-animation: blink .75s linear infinite;\n -moz-animation: blink .75s linear infinite;\n -ms-animation: blink .75s linear infinite;\n -o-animation: blink .75s linear infinite;\n animation: blink .75s linear infinite;\n}\n\nul {\n list-style: none;\n margin-left: 30px;\n}\nul li {\n margin-top: 3px;\n}\n\n@-webkit-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-moz-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-ms-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@-o-keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n@keyframes blink {\n 0% {\n background: #ddd;\n color: #000;\n }\n 50% {\n background: #ddd;\n color: #000;\n }\n 50.01% {\n background: transparent;\n color: #aaa;\n }\n 99.99% {\n background: transparent;\n color: #aaa;\n }\n 100% {\n background: #ddd;\n color: #aaa;\n }\n}\n\n[touch-action=\"none\"]{ -ms-touch-action: none; touch-action: none; }\n[touch-action=\"pan-x\"]{ -ms-touch-action: pan-x; touch-action: pan-x; }\n[touch-action=\"pan-y\"]{ -ms-touch-action: pan-y; touch-action: pan-y; }\n[touch-action=\"scroll\"],[touch-action=\"pan-x pan-y\"],[touch-action=\"pan-y pan-x\"]{ -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; }"}],"Post":[{"title":"JsWeb框架手册","comment":true,"date":"2018-03-10T09:07:24.000Z","_content":"\n# 第一章 创建工程\n\n## 1.1 创建工程\n\n工程得创建分为两种方式:第一种,从空工程开始创建。第二种,通过intellij idea得项目模板来创建。使用第二种方式创建得时候需要使用网络,由于idea得服务器在国外,所以速度相对比较慢。本节介绍的是第一种方法。\n\n \n\n第一种方法所需的条件:1.类库文件,2.JsWeb框架的js服务端类库。这些文件在公司的资料共享服务器中。\n\n \n\n文件-新建-工程,不要选任何选项,点击下一步。创建一个普通的java工程。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685C.tmp.jpg) \n\n输入工程名字\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685D.tmp.jpg) \n\n新建完成后工程目录如下:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686D.tmp.jpg) \n\n创建一个lib目录\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686E.tmp.jpg) \n\n将类库文件复制到工程中\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686F.tmp.jpg) \n\n复制完成后,右键add as library\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6880.tmp.jpg) \n\nLibrary的名字和文件夹的名字保持一致。\n\n \n\n添加完成后,打开工程属性\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6881.tmp.jpg) \n\n \n\n打开工程属性 添加 facets,选择spring,然后选择web,点击 create artifact\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6892.tmp.jpg) \n\n将工程右侧的libraries都添加到左侧output目录里面,如下图\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6893.tmp.jpg) \n\nProblems的数量为0.\n\n目前,IDE应该已经自动创建了Web目录和Web.xml文件。\n\n将 配置文件和js类库文件复制到工程中\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A3.tmp.jpg) \n\n复制完成后如下图:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A4.tmp.jpg) \n\n将JspPageController类复制到Src目录下的如下位置,若包不存在请创建\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A5.tmp.jpg) \n\n## 1.2 工程配置\n\n在JSAPI.xml文件中 进行项目的配置\n\n \n\n连接字符串的配置:\n\n修改driverclassname,jdbcurl,username,password 默认线程池大小:最小10,最大100\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68B6.tmp.jpg) \n\n常见配置方案:\n\n1. MySql\n\n2. Oracle\n\n3. SqlServer\n\n\n\n\n\nJsweb扫描器:\n\n配置js服务接口根目录\n\n配置js服务端类库跟目录\n\n配置js服务端自定义类库跟目录\n\n配置licensekey\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68C6.tmp.jpg) \n\n \n\n映射和拦截器:\n\nJsweb接口的基础路径是 /jsons 所有/jsons/*.form的请求都会由jsapicontroller来处理。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D7.tmp.jpg) \n\n## 1.3 工程结构\n\n工程建立完成后目录结构如下:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D8.tmp.jpg) \n\nsrc文件夹用于存放java代码文件\n\njsapis用于存放jsweb的服务端接口文件\n\njscustomlibs 用于存放与当前工程相关的函数库文件\n\njslibs 用于存放通用函数库文件\n\npages用于存放jsp文件\n\nweb目录下用于存放网站的静态资源\n\napplicationContext.xml 为工程中的spring配置文件\n\ndispatcher-servlet.xml 为系统spring配置文件\n\njsapi.xml jsweb配置文件\n\nweb.xml web配置文件\n\n# 第二章 JsWeb框架的简单介绍\n\n## 2.1 框架的工作原理\n\n目前项目的开发框架为:Spring+SpringMVC+JsWeb框架。JsWeb框架本身依赖于Spring 和 Spring MVC框架。框架本身兼容其他第三方框架,JsWeb框架通过Controller与Spring MVC项目相结合,通过实现Controller接口从Spring MVC获取Request、Repsonse、ModelAndView、SevletSession等对象。JsApiController通过调用编译后的JS对请求进行处理。工作原理如图2-1。框架本身是基于SpringMVC框架扩展,与其他框架不产生冲突。\n\n \n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68E9.tmp.png)\n\n图2-1 JsWeb框架工作原理图\n\n为了能快速的开发服务端接口,开发了JSWEB框架——一个可以使用javascript脚本来开发服务端数据接口的框架。\n\n### 框架优势\n\nJSWEB框架相比传统的Java服务端框架具有以下优势:\n\n- 无model层,当数据库发生变更时无需重新写model类,而对于某些返回数据(由表链接产生,不存在于model层)无需创建大量的model类。\n- 基于实体关系的sql生成类库,可动态生成sql。使用类似于mongodb的语法 操纵表连接查询,无需创建大量视图,无惧数据库字段增加删除更改。\n- 可直接操作WEB底层(Session,Request,Response,Header,Status等)\n- 可灵活扩展第三方插件(支付、快递、短信、邮件等)\n\n## 2.2 框架功能介绍\n\n框架针对Web开发中所遇到的各类问题,封装了相应的函数。下面简单介绍下各个函数库中各个函数库中函数的功能。\n\n### 2.2.1 codec函数库\n\ncodec函数库用于做字符串编码,目前函数库里的函数主要用于生成字符串的摘要。主要应用于密码保存。主要函数及功能见表2-1。\n\n| 函数名 | 功能 | 参数 |\n| --------- | ---------------------------------------------- | ---------------------------------------------- |\n| md5hex | 求解字符串的MD5值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha1hex | 求解字符串的sha1值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha256hex | 求解字符串的sha256值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha384hex | 求解字符串的sha384值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha512hex | 求解字符串的sha512值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n\n表2-1 codec函数库的主要函数\n\n### 2.2.2 email函数库\n\nemail函数库用于邮件的发送和读取。函数库可应用于项目中的用户注册、用户激活账户、邮件找回密码、消息通知、广告推广等模块。主要函数及功能见表2-2。\n\n| 函数名 | 功能 | 参数 |\n| ------------ | ------------------ | ------------------------------------------------------------ |\n| sendhtmlmail | 发送html富文本邮件 | 1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(html)11.attachementFiles 附件列表(文件地址列表) |\n| sendtextmail | 发送纯文本邮件 | 1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(文本)11.attachementFiles 附件列表(文件地址列表) |\n\n表2-2 email函数库的主要函数\n\n### 2.2.3 fileutils函数库\n\nfileutils函数库用于文件操作。函数库可以用于管理服务器端的文件,比如清理用户上传的临时文件。也可以读取服务器端的文本文件。主要函数及功能见表2-3。\n\n| 函数名 | 功能 | 参数 |\n| ------------- | ---------------------------------- | ------------------------------------------------------------ |\n| createfile | 创建文件 | 1. filepath 需要创建的文件的路径,绝对路径return true/false 成功/失败 |\n| listfiles | 列出目录下的所有文件 | 1.dir 目录的绝对路径return 字符串列表,用于保存目录下所有文件的数组 |\n| listfileitems | 列出目录下的所有文件,包括文件属性 | 1.dir目录的绝对路径return 目录下的所有文件的列表,列表中保存了每个文件的详细信息。 |\n| searchFiles | 搜索目录下的文件,包括子目录 | 1.dir目录的绝对路径2.keyword 搜素关键字return 字符串列表,用于保存目录下所有文件的数组 |\n| mkdir | 创建目录 | 1.dir目录的绝对路径return true/false 成功/失败 |\n| deletefile | 删除文件或文件夹 | 1. fileordir文件或目录的绝对路径return true/false 成功/失败 |\n| readfile | 读取文本文件的内容 | 1. filepath需要读取的文件的绝对路径2.encoding 文件的编码,默认为utf-8return 文件中的文本内容 |\n| writefile | 将文本写入文本文件 | 1. filepath需要读取的文件的绝对路径2.content 要写入的文件内容3.encoding 文件的编码,默认为utf-8return true/false 成功/失败 |\n\n表2-3 fileutils函数库的主要函数\n\n### 2.2.4 image函数库\n\nimage函数库用于图像处理相关的应用,基本功能包括生成数字验证码。图片调整大小,获取图片的大小等。主要函数及功能见表2-4。\n\n| 函数名 | 功能 | 参数 |\n| ----------------------- | ---------------------------------- | ------------------------------------------------------------ |\n| generatenumbercheckcode | 生成4位数验证码 | 1.context jsweb上下文2.sessionkey 存储验证码的session字段return 生成的4位数字验证码 |\n| resizeimage2file | 将图片进行缩放操作,输出到本地文件 | 1.imagefilepath 图片文件的路径2.targetfilepath目标文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败 |\n| resizeimage2response | 将图片进行缩放操作,输出到response | 1.context jsweb上下文2.imagefilepath 图片文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败 |\n| imagesize | 获取图片得大小 | 1. imagepath 图片文件的路径return 图片的大小{w,h} |\n\n表2-4 image函数库的主要函数\n\n### 2.2.5 net函数库\n\nnet函数库中包含了与网络相关的函数,函数库的功能包括两大类:1.负责给用户端提供上传、下载服务。2.给其他服务端发送get/post请求。主要函数及功能见表2-5。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | ---------------------- | ------------------------------------------------------------ |\n| uploadfileserver | 文件上传服务 | 1.context jsweb上下文2.path 上传文件保存位置3.isrelative 是否是相对路径 |\n| downloadfileserver | 文件下载服务 | 1.context jsweb上下文2.targetfilepath要下载的文件的路径3.isrelative 路径是否是相对路径4.浏览器下载时的文件名5.输出的content-type |\n| postform | post form数据到某url | 1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| poststring | post string数据到某url | 1.url 远程服务端接口url2.str 要发送的字符串3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| postfile | post 文件到远程服务器 | |\n| getform | get 数据从某url | 1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| downloadfile | 下载远程服务器上的文件 | 1.url 远程文件的url2.method 下载方法get/post3.formdata 发送的form数据4.headers http头,格式为keyvalue5.encoding 发送和接收编码,默认为utf-86.targetfilepath 保存在本地的文件路径,绝对路径return 返回{status,content,responseduration} |\n\n表2-5 net函数库的主要函数\n\n \n\n### 2.2.6 runtime函数库\n\nruntime函数库中,包含了与运行时相关的函数。主要函数及功能见表2-6。\n\n| 函数名 | 功能 | 参数 |\n| --------------- | ------------------------------------------------------------ | ---------------------------------------------------- |\n| rumtimeexec | 执行本地可执行文件 | 1.path 可执行文件的路径2.startuppath 执行的开始目录 |\n| runinbackground | 创建一个新线程执行一个任务。线程从线程池中创建,如果线程池使用枯竭,则需要等待空闲线程。 | 1.context jsweb上下文2.apiname 要执行的任务的api名称 |\n| sleep | 睡眠,停止当前线程一定时间。 | 1.miliseconds 睡眠的毫秒数 |\n\n表2-6 runtime函数库的主要函数\n\n### 2.2.7 servlet函数库\n\nservlet函数库中包含了与request、response、session相关的处理函数。主要函数及功能见表2-7。\n\n| 函数名 | 功能 | 参数 |\n| ------------------- | -------------------------- | ------------------------------------------------------------ |\n| httpstatus | 设置response的状态值 | 1.context jsweb上下文2.status 状态码,数值类型 |\n| contenttype | 设置response的相应内容 | 1.context jsweb上下文2.contenttype0 content-type |\n| setsession | 设置session的值 | 1.context jsweb上下文2.key session的键3.value session的值 |\n| getsession | 获取session的值 | 1.context jsweb上下文2.key session的键return session的值 |\n| setheader | 设置header的值 | 1.context jsweb上下文2.key session的键3.value header的值 |\n| redirect | 访问重定向 | 1.context jsweb上下文2.url 重定向的url地址 |\n| getheader | 获取header的值 | 1.context jsweb上下文2.key session的键 |\n| setcontenttype | 设置response的相应内容 | 1.context jsweb上下文2.contenttype0 content-type |\n| setview | 设置modelandview中的view | 1.context jsweb上下文2.viewname 视图路径,和spring设置方法一致 |\n| rootphysicpath | 获取网站的绝对路径 | 1.context jsweb上下文2.path 网站根目录的相对路径return 字符串,绝对路径 |\n| contextpath | 获取contextpath | 1.context jsweb上下文return 字符串,访问的contextpath |\n| writeresponsestream | 写入response输出流 | 1.context jsweb上下文2.inputstream 输入流return true/false 成功/失败 |\n| getresponse | 获取response对象 | 1.context jsweb上下文return response |\n| getresponsestream | 获取response输出流 | 1.context jsweb上下文return outputstream |\n| setresponsefilename | 设置response中输出的文件名 | 1.context jsweb上下文2.filename 输出显示的文件名 |\n| getmethod | 获取当前访问的方式 | 1.context jsweb上下文return 字符串,get/set |\n\n表2-7 servlet函数库的主要函数\n\n### 2.2.8 utils函数库\n\nutils工具函数库,主要功能为开发中常见的工具,比如uuid、md5、base64、json序列化反序列化、向内存中获取/保存对象,路径合并等。主要函数及功能见表2-8。\n\n \n\n| 函数名 | 功能 | 参数 |\n| ------------------ | --------------------------------------------- | ----------------------------------------------------- |\n| uuid | 生成一个UUID | 无 |\n| md5 | 计算输入字符串的md5,输出为base64编码的字符串 | 1.input 输入字符串return 返回摘要字符串 |\n| base64 | base64编码函数 | 1.input 输入字符串return 编码后的字符串 |\n| jsonStringify | 对象的json序列化 | 1.obj 要进行序列化的对象return 序列化之后的json字符串 |\n| jsonParse | 对象反序列化 | 1.jsonstr json字符串return 反序列化后的对象 |\n| getmemcache | 获取运行jsweb服务器里面的缓存对象 | 1.key 对象的名称return 缓存的对象 |\n| putmemcache | 将对象放入运行jsweb服务器里面的缓存 | 1.key 对象的名称2.value 要缓存的对象 |\n| ismemcachecontains | 判断缓存中是否包含对象的名称 | 1.key 对象的名称return true/false 成功/失败 |\n| console | 从控制台中输出对象 | 1.str 要输出的对象 |\n| threadid | 获取当前线程的线程id | return 线程id,数字 |\n| createlist | 创建java的list | return list |\n| createsafemap | 创建java中的map | return map |\n| pathcombine | 合并路径 | 无限参数,路径return 合并后的路径 |\n\n表2-8 servlet函数库的主要函数\n\n### 2.2.9 compress函数库\n\ncompress函数库用于在服务端创建压缩文件。目前功能是可以把文件夹中的文件压缩为一个压缩文件,支持的格式为zip。主要函数及功能见表2-9。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | ----------------------------------------- | ------------------------------------------------------------ |\n| zipfolder | 将文件夹压缩为一个zip文件,保存到文件 | 1.rootfolder 要压缩的根目录2.extlist 后缀列表3.outfile 输出文件的路径 |\n| zipfolder2response | 将文件夹压缩为一个zip文件,输出到response | 1.context jsweb上下文2.rootfolder 要压缩的根目录3.extlist 后缀列表 |\n\n表2-9 compress函数库的主要函数\n\n应用场景:\n\n1.需要批量下载文件的需求,如:沐诺农场批量下载二维码\n\n2.需要下载的文件过大或数量过多,如:下载整年的统计表\n\n### 2.2.10 sqlbase函数库\n\nsqlbase函数库中包含了sql查询的基本函数。该函数库是jsweb项目中最重要的函数库,在一个项目中该函数库会被高频的使用。主要的函数及功能见表2-10。\n\n| 函数名 | 功能 | 参数 |\n| ---------------- | ------------------------------------------------------- | ------------------------------------------------------------ |\n| query | 查询sql并返回查询结果,查询结果为数组 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串return 返回查询结果 |\n| querypagedata | 分页查询sql并返回查询结果,查询结果为数组 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5.pagesize 每页记录的数量return 返回分页查询结果 |\n| multiquery | 查询sql并返回查询结果,查询结果为数组,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文4.mappingstr 映射字符串return 返回查询结果 |\n| exec | 执行sql语句。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文return true/false 成功/失败 |\n| multiexec | 执行sql语句,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文return true/false 成功/失败 |\n| execbatch | 批量执行sql语句。 | 1.fn 查询语句(func注释或字符串格式)2.datalist 数据列表return true/false 成功/失败 |\n| multiexecbatch | 批量执行sql语句,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.datalist 数据列表return true/false 成功/失败 |\n| createconnection | 创建jdbc连接 | 无 |\n| closeconnection | 关闭jdbc连接 | 1.con jdbc连接 |\n| commit | 提交连接中的数据 | 1.con jdbc连接return true/false 成功/失败 |\n| rollback | 回滚连接中的数据 | 1.con jdbc连接return true/false 成功/失败 |\n\n表2-10 sqlbase函数库的主要函数\n\n### 2.2.11 redissql函数库\n\nredissql 为利用redis内存数据库,对接口的数据进行缓存,从而提高实时性不高的接口的访问性能。提升后的性能接近静态资源访问速度。主要的函数及功能见表2-11。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | --------------------------------- | ------------------------------------------------------------ |\n| redisquery | 基于redis内存数据的缓存查询。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4. expire 设置超时时间,毫秒return 返回查询结果 |\n| redisquerypagedata | 基于redis内存数据的缓存分页查询。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5. expire 设置超时时间,毫秒return 返回分页查询结果 |\n\n表2-11 redissql函数库的主要函数\n\n应用场景:\n\n1. 高频且对数据实时性不高的接口,如商城主页的商品列表接口、商品品类接口、商店店铺页面的商品品类和 商品接口。\n\n### 2.2.12 dber/dberjs函数库\n\ndber/dberjs函数库是一个全新的基于实体关系进行数据查询和插入的函数库。与传统的sql不用,基于实体关系的查询根据数据表中预定义的连接关系自动生成查询的sql语句。实体关系查询提供了几种查询源语:query filter search orderby。除了查询功能外还提供基于实体的删除、更新和插入功能。主要的函数及功能见表2-12,2-13。\n\n| 函数名 | 功能 | 参数 |\n| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n| dbcontext().query | 根据用户输入的实体结构字符串进行查询 | 1.structurestr 实体结构字符串 |\n| dbcontext().[filter]() | 根据过滤条件进行过滤 | 1.filterstr 过滤字符串 |\n| dbcontext().search | 综合搜索,当用户没有提交搜索变量的值的时候不进行该条件搜索,否则进行搜索。通常用于多条件搜索。 | 1.varname 搜索变量名2.condition 过滤字符串 |\n| dbcontext().orderby | 排序 | 1.orderbystr 排序字符串 |\n| dbcontext().buildsqlquery | 构建sql字符串和映射字符串 | return 返回{sql,mappingstr} |\n| initmysqldb | 初始化mysql数据库的实体关系 | 数据库schema名称 |\n| db.relation | 预定义实体与实体的关系 | 1.modelpropertystr 实体属性字符串2.modelconnectorstr 实体连接字符串3.relationtype 实体关系,1:1 1:n |\n\n表2-12 dber函数库的主要函数\n\n| 函数名 | 功能 | 参数 |\n| ------------------------- | -------------------------------- | ------------------------------------------------------------ |\n| deleteentity | 删除数据库中实体 | 1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| updateentity | 更新数据库中的实体 | 1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertentity | 将实体对象插入数据库 | 1.entityname 实体名称2.entitydata 实体的对象3.isuserpk 是否使用entitydata中的主键,默认为null4. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multideleteentity | 删除数据库中实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multiupdateentity | 更新数据库中的实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multiinsertentity | 将实体对象插入数据库,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| updateentitybatch | 批量更新实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertentitybatch | 批量插入实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertorupdateentity | 插入或更新实体 | 1.entityname 实体名称2.entitydata 实体的对象return {result,errormessage} |\n| multiinsertorupdateentity | 插入或更新实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象return {result,errormessage} |\n| insertorupdateentitybatch | 批量插入或更新实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表return {result,errormessage} |\n\n表2-13 dberjs函数库的主要函数\n\n \n\n### 2.2.13 text函数库\n\ntext函数库是一个文本计算的科学函数库。主要功能为计算文本之间的相似性,提供多种相似性衡量标准,计算文本的最长公共子串。主要的函数及功能见表2-14。\n\n| 函数名 | 功能 | 参数 |\n| ----------------------------------- | ----------------------- | ----------------------- |\n| textjaccardsimilarity | 计算文本的jaccard相似性 | 1.str12.str2return 数值 |\n| textlongestcommonsubsequnce | 计算最长公共子串(LCS) | 1.str12.str2return 数值 |\n| textlongestcommonsubsequncedistance | 计算最长公共子串相似性 | 1.str12.str2return 数值 |\n| texthammingdistance | 计算汉明距离 | 1.str12.str2return 数值 |\n| textfuzzyscore | 计算模糊值 | 1.str12.str2return 数值 |\n\n表2-14 text函数库的主要函数\n\n函数库的可应用场景举例:\n\n1.在输入提示框中显示提示,如果使用子串搜索方法,用户输入错误将导致提示消失。最相似方法 可以容许一定的错误。\n\n2.差异比较,比如比较两段文本 完全相同的部分。\n\n### 2.2.14 velocity函数库\n\nvelocity函数库的主要功能是提供模板渲染功能,目前渲染的模板引擎是velocity。主要的函数及功能见表2-15。\n\n| 函数名 | 功能 | 参数 |\n| ---------------- | ------------------------------ | ----------------------------------------- |\n| velocitytemplate | 将用户输入的模板字符串进行渲染 | 1.tempatestr2.paramsreturn 渲染后的字符串 |\n\n表2-15 velocity函数库的主要函数\n\n应用场景举例:\n\n1. 发送验证码短信\n\n2. 发送激活账号邮件\n\n3. 找回密码邮件/短信\n\n4. 业务通知类短信/邮件/微信客服消息\n\n### 2.2.15 excel函数库\n\nexcel函数库主要功能是提供excel操作的相关函数。目前使用的excel文件操作类库是poi。主要的函数及功能见表2-16。\n\n| 函数名 | 功能 | 参数 |\n| ---------------------------- | ----------------------------- | ------------------------------------------------------------ |\n| exportexceltemplate2file | 导出excel模板文件到指定的路径 | 1.datacontext 数据上下文2.templatefilepath excel模板的路径3.outfilepath 输出文件路径 |\n| exportexceltemplate2response | 导出excel模板文件到response | 1.context jsweb上下文2.datacontext 数据上下文3.templatefilepath excel模板的路径4.outfilename 输出文件名 |\n| readexcelrows | 读取excel文件的部分内容 | 1.excelfilepath excel文件路径2.sheetindex sheet的index3.column 列号,从0开始4.start 起始行号5.end 终止行号return 数组 |\n| readexcelcolumns | 读取excel文件的部分内容 | 1.excelfilepath excel文件路径2.sheetindex sheet的index3.rownumber 行号,从0开始4.start 起始列号5.end 终止列号return 数组 |\n\n表2-16 excel函数库的主要函数\n\n应用场景举例:\n\n1.导出店铺订单\n\n2.导出用户列表\n\n3.批量添加数据\n\n4.导出统计表,带筛选功能,富文本等\n\n# 第三章 JsWeb框架的用法\n\n\n\n## 3.1 基本sql查询\n\n数据库查询在传统的web项目中是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。\n\n \n\n数据库:shunfengtest 本地版,在资料中有,在运行本教程中的例子之前需要先部署好数据库。\n\n设置jsapi.xml文件中的 jdbcUrl为:\n\njdbc:mysql://localhost/shunfengtest?allowMultiQueries=true\n\nshunfengtest数据库简介:shunfengtest数据库是顺丰通服务的数据库,顺丰通系统中包含一个商城系统和一个外卖系统,商城功能中除了正常的商城功能外,还包含一个三级代理功能,即普通用户通过身份认证后,可以代理商家或一二级代理商的商品,当商品通过代理人的分享售卖后,代理人以及代理人的上级可得到代理分红。系统中表sp开头的的是商城的数据表,rs开头的是外卖的数据表,cm是公用数据表,as是代理数据表,ed是快递的数据表,sys是系统数据表。\n\n \n\n### 场景1\n\n系统管理员需要管理在商城中注册的商家,所需要获取全部的商家列表。需要显示的数据包括sp_shop表中的 shopname、shopimg、shopshortdescription、shopownername、商店所在的省市区字符串和详细地址。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6909.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_3_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps690A.tmp.jpg) \n\n返回的是json数组。\n\n如果sql语句是多行的 ,用“”或‘’则比较麻烦。可以用函数注释方法进行多行字符串输入。(仅限sqlbase函数库)。\n\n当查询无参数且无需改变默认映射的时候,后面两个参数可以省略。\n\n[{shopid,shopname,shop…..}, {shopid,shopname,shop…..},….]\n\n \n\n### 场景2\n\n在管理员使用的管理系统中,管理员需要查看各个商家上架的商品。同时,普通用户也需要查看某个商家店铺内的所有商品。因此,需要一个获取某商家全部商品列表的接口。接口需要传入shopid,接口返回该shop内所有商品的列表。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6949.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_3_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695A.tmp.jpg) \n\n测试数据:\n\nshopid=[006e0aca-0aae-11e7-ab6a-00ac2794c53f]()\n\n本接口没有设置映射,默认映射按照数据库表定义进行字段的映射。\n\nsql语句中存在一个变量${shopid},所以在query的第二个参数中构造了一个包含shopid的对象。如果context中包含该字段可以直接传入context作为query函数的第二个参数。\n\n \n\n### 场景3\n\n在管理员的管理界面中,需要以一个商家商品树,列出全部商家和商家下的全部商品,并显示在easyui的tree中。对于sp_shop表仅需要字段 shopid、shopname,对于商品表sp_good仅需要goodid,goodname即可。返回的json格式应满足easyui中的tree的输入格式。\n\n \n\ntree的输入格式\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695B.tmp.jpg) \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695C.tmp.jpg) \n\n[jsweb代码:详见jsapis]()/jsons/case2_3_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696D.tmp.jpg) \n\n输出的部分结果:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696E.tmp.jpg) \n\n### 场景4\n\n管理员或者某商店用户查看所有或者商店对应的商品时,后台easyui框架中通常是使用分页,而不是直接把所有的数据展示出来。接口需要传入两个参数,page和rows。page代表当前是第几页,rows代表每页显示的行数。返回的json格式为rows:当前页的数据,total:一共多少行。\n\n \n\n结果的返回格式:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697E.tmp.jpg) \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697F.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_3_4.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6990.tmp.jpg) \n\n \n\n### 场景5\n\n基于实体关系的查询,使用实体关系查询不需要自己写sql语句,基本的查询语句这样写,首先需要调用dbcontext()方法,然后调用其query方法,参数为数据库名或结构化字符串,然后调用buildsqlquery()方法,最后在query方法中传入buildsqlquery()方法返回值对应的两个参数即可。对于场景1,显示全部的属性,使用实体关系查询。\n\n \n\njsweb代码:详见jsapis/jsons/case2_3_5.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6991.tmp.jpg) \n\n.buildsqlquery()方法返回了其创建的映射关系q.mappingstr,若想使用自己的映射关系将q.mappingstr改为自己想要的映射关系即可。\n\n \n\n### 场景6\n\n基于场景2,管理员查看某个商家的商品,然后管理员还想要通过商品名进行检索,比如商品产地为沈阳(商品产地为商品名第一项),这种时候书写sql语句就需要使用like关键词。使用实体关系查询就需要使用.filter()方法和.search()方法,具体使用方法见[2.2.12](#_2.2.12_dber/dberjs函数库)。\n\n \n\n[jsweb代码:详见jsapis]()/jsons/case2_3_6.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6992.tmp.jpg) \n\n测试数据:\n\nshopid=006e0aca-0aae-11e7-ab6a-00ac2794c53f\n\nkeyword=沈阳\n\n \n\n### 场景7\n\n项目上线后,商城的主页会经常被访问,为了提高性能可以使用内存数据库查询,具体介绍见[2.2.11](#_2.2.11_redissql函数库)。\n\n \n\njsweb代码:详见jsapis/jsons/case2_3_7.js\n\n \n\n \n\n \n\n \n\n \n\n## 3.2 基本sql操作\n\n数据库操作(插入、更新、删除)在传统的web项目中同样也是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。\n\n \n\n数据库介绍和配置同2.3。\n\n \n\n### 场景1\n\n商家需要管理他们商店的商品,首先是上线新的商品,这里就需要向数据库表sp_good表中插入一条数据,需要的字段有goodid、goodname、[gooddetaildescription]()、goodminprice、goodmaxprice、shopid等。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A3.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A4.tmp.jpg) \n\n测试数据:\n\ngoodname:‘大连|樱桃’、[gooddetaildescription]():‘大连大樱桃’、gooddetaildescription:15、\n\ngoodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、\n\ngoodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、\n\ngoodisputway:2017-5-31、goodisremind:1\n\n返回的是true或false,成功为true,失败为false。\n\n \n\n### 场景2\n\n在一段时间后,商家可能需要修改商品信息,比如修改商品详情,这样情况下需要修改产品表中的数据。比如根据goodid修改gooddetaildescription字段。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B4.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B5.tmp.jpg) \n\n测试数据:\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\ngooddetaildescription:’大连大樱桃,好吃又便宜’\n\n \n\n### 场景3\n\n商家管理商品,当商家不在卖某个商品时,需要将其删除,根据这个商品的id将其在数据库表中删除。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C6.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C7.tmp.jpg) \n\n测试数据:\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\n \n\n### 场景4\n\n使用实体关系向表中插入数据。方法为insertentity()方法,参数为:第一个为表名、第二个为参数。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_4_4.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C8.tmp.jpg) \n\n测试数据:\n\ngoodname:‘大连|樱桃’、gooddetaildescription:‘大连大樱桃’、gooddetaildescription:15、\n\ngoodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、\n\ngoodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、\n\ngoodisputway:2017-5-31、goodisremind:1\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D8.tmp.jpg) \n\n \n\n### 场景5\n\n[使用实体关系更新数据库表中的数据](),方法为updateentity(),参数为:第一个为表名、第二个为参数,第三个为更新的条件。\n\n \n\n[jsweb代码:详见]()jsapis/jsons/case_2_4_5.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D9.tmp.jpg) \n\n[测试数据]():\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\ngooddetaildescription:’大连大樱桃,好吃又便宜’\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EA.tmp.jpg) \n\n \n\n### 场景6\n\n使用实体关系删除数据库表中的数据,方法为updateentity(),参数为:第一个为表名、第二个为实体(删除数据的依据,主要是id),第三个为更新的条件(可不填)。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_4_6.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EB.tmp.jpg) \n\n测试数据:\n\ngoodname:\"大连|樱桃\";\n\ngooddetaildescription:\"大连大樱桃\";\n\ngoodminprice:\"15\";\n\ngoodmaxprice:\"20\";\n\ngoodcreator:\"lirf\";\n\ngoodcategory:\"水果\";\n\nshopid:\"ff45459f-45d3-11e7-9b1c-38d547ab4abf\";\n\ngoodid:\"ff45459f-45d3-11e7-9b1c-38d547ab4abf\";\n\ngoodorder:\"1\";\n\ngoodisputway:\"1\";\n\ngoodproducedate:\"2017-5-31\";\n\ngoodisremind:\"1\";\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FC.tmp.jpg) \n\n## 3.3 sql事务操作\n\n在对数据库进行插入、更新、删除等操作时,经常遇到同时执行多条sql语句的情况,这种情况下就需要使用事务操作。在mybatis中支持事务操作,只需要在方法前加上注解就可以,在JSWEB框架中,事务操作有其特定的方法,下面来看几个例子。\n\n \n\n### 场景1\n\n用户提交订单之后进行支付,支付完成之后需要将订单状态改为已支付,同时需要在支付记录中插入一条新的数据。这种情况下需要使用事务来完成,在框架中使用multiexec()方法来完成,具体的参数及使用方法见[2.2.10](#_2.2.10_sqlbase函数库)。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FD.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_5_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FE.tmp.jpg) \n\n测试数据:\n\norderpayedprice:100\n\nordernumber:CP1704281613263536\n\n \n\n### 场景2\n\n场景同上,使用实体关系进行事务操作,需要用到的方法为multideleteentity()、multiupdateentity()、multiinsertentity(),详情见[2.2.12](#_2.2.12_dber/dberjs函数库)。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_5_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0E.tmp.jpg) \n\n \n\n## 3.4 实体关系查询\n\n在前面介绍了实体关系查询的基本用法,但是实体关系查询最实用的是当两个或多个表关联查询时可以用比较少的代码来实现。下边来看几个场景。\n\n### 场景1\n\n在管理员的管理界面中,需要列出全部商家和商家下的全部商品,并显示在easyui中。通过实体关系查询可以查询出所有店铺的所有商品,还可以使用filter()或search()方法进行条件筛选。\n\n \n\n使用实体关系关联查询首先需要shunfengdb.js文件中写配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0F.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A20.tmp.jpg) \n\n### 场景2\n\n在前台微信端页面,当用户点进一个商品的详情页之后需要查询该商品的详细信息,包括品类、图片、代理配置以及拥有的规格等信息,这些信息分别存在四个表中,如果写连接查询的sql语句会比较复杂,如果用实体关系查询就非常简单。\n\n \n\n首先shunfengdb.js文件中的配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A21.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A32.tmp.jpg) \n\n部分结果如下如所示\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A33.tmp.jpg) \n\n### 场景3\n\n在前台微信端页面,当用户提交订单信息时可能需要根据规格去查询商品信息以及该商品对应的店铺信息,这种情况下也可以使用实体关系查询。\n\n \n\n首先shunfengdb.js文件中的配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A43.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A44.tmp.jpg) ","source":"_posts/JsWeb框架手册.md","raw":"---\ntitle: JsWeb框架手册\ncomment: true\ndate: 2018-03-10 17:07:24\ntags: [Java, JavaWeb, JsWeb]\n---\n\n# 第一章 创建工程\n\n## 1.1 创建工程\n\n工程得创建分为两种方式:第一种,从空工程开始创建。第二种,通过intellij idea得项目模板来创建。使用第二种方式创建得时候需要使用网络,由于idea得服务器在国外,所以速度相对比较慢。本节介绍的是第一种方法。\n\n \n\n第一种方法所需的条件:1.类库文件,2.JsWeb框架的js服务端类库。这些文件在公司的资料共享服务器中。\n\n \n\n文件-新建-工程,不要选任何选项,点击下一步。创建一个普通的java工程。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685C.tmp.jpg) \n\n输入工程名字\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685D.tmp.jpg) \n\n新建完成后工程目录如下:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686D.tmp.jpg) \n\n创建一个lib目录\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686E.tmp.jpg) \n\n将类库文件复制到工程中\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686F.tmp.jpg) \n\n复制完成后,右键add as library\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6880.tmp.jpg) \n\nLibrary的名字和文件夹的名字保持一致。\n\n \n\n添加完成后,打开工程属性\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6881.tmp.jpg) \n\n \n\n打开工程属性 添加 facets,选择spring,然后选择web,点击 create artifact\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6892.tmp.jpg) \n\n将工程右侧的libraries都添加到左侧output目录里面,如下图\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6893.tmp.jpg) \n\nProblems的数量为0.\n\n目前,IDE应该已经自动创建了Web目录和Web.xml文件。\n\n将 配置文件和js类库文件复制到工程中\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A3.tmp.jpg) \n\n复制完成后如下图:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A4.tmp.jpg) \n\n将JspPageController类复制到Src目录下的如下位置,若包不存在请创建\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A5.tmp.jpg) \n\n## 1.2 工程配置\n\n在JSAPI.xml文件中 进行项目的配置\n\n \n\n连接字符串的配置:\n\n修改driverclassname,jdbcurl,username,password 默认线程池大小:最小10,最大100\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68B6.tmp.jpg) \n\n常见配置方案:\n\n1. MySql\n\n2. Oracle\n\n3. SqlServer\n\n\n\n\n\nJsweb扫描器:\n\n配置js服务接口根目录\n\n配置js服务端类库跟目录\n\n配置js服务端自定义类库跟目录\n\n配置licensekey\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68C6.tmp.jpg) \n\n \n\n映射和拦截器:\n\nJsweb接口的基础路径是 /jsons 所有/jsons/*.form的请求都会由jsapicontroller来处理。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D7.tmp.jpg) \n\n## 1.3 工程结构\n\n工程建立完成后目录结构如下:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D8.tmp.jpg) \n\nsrc文件夹用于存放java代码文件\n\njsapis用于存放jsweb的服务端接口文件\n\njscustomlibs 用于存放与当前工程相关的函数库文件\n\njslibs 用于存放通用函数库文件\n\npages用于存放jsp文件\n\nweb目录下用于存放网站的静态资源\n\napplicationContext.xml 为工程中的spring配置文件\n\ndispatcher-servlet.xml 为系统spring配置文件\n\njsapi.xml jsweb配置文件\n\nweb.xml web配置文件\n\n# 第二章 JsWeb框架的简单介绍\n\n## 2.1 框架的工作原理\n\n目前项目的开发框架为:Spring+SpringMVC+JsWeb框架。JsWeb框架本身依赖于Spring 和 Spring MVC框架。框架本身兼容其他第三方框架,JsWeb框架通过Controller与Spring MVC项目相结合,通过实现Controller接口从Spring MVC获取Request、Repsonse、ModelAndView、SevletSession等对象。JsApiController通过调用编译后的JS对请求进行处理。工作原理如图2-1。框架本身是基于SpringMVC框架扩展,与其他框架不产生冲突。\n\n \n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68E9.tmp.png)\n\n图2-1 JsWeb框架工作原理图\n\n为了能快速的开发服务端接口,开发了JSWEB框架——一个可以使用javascript脚本来开发服务端数据接口的框架。\n\n### 框架优势\n\nJSWEB框架相比传统的Java服务端框架具有以下优势:\n\n- 无model层,当数据库发生变更时无需重新写model类,而对于某些返回数据(由表链接产生,不存在于model层)无需创建大量的model类。\n- 基于实体关系的sql生成类库,可动态生成sql。使用类似于mongodb的语法 操纵表连接查询,无需创建大量视图,无惧数据库字段增加删除更改。\n- 可直接操作WEB底层(Session,Request,Response,Header,Status等)\n- 可灵活扩展第三方插件(支付、快递、短信、邮件等)\n\n## 2.2 框架功能介绍\n\n框架针对Web开发中所遇到的各类问题,封装了相应的函数。下面简单介绍下各个函数库中各个函数库中函数的功能。\n\n### 2.2.1 codec函数库\n\ncodec函数库用于做字符串编码,目前函数库里的函数主要用于生成字符串的摘要。主要应用于密码保存。主要函数及功能见表2-1。\n\n| 函数名 | 功能 | 参数 |\n| --------- | ---------------------------------------------- | ---------------------------------------------- |\n| md5hex | 求解字符串的MD5值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha1hex | 求解字符串的sha1值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha256hex | 求解字符串的sha256值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha384hex | 求解字符串的sha384值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n| sha512hex | 求解字符串的sha512值,输出为16进制表示的字符串 | 1.str 输入的字符串return 16进制表示的byte数组 |\n\n表2-1 codec函数库的主要函数\n\n### 2.2.2 email函数库\n\nemail函数库用于邮件的发送和读取。函数库可应用于项目中的用户注册、用户激活账户、邮件找回密码、消息通知、广告推广等模块。主要函数及功能见表2-2。\n\n| 函数名 | 功能 | 参数 |\n| ------------ | ------------------ | ------------------------------------------------------------ |\n| sendhtmlmail | 发送html富文本邮件 | 1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(html)11.attachementFiles 附件列表(文件地址列表) |\n| sendtextmail | 发送纯文本邮件 | 1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(文本)11.attachementFiles 附件列表(文件地址列表) |\n\n表2-2 email函数库的主要函数\n\n### 2.2.3 fileutils函数库\n\nfileutils函数库用于文件操作。函数库可以用于管理服务器端的文件,比如清理用户上传的临时文件。也可以读取服务器端的文本文件。主要函数及功能见表2-3。\n\n| 函数名 | 功能 | 参数 |\n| ------------- | ---------------------------------- | ------------------------------------------------------------ |\n| createfile | 创建文件 | 1. filepath 需要创建的文件的路径,绝对路径return true/false 成功/失败 |\n| listfiles | 列出目录下的所有文件 | 1.dir 目录的绝对路径return 字符串列表,用于保存目录下所有文件的数组 |\n| listfileitems | 列出目录下的所有文件,包括文件属性 | 1.dir目录的绝对路径return 目录下的所有文件的列表,列表中保存了每个文件的详细信息。 |\n| searchFiles | 搜索目录下的文件,包括子目录 | 1.dir目录的绝对路径2.keyword 搜素关键字return 字符串列表,用于保存目录下所有文件的数组 |\n| mkdir | 创建目录 | 1.dir目录的绝对路径return true/false 成功/失败 |\n| deletefile | 删除文件或文件夹 | 1. fileordir文件或目录的绝对路径return true/false 成功/失败 |\n| readfile | 读取文本文件的内容 | 1. filepath需要读取的文件的绝对路径2.encoding 文件的编码,默认为utf-8return 文件中的文本内容 |\n| writefile | 将文本写入文本文件 | 1. filepath需要读取的文件的绝对路径2.content 要写入的文件内容3.encoding 文件的编码,默认为utf-8return true/false 成功/失败 |\n\n表2-3 fileutils函数库的主要函数\n\n### 2.2.4 image函数库\n\nimage函数库用于图像处理相关的应用,基本功能包括生成数字验证码。图片调整大小,获取图片的大小等。主要函数及功能见表2-4。\n\n| 函数名 | 功能 | 参数 |\n| ----------------------- | ---------------------------------- | ------------------------------------------------------------ |\n| generatenumbercheckcode | 生成4位数验证码 | 1.context jsweb上下文2.sessionkey 存储验证码的session字段return 生成的4位数字验证码 |\n| resizeimage2file | 将图片进行缩放操作,输出到本地文件 | 1.imagefilepath 图片文件的路径2.targetfilepath目标文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败 |\n| resizeimage2response | 将图片进行缩放操作,输出到response | 1.context jsweb上下文2.imagefilepath 图片文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败 |\n| imagesize | 获取图片得大小 | 1. imagepath 图片文件的路径return 图片的大小{w,h} |\n\n表2-4 image函数库的主要函数\n\n### 2.2.5 net函数库\n\nnet函数库中包含了与网络相关的函数,函数库的功能包括两大类:1.负责给用户端提供上传、下载服务。2.给其他服务端发送get/post请求。主要函数及功能见表2-5。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | ---------------------- | ------------------------------------------------------------ |\n| uploadfileserver | 文件上传服务 | 1.context jsweb上下文2.path 上传文件保存位置3.isrelative 是否是相对路径 |\n| downloadfileserver | 文件下载服务 | 1.context jsweb上下文2.targetfilepath要下载的文件的路径3.isrelative 路径是否是相对路径4.浏览器下载时的文件名5.输出的content-type |\n| postform | post form数据到某url | 1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| poststring | post string数据到某url | 1.url 远程服务端接口url2.str 要发送的字符串3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| postfile | post 文件到远程服务器 | |\n| getform | get 数据从某url | 1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration} |\n| downloadfile | 下载远程服务器上的文件 | 1.url 远程文件的url2.method 下载方法get/post3.formdata 发送的form数据4.headers http头,格式为keyvalue5.encoding 发送和接收编码,默认为utf-86.targetfilepath 保存在本地的文件路径,绝对路径return 返回{status,content,responseduration} |\n\n表2-5 net函数库的主要函数\n\n \n\n### 2.2.6 runtime函数库\n\nruntime函数库中,包含了与运行时相关的函数。主要函数及功能见表2-6。\n\n| 函数名 | 功能 | 参数 |\n| --------------- | ------------------------------------------------------------ | ---------------------------------------------------- |\n| rumtimeexec | 执行本地可执行文件 | 1.path 可执行文件的路径2.startuppath 执行的开始目录 |\n| runinbackground | 创建一个新线程执行一个任务。线程从线程池中创建,如果线程池使用枯竭,则需要等待空闲线程。 | 1.context jsweb上下文2.apiname 要执行的任务的api名称 |\n| sleep | 睡眠,停止当前线程一定时间。 | 1.miliseconds 睡眠的毫秒数 |\n\n表2-6 runtime函数库的主要函数\n\n### 2.2.7 servlet函数库\n\nservlet函数库中包含了与request、response、session相关的处理函数。主要函数及功能见表2-7。\n\n| 函数名 | 功能 | 参数 |\n| ------------------- | -------------------------- | ------------------------------------------------------------ |\n| httpstatus | 设置response的状态值 | 1.context jsweb上下文2.status 状态码,数值类型 |\n| contenttype | 设置response的相应内容 | 1.context jsweb上下文2.contenttype0 content-type |\n| setsession | 设置session的值 | 1.context jsweb上下文2.key session的键3.value session的值 |\n| getsession | 获取session的值 | 1.context jsweb上下文2.key session的键return session的值 |\n| setheader | 设置header的值 | 1.context jsweb上下文2.key session的键3.value header的值 |\n| redirect | 访问重定向 | 1.context jsweb上下文2.url 重定向的url地址 |\n| getheader | 获取header的值 | 1.context jsweb上下文2.key session的键 |\n| setcontenttype | 设置response的相应内容 | 1.context jsweb上下文2.contenttype0 content-type |\n| setview | 设置modelandview中的view | 1.context jsweb上下文2.viewname 视图路径,和spring设置方法一致 |\n| rootphysicpath | 获取网站的绝对路径 | 1.context jsweb上下文2.path 网站根目录的相对路径return 字符串,绝对路径 |\n| contextpath | 获取contextpath | 1.context jsweb上下文return 字符串,访问的contextpath |\n| writeresponsestream | 写入response输出流 | 1.context jsweb上下文2.inputstream 输入流return true/false 成功/失败 |\n| getresponse | 获取response对象 | 1.context jsweb上下文return response |\n| getresponsestream | 获取response输出流 | 1.context jsweb上下文return outputstream |\n| setresponsefilename | 设置response中输出的文件名 | 1.context jsweb上下文2.filename 输出显示的文件名 |\n| getmethod | 获取当前访问的方式 | 1.context jsweb上下文return 字符串,get/set |\n\n表2-7 servlet函数库的主要函数\n\n### 2.2.8 utils函数库\n\nutils工具函数库,主要功能为开发中常见的工具,比如uuid、md5、base64、json序列化反序列化、向内存中获取/保存对象,路径合并等。主要函数及功能见表2-8。\n\n \n\n| 函数名 | 功能 | 参数 |\n| ------------------ | --------------------------------------------- | ----------------------------------------------------- |\n| uuid | 生成一个UUID | 无 |\n| md5 | 计算输入字符串的md5,输出为base64编码的字符串 | 1.input 输入字符串return 返回摘要字符串 |\n| base64 | base64编码函数 | 1.input 输入字符串return 编码后的字符串 |\n| jsonStringify | 对象的json序列化 | 1.obj 要进行序列化的对象return 序列化之后的json字符串 |\n| jsonParse | 对象反序列化 | 1.jsonstr json字符串return 反序列化后的对象 |\n| getmemcache | 获取运行jsweb服务器里面的缓存对象 | 1.key 对象的名称return 缓存的对象 |\n| putmemcache | 将对象放入运行jsweb服务器里面的缓存 | 1.key 对象的名称2.value 要缓存的对象 |\n| ismemcachecontains | 判断缓存中是否包含对象的名称 | 1.key 对象的名称return true/false 成功/失败 |\n| console | 从控制台中输出对象 | 1.str 要输出的对象 |\n| threadid | 获取当前线程的线程id | return 线程id,数字 |\n| createlist | 创建java的list | return list |\n| createsafemap | 创建java中的map | return map |\n| pathcombine | 合并路径 | 无限参数,路径return 合并后的路径 |\n\n表2-8 servlet函数库的主要函数\n\n### 2.2.9 compress函数库\n\ncompress函数库用于在服务端创建压缩文件。目前功能是可以把文件夹中的文件压缩为一个压缩文件,支持的格式为zip。主要函数及功能见表2-9。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | ----------------------------------------- | ------------------------------------------------------------ |\n| zipfolder | 将文件夹压缩为一个zip文件,保存到文件 | 1.rootfolder 要压缩的根目录2.extlist 后缀列表3.outfile 输出文件的路径 |\n| zipfolder2response | 将文件夹压缩为一个zip文件,输出到response | 1.context jsweb上下文2.rootfolder 要压缩的根目录3.extlist 后缀列表 |\n\n表2-9 compress函数库的主要函数\n\n应用场景:\n\n1.需要批量下载文件的需求,如:沐诺农场批量下载二维码\n\n2.需要下载的文件过大或数量过多,如:下载整年的统计表\n\n### 2.2.10 sqlbase函数库\n\nsqlbase函数库中包含了sql查询的基本函数。该函数库是jsweb项目中最重要的函数库,在一个项目中该函数库会被高频的使用。主要的函数及功能见表2-10。\n\n| 函数名 | 功能 | 参数 |\n| ---------------- | ------------------------------------------------------- | ------------------------------------------------------------ |\n| query | 查询sql并返回查询结果,查询结果为数组 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串return 返回查询结果 |\n| querypagedata | 分页查询sql并返回查询结果,查询结果为数组 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5.pagesize 每页记录的数量return 返回分页查询结果 |\n| multiquery | 查询sql并返回查询结果,查询结果为数组,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文4.mappingstr 映射字符串return 返回查询结果 |\n| exec | 执行sql语句。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文return true/false 成功/失败 |\n| multiexec | 执行sql语句,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文return true/false 成功/失败 |\n| execbatch | 批量执行sql语句。 | 1.fn 查询语句(func注释或字符串格式)2.datalist 数据列表return true/false 成功/失败 |\n| multiexecbatch | 批量执行sql语句,需要传入jdbc连接 | 1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.datalist 数据列表return true/false 成功/失败 |\n| createconnection | 创建jdbc连接 | 无 |\n| closeconnection | 关闭jdbc连接 | 1.con jdbc连接 |\n| commit | 提交连接中的数据 | 1.con jdbc连接return true/false 成功/失败 |\n| rollback | 回滚连接中的数据 | 1.con jdbc连接return true/false 成功/失败 |\n\n表2-10 sqlbase函数库的主要函数\n\n### 2.2.11 redissql函数库\n\nredissql 为利用redis内存数据库,对接口的数据进行缓存,从而提高实时性不高的接口的访问性能。提升后的性能接近静态资源访问速度。主要的函数及功能见表2-11。\n\n| 函数名 | 功能 | 参数 |\n| ------------------ | --------------------------------- | ------------------------------------------------------------ |\n| redisquery | 基于redis内存数据的缓存查询。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4. expire 设置超时时间,毫秒return 返回查询结果 |\n| redisquerypagedata | 基于redis内存数据的缓存分页查询。 | 1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5. expire 设置超时时间,毫秒return 返回分页查询结果 |\n\n表2-11 redissql函数库的主要函数\n\n应用场景:\n\n1. 高频且对数据实时性不高的接口,如商城主页的商品列表接口、商品品类接口、商店店铺页面的商品品类和 商品接口。\n\n### 2.2.12 dber/dberjs函数库\n\ndber/dberjs函数库是一个全新的基于实体关系进行数据查询和插入的函数库。与传统的sql不用,基于实体关系的查询根据数据表中预定义的连接关系自动生成查询的sql语句。实体关系查询提供了几种查询源语:query filter search orderby。除了查询功能外还提供基于实体的删除、更新和插入功能。主要的函数及功能见表2-12,2-13。\n\n| 函数名 | 功能 | 参数 |\n| ------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n| dbcontext().query | 根据用户输入的实体结构字符串进行查询 | 1.structurestr 实体结构字符串 |\n| dbcontext().[filter]() | 根据过滤条件进行过滤 | 1.filterstr 过滤字符串 |\n| dbcontext().search | 综合搜索,当用户没有提交搜索变量的值的时候不进行该条件搜索,否则进行搜索。通常用于多条件搜索。 | 1.varname 搜索变量名2.condition 过滤字符串 |\n| dbcontext().orderby | 排序 | 1.orderbystr 排序字符串 |\n| dbcontext().buildsqlquery | 构建sql字符串和映射字符串 | return 返回{sql,mappingstr} |\n| initmysqldb | 初始化mysql数据库的实体关系 | 数据库schema名称 |\n| db.relation | 预定义实体与实体的关系 | 1.modelpropertystr 实体属性字符串2.modelconnectorstr 实体连接字符串3.relationtype 实体关系,1:1 1:n |\n\n表2-12 dber函数库的主要函数\n\n| 函数名 | 功能 | 参数 |\n| ------------------------- | -------------------------------- | ------------------------------------------------------------ |\n| deleteentity | 删除数据库中实体 | 1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| updateentity | 更新数据库中的实体 | 1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertentity | 将实体对象插入数据库 | 1.entityname 实体名称2.entitydata 实体的对象3.isuserpk 是否使用entitydata中的主键,默认为null4. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multideleteentity | 删除数据库中实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multiupdateentity | 更新数据库中的实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| multiinsertentity | 将实体对象插入数据库,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| updateentitybatch | 批量更新实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertentitybatch | 批量插入实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage} |\n| insertorupdateentity | 插入或更新实体 | 1.entityname 实体名称2.entitydata 实体的对象return {result,errormessage} |\n| multiinsertorupdateentity | 插入或更新实体,带传入连接 | 1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象return {result,errormessage} |\n| insertorupdateentitybatch | 批量插入或更新实体 | 1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表return {result,errormessage} |\n\n表2-13 dberjs函数库的主要函数\n\n \n\n### 2.2.13 text函数库\n\ntext函数库是一个文本计算的科学函数库。主要功能为计算文本之间的相似性,提供多种相似性衡量标准,计算文本的最长公共子串。主要的函数及功能见表2-14。\n\n| 函数名 | 功能 | 参数 |\n| ----------------------------------- | ----------------------- | ----------------------- |\n| textjaccardsimilarity | 计算文本的jaccard相似性 | 1.str12.str2return 数值 |\n| textlongestcommonsubsequnce | 计算最长公共子串(LCS) | 1.str12.str2return 数值 |\n| textlongestcommonsubsequncedistance | 计算最长公共子串相似性 | 1.str12.str2return 数值 |\n| texthammingdistance | 计算汉明距离 | 1.str12.str2return 数值 |\n| textfuzzyscore | 计算模糊值 | 1.str12.str2return 数值 |\n\n表2-14 text函数库的主要函数\n\n函数库的可应用场景举例:\n\n1.在输入提示框中显示提示,如果使用子串搜索方法,用户输入错误将导致提示消失。最相似方法 可以容许一定的错误。\n\n2.差异比较,比如比较两段文本 完全相同的部分。\n\n### 2.2.14 velocity函数库\n\nvelocity函数库的主要功能是提供模板渲染功能,目前渲染的模板引擎是velocity。主要的函数及功能见表2-15。\n\n| 函数名 | 功能 | 参数 |\n| ---------------- | ------------------------------ | ----------------------------------------- |\n| velocitytemplate | 将用户输入的模板字符串进行渲染 | 1.tempatestr2.paramsreturn 渲染后的字符串 |\n\n表2-15 velocity函数库的主要函数\n\n应用场景举例:\n\n1. 发送验证码短信\n\n2. 发送激活账号邮件\n\n3. 找回密码邮件/短信\n\n4. 业务通知类短信/邮件/微信客服消息\n\n### 2.2.15 excel函数库\n\nexcel函数库主要功能是提供excel操作的相关函数。目前使用的excel文件操作类库是poi。主要的函数及功能见表2-16。\n\n| 函数名 | 功能 | 参数 |\n| ---------------------------- | ----------------------------- | ------------------------------------------------------------ |\n| exportexceltemplate2file | 导出excel模板文件到指定的路径 | 1.datacontext 数据上下文2.templatefilepath excel模板的路径3.outfilepath 输出文件路径 |\n| exportexceltemplate2response | 导出excel模板文件到response | 1.context jsweb上下文2.datacontext 数据上下文3.templatefilepath excel模板的路径4.outfilename 输出文件名 |\n| readexcelrows | 读取excel文件的部分内容 | 1.excelfilepath excel文件路径2.sheetindex sheet的index3.column 列号,从0开始4.start 起始行号5.end 终止行号return 数组 |\n| readexcelcolumns | 读取excel文件的部分内容 | 1.excelfilepath excel文件路径2.sheetindex sheet的index3.rownumber 行号,从0开始4.start 起始列号5.end 终止列号return 数组 |\n\n表2-16 excel函数库的主要函数\n\n应用场景举例:\n\n1.导出店铺订单\n\n2.导出用户列表\n\n3.批量添加数据\n\n4.导出统计表,带筛选功能,富文本等\n\n# 第三章 JsWeb框架的用法\n\n\n\n## 3.1 基本sql查询\n\n数据库查询在传统的web项目中是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。\n\n \n\n数据库:shunfengtest 本地版,在资料中有,在运行本教程中的例子之前需要先部署好数据库。\n\n设置jsapi.xml文件中的 jdbcUrl为:\n\njdbc:mysql://localhost/shunfengtest?allowMultiQueries=true\n\nshunfengtest数据库简介:shunfengtest数据库是顺丰通服务的数据库,顺丰通系统中包含一个商城系统和一个外卖系统,商城功能中除了正常的商城功能外,还包含一个三级代理功能,即普通用户通过身份认证后,可以代理商家或一二级代理商的商品,当商品通过代理人的分享售卖后,代理人以及代理人的上级可得到代理分红。系统中表sp开头的的是商城的数据表,rs开头的是外卖的数据表,cm是公用数据表,as是代理数据表,ed是快递的数据表,sys是系统数据表。\n\n \n\n### 场景1\n\n系统管理员需要管理在商城中注册的商家,所需要获取全部的商家列表。需要显示的数据包括sp_shop表中的 shopname、shopimg、shopshortdescription、shopownername、商店所在的省市区字符串和详细地址。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6909.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_3_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps690A.tmp.jpg) \n\n返回的是json数组。\n\n如果sql语句是多行的 ,用“”或‘’则比较麻烦。可以用函数注释方法进行多行字符串输入。(仅限sqlbase函数库)。\n\n当查询无参数且无需改变默认映射的时候,后面两个参数可以省略。\n\n[{shopid,shopname,shop…..}, {shopid,shopname,shop…..},….]\n\n \n\n### 场景2\n\n在管理员使用的管理系统中,管理员需要查看各个商家上架的商品。同时,普通用户也需要查看某个商家店铺内的所有商品。因此,需要一个获取某商家全部商品列表的接口。接口需要传入shopid,接口返回该shop内所有商品的列表。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6949.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_3_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695A.tmp.jpg) \n\n测试数据:\n\nshopid=[006e0aca-0aae-11e7-ab6a-00ac2794c53f]()\n\n本接口没有设置映射,默认映射按照数据库表定义进行字段的映射。\n\nsql语句中存在一个变量${shopid},所以在query的第二个参数中构造了一个包含shopid的对象。如果context中包含该字段可以直接传入context作为query函数的第二个参数。\n\n \n\n### 场景3\n\n在管理员的管理界面中,需要以一个商家商品树,列出全部商家和商家下的全部商品,并显示在easyui的tree中。对于sp_shop表仅需要字段 shopid、shopname,对于商品表sp_good仅需要goodid,goodname即可。返回的json格式应满足easyui中的tree的输入格式。\n\n \n\ntree的输入格式\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695B.tmp.jpg) \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695C.tmp.jpg) \n\n[jsweb代码:详见jsapis]()/jsons/case2_3_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696D.tmp.jpg) \n\n输出的部分结果:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696E.tmp.jpg) \n\n### 场景4\n\n管理员或者某商店用户查看所有或者商店对应的商品时,后台easyui框架中通常是使用分页,而不是直接把所有的数据展示出来。接口需要传入两个参数,page和rows。page代表当前是第几页,rows代表每页显示的行数。返回的json格式为rows:当前页的数据,total:一共多少行。\n\n \n\n结果的返回格式:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697E.tmp.jpg) \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697F.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_3_4.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6990.tmp.jpg) \n\n \n\n### 场景5\n\n基于实体关系的查询,使用实体关系查询不需要自己写sql语句,基本的查询语句这样写,首先需要调用dbcontext()方法,然后调用其query方法,参数为数据库名或结构化字符串,然后调用buildsqlquery()方法,最后在query方法中传入buildsqlquery()方法返回值对应的两个参数即可。对于场景1,显示全部的属性,使用实体关系查询。\n\n \n\njsweb代码:详见jsapis/jsons/case2_3_5.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6991.tmp.jpg) \n\n.buildsqlquery()方法返回了其创建的映射关系q.mappingstr,若想使用自己的映射关系将q.mappingstr改为自己想要的映射关系即可。\n\n \n\n### 场景6\n\n基于场景2,管理员查看某个商家的商品,然后管理员还想要通过商品名进行检索,比如商品产地为沈阳(商品产地为商品名第一项),这种时候书写sql语句就需要使用like关键词。使用实体关系查询就需要使用.filter()方法和.search()方法,具体使用方法见[2.2.12](#_2.2.12_dber/dberjs函数库)。\n\n \n\n[jsweb代码:详见jsapis]()/jsons/case2_3_6.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6992.tmp.jpg) \n\n测试数据:\n\nshopid=006e0aca-0aae-11e7-ab6a-00ac2794c53f\n\nkeyword=沈阳\n\n \n\n### 场景7\n\n项目上线后,商城的主页会经常被访问,为了提高性能可以使用内存数据库查询,具体介绍见[2.2.11](#_2.2.11_redissql函数库)。\n\n \n\njsweb代码:详见jsapis/jsons/case2_3_7.js\n\n \n\n \n\n \n\n \n\n \n\n## 3.2 基本sql操作\n\n数据库操作(插入、更新、删除)在传统的web项目中同样也是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。\n\n \n\n数据库介绍和配置同2.3。\n\n \n\n### 场景1\n\n商家需要管理他们商店的商品,首先是上线新的商品,这里就需要向数据库表sp_good表中插入一条数据,需要的字段有goodid、goodname、[gooddetaildescription]()、goodminprice、goodmaxprice、shopid等。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A3.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A4.tmp.jpg) \n\n测试数据:\n\ngoodname:‘大连|樱桃’、[gooddetaildescription]():‘大连大樱桃’、gooddetaildescription:15、\n\ngoodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、\n\ngoodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、\n\ngoodisputway:2017-5-31、goodisremind:1\n\n返回的是true或false,成功为true,失败为false。\n\n \n\n### 场景2\n\n在一段时间后,商家可能需要修改商品信息,比如修改商品详情,这样情况下需要修改产品表中的数据。比如根据goodid修改gooddetaildescription字段。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B4.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B5.tmp.jpg) \n\n测试数据:\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\ngooddetaildescription:’大连大樱桃,好吃又便宜’\n\n \n\n### 场景3\n\n商家管理商品,当商家不在卖某个商品时,需要将其删除,根据这个商品的id将其在数据库表中删除。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C6.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_4_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C7.tmp.jpg) \n\n测试数据:\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\n \n\n### 场景4\n\n使用实体关系向表中插入数据。方法为insertentity()方法,参数为:第一个为表名、第二个为参数。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_4_4.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C8.tmp.jpg) \n\n测试数据:\n\ngoodname:‘大连|樱桃’、gooddetaildescription:‘大连大樱桃’、gooddetaildescription:15、\n\ngoodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、\n\ngoodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、\n\ngoodisputway:2017-5-31、goodisremind:1\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D8.tmp.jpg) \n\n \n\n### 场景5\n\n[使用实体关系更新数据库表中的数据](),方法为updateentity(),参数为:第一个为表名、第二个为参数,第三个为更新的条件。\n\n \n\n[jsweb代码:详见]()jsapis/jsons/case_2_4_5.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D9.tmp.jpg) \n\n[测试数据]():\n\ngoodid: f539819c-45cf-11e7-9b1c-38d547ab4abf\n\ngooddetaildescription:’大连大樱桃,好吃又便宜’\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EA.tmp.jpg) \n\n \n\n### 场景6\n\n使用实体关系删除数据库表中的数据,方法为updateentity(),参数为:第一个为表名、第二个为实体(删除数据的依据,主要是id),第三个为更新的条件(可不填)。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_4_6.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EB.tmp.jpg) \n\n测试数据:\n\ngoodname:\"大连|樱桃\";\n\ngooddetaildescription:\"大连大樱桃\";\n\ngoodminprice:\"15\";\n\ngoodmaxprice:\"20\";\n\ngoodcreator:\"lirf\";\n\ngoodcategory:\"水果\";\n\nshopid:\"ff45459f-45d3-11e7-9b1c-38d547ab4abf\";\n\ngoodid:\"ff45459f-45d3-11e7-9b1c-38d547ab4abf\";\n\ngoodorder:\"1\";\n\ngoodisputway:\"1\";\n\ngoodproducedate:\"2017-5-31\";\n\ngoodisremind:\"1\";\n\n返回的是json格式,执行结果(true|false)和执行的sql语句。\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FC.tmp.jpg) \n\n## 3.3 sql事务操作\n\n在对数据库进行插入、更新、删除等操作时,经常遇到同时执行多条sql语句的情况,这种情况下就需要使用事务操作。在mybatis中支持事务操作,只需要在方法前加上注解就可以,在JSWEB框架中,事务操作有其特定的方法,下面来看几个例子。\n\n \n\n### 场景1\n\n用户提交订单之后进行支付,支付完成之后需要将订单状态改为已支付,同时需要在支付记录中插入一条新的数据。这种情况下需要使用事务来完成,在框架中使用multiexec()方法来完成,具体的参数及使用方法见[2.2.10](#_2.2.10_sqlbase函数库)。\n\n \n\nsql语句:\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FD.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case_2_5_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FE.tmp.jpg) \n\n测试数据:\n\norderpayedprice:100\n\nordernumber:CP1704281613263536\n\n \n\n### 场景2\n\n场景同上,使用实体关系进行事务操作,需要用到的方法为multideleteentity()、multiupdateentity()、multiinsertentity(),详情见[2.2.12](#_2.2.12_dber/dberjs函数库)。\n\n \n\njsweb代码:详见jsapis/jsons/case_2_5_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0E.tmp.jpg) \n\n \n\n## 3.4 实体关系查询\n\n在前面介绍了实体关系查询的基本用法,但是实体关系查询最实用的是当两个或多个表关联查询时可以用比较少的代码来实现。下边来看几个场景。\n\n### 场景1\n\n在管理员的管理界面中,需要列出全部商家和商家下的全部商品,并显示在easyui中。通过实体关系查询可以查询出所有店铺的所有商品,还可以使用filter()或search()方法进行条件筛选。\n\n \n\n使用实体关系关联查询首先需要shunfengdb.js文件中写配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0F.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_1.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A20.tmp.jpg) \n\n### 场景2\n\n在前台微信端页面,当用户点进一个商品的详情页之后需要查询该商品的详细信息,包括品类、图片、代理配置以及拥有的规格等信息,这些信息分别存在四个表中,如果写连接查询的sql语句会比较复杂,如果用实体关系查询就非常简单。\n\n \n\n首先shunfengdb.js文件中的配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A21.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_2.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A32.tmp.jpg) \n\n部分结果如下如所示\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A33.tmp.jpg) \n\n### 场景3\n\n在前台微信端页面,当用户提交订单信息时可能需要根据规格去查询商品信息以及该商品对应的店铺信息,这种情况下也可以使用实体关系查询。\n\n \n\n首先shunfengdb.js文件中的配置语句\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A43.tmp.jpg) \n\njsweb代码:详见jsapis/jsons/case2_6_3.js\n\n![img](http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A44.tmp.jpg) ","slug":"JsWeb框架手册","published":1,"updated":"2018-03-10T11:15:30.759Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k5b0001wsv7kz6b5og5","content":"<h1 id=\"第一章-创建工程\"><a href=\"#第一章-创建工程\" class=\"headerlink\" title=\"第一章 创建工程\"></a>第一章 创建工程</h1><h2 id=\"1-1-创建工程\"><a href=\"#1-1-创建工程\" class=\"headerlink\" title=\"1.1 创建工程\"></a>1.1 创建工程</h2><p>工程得创建分为两种方式:第一种,从空工程开始创建。第二种,通过intellij idea得项目模板来创建。使用第二种方式创建得时候需要使用网络,由于idea得服务器在国外,所以速度相对比较慢。本节介绍的是第一种方法。</p>\n<p>第一种方法所需的条件:1.类库文件,2.JsWeb框架的js服务端类库。这些文件在公司的资料共享服务器中。</p>\n<p>文件-新建-工程,不要选任何选项,点击下一步。创建一个普通的java工程。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685C.tmp.jpg\" alt=\"img\"> </p>\n<p>输入工程名字</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685D.tmp.jpg\" alt=\"img\"> </p>\n<p>新建完成后工程目录如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686D.tmp.jpg\" alt=\"img\"> </p>\n<p>创建一个lib目录</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686E.tmp.jpg\" alt=\"img\"> </p>\n<p>将类库文件复制到工程中</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686F.tmp.jpg\" alt=\"img\"> </p>\n<p>复制完成后,右键add as library</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6880.tmp.jpg\" alt=\"img\"> </p>\n<p>Library的名字和文件夹的名字保持一致。</p>\n<p>添加完成后,打开工程属性</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6881.tmp.jpg\" alt=\"img\"> </p>\n<p>打开工程属性 添加 facets,选择spring,然后选择web,点击 create artifact</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6892.tmp.jpg\" alt=\"img\"> </p>\n<p>将工程右侧的libraries都添加到左侧output目录里面,如下图</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6893.tmp.jpg\" alt=\"img\"> </p>\n<p>Problems的数量为0.</p>\n<p>目前,IDE应该已经自动创建了Web目录和Web.xml文件。</p>\n<p>将 配置文件和js类库文件复制到工程中</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A3.tmp.jpg\" alt=\"img\"> </p>\n<p>复制完成后如下图:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A4.tmp.jpg\" alt=\"img\"> </p>\n<p>将JspPageController类复制到Src目录下的如下位置,若包不存在请创建</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A5.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"1-2-工程配置\"><a href=\"#1-2-工程配置\" class=\"headerlink\" title=\"1.2 工程配置\"></a>1.2 工程配置</h2><p>在JSAPI.xml文件中 进行项目的配置</p>\n<p>连接字符串的配置:</p>\n<p>修改driverclassname,jdbcurl,username,password 默认线程池大小:最小10,最大100</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68B6.tmp.jpg\" alt=\"img\"> </p>\n<p>常见配置方案:</p>\n<ol>\n<li><p>MySql</p>\n</li>\n<li><p>Oracle</p>\n</li>\n<li><p>SqlServer</p>\n</li>\n</ol>\n<p>Jsweb扫描器:</p>\n<p>配置js服务接口根目录</p>\n<p>配置js服务端类库跟目录</p>\n<p>配置js服务端自定义类库跟目录</p>\n<p>配置licensekey</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68C6.tmp.jpg\" alt=\"img\"> </p>\n<p>映射和拦截器:</p>\n<p>Jsweb接口的基础路径是 /jsons 所有/jsons/*.form的请求都会由jsapicontroller来处理。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D7.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"1-3-工程结构\"><a href=\"#1-3-工程结构\" class=\"headerlink\" title=\"1.3 工程结构\"></a>1.3 工程结构</h2><p>工程建立完成后目录结构如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D8.tmp.jpg\" alt=\"img\"> </p>\n<p>src文件夹用于存放java代码文件</p>\n<p>jsapis用于存放jsweb的服务端接口文件</p>\n<p>jscustomlibs 用于存放与当前工程相关的函数库文件</p>\n<p>jslibs 用于存放通用函数库文件</p>\n<p>pages用于存放jsp文件</p>\n<p>web目录下用于存放网站的静态资源</p>\n<p>applicationContext.xml 为工程中的spring配置文件</p>\n<p>dispatcher-servlet.xml 为系统spring配置文件</p>\n<p>jsapi.xml jsweb配置文件</p>\n<p>web.xml web配置文件</p>\n<h1 id=\"第二章-JsWeb框架的简单介绍\"><a href=\"#第二章-JsWeb框架的简单介绍\" class=\"headerlink\" title=\"第二章 JsWeb框架的简单介绍\"></a>第二章 JsWeb框架的简单介绍</h1><h2 id=\"2-1-框架的工作原理\"><a href=\"#2-1-框架的工作原理\" class=\"headerlink\" title=\"2.1 框架的工作原理\"></a>2.1 框架的工作原理</h2><p>目前项目的开发框架为:Spring+SpringMVC+JsWeb框架。JsWeb框架本身依赖于Spring 和 Spring MVC框架。框架本身兼容其他第三方框架,JsWeb框架通过Controller与Spring MVC项目相结合,通过实现Controller接口从Spring MVC获取Request、Repsonse、ModelAndView、SevletSession等对象。JsApiController通过调用编译后的JS对请求进行处理。工作原理如图2-1。框架本身是基于SpringMVC框架扩展,与其他框架不产生冲突。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68E9.tmp.png\" alt=\"img\"></p>\n<p>图2-1 JsWeb框架工作原理图</p>\n<p>为了能快速的开发服务端接口,开发了JSWEB框架——一个可以使用javascript脚本来开发服务端数据接口的框架。</p>\n<h3 id=\"框架优势\"><a href=\"#框架优势\" class=\"headerlink\" title=\"框架优势\"></a>框架优势</h3><p>JSWEB框架相比传统的Java服务端框架具有以下优势:</p>\n<ul>\n<li>无model层,当数据库发生变更时无需重新写model类,而对于某些返回数据(由表链接产生,不存在于model层)无需创建大量的model类。</li>\n<li>基于实体关系的sql生成类库,可动态生成sql。使用类似于mongodb的语法 操纵表连接查询,无需创建大量视图,无惧数据库字段增加删除更改。</li>\n<li>可直接操作WEB底层(Session,Request,Response,Header,Status等)</li>\n<li>可灵活扩展第三方插件(支付、快递、短信、邮件等)</li>\n</ul>\n<h2 id=\"2-2-框架功能介绍\"><a href=\"#2-2-框架功能介绍\" class=\"headerlink\" title=\"2.2 框架功能介绍\"></a>2.2 框架功能介绍</h2><p>框架针对Web开发中所遇到的各类问题,封装了相应的函数。下面简单介绍下各个函数库中各个函数库中函数的功能。</p>\n<h3 id=\"2-2-1-codec函数库\"><a href=\"#2-2-1-codec函数库\" class=\"headerlink\" title=\"2.2.1 codec函数库\"></a>2.2.1 codec函数库</h3><p>codec函数库用于做字符串编码,目前函数库里的函数主要用于生成字符串的摘要。主要应用于密码保存。主要函数及功能见表2-1。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>md5hex</td>\n<td>求解字符串的MD5值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha1hex</td>\n<td>求解字符串的sha1值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha256hex</td>\n<td>求解字符串的sha256值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha384hex</td>\n<td>求解字符串的sha384值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha512hex</td>\n<td>求解字符串的sha512值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n</tbody>\n</table>\n<p>表2-1 codec函数库的主要函数</p>\n<h3 id=\"2-2-2-email函数库\"><a href=\"#2-2-2-email函数库\" class=\"headerlink\" title=\"2.2.2 email函数库\"></a>2.2.2 email函数库</h3><p>email函数库用于邮件的发送和读取。函数库可应用于项目中的用户注册、用户激活账户、邮件找回密码、消息通知、广告推广等模块。主要函数及功能见表2-2。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>sendhtmlmail</td>\n<td>发送html富文本邮件</td>\n<td>1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(html)11.attachementFiles 附件列表(文件地址列表)</td>\n</tr>\n<tr>\n<td>sendtextmail</td>\n<td>发送纯文本邮件</td>\n<td>1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(文本)11.attachementFiles 附件列表(文件地址列表)</td>\n</tr>\n</tbody>\n</table>\n<p>表2-2 email函数库的主要函数</p>\n<h3 id=\"2-2-3-fileutils函数库\"><a href=\"#2-2-3-fileutils函数库\" class=\"headerlink\" title=\"2.2.3 fileutils函数库\"></a>2.2.3 fileutils函数库</h3><p>fileutils函数库用于文件操作。函数库可以用于管理服务器端的文件,比如清理用户上传的临时文件。也可以读取服务器端的文本文件。主要函数及功能见表2-3。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>createfile</td>\n<td>创建文件</td>\n<td>1. filepath 需要创建的文件的路径,绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>listfiles</td>\n<td>列出目录下的所有文件</td>\n<td>1.dir 目录的绝对路径return 字符串列表,用于保存目录下所有文件的数组</td>\n</tr>\n<tr>\n<td>listfileitems</td>\n<td>列出目录下的所有文件,包括文件属性</td>\n<td>1.dir目录的绝对路径return 目录下的所有文件的列表,列表中保存了每个文件的详细信息。</td>\n</tr>\n<tr>\n<td>searchFiles</td>\n<td>搜索目录下的文件,包括子目录</td>\n<td>1.dir目录的绝对路径2.keyword 搜素关键字return 字符串列表,用于保存目录下所有文件的数组</td>\n</tr>\n<tr>\n<td>mkdir</td>\n<td>创建目录</td>\n<td>1.dir目录的绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>deletefile</td>\n<td>删除文件或文件夹</td>\n<td>1. fileordir文件或目录的绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>readfile</td>\n<td>读取文本文件的内容</td>\n<td>1. filepath需要读取的文件的绝对路径2.encoding 文件的编码,默认为utf-8return 文件中的文本内容</td>\n</tr>\n<tr>\n<td>writefile</td>\n<td>将文本写入文本文件</td>\n<td>1. filepath需要读取的文件的绝对路径2.content 要写入的文件内容3.encoding 文件的编码,默认为utf-8return true/false 成功/失败</td>\n</tr>\n</tbody>\n</table>\n<p>表2-3 fileutils函数库的主要函数</p>\n<h3 id=\"2-2-4-image函数库\"><a href=\"#2-2-4-image函数库\" class=\"headerlink\" title=\"2.2.4 image函数库\"></a>2.2.4 image函数库</h3><p>image函数库用于图像处理相关的应用,基本功能包括生成数字验证码。图片调整大小,获取图片的大小等。主要函数及功能见表2-4。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>generatenumbercheckcode</td>\n<td>生成4位数验证码</td>\n<td>1.context jsweb上下文2.sessionkey 存储验证码的session字段return 生成的4位数字验证码</td>\n</tr>\n<tr>\n<td>resizeimage2file</td>\n<td>将图片进行缩放操作,输出到本地文件</td>\n<td>1.imagefilepath 图片文件的路径2.targetfilepath目标文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>resizeimage2response</td>\n<td>将图片进行缩放操作,输出到response</td>\n<td>1.context jsweb上下文2.imagefilepath 图片文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>imagesize</td>\n<td>获取图片得大小</td>\n<td>1. imagepath 图片文件的路径return 图片的大小{w,h}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-4 image函数库的主要函数</p>\n<h3 id=\"2-2-5-net函数库\"><a href=\"#2-2-5-net函数库\" class=\"headerlink\" title=\"2.2.5 net函数库\"></a>2.2.5 net函数库</h3><p>net函数库中包含了与网络相关的函数,函数库的功能包括两大类:1.负责给用户端提供上传、下载服务。2.给其他服务端发送get/post请求。主要函数及功能见表2-5。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>uploadfileserver</td>\n<td>文件上传服务</td>\n<td>1.context jsweb上下文2.path 上传文件保存位置3.isrelative 是否是相对路径</td>\n</tr>\n<tr>\n<td>downloadfileserver</td>\n<td>文件下载服务</td>\n<td>1.context jsweb上下文2.targetfilepath要下载的文件的路径3.isrelative 路径是否是相对路径4.浏览器下载时的文件名5.输出的content-type</td>\n</tr>\n<tr>\n<td>postform</td>\n<td>post form数据到某url</td>\n<td>1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>poststring</td>\n<td>post string数据到某url</td>\n<td>1.url 远程服务端接口url2.str 要发送的字符串3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>postfile</td>\n<td>post 文件到远程服务器</td>\n<td></td>\n</tr>\n<tr>\n<td>getform</td>\n<td>get 数据从某url</td>\n<td>1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>downloadfile</td>\n<td>下载远程服务器上的文件</td>\n<td>1.url 远程文件的url2.method 下载方法get/post3.formdata 发送的form数据4.headers http头,格式为keyvalue5.encoding 发送和接收编码,默认为utf-86.targetfilepath 保存在本地的文件路径,绝对路径return 返回{status,content,responseduration}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-5 net函数库的主要函数</p>\n<h3 id=\"2-2-6-runtime函数库\"><a href=\"#2-2-6-runtime函数库\" class=\"headerlink\" title=\"2.2.6 runtime函数库\"></a>2.2.6 runtime函数库</h3><p>runtime函数库中,包含了与运行时相关的函数。主要函数及功能见表2-6。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>rumtimeexec</td>\n<td>执行本地可执行文件</td>\n<td>1.path 可执行文件的路径2.startuppath 执行的开始目录</td>\n</tr>\n<tr>\n<td>runinbackground</td>\n<td>创建一个新线程执行一个任务。线程从线程池中创建,如果线程池使用枯竭,则需要等待空闲线程。</td>\n<td>1.context jsweb上下文2.apiname 要执行的任务的api名称</td>\n</tr>\n<tr>\n<td>sleep</td>\n<td>睡眠,停止当前线程一定时间。</td>\n<td>1.miliseconds 睡眠的毫秒数</td>\n</tr>\n</tbody>\n</table>\n<p>表2-6 runtime函数库的主要函数</p>\n<h3 id=\"2-2-7-servlet函数库\"><a href=\"#2-2-7-servlet函数库\" class=\"headerlink\" title=\"2.2.7 servlet函数库\"></a>2.2.7 servlet函数库</h3><p>servlet函数库中包含了与request、response、session相关的处理函数。主要函数及功能见表2-7。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>httpstatus</td>\n<td>设置response的状态值</td>\n<td>1.context jsweb上下文2.status 状态码,数值类型</td>\n</tr>\n<tr>\n<td>contenttype</td>\n<td>设置response的相应内容</td>\n<td>1.context jsweb上下文2.contenttype0 content-type</td>\n</tr>\n<tr>\n<td>setsession</td>\n<td>设置session的值</td>\n<td>1.context jsweb上下文2.key session的键3.value session的值</td>\n</tr>\n<tr>\n<td>getsession</td>\n<td>获取session的值</td>\n<td>1.context jsweb上下文2.key session的键return session的值</td>\n</tr>\n<tr>\n<td>setheader</td>\n<td>设置header的值</td>\n<td>1.context jsweb上下文2.key session的键3.value header的值</td>\n</tr>\n<tr>\n<td>redirect</td>\n<td>访问重定向</td>\n<td>1.context jsweb上下文2.url 重定向的url地址</td>\n</tr>\n<tr>\n<td>getheader</td>\n<td>获取header的值</td>\n<td>1.context jsweb上下文2.key session的键</td>\n</tr>\n<tr>\n<td>setcontenttype</td>\n<td>设置response的相应内容</td>\n<td>1.context jsweb上下文2.contenttype0 content-type</td>\n</tr>\n<tr>\n<td>setview</td>\n<td>设置modelandview中的view</td>\n<td>1.context jsweb上下文2.viewname 视图路径,和spring设置方法一致</td>\n</tr>\n<tr>\n<td>rootphysicpath</td>\n<td>获取网站的绝对路径</td>\n<td>1.context jsweb上下文2.path 网站根目录的相对路径return 字符串,绝对路径</td>\n</tr>\n<tr>\n<td>contextpath</td>\n<td>获取contextpath</td>\n<td>1.context jsweb上下文return 字符串,访问的contextpath</td>\n</tr>\n<tr>\n<td>writeresponsestream</td>\n<td>写入response输出流</td>\n<td>1.context jsweb上下文2.inputstream 输入流return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>getresponse</td>\n<td>获取response对象</td>\n<td>1.context jsweb上下文return response</td>\n</tr>\n<tr>\n<td>getresponsestream</td>\n<td>获取response输出流</td>\n<td>1.context jsweb上下文return outputstream</td>\n</tr>\n<tr>\n<td>setresponsefilename</td>\n<td>设置response中输出的文件名</td>\n<td>1.context jsweb上下文2.filename 输出显示的文件名</td>\n</tr>\n<tr>\n<td>getmethod</td>\n<td>获取当前访问的方式</td>\n<td>1.context jsweb上下文return 字符串,get/set</td>\n</tr>\n</tbody>\n</table>\n<p>表2-7 servlet函数库的主要函数</p>\n<h3 id=\"2-2-8-utils函数库\"><a href=\"#2-2-8-utils函数库\" class=\"headerlink\" title=\"2.2.8 utils函数库\"></a>2.2.8 utils函数库</h3><p>utils工具函数库,主要功能为开发中常见的工具,比如uuid、md5、base64、json序列化反序列化、向内存中获取/保存对象,路径合并等。主要函数及功能见表2-8。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>uuid</td>\n<td>生成一个UUID</td>\n<td>无</td>\n</tr>\n<tr>\n<td>md5</td>\n<td>计算输入字符串的md5,输出为base64编码的字符串</td>\n<td>1.input 输入字符串return 返回摘要字符串</td>\n</tr>\n<tr>\n<td>base64</td>\n<td>base64编码函数</td>\n<td>1.input 输入字符串return 编码后的字符串</td>\n</tr>\n<tr>\n<td>jsonStringify</td>\n<td>对象的json序列化</td>\n<td>1.obj 要进行序列化的对象return 序列化之后的json字符串</td>\n</tr>\n<tr>\n<td>jsonParse</td>\n<td>对象反序列化</td>\n<td>1.jsonstr json字符串return 反序列化后的对象</td>\n</tr>\n<tr>\n<td>getmemcache</td>\n<td>获取运行jsweb服务器里面的缓存对象</td>\n<td>1.key 对象的名称return 缓存的对象</td>\n</tr>\n<tr>\n<td>putmemcache</td>\n<td>将对象放入运行jsweb服务器里面的缓存</td>\n<td>1.key 对象的名称2.value 要缓存的对象</td>\n</tr>\n<tr>\n<td>ismemcachecontains</td>\n<td>判断缓存中是否包含对象的名称</td>\n<td>1.key 对象的名称return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>console</td>\n<td>从控制台中输出对象</td>\n<td>1.str 要输出的对象</td>\n</tr>\n<tr>\n<td>threadid</td>\n<td>获取当前线程的线程id</td>\n<td>return 线程id,数字</td>\n</tr>\n<tr>\n<td>createlist</td>\n<td>创建java的list</td>\n<td>return list</td>\n</tr>\n<tr>\n<td>createsafemap</td>\n<td>创建java中的map</td>\n<td>return map</td>\n</tr>\n<tr>\n<td>pathcombine</td>\n<td>合并路径</td>\n<td>无限参数,路径return 合并后的路径</td>\n</tr>\n</tbody>\n</table>\n<p>表2-8 servlet函数库的主要函数</p>\n<h3 id=\"2-2-9-compress函数库\"><a href=\"#2-2-9-compress函数库\" class=\"headerlink\" title=\"2.2.9 compress函数库\"></a>2.2.9 compress函数库</h3><p>compress函数库用于在服务端创建压缩文件。目前功能是可以把文件夹中的文件压缩为一个压缩文件,支持的格式为zip。主要函数及功能见表2-9。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>zipfolder</td>\n<td>将文件夹压缩为一个zip文件,保存到文件</td>\n<td>1.rootfolder 要压缩的根目录2.extlist 后缀列表3.outfile 输出文件的路径</td>\n</tr>\n<tr>\n<td>zipfolder2response</td>\n<td>将文件夹压缩为一个zip文件,输出到response</td>\n<td>1.context jsweb上下文2.rootfolder 要压缩的根目录3.extlist 后缀列表</td>\n</tr>\n</tbody>\n</table>\n<p>表2-9 compress函数库的主要函数</p>\n<p>应用场景:</p>\n<p>1.需要批量下载文件的需求,如:沐诺农场批量下载二维码</p>\n<p>2.需要下载的文件过大或数量过多,如:下载整年的统计表</p>\n<h3 id=\"2-2-10-sqlbase函数库\"><a href=\"#2-2-10-sqlbase函数库\" class=\"headerlink\" title=\"2.2.10 sqlbase函数库\"></a>2.2.10 sqlbase函数库</h3><p>sqlbase函数库中包含了sql查询的基本函数。该函数库是jsweb项目中最重要的函数库,在一个项目中该函数库会被高频的使用。主要的函数及功能见表2-10。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>query</td>\n<td>查询sql并返回查询结果,查询结果为数组</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串return 返回查询结果</td>\n</tr>\n<tr>\n<td>querypagedata</td>\n<td>分页查询sql并返回查询结果,查询结果为数组</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5.pagesize 每页记录的数量return 返回分页查询结果</td>\n</tr>\n<tr>\n<td>multiquery</td>\n<td>查询sql并返回查询结果,查询结果为数组,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文4.mappingstr 映射字符串return 返回查询结果</td>\n</tr>\n<tr>\n<td>exec</td>\n<td>执行sql语句。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>multiexec</td>\n<td>执行sql语句,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>execbatch</td>\n<td>批量执行sql语句。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.datalist 数据列表return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>multiexecbatch</td>\n<td>批量执行sql语句,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.datalist 数据列表return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>createconnection</td>\n<td>创建jdbc连接</td>\n<td>无</td>\n</tr>\n<tr>\n<td>closeconnection</td>\n<td>关闭jdbc连接</td>\n<td>1.con jdbc连接</td>\n</tr>\n<tr>\n<td>commit</td>\n<td>提交连接中的数据</td>\n<td>1.con jdbc连接return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>rollback</td>\n<td>回滚连接中的数据</td>\n<td>1.con jdbc连接return true/false 成功/失败</td>\n</tr>\n</tbody>\n</table>\n<p>表2-10 sqlbase函数库的主要函数</p>\n<h3 id=\"2-2-11-redissql函数库\"><a href=\"#2-2-11-redissql函数库\" class=\"headerlink\" title=\"2.2.11 redissql函数库\"></a>2.2.11 redissql函数库</h3><p>redissql 为利用redis内存数据库,对接口的数据进行缓存,从而提高实时性不高的接口的访问性能。提升后的性能接近静态资源访问速度。主要的函数及功能见表2-11。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>redisquery</td>\n<td>基于redis内存数据的缓存查询。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4. expire 设置超时时间,毫秒return 返回查询结果</td>\n</tr>\n<tr>\n<td>redisquerypagedata</td>\n<td>基于redis内存数据的缓存分页查询。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5. expire 设置超时时间,毫秒return 返回分页查询结果</td>\n</tr>\n</tbody>\n</table>\n<p>表2-11 redissql函数库的主要函数</p>\n<p>应用场景:</p>\n<ol>\n<li>高频且对数据实时性不高的接口,如商城主页的商品列表接口、商品品类接口、商店店铺页面的商品品类和 商品接口。</li>\n</ol>\n<h3 id=\"2-2-12-dber-dberjs函数库\"><a href=\"#2-2-12-dber-dberjs函数库\" class=\"headerlink\" title=\"2.2.12 dber/dberjs函数库\"></a>2.2.12 dber/dberjs函数库</h3><p>dber/dberjs函数库是一个全新的基于实体关系进行数据查询和插入的函数库。与传统的sql不用,基于实体关系的查询根据数据表中预定义的连接关系自动生成查询的sql语句。实体关系查询提供了几种查询源语:query filter search orderby。除了查询功能外还提供基于实体的删除、更新和插入功能。主要的函数及功能见表2-12,2-13。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>dbcontext().query</td>\n<td>根据用户输入的实体结构字符串进行查询</td>\n<td>1.structurestr 实体结构字符串</td>\n</tr>\n<tr>\n<td>dbcontext().<a href=\"\">filter</a></td>\n<td>根据过滤条件进行过滤</td>\n<td>1.filterstr 过滤字符串</td>\n</tr>\n<tr>\n<td>dbcontext().search</td>\n<td>综合搜索,当用户没有提交搜索变量的值的时候不进行该条件搜索,否则进行搜索。通常用于多条件搜索。</td>\n<td>1.varname 搜索变量名2.condition 过滤字符串</td>\n</tr>\n<tr>\n<td>dbcontext().orderby</td>\n<td>排序</td>\n<td>1.orderbystr 排序字符串</td>\n</tr>\n<tr>\n<td>dbcontext().buildsqlquery</td>\n<td>构建sql字符串和映射字符串</td>\n<td>return 返回{sql,mappingstr}</td>\n</tr>\n<tr>\n<td>initmysqldb</td>\n<td>初始化mysql数据库的实体关系</td>\n<td>数据库schema名称</td>\n</tr>\n<tr>\n<td>db.relation</td>\n<td>预定义实体与实体的关系</td>\n<td>1.modelpropertystr 实体属性字符串2.modelconnectorstr 实体连接字符串3.relationtype 实体关系,1:1 1:n</td>\n</tr>\n</tbody>\n</table>\n<p>表2-12 dber函数库的主要函数</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>deleteentity</td>\n<td>删除数据库中实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>updateentity</td>\n<td>更新数据库中的实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertentity</td>\n<td>将实体对象插入数据库</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.isuserpk 是否使用entitydata中的主键,默认为null4. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multideleteentity</td>\n<td>删除数据库中实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiupdateentity</td>\n<td>更新数据库中的实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiinsertentity</td>\n<td>将实体对象插入数据库,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>updateentitybatch</td>\n<td>批量更新实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertentitybatch</td>\n<td>批量插入实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertorupdateentity</td>\n<td>插入或更新实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象return {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiinsertorupdateentity</td>\n<td>插入或更新实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象return {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertorupdateentitybatch</td>\n<td>批量插入或更新实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表return {result,errormessage}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-13 dberjs函数库的主要函数</p>\n<h3 id=\"2-2-13-text函数库\"><a href=\"#2-2-13-text函数库\" class=\"headerlink\" title=\"2.2.13 text函数库\"></a>2.2.13 text函数库</h3><p>text函数库是一个文本计算的科学函数库。主要功能为计算文本之间的相似性,提供多种相似性衡量标准,计算文本的最长公共子串。主要的函数及功能见表2-14。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>textjaccardsimilarity</td>\n<td>计算文本的jaccard相似性</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textlongestcommonsubsequnce</td>\n<td>计算最长公共子串(LCS)</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textlongestcommonsubsequncedistance</td>\n<td>计算最长公共子串相似性</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>texthammingdistance</td>\n<td>计算汉明距离</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textfuzzyscore</td>\n<td>计算模糊值</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n</tbody>\n</table>\n<p>表2-14 text函数库的主要函数</p>\n<p>函数库的可应用场景举例:</p>\n<p>1.在输入提示框中显示提示,如果使用子串搜索方法,用户输入错误将导致提示消失。最相似方法 可以容许一定的错误。</p>\n<p>2.差异比较,比如比较两段文本 完全相同的部分。</p>\n<h3 id=\"2-2-14-velocity函数库\"><a href=\"#2-2-14-velocity函数库\" class=\"headerlink\" title=\"2.2.14 velocity函数库\"></a>2.2.14 velocity函数库</h3><p>velocity函数库的主要功能是提供模板渲染功能,目前渲染的模板引擎是velocity。主要的函数及功能见表2-15。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>velocitytemplate</td>\n<td>将用户输入的模板字符串进行渲染</td>\n<td>1.tempatestr2.paramsreturn 渲染后的字符串</td>\n</tr>\n</tbody>\n</table>\n<p>表2-15 velocity函数库的主要函数</p>\n<p>应用场景举例:</p>\n<ol>\n<li><p>发送验证码短信</p>\n</li>\n<li><p>发送激活账号邮件</p>\n</li>\n<li><p>找回密码邮件/短信</p>\n</li>\n<li><p>业务通知类短信/邮件/微信客服消息</p>\n</li>\n</ol>\n<h3 id=\"2-2-15-excel函数库\"><a href=\"#2-2-15-excel函数库\" class=\"headerlink\" title=\"2.2.15 excel函数库\"></a>2.2.15 excel函数库</h3><p>excel函数库主要功能是提供excel操作的相关函数。目前使用的excel文件操作类库是poi。主要的函数及功能见表2-16。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>exportexceltemplate2file</td>\n<td>导出excel模板文件到指定的路径</td>\n<td>1.datacontext 数据上下文2.templatefilepath excel模板的路径3.outfilepath 输出文件路径</td>\n</tr>\n<tr>\n<td>exportexceltemplate2response</td>\n<td>导出excel模板文件到response</td>\n<td>1.context jsweb上下文2.datacontext 数据上下文3.templatefilepath excel模板的路径4.outfilename 输出文件名</td>\n</tr>\n<tr>\n<td>readexcelrows</td>\n<td>读取excel文件的部分内容</td>\n<td>1.excelfilepath excel文件路径2.sheetindex sheet的index3.column 列号,从0开始4.start 起始行号5.end 终止行号return 数组</td>\n</tr>\n<tr>\n<td>readexcelcolumns</td>\n<td>读取excel文件的部分内容</td>\n<td>1.excelfilepath excel文件路径2.sheetindex sheet的index3.rownumber 行号,从0开始4.start 起始列号5.end 终止列号return 数组</td>\n</tr>\n</tbody>\n</table>\n<p>表2-16 excel函数库的主要函数</p>\n<p>应用场景举例:</p>\n<p>1.导出店铺订单</p>\n<p>2.导出用户列表</p>\n<p>3.批量添加数据</p>\n<p>4.导出统计表,带筛选功能,富文本等</p>\n<h1 id=\"第三章-JsWeb框架的用法\"><a href=\"#第三章-JsWeb框架的用法\" class=\"headerlink\" title=\"第三章 JsWeb框架的用法\"></a>第三章 JsWeb框架的用法</h1><h2 id=\"3-1-基本sql查询\"><a href=\"#3-1-基本sql查询\" class=\"headerlink\" title=\"3.1 基本sql查询\"></a>3.1 基本sql查询</h2><p>数据库查询在传统的web项目中是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。</p>\n<p>数据库:shunfengtest 本地版,在资料中有,在运行本教程中的例子之前需要先部署好数据库。</p>\n<p>设置jsapi.xml文件中的 jdbcUrl为:</p>\n<p>jdbc:mysql://localhost/shunfengtest?allowMultiQueries=true</p>\n<p>shunfengtest数据库简介:shunfengtest数据库是顺丰通服务的数据库,顺丰通系统中包含一个商城系统和一个外卖系统,商城功能中除了正常的商城功能外,还包含一个三级代理功能,即普通用户通过身份认证后,可以代理商家或一二级代理商的商品,当商品通过代理人的分享售卖后,代理人以及代理人的上级可得到代理分红。系统中表sp开头的的是商城的数据表,rs开头的是外卖的数据表,cm是公用数据表,as是代理数据表,ed是快递的数据表,sys是系统数据表。</p>\n<h3 id=\"场景1\"><a href=\"#场景1\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>系统管理员需要管理在商城中注册的商家,所需要获取全部的商家列表。需要显示的数据包括sp_shop表中的 shopname、shopimg、shopshortdescription、shopownername、商店所在的省市区字符串和详细地址。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6909.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_3_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps690A.tmp.jpg\" alt=\"img\"> </p>\n<p>返回的是json数组。</p>\n<p>如果sql语句是多行的 ,用“”或‘’则比较麻烦。可以用函数注释方法进行多行字符串输入。(仅限sqlbase函数库)。</p>\n<p>当查询无参数且无需改变默认映射的时候,后面两个参数可以省略。</p>\n<p>[{shopid,shopname,shop…..}, {shopid,shopname,shop…..},….]</p>\n<h3 id=\"场景2\"><a href=\"#场景2\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在管理员使用的管理系统中,管理员需要查看各个商家上架的商品。同时,普通用户也需要查看某个商家店铺内的所有商品。因此,需要一个获取某商家全部商品列表的接口。接口需要传入shopid,接口返回该shop内所有商品的列表。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6949.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695A.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>shopid=<a href=\"\">006e0aca-0aae-11e7-ab6a-00ac2794c53f</a></p>\n<p>本接口没有设置映射,默认映射按照数据库表定义进行字段的映射。</p>\n<p>sql语句中存在一个变量${shopid},所以在query的第二个参数中构造了一个包含shopid的对象。如果context中包含该字段可以直接传入context作为query函数的第二个参数。</p>\n<h3 id=\"场景3\"><a href=\"#场景3\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>在管理员的管理界面中,需要以一个商家商品树,列出全部商家和商家下的全部商品,并显示在easyui的tree中。对于sp_shop表仅需要字段 shopid、shopname,对于商品表sp_good仅需要goodid,goodname即可。返回的json格式应满足easyui中的tree的输入格式。</p>\n<p>tree的输入格式</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695B.tmp.jpg\" alt=\"img\"> </p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695C.tmp.jpg\" alt=\"img\"> </p>\n<p><a href=\"\">jsweb代码:详见jsapis</a>/jsons/case2_3_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696D.tmp.jpg\" alt=\"img\"> </p>\n<p>输出的部分结果:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696E.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景4\"><a href=\"#场景4\" class=\"headerlink\" title=\"场景4\"></a>场景4</h3><p>管理员或者某商店用户查看所有或者商店对应的商品时,后台easyui框架中通常是使用分页,而不是直接把所有的数据展示出来。接口需要传入两个参数,page和rows。page代表当前是第几页,rows代表每页显示的行数。返回的json格式为rows:当前页的数据,total:一共多少行。</p>\n<p>结果的返回格式:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697E.tmp.jpg\" alt=\"img\"> </p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697F.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_4.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6990.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景5\"><a href=\"#场景5\" class=\"headerlink\" title=\"场景5\"></a>场景5</h3><p>基于实体关系的查询,使用实体关系查询不需要自己写sql语句,基本的查询语句这样写,首先需要调用dbcontext()方法,然后调用其query方法,参数为数据库名或结构化字符串,然后调用buildsqlquery()方法,最后在query方法中传入buildsqlquery()方法返回值对应的两个参数即可。对于场景1,显示全部的属性,使用实体关系查询。</p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_5.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6991.tmp.jpg\" alt=\"img\"> </p>\n<p>.buildsqlquery()方法返回了其创建的映射关系q.mappingstr,若想使用自己的映射关系将q.mappingstr改为自己想要的映射关系即可。</p>\n<h3 id=\"场景6\"><a href=\"#场景6\" class=\"headerlink\" title=\"场景6\"></a>场景6</h3><p>基于场景2,管理员查看某个商家的商品,然后管理员还想要通过商品名进行检索,比如商品产地为沈阳(商品产地为商品名第一项),这种时候书写sql语句就需要使用like关键词。使用实体关系查询就需要使用.filter()方法和.search()方法,具体使用方法见<a href=\"#_2.2.12_dber/dberjs函数库\">2.2.12</a>。</p>\n<p><a href=\"\">jsweb代码:详见jsapis</a>/jsons/case2_3_6.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6992.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>shopid=006e0aca-0aae-11e7-ab6a-00ac2794c53f</p>\n<p>keyword=沈阳</p>\n<h3 id=\"场景7\"><a href=\"#场景7\" class=\"headerlink\" title=\"场景7\"></a>场景7</h3><p>项目上线后,商城的主页会经常被访问,为了提高性能可以使用内存数据库查询,具体介绍见<a href=\"#_2.2.11_redissql函数库\">2.2.11</a>。</p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_7.js</p>\n<h2 id=\"3-2-基本sql操作\"><a href=\"#3-2-基本sql操作\" class=\"headerlink\" title=\"3.2 基本sql操作\"></a>3.2 基本sql操作</h2><p>数据库操作(插入、更新、删除)在传统的web项目中同样也是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。</p>\n<p>数据库介绍和配置同2.3。</p>\n<h3 id=\"场景1-1\"><a href=\"#场景1-1\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>商家需要管理他们商店的商品,首先是上线新的商品,这里就需要向数据库表sp_good表中插入一条数据,需要的字段有goodid、goodname、<a href=\"\">gooddetaildescription</a>、goodminprice、goodmaxprice、shopid等。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A3.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A4.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:‘大连|樱桃’、<a href=\"\">gooddetaildescription</a>:‘大连大樱桃’、gooddetaildescription:15、</p>\n<p>goodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、</p>\n<p>goodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、</p>\n<p>goodisputway:2017-5-31、goodisremind:1</p>\n<p>返回的是true或false,成功为true,失败为false。</p>\n<h3 id=\"场景2-1\"><a href=\"#场景2-1\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在一段时间后,商家可能需要修改商品信息,比如修改商品详情,这样情况下需要修改产品表中的数据。比如根据goodid修改gooddetaildescription字段。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B4.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B5.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<p>gooddetaildescription:’大连大樱桃,好吃又便宜’</p>\n<h3 id=\"场景3-1\"><a href=\"#场景3-1\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>商家管理商品,当商家不在卖某个商品时,需要将其删除,根据这个商品的id将其在数据库表中删除。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C6.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C7.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<h3 id=\"场景4-1\"><a href=\"#场景4-1\" class=\"headerlink\" title=\"场景4\"></a>场景4</h3><p>使用实体关系向表中插入数据。方法为insertentity()方法,参数为:第一个为表名、第二个为参数。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_4.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C8.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:‘大连|樱桃’、gooddetaildescription:‘大连大樱桃’、gooddetaildescription:15、</p>\n<p>goodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、</p>\n<p>goodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、</p>\n<p>goodisputway:2017-5-31、goodisremind:1</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D8.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景5-1\"><a href=\"#场景5-1\" class=\"headerlink\" title=\"场景5\"></a>场景5</h3><p><a href=\"\">使用实体关系更新数据库表中的数据</a>,方法为updateentity(),参数为:第一个为表名、第二个为参数,第三个为更新的条件。</p>\n<p><a href=\"\">jsweb代码:详见</a>jsapis/jsons/case_2_4_5.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D9.tmp.jpg\" alt=\"img\"> </p>\n<p><a href=\"\">测试数据</a>:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<p>gooddetaildescription:’大连大樱桃,好吃又便宜’</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EA.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景6-1\"><a href=\"#场景6-1\" class=\"headerlink\" title=\"场景6\"></a>场景6</h3><p>使用实体关系删除数据库表中的数据,方法为updateentity(),参数为:第一个为表名、第二个为实体(删除数据的依据,主要是id),第三个为更新的条件(可不填)。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_6.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EB.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:”大连|樱桃”;</p>\n<p>gooddetaildescription:”大连大樱桃”;</p>\n<p>goodminprice:”15”;</p>\n<p>goodmaxprice:”20”;</p>\n<p>goodcreator:”lirf”;</p>\n<p>goodcategory:”水果”;</p>\n<p>shopid:”ff45459f-45d3-11e7-9b1c-38d547ab4abf”;</p>\n<p>goodid:”ff45459f-45d3-11e7-9b1c-38d547ab4abf”;</p>\n<p>goodorder:”1”;</p>\n<p>goodisputway:”1”;</p>\n<p>goodproducedate:”2017-5-31”;</p>\n<p>goodisremind:”1”;</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FC.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"3-3-sql事务操作\"><a href=\"#3-3-sql事务操作\" class=\"headerlink\" title=\"3.3 sql事务操作\"></a>3.3 sql事务操作</h2><p>在对数据库进行插入、更新、删除等操作时,经常遇到同时执行多条sql语句的情况,这种情况下就需要使用事务操作。在mybatis中支持事务操作,只需要在方法前加上注解就可以,在JSWEB框架中,事务操作有其特定的方法,下面来看几个例子。</p>\n<h3 id=\"场景1-2\"><a href=\"#场景1-2\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>用户提交订单之后进行支付,支付完成之后需要将订单状态改为已支付,同时需要在支付记录中插入一条新的数据。这种情况下需要使用事务来完成,在框架中使用multiexec()方法来完成,具体的参数及使用方法见<a href=\"#_2.2.10_sqlbase函数库\">2.2.10</a>。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FD.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_5_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FE.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>orderpayedprice:100</p>\n<p>ordernumber:CP1704281613263536</p>\n<h3 id=\"场景2-2\"><a href=\"#场景2-2\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>场景同上,使用实体关系进行事务操作,需要用到的方法为multideleteentity()、multiupdateentity()、multiinsertentity(),详情见<a href=\"#_2.2.12_dber/dberjs函数库\">2.2.12</a>。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_5_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0E.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"3-4-实体关系查询\"><a href=\"#3-4-实体关系查询\" class=\"headerlink\" title=\"3.4 实体关系查询\"></a>3.4 实体关系查询</h2><p>在前面介绍了实体关系查询的基本用法,但是实体关系查询最实用的是当两个或多个表关联查询时可以用比较少的代码来实现。下边来看几个场景。</p>\n<h3 id=\"场景1-3\"><a href=\"#场景1-3\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>在管理员的管理界面中,需要列出全部商家和商家下的全部商品,并显示在easyui中。通过实体关系查询可以查询出所有店铺的所有商品,还可以使用filter()或search()方法进行条件筛选。</p>\n<p>使用实体关系关联查询首先需要shunfengdb.js文件中写配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0F.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A20.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景2-3\"><a href=\"#场景2-3\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在前台微信端页面,当用户点进一个商品的详情页之后需要查询该商品的详细信息,包括品类、图片、代理配置以及拥有的规格等信息,这些信息分别存在四个表中,如果写连接查询的sql语句会比较复杂,如果用实体关系查询就非常简单。</p>\n<p>首先shunfengdb.js文件中的配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A21.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A32.tmp.jpg\" alt=\"img\"> </p>\n<p>部分结果如下如所示</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A33.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景3-2\"><a href=\"#场景3-2\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>在前台微信端页面,当用户提交订单信息时可能需要根据规格去查询商品信息以及该商品对应的店铺信息,这种情况下也可以使用实体关系查询。</p>\n<p>首先shunfengdb.js文件中的配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A43.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A44.tmp.jpg\" alt=\"img\"> </p>\n","excerpt":"","more":"<h1 id=\"第一章-创建工程\"><a href=\"#第一章-创建工程\" class=\"headerlink\" title=\"第一章 创建工程\"></a>第一章 创建工程</h1><h2 id=\"1-1-创建工程\"><a href=\"#1-1-创建工程\" class=\"headerlink\" title=\"1.1 创建工程\"></a>1.1 创建工程</h2><p>工程得创建分为两种方式:第一种,从空工程开始创建。第二种,通过intellij idea得项目模板来创建。使用第二种方式创建得时候需要使用网络,由于idea得服务器在国外,所以速度相对比较慢。本节介绍的是第一种方法。</p>\n<p>第一种方法所需的条件:1.类库文件,2.JsWeb框架的js服务端类库。这些文件在公司的资料共享服务器中。</p>\n<p>文件-新建-工程,不要选任何选项,点击下一步。创建一个普通的java工程。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685C.tmp.jpg\" alt=\"img\"> </p>\n<p>输入工程名字</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps685D.tmp.jpg\" alt=\"img\"> </p>\n<p>新建完成后工程目录如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686D.tmp.jpg\" alt=\"img\"> </p>\n<p>创建一个lib目录</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686E.tmp.jpg\" alt=\"img\"> </p>\n<p>将类库文件复制到工程中</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps686F.tmp.jpg\" alt=\"img\"> </p>\n<p>复制完成后,右键add as library</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6880.tmp.jpg\" alt=\"img\"> </p>\n<p>Library的名字和文件夹的名字保持一致。</p>\n<p>添加完成后,打开工程属性</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6881.tmp.jpg\" alt=\"img\"> </p>\n<p>打开工程属性 添加 facets,选择spring,然后选择web,点击 create artifact</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6892.tmp.jpg\" alt=\"img\"> </p>\n<p>将工程右侧的libraries都添加到左侧output目录里面,如下图</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6893.tmp.jpg\" alt=\"img\"> </p>\n<p>Problems的数量为0.</p>\n<p>目前,IDE应该已经自动创建了Web目录和Web.xml文件。</p>\n<p>将 配置文件和js类库文件复制到工程中</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A3.tmp.jpg\" alt=\"img\"> </p>\n<p>复制完成后如下图:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A4.tmp.jpg\" alt=\"img\"> </p>\n<p>将JspPageController类复制到Src目录下的如下位置,若包不存在请创建</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68A5.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"1-2-工程配置\"><a href=\"#1-2-工程配置\" class=\"headerlink\" title=\"1.2 工程配置\"></a>1.2 工程配置</h2><p>在JSAPI.xml文件中 进行项目的配置</p>\n<p>连接字符串的配置:</p>\n<p>修改driverclassname,jdbcurl,username,password 默认线程池大小:最小10,最大100</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68B6.tmp.jpg\" alt=\"img\"> </p>\n<p>常见配置方案:</p>\n<ol>\n<li><p>MySql</p>\n</li>\n<li><p>Oracle</p>\n</li>\n<li><p>SqlServer</p>\n</li>\n</ol>\n<p>Jsweb扫描器:</p>\n<p>配置js服务接口根目录</p>\n<p>配置js服务端类库跟目录</p>\n<p>配置js服务端自定义类库跟目录</p>\n<p>配置licensekey</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68C6.tmp.jpg\" alt=\"img\"> </p>\n<p>映射和拦截器:</p>\n<p>Jsweb接口的基础路径是 /jsons 所有/jsons/*.form的请求都会由jsapicontroller来处理。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D7.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"1-3-工程结构\"><a href=\"#1-3-工程结构\" class=\"headerlink\" title=\"1.3 工程结构\"></a>1.3 工程结构</h2><p>工程建立完成后目录结构如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68D8.tmp.jpg\" alt=\"img\"> </p>\n<p>src文件夹用于存放java代码文件</p>\n<p>jsapis用于存放jsweb的服务端接口文件</p>\n<p>jscustomlibs 用于存放与当前工程相关的函数库文件</p>\n<p>jslibs 用于存放通用函数库文件</p>\n<p>pages用于存放jsp文件</p>\n<p>web目录下用于存放网站的静态资源</p>\n<p>applicationContext.xml 为工程中的spring配置文件</p>\n<p>dispatcher-servlet.xml 为系统spring配置文件</p>\n<p>jsapi.xml jsweb配置文件</p>\n<p>web.xml web配置文件</p>\n<h1 id=\"第二章-JsWeb框架的简单介绍\"><a href=\"#第二章-JsWeb框架的简单介绍\" class=\"headerlink\" title=\"第二章 JsWeb框架的简单介绍\"></a>第二章 JsWeb框架的简单介绍</h1><h2 id=\"2-1-框架的工作原理\"><a href=\"#2-1-框架的工作原理\" class=\"headerlink\" title=\"2.1 框架的工作原理\"></a>2.1 框架的工作原理</h2><p>目前项目的开发框架为:Spring+SpringMVC+JsWeb框架。JsWeb框架本身依赖于Spring 和 Spring MVC框架。框架本身兼容其他第三方框架,JsWeb框架通过Controller与Spring MVC项目相结合,通过实现Controller接口从Spring MVC获取Request、Repsonse、ModelAndView、SevletSession等对象。JsApiController通过调用编译后的JS对请求进行处理。工作原理如图2-1。框架本身是基于SpringMVC框架扩展,与其他框架不产生冲突。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps68E9.tmp.png\" alt=\"img\"></p>\n<p>图2-1 JsWeb框架工作原理图</p>\n<p>为了能快速的开发服务端接口,开发了JSWEB框架——一个可以使用javascript脚本来开发服务端数据接口的框架。</p>\n<h3 id=\"框架优势\"><a href=\"#框架优势\" class=\"headerlink\" title=\"框架优势\"></a>框架优势</h3><p>JSWEB框架相比传统的Java服务端框架具有以下优势:</p>\n<ul>\n<li>无model层,当数据库发生变更时无需重新写model类,而对于某些返回数据(由表链接产生,不存在于model层)无需创建大量的model类。</li>\n<li>基于实体关系的sql生成类库,可动态生成sql。使用类似于mongodb的语法 操纵表连接查询,无需创建大量视图,无惧数据库字段增加删除更改。</li>\n<li>可直接操作WEB底层(Session,Request,Response,Header,Status等)</li>\n<li>可灵活扩展第三方插件(支付、快递、短信、邮件等)</li>\n</ul>\n<h2 id=\"2-2-框架功能介绍\"><a href=\"#2-2-框架功能介绍\" class=\"headerlink\" title=\"2.2 框架功能介绍\"></a>2.2 框架功能介绍</h2><p>框架针对Web开发中所遇到的各类问题,封装了相应的函数。下面简单介绍下各个函数库中各个函数库中函数的功能。</p>\n<h3 id=\"2-2-1-codec函数库\"><a href=\"#2-2-1-codec函数库\" class=\"headerlink\" title=\"2.2.1 codec函数库\"></a>2.2.1 codec函数库</h3><p>codec函数库用于做字符串编码,目前函数库里的函数主要用于生成字符串的摘要。主要应用于密码保存。主要函数及功能见表2-1。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>md5hex</td>\n<td>求解字符串的MD5值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha1hex</td>\n<td>求解字符串的sha1值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha256hex</td>\n<td>求解字符串的sha256值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha384hex</td>\n<td>求解字符串的sha384值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n<tr>\n<td>sha512hex</td>\n<td>求解字符串的sha512值,输出为16进制表示的字符串</td>\n<td>1.str 输入的字符串return 16进制表示的byte数组</td>\n</tr>\n</tbody>\n</table>\n<p>表2-1 codec函数库的主要函数</p>\n<h3 id=\"2-2-2-email函数库\"><a href=\"#2-2-2-email函数库\" class=\"headerlink\" title=\"2.2.2 email函数库\"></a>2.2.2 email函数库</h3><p>email函数库用于邮件的发送和读取。函数库可应用于项目中的用户注册、用户激活账户、邮件找回密码、消息通知、广告推广等模块。主要函数及功能见表2-2。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>sendhtmlmail</td>\n<td>发送html富文本邮件</td>\n<td>1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(html)11.attachementFiles 附件列表(文件地址列表)</td>\n</tr>\n<tr>\n<td>sendtextmail</td>\n<td>发送纯文本邮件</td>\n<td>1.sender发件人姓名2.senderEmail 发件人邮箱地址3.receiver 收件人姓名4. receiverEmail 收件人邮箱地址5.stmpserver 发件人邮箱的STMP服务器地址6. smtpport STMP服务器的端口7.username发件人邮箱的用户名8.password 发件人的邮箱的密码9.subject邮件主题10.content 邮件内容(文本)11.attachementFiles 附件列表(文件地址列表)</td>\n</tr>\n</tbody>\n</table>\n<p>表2-2 email函数库的主要函数</p>\n<h3 id=\"2-2-3-fileutils函数库\"><a href=\"#2-2-3-fileutils函数库\" class=\"headerlink\" title=\"2.2.3 fileutils函数库\"></a>2.2.3 fileutils函数库</h3><p>fileutils函数库用于文件操作。函数库可以用于管理服务器端的文件,比如清理用户上传的临时文件。也可以读取服务器端的文本文件。主要函数及功能见表2-3。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>createfile</td>\n<td>创建文件</td>\n<td>1. filepath 需要创建的文件的路径,绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>listfiles</td>\n<td>列出目录下的所有文件</td>\n<td>1.dir 目录的绝对路径return 字符串列表,用于保存目录下所有文件的数组</td>\n</tr>\n<tr>\n<td>listfileitems</td>\n<td>列出目录下的所有文件,包括文件属性</td>\n<td>1.dir目录的绝对路径return 目录下的所有文件的列表,列表中保存了每个文件的详细信息。</td>\n</tr>\n<tr>\n<td>searchFiles</td>\n<td>搜索目录下的文件,包括子目录</td>\n<td>1.dir目录的绝对路径2.keyword 搜素关键字return 字符串列表,用于保存目录下所有文件的数组</td>\n</tr>\n<tr>\n<td>mkdir</td>\n<td>创建目录</td>\n<td>1.dir目录的绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>deletefile</td>\n<td>删除文件或文件夹</td>\n<td>1. fileordir文件或目录的绝对路径return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>readfile</td>\n<td>读取文本文件的内容</td>\n<td>1. filepath需要读取的文件的绝对路径2.encoding 文件的编码,默认为utf-8return 文件中的文本内容</td>\n</tr>\n<tr>\n<td>writefile</td>\n<td>将文本写入文本文件</td>\n<td>1. filepath需要读取的文件的绝对路径2.content 要写入的文件内容3.encoding 文件的编码,默认为utf-8return true/false 成功/失败</td>\n</tr>\n</tbody>\n</table>\n<p>表2-3 fileutils函数库的主要函数</p>\n<h3 id=\"2-2-4-image函数库\"><a href=\"#2-2-4-image函数库\" class=\"headerlink\" title=\"2.2.4 image函数库\"></a>2.2.4 image函数库</h3><p>image函数库用于图像处理相关的应用,基本功能包括生成数字验证码。图片调整大小,获取图片的大小等。主要函数及功能见表2-4。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>generatenumbercheckcode</td>\n<td>生成4位数验证码</td>\n<td>1.context jsweb上下文2.sessionkey 存储验证码的session字段return 生成的4位数字验证码</td>\n</tr>\n<tr>\n<td>resizeimage2file</td>\n<td>将图片进行缩放操作,输出到本地文件</td>\n<td>1.imagefilepath 图片文件的路径2.targetfilepath目标文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>resizeimage2response</td>\n<td>将图片进行缩放操作,输出到response</td>\n<td>1.context jsweb上下文2.imagefilepath 图片文件的路径3.w处理后图片的宽度4.h处理后图片的高度return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>imagesize</td>\n<td>获取图片得大小</td>\n<td>1. imagepath 图片文件的路径return 图片的大小{w,h}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-4 image函数库的主要函数</p>\n<h3 id=\"2-2-5-net函数库\"><a href=\"#2-2-5-net函数库\" class=\"headerlink\" title=\"2.2.5 net函数库\"></a>2.2.5 net函数库</h3><p>net函数库中包含了与网络相关的函数,函数库的功能包括两大类:1.负责给用户端提供上传、下载服务。2.给其他服务端发送get/post请求。主要函数及功能见表2-5。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>uploadfileserver</td>\n<td>文件上传服务</td>\n<td>1.context jsweb上下文2.path 上传文件保存位置3.isrelative 是否是相对路径</td>\n</tr>\n<tr>\n<td>downloadfileserver</td>\n<td>文件下载服务</td>\n<td>1.context jsweb上下文2.targetfilepath要下载的文件的路径3.isrelative 路径是否是相对路径4.浏览器下载时的文件名5.输出的content-type</td>\n</tr>\n<tr>\n<td>postform</td>\n<td>post form数据到某url</td>\n<td>1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>poststring</td>\n<td>post string数据到某url</td>\n<td>1.url 远程服务端接口url2.str 要发送的字符串3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>postfile</td>\n<td>post 文件到远程服务器</td>\n<td></td>\n</tr>\n<tr>\n<td>getform</td>\n<td>get 数据从某url</td>\n<td>1.url 远程服务端接口url2.formData 数据,格式为object3.headers http头,格式为keyvalue4.encoding 发送和接收编码,默认为utf-8return 返回{status,content,responseduration}</td>\n</tr>\n<tr>\n<td>downloadfile</td>\n<td>下载远程服务器上的文件</td>\n<td>1.url 远程文件的url2.method 下载方法get/post3.formdata 发送的form数据4.headers http头,格式为keyvalue5.encoding 发送和接收编码,默认为utf-86.targetfilepath 保存在本地的文件路径,绝对路径return 返回{status,content,responseduration}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-5 net函数库的主要函数</p>\n<h3 id=\"2-2-6-runtime函数库\"><a href=\"#2-2-6-runtime函数库\" class=\"headerlink\" title=\"2.2.6 runtime函数库\"></a>2.2.6 runtime函数库</h3><p>runtime函数库中,包含了与运行时相关的函数。主要函数及功能见表2-6。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>rumtimeexec</td>\n<td>执行本地可执行文件</td>\n<td>1.path 可执行文件的路径2.startuppath 执行的开始目录</td>\n</tr>\n<tr>\n<td>runinbackground</td>\n<td>创建一个新线程执行一个任务。线程从线程池中创建,如果线程池使用枯竭,则需要等待空闲线程。</td>\n<td>1.context jsweb上下文2.apiname 要执行的任务的api名称</td>\n</tr>\n<tr>\n<td>sleep</td>\n<td>睡眠,停止当前线程一定时间。</td>\n<td>1.miliseconds 睡眠的毫秒数</td>\n</tr>\n</tbody>\n</table>\n<p>表2-6 runtime函数库的主要函数</p>\n<h3 id=\"2-2-7-servlet函数库\"><a href=\"#2-2-7-servlet函数库\" class=\"headerlink\" title=\"2.2.7 servlet函数库\"></a>2.2.7 servlet函数库</h3><p>servlet函数库中包含了与request、response、session相关的处理函数。主要函数及功能见表2-7。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>httpstatus</td>\n<td>设置response的状态值</td>\n<td>1.context jsweb上下文2.status 状态码,数值类型</td>\n</tr>\n<tr>\n<td>contenttype</td>\n<td>设置response的相应内容</td>\n<td>1.context jsweb上下文2.contenttype0 content-type</td>\n</tr>\n<tr>\n<td>setsession</td>\n<td>设置session的值</td>\n<td>1.context jsweb上下文2.key session的键3.value session的值</td>\n</tr>\n<tr>\n<td>getsession</td>\n<td>获取session的值</td>\n<td>1.context jsweb上下文2.key session的键return session的值</td>\n</tr>\n<tr>\n<td>setheader</td>\n<td>设置header的值</td>\n<td>1.context jsweb上下文2.key session的键3.value header的值</td>\n</tr>\n<tr>\n<td>redirect</td>\n<td>访问重定向</td>\n<td>1.context jsweb上下文2.url 重定向的url地址</td>\n</tr>\n<tr>\n<td>getheader</td>\n<td>获取header的值</td>\n<td>1.context jsweb上下文2.key session的键</td>\n</tr>\n<tr>\n<td>setcontenttype</td>\n<td>设置response的相应内容</td>\n<td>1.context jsweb上下文2.contenttype0 content-type</td>\n</tr>\n<tr>\n<td>setview</td>\n<td>设置modelandview中的view</td>\n<td>1.context jsweb上下文2.viewname 视图路径,和spring设置方法一致</td>\n</tr>\n<tr>\n<td>rootphysicpath</td>\n<td>获取网站的绝对路径</td>\n<td>1.context jsweb上下文2.path 网站根目录的相对路径return 字符串,绝对路径</td>\n</tr>\n<tr>\n<td>contextpath</td>\n<td>获取contextpath</td>\n<td>1.context jsweb上下文return 字符串,访问的contextpath</td>\n</tr>\n<tr>\n<td>writeresponsestream</td>\n<td>写入response输出流</td>\n<td>1.context jsweb上下文2.inputstream 输入流return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>getresponse</td>\n<td>获取response对象</td>\n<td>1.context jsweb上下文return response</td>\n</tr>\n<tr>\n<td>getresponsestream</td>\n<td>获取response输出流</td>\n<td>1.context jsweb上下文return outputstream</td>\n</tr>\n<tr>\n<td>setresponsefilename</td>\n<td>设置response中输出的文件名</td>\n<td>1.context jsweb上下文2.filename 输出显示的文件名</td>\n</tr>\n<tr>\n<td>getmethod</td>\n<td>获取当前访问的方式</td>\n<td>1.context jsweb上下文return 字符串,get/set</td>\n</tr>\n</tbody>\n</table>\n<p>表2-7 servlet函数库的主要函数</p>\n<h3 id=\"2-2-8-utils函数库\"><a href=\"#2-2-8-utils函数库\" class=\"headerlink\" title=\"2.2.8 utils函数库\"></a>2.2.8 utils函数库</h3><p>utils工具函数库,主要功能为开发中常见的工具,比如uuid、md5、base64、json序列化反序列化、向内存中获取/保存对象,路径合并等。主要函数及功能见表2-8。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>uuid</td>\n<td>生成一个UUID</td>\n<td>无</td>\n</tr>\n<tr>\n<td>md5</td>\n<td>计算输入字符串的md5,输出为base64编码的字符串</td>\n<td>1.input 输入字符串return 返回摘要字符串</td>\n</tr>\n<tr>\n<td>base64</td>\n<td>base64编码函数</td>\n<td>1.input 输入字符串return 编码后的字符串</td>\n</tr>\n<tr>\n<td>jsonStringify</td>\n<td>对象的json序列化</td>\n<td>1.obj 要进行序列化的对象return 序列化之后的json字符串</td>\n</tr>\n<tr>\n<td>jsonParse</td>\n<td>对象反序列化</td>\n<td>1.jsonstr json字符串return 反序列化后的对象</td>\n</tr>\n<tr>\n<td>getmemcache</td>\n<td>获取运行jsweb服务器里面的缓存对象</td>\n<td>1.key 对象的名称return 缓存的对象</td>\n</tr>\n<tr>\n<td>putmemcache</td>\n<td>将对象放入运行jsweb服务器里面的缓存</td>\n<td>1.key 对象的名称2.value 要缓存的对象</td>\n</tr>\n<tr>\n<td>ismemcachecontains</td>\n<td>判断缓存中是否包含对象的名称</td>\n<td>1.key 对象的名称return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>console</td>\n<td>从控制台中输出对象</td>\n<td>1.str 要输出的对象</td>\n</tr>\n<tr>\n<td>threadid</td>\n<td>获取当前线程的线程id</td>\n<td>return 线程id,数字</td>\n</tr>\n<tr>\n<td>createlist</td>\n<td>创建java的list</td>\n<td>return list</td>\n</tr>\n<tr>\n<td>createsafemap</td>\n<td>创建java中的map</td>\n<td>return map</td>\n</tr>\n<tr>\n<td>pathcombine</td>\n<td>合并路径</td>\n<td>无限参数,路径return 合并后的路径</td>\n</tr>\n</tbody>\n</table>\n<p>表2-8 servlet函数库的主要函数</p>\n<h3 id=\"2-2-9-compress函数库\"><a href=\"#2-2-9-compress函数库\" class=\"headerlink\" title=\"2.2.9 compress函数库\"></a>2.2.9 compress函数库</h3><p>compress函数库用于在服务端创建压缩文件。目前功能是可以把文件夹中的文件压缩为一个压缩文件,支持的格式为zip。主要函数及功能见表2-9。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>zipfolder</td>\n<td>将文件夹压缩为一个zip文件,保存到文件</td>\n<td>1.rootfolder 要压缩的根目录2.extlist 后缀列表3.outfile 输出文件的路径</td>\n</tr>\n<tr>\n<td>zipfolder2response</td>\n<td>将文件夹压缩为一个zip文件,输出到response</td>\n<td>1.context jsweb上下文2.rootfolder 要压缩的根目录3.extlist 后缀列表</td>\n</tr>\n</tbody>\n</table>\n<p>表2-9 compress函数库的主要函数</p>\n<p>应用场景:</p>\n<p>1.需要批量下载文件的需求,如:沐诺农场批量下载二维码</p>\n<p>2.需要下载的文件过大或数量过多,如:下载整年的统计表</p>\n<h3 id=\"2-2-10-sqlbase函数库\"><a href=\"#2-2-10-sqlbase函数库\" class=\"headerlink\" title=\"2.2.10 sqlbase函数库\"></a>2.2.10 sqlbase函数库</h3><p>sqlbase函数库中包含了sql查询的基本函数。该函数库是jsweb项目中最重要的函数库,在一个项目中该函数库会被高频的使用。主要的函数及功能见表2-10。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>query</td>\n<td>查询sql并返回查询结果,查询结果为数组</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串return 返回查询结果</td>\n</tr>\n<tr>\n<td>querypagedata</td>\n<td>分页查询sql并返回查询结果,查询结果为数组</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5.pagesize 每页记录的数量return 返回分页查询结果</td>\n</tr>\n<tr>\n<td>multiquery</td>\n<td>查询sql并返回查询结果,查询结果为数组,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文4.mappingstr 映射字符串return 返回查询结果</td>\n</tr>\n<tr>\n<td>exec</td>\n<td>执行sql语句。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>multiexec</td>\n<td>执行sql语句,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.params sql查询上下文return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>execbatch</td>\n<td>批量执行sql语句。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.datalist 数据列表return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>multiexecbatch</td>\n<td>批量执行sql语句,需要传入jdbc连接</td>\n<td>1.con jdbc连接2.fn 查询语句(func注释或字符串格式)3.datalist 数据列表return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>createconnection</td>\n<td>创建jdbc连接</td>\n<td>无</td>\n</tr>\n<tr>\n<td>closeconnection</td>\n<td>关闭jdbc连接</td>\n<td>1.con jdbc连接</td>\n</tr>\n<tr>\n<td>commit</td>\n<td>提交连接中的数据</td>\n<td>1.con jdbc连接return true/false 成功/失败</td>\n</tr>\n<tr>\n<td>rollback</td>\n<td>回滚连接中的数据</td>\n<td>1.con jdbc连接return true/false 成功/失败</td>\n</tr>\n</tbody>\n</table>\n<p>表2-10 sqlbase函数库的主要函数</p>\n<h3 id=\"2-2-11-redissql函数库\"><a href=\"#2-2-11-redissql函数库\" class=\"headerlink\" title=\"2.2.11 redissql函数库\"></a>2.2.11 redissql函数库</h3><p>redissql 为利用redis内存数据库,对接口的数据进行缓存,从而提高实时性不高的接口的访问性能。提升后的性能接近静态资源访问速度。主要的函数及功能见表2-11。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>redisquery</td>\n<td>基于redis内存数据的缓存查询。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4. expire 设置超时时间,毫秒return 返回查询结果</td>\n</tr>\n<tr>\n<td>redisquerypagedata</td>\n<td>基于redis内存数据的缓存分页查询。</td>\n<td>1.fn 查询语句(func注释或字符串格式)2.params sql查询上下文3.mappingstr 映射字符串4.pagenum 当前的页码,从1开始5. expire 设置超时时间,毫秒return 返回分页查询结果</td>\n</tr>\n</tbody>\n</table>\n<p>表2-11 redissql函数库的主要函数</p>\n<p>应用场景:</p>\n<ol>\n<li>高频且对数据实时性不高的接口,如商城主页的商品列表接口、商品品类接口、商店店铺页面的商品品类和 商品接口。</li>\n</ol>\n<h3 id=\"2-2-12-dber-dberjs函数库\"><a href=\"#2-2-12-dber-dberjs函数库\" class=\"headerlink\" title=\"2.2.12 dber/dberjs函数库\"></a>2.2.12 dber/dberjs函数库</h3><p>dber/dberjs函数库是一个全新的基于实体关系进行数据查询和插入的函数库。与传统的sql不用,基于实体关系的查询根据数据表中预定义的连接关系自动生成查询的sql语句。实体关系查询提供了几种查询源语:query filter search orderby。除了查询功能外还提供基于实体的删除、更新和插入功能。主要的函数及功能见表2-12,2-13。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>dbcontext().query</td>\n<td>根据用户输入的实体结构字符串进行查询</td>\n<td>1.structurestr 实体结构字符串</td>\n</tr>\n<tr>\n<td>dbcontext().<a href=\"\">filter</a></td>\n<td>根据过滤条件进行过滤</td>\n<td>1.filterstr 过滤字符串</td>\n</tr>\n<tr>\n<td>dbcontext().search</td>\n<td>综合搜索,当用户没有提交搜索变量的值的时候不进行该条件搜索,否则进行搜索。通常用于多条件搜索。</td>\n<td>1.varname 搜索变量名2.condition 过滤字符串</td>\n</tr>\n<tr>\n<td>dbcontext().orderby</td>\n<td>排序</td>\n<td>1.orderbystr 排序字符串</td>\n</tr>\n<tr>\n<td>dbcontext().buildsqlquery</td>\n<td>构建sql字符串和映射字符串</td>\n<td>return 返回{sql,mappingstr}</td>\n</tr>\n<tr>\n<td>initmysqldb</td>\n<td>初始化mysql数据库的实体关系</td>\n<td>数据库schema名称</td>\n</tr>\n<tr>\n<td>db.relation</td>\n<td>预定义实体与实体的关系</td>\n<td>1.modelpropertystr 实体属性字符串2.modelconnectorstr 实体连接字符串3.relationtype 实体关系,1:1 1:n</td>\n</tr>\n</tbody>\n</table>\n<p>表2-12 dber函数库的主要函数</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>deleteentity</td>\n<td>删除数据库中实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>updateentity</td>\n<td>更新数据库中的实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertentity</td>\n<td>将实体对象插入数据库</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象3.isuserpk 是否使用entitydata中的主键,默认为null4. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multideleteentity</td>\n<td>删除数据库中实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiupdateentity</td>\n<td>更新数据库中的实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiinsertentity</td>\n<td>将实体对象插入数据库,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>updateentitybatch</td>\n<td>批量更新实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.wherestr where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertentitybatch</td>\n<td>批量插入实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表4.isuserpk 是否使用entitydata中的主键,默认为null5. where查询子句,用于定位删除规则,默认为nullreturn {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertorupdateentity</td>\n<td>插入或更新实体</td>\n<td>1.entityname 实体名称2.entitydata 实体的对象return {result,errormessage}</td>\n</tr>\n<tr>\n<td>multiinsertorupdateentity</td>\n<td>插入或更新实体,带传入连接</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitydata 实体的对象return {result,errormessage}</td>\n</tr>\n<tr>\n<td>insertorupdateentitybatch</td>\n<td>批量插入或更新实体</td>\n<td>1.con jdbc连接2.entityname 实体名称3.entitylistdata 实体对象列表return {result,errormessage}</td>\n</tr>\n</tbody>\n</table>\n<p>表2-13 dberjs函数库的主要函数</p>\n<h3 id=\"2-2-13-text函数库\"><a href=\"#2-2-13-text函数库\" class=\"headerlink\" title=\"2.2.13 text函数库\"></a>2.2.13 text函数库</h3><p>text函数库是一个文本计算的科学函数库。主要功能为计算文本之间的相似性,提供多种相似性衡量标准,计算文本的最长公共子串。主要的函数及功能见表2-14。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>textjaccardsimilarity</td>\n<td>计算文本的jaccard相似性</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textlongestcommonsubsequnce</td>\n<td>计算最长公共子串(LCS)</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textlongestcommonsubsequncedistance</td>\n<td>计算最长公共子串相似性</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>texthammingdistance</td>\n<td>计算汉明距离</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n<tr>\n<td>textfuzzyscore</td>\n<td>计算模糊值</td>\n<td>1.str12.str2return 数值</td>\n</tr>\n</tbody>\n</table>\n<p>表2-14 text函数库的主要函数</p>\n<p>函数库的可应用场景举例:</p>\n<p>1.在输入提示框中显示提示,如果使用子串搜索方法,用户输入错误将导致提示消失。最相似方法 可以容许一定的错误。</p>\n<p>2.差异比较,比如比较两段文本 完全相同的部分。</p>\n<h3 id=\"2-2-14-velocity函数库\"><a href=\"#2-2-14-velocity函数库\" class=\"headerlink\" title=\"2.2.14 velocity函数库\"></a>2.2.14 velocity函数库</h3><p>velocity函数库的主要功能是提供模板渲染功能,目前渲染的模板引擎是velocity。主要的函数及功能见表2-15。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>velocitytemplate</td>\n<td>将用户输入的模板字符串进行渲染</td>\n<td>1.tempatestr2.paramsreturn 渲染后的字符串</td>\n</tr>\n</tbody>\n</table>\n<p>表2-15 velocity函数库的主要函数</p>\n<p>应用场景举例:</p>\n<ol>\n<li><p>发送验证码短信</p>\n</li>\n<li><p>发送激活账号邮件</p>\n</li>\n<li><p>找回密码邮件/短信</p>\n</li>\n<li><p>业务通知类短信/邮件/微信客服消息</p>\n</li>\n</ol>\n<h3 id=\"2-2-15-excel函数库\"><a href=\"#2-2-15-excel函数库\" class=\"headerlink\" title=\"2.2.15 excel函数库\"></a>2.2.15 excel函数库</h3><p>excel函数库主要功能是提供excel操作的相关函数。目前使用的excel文件操作类库是poi。主要的函数及功能见表2-16。</p>\n<table>\n<thead>\n<tr>\n<th>函数名</th>\n<th>功能</th>\n<th>参数</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>exportexceltemplate2file</td>\n<td>导出excel模板文件到指定的路径</td>\n<td>1.datacontext 数据上下文2.templatefilepath excel模板的路径3.outfilepath 输出文件路径</td>\n</tr>\n<tr>\n<td>exportexceltemplate2response</td>\n<td>导出excel模板文件到response</td>\n<td>1.context jsweb上下文2.datacontext 数据上下文3.templatefilepath excel模板的路径4.outfilename 输出文件名</td>\n</tr>\n<tr>\n<td>readexcelrows</td>\n<td>读取excel文件的部分内容</td>\n<td>1.excelfilepath excel文件路径2.sheetindex sheet的index3.column 列号,从0开始4.start 起始行号5.end 终止行号return 数组</td>\n</tr>\n<tr>\n<td>readexcelcolumns</td>\n<td>读取excel文件的部分内容</td>\n<td>1.excelfilepath excel文件路径2.sheetindex sheet的index3.rownumber 行号,从0开始4.start 起始列号5.end 终止列号return 数组</td>\n</tr>\n</tbody>\n</table>\n<p>表2-16 excel函数库的主要函数</p>\n<p>应用场景举例:</p>\n<p>1.导出店铺订单</p>\n<p>2.导出用户列表</p>\n<p>3.批量添加数据</p>\n<p>4.导出统计表,带筛选功能,富文本等</p>\n<h1 id=\"第三章-JsWeb框架的用法\"><a href=\"#第三章-JsWeb框架的用法\" class=\"headerlink\" title=\"第三章 JsWeb框架的用法\"></a>第三章 JsWeb框架的用法</h1><h2 id=\"3-1-基本sql查询\"><a href=\"#3-1-基本sql查询\" class=\"headerlink\" title=\"3.1 基本sql查询\"></a>3.1 基本sql查询</h2><p>数据库查询在传统的web项目中是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。</p>\n<p>数据库:shunfengtest 本地版,在资料中有,在运行本教程中的例子之前需要先部署好数据库。</p>\n<p>设置jsapi.xml文件中的 jdbcUrl为:</p>\n<p>jdbc:mysql://localhost/shunfengtest?allowMultiQueries=true</p>\n<p>shunfengtest数据库简介:shunfengtest数据库是顺丰通服务的数据库,顺丰通系统中包含一个商城系统和一个外卖系统,商城功能中除了正常的商城功能外,还包含一个三级代理功能,即普通用户通过身份认证后,可以代理商家或一二级代理商的商品,当商品通过代理人的分享售卖后,代理人以及代理人的上级可得到代理分红。系统中表sp开头的的是商城的数据表,rs开头的是外卖的数据表,cm是公用数据表,as是代理数据表,ed是快递的数据表,sys是系统数据表。</p>\n<h3 id=\"场景1\"><a href=\"#场景1\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>系统管理员需要管理在商城中注册的商家,所需要获取全部的商家列表。需要显示的数据包括sp_shop表中的 shopname、shopimg、shopshortdescription、shopownername、商店所在的省市区字符串和详细地址。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6909.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_3_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps690A.tmp.jpg\" alt=\"img\"> </p>\n<p>返回的是json数组。</p>\n<p>如果sql语句是多行的 ,用“”或‘’则比较麻烦。可以用函数注释方法进行多行字符串输入。(仅限sqlbase函数库)。</p>\n<p>当查询无参数且无需改变默认映射的时候,后面两个参数可以省略。</p>\n<p>[{shopid,shopname,shop…..}, {shopid,shopname,shop…..},….]</p>\n<h3 id=\"场景2\"><a href=\"#场景2\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在管理员使用的管理系统中,管理员需要查看各个商家上架的商品。同时,普通用户也需要查看某个商家店铺内的所有商品。因此,需要一个获取某商家全部商品列表的接口。接口需要传入shopid,接口返回该shop内所有商品的列表。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6949.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695A.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>shopid=<a href=\"\">006e0aca-0aae-11e7-ab6a-00ac2794c53f</a></p>\n<p>本接口没有设置映射,默认映射按照数据库表定义进行字段的映射。</p>\n<p>sql语句中存在一个变量${shopid},所以在query的第二个参数中构造了一个包含shopid的对象。如果context中包含该字段可以直接传入context作为query函数的第二个参数。</p>\n<h3 id=\"场景3\"><a href=\"#场景3\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>在管理员的管理界面中,需要以一个商家商品树,列出全部商家和商家下的全部商品,并显示在easyui的tree中。对于sp_shop表仅需要字段 shopid、shopname,对于商品表sp_good仅需要goodid,goodname即可。返回的json格式应满足easyui中的tree的输入格式。</p>\n<p>tree的输入格式</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695B.tmp.jpg\" alt=\"img\"> </p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps695C.tmp.jpg\" alt=\"img\"> </p>\n<p><a href=\"\">jsweb代码:详见jsapis</a>/jsons/case2_3_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696D.tmp.jpg\" alt=\"img\"> </p>\n<p>输出的部分结果:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps696E.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景4\"><a href=\"#场景4\" class=\"headerlink\" title=\"场景4\"></a>场景4</h3><p>管理员或者某商店用户查看所有或者商店对应的商品时,后台easyui框架中通常是使用分页,而不是直接把所有的数据展示出来。接口需要传入两个参数,page和rows。page代表当前是第几页,rows代表每页显示的行数。返回的json格式为rows:当前页的数据,total:一共多少行。</p>\n<p>结果的返回格式:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697E.tmp.jpg\" alt=\"img\"> </p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps697F.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_4.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6990.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景5\"><a href=\"#场景5\" class=\"headerlink\" title=\"场景5\"></a>场景5</h3><p>基于实体关系的查询,使用实体关系查询不需要自己写sql语句,基本的查询语句这样写,首先需要调用dbcontext()方法,然后调用其query方法,参数为数据库名或结构化字符串,然后调用buildsqlquery()方法,最后在query方法中传入buildsqlquery()方法返回值对应的两个参数即可。对于场景1,显示全部的属性,使用实体关系查询。</p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_5.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6991.tmp.jpg\" alt=\"img\"> </p>\n<p>.buildsqlquery()方法返回了其创建的映射关系q.mappingstr,若想使用自己的映射关系将q.mappingstr改为自己想要的映射关系即可。</p>\n<h3 id=\"场景6\"><a href=\"#场景6\" class=\"headerlink\" title=\"场景6\"></a>场景6</h3><p>基于场景2,管理员查看某个商家的商品,然后管理员还想要通过商品名进行检索,比如商品产地为沈阳(商品产地为商品名第一项),这种时候书写sql语句就需要使用like关键词。使用实体关系查询就需要使用.filter()方法和.search()方法,具体使用方法见<a href=\"#_2.2.12_dber/dberjs函数库\">2.2.12</a>。</p>\n<p><a href=\"\">jsweb代码:详见jsapis</a>/jsons/case2_3_6.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6992.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>shopid=006e0aca-0aae-11e7-ab6a-00ac2794c53f</p>\n<p>keyword=沈阳</p>\n<h3 id=\"场景7\"><a href=\"#场景7\" class=\"headerlink\" title=\"场景7\"></a>场景7</h3><p>项目上线后,商城的主页会经常被访问,为了提高性能可以使用内存数据库查询,具体介绍见<a href=\"#_2.2.11_redissql函数库\">2.2.11</a>。</p>\n<p>jsweb代码:详见jsapis/jsons/case2_3_7.js</p>\n<h2 id=\"3-2-基本sql操作\"><a href=\"#3-2-基本sql操作\" class=\"headerlink\" title=\"3.2 基本sql操作\"></a>3.2 基本sql操作</h2><p>数据库操作(插入、更新、删除)在传统的web项目中同样也是一个很常见的需求。传统的方法是通过orm框架(如mybatis)将resultset中的数据映射为对象。在JSWeb框架中,方法也是类似的。但是并不需要定义映射对象,也不需要复杂的映射配置。</p>\n<p>数据库介绍和配置同2.3。</p>\n<h3 id=\"场景1-1\"><a href=\"#场景1-1\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>商家需要管理他们商店的商品,首先是上线新的商品,这里就需要向数据库表sp_good表中插入一条数据,需要的字段有goodid、goodname、<a href=\"\">gooddetaildescription</a>、goodminprice、goodmaxprice、shopid等。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A3.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69A4.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:‘大连|樱桃’、<a href=\"\">gooddetaildescription</a>:‘大连大樱桃’、gooddetaildescription:15、</p>\n<p>goodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、</p>\n<p>goodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、</p>\n<p>goodisputway:2017-5-31、goodisremind:1</p>\n<p>返回的是true或false,成功为true,失败为false。</p>\n<h3 id=\"场景2-1\"><a href=\"#场景2-1\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在一段时间后,商家可能需要修改商品信息,比如修改商品详情,这样情况下需要修改产品表中的数据。比如根据goodid修改gooddetaildescription字段。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B4.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69B5.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<p>gooddetaildescription:’大连大樱桃,好吃又便宜’</p>\n<h3 id=\"场景3-1\"><a href=\"#场景3-1\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>商家管理商品,当商家不在卖某个商品时,需要将其删除,根据这个商品的id将其在数据库表中删除。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C6.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C7.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<h3 id=\"场景4-1\"><a href=\"#场景4-1\" class=\"headerlink\" title=\"场景4\"></a>场景4</h3><p>使用实体关系向表中插入数据。方法为insertentity()方法,参数为:第一个为表名、第二个为参数。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_4.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69C8.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:‘大连|樱桃’、gooddetaildescription:‘大连大樱桃’、gooddetaildescription:15、</p>\n<p>goodmaxprice:20、goodmaxprice:lirf、goodcategory:水果、</p>\n<p>goodcategory:006e0aca-0aae-11e7-ab6a-00ac2794c53f、goodorder:1、goodisputway:1、</p>\n<p>goodisputway:2017-5-31、goodisremind:1</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D8.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景5-1\"><a href=\"#场景5-1\" class=\"headerlink\" title=\"场景5\"></a>场景5</h3><p><a href=\"\">使用实体关系更新数据库表中的数据</a>,方法为updateentity(),参数为:第一个为表名、第二个为参数,第三个为更新的条件。</p>\n<p><a href=\"\">jsweb代码:详见</a>jsapis/jsons/case_2_4_5.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69D9.tmp.jpg\" alt=\"img\"> </p>\n<p><a href=\"\">测试数据</a>:</p>\n<p>goodid: f539819c-45cf-11e7-9b1c-38d547ab4abf</p>\n<p>gooddetaildescription:’大连大樱桃,好吃又便宜’</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EA.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景6-1\"><a href=\"#场景6-1\" class=\"headerlink\" title=\"场景6\"></a>场景6</h3><p>使用实体关系删除数据库表中的数据,方法为updateentity(),参数为:第一个为表名、第二个为实体(删除数据的依据,主要是id),第三个为更新的条件(可不填)。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_4_6.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69EB.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>goodname:”大连|樱桃”;</p>\n<p>gooddetaildescription:”大连大樱桃”;</p>\n<p>goodminprice:”15”;</p>\n<p>goodmaxprice:”20”;</p>\n<p>goodcreator:”lirf”;</p>\n<p>goodcategory:”水果”;</p>\n<p>shopid:”ff45459f-45d3-11e7-9b1c-38d547ab4abf”;</p>\n<p>goodid:”ff45459f-45d3-11e7-9b1c-38d547ab4abf”;</p>\n<p>goodorder:”1”;</p>\n<p>goodisputway:”1”;</p>\n<p>goodproducedate:”2017-5-31”;</p>\n<p>goodisremind:”1”;</p>\n<p>返回的是json格式,执行结果(true|false)和执行的sql语句。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FC.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"3-3-sql事务操作\"><a href=\"#3-3-sql事务操作\" class=\"headerlink\" title=\"3.3 sql事务操作\"></a>3.3 sql事务操作</h2><p>在对数据库进行插入、更新、删除等操作时,经常遇到同时执行多条sql语句的情况,这种情况下就需要使用事务操作。在mybatis中支持事务操作,只需要在方法前加上注解就可以,在JSWEB框架中,事务操作有其特定的方法,下面来看几个例子。</p>\n<h3 id=\"场景1-2\"><a href=\"#场景1-2\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>用户提交订单之后进行支付,支付完成之后需要将订单状态改为已支付,同时需要在支付记录中插入一条新的数据。这种情况下需要使用事务来完成,在框架中使用multiexec()方法来完成,具体的参数及使用方法见<a href=\"#_2.2.10_sqlbase函数库\">2.2.10</a>。</p>\n<p>sql语句:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FD.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case_2_5_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps69FE.tmp.jpg\" alt=\"img\"> </p>\n<p>测试数据:</p>\n<p>orderpayedprice:100</p>\n<p>ordernumber:CP1704281613263536</p>\n<h3 id=\"场景2-2\"><a href=\"#场景2-2\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>场景同上,使用实体关系进行事务操作,需要用到的方法为multideleteentity()、multiupdateentity()、multiinsertentity(),详情见<a href=\"#_2.2.12_dber/dberjs函数库\">2.2.12</a>。</p>\n<p>jsweb代码:详见jsapis/jsons/case_2_5_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0E.tmp.jpg\" alt=\"img\"> </p>\n<h2 id=\"3-4-实体关系查询\"><a href=\"#3-4-实体关系查询\" class=\"headerlink\" title=\"3.4 实体关系查询\"></a>3.4 实体关系查询</h2><p>在前面介绍了实体关系查询的基本用法,但是实体关系查询最实用的是当两个或多个表关联查询时可以用比较少的代码来实现。下边来看几个场景。</p>\n<h3 id=\"场景1-3\"><a href=\"#场景1-3\" class=\"headerlink\" title=\"场景1\"></a>场景1</h3><p>在管理员的管理界面中,需要列出全部商家和商家下的全部商品,并显示在easyui中。通过实体关系查询可以查询出所有店铺的所有商品,还可以使用filter()或search()方法进行条件筛选。</p>\n<p>使用实体关系关联查询首先需要shunfengdb.js文件中写配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A0F.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_1.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A20.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景2-3\"><a href=\"#场景2-3\" class=\"headerlink\" title=\"场景2\"></a>场景2</h3><p>在前台微信端页面,当用户点进一个商品的详情页之后需要查询该商品的详细信息,包括品类、图片、代理配置以及拥有的规格等信息,这些信息分别存在四个表中,如果写连接查询的sql语句会比较复杂,如果用实体关系查询就非常简单。</p>\n<p>首先shunfengdb.js文件中的配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A21.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_2.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A32.tmp.jpg\" alt=\"img\"> </p>\n<p>部分结果如下如所示</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A33.tmp.jpg\" alt=\"img\"> </p>\n<h3 id=\"场景3-2\"><a href=\"#场景3-2\" class=\"headerlink\" title=\"场景3\"></a>场景3</h3><p>在前台微信端页面,当用户提交订单信息时可能需要根据规格去查询商品信息以及该商品对应的店铺信息,这种情况下也可以使用实体关系查询。</p>\n<p>首先shunfengdb.js文件中的配置语句</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A43.tmp.jpg\" alt=\"img\"> </p>\n<p>jsweb代码:详见jsapis/jsons/case2_6_3.js</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/github/jsweb/wps6A44.tmp.jpg\" alt=\"img\"> </p>\n"},{"title":"HttpClient学习记录","comment":true,"date":"2017-10-14T08:55:10.000Z","_content":"\n# 一、前期准备\n> [HttpClient](https://hc.apache.org/httpcomponents-client-ga/index.html) is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reusable components for client-side authentication, HTTP state management, and HTTP connection management. HttpComponents Client is a successor of and replacement for [Commons HttpClient 3.x](http://hc.apache.org/httpclient-legacy/index.html). Users of Commons HttpClient are strongly encouraged to upgrade.\n\n**总结:** HttpClient 是apache 组织下面的一个用于处理HTTP 请求和响应的开源工具。\n\n需要的jar包:\n\n\thttpclient-4.3.6.jar、httpcore-4.3.3.jar、httpmime-4.3.6.jar、commons-codec-1.6.jar。\n\n# 二、操作步骤\n\n由于HttpClient从4.X开始,基本的get/post 等http请求实现方式与之前版本的写法有很大的差异,所以在此总结一下4.X版本之后的官方推荐写法。\n\n**操作顺序:** \n\n1. 创建CloseableHttpClient对象\n2. 创建请求方法实例:HttpGet/HttpPost\n3. (可选)需要请求参数时\n - HttpGet/HttpPost都可以使用setParams方法添加参数(deprecated 已过时)\n - 对于HttpPost方法可以使用SetEntity(HttpEntity entity)参加请求参数\n - 对于HttpGet方法,可以通过拼接url的方式添加请求参数\n4. 调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。\n5. 通过CloseableHttpResponse对象获取服务器的响应内容。\n6. 释放连接。无论执行方法是否成功,都必须释放连接\n\n# 三、代码实例\n\n```java\npackage com.learn.http;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.ParseException;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.util.EntityUtils;\n\npublic class HttpSend {\n\n\tpublic static void main(String[] args) {\n\t\t// post请求百度地址,返回404\n\t\tnew HttpSend().post(\"http://www.baidu.com\");\n\t\tnew HttpSend().get(\"http://www.baidu.com\");\n\t}\n\n\t/**\n\t * 发送 post请求访问本地应用并根据传递参数不同返回不同结果\n\t */\n\tpublic void post(String url) {\n\n\t\t// 创建默认的httpClient实例.\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault();\n\t\t// 创建httppost\n\t\tHttpPost httppost = new HttpPost(url);\n\t\t\n\t\t// 创建参数队列\n\t\tList<NameValuePair> formparams = new ArrayList<NameValuePair>();\n\t\t// 添加参数\n\t\t// formparams.add(new BasicNameValuePair(\"gg\", \"1\"));\n\n\t\tUrlEncodedFormEntity uefEntity;\n\t\ttry {\n\t\t\t//传入空参数,创建实体对象\n\t\t\tuefEntity = new UrlEncodedFormEntity(formparams, \"UTF-8\");\n\t\t\t//设置post对象的实体对象\n\t\t\thttppost.setEntity(uefEntity);\n\t\t\tSystem.out.println(\"executing post request \" + httppost.getURI());\n\t\t\t//执行post请求\n\t\t\tCloseableHttpResponse response = httpclient.execute(httppost);\n\t\t\ttry {\n\t\t\t\t//获取请求结果对象\n\t\t\t\tHttpEntity entity = response.getEntity();\n\t\t\t\tif (entity != null) {\n\t\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t\tSystem.out.println(\"Response content: \" + EntityUtils.toString(entity));\n\t\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tresponse.close();\n\t\t\t}\n\t\t} catch (ClientProtocolException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (UnsupportedEncodingException e1) {\n\t\t\te1.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\t// 关闭连接,释放资源\n\t\t\ttry {\n\t\t\t\thttpclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 发送 get请求\n\t */\n\tpublic void get(String url) {\n\n\t\t// 创建默认的httpClient实例.\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault();\n\t\t\n\t\ttry {\n\t\t\t// 封装请求参数\n\t\t\tList<NameValuePair> params = new ArrayList<>();\n\t\t\tparams.add(new BasicNameValuePair(\"cityEname\", \"henan\"));\n\t\t\t//转换为键值对\n\t\t\tString str = EntityUtils.toString(new UrlEncodedFormEntity(params, \"UTF-8\"));\n\t\t\tSystem.out.println(str);\n\t\t\t//创建带参数get请求(示例)\n\t\t\tHttpGet httpGet = new HttpGet(url+\"?\"+str);\n\n\t\t\t// 创建不带参数get请求\n\t\t\tHttpGet httpget = new HttpGet(url);\n\t\t\tSystem.out.println(\"executing get request \" + httpget.getURI());\n\t\t\t// 执行get请求.\n\t\t\tCloseableHttpResponse response = httpclient.execute(httpget);\n\t\t\ttry {\n\t\t\t\t// 获取响应实体\n\t\t\t\tHttpEntity entity = response.getEntity();\n\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t// 打印响应状态\n\t\t\t\tSystem.out.println(response.getStatusLine());\n\t\t\t\tif (entity != null) {\n\t\t\t\t\t// 打印响应内容长度\n\t\t\t\t\tSystem.out.println(\"Response content length: \" + entity.getContentLength());\n\t\t\t\t\t// 打印响应内容\n\t\t\t\t\tSystem.out.println(\"Response content: \" + EntityUtils.toString(entity));\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"------------------------------------\");\n\t\t\t} finally {\n\t\t\t\tresponse.close();\n\t\t\t}\n\t\t} catch (ClientProtocolException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\t// 关闭连接,释放资源\n\t\t\ttry {\n\t\t\t\thttpclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n\n\n","source":"_posts/HttpClient学习记录.md","raw":"---\ntitle: HttpClient学习记录\ncomment: true\ndate: 2017-10-14 16:55:10\ntags: [HttpClient, Java]\n---\n\n# 一、前期准备\n> [HttpClient](https://hc.apache.org/httpcomponents-client-ga/index.html) is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reusable components for client-side authentication, HTTP state management, and HTTP connection management. HttpComponents Client is a successor of and replacement for [Commons HttpClient 3.x](http://hc.apache.org/httpclient-legacy/index.html). Users of Commons HttpClient are strongly encouraged to upgrade.\n\n**总结:** HttpClient 是apache 组织下面的一个用于处理HTTP 请求和响应的开源工具。\n\n需要的jar包:\n\n\thttpclient-4.3.6.jar、httpcore-4.3.3.jar、httpmime-4.3.6.jar、commons-codec-1.6.jar。\n\n# 二、操作步骤\n\n由于HttpClient从4.X开始,基本的get/post 等http请求实现方式与之前版本的写法有很大的差异,所以在此总结一下4.X版本之后的官方推荐写法。\n\n**操作顺序:** \n\n1. 创建CloseableHttpClient对象\n2. 创建请求方法实例:HttpGet/HttpPost\n3. (可选)需要请求参数时\n - HttpGet/HttpPost都可以使用setParams方法添加参数(deprecated 已过时)\n - 对于HttpPost方法可以使用SetEntity(HttpEntity entity)参加请求参数\n - 对于HttpGet方法,可以通过拼接url的方式添加请求参数\n4. 调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。\n5. 通过CloseableHttpResponse对象获取服务器的响应内容。\n6. 释放连接。无论执行方法是否成功,都必须释放连接\n\n# 三、代码实例\n\n```java\npackage com.learn.http;\n\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.ParseException;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.util.EntityUtils;\n\npublic class HttpSend {\n\n\tpublic static void main(String[] args) {\n\t\t// post请求百度地址,返回404\n\t\tnew HttpSend().post(\"http://www.baidu.com\");\n\t\tnew HttpSend().get(\"http://www.baidu.com\");\n\t}\n\n\t/**\n\t * 发送 post请求访问本地应用并根据传递参数不同返回不同结果\n\t */\n\tpublic void post(String url) {\n\n\t\t// 创建默认的httpClient实例.\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault();\n\t\t// 创建httppost\n\t\tHttpPost httppost = new HttpPost(url);\n\t\t\n\t\t// 创建参数队列\n\t\tList<NameValuePair> formparams = new ArrayList<NameValuePair>();\n\t\t// 添加参数\n\t\t// formparams.add(new BasicNameValuePair(\"gg\", \"1\"));\n\n\t\tUrlEncodedFormEntity uefEntity;\n\t\ttry {\n\t\t\t//传入空参数,创建实体对象\n\t\t\tuefEntity = new UrlEncodedFormEntity(formparams, \"UTF-8\");\n\t\t\t//设置post对象的实体对象\n\t\t\thttppost.setEntity(uefEntity);\n\t\t\tSystem.out.println(\"executing post request \" + httppost.getURI());\n\t\t\t//执行post请求\n\t\t\tCloseableHttpResponse response = httpclient.execute(httppost);\n\t\t\ttry {\n\t\t\t\t//获取请求结果对象\n\t\t\t\tHttpEntity entity = response.getEntity();\n\t\t\t\tif (entity != null) {\n\t\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t\tSystem.out.println(\"Response content: \" + EntityUtils.toString(entity));\n\t\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tresponse.close();\n\t\t\t}\n\t\t} catch (ClientProtocolException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (UnsupportedEncodingException e1) {\n\t\t\te1.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\t// 关闭连接,释放资源\n\t\t\ttry {\n\t\t\t\thttpclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 发送 get请求\n\t */\n\tpublic void get(String url) {\n\n\t\t// 创建默认的httpClient实例.\n\t\tCloseableHttpClient httpclient = HttpClients.createDefault();\n\t\t\n\t\ttry {\n\t\t\t// 封装请求参数\n\t\t\tList<NameValuePair> params = new ArrayList<>();\n\t\t\tparams.add(new BasicNameValuePair(\"cityEname\", \"henan\"));\n\t\t\t//转换为键值对\n\t\t\tString str = EntityUtils.toString(new UrlEncodedFormEntity(params, \"UTF-8\"));\n\t\t\tSystem.out.println(str);\n\t\t\t//创建带参数get请求(示例)\n\t\t\tHttpGet httpGet = new HttpGet(url+\"?\"+str);\n\n\t\t\t// 创建不带参数get请求\n\t\t\tHttpGet httpget = new HttpGet(url);\n\t\t\tSystem.out.println(\"executing get request \" + httpget.getURI());\n\t\t\t// 执行get请求.\n\t\t\tCloseableHttpResponse response = httpclient.execute(httpget);\n\t\t\ttry {\n\t\t\t\t// 获取响应实体\n\t\t\t\tHttpEntity entity = response.getEntity();\n\t\t\t\tSystem.out.println(\"--------------------------------------\");\n\t\t\t\t// 打印响应状态\n\t\t\t\tSystem.out.println(response.getStatusLine());\n\t\t\t\tif (entity != null) {\n\t\t\t\t\t// 打印响应内容长度\n\t\t\t\t\tSystem.out.println(\"Response content length: \" + entity.getContentLength());\n\t\t\t\t\t// 打印响应内容\n\t\t\t\t\tSystem.out.println(\"Response content: \" + EntityUtils.toString(entity));\n\t\t\t\t}\n\t\t\t\tSystem.out.println(\"------------------------------------\");\n\t\t\t} finally {\n\t\t\t\tresponse.close();\n\t\t\t}\n\t\t} catch (ClientProtocolException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t} catch (IOException e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\t// 关闭连接,释放资源\n\t\t\ttry {\n\t\t\t\thttpclient.close();\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n}\n```\n\n\n\n","slug":"HttpClient学习记录","published":1,"updated":"2017-10-14T12:25:12.749Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k5r0003wsv7bodrzlux","content":"<h1 id=\"一、前期准备\"><a href=\"#一、前期准备\" class=\"headerlink\" title=\"一、前期准备\"></a>一、前期准备</h1><blockquote>\n<p><a href=\"https://hc.apache.org/httpcomponents-client-ga/index.html\" target=\"_blank\" rel=\"external\">HttpClient</a> is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reusable components for client-side authentication, HTTP state management, and HTTP connection management. HttpComponents Client is a successor of and replacement for <a href=\"http://hc.apache.org/httpclient-legacy/index.html\" target=\"_blank\" rel=\"external\">Commons HttpClient 3.x</a>. Users of Commons HttpClient are strongly encouraged to upgrade.</p>\n</blockquote>\n<p><strong>总结:</strong> HttpClient 是apache 组织下面的一个用于处理HTTP 请求和响应的开源工具。</p>\n<p>需要的jar包:</p>\n<p> httpclient-4.3.6.jar、httpcore-4.3.3.jar、httpmime-4.3.6.jar、commons-codec-1.6.jar。</p>\n<h1 id=\"二、操作步骤\"><a href=\"#二、操作步骤\" class=\"headerlink\" title=\"二、操作步骤\"></a>二、操作步骤</h1><p>由于HttpClient从4.X开始,基本的get/post 等http请求实现方式与之前版本的写法有很大的差异,所以在此总结一下4.X版本之后的官方推荐写法。</p>\n<p><strong>操作顺序:</strong> </p>\n<ol>\n<li>创建CloseableHttpClient对象</li>\n<li>创建请求方法实例:HttpGet/HttpPost</li>\n<li>(可选)需要请求参数时<ul>\n<li>HttpGet/HttpPost都可以使用setParams方法添加参数(deprecated 已过时)</li>\n<li>对于HttpPost方法可以使用SetEntity(HttpEntity entity)参加请求参数</li>\n<li>对于HttpGet方法,可以通过拼接url的方式添加请求参数</li>\n</ul>\n</li>\n<li>调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。</li>\n<li>通过CloseableHttpResponse对象获取服务器的响应内容。</li>\n<li>释放连接。无论执行方法是否成功,都必须释放连接</li>\n</ol>\n<h1 id=\"三、代码实例\"><a href=\"#三、代码实例\" class=\"headerlink\" title=\"三、代码实例\"></a>三、代码实例</h1><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.learn.http;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> java.io.IOException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.UnsupportedEncodingException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.ArrayList;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.List;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.HttpEntity;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.NameValuePair;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.ParseException;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.ClientProtocolException;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.entity.UrlEncodedFormEntity;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.CloseableHttpResponse;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.HttpGet;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.HttpPost;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.impl.client.CloseableHttpClient;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.impl.client.HttpClients;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.message.BasicNameValuePair;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.util.EntityUtils;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">HttpSend</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\">\t\t<span class=\"comment\">// post请求百度地址,返回404</span></div><div class=\"line\">\t\t<span class=\"keyword\">new</span> HttpSend().post(<span class=\"string\">\"http://www.baidu.com\"</span>);</div><div class=\"line\">\t\t<span class=\"keyword\">new</span> HttpSend().get(<span class=\"string\">\"http://www.baidu.com\"</span>);</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"comment\">/**</span></div><div class=\"line\">\t * 发送 post请求访问本地应用并根据传递参数不同返回不同结果</div><div class=\"line\">\t */</div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">post</span><span class=\"params\">(String url)</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t\t<span class=\"comment\">// 创建默认的httpClient实例.</span></div><div class=\"line\">\t\tCloseableHttpClient httpclient = HttpClients.createDefault();</div><div class=\"line\">\t\t<span class=\"comment\">// 创建httppost</span></div><div class=\"line\">\t\tHttpPost httppost = <span class=\"keyword\">new</span> HttpPost(url);</div><div class=\"line\">\t\t</div><div class=\"line\">\t\t<span class=\"comment\">// 创建参数队列</span></div><div class=\"line\">\t\tList<NameValuePair> formparams = <span class=\"keyword\">new</span> ArrayList<NameValuePair>();</div><div class=\"line\">\t\t<span class=\"comment\">// 添加参数</span></div><div class=\"line\">\t\t<span class=\"comment\">// formparams.add(new BasicNameValuePair(\"gg\", \"1\"));</span></div><div class=\"line\"></div><div class=\"line\">\t\tUrlEncodedFormEntity uefEntity;</div><div class=\"line\">\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">//传入空参数,创建实体对象</span></div><div class=\"line\">\t\t\tuefEntity = <span class=\"keyword\">new</span> UrlEncodedFormEntity(formparams, <span class=\"string\">\"UTF-8\"</span>);</div><div class=\"line\">\t\t\t<span class=\"comment\">//设置post对象的实体对象</span></div><div class=\"line\">\t\t\thttppost.setEntity(uefEntity);</div><div class=\"line\">\t\t\tSystem.out.println(<span class=\"string\">\"executing post request \"</span> + httppost.getURI());</div><div class=\"line\">\t\t\t<span class=\"comment\">//执行post请求</span></div><div class=\"line\">\t\t\tCloseableHttpResponse response = httpclient.execute(httppost);</div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\t<span class=\"comment\">//获取请求结果对象</span></div><div class=\"line\">\t\t\t\tHttpEntity entity = response.getEntity();</div><div class=\"line\">\t\t\t\t<span class=\"keyword\">if</span> (entity != <span class=\"keyword\">null</span>) {</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content: \"</span> + EntityUtils.toString(entity));</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t}</div><div class=\"line\">\t\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t\tresponse.close();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ClientProtocolException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (UnsupportedEncodingException e1) {</div><div class=\"line\">\t\t\te1.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 关闭连接,释放资源</span></div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\thttpclient.close();</div><div class=\"line\">\t\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\t\te.printStackTrace();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"comment\">/**</span></div><div class=\"line\">\t * 发送 get请求</div><div class=\"line\">\t */</div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">get</span><span class=\"params\">(String url)</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t\t<span class=\"comment\">// 创建默认的httpClient实例.</span></div><div class=\"line\">\t\tCloseableHttpClient httpclient = HttpClients.createDefault();</div><div class=\"line\">\t\t</div><div class=\"line\">\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 封装请求参数</span></div><div class=\"line\">\t\t\tList<NameValuePair> params = <span class=\"keyword\">new</span> ArrayList<>();</div><div class=\"line\">\t\t\tparams.add(<span class=\"keyword\">new</span> BasicNameValuePair(<span class=\"string\">\"cityEname\"</span>, <span class=\"string\">\"henan\"</span>));</div><div class=\"line\">\t\t\t<span class=\"comment\">//转换为键值对</span></div><div class=\"line\">\t\t\tString str = EntityUtils.toString(<span class=\"keyword\">new</span> UrlEncodedFormEntity(params, <span class=\"string\">\"UTF-8\"</span>));</div><div class=\"line\">\t\t\tSystem.out.println(str);</div><div class=\"line\">\t\t\t<span class=\"comment\">//创建带参数get请求(示例)</span></div><div class=\"line\">\t\t\tHttpGet httpGet = <span class=\"keyword\">new</span> HttpGet(url+<span class=\"string\">\"?\"</span>+str);</div><div class=\"line\"></div><div class=\"line\">\t\t\t<span class=\"comment\">// 创建不带参数get请求</span></div><div class=\"line\">\t\t\tHttpGet httpget = <span class=\"keyword\">new</span> HttpGet(url);</div><div class=\"line\">\t\t\tSystem.out.println(<span class=\"string\">\"executing get request \"</span> + httpget.getURI());</div><div class=\"line\">\t\t\t<span class=\"comment\">// 执行get请求.</span></div><div class=\"line\">\t\t\tCloseableHttpResponse response = httpclient.execute(httpget);</div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\t<span class=\"comment\">// 获取响应实体</span></div><div class=\"line\">\t\t\t\tHttpEntity entity = response.getEntity();</div><div class=\"line\">\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t<span class=\"comment\">// 打印响应状态</span></div><div class=\"line\">\t\t\t\tSystem.out.println(response.getStatusLine());</div><div class=\"line\">\t\t\t\t<span class=\"keyword\">if</span> (entity != <span class=\"keyword\">null</span>) {</div><div class=\"line\">\t\t\t\t\t<span class=\"comment\">// 打印响应内容长度</span></div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content length: \"</span> + entity.getContentLength());</div><div class=\"line\">\t\t\t\t\t<span class=\"comment\">// 打印响应内容</span></div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content: \"</span> + EntityUtils.toString(entity));</div><div class=\"line\">\t\t\t\t}</div><div class=\"line\">\t\t\t\tSystem.out.println(<span class=\"string\">\"------------------------------------\"</span>);</div><div class=\"line\">\t\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t\tresponse.close();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ClientProtocolException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ParseException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 关闭连接,释放资源</span></div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\thttpclient.close();</div><div class=\"line\">\t\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\t\te.printStackTrace();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n","excerpt":"","more":"<h1 id=\"一、前期准备\"><a href=\"#一、前期准备\" class=\"headerlink\" title=\"一、前期准备\"></a>一、前期准备</h1><blockquote>\n<p><a href=\"https://hc.apache.org/httpcomponents-client-ga/index.html\">HttpClient</a> is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reusable components for client-side authentication, HTTP state management, and HTTP connection management. HttpComponents Client is a successor of and replacement for <a href=\"http://hc.apache.org/httpclient-legacy/index.html\">Commons HttpClient 3.x</a>. Users of Commons HttpClient are strongly encouraged to upgrade.</p>\n</blockquote>\n<p><strong>总结:</strong> HttpClient 是apache 组织下面的一个用于处理HTTP 请求和响应的开源工具。</p>\n<p>需要的jar包:</p>\n<p> httpclient-4.3.6.jar、httpcore-4.3.3.jar、httpmime-4.3.6.jar、commons-codec-1.6.jar。</p>\n<h1 id=\"二、操作步骤\"><a href=\"#二、操作步骤\" class=\"headerlink\" title=\"二、操作步骤\"></a>二、操作步骤</h1><p>由于HttpClient从4.X开始,基本的get/post 等http请求实现方式与之前版本的写法有很大的差异,所以在此总结一下4.X版本之后的官方推荐写法。</p>\n<p><strong>操作顺序:</strong> </p>\n<ol>\n<li>创建CloseableHttpClient对象</li>\n<li>创建请求方法实例:HttpGet/HttpPost</li>\n<li>(可选)需要请求参数时<ul>\n<li>HttpGet/HttpPost都可以使用setParams方法添加参数(deprecated 已过时)</li>\n<li>对于HttpPost方法可以使用SetEntity(HttpEntity entity)参加请求参数</li>\n<li>对于HttpGet方法,可以通过拼接url的方式添加请求参数</li>\n</ul>\n</li>\n<li>调用CloseableHttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个CloseableHttpResponse。</li>\n<li>通过CloseableHttpResponse对象获取服务器的响应内容。</li>\n<li>释放连接。无论执行方法是否成功,都必须释放连接</li>\n</ol>\n<h1 id=\"三、代码实例\"><a href=\"#三、代码实例\" class=\"headerlink\" title=\"三、代码实例\"></a>三、代码实例</h1><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div><div class=\"line\">88</div><div class=\"line\">89</div><div class=\"line\">90</div><div class=\"line\">91</div><div class=\"line\">92</div><div class=\"line\">93</div><div class=\"line\">94</div><div class=\"line\">95</div><div class=\"line\">96</div><div class=\"line\">97</div><div class=\"line\">98</div><div class=\"line\">99</div><div class=\"line\">100</div><div class=\"line\">101</div><div class=\"line\">102</div><div class=\"line\">103</div><div class=\"line\">104</div><div class=\"line\">105</div><div class=\"line\">106</div><div class=\"line\">107</div><div class=\"line\">108</div><div class=\"line\">109</div><div class=\"line\">110</div><div class=\"line\">111</div><div class=\"line\">112</div><div class=\"line\">113</div><div class=\"line\">114</div><div class=\"line\">115</div><div class=\"line\">116</div><div class=\"line\">117</div><div class=\"line\">118</div><div class=\"line\">119</div><div class=\"line\">120</div><div class=\"line\">121</div><div class=\"line\">122</div><div class=\"line\">123</div><div class=\"line\">124</div><div class=\"line\">125</div><div class=\"line\">126</div><div class=\"line\">127</div><div class=\"line\">128</div><div class=\"line\">129</div><div class=\"line\">130</div><div class=\"line\">131</div><div class=\"line\">132</div><div class=\"line\">133</div><div class=\"line\">134</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.learn.http;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> java.io.IOException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.UnsupportedEncodingException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.ArrayList;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.List;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.HttpEntity;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.NameValuePair;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.ParseException;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.ClientProtocolException;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.entity.UrlEncodedFormEntity;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.CloseableHttpResponse;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.HttpGet;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.client.methods.HttpPost;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.impl.client.CloseableHttpClient;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.impl.client.HttpClients;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.message.BasicNameValuePair;</div><div class=\"line\"><span class=\"keyword\">import</span> org.apache.http.util.EntityUtils;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">HttpSend</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\">\t\t<span class=\"comment\">// post请求百度地址,返回404</span></div><div class=\"line\">\t\t<span class=\"keyword\">new</span> HttpSend().post(<span class=\"string\">\"http://www.baidu.com\"</span>);</div><div class=\"line\">\t\t<span class=\"keyword\">new</span> HttpSend().get(<span class=\"string\">\"http://www.baidu.com\"</span>);</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"comment\">/**</div><div class=\"line\">\t * 发送 post请求访问本地应用并根据传递参数不同返回不同结果</div><div class=\"line\">\t */</span></div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">post</span><span class=\"params\">(String url)</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t\t<span class=\"comment\">// 创建默认的httpClient实例.</span></div><div class=\"line\">\t\tCloseableHttpClient httpclient = HttpClients.createDefault();</div><div class=\"line\">\t\t<span class=\"comment\">// 创建httppost</span></div><div class=\"line\">\t\tHttpPost httppost = <span class=\"keyword\">new</span> HttpPost(url);</div><div class=\"line\">\t\t</div><div class=\"line\">\t\t<span class=\"comment\">// 创建参数队列</span></div><div class=\"line\">\t\tList<NameValuePair> formparams = <span class=\"keyword\">new</span> ArrayList<NameValuePair>();</div><div class=\"line\">\t\t<span class=\"comment\">// 添加参数</span></div><div class=\"line\">\t\t<span class=\"comment\">// formparams.add(new BasicNameValuePair(\"gg\", \"1\"));</span></div><div class=\"line\"></div><div class=\"line\">\t\tUrlEncodedFormEntity uefEntity;</div><div class=\"line\">\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">//传入空参数,创建实体对象</span></div><div class=\"line\">\t\t\tuefEntity = <span class=\"keyword\">new</span> UrlEncodedFormEntity(formparams, <span class=\"string\">\"UTF-8\"</span>);</div><div class=\"line\">\t\t\t<span class=\"comment\">//设置post对象的实体对象</span></div><div class=\"line\">\t\t\thttppost.setEntity(uefEntity);</div><div class=\"line\">\t\t\tSystem.out.println(<span class=\"string\">\"executing post request \"</span> + httppost.getURI());</div><div class=\"line\">\t\t\t<span class=\"comment\">//执行post请求</span></div><div class=\"line\">\t\t\tCloseableHttpResponse response = httpclient.execute(httppost);</div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\t<span class=\"comment\">//获取请求结果对象</span></div><div class=\"line\">\t\t\t\tHttpEntity entity = response.getEntity();</div><div class=\"line\">\t\t\t\t<span class=\"keyword\">if</span> (entity != <span class=\"keyword\">null</span>) {</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content: \"</span> + EntityUtils.toString(entity));</div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t}</div><div class=\"line\">\t\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t\tresponse.close();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ClientProtocolException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (UnsupportedEncodingException e1) {</div><div class=\"line\">\t\t\te1.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 关闭连接,释放资源</span></div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\thttpclient.close();</div><div class=\"line\">\t\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\t\te.printStackTrace();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t}</div><div class=\"line\"></div><div class=\"line\">\t<span class=\"comment\">/**</div><div class=\"line\">\t * 发送 get请求</div><div class=\"line\">\t */</span></div><div class=\"line\">\t<span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">get</span><span class=\"params\">(String url)</span> </span>{</div><div class=\"line\"></div><div class=\"line\">\t\t<span class=\"comment\">// 创建默认的httpClient实例.</span></div><div class=\"line\">\t\tCloseableHttpClient httpclient = HttpClients.createDefault();</div><div class=\"line\">\t\t</div><div class=\"line\">\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 封装请求参数</span></div><div class=\"line\">\t\t\tList<NameValuePair> params = <span class=\"keyword\">new</span> ArrayList<>();</div><div class=\"line\">\t\t\tparams.add(<span class=\"keyword\">new</span> BasicNameValuePair(<span class=\"string\">\"cityEname\"</span>, <span class=\"string\">\"henan\"</span>));</div><div class=\"line\">\t\t\t<span class=\"comment\">//转换为键值对</span></div><div class=\"line\">\t\t\tString str = EntityUtils.toString(<span class=\"keyword\">new</span> UrlEncodedFormEntity(params, <span class=\"string\">\"UTF-8\"</span>));</div><div class=\"line\">\t\t\tSystem.out.println(str);</div><div class=\"line\">\t\t\t<span class=\"comment\">//创建带参数get请求(示例)</span></div><div class=\"line\">\t\t\tHttpGet httpGet = <span class=\"keyword\">new</span> HttpGet(url+<span class=\"string\">\"?\"</span>+str);</div><div class=\"line\"></div><div class=\"line\">\t\t\t<span class=\"comment\">// 创建不带参数get请求</span></div><div class=\"line\">\t\t\tHttpGet httpget = <span class=\"keyword\">new</span> HttpGet(url);</div><div class=\"line\">\t\t\tSystem.out.println(<span class=\"string\">\"executing get request \"</span> + httpget.getURI());</div><div class=\"line\">\t\t\t<span class=\"comment\">// 执行get请求.</span></div><div class=\"line\">\t\t\tCloseableHttpResponse response = httpclient.execute(httpget);</div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\t<span class=\"comment\">// 获取响应实体</span></div><div class=\"line\">\t\t\t\tHttpEntity entity = response.getEntity();</div><div class=\"line\">\t\t\t\tSystem.out.println(<span class=\"string\">\"--------------------------------------\"</span>);</div><div class=\"line\">\t\t\t\t<span class=\"comment\">// 打印响应状态</span></div><div class=\"line\">\t\t\t\tSystem.out.println(response.getStatusLine());</div><div class=\"line\">\t\t\t\t<span class=\"keyword\">if</span> (entity != <span class=\"keyword\">null</span>) {</div><div class=\"line\">\t\t\t\t\t<span class=\"comment\">// 打印响应内容长度</span></div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content length: \"</span> + entity.getContentLength());</div><div class=\"line\">\t\t\t\t\t<span class=\"comment\">// 打印响应内容</span></div><div class=\"line\">\t\t\t\t\tSystem.out.println(<span class=\"string\">\"Response content: \"</span> + EntityUtils.toString(entity));</div><div class=\"line\">\t\t\t\t}</div><div class=\"line\">\t\t\t\tSystem.out.println(<span class=\"string\">\"------------------------------------\"</span>);</div><div class=\"line\">\t\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t\tresponse.close();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ClientProtocolException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (ParseException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\te.printStackTrace();</div><div class=\"line\">\t\t} <span class=\"keyword\">finally</span> {</div><div class=\"line\">\t\t\t<span class=\"comment\">// 关闭连接,释放资源</span></div><div class=\"line\">\t\t\t<span class=\"keyword\">try</span> {</div><div class=\"line\">\t\t\t\thttpclient.close();</div><div class=\"line\">\t\t\t} <span class=\"keyword\">catch</span> (IOException e) {</div><div class=\"line\">\t\t\t\te.printStackTrace();</div><div class=\"line\">\t\t\t}</div><div class=\"line\">\t\t}</div><div class=\"line\">\t}</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n"},{"title":"Web开发中前后端的模板引擎","comment":true,"date":"2017-05-23T08:45:12.000Z","_content":"\n最近在学习Node.js,所以想自己实践一个用Node做后端的小项目,过程中不可避免的涉及到了模板引擎的问题。但在选择模板引擎的时被五花八门的模板引擎迷了眼。搜索到的java使用的模板有velocity、FreeMarker,Node使用的模板引擎jade、Ejs、Swig等等,甚至连一直使用的Angular等前端开发框架也成了模板引擎?这让我陷入了深深地自我怀疑,现在就来看一下模板引擎到底是什么鬼。\n\n# 1. 模板引擎是什么?\n\n模板,就是指有固定的格式,可以生成多个实例的样板。\n\n代码中的模板就是几个变量,允许我们自己塞入数据。举个例子:\n\n``` javascript\n// 模板\nvar tpl = 'Hei, my name is <%name%>, and I\\'m <%age%> years old.';\n```\n\n``` javascript\nvar data = {\n \"name\": \"zproo\",\n \"age\": \"20\"\n};\nvar result = tplEngine(tpl, data); // 通过模板引擎将数据给到模板\n```\n\n这就是一个模板引擎干的事情。\n\n# 2. 模板引擎的意义\n\n## 2.1 后端模板引擎\n\n说模板引擎,要从后端说起。现在后端开发基本是MVC的架构模式。从Model层获取数据,然后将数据传到 View 层渲染(渲染成 HTML 文件),而 View 层,一般都会用到模板引擎。\n\n大体过程是这样的:\n\n![mvc](http://ortur5wom.bkt.clouddn.com/mvc.gif)\n\n### 2.1.1 传统方式的缺点\n\n后端模板引擎最常见的使用java之类的后端语言模板,这样做有利于 SEO,并且与前端请求接口的方式相比,少了个 HTTP 请求,理论上加载速度可能会稍微快些。其最大的问题就是模板文件的耦合度太高,出了问题谁都不想来解决,前端人员看不到数据,后端人员不懂页面。所以一般的后端都会写js。。不利于前后端分离,降低了开发效率。\n\n## 2.2 前端模板引擎\n\nAjax的出现使前后端的分离成为可能。后端专注于业务逻辑,给前端提供接口;而前端通过 AJAX 的方式向后端请求数据,然后动态的渲染页面。很好的解决了使用后端模板带来的前后端耦合问题。具体开发场景变成了这样:\n\n数据接口获得数据:\n\n``` javascript\n [{name: \"zproo\"}, {age: \"20\"}]\n```\n\n要渲染的页面结构:\n\n``` html\n<ul class=\"list\">\n <li>null</li>\n <li>null</li>\n</ul>\n```\n\n将数据应用到页面:\n\n``` javascript\n// 假设接口数据\nvar data = [{name: \"zproo\"}, {age: \"20\"}];\n\nvar str = \"\";\nstr += '<ul class=\"list\">';\n\nfor (var i = 0, len = data.length; i < len; i++) {\n if (i !== len - 1)\n str += \"<li>\" + data[i].name + \"</li>\";\n else\n str += \"<li>\" + data[i].age + \"</li>\";\n}\n\nstr += \"</ul>\";\ndocument.querySelector(\"div\").innerHTML = str;\n```\n\n出现了!传说中的拼串!!\n\n相信这么干过的都感受过拼串的绝望,当页面显示逻辑或数据复杂之后,你不出错算我输。前端模板引擎解决的就是这个问题。上面介绍过了模板的用法,如果用模板的话我们只需要在数据应该显示的地方设置好变量,而数据怎么应用到页面中的变量上去就是模板引擎的具体工作了。\n\n# 3. 前端模板引擎与前端框架的区别\n\n如果你看了我上面的介绍,并且你还使用过Angular和Vue这样的前端开发框架的话,肯定会觉得前端模板框架和Angular很像吧。是的,他们确实很像,至少在这部分实现的功能是挺像的。\n\nAngular中能够使用指令将数据双向绑定到显示页面上,可以说完全可以覆盖前端模板引擎的功能。但是Angular中双向数据绑定的实现原理肯定是跟模板引擎不同的,而且Angular中还包含MVC架构等很多的框架方面的思想,所以说跟模板引擎的区别还是很明显的。\n\n# 4. 前端框架能够取代模板引擎吗\n\n我上面说了Angular覆盖了前端模板引擎的功能,那我们能用Angular取代模板引擎吗?根据我现在的认知来说,其实是可以取代的。但是有一个我能想到的问题就是Angular这种大而全的前端框架在移动端设备上可能造成的性能问题,尤其是在比较低端的设备上,这也是Angular的一个问题。\n\n# 5.使用前端模板引擎有什么缺点\n\n缺点的话就是老生常谈的SEO问题了,毕竟爬虫只会抓取 HTML 代码,不会去渲染 JS。","source":"_posts/Web开发中前后端的模板引擎.md","raw":"---\ntitle: Web开发中前后端的模板引擎\ncomment: true\ndate: 2017-05-23 16:45:12\ntags: [jade,模板引擎,angualr,mvc,Nodejs]\n---\n\n最近在学习Node.js,所以想自己实践一个用Node做后端的小项目,过程中不可避免的涉及到了模板引擎的问题。但在选择模板引擎的时被五花八门的模板引擎迷了眼。搜索到的java使用的模板有velocity、FreeMarker,Node使用的模板引擎jade、Ejs、Swig等等,甚至连一直使用的Angular等前端开发框架也成了模板引擎?这让我陷入了深深地自我怀疑,现在就来看一下模板引擎到底是什么鬼。\n\n# 1. 模板引擎是什么?\n\n模板,就是指有固定的格式,可以生成多个实例的样板。\n\n代码中的模板就是几个变量,允许我们自己塞入数据。举个例子:\n\n``` javascript\n// 模板\nvar tpl = 'Hei, my name is <%name%>, and I\\'m <%age%> years old.';\n```\n\n``` javascript\nvar data = {\n \"name\": \"zproo\",\n \"age\": \"20\"\n};\nvar result = tplEngine(tpl, data); // 通过模板引擎将数据给到模板\n```\n\n这就是一个模板引擎干的事情。\n\n# 2. 模板引擎的意义\n\n## 2.1 后端模板引擎\n\n说模板引擎,要从后端说起。现在后端开发基本是MVC的架构模式。从Model层获取数据,然后将数据传到 View 层渲染(渲染成 HTML 文件),而 View 层,一般都会用到模板引擎。\n\n大体过程是这样的:\n\n![mvc](http://ortur5wom.bkt.clouddn.com/mvc.gif)\n\n### 2.1.1 传统方式的缺点\n\n后端模板引擎最常见的使用java之类的后端语言模板,这样做有利于 SEO,并且与前端请求接口的方式相比,少了个 HTTP 请求,理论上加载速度可能会稍微快些。其最大的问题就是模板文件的耦合度太高,出了问题谁都不想来解决,前端人员看不到数据,后端人员不懂页面。所以一般的后端都会写js。。不利于前后端分离,降低了开发效率。\n\n## 2.2 前端模板引擎\n\nAjax的出现使前后端的分离成为可能。后端专注于业务逻辑,给前端提供接口;而前端通过 AJAX 的方式向后端请求数据,然后动态的渲染页面。很好的解决了使用后端模板带来的前后端耦合问题。具体开发场景变成了这样:\n\n数据接口获得数据:\n\n``` javascript\n [{name: \"zproo\"}, {age: \"20\"}]\n```\n\n要渲染的页面结构:\n\n``` html\n<ul class=\"list\">\n <li>null</li>\n <li>null</li>\n</ul>\n```\n\n将数据应用到页面:\n\n``` javascript\n// 假设接口数据\nvar data = [{name: \"zproo\"}, {age: \"20\"}];\n\nvar str = \"\";\nstr += '<ul class=\"list\">';\n\nfor (var i = 0, len = data.length; i < len; i++) {\n if (i !== len - 1)\n str += \"<li>\" + data[i].name + \"</li>\";\n else\n str += \"<li>\" + data[i].age + \"</li>\";\n}\n\nstr += \"</ul>\";\ndocument.querySelector(\"div\").innerHTML = str;\n```\n\n出现了!传说中的拼串!!\n\n相信这么干过的都感受过拼串的绝望,当页面显示逻辑或数据复杂之后,你不出错算我输。前端模板引擎解决的就是这个问题。上面介绍过了模板的用法,如果用模板的话我们只需要在数据应该显示的地方设置好变量,而数据怎么应用到页面中的变量上去就是模板引擎的具体工作了。\n\n# 3. 前端模板引擎与前端框架的区别\n\n如果你看了我上面的介绍,并且你还使用过Angular和Vue这样的前端开发框架的话,肯定会觉得前端模板框架和Angular很像吧。是的,他们确实很像,至少在这部分实现的功能是挺像的。\n\nAngular中能够使用指令将数据双向绑定到显示页面上,可以说完全可以覆盖前端模板引擎的功能。但是Angular中双向数据绑定的实现原理肯定是跟模板引擎不同的,而且Angular中还包含MVC架构等很多的框架方面的思想,所以说跟模板引擎的区别还是很明显的。\n\n# 4. 前端框架能够取代模板引擎吗\n\n我上面说了Angular覆盖了前端模板引擎的功能,那我们能用Angular取代模板引擎吗?根据我现在的认知来说,其实是可以取代的。但是有一个我能想到的问题就是Angular这种大而全的前端框架在移动端设备上可能造成的性能问题,尤其是在比较低端的设备上,这也是Angular的一个问题。\n\n# 5.使用前端模板引擎有什么缺点\n\n缺点的话就是老生常谈的SEO问题了,毕竟爬虫只会抓取 HTML 代码,不会去渲染 JS。","slug":"Web开发中前后端的模板引擎","published":1,"updated":"2017-10-14T12:25:12.750Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k660006wsv7a6kh9wrx","content":"<p>最近在学习Node.js,所以想自己实践一个用Node做后端的小项目,过程中不可避免的涉及到了模板引擎的问题。但在选择模板引擎的时被五花八门的模板引擎迷了眼。搜索到的java使用的模板有velocity、FreeMarker,Node使用的模板引擎jade、Ejs、Swig等等,甚至连一直使用的Angular等前端开发框架也成了模板引擎?这让我陷入了深深地自我怀疑,现在就来看一下模板引擎到底是什么鬼。</p>\n<h1 id=\"1-模板引擎是什么?\"><a href=\"#1-模板引擎是什么?\" class=\"headerlink\" title=\"1. 模板引擎是什么?\"></a>1. 模板引擎是什么?</h1><p>模板,就是指有固定的格式,可以生成多个实例的样板。</p>\n<p>代码中的模板就是几个变量,允许我们自己塞入数据。举个例子:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 模板</span></div><div class=\"line\"><span class=\"keyword\">var</span> tpl = <span class=\"string\">'Hei, my name is <%name%>, and I\\'m <%age%> years old.'</span>;</div></pre></td></tr></table></figure>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">var</span> data = {</div><div class=\"line\"> <span class=\"string\">\"name\"</span>: <span class=\"string\">\"zproo\"</span>,</div><div class=\"line\"> <span class=\"string\">\"age\"</span>: <span class=\"string\">\"20\"</span></div><div class=\"line\">};</div><div class=\"line\"><span class=\"keyword\">var</span> result = tplEngine(tpl, data); <span class=\"comment\">// 通过模板引擎将数据给到模板</span></div></pre></td></tr></table></figure>\n<p>这就是一个模板引擎干的事情。</p>\n<h1 id=\"2-模板引擎的意义\"><a href=\"#2-模板引擎的意义\" class=\"headerlink\" title=\"2. 模板引擎的意义\"></a>2. 模板引擎的意义</h1><h2 id=\"2-1-后端模板引擎\"><a href=\"#2-1-后端模板引擎\" class=\"headerlink\" title=\"2.1 后端模板引擎\"></a>2.1 后端模板引擎</h2><p>说模板引擎,要从后端说起。现在后端开发基本是MVC的架构模式。从Model层获取数据,然后将数据传到 View 层渲染(渲染成 HTML 文件),而 View 层,一般都会用到模板引擎。</p>\n<p>大体过程是这样的:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/mvc.gif\" alt=\"mvc\"></p>\n<h3 id=\"2-1-1-传统方式的缺点\"><a href=\"#2-1-1-传统方式的缺点\" class=\"headerlink\" title=\"2.1.1 传统方式的缺点\"></a>2.1.1 传统方式的缺点</h3><p>后端模板引擎最常见的使用java之类的后端语言模板,这样做有利于 SEO,并且与前端请求接口的方式相比,少了个 HTTP 请求,理论上加载速度可能会稍微快些。其最大的问题就是模板文件的耦合度太高,出了问题谁都不想来解决,前端人员看不到数据,后端人员不懂页面。所以一般的后端都会写js。。不利于前后端分离,降低了开发效率。</p>\n<h2 id=\"2-2-前端模板引擎\"><a href=\"#2-2-前端模板引擎\" class=\"headerlink\" title=\"2.2 前端模板引擎\"></a>2.2 前端模板引擎</h2><p>Ajax的出现使前后端的分离成为可能。后端专注于业务逻辑,给前端提供接口;而前端通过 AJAX 的方式向后端请求数据,然后动态的渲染页面。很好的解决了使用后端模板带来的前后端耦合问题。具体开发场景变成了这样:</p>\n<p>数据接口获得数据:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">[{<span class=\"attr\">name</span>: <span class=\"string\">\"zproo\"</span>}, {<span class=\"attr\">age</span>: <span class=\"string\">\"20\"</span>}]</div></pre></td></tr></table></figure>\n<p>要渲染的页面结构:</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">ul</span> <span class=\"attr\">class</span>=<span class=\"string\">\"list\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">li</span>></span>null<span class=\"tag\"></<span class=\"name\">li</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">li</span>></span>null<span class=\"tag\"></<span class=\"name\">li</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">ul</span>></span></div></pre></td></tr></table></figure>\n<p>将数据应用到页面:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 假设接口数据</span></div><div class=\"line\"><span class=\"keyword\">var</span> data = [{<span class=\"attr\">name</span>: <span class=\"string\">\"zproo\"</span>}, {<span class=\"attr\">age</span>: <span class=\"string\">\"20\"</span>}];</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">var</span> str = <span class=\"string\">\"\"</span>;</div><div class=\"line\">str += <span class=\"string\">'<ul class=\"list\">'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> i = <span class=\"number\">0</span>, len = data.length; i < len; i++) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (i !== len - <span class=\"number\">1</span>)</div><div class=\"line\"> str += <span class=\"string\">\"<li>\"</span> + data[i].name + <span class=\"string\">\"</li>\"</span>;</div><div class=\"line\"> <span class=\"keyword\">else</span></div><div class=\"line\"> str += <span class=\"string\">\"<li>\"</span> + data[i].age + <span class=\"string\">\"</li>\"</span>;</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\">str += <span class=\"string\">\"</ul>\"</span>;</div><div class=\"line\"><span class=\"built_in\">document</span>.querySelector(<span class=\"string\">\"div\"</span>).innerHTML = str;</div></pre></td></tr></table></figure>\n<p>出现了!传说中的拼串!!</p>\n<p>相信这么干过的都感受过拼串的绝望,当页面显示逻辑或数据复杂之后,你不出错算我输。前端模板引擎解决的就是这个问题。上面介绍过了模板的用法,如果用模板的话我们只需要在数据应该显示的地方设置好变量,而数据怎么应用到页面中的变量上去就是模板引擎的具体工作了。</p>\n<h1 id=\"3-前端模板引擎与前端框架的区别\"><a href=\"#3-前端模板引擎与前端框架的区别\" class=\"headerlink\" title=\"3. 前端模板引擎与前端框架的区别\"></a>3. 前端模板引擎与前端框架的区别</h1><p>如果你看了我上面的介绍,并且你还使用过Angular和Vue这样的前端开发框架的话,肯定会觉得前端模板框架和Angular很像吧。是的,他们确实很像,至少在这部分实现的功能是挺像的。</p>\n<p>Angular中能够使用指令将数据双向绑定到显示页面上,可以说完全可以覆盖前端模板引擎的功能。但是Angular中双向数据绑定的实现原理肯定是跟模板引擎不同的,而且Angular中还包含MVC架构等很多的框架方面的思想,所以说跟模板引擎的区别还是很明显的。</p>\n<h1 id=\"4-前端框架能够取代模板引擎吗\"><a href=\"#4-前端框架能够取代模板引擎吗\" class=\"headerlink\" title=\"4. 前端框架能够取代模板引擎吗\"></a>4. 前端框架能够取代模板引擎吗</h1><p>我上面说了Angular覆盖了前端模板引擎的功能,那我们能用Angular取代模板引擎吗?根据我现在的认知来说,其实是可以取代的。但是有一个我能想到的问题就是Angular这种大而全的前端框架在移动端设备上可能造成的性能问题,尤其是在比较低端的设备上,这也是Angular的一个问题。</p>\n<h1 id=\"5-使用前端模板引擎有什么缺点\"><a href=\"#5-使用前端模板引擎有什么缺点\" class=\"headerlink\" title=\"5.使用前端模板引擎有什么缺点\"></a>5.使用前端模板引擎有什么缺点</h1><p>缺点的话就是老生常谈的SEO问题了,毕竟爬虫只会抓取 HTML 代码,不会去渲染 JS。</p>\n","excerpt":"","more":"<p>最近在学习Node.js,所以想自己实践一个用Node做后端的小项目,过程中不可避免的涉及到了模板引擎的问题。但在选择模板引擎的时被五花八门的模板引擎迷了眼。搜索到的java使用的模板有velocity、FreeMarker,Node使用的模板引擎jade、Ejs、Swig等等,甚至连一直使用的Angular等前端开发框架也成了模板引擎?这让我陷入了深深地自我怀疑,现在就来看一下模板引擎到底是什么鬼。</p>\n<h1 id=\"1-模板引擎是什么?\"><a href=\"#1-模板引擎是什么?\" class=\"headerlink\" title=\"1. 模板引擎是什么?\"></a>1. 模板引擎是什么?</h1><p>模板,就是指有固定的格式,可以生成多个实例的样板。</p>\n<p>代码中的模板就是几个变量,允许我们自己塞入数据。举个例子:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 模板</span></div><div class=\"line\"><span class=\"keyword\">var</span> tpl = <span class=\"string\">'Hei, my name is <%name%>, and I\\'m <%age%> years old.'</span>;</div></pre></td></tr></table></figure>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">var</span> data = {</div><div class=\"line\"> <span class=\"string\">\"name\"</span>: <span class=\"string\">\"zproo\"</span>,</div><div class=\"line\"> <span class=\"string\">\"age\"</span>: <span class=\"string\">\"20\"</span></div><div class=\"line\">};</div><div class=\"line\"><span class=\"keyword\">var</span> result = tplEngine(tpl, data); <span class=\"comment\">// 通过模板引擎将数据给到模板</span></div></pre></td></tr></table></figure>\n<p>这就是一个模板引擎干的事情。</p>\n<h1 id=\"2-模板引擎的意义\"><a href=\"#2-模板引擎的意义\" class=\"headerlink\" title=\"2. 模板引擎的意义\"></a>2. 模板引擎的意义</h1><h2 id=\"2-1-后端模板引擎\"><a href=\"#2-1-后端模板引擎\" class=\"headerlink\" title=\"2.1 后端模板引擎\"></a>2.1 后端模板引擎</h2><p>说模板引擎,要从后端说起。现在后端开发基本是MVC的架构模式。从Model层获取数据,然后将数据传到 View 层渲染(渲染成 HTML 文件),而 View 层,一般都会用到模板引擎。</p>\n<p>大体过程是这样的:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/mvc.gif\" alt=\"mvc\"></p>\n<h3 id=\"2-1-1-传统方式的缺点\"><a href=\"#2-1-1-传统方式的缺点\" class=\"headerlink\" title=\"2.1.1 传统方式的缺点\"></a>2.1.1 传统方式的缺点</h3><p>后端模板引擎最常见的使用java之类的后端语言模板,这样做有利于 SEO,并且与前端请求接口的方式相比,少了个 HTTP 请求,理论上加载速度可能会稍微快些。其最大的问题就是模板文件的耦合度太高,出了问题谁都不想来解决,前端人员看不到数据,后端人员不懂页面。所以一般的后端都会写js。。不利于前后端分离,降低了开发效率。</p>\n<h2 id=\"2-2-前端模板引擎\"><a href=\"#2-2-前端模板引擎\" class=\"headerlink\" title=\"2.2 前端模板引擎\"></a>2.2 前端模板引擎</h2><p>Ajax的出现使前后端的分离成为可能。后端专注于业务逻辑,给前端提供接口;而前端通过 AJAX 的方式向后端请求数据,然后动态的渲染页面。很好的解决了使用后端模板带来的前后端耦合问题。具体开发场景变成了这样:</p>\n<p>数据接口获得数据:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">[{<span class=\"attr\">name</span>: <span class=\"string\">\"zproo\"</span>}, {<span class=\"attr\">age</span>: <span class=\"string\">\"20\"</span>}]</div></pre></td></tr></table></figure>\n<p>要渲染的页面结构:</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">ul</span> <span class=\"attr\">class</span>=<span class=\"string\">\"list\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">li</span>></span>null<span class=\"tag\"></<span class=\"name\">li</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">li</span>></span>null<span class=\"tag\"></<span class=\"name\">li</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">ul</span>></span></div></pre></td></tr></table></figure>\n<p>将数据应用到页面:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 假设接口数据</span></div><div class=\"line\"><span class=\"keyword\">var</span> data = [{<span class=\"attr\">name</span>: <span class=\"string\">\"zproo\"</span>}, {<span class=\"attr\">age</span>: <span class=\"string\">\"20\"</span>}];</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">var</span> str = <span class=\"string\">\"\"</span>;</div><div class=\"line\">str += <span class=\"string\">'<ul class=\"list\">'</span>;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> i = <span class=\"number\">0</span>, len = data.length; i < len; i++) {</div><div class=\"line\"> <span class=\"keyword\">if</span> (i !== len - <span class=\"number\">1</span>)</div><div class=\"line\"> str += <span class=\"string\">\"<li>\"</span> + data[i].name + <span class=\"string\">\"</li>\"</span>;</div><div class=\"line\"> <span class=\"keyword\">else</span></div><div class=\"line\"> str += <span class=\"string\">\"<li>\"</span> + data[i].age + <span class=\"string\">\"</li>\"</span>;</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\">str += <span class=\"string\">\"</ul>\"</span>;</div><div class=\"line\"><span class=\"built_in\">document</span>.querySelector(<span class=\"string\">\"div\"</span>).innerHTML = str;</div></pre></td></tr></table></figure>\n<p>出现了!传说中的拼串!!</p>\n<p>相信这么干过的都感受过拼串的绝望,当页面显示逻辑或数据复杂之后,你不出错算我输。前端模板引擎解决的就是这个问题。上面介绍过了模板的用法,如果用模板的话我们只需要在数据应该显示的地方设置好变量,而数据怎么应用到页面中的变量上去就是模板引擎的具体工作了。</p>\n<h1 id=\"3-前端模板引擎与前端框架的区别\"><a href=\"#3-前端模板引擎与前端框架的区别\" class=\"headerlink\" title=\"3. 前端模板引擎与前端框架的区别\"></a>3. 前端模板引擎与前端框架的区别</h1><p>如果你看了我上面的介绍,并且你还使用过Angular和Vue这样的前端开发框架的话,肯定会觉得前端模板框架和Angular很像吧。是的,他们确实很像,至少在这部分实现的功能是挺像的。</p>\n<p>Angular中能够使用指令将数据双向绑定到显示页面上,可以说完全可以覆盖前端模板引擎的功能。但是Angular中双向数据绑定的实现原理肯定是跟模板引擎不同的,而且Angular中还包含MVC架构等很多的框架方面的思想,所以说跟模板引擎的区别还是很明显的。</p>\n<h1 id=\"4-前端框架能够取代模板引擎吗\"><a href=\"#4-前端框架能够取代模板引擎吗\" class=\"headerlink\" title=\"4. 前端框架能够取代模板引擎吗\"></a>4. 前端框架能够取代模板引擎吗</h1><p>我上面说了Angular覆盖了前端模板引擎的功能,那我们能用Angular取代模板引擎吗?根据我现在的认知来说,其实是可以取代的。但是有一个我能想到的问题就是Angular这种大而全的前端框架在移动端设备上可能造成的性能问题,尤其是在比较低端的设备上,这也是Angular的一个问题。</p>\n<h1 id=\"5-使用前端模板引擎有什么缺点\"><a href=\"#5-使用前端模板引擎有什么缺点\" class=\"headerlink\" title=\"5.使用前端模板引擎有什么缺点\"></a>5.使用前端模板引擎有什么缺点</h1><p>缺点的话就是老生常谈的SEO问题了,毕竟爬虫只会抓取 HTML 代码,不会去渲染 JS。</p>\n"},{"title":"git bash修改主题配色","comment":true,"date":"2017-05-05T06:30:20.000Z","cover":"http://ortur5wom.bkt.clouddn.com/cover-bash.jpg","_content":"\n# 1.获取主题配置文件\n\n在git bash窗口点击右键,选择option选项。\n\n![11ScreenClip](http://ortur5wom.bkt.clouddn.com/bash1.png)\n\n进入`Options`窗口,可以看到looks标签下的`Theme`选择。\n\n![22ScreenClip](http://ortur5wom.bkt.clouddn.com/bash2.png)\n\n但是git bash默认的是没有主题供选择的。我们点击`Theme`下的`Color Schema Designer`按钮,此时我们会来到下面这个网站。\n\n你可以自定义喜欢的背景、文字为你喜欢的搭配,然后点击右上角的`Get Scheme`,这里我们选择`.minttyrc`类型\n\n![3ScreenClip](http://ortur5wom.bkt.clouddn.com/bash3.png)\n\n![44ScreenClip](http://ortur5wom.bkt.clouddn.com/bash4.png)\n\n此时你会获得如下的文件内容:\n\n![55ScreenClip](http://ortur5wom.bkt.clouddn.com/bash5.png)\n\n下面给出文字版:\n\n``` shell\nBackgroundColour=13,25,38\nForegroundColour=217,230,242\nCursorColour=217,230,242\nBlack=0,0,0\nBoldBlack=38,38,38\nRed=184,122,122\nBoldRed=219,189,189\nGreen=122,184,122\nBoldGreen=189,219,189\nYellow=184,184,122\nBoldYellow=219,219,189\nBlue=122,122,184\nBoldBlue=189,189,219\nMagenta=184,122,184\nBoldMagenta=219,189,219\nCyan=122,184,184\nBoldCyan=189,219,219\nWhite=217,217,217\nBoldWhite=255,255,255\n```\n\n(这是上面网站默认的主题配置,你可以直接使用)\n\n# 2.设置Git Bash主题\n\n好的,我们有了主题配置文件,现在我们来设置为Git Bash的主题。\n\n1. 打开git bash命令行(任意位置),输入如下命令,回车\n\n```shell\ncd ~\nvim .minttyrc\n```\n\n2. 进入vim编辑模式后,我们先按`Insert`键,即切换到“插入”状态。就可以通过上下左右移动光标,或空格、退格及回车等进行编辑内容了,和WINDOWS是一样的。我们删除原有内容,将刚才得到的`主题配置文件`复制到此处。\n ![66ScreenClip](http://ortur5wom.bkt.clouddn.com/bash6.png)\n3. 按键盘左上角的\"ESC\",左下角的插入状态消失。 然后这时,我们输入“冒号”,即\":\"(不需双引号),在下方会出现冒号,等待输入命令。再输入\"x\",即保存退出。(注意:在英文状态下进行输入)\n\n此时,重启Git Bash,你会发现主题配置已经生效!!\n\n\n\n","source":"_posts/git bash修改主题配色.md","raw":"---\ntitle: git bash修改主题配色\ncomment: true\ndate: 2017-05-05 14:30:20\ntags: [Git bash, Git, Scheme,Shell]\ncover: http://ortur5wom.bkt.clouddn.com/cover-bash.jpg\n---\n\n# 1.获取主题配置文件\n\n在git bash窗口点击右键,选择option选项。\n\n![11ScreenClip](http://ortur5wom.bkt.clouddn.com/bash1.png)\n\n进入`Options`窗口,可以看到looks标签下的`Theme`选择。\n\n![22ScreenClip](http://ortur5wom.bkt.clouddn.com/bash2.png)\n\n但是git bash默认的是没有主题供选择的。我们点击`Theme`下的`Color Schema Designer`按钮,此时我们会来到下面这个网站。\n\n你可以自定义喜欢的背景、文字为你喜欢的搭配,然后点击右上角的`Get Scheme`,这里我们选择`.minttyrc`类型\n\n![3ScreenClip](http://ortur5wom.bkt.clouddn.com/bash3.png)\n\n![44ScreenClip](http://ortur5wom.bkt.clouddn.com/bash4.png)\n\n此时你会获得如下的文件内容:\n\n![55ScreenClip](http://ortur5wom.bkt.clouddn.com/bash5.png)\n\n下面给出文字版:\n\n``` shell\nBackgroundColour=13,25,38\nForegroundColour=217,230,242\nCursorColour=217,230,242\nBlack=0,0,0\nBoldBlack=38,38,38\nRed=184,122,122\nBoldRed=219,189,189\nGreen=122,184,122\nBoldGreen=189,219,189\nYellow=184,184,122\nBoldYellow=219,219,189\nBlue=122,122,184\nBoldBlue=189,189,219\nMagenta=184,122,184\nBoldMagenta=219,189,219\nCyan=122,184,184\nBoldCyan=189,219,219\nWhite=217,217,217\nBoldWhite=255,255,255\n```\n\n(这是上面网站默认的主题配置,你可以直接使用)\n\n# 2.设置Git Bash主题\n\n好的,我们有了主题配置文件,现在我们来设置为Git Bash的主题。\n\n1. 打开git bash命令行(任意位置),输入如下命令,回车\n\n```shell\ncd ~\nvim .minttyrc\n```\n\n2. 进入vim编辑模式后,我们先按`Insert`键,即切换到“插入”状态。就可以通过上下左右移动光标,或空格、退格及回车等进行编辑内容了,和WINDOWS是一样的。我们删除原有内容,将刚才得到的`主题配置文件`复制到此处。\n ![66ScreenClip](http://ortur5wom.bkt.clouddn.com/bash6.png)\n3. 按键盘左上角的\"ESC\",左下角的插入状态消失。 然后这时,我们输入“冒号”,即\":\"(不需双引号),在下方会出现冒号,等待输入命令。再输入\"x\",即保存退出。(注意:在英文状态下进行输入)\n\n此时,重启Git Bash,你会发现主题配置已经生效!!\n\n\n\n","slug":"git bash修改主题配色","published":1,"updated":"2017-10-14T12:25:12.750Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k660008wsv71oh4iqhz","content":"<h1 id=\"1-获取主题配置文件\"><a href=\"#1-获取主题配置文件\" class=\"headerlink\" title=\"1.获取主题配置文件\"></a>1.获取主题配置文件</h1><p>在git bash窗口点击右键,选择option选项。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash1.png\" alt=\"11ScreenClip\"></p>\n<p>进入<code>Options</code>窗口,可以看到looks标签下的<code>Theme</code>选择。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash2.png\" alt=\"22ScreenClip\"></p>\n<p>但是git bash默认的是没有主题供选择的。我们点击<code>Theme</code>下的<code>Color Schema Designer</code>按钮,此时我们会来到下面这个网站。</p>\n<p>你可以自定义喜欢的背景、文字为你喜欢的搭配,然后点击右上角的<code>Get Scheme</code>,这里我们选择<code>.minttyrc</code>类型</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash3.png\" alt=\"3ScreenClip\"></p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash4.png\" alt=\"44ScreenClip\"></p>\n<p>此时你会获得如下的文件内容:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash5.png\" alt=\"55ScreenClip\"></p>\n<p>下面给出文字版:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\">BackgroundColour=13,25,38</div><div class=\"line\">ForegroundColour=217,230,242</div><div class=\"line\">CursorColour=217,230,242</div><div class=\"line\">Black=0,0,0</div><div class=\"line\">BoldBlack=38,38,38</div><div class=\"line\">Red=184,122,122</div><div class=\"line\">BoldRed=219,189,189</div><div class=\"line\">Green=122,184,122</div><div class=\"line\">BoldGreen=189,219,189</div><div class=\"line\">Yellow=184,184,122</div><div class=\"line\">BoldYellow=219,219,189</div><div class=\"line\">Blue=122,122,184</div><div class=\"line\">BoldBlue=189,189,219</div><div class=\"line\">Magenta=184,122,184</div><div class=\"line\">BoldMagenta=219,189,219</div><div class=\"line\">Cyan=122,184,184</div><div class=\"line\">BoldCyan=189,219,219</div><div class=\"line\">White=217,217,217</div><div class=\"line\">BoldWhite=255,255,255</div></pre></td></tr></table></figure>\n<p>(这是上面网站默认的主题配置,你可以直接使用)</p>\n<h1 id=\"2-设置Git-Bash主题\"><a href=\"#2-设置Git-Bash主题\" class=\"headerlink\" title=\"2.设置Git Bash主题\"></a>2.设置Git Bash主题</h1><p>好的,我们有了主题配置文件,现在我们来设置为Git Bash的主题。</p>\n<ol>\n<li>打开git bash命令行(任意位置),输入如下命令,回车</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">cd ~</div><div class=\"line\">vim .minttyrc</div></pre></td></tr></table></figure>\n<ol>\n<li>进入vim编辑模式后,我们先按<code>Insert</code>键,即切换到“插入”状态。就可以通过上下左右移动光标,或空格、退格及回车等进行编辑内容了,和WINDOWS是一样的。我们删除原有内容,将刚才得到的<code>主题配置文件</code>复制到此处。<br><img src=\"http://ortur5wom.bkt.clouddn.com/bash6.png\" alt=\"66ScreenClip\"></li>\n<li>按键盘左上角的”ESC”,左下角的插入状态消失。 然后这时,我们输入“冒号”,即”:”(不需双引号),在下方会出现冒号,等待输入命令。再输入”x”,即保存退出。(注意:在英文状态下进行输入)</li>\n</ol>\n<p>此时,重启Git Bash,你会发现主题配置已经生效!!</p>\n","excerpt":"","more":"<h1 id=\"1-获取主题配置文件\"><a href=\"#1-获取主题配置文件\" class=\"headerlink\" title=\"1.获取主题配置文件\"></a>1.获取主题配置文件</h1><p>在git bash窗口点击右键,选择option选项。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash1.png\" alt=\"11ScreenClip\"></p>\n<p>进入<code>Options</code>窗口,可以看到looks标签下的<code>Theme</code>选择。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash2.png\" alt=\"22ScreenClip\"></p>\n<p>但是git bash默认的是没有主题供选择的。我们点击<code>Theme</code>下的<code>Color Schema Designer</code>按钮,此时我们会来到下面这个网站。</p>\n<p>你可以自定义喜欢的背景、文字为你喜欢的搭配,然后点击右上角的<code>Get Scheme</code>,这里我们选择<code>.minttyrc</code>类型</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash3.png\" alt=\"3ScreenClip\"></p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash4.png\" alt=\"44ScreenClip\"></p>\n<p>此时你会获得如下的文件内容:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/bash5.png\" alt=\"55ScreenClip\"></p>\n<p>下面给出文字版:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div></pre></td><td class=\"code\"><pre><div class=\"line\">BackgroundColour=13,25,38</div><div class=\"line\">ForegroundColour=217,230,242</div><div class=\"line\">CursorColour=217,230,242</div><div class=\"line\">Black=0,0,0</div><div class=\"line\">BoldBlack=38,38,38</div><div class=\"line\">Red=184,122,122</div><div class=\"line\">BoldRed=219,189,189</div><div class=\"line\">Green=122,184,122</div><div class=\"line\">BoldGreen=189,219,189</div><div class=\"line\">Yellow=184,184,122</div><div class=\"line\">BoldYellow=219,219,189</div><div class=\"line\">Blue=122,122,184</div><div class=\"line\">BoldBlue=189,189,219</div><div class=\"line\">Magenta=184,122,184</div><div class=\"line\">BoldMagenta=219,189,219</div><div class=\"line\">Cyan=122,184,184</div><div class=\"line\">BoldCyan=189,219,219</div><div class=\"line\">White=217,217,217</div><div class=\"line\">BoldWhite=255,255,255</div></pre></td></tr></table></figure>\n<p>(这是上面网站默认的主题配置,你可以直接使用)</p>\n<h1 id=\"2-设置Git-Bash主题\"><a href=\"#2-设置Git-Bash主题\" class=\"headerlink\" title=\"2.设置Git Bash主题\"></a>2.设置Git Bash主题</h1><p>好的,我们有了主题配置文件,现在我们来设置为Git Bash的主题。</p>\n<ol>\n<li>打开git bash命令行(任意位置),输入如下命令,回车</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\">cd ~</div><div class=\"line\">vim .minttyrc</div></pre></td></tr></table></figure>\n<ol>\n<li>进入vim编辑模式后,我们先按<code>Insert</code>键,即切换到“插入”状态。就可以通过上下左右移动光标,或空格、退格及回车等进行编辑内容了,和WINDOWS是一样的。我们删除原有内容,将刚才得到的<code>主题配置文件</code>复制到此处。<br><img src=\"http://ortur5wom.bkt.clouddn.com/bash6.png\" alt=\"66ScreenClip\"></li>\n<li>按键盘左上角的”ESC”,左下角的插入状态消失。 然后这时,我们输入“冒号”,即”:”(不需双引号),在下方会出现冒号,等待输入命令。再输入”x”,即保存退出。(注意:在英文状态下进行输入)</li>\n</ol>\n<p>此时,重启Git Bash,你会发现主题配置已经生效!!</p>\n"},{"title":"Hello World","comment":true,"date":"2017-04-02T02:27:15.000Z","_content":"Welcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).\n\n## Quick Start\n\n### Create a new post\n\n``` bash\n$ hexo new \"My New Post\"\n```\n\nMore info: [Writing](https://hexo.io/docs/writing.html)\n\n### Run server\n\n``` bash\n$ hexo server\n```\n\nMore info: [Server](https://hexo.io/docs/server.html)\n\n### Generate static files\n\n``` bash\n$ hexo generate\n```\n\nMore info: [Generating](https://hexo.io/docs/generating.html)\n\n### Deploy to remote sites\n\n``` bash\n$ hexo deploy\n```\n\nMore info: [Deployment](https://hexo.io/docs/deployment.html)\n","source":"_posts/hello-world.md","raw":"---\ntitle: Hello World\ncomment: true\ndate: 2017-04-02 10:27:15\ntags: [Hexo, GitHub]\n---\nWelcome to [Hexo](https://hexo.io/)! This is your very first post. Check [documentation](https://hexo.io/docs/) for more info. If you get any problems when using Hexo, you can find the answer in [troubleshooting](https://hexo.io/docs/troubleshooting.html) or you can ask me on [GitHub](https://github.com/hexojs/hexo/issues).\n\n## Quick Start\n\n### Create a new post\n\n``` bash\n$ hexo new \"My New Post\"\n```\n\nMore info: [Writing](https://hexo.io/docs/writing.html)\n\n### Run server\n\n``` bash\n$ hexo server\n```\n\nMore info: [Server](https://hexo.io/docs/server.html)\n\n### Generate static files\n\n``` bash\n$ hexo generate\n```\n\nMore info: [Generating](https://hexo.io/docs/generating.html)\n\n### Deploy to remote sites\n\n``` bash\n$ hexo deploy\n```\n\nMore info: [Deployment](https://hexo.io/docs/deployment.html)\n","slug":"hello-world","published":1,"updated":"2017-05-11T12:27:08.337Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k6m000awsv7xccwnc3k","content":"<p>Welcome to <a href=\"https://hexo.io/\" target=\"_blank\" rel=\"external\">Hexo</a>! This is your very first post. Check <a href=\"https://hexo.io/docs/\" target=\"_blank\" rel=\"external\">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href=\"https://hexo.io/docs/troubleshooting.html\" target=\"_blank\" rel=\"external\">troubleshooting</a> or you can ask me on <a href=\"https://github.com/hexojs/hexo/issues\" target=\"_blank\" rel=\"external\">GitHub</a>.</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><h3 id=\"Create-a-new-post\"><a href=\"#Create-a-new-post\" class=\"headerlink\" title=\"Create a new post\"></a>Create a new post</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo new <span class=\"string\">\"My New Post\"</span></div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/writing.html\" target=\"_blank\" rel=\"external\">Writing</a></p>\n<h3 id=\"Run-server\"><a href=\"#Run-server\" class=\"headerlink\" title=\"Run server\"></a>Run server</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo server</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/server.html\" target=\"_blank\" rel=\"external\">Server</a></p>\n<h3 id=\"Generate-static-files\"><a href=\"#Generate-static-files\" class=\"headerlink\" title=\"Generate static files\"></a>Generate static files</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo generate</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/generating.html\" target=\"_blank\" rel=\"external\">Generating</a></p>\n<h3 id=\"Deploy-to-remote-sites\"><a href=\"#Deploy-to-remote-sites\" class=\"headerlink\" title=\"Deploy to remote sites\"></a>Deploy to remote sites</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo deploy</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/deployment.html\" target=\"_blank\" rel=\"external\">Deployment</a></p>\n","excerpt":"","more":"<p>Welcome to <a href=\"https://hexo.io/\">Hexo</a>! This is your very first post. Check <a href=\"https://hexo.io/docs/\">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href=\"https://hexo.io/docs/troubleshooting.html\">troubleshooting</a> or you can ask me on <a href=\"https://github.com/hexojs/hexo/issues\">GitHub</a>.</p>\n<h2 id=\"Quick-Start\"><a href=\"#Quick-Start\" class=\"headerlink\" title=\"Quick Start\"></a>Quick Start</h2><h3 id=\"Create-a-new-post\"><a href=\"#Create-a-new-post\" class=\"headerlink\" title=\"Create a new post\"></a>Create a new post</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo new <span class=\"string\">\"My New Post\"</span></div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/writing.html\">Writing</a></p>\n<h3 id=\"Run-server\"><a href=\"#Run-server\" class=\"headerlink\" title=\"Run server\"></a>Run server</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo server</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/server.html\">Server</a></p>\n<h3 id=\"Generate-static-files\"><a href=\"#Generate-static-files\" class=\"headerlink\" title=\"Generate static files\"></a>Generate static files</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo generate</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/generating.html\">Generating</a></p>\n<h3 id=\"Deploy-to-remote-sites\"><a href=\"#Deploy-to-remote-sites\" class=\"headerlink\" title=\"Deploy to remote sites\"></a>Deploy to remote sites</h3><figure class=\"highlight bash\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">$ hexo deploy</div></pre></td></tr></table></figure>\n<p>More info: <a href=\"https://hexo.io/docs/deployment.html\">Deployment</a></p>\n"},{"title":"java多线程编程(一)","comment":true,"date":"2017-10-30T07:39:10.000Z","_content":"\n# 1. 线程与进程\n\n1. 线程:进程中负责程序执行的执行单元。线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境\n2. 进程:执行中的程序,一个进程至少包含一个线程\n3. 单线程:程序中只存在一个线程,实际上主方法就是一个主线程\n4. 多线程:在一个程序中运行多个任务,目的是更好地使用CPU资源\n\n# 2. 一个线程的生命周期\n\n![线程的生命周期图](http://www.runoob.com/wp-content/uploads/2014/01/java-thread.jpg)\n\n- 创建(new)状态: 准备好了一个多线程的对象\n- 就绪(runnable)状态: 调用了`start()`方法, 等待CPU进行调度\n- 运行(running)状态: 如果就绪状态的线程获取 CPU 资源,就可以执行`run()`方法\n- 阻塞(blocked)状态: 暂时停止执行, 可能将资源交给其它线程使用。如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。\n- 终止(dead)状态: 线程销毁\n\n# 3. 线程的实现\n\n创建线程有两种主要的方式:\n\n- 通过实现 Runnable 接口;(推荐)\n- 通过继承 Thread 类本身;\n\n## 3.1 通过实现Runnable接口来创建线程\n\n实例:\n\n``` java\npublic class Main {\n public static void main(String args[]) {\n RunnableDemo R1 = new RunnableDemo( \"Thread-1\");\n Thread t1 = new Thread(R1);\n t1.start();\n\n RunnableDemo R2 = new RunnableDemo( \"Thread-2\");\n Thread t2 = new Thread(R2);\n t2.start();\n }\n}\nclass RunnableDemo implements Runnable {\n private String threadName;\n\n RunnableDemo( String name) {\n threadName = name;\n System.out.println(\"Creating \" + threadName );\n }\n\n public void run() {\n System.out.println(\"Running \" + threadName );\n try {\n for(int i = 4; i > 0; i--) {\n System.out.println(\"Thread: \" + threadName + \", \" + i);\n // 让线程睡眠一会\n Thread.sleep(50);\n }\n }catch (InterruptedException e) {\n System.out.println(\"Thread \" + threadName + \" interrupted.\");\n }\n System.out.println(\"Thread \" + threadName + \" exiting.\");\n }\n}\n```\n\n运行输出:\n\n``` \nCreating Thread-1\nCreating Thread-2\nRunning Thread-2\nThread: Thread-2, 4\nRunning Thread-1\nThread: Thread-1, 4\nThread: Thread-1, 3\nThread: Thread-2, 3\nThread: Thread-2, 2\nThread: Thread-1, 2\nThread: Thread-1, 1\nThread: Thread-2, 1\nThread Thread-2 exiting.\nThread Thread-1 exiting.\n```\n\n## 3.2 通过继承Thread来创建线程\n\n实例:\n\n``` java\npublic class Main {\n public static void main(String args[]) {\n ThreadDemo T1 = new ThreadDemo( \"Thread-1\");\n T1.start();\n\n ThreadDemo T2 = new ThreadDemo( \"Thread-2\");\n T2.start();\n }\n}\nclass ThreadDemo extends Thread {\n private String threadName;\n\n ThreadDemo( String name) {\n threadName = name;\n System.out.println(\"Creating \" + threadName );\n }\n\n public void run() {\n System.out.println(\"Running \" + threadName );\n try {\n for(int i = 4; i > 0; i--) {\n System.out.println(\"Thread: \" + threadName + \", \" + i);\n // 让线程睡醒一会\n Thread.sleep(50);\n }\n }catch (InterruptedException e) {\n System.out.println(\"Thread \" + threadName + \" interrupted.\");\n }\n System.out.println(\"Thread \" + threadName + \" exiting.\");\n }\n}\n\n```\n\n输出结果:\n\n```\nCreating Thread-1\nCreating Thread-2\nRunning Thread-1\nThread: Thread-1, 4\nRunning Thread-2\nThread: Thread-2, 4\nThread: Thread-1, 3\nThread: Thread-2, 3\nThread: Thread-2, 2\nThread: Thread-1, 2\nThread: Thread-2, 1\nThread: Thread-1, 1\nThread Thread-2 exiting.\nThread Thread-1 exiting.\n```\n\n## 3.3 为什么推荐使用Runnable接口的方式\n\nRunnable接口和Thread之间的联系:\n\n`public class Thread extends Object implements Runnable`\n\n我们发现Thread类其实也是Runnable接口的子类。\n\n在程序开发中只要是多线程都以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:\n\n- 避免点继承的局限,一个类可以继承多个接口。\n- 适合于资源的共享\n\n# 参考文献:\n\n- [Java 多线程与并发编程专题](https://www.ibm.com/developerworks/cn/java/j-concurrent/)\n- [Java多线程干货系列(1):Java多线程基础](http://www.importnew.com/21136.html)\n- [菜鸟教程:Java多线程编程](http://www.runoob.com/java/java-multithreading.html)\n- [Java中Runnable和Thread的区别](http://developer.51cto.com/art/201203/321042.htm)\n\n\n","source":"_posts/java多线程编程(一).md","raw":"---\ntitle: java多线程编程(一)\ncomment: true\ndate: 2017-10-30 15:39:10\ntags: [Java, 多线程]\n---\n\n# 1. 线程与进程\n\n1. 线程:进程中负责程序执行的执行单元。线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境\n2. 进程:执行中的程序,一个进程至少包含一个线程\n3. 单线程:程序中只存在一个线程,实际上主方法就是一个主线程\n4. 多线程:在一个程序中运行多个任务,目的是更好地使用CPU资源\n\n# 2. 一个线程的生命周期\n\n![线程的生命周期图](http://www.runoob.com/wp-content/uploads/2014/01/java-thread.jpg)\n\n- 创建(new)状态: 准备好了一个多线程的对象\n- 就绪(runnable)状态: 调用了`start()`方法, 等待CPU进行调度\n- 运行(running)状态: 如果就绪状态的线程获取 CPU 资源,就可以执行`run()`方法\n- 阻塞(blocked)状态: 暂时停止执行, 可能将资源交给其它线程使用。如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。\n- 终止(dead)状态: 线程销毁\n\n# 3. 线程的实现\n\n创建线程有两种主要的方式:\n\n- 通过实现 Runnable 接口;(推荐)\n- 通过继承 Thread 类本身;\n\n## 3.1 通过实现Runnable接口来创建线程\n\n实例:\n\n``` java\npublic class Main {\n public static void main(String args[]) {\n RunnableDemo R1 = new RunnableDemo( \"Thread-1\");\n Thread t1 = new Thread(R1);\n t1.start();\n\n RunnableDemo R2 = new RunnableDemo( \"Thread-2\");\n Thread t2 = new Thread(R2);\n t2.start();\n }\n}\nclass RunnableDemo implements Runnable {\n private String threadName;\n\n RunnableDemo( String name) {\n threadName = name;\n System.out.println(\"Creating \" + threadName );\n }\n\n public void run() {\n System.out.println(\"Running \" + threadName );\n try {\n for(int i = 4; i > 0; i--) {\n System.out.println(\"Thread: \" + threadName + \", \" + i);\n // 让线程睡眠一会\n Thread.sleep(50);\n }\n }catch (InterruptedException e) {\n System.out.println(\"Thread \" + threadName + \" interrupted.\");\n }\n System.out.println(\"Thread \" + threadName + \" exiting.\");\n }\n}\n```\n\n运行输出:\n\n``` \nCreating Thread-1\nCreating Thread-2\nRunning Thread-2\nThread: Thread-2, 4\nRunning Thread-1\nThread: Thread-1, 4\nThread: Thread-1, 3\nThread: Thread-2, 3\nThread: Thread-2, 2\nThread: Thread-1, 2\nThread: Thread-1, 1\nThread: Thread-2, 1\nThread Thread-2 exiting.\nThread Thread-1 exiting.\n```\n\n## 3.2 通过继承Thread来创建线程\n\n实例:\n\n``` java\npublic class Main {\n public static void main(String args[]) {\n ThreadDemo T1 = new ThreadDemo( \"Thread-1\");\n T1.start();\n\n ThreadDemo T2 = new ThreadDemo( \"Thread-2\");\n T2.start();\n }\n}\nclass ThreadDemo extends Thread {\n private String threadName;\n\n ThreadDemo( String name) {\n threadName = name;\n System.out.println(\"Creating \" + threadName );\n }\n\n public void run() {\n System.out.println(\"Running \" + threadName );\n try {\n for(int i = 4; i > 0; i--) {\n System.out.println(\"Thread: \" + threadName + \", \" + i);\n // 让线程睡醒一会\n Thread.sleep(50);\n }\n }catch (InterruptedException e) {\n System.out.println(\"Thread \" + threadName + \" interrupted.\");\n }\n System.out.println(\"Thread \" + threadName + \" exiting.\");\n }\n}\n\n```\n\n输出结果:\n\n```\nCreating Thread-1\nCreating Thread-2\nRunning Thread-1\nThread: Thread-1, 4\nRunning Thread-2\nThread: Thread-2, 4\nThread: Thread-1, 3\nThread: Thread-2, 3\nThread: Thread-2, 2\nThread: Thread-1, 2\nThread: Thread-2, 1\nThread: Thread-1, 1\nThread Thread-2 exiting.\nThread Thread-1 exiting.\n```\n\n## 3.3 为什么推荐使用Runnable接口的方式\n\nRunnable接口和Thread之间的联系:\n\n`public class Thread extends Object implements Runnable`\n\n我们发现Thread类其实也是Runnable接口的子类。\n\n在程序开发中只要是多线程都以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:\n\n- 避免点继承的局限,一个类可以继承多个接口。\n- 适合于资源的共享\n\n# 参考文献:\n\n- [Java 多线程与并发编程专题](https://www.ibm.com/developerworks/cn/java/j-concurrent/)\n- [Java多线程干货系列(1):Java多线程基础](http://www.importnew.com/21136.html)\n- [菜鸟教程:Java多线程编程](http://www.runoob.com/java/java-multithreading.html)\n- [Java中Runnable和Thread的区别](http://developer.51cto.com/art/201203/321042.htm)\n\n\n","slug":"java多线程编程(一)","published":1,"updated":"2017-10-30T07:42:49.192Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k6m000cwsv7ye77iubb","content":"<h1 id=\"1-线程与进程\"><a href=\"#1-线程与进程\" class=\"headerlink\" title=\"1. 线程与进程\"></a>1. 线程与进程</h1><ol>\n<li>线程:进程中负责程序执行的执行单元。线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境</li>\n<li>进程:执行中的程序,一个进程至少包含一个线程</li>\n<li>单线程:程序中只存在一个线程,实际上主方法就是一个主线程</li>\n<li>多线程:在一个程序中运行多个任务,目的是更好地使用CPU资源</li>\n</ol>\n<h1 id=\"2-一个线程的生命周期\"><a href=\"#2-一个线程的生命周期\" class=\"headerlink\" title=\"2. 一个线程的生命周期\"></a>2. 一个线程的生命周期</h1><p><img src=\"http://www.runoob.com/wp-content/uploads/2014/01/java-thread.jpg\" alt=\"线程的生命周期图\"></p>\n<ul>\n<li>创建(new)状态: 准备好了一个多线程的对象</li>\n<li>就绪(runnable)状态: 调用了<code>start()</code>方法, 等待CPU进行调度</li>\n<li>运行(running)状态: 如果就绪状态的线程获取 CPU 资源,就可以执行<code>run()</code>方法</li>\n<li>阻塞(blocked)状态: 暂时停止执行, 可能将资源交给其它线程使用。如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。</li>\n<li>终止(dead)状态: 线程销毁</li>\n</ul>\n<h1 id=\"3-线程的实现\"><a href=\"#3-线程的实现\" class=\"headerlink\" title=\"3. 线程的实现\"></a>3. 线程的实现</h1><p>创建线程有两种主要的方式:</p>\n<ul>\n<li>通过实现 Runnable 接口;(推荐)</li>\n<li>通过继承 Thread 类本身;</li>\n</ul>\n<h2 id=\"3-1-通过实现Runnable接口来创建线程\"><a href=\"#3-1-通过实现Runnable接口来创建线程\" class=\"headerlink\" title=\"3.1 通过实现Runnable接口来创建线程\"></a>3.1 通过实现Runnable接口来创建线程</h2><p>实例:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String args[])</span> </span>{</div><div class=\"line\"> RunnableDemo R1 = <span class=\"keyword\">new</span> RunnableDemo( <span class=\"string\">\"Thread-1\"</span>);</div><div class=\"line\"> Thread t1 = <span class=\"keyword\">new</span> Thread(R1);</div><div class=\"line\"> t1.start();</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo R2 = <span class=\"keyword\">new</span> RunnableDemo( <span class=\"string\">\"Thread-2\"</span>);</div><div class=\"line\"> Thread t2 = <span class=\"keyword\">new</span> Thread(R2);</div><div class=\"line\"> t2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">RunnableDemo</span> <span class=\"keyword\">implements</span> <span class=\"title\">Runnable</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo( String name) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Creating \"</span> + threadName );</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName );</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">for</span>(<span class=\"keyword\">int</span> i = <span class=\"number\">4</span>; i > <span class=\"number\">0</span>; i--) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread: \"</span> + threadName + <span class=\"string\">\", \"</span> + i);</div><div class=\"line\"> <span class=\"comment\">// 让线程睡眠一会</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">50</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }<span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" interrupted.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" exiting.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>运行输出:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Creating Thread-1</div><div class=\"line\">Creating Thread-2</div><div class=\"line\">Running Thread-2</div><div class=\"line\">Thread: Thread-2, 4</div><div class=\"line\">Running Thread-1</div><div class=\"line\">Thread: Thread-1, 4</div><div class=\"line\">Thread: Thread-1, 3</div><div class=\"line\">Thread: Thread-2, 3</div><div class=\"line\">Thread: Thread-2, 2</div><div class=\"line\">Thread: Thread-1, 2</div><div class=\"line\">Thread: Thread-1, 1</div><div class=\"line\">Thread: Thread-2, 1</div><div class=\"line\">Thread Thread-2 exiting.</div><div class=\"line\">Thread Thread-1 exiting.</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-通过继承Thread来创建线程\"><a href=\"#3-2-通过继承Thread来创建线程\" class=\"headerlink\" title=\"3.2 通过继承Thread来创建线程\"></a>3.2 通过继承Thread来创建线程</h2><p>实例:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String args[])</span> </span>{</div><div class=\"line\"> ThreadDemo T1 = <span class=\"keyword\">new</span> ThreadDemo( <span class=\"string\">\"Thread-1\"</span>);</div><div class=\"line\"> T1.start();</div><div class=\"line\"></div><div class=\"line\"> ThreadDemo T2 = <span class=\"keyword\">new</span> ThreadDemo( <span class=\"string\">\"Thread-2\"</span>);</div><div class=\"line\"> T2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">ThreadDemo</span> <span class=\"keyword\">extends</span> <span class=\"title\">Thread</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"></div><div class=\"line\"> ThreadDemo( String name) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Creating \"</span> + threadName );</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName );</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">for</span>(<span class=\"keyword\">int</span> i = <span class=\"number\">4</span>; i > <span class=\"number\">0</span>; i--) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread: \"</span> + threadName + <span class=\"string\">\", \"</span> + i);</div><div class=\"line\"> <span class=\"comment\">// 让线程睡醒一会</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">50</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }<span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" interrupted.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" exiting.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>输出结果:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Creating Thread-1</div><div class=\"line\">Creating Thread-2</div><div class=\"line\">Running Thread-1</div><div class=\"line\">Thread: Thread-1, 4</div><div class=\"line\">Running Thread-2</div><div class=\"line\">Thread: Thread-2, 4</div><div class=\"line\">Thread: Thread-1, 3</div><div class=\"line\">Thread: Thread-2, 3</div><div class=\"line\">Thread: Thread-2, 2</div><div class=\"line\">Thread: Thread-1, 2</div><div class=\"line\">Thread: Thread-2, 1</div><div class=\"line\">Thread: Thread-1, 1</div><div class=\"line\">Thread Thread-2 exiting.</div><div class=\"line\">Thread Thread-1 exiting.</div></pre></td></tr></table></figure>\n<h2 id=\"3-3-为什么推荐使用Runnable接口的方式\"><a href=\"#3-3-为什么推荐使用Runnable接口的方式\" class=\"headerlink\" title=\"3.3 为什么推荐使用Runnable接口的方式\"></a>3.3 为什么推荐使用Runnable接口的方式</h2><p>Runnable接口和Thread之间的联系:</p>\n<p><code>public class Thread extends Object implements Runnable</code></p>\n<p>我们发现Thread类其实也是Runnable接口的子类。</p>\n<p>在程序开发中只要是多线程都以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:</p>\n<ul>\n<li>避免点继承的局限,一个类可以继承多个接口。</li>\n<li>适合于资源的共享</li>\n</ul>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><a href=\"https://www.ibm.com/developerworks/cn/java/j-concurrent/\" target=\"_blank\" rel=\"external\">Java 多线程与并发编程专题</a></li>\n<li><a href=\"http://www.importnew.com/21136.html\" target=\"_blank\" rel=\"external\">Java多线程干货系列(1):Java多线程基础</a></li>\n<li><a href=\"http://www.runoob.com/java/java-multithreading.html\" target=\"_blank\" rel=\"external\">菜鸟教程:Java多线程编程</a></li>\n<li><a href=\"http://developer.51cto.com/art/201203/321042.htm\" target=\"_blank\" rel=\"external\">Java中Runnable和Thread的区别</a></li>\n</ul>\n","excerpt":"","more":"<h1 id=\"1-线程与进程\"><a href=\"#1-线程与进程\" class=\"headerlink\" title=\"1. 线程与进程\"></a>1. 线程与进程</h1><ol>\n<li>线程:进程中负责程序执行的执行单元。线程本身依靠程序进行运行,线程是程序中的顺序控制流,只能使用分配给程序的资源和环境</li>\n<li>进程:执行中的程序,一个进程至少包含一个线程</li>\n<li>单线程:程序中只存在一个线程,实际上主方法就是一个主线程</li>\n<li>多线程:在一个程序中运行多个任务,目的是更好地使用CPU资源</li>\n</ol>\n<h1 id=\"2-一个线程的生命周期\"><a href=\"#2-一个线程的生命周期\" class=\"headerlink\" title=\"2. 一个线程的生命周期\"></a>2. 一个线程的生命周期</h1><p><img src=\"http://www.runoob.com/wp-content/uploads/2014/01/java-thread.jpg\" alt=\"线程的生命周期图\"></p>\n<ul>\n<li>创建(new)状态: 准备好了一个多线程的对象</li>\n<li>就绪(runnable)状态: 调用了<code>start()</code>方法, 等待CPU进行调度</li>\n<li>运行(running)状态: 如果就绪状态的线程获取 CPU 资源,就可以执行<code>run()</code>方法</li>\n<li>阻塞(blocked)状态: 暂时停止执行, 可能将资源交给其它线程使用。如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。</li>\n<li>终止(dead)状态: 线程销毁</li>\n</ul>\n<h1 id=\"3-线程的实现\"><a href=\"#3-线程的实现\" class=\"headerlink\" title=\"3. 线程的实现\"></a>3. 线程的实现</h1><p>创建线程有两种主要的方式:</p>\n<ul>\n<li>通过实现 Runnable 接口;(推荐)</li>\n<li>通过继承 Thread 类本身;</li>\n</ul>\n<h2 id=\"3-1-通过实现Runnable接口来创建线程\"><a href=\"#3-1-通过实现Runnable接口来创建线程\" class=\"headerlink\" title=\"3.1 通过实现Runnable接口来创建线程\"></a>3.1 通过实现Runnable接口来创建线程</h2><p>实例:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String args[])</span> </span>{</div><div class=\"line\"> RunnableDemo R1 = <span class=\"keyword\">new</span> RunnableDemo( <span class=\"string\">\"Thread-1\"</span>);</div><div class=\"line\"> Thread t1 = <span class=\"keyword\">new</span> Thread(R1);</div><div class=\"line\"> t1.start();</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo R2 = <span class=\"keyword\">new</span> RunnableDemo( <span class=\"string\">\"Thread-2\"</span>);</div><div class=\"line\"> Thread t2 = <span class=\"keyword\">new</span> Thread(R2);</div><div class=\"line\"> t2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">RunnableDemo</span> <span class=\"keyword\">implements</span> <span class=\"title\">Runnable</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo( String name) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Creating \"</span> + threadName );</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName );</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">for</span>(<span class=\"keyword\">int</span> i = <span class=\"number\">4</span>; i > <span class=\"number\">0</span>; i--) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread: \"</span> + threadName + <span class=\"string\">\", \"</span> + i);</div><div class=\"line\"> <span class=\"comment\">// 让线程睡眠一会</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">50</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }<span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" interrupted.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" exiting.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>运行输出:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Creating Thread-1</div><div class=\"line\">Creating Thread-2</div><div class=\"line\">Running Thread-2</div><div class=\"line\">Thread: Thread-2, 4</div><div class=\"line\">Running Thread-1</div><div class=\"line\">Thread: Thread-1, 4</div><div class=\"line\">Thread: Thread-1, 3</div><div class=\"line\">Thread: Thread-2, 3</div><div class=\"line\">Thread: Thread-2, 2</div><div class=\"line\">Thread: Thread-1, 2</div><div class=\"line\">Thread: Thread-1, 1</div><div class=\"line\">Thread: Thread-2, 1</div><div class=\"line\">Thread Thread-2 exiting.</div><div class=\"line\">Thread Thread-1 exiting.</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-通过继承Thread来创建线程\"><a href=\"#3-2-通过继承Thread来创建线程\" class=\"headerlink\" title=\"3.2 通过继承Thread来创建线程\"></a>3.2 通过继承Thread来创建线程</h2><p>实例:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String args[])</span> </span>{</div><div class=\"line\"> ThreadDemo T1 = <span class=\"keyword\">new</span> ThreadDemo( <span class=\"string\">\"Thread-1\"</span>);</div><div class=\"line\"> T1.start();</div><div class=\"line\"></div><div class=\"line\"> ThreadDemo T2 = <span class=\"keyword\">new</span> ThreadDemo( <span class=\"string\">\"Thread-2\"</span>);</div><div class=\"line\"> T2.start();</div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">ThreadDemo</span> <span class=\"keyword\">extends</span> <span class=\"title\">Thread</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"></div><div class=\"line\"> ThreadDemo( String name) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Creating \"</span> + threadName );</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName );</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">for</span>(<span class=\"keyword\">int</span> i = <span class=\"number\">4</span>; i > <span class=\"number\">0</span>; i--) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread: \"</span> + threadName + <span class=\"string\">\", \"</span> + i);</div><div class=\"line\"> <span class=\"comment\">// 让线程睡醒一会</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">50</span>);</div><div class=\"line\"> }</div><div class=\"line\"> }<span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" interrupted.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\"> System.out.println(<span class=\"string\">\"Thread \"</span> + threadName + <span class=\"string\">\" exiting.\"</span>);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>输出结果:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div></pre></td><td class=\"code\"><pre><div class=\"line\">Creating Thread-1</div><div class=\"line\">Creating Thread-2</div><div class=\"line\">Running Thread-1</div><div class=\"line\">Thread: Thread-1, 4</div><div class=\"line\">Running Thread-2</div><div class=\"line\">Thread: Thread-2, 4</div><div class=\"line\">Thread: Thread-1, 3</div><div class=\"line\">Thread: Thread-2, 3</div><div class=\"line\">Thread: Thread-2, 2</div><div class=\"line\">Thread: Thread-1, 2</div><div class=\"line\">Thread: Thread-2, 1</div><div class=\"line\">Thread: Thread-1, 1</div><div class=\"line\">Thread Thread-2 exiting.</div><div class=\"line\">Thread Thread-1 exiting.</div></pre></td></tr></table></figure>\n<h2 id=\"3-3-为什么推荐使用Runnable接口的方式\"><a href=\"#3-3-为什么推荐使用Runnable接口的方式\" class=\"headerlink\" title=\"3.3 为什么推荐使用Runnable接口的方式\"></a>3.3 为什么推荐使用Runnable接口的方式</h2><p>Runnable接口和Thread之间的联系:</p>\n<p><code>public class Thread extends Object implements Runnable</code></p>\n<p>我们发现Thread类其实也是Runnable接口的子类。</p>\n<p>在程序开发中只要是多线程都以实现Runnable接口为主,因为实现Runnable接口相比继承Thread类有如下好处:</p>\n<ul>\n<li>避免点继承的局限,一个类可以继承多个接口。</li>\n<li>适合于资源的共享</li>\n</ul>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><a href=\"https://www.ibm.com/developerworks/cn/java/j-concurrent/\">Java 多线程与并发编程专题</a></li>\n<li><a href=\"http://www.importnew.com/21136.html\">Java多线程干货系列(1):Java多线程基础</a></li>\n<li><a href=\"http://www.runoob.com/java/java-multithreading.html\">菜鸟教程:Java多线程编程</a></li>\n<li><a href=\"http://developer.51cto.com/art/201203/321042.htm\">Java中Runnable和Thread的区别</a></li>\n</ul>\n"},{"title":"java多线程编程(二):CountDownLatch","comment":true,"date":"2017-11-02T02:24:16.000Z","_content":"\n# 1. CountDownLatch是什么\nCountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。\n\n**主要方法:**\n\n``` java\npublic CountDownLatch(int count); // 构造方法,参数指定了计数的次数 \npublic void countDown(); // 当前线程调用此方法,则计数减一\npublic void await() throws InterruptedException // 调用此方法会一直阻塞当前线程,直到计时器的值为0\n```\n\n# 2. CountDownLatchde的使用场景\n\n1. **实现最大的并行性**:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。\n2. **开始执行前等待n个线程完成各自任务**:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。\n3. **死锁检测:**一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。\n\n# 3. 实例:实现最大的并行性\n\n> **问题描述:** 我们使用for循环创建50个线程,使用CountDownLatch.await()方法让所有新创建的线程都处于阻塞状态,当所有线程创建完成后使用CountDownLatch.countDown()方法让所有线程同时解除等待状态,恢复执行。\n\n**代码实例:**\n\n``` java\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\n\npublic class Main {\n public static void main(String[] args) {\n CountDownLatch latch = new CountDownLatch(1);\n int count = 50;\n for (int i = 0; i < count; i++) {\n String threadName = \"Thread\" + i;\n new Thread(new RunnableDemo(threadName, latch)).start();\n \n try {\n Thread.sleep(20);\n } catch (InterruptedException e) {\n e.printStackTrace();\n }\n }\n\n// latch.countDown();\n }\n}\n\nclass RunnableDemo implements Runnable {\n private String threadName;\n CountDownLatch latch;\n\n RunnableDemo(String name, CountDownLatch latch) {\n threadName = name;\n this.latch = latch;\n }\n\n public void run() {\n// try {\n// this.latch.await();\n System.out.println(\"Running \" + threadName);\n// } catch (InterruptedException e) {\n// e.printStackTrace();\n// }\n }\n}\n\n```\n\n以下是不使用CountDownLatch的执行结果:\n\n``` \nRunning Thread0\nRunning Thread1\nRunning Thread2\nRunning Thread3\nRunning Thread4\nRunning Thread5\nRunning Thread6\nRunning Thread7\nRunning Thread8\nRunning Thread9\n...\n```\n\n以下是使用CountDownLatch后的执行结果:\n\n(即打开以上代码的注释部分)\n\n```\nRunning Thread5\nRunning Thread2\nRunning Thread11\nRunning Thread1\nRunning Thread13\nRunning Thread14\nRunning Thread17\nRunning Thread19\nRunning Thread21\nRunning Thread24\n...\n```\n\n**结论:** 可见使用CountDownLatch可以实现多个线程的最大并行性。\n\n# 参考文献:\n\n- [java 多线程 CountDownLatch用法](http://www.iteye.com/topic/1002652)\n- [Java之CountDownLatch使用](http://blog.csdn.net/shihuacai/article/details/8856370)\n- [什么时候使用CountDownLatch](http://www.importnew.com/15731.html)\n\n","source":"_posts/java多线程编程(二):CountDownLatch.md","raw":"---\ntitle: java多线程编程(二):CountDownLatch\ncomment: true\ndate: 2017-11-02 10:24:16\ntags: [Java, 多线程, CountDownLatch]\n---\n\n# 1. CountDownLatch是什么\nCountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。\n\n**主要方法:**\n\n``` java\npublic CountDownLatch(int count); // 构造方法,参数指定了计数的次数 \npublic void countDown(); // 当前线程调用此方法,则计数减一\npublic void await() throws InterruptedException // 调用此方法会一直阻塞当前线程,直到计时器的值为0\n```\n\n# 2. CountDownLatchde的使用场景\n\n1. **实现最大的并行性**:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。\n2. **开始执行前等待n个线程完成各自任务**:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。\n3. **死锁检测:**一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。\n\n# 3. 实例:实现最大的并行性\n\n> **问题描述:** 我们使用for循环创建50个线程,使用CountDownLatch.await()方法让所有新创建的线程都处于阻塞状态,当所有线程创建完成后使用CountDownLatch.countDown()方法让所有线程同时解除等待状态,恢复执行。\n\n**代码实例:**\n\n``` java\nimport java.util.Random;\nimport java.util.concurrent.CountDownLatch;\n\npublic class Main {\n public static void main(String[] args) {\n CountDownLatch latch = new CountDownLatch(1);\n int count = 50;\n for (int i = 0; i < count; i++) {\n String threadName = \"Thread\" + i;\n new Thread(new RunnableDemo(threadName, latch)).start();\n \n try {\n Thread.sleep(20);\n } catch (InterruptedException e) {\n e.printStackTrace();\n }\n }\n\n// latch.countDown();\n }\n}\n\nclass RunnableDemo implements Runnable {\n private String threadName;\n CountDownLatch latch;\n\n RunnableDemo(String name, CountDownLatch latch) {\n threadName = name;\n this.latch = latch;\n }\n\n public void run() {\n// try {\n// this.latch.await();\n System.out.println(\"Running \" + threadName);\n// } catch (InterruptedException e) {\n// e.printStackTrace();\n// }\n }\n}\n\n```\n\n以下是不使用CountDownLatch的执行结果:\n\n``` \nRunning Thread0\nRunning Thread1\nRunning Thread2\nRunning Thread3\nRunning Thread4\nRunning Thread5\nRunning Thread6\nRunning Thread7\nRunning Thread8\nRunning Thread9\n...\n```\n\n以下是使用CountDownLatch后的执行结果:\n\n(即打开以上代码的注释部分)\n\n```\nRunning Thread5\nRunning Thread2\nRunning Thread11\nRunning Thread1\nRunning Thread13\nRunning Thread14\nRunning Thread17\nRunning Thread19\nRunning Thread21\nRunning Thread24\n...\n```\n\n**结论:** 可见使用CountDownLatch可以实现多个线程的最大并行性。\n\n# 参考文献:\n\n- [java 多线程 CountDownLatch用法](http://www.iteye.com/topic/1002652)\n- [Java之CountDownLatch使用](http://blog.csdn.net/shihuacai/article/details/8856370)\n- [什么时候使用CountDownLatch](http://www.importnew.com/15731.html)\n\n","slug":"java多线程编程(二):CountDownLatch","published":1,"updated":"2017-10-30T07:43:39.730Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k6m000dwsv7pm68tbzi","content":"<h1 id=\"1-CountDownLatch是什么\"><a href=\"#1-CountDownLatch是什么\" class=\"headerlink\" title=\"1. CountDownLatch是什么\"></a>1. CountDownLatch是什么</h1><p>CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。</p>\n<p><strong>主要方法:</strong></p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">CountDownLatch</span><span class=\"params\">(<span class=\"keyword\">int</span> count)</span></span>; <span class=\"comment\">// 构造方法,参数指定了计数的次数 </span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">countDown</span><span class=\"params\">()</span></span>; <span class=\"comment\">// 当前线程调用此方法,则计数减一</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">await</span><span class=\"params\">()</span> <span class=\"keyword\">throws</span> InterruptedException <span class=\"comment\">// 调用此方法会一直阻塞当前线程,直到计时器的值为0</span></span></div></pre></td></tr></table></figure>\n<h1 id=\"2-CountDownLatchde的使用场景\"><a href=\"#2-CountDownLatchde的使用场景\" class=\"headerlink\" title=\"2. CountDownLatchde的使用场景\"></a>2. CountDownLatchde的使用场景</h1><ol>\n<li><strong>实现最大的并行性</strong>:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。</li>\n<li><strong>开始执行前等待n个线程完成各自任务</strong>:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。</li>\n<li><strong>死锁检测:</strong>一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。</li>\n</ol>\n<h1 id=\"3-实例:实现最大的并行性\"><a href=\"#3-实例:实现最大的并行性\" class=\"headerlink\" title=\"3. 实例:实现最大的并行性\"></a>3. 实例:实现最大的并行性</h1><blockquote>\n<p><strong>问题描述:</strong> 我们使用for循环创建50个线程,使用CountDownLatch.await()方法让所有新创建的线程都处于阻塞状态,当所有线程创建完成后使用CountDownLatch.countDown()方法让所有线程同时解除等待状态,恢复执行。</p>\n</blockquote>\n<p><strong>代码实例:</strong></p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> java.util.Random;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.concurrent.CountDownLatch;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\"> CountDownLatch latch = <span class=\"keyword\">new</span> CountDownLatch(<span class=\"number\">1</span>);</div><div class=\"line\"> <span class=\"keyword\">int</span> count = <span class=\"number\">50</span>;</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < count; i++) {</div><div class=\"line\"> String threadName = <span class=\"string\">\"Thread\"</span> + i;</div><div class=\"line\"> <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> RunnableDemo(threadName, latch)).start();</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> Thread.sleep(<span class=\"number\">20</span>);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// latch.countDown();</span></div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">RunnableDemo</span> <span class=\"keyword\">implements</span> <span class=\"title\">Runnable</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"> CountDownLatch latch;</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo(String name, CountDownLatch latch) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> <span class=\"keyword\">this</span>.latch = latch;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"><span class=\"comment\">// try {</span></div><div class=\"line\"><span class=\"comment\">// this.latch.await();</span></div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName);</div><div class=\"line\"><span class=\"comment\">// } catch (InterruptedException e) {</span></div><div class=\"line\"><span class=\"comment\">// e.printStackTrace();</span></div><div class=\"line\"><span class=\"comment\">// }</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>以下是不使用CountDownLatch的执行结果:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Running Thread0</div><div class=\"line\">Running Thread1</div><div class=\"line\">Running Thread2</div><div class=\"line\">Running Thread3</div><div class=\"line\">Running Thread4</div><div class=\"line\">Running Thread5</div><div class=\"line\">Running Thread6</div><div class=\"line\">Running Thread7</div><div class=\"line\">Running Thread8</div><div class=\"line\">Running Thread9</div><div class=\"line\">...</div></pre></td></tr></table></figure>\n<p>以下是使用CountDownLatch后的执行结果:</p>\n<p>(即打开以上代码的注释部分)</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Running Thread5</div><div class=\"line\">Running Thread2</div><div class=\"line\">Running Thread11</div><div class=\"line\">Running Thread1</div><div class=\"line\">Running Thread13</div><div class=\"line\">Running Thread14</div><div class=\"line\">Running Thread17</div><div class=\"line\">Running Thread19</div><div class=\"line\">Running Thread21</div><div class=\"line\">Running Thread24</div><div class=\"line\">...</div></pre></td></tr></table></figure>\n<p><strong>结论:</strong> 可见使用CountDownLatch可以实现多个线程的最大并行性。</p>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><a href=\"http://www.iteye.com/topic/1002652\" target=\"_blank\" rel=\"external\">java 多线程 CountDownLatch用法</a></li>\n<li><a href=\"http://blog.csdn.net/shihuacai/article/details/8856370\" target=\"_blank\" rel=\"external\">Java之CountDownLatch使用</a></li>\n<li><a href=\"http://www.importnew.com/15731.html\" target=\"_blank\" rel=\"external\">什么时候使用CountDownLatch</a></li>\n</ul>\n","excerpt":"","more":"<h1 id=\"1-CountDownLatch是什么\"><a href=\"#1-CountDownLatch是什么\" class=\"headerlink\" title=\"1. CountDownLatch是什么\"></a>1. CountDownLatch是什么</h1><p>CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。</p>\n<p><strong>主要方法:</strong></p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"title\">CountDownLatch</span><span class=\"params\">(<span class=\"keyword\">int</span> count)</span></span>; <span class=\"comment\">// 构造方法,参数指定了计数的次数 </span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">countDown</span><span class=\"params\">()</span></span>; <span class=\"comment\">// 当前线程调用此方法,则计数减一</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">await</span><span class=\"params\">()</span> <span class=\"keyword\">throws</span> InterruptedException <span class=\"comment\">// 调用此方法会一直阻塞当前线程,直到计时器的值为0</span></span></div></pre></td></tr></table></figure>\n<h1 id=\"2-CountDownLatchde的使用场景\"><a href=\"#2-CountDownLatchde的使用场景\" class=\"headerlink\" title=\"2. CountDownLatchde的使用场景\"></a>2. CountDownLatchde的使用场景</h1><ol>\n<li><strong>实现最大的并行性</strong>:有时我们想同时启动多个线程,实现最大程度的并行性。例如,我们想测试一个单例类。如果我们创建一个初始计数为1的CountDownLatch,并让所有线程都在这个锁上等待,那么我们可以很轻松地完成测试。我们只需调用 一次countDown()方法就可以让所有的等待线程同时恢复执行。</li>\n<li><strong>开始执行前等待n个线程完成各自任务</strong>:例如应用程序启动类要确保在处理用户请求前,所有N个外部系统已经启动和运行了。</li>\n<li><strong>死锁检测:</strong>一个非常方便的使用场景是,你可以使用n个线程访问共享资源,在每次测试阶段的线程数目是不同的,并尝试产生死锁。</li>\n</ol>\n<h1 id=\"3-实例:实现最大的并行性\"><a href=\"#3-实例:实现最大的并行性\" class=\"headerlink\" title=\"3. 实例:实现最大的并行性\"></a>3. 实例:实现最大的并行性</h1><blockquote>\n<p><strong>问题描述:</strong> 我们使用for循环创建50个线程,使用CountDownLatch.await()方法让所有新创建的线程都处于阻塞状态,当所有线程创建完成后使用CountDownLatch.countDown()方法让所有线程同时解除等待状态,恢复执行。</p>\n</blockquote>\n<p><strong>代码实例:</strong></p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">import</span> java.util.Random;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.concurrent.CountDownLatch;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">Main</span> </span>{</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title\">main</span><span class=\"params\">(String[] args)</span> </span>{</div><div class=\"line\"> CountDownLatch latch = <span class=\"keyword\">new</span> CountDownLatch(<span class=\"number\">1</span>);</div><div class=\"line\"> <span class=\"keyword\">int</span> count = <span class=\"number\">50</span>;</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < count; i++) {</div><div class=\"line\"> String threadName = <span class=\"string\">\"Thread\"</span> + i;</div><div class=\"line\"> <span class=\"keyword\">new</span> Thread(<span class=\"keyword\">new</span> RunnableDemo(threadName, latch)).start();</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> Thread.sleep(<span class=\"number\">20</span>);</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (InterruptedException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">// latch.countDown();</span></div><div class=\"line\"> }</div><div class=\"line\">}</div><div class=\"line\"></div><div class=\"line\"><span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">RunnableDemo</span> <span class=\"keyword\">implements</span> <span class=\"title\">Runnable</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> String threadName;</div><div class=\"line\"> CountDownLatch latch;</div><div class=\"line\"></div><div class=\"line\"> RunnableDemo(String name, CountDownLatch latch) {</div><div class=\"line\"> threadName = name;</div><div class=\"line\"> <span class=\"keyword\">this</span>.latch = latch;</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title\">run</span><span class=\"params\">()</span> </span>{</div><div class=\"line\"><span class=\"comment\">// try {</span></div><div class=\"line\"><span class=\"comment\">// this.latch.await();</span></div><div class=\"line\"> System.out.println(<span class=\"string\">\"Running \"</span> + threadName);</div><div class=\"line\"><span class=\"comment\">// } catch (InterruptedException e) {</span></div><div class=\"line\"><span class=\"comment\">// e.printStackTrace();</span></div><div class=\"line\"><span class=\"comment\">// }</span></div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>以下是不使用CountDownLatch的执行结果:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Running Thread0</div><div class=\"line\">Running Thread1</div><div class=\"line\">Running Thread2</div><div class=\"line\">Running Thread3</div><div class=\"line\">Running Thread4</div><div class=\"line\">Running Thread5</div><div class=\"line\">Running Thread6</div><div class=\"line\">Running Thread7</div><div class=\"line\">Running Thread8</div><div class=\"line\">Running Thread9</div><div class=\"line\">...</div></pre></td></tr></table></figure>\n<p>以下是使用CountDownLatch后的执行结果:</p>\n<p>(即打开以上代码的注释部分)</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">Running Thread5</div><div class=\"line\">Running Thread2</div><div class=\"line\">Running Thread11</div><div class=\"line\">Running Thread1</div><div class=\"line\">Running Thread13</div><div class=\"line\">Running Thread14</div><div class=\"line\">Running Thread17</div><div class=\"line\">Running Thread19</div><div class=\"line\">Running Thread21</div><div class=\"line\">Running Thread24</div><div class=\"line\">...</div></pre></td></tr></table></figure>\n<p><strong>结论:</strong> 可见使用CountDownLatch可以实现多个线程的最大并行性。</p>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><a href=\"http://www.iteye.com/topic/1002652\">java 多线程 CountDownLatch用法</a></li>\n<li><a href=\"http://blog.csdn.net/shihuacai/article/details/8856370\">Java之CountDownLatch使用</a></li>\n<li><a href=\"http://www.importnew.com/15731.html\">什么时候使用CountDownLatch</a></li>\n</ul>\n"},{"title":"jsp页面中获取session对象","comment":true,"date":"2017-06-08T07:10:10.000Z","_content":"# 1.session的介绍\n\n客户首次访问服务器时,会话session对象被创建并分配一个唯一的Id,同时id号发送到客户端,并存入cookie,使得客户端session对象和服务器端一致。\n\n存储会话信息session供浏览器后续请求使用,可以获取并修改变量的值。和cookie一起使用识别同一个客户。\n\n当用户关闭浏览器时,客户针对当前服务器的session即被关闭或超时失效,当客户再次打开浏览器访问的时候,会重新分配会话session ID。若禁止cookie,,同一个客户就会对应多个session对象,服务器无法识别访问这些页面是同一个客户。\n\n# 2.session和cookie的区别\n\n1. session 在服务器端,cookie 在客户端(浏览器)\n2. session 默认被存在在服务器的一个文件里(不是内存)\n3. session 的运行依赖 session id,而 session id 是存在 cookie 中的。\n4. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗\n 考虑到安全应当使用session\n5. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能\n 考虑到减轻服务器性能方面,应当使用COOKIE\n6. 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。(将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中)\n\n\n# 3.前端Jsp页面中获取session对象\n\n## 3.1 方法一(EL表达式)\n\n``` javascript\n// 前端获取存储在session对象中的用户id:userId\nvar studentId = \"${sessionScope.userId}\";\n```\n\n\n\n## 3.2 方法二(Jsp语法)\n\n``` javascript\n// 前端获取存储在session对象中的用户id:userId\nvar studentId = \"<%=session.getAttribute(\"userId\")%>\";\n```\n\n## 注意小坑\n\n以上代码必须写在Jsp文件中,在引入外部Js文件时上述代码失效。\n\n\n","source":"_posts/jsp页面中获取session对象.md","raw":"---\ntitle: jsp页面中获取session对象\ncomment: true\ndate: 2017-06-08 15:10:10\ntags: [jsp,session,el表达式]\n---\n# 1.session的介绍\n\n客户首次访问服务器时,会话session对象被创建并分配一个唯一的Id,同时id号发送到客户端,并存入cookie,使得客户端session对象和服务器端一致。\n\n存储会话信息session供浏览器后续请求使用,可以获取并修改变量的值。和cookie一起使用识别同一个客户。\n\n当用户关闭浏览器时,客户针对当前服务器的session即被关闭或超时失效,当客户再次打开浏览器访问的时候,会重新分配会话session ID。若禁止cookie,,同一个客户就会对应多个session对象,服务器无法识别访问这些页面是同一个客户。\n\n# 2.session和cookie的区别\n\n1. session 在服务器端,cookie 在客户端(浏览器)\n2. session 默认被存在在服务器的一个文件里(不是内存)\n3. session 的运行依赖 session id,而 session id 是存在 cookie 中的。\n4. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗\n 考虑到安全应当使用session\n5. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能\n 考虑到减轻服务器性能方面,应当使用COOKIE\n6. 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。(将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中)\n\n\n# 3.前端Jsp页面中获取session对象\n\n## 3.1 方法一(EL表达式)\n\n``` javascript\n// 前端获取存储在session对象中的用户id:userId\nvar studentId = \"${sessionScope.userId}\";\n```\n\n\n\n## 3.2 方法二(Jsp语法)\n\n``` javascript\n// 前端获取存储在session对象中的用户id:userId\nvar studentId = \"<%=session.getAttribute(\"userId\")%>\";\n```\n\n## 注意小坑\n\n以上代码必须写在Jsp文件中,在引入外部Js文件时上述代码失效。\n\n\n","slug":"jsp页面中获取session对象","published":1,"updated":"2017-10-14T12:25:12.750Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k6m000fwsv7hdzt67n2","content":"<h1 id=\"1-session的介绍\"><a href=\"#1-session的介绍\" class=\"headerlink\" title=\"1.session的介绍\"></a>1.session的介绍</h1><p>客户首次访问服务器时,会话session对象被创建并分配一个唯一的Id,同时id号发送到客户端,并存入cookie,使得客户端session对象和服务器端一致。</p>\n<p>存储会话信息session供浏览器后续请求使用,可以获取并修改变量的值。和cookie一起使用识别同一个客户。</p>\n<p>当用户关闭浏览器时,客户针对当前服务器的session即被关闭或超时失效,当客户再次打开浏览器访问的时候,会重新分配会话session ID。若禁止cookie,,同一个客户就会对应多个session对象,服务器无法识别访问这些页面是同一个客户。</p>\n<h1 id=\"2-session和cookie的区别\"><a href=\"#2-session和cookie的区别\" class=\"headerlink\" title=\"2.session和cookie的区别\"></a>2.session和cookie的区别</h1><ol>\n<li>session 在服务器端,cookie 在客户端(浏览器)</li>\n<li>session 默认被存在在服务器的一个文件里(不是内存)</li>\n<li>session 的运行依赖 session id,而 session id 是存在 cookie 中的。</li>\n<li>cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗<br>考虑到安全应当使用session</li>\n<li>session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能<br>考虑到减轻服务器性能方面,应当使用COOKIE</li>\n<li>单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。(将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中)</li>\n</ol>\n<h1 id=\"3-前端Jsp页面中获取session对象\"><a href=\"#3-前端Jsp页面中获取session对象\" class=\"headerlink\" title=\"3.前端Jsp页面中获取session对象\"></a>3.前端Jsp页面中获取session对象</h1><h2 id=\"3-1-方法一(EL表达式)\"><a href=\"#3-1-方法一(EL表达式)\" class=\"headerlink\" title=\"3.1 方法一(EL表达式)\"></a>3.1 方法一(EL表达式)</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 前端获取存储在session对象中的用户id:userId</span></div><div class=\"line\"><span class=\"keyword\">var</span> studentId = <span class=\"string\">\"${sessionScope.userId}\"</span>;</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-方法二(Jsp语法)\"><a href=\"#3-2-方法二(Jsp语法)\" class=\"headerlink\" title=\"3.2 方法二(Jsp语法)\"></a>3.2 方法二(Jsp语法)</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 前端获取存储在session对象中的用户id:userId</span></div><div class=\"line\"><span class=\"keyword\">var</span> studentId = <span class=\"string\">\"<%=session.getAttribute(\"</span>userId<span class=\"string\">\")%>\"</span>;</div></pre></td></tr></table></figure>\n<h2 id=\"注意小坑\"><a href=\"#注意小坑\" class=\"headerlink\" title=\"注意小坑\"></a>注意小坑</h2><p>以上代码必须写在Jsp文件中,在引入外部Js文件时上述代码失效。</p>\n","excerpt":"","more":"<h1 id=\"1-session的介绍\"><a href=\"#1-session的介绍\" class=\"headerlink\" title=\"1.session的介绍\"></a>1.session的介绍</h1><p>客户首次访问服务器时,会话session对象被创建并分配一个唯一的Id,同时id号发送到客户端,并存入cookie,使得客户端session对象和服务器端一致。</p>\n<p>存储会话信息session供浏览器后续请求使用,可以获取并修改变量的值。和cookie一起使用识别同一个客户。</p>\n<p>当用户关闭浏览器时,客户针对当前服务器的session即被关闭或超时失效,当客户再次打开浏览器访问的时候,会重新分配会话session ID。若禁止cookie,,同一个客户就会对应多个session对象,服务器无法识别访问这些页面是同一个客户。</p>\n<h1 id=\"2-session和cookie的区别\"><a href=\"#2-session和cookie的区别\" class=\"headerlink\" title=\"2.session和cookie的区别\"></a>2.session和cookie的区别</h1><ol>\n<li>session 在服务器端,cookie 在客户端(浏览器)</li>\n<li>session 默认被存在在服务器的一个文件里(不是内存)</li>\n<li>session 的运行依赖 session id,而 session id 是存在 cookie 中的。</li>\n<li>cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗<br>考虑到安全应当使用session</li>\n<li>session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能<br>考虑到减轻服务器性能方面,应当使用COOKIE</li>\n<li>单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。(将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中)</li>\n</ol>\n<h1 id=\"3-前端Jsp页面中获取session对象\"><a href=\"#3-前端Jsp页面中获取session对象\" class=\"headerlink\" title=\"3.前端Jsp页面中获取session对象\"></a>3.前端Jsp页面中获取session对象</h1><h2 id=\"3-1-方法一(EL表达式)\"><a href=\"#3-1-方法一(EL表达式)\" class=\"headerlink\" title=\"3.1 方法一(EL表达式)\"></a>3.1 方法一(EL表达式)</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 前端获取存储在session对象中的用户id:userId</span></div><div class=\"line\"><span class=\"keyword\">var</span> studentId = <span class=\"string\">\"${sessionScope.userId}\"</span>;</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-方法二(Jsp语法)\"><a href=\"#3-2-方法二(Jsp语法)\" class=\"headerlink\" title=\"3.2 方法二(Jsp语法)\"></a>3.2 方法二(Jsp语法)</h2><figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 前端获取存储在session对象中的用户id:userId</span></div><div class=\"line\"><span class=\"keyword\">var</span> studentId = <span class=\"string\">\"<%=session.getAttribute(\"</span>userId<span class=\"string\">\")%>\"</span>;</div></pre></td></tr></table></figure>\n<h2 id=\"注意小坑\"><a href=\"#注意小坑\" class=\"headerlink\" title=\"注意小坑\"></a>注意小坑</h2><p>以上代码必须写在Jsp文件中,在引入外部Js文件时上述代码失效。</p>\n"},{"title":"ngrok外网映射","comment":true,"date":"2017-06-20T03:32:50.000Z","_content":"# 1.为什么需要外网映射\n\n我遇到的主要场景是在微信公众号开发中,因为用户跟微信公众号产生的交互行为,微信会把用户的相关信息推送到我们自己的服务器,而这个推送的前提是微信能够访问到我们的服务,如果服务在本地,那微信当然无法推送给我们,这使得开发功能的时候调试相当麻烦。外网映射就是把本地站点映射出去,解决微信推送给我们的用户信息等消息进行实时本地调试。\n\n# 2.外网映射工具ngrok\n\n> 官方介绍:ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay.\n>\n> 翻译: ngrok是一个能够将本地的网络服务安全的映射到公共网络的反向代理工具。ngrok捕获和分析所有通过隧道的流量后检查和重放。\n\n# 3. 使用方式\n\n## 3.1 ngrok几个问题\n\n- 目前国内访问该网站提供的服务(服务器在国外)相当不稳定,经常连接不上\n\n- 映射的外网域名是随机的。(想要固定域名需要付费服务)\n\n ![ScreenClip](http://ortur5wom.bkt.clouddn.com/ngrok0.png)\n\n## 3.2 ngrok国内服务器+固定域名\n\n国内有不少第三方的ngrok服务提供,如natapp、花生壳、Sunny-Ngrok等。这里我们选用Sunny-Ngrok,官网地址:[http://www.ngrok.cc/](http://www.ngrok.cc/)。\n\n**使用步骤:**\n\n1. 进入官网完成注册,登陆后点击 `开通隧道`(免费)\n\n2. 按照下图填写信息。\n\n ![2214876990875395](http://ortur5wom.bkt.clouddn.com/ngrok1.png)\n\n 点击 `确定添加`,获得`隧道id`。\n\n ![ScreenClip1](http://ortur5wom.bkt.clouddn.com/ngrok2.png)\n\n\n3. 官网下载客户端,使用`隧道id`启动已经创建好的隧道。\n\n ![ScreenClip1](http://ortur5wom.bkt.clouddn.com/ngrok3.png)\n\n 详细步骤地址:[http://www.sunnyos.com/article-show-71.html](http://www.sunnyos.com/article-show-71.html)\n\n","source":"_posts/ngrok外网映射.md","raw":"---\ntitle: ngrok外网映射\ncomment: true\ndate: 2017-06-20 11:32:50\ntags: [ngrok, 外网映射, 微信开发]\n---\n# 1.为什么需要外网映射\n\n我遇到的主要场景是在微信公众号开发中,因为用户跟微信公众号产生的交互行为,微信会把用户的相关信息推送到我们自己的服务器,而这个推送的前提是微信能够访问到我们的服务,如果服务在本地,那微信当然无法推送给我们,这使得开发功能的时候调试相当麻烦。外网映射就是把本地站点映射出去,解决微信推送给我们的用户信息等消息进行实时本地调试。\n\n# 2.外网映射工具ngrok\n\n> 官方介绍:ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay.\n>\n> 翻译: ngrok是一个能够将本地的网络服务安全的映射到公共网络的反向代理工具。ngrok捕获和分析所有通过隧道的流量后检查和重放。\n\n# 3. 使用方式\n\n## 3.1 ngrok几个问题\n\n- 目前国内访问该网站提供的服务(服务器在国外)相当不稳定,经常连接不上\n\n- 映射的外网域名是随机的。(想要固定域名需要付费服务)\n\n ![ScreenClip](http://ortur5wom.bkt.clouddn.com/ngrok0.png)\n\n## 3.2 ngrok国内服务器+固定域名\n\n国内有不少第三方的ngrok服务提供,如natapp、花生壳、Sunny-Ngrok等。这里我们选用Sunny-Ngrok,官网地址:[http://www.ngrok.cc/](http://www.ngrok.cc/)。\n\n**使用步骤:**\n\n1. 进入官网完成注册,登陆后点击 `开通隧道`(免费)\n\n2. 按照下图填写信息。\n\n ![2214876990875395](http://ortur5wom.bkt.clouddn.com/ngrok1.png)\n\n 点击 `确定添加`,获得`隧道id`。\n\n ![ScreenClip1](http://ortur5wom.bkt.clouddn.com/ngrok2.png)\n\n\n3. 官网下载客户端,使用`隧道id`启动已经创建好的隧道。\n\n ![ScreenClip1](http://ortur5wom.bkt.clouddn.com/ngrok3.png)\n\n 详细步骤地址:[http://www.sunnyos.com/article-show-71.html](http://www.sunnyos.com/article-show-71.html)\n\n","slug":"ngrok外网映射","published":1,"updated":"2017-10-14T12:25:12.751Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k6m000gwsv7pzipgtm7","content":"<h1 id=\"1-为什么需要外网映射\"><a href=\"#1-为什么需要外网映射\" class=\"headerlink\" title=\"1.为什么需要外网映射\"></a>1.为什么需要外网映射</h1><p>我遇到的主要场景是在微信公众号开发中,因为用户跟微信公众号产生的交互行为,微信会把用户的相关信息推送到我们自己的服务器,而这个推送的前提是微信能够访问到我们的服务,如果服务在本地,那微信当然无法推送给我们,这使得开发功能的时候调试相当麻烦。外网映射就是把本地站点映射出去,解决微信推送给我们的用户信息等消息进行实时本地调试。</p>\n<h1 id=\"2-外网映射工具ngrok\"><a href=\"#2-外网映射工具ngrok\" class=\"headerlink\" title=\"2.外网映射工具ngrok\"></a>2.外网映射工具ngrok</h1><blockquote>\n<p> 官方介绍:ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay.</p>\n<p> 翻译: ngrok是一个能够将本地的网络服务安全的映射到公共网络的反向代理工具。ngrok捕获和分析所有通过隧道的流量后检查和重放。</p>\n</blockquote>\n<h1 id=\"3-使用方式\"><a href=\"#3-使用方式\" class=\"headerlink\" title=\"3. 使用方式\"></a>3. 使用方式</h1><h2 id=\"3-1-ngrok几个问题\"><a href=\"#3-1-ngrok几个问题\" class=\"headerlink\" title=\"3.1 ngrok几个问题\"></a>3.1 ngrok几个问题</h2><ul>\n<li><p>目前国内访问该网站提供的服务(服务器在国外)相当不稳定,经常连接不上</p>\n</li>\n<li><p>映射的外网域名是随机的。(想要固定域名需要付费服务)</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok0.png\" alt=\"ScreenClip\"></p>\n</li>\n</ul>\n<h2 id=\"3-2-ngrok国内服务器-固定域名\"><a href=\"#3-2-ngrok国内服务器-固定域名\" class=\"headerlink\" title=\"3.2 ngrok国内服务器+固定域名\"></a>3.2 ngrok国内服务器+固定域名</h2><p>国内有不少第三方的ngrok服务提供,如natapp、花生壳、Sunny-Ngrok等。这里我们选用Sunny-Ngrok,官网地址:<a href=\"http://www.ngrok.cc/\" target=\"_blank\" rel=\"external\">http://www.ngrok.cc/</a>。</p>\n<p><strong>使用步骤:</strong></p>\n<ol>\n<li><p>进入官网完成注册,登陆后点击 <code>开通隧道</code>(免费)</p>\n</li>\n<li><p>按照下图填写信息。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok1.png\" alt=\"2214876990875395\"></p>\n<p>点击 <code>确定添加</code>,获得<code>隧道id</code>。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok2.png\" alt=\"ScreenClip1\"></p>\n</li>\n</ol>\n<ol>\n<li><p>官网下载客户端,使用<code>隧道id</code>启动已经创建好的隧道。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok3.png\" alt=\"ScreenClip1\"></p>\n<p>详细步骤地址:<a href=\"http://www.sunnyos.com/article-show-71.html\" target=\"_blank\" rel=\"external\">http://www.sunnyos.com/article-show-71.html</a></p>\n</li>\n</ol>\n","excerpt":"","more":"<h1 id=\"1-为什么需要外网映射\"><a href=\"#1-为什么需要外网映射\" class=\"headerlink\" title=\"1.为什么需要外网映射\"></a>1.为什么需要外网映射</h1><p>我遇到的主要场景是在微信公众号开发中,因为用户跟微信公众号产生的交互行为,微信会把用户的相关信息推送到我们自己的服务器,而这个推送的前提是微信能够访问到我们的服务,如果服务在本地,那微信当然无法推送给我们,这使得开发功能的时候调试相当麻烦。外网映射就是把本地站点映射出去,解决微信推送给我们的用户信息等消息进行实时本地调试。</p>\n<h1 id=\"2-外网映射工具ngrok\"><a href=\"#2-外网映射工具ngrok\" class=\"headerlink\" title=\"2.外网映射工具ngrok\"></a>2.外网映射工具ngrok</h1><blockquote>\n<p> 官方介绍:ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay.</p>\n<p> 翻译: ngrok是一个能够将本地的网络服务安全的映射到公共网络的反向代理工具。ngrok捕获和分析所有通过隧道的流量后检查和重放。</p>\n</blockquote>\n<h1 id=\"3-使用方式\"><a href=\"#3-使用方式\" class=\"headerlink\" title=\"3. 使用方式\"></a>3. 使用方式</h1><h2 id=\"3-1-ngrok几个问题\"><a href=\"#3-1-ngrok几个问题\" class=\"headerlink\" title=\"3.1 ngrok几个问题\"></a>3.1 ngrok几个问题</h2><ul>\n<li><p>目前国内访问该网站提供的服务(服务器在国外)相当不稳定,经常连接不上</p>\n</li>\n<li><p>映射的外网域名是随机的。(想要固定域名需要付费服务)</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok0.png\" alt=\"ScreenClip\"></p>\n</li>\n</ul>\n<h2 id=\"3-2-ngrok国内服务器-固定域名\"><a href=\"#3-2-ngrok国内服务器-固定域名\" class=\"headerlink\" title=\"3.2 ngrok国内服务器+固定域名\"></a>3.2 ngrok国内服务器+固定域名</h2><p>国内有不少第三方的ngrok服务提供,如natapp、花生壳、Sunny-Ngrok等。这里我们选用Sunny-Ngrok,官网地址:<a href=\"http://www.ngrok.cc/\">http://www.ngrok.cc/</a>。</p>\n<p><strong>使用步骤:</strong></p>\n<ol>\n<li><p>进入官网完成注册,登陆后点击 <code>开通隧道</code>(免费)</p>\n</li>\n<li><p>按照下图填写信息。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok1.png\" alt=\"2214876990875395\"></p>\n<p>点击 <code>确定添加</code>,获得<code>隧道id</code>。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok2.png\" alt=\"ScreenClip1\"></p>\n</li>\n</ol>\n<ol>\n<li><p>官网下载客户端,使用<code>隧道id</code>启动已经创建好的隧道。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/ngrok3.png\" alt=\"ScreenClip1\"></p>\n<p>详细步骤地址:<a href=\"http://www.sunnyos.com/article-show-71.html\">http://www.sunnyos.com/article-show-71.html</a></p>\n</li>\n</ol>\n"},{"title":"为你的网站添加动画彩带背景-尤雨溪博客","comment":true,"date":"2017-04-10T12:57:25.000Z","cover":"http://ortur5wom.bkt.clouddn.com/cover-ribbon.jpg","_content":"\n一直关注着前端框架Vue的作者尤雨溪,前些天浏览到他的博客,被他博客的动画背景深深吸引。大体效果如下图。\n\n![ScreenClip](http://ortur5wom.bkt.clouddn.com/canvas1.png)\n\n是的,一条飘逸、灵动的彩带!但更Amazing的是当用用户点击页面时,背景彩带也会实时响应点击事件,随机生成不同路径、不同颜色的新彩带。我瞬间中了这变幻莫测彩带条的毒,呆呆地点了半天的屏幕,好玩到根本停不下来。。\n\n\n接下来,让我们看一下如何实现这一canvas背景彩带的效果。其实只需要简单的几十行代码,就能轻松实现。然后就可以添加到自己的个人网站了。\n\n# 用到的知识\n\njs基础+canvas\n\n# 实现思路\n\n## 1.canvas的使用\n\n`CanvasRenderingContext2D` 接口提供的 2D 渲染背景用来绘制[canvas](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas)元素,为了获得这个接口的对象,需要在`<canvas>`上调用 [getContext()](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext) ,并提供一个 `\"2d\"` 的参数:\n\n```javascript\nvar canvas = document.getElementById('tutorial');\nvar ctx = canvas.getContext('2d');\n```\n\n一旦你得到 2D 渲染背景后,你可以像下面一样绘制:\n\n(以绘制`路径`为例,此外矩形、文本、图像等)\n\n```javascript\nctx.beginPath();\nctx.strokeStyle = 'blue';\nctx.moveTo(10,50);\nctx.lineTo(200,50);\nctx.stroke();\n```\n\n绘制效果如下:\n\n![ScreenClip1](http://ortur5wom.bkt.clouddn.com/canvas2.png)\n\n## 2.绘制折线\n\n对以上代码稍作改变,使直线变为折线:\n\n``` javascript\nctx.beginPath();\nctx.strokeStyle = 'blue';\nctx.moveTo(10,50);\nctx.lineTo(100,80);\nctx.lineTo(200,20);\nctx.lineTo(300,40);\nctx.stroke();\nctx.closePath();\n```\n\n绘制效果如下:\n\n![ScreenClip2](http://ortur5wom.bkt.clouddn.com/canvas3.png)\n\n此时,一条与最终要实现的背景彩带在大体形状上已初具雏形。只是缺少自动绘制、路径宽度和其中每一段路径上随机的颜色。\n\n## 3.绘制背景彩带\n\n以下是我的源代码,其中已有详细的注释信息,相信你一定能够看懂的。复制一下代码,保存为html文件,浏览器打开即可运行查看。\n\n``` html\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\"\n content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n <title>Document</title>\n</head>\n<body>\n<canvas></canvas>\n<script>\n document.addEventListener('touchmove', function (e) {\n e.preventDefault()\n });\n var canvasRibbon = document.getElementsByTagName('canvas')[0],\n ctx = canvasRibbon.getContext('2d'), // 获取canvas 2d上下文\n dpr = window.devicePixelRatio || 1, // the size of one CSS pixel to the size of one physical pixel.\n width = window.innerWidth, // 返回窗口的文档显示区的宽高\n height = window.innerHeight,\n RIBBON_WIDE = 90,\n path,\n math = Math,\n r = 0,\n PI_2 = math.PI * 2, // 圆周率*2\n cos = math.cos, // cos函数返回一个数值的余弦值(-1~1)\n random = math.random; // 返回0-1随机数\n\n canvasRibbon.width = width * dpr; // 返回实际宽高\n canvasRibbon.height = height * dpr;\n ctx.scale(dpr, dpr); // 水平、竖直方向缩放\n ctx.globalAlpha = 0.6; // 图形透明度\n\n function init() {\n ctx.clearRect(0, 0, width, height); // 擦除之前绘制内容\n path = [{x: 0, y: height * 0.7 + RIBBON_WIDE}, {x: 0, y: height * 0.7 - RIBBON_WIDE}];\n // 路径没有填满屏幕宽度时,绘制路径\n while (path[1].x < width + RIBBON_WIDE) {\n draw(path[0], path[1]) // 调用绘制方法\n }\n }\n\n // 绘制彩带每一段路径\n function draw(start, end) {\n ctx.beginPath(); // 创建一个新的路径\n ctx.moveTo(start.x, start.y); // path起点\n ctx.lineTo(end.x, end.y); // path终点\n var nextX = end.x + (random() * 2 - 0.25) * RIBBON_WIDE,\n nextY = geneY(end.y);\n ctx.lineTo(nextX, nextY);\n ctx.closePath();\n\n r -= PI_2 / -50;\n // 随机生成并设置canvas路径16进制颜色\n ctx.fillStyle = '#' + (cos(r) * 127 + 128 << 16 | cos(r + PI_2 / 3) * 127 + 128 << 8 | cos(r + PI_2 / 3 * 2) * 127 + 128).toString(16);\n ctx.fill(); // 根据当前样式填充路径\n path[0] = path[1]; // 起点更新为当前终点\n path[1] = {x: nextX, y: nextY} // 更新终点\n }\n\n // 获取下一路径终点的y坐标值\n function geneY(y) {\n var temp = y + (random() * 2 - 1.1) * RIBBON_WIDE;\n return (temp > height || temp < 0) ? geneY(y) : temp\n }\n\n document.onclick = init;\n document.ontouchstart = init;\n init();\n</script>\n</body>\n</html>\n```\n\n此外我还提供[简单一条命令为你的网页添加canvas-ribbon背景彩带](https://github.com/zproo/canvas-ribbon)(Github源码)的方法。你可以直接访问我的github仓库获得,只需要一行代码就可以为你的网站添加上面介绍的canvas-ribbon背景彩带了。\n\n# 后记\n\n在为我自己的博客添加成功后,我还对Hexo 的Next主题添加了这一功能(只适用于Next的Pisces主题),并给Next作者发了PR。\n\n现在此提交已被作者Merge,所以如果你的博客使用了Hexo的Next主题,只需要在`主题配置文件`中找到`canvas-ribbon`属性,并设置为`true`,即可拥有背景彩带的效果。\n\n![ScreenClip3](http://ortur5wom.bkt.clouddn.com/canvas4.png)\n\n# 参考资料\n\n- [CanvasRenderingContext2D-路径](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/beginPath)\n- [evanyou](http://evanyou.me/)","source":"_posts/为Next主题添加canvas-ribbon.md","raw":"---\ntitle: 为你的网站添加动画彩带背景-尤雨溪博客\ncomment: true\ndate: 2017-04-10 20:57:25\ntags: [Hexo, GitHub, Canvas,Next,JavaScript]\ncover: http://ortur5wom.bkt.clouddn.com/cover-ribbon.jpg\n---\n\n一直关注着前端框架Vue的作者尤雨溪,前些天浏览到他的博客,被他博客的动画背景深深吸引。大体效果如下图。\n\n![ScreenClip](http://ortur5wom.bkt.clouddn.com/canvas1.png)\n\n是的,一条飘逸、灵动的彩带!但更Amazing的是当用用户点击页面时,背景彩带也会实时响应点击事件,随机生成不同路径、不同颜色的新彩带。我瞬间中了这变幻莫测彩带条的毒,呆呆地点了半天的屏幕,好玩到根本停不下来。。\n\n\n接下来,让我们看一下如何实现这一canvas背景彩带的效果。其实只需要简单的几十行代码,就能轻松实现。然后就可以添加到自己的个人网站了。\n\n# 用到的知识\n\njs基础+canvas\n\n# 实现思路\n\n## 1.canvas的使用\n\n`CanvasRenderingContext2D` 接口提供的 2D 渲染背景用来绘制[canvas](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas)元素,为了获得这个接口的对象,需要在`<canvas>`上调用 [getContext()](https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext) ,并提供一个 `\"2d\"` 的参数:\n\n```javascript\nvar canvas = document.getElementById('tutorial');\nvar ctx = canvas.getContext('2d');\n```\n\n一旦你得到 2D 渲染背景后,你可以像下面一样绘制:\n\n(以绘制`路径`为例,此外矩形、文本、图像等)\n\n```javascript\nctx.beginPath();\nctx.strokeStyle = 'blue';\nctx.moveTo(10,50);\nctx.lineTo(200,50);\nctx.stroke();\n```\n\n绘制效果如下:\n\n![ScreenClip1](http://ortur5wom.bkt.clouddn.com/canvas2.png)\n\n## 2.绘制折线\n\n对以上代码稍作改变,使直线变为折线:\n\n``` javascript\nctx.beginPath();\nctx.strokeStyle = 'blue';\nctx.moveTo(10,50);\nctx.lineTo(100,80);\nctx.lineTo(200,20);\nctx.lineTo(300,40);\nctx.stroke();\nctx.closePath();\n```\n\n绘制效果如下:\n\n![ScreenClip2](http://ortur5wom.bkt.clouddn.com/canvas3.png)\n\n此时,一条与最终要实现的背景彩带在大体形状上已初具雏形。只是缺少自动绘制、路径宽度和其中每一段路径上随机的颜色。\n\n## 3.绘制背景彩带\n\n以下是我的源代码,其中已有详细的注释信息,相信你一定能够看懂的。复制一下代码,保存为html文件,浏览器打开即可运行查看。\n\n``` html\n<html>\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\"\n content=\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n <title>Document</title>\n</head>\n<body>\n<canvas></canvas>\n<script>\n document.addEventListener('touchmove', function (e) {\n e.preventDefault()\n });\n var canvasRibbon = document.getElementsByTagName('canvas')[0],\n ctx = canvasRibbon.getContext('2d'), // 获取canvas 2d上下文\n dpr = window.devicePixelRatio || 1, // the size of one CSS pixel to the size of one physical pixel.\n width = window.innerWidth, // 返回窗口的文档显示区的宽高\n height = window.innerHeight,\n RIBBON_WIDE = 90,\n path,\n math = Math,\n r = 0,\n PI_2 = math.PI * 2, // 圆周率*2\n cos = math.cos, // cos函数返回一个数值的余弦值(-1~1)\n random = math.random; // 返回0-1随机数\n\n canvasRibbon.width = width * dpr; // 返回实际宽高\n canvasRibbon.height = height * dpr;\n ctx.scale(dpr, dpr); // 水平、竖直方向缩放\n ctx.globalAlpha = 0.6; // 图形透明度\n\n function init() {\n ctx.clearRect(0, 0, width, height); // 擦除之前绘制内容\n path = [{x: 0, y: height * 0.7 + RIBBON_WIDE}, {x: 0, y: height * 0.7 - RIBBON_WIDE}];\n // 路径没有填满屏幕宽度时,绘制路径\n while (path[1].x < width + RIBBON_WIDE) {\n draw(path[0], path[1]) // 调用绘制方法\n }\n }\n\n // 绘制彩带每一段路径\n function draw(start, end) {\n ctx.beginPath(); // 创建一个新的路径\n ctx.moveTo(start.x, start.y); // path起点\n ctx.lineTo(end.x, end.y); // path终点\n var nextX = end.x + (random() * 2 - 0.25) * RIBBON_WIDE,\n nextY = geneY(end.y);\n ctx.lineTo(nextX, nextY);\n ctx.closePath();\n\n r -= PI_2 / -50;\n // 随机生成并设置canvas路径16进制颜色\n ctx.fillStyle = '#' + (cos(r) * 127 + 128 << 16 | cos(r + PI_2 / 3) * 127 + 128 << 8 | cos(r + PI_2 / 3 * 2) * 127 + 128).toString(16);\n ctx.fill(); // 根据当前样式填充路径\n path[0] = path[1]; // 起点更新为当前终点\n path[1] = {x: nextX, y: nextY} // 更新终点\n }\n\n // 获取下一路径终点的y坐标值\n function geneY(y) {\n var temp = y + (random() * 2 - 1.1) * RIBBON_WIDE;\n return (temp > height || temp < 0) ? geneY(y) : temp\n }\n\n document.onclick = init;\n document.ontouchstart = init;\n init();\n</script>\n</body>\n</html>\n```\n\n此外我还提供[简单一条命令为你的网页添加canvas-ribbon背景彩带](https://github.com/zproo/canvas-ribbon)(Github源码)的方法。你可以直接访问我的github仓库获得,只需要一行代码就可以为你的网站添加上面介绍的canvas-ribbon背景彩带了。\n\n# 后记\n\n在为我自己的博客添加成功后,我还对Hexo 的Next主题添加了这一功能(只适用于Next的Pisces主题),并给Next作者发了PR。\n\n现在此提交已被作者Merge,所以如果你的博客使用了Hexo的Next主题,只需要在`主题配置文件`中找到`canvas-ribbon`属性,并设置为`true`,即可拥有背景彩带的效果。\n\n![ScreenClip3](http://ortur5wom.bkt.clouddn.com/canvas4.png)\n\n# 参考资料\n\n- [CanvasRenderingContext2D-路径](https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/beginPath)\n- [evanyou](http://evanyou.me/)","slug":"为Next主题添加canvas-ribbon","published":1,"updated":"2017-10-14T12:25:12.751Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k72000iwsv7g7xzdin1","content":"<p>一直关注着前端框架Vue的作者尤雨溪,前些天浏览到他的博客,被他博客的动画背景深深吸引。大体效果如下图。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas1.png\" alt=\"ScreenClip\"></p>\n<p>是的,一条飘逸、灵动的彩带!但更Amazing的是当用用户点击页面时,背景彩带也会实时响应点击事件,随机生成不同路径、不同颜色的新彩带。我瞬间中了这变幻莫测彩带条的毒,呆呆地点了半天的屏幕,好玩到根本停不下来。。</p>\n<p>接下来,让我们看一下如何实现这一canvas背景彩带的效果。其实只需要简单的几十行代码,就能轻松实现。然后就可以添加到自己的个人网站了。</p>\n<h1 id=\"用到的知识\"><a href=\"#用到的知识\" class=\"headerlink\" title=\"用到的知识\"></a>用到的知识</h1><p>js基础+canvas</p>\n<h1 id=\"实现思路\"><a href=\"#实现思路\" class=\"headerlink\" title=\"实现思路\"></a>实现思路</h1><h2 id=\"1-canvas的使用\"><a href=\"#1-canvas的使用\" class=\"headerlink\" title=\"1.canvas的使用\"></a>1.canvas的使用</h2><p><code>CanvasRenderingContext2D</code> 接口提供的 2D 渲染背景用来绘制<a href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas\" target=\"_blank\" rel=\"external\">canvas</a>元素,为了获得这个接口的对象,需要在<code><canvas></code>上调用 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext\" target=\"_blank\" rel=\"external\">getContext()</a> ,并提供一个 <code>"2d"</code> 的参数:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">var</span> canvas = <span class=\"built_in\">document</span>.getElementById(<span class=\"string\">'tutorial'</span>);</div><div class=\"line\"><span class=\"keyword\">var</span> ctx = canvas.getContext(<span class=\"string\">'2d'</span>);</div></pre></td></tr></table></figure>\n<p>一旦你得到 2D 渲染背景后,你可以像下面一样绘制:</p>\n<p>(以绘制<code>路径</code>为例,此外矩形、文本、图像等)</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">ctx.beginPath();</div><div class=\"line\">ctx.strokeStyle = <span class=\"string\">'blue'</span>;</div><div class=\"line\">ctx.moveTo(<span class=\"number\">10</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">200</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.stroke();</div></pre></td></tr></table></figure>\n<p>绘制效果如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas2.png\" alt=\"ScreenClip1\"></p>\n<h2 id=\"2-绘制折线\"><a href=\"#2-绘制折线\" class=\"headerlink\" title=\"2.绘制折线\"></a>2.绘制折线</h2><p>对以上代码稍作改变,使直线变为折线:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">ctx.beginPath();</div><div class=\"line\">ctx.strokeStyle = <span class=\"string\">'blue'</span>;</div><div class=\"line\">ctx.moveTo(<span class=\"number\">10</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">100</span>,<span class=\"number\">80</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">200</span>,<span class=\"number\">20</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">300</span>,<span class=\"number\">40</span>);</div><div class=\"line\">ctx.stroke();</div><div class=\"line\">ctx.closePath();</div></pre></td></tr></table></figure>\n<p>绘制效果如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas3.png\" alt=\"ScreenClip2\"></p>\n<p>此时,一条与最终要实现的背景彩带在大体形状上已初具雏形。只是缺少自动绘制、路径宽度和其中每一段路径上随机的颜色。</p>\n<h2 id=\"3-绘制背景彩带\"><a href=\"#3-绘制背景彩带\" class=\"headerlink\" title=\"3.绘制背景彩带\"></a>3.绘制背景彩带</h2><p>以下是我的源代码,其中已有详细的注释信息,相信你一定能够看懂的。复制一下代码,保存为html文件,浏览器打开即可运行查看。</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">charset</span>=<span class=\"string\">\"UTF-8\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">name</span>=<span class=\"string\">\"viewport\"</span></span></div><div class=\"line\"> <span class=\"attr\">content</span>=<span class=\"string\">\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\"</span>></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">http-equiv</span>=<span class=\"string\">\"X-UA-Compatible\"</span> <span class=\"attr\">content</span>=<span class=\"string\">\"ie=edge\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">title</span>></span>Document<span class=\"tag\"></<span class=\"name\">title</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">canvas</span>></span><span class=\"tag\"></<span class=\"name\">canvas</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></span></div><div class=\"line\"> <span class=\"built_in\">document</span>.addEventListener(<span class=\"string\">'touchmove'</span>, <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\">e</span>) </span>{</div><div class=\"line\"> e.preventDefault()</div><div class=\"line\"> });</div><div class=\"line\"> <span class=\"keyword\">var</span> canvasRibbon = <span class=\"built_in\">document</span>.getElementsByTagName(<span class=\"string\">'canvas'</span>)[<span class=\"number\">0</span>],</div><div class=\"line\"> ctx = canvasRibbon.getContext(<span class=\"string\">'2d'</span>), <span class=\"comment\">// 获取canvas 2d上下文</span></div><div class=\"line\"> dpr = <span class=\"built_in\">window</span>.devicePixelRatio || <span class=\"number\">1</span>, <span class=\"comment\">// the size of one CSS pixel to the size of one physical pixel.</span></div><div class=\"line\"> width = <span class=\"built_in\">window</span>.innerWidth, <span class=\"comment\">// 返回窗口的文档显示区的宽高</span></div><div class=\"line\"> height = <span class=\"built_in\">window</span>.innerHeight,</div><div class=\"line\"> RIBBON_WIDE = <span class=\"number\">90</span>,</div><div class=\"line\"> path,</div><div class=\"line\"> math = <span class=\"built_in\">Math</span>,</div><div class=\"line\"> r = <span class=\"number\">0</span>,</div><div class=\"line\"> PI_2 = math.PI * <span class=\"number\">2</span>, <span class=\"comment\">// 圆周率*2</span></div><div class=\"line\"> cos = math.cos, <span class=\"comment\">// cos函数返回一个数值的余弦值(-1~1)</span></div><div class=\"line\"> random = math.random; <span class=\"comment\">// 返回0-1随机数</span></div><div class=\"line\"></div><div class=\"line\"> canvasRibbon.width = width * dpr; <span class=\"comment\">// 返回实际宽高</span></div><div class=\"line\"> canvasRibbon.height = height * dpr;</div><div class=\"line\"> ctx.scale(dpr, dpr); <span class=\"comment\">// 水平、竖直方向缩放</span></div><div class=\"line\"> ctx.globalAlpha = <span class=\"number\">0.6</span>; <span class=\"comment\">// 图形透明度</span></div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">init</span>(<span class=\"params\"></span>) </span>{</div><div class=\"line\"> ctx.clearRect(<span class=\"number\">0</span>, <span class=\"number\">0</span>, width, height); <span class=\"comment\">// 擦除之前绘制内容</span></div><div class=\"line\"> path = [{<span class=\"attr\">x</span>: <span class=\"number\">0</span>, <span class=\"attr\">y</span>: height * <span class=\"number\">0.7</span> + RIBBON_WIDE}, {<span class=\"attr\">x</span>: <span class=\"number\">0</span>, <span class=\"attr\">y</span>: height * <span class=\"number\">0.7</span> - RIBBON_WIDE}];</div><div class=\"line\"> <span class=\"comment\">// 路径没有填满屏幕宽度时,绘制路径</span></div><div class=\"line\"> <span class=\"keyword\">while</span> (path[<span class=\"number\">1</span>].x < width + RIBBON_WIDE) {</div><div class=\"line\"> draw(path[<span class=\"number\">0</span>], path[<span class=\"number\">1</span>]) <span class=\"comment\">// 调用绘制方法</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 绘制彩带每一段路径</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">draw</span>(<span class=\"params\">start, end</span>) </span>{</div><div class=\"line\"> ctx.beginPath(); <span class=\"comment\">// 创建一个新的路径</span></div><div class=\"line\"> ctx.moveTo(start.x, start.y); <span class=\"comment\">// path起点</span></div><div class=\"line\"> ctx.lineTo(end.x, end.y); <span class=\"comment\">// path终点</span></div><div class=\"line\"> <span class=\"keyword\">var</span> nextX = end.x + (random() * <span class=\"number\">2</span> - <span class=\"number\">0.25</span>) * RIBBON_WIDE,</div><div class=\"line\"> nextY = geneY(end.y);</div><div class=\"line\"> ctx.lineTo(nextX, nextY);</div><div class=\"line\"> ctx.closePath();</div><div class=\"line\"></div><div class=\"line\"> r -= PI_2 / <span class=\"number\">-50</span>;</div><div class=\"line\"> <span class=\"comment\">// 随机生成并设置canvas路径16进制颜色</span></div><div class=\"line\"> ctx.fillStyle = <span class=\"string\">'#'</span> + (cos(r) * <span class=\"number\">127</span> + <span class=\"number\">128</span> << <span class=\"number\">16</span> | cos(r + PI_2 / <span class=\"number\">3</span>) * <span class=\"number\">127</span> + <span class=\"number\">128</span> << <span class=\"number\">8</span> | cos(r + PI_2 / <span class=\"number\">3</span> * <span class=\"number\">2</span>) * <span class=\"number\">127</span> + <span class=\"number\">128</span>).toString(<span class=\"number\">16</span>);</div><div class=\"line\"> ctx.fill(); <span class=\"comment\">// 根据当前样式填充路径</span></div><div class=\"line\"> path[<span class=\"number\">0</span>] = path[<span class=\"number\">1</span>]; <span class=\"comment\">// 起点更新为当前终点</span></div><div class=\"line\"> path[<span class=\"number\">1</span>] = {<span class=\"attr\">x</span>: nextX, <span class=\"attr\">y</span>: nextY} <span class=\"comment\">// 更新终点</span></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 获取下一路径终点的y坐标值</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">geneY</span>(<span class=\"params\">y</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> temp = y + (random() * <span class=\"number\">2</span> - <span class=\"number\">1.1</span>) * RIBBON_WIDE;</div><div class=\"line\"> <span class=\"keyword\">return</span> (temp > height || temp < <span class=\"number\">0</span>) ? geneY(y) : temp</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"built_in\">document</span>.onclick = init;</div><div class=\"line\"> <span class=\"built_in\">document</span>.ontouchstart = init;</div><div class=\"line\"> init();</div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>此外我还提供<a href=\"https://github.com/zproo/canvas-ribbon\" target=\"_blank\" rel=\"external\">简单一条命令为你的网页添加canvas-ribbon背景彩带</a>(Github源码)的方法。你可以直接访问我的github仓库获得,只需要一行代码就可以为你的网站添加上面介绍的canvas-ribbon背景彩带了。</p>\n<h1 id=\"后记\"><a href=\"#后记\" class=\"headerlink\" title=\"后记\"></a>后记</h1><p>在为我自己的博客添加成功后,我还对Hexo 的Next主题添加了这一功能(只适用于Next的Pisces主题),并给Next作者发了PR。</p>\n<p>现在此提交已被作者Merge,所以如果你的博客使用了Hexo的Next主题,只需要在<code>主题配置文件</code>中找到<code>canvas-ribbon</code>属性,并设置为<code>true</code>,即可拥有背景彩带的效果。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas4.png\" alt=\"ScreenClip3\"></p>\n<h1 id=\"参考资料\"><a href=\"#参考资料\" class=\"headerlink\" title=\"参考资料\"></a>参考资料</h1><ul>\n<li><a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/beginPath\" target=\"_blank\" rel=\"external\">CanvasRenderingContext2D-路径</a></li>\n<li><a href=\"http://evanyou.me/\" target=\"_blank\" rel=\"external\">evanyou</a></li>\n</ul>\n","excerpt":"","more":"<p>一直关注着前端框架Vue的作者尤雨溪,前些天浏览到他的博客,被他博客的动画背景深深吸引。大体效果如下图。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas1.png\" alt=\"ScreenClip\"></p>\n<p>是的,一条飘逸、灵动的彩带!但更Amazing的是当用用户点击页面时,背景彩带也会实时响应点击事件,随机生成不同路径、不同颜色的新彩带。我瞬间中了这变幻莫测彩带条的毒,呆呆地点了半天的屏幕,好玩到根本停不下来。。</p>\n<p>接下来,让我们看一下如何实现这一canvas背景彩带的效果。其实只需要简单的几十行代码,就能轻松实现。然后就可以添加到自己的个人网站了。</p>\n<h1 id=\"用到的知识\"><a href=\"#用到的知识\" class=\"headerlink\" title=\"用到的知识\"></a>用到的知识</h1><p>js基础+canvas</p>\n<h1 id=\"实现思路\"><a href=\"#实现思路\" class=\"headerlink\" title=\"实现思路\"></a>实现思路</h1><h2 id=\"1-canvas的使用\"><a href=\"#1-canvas的使用\" class=\"headerlink\" title=\"1.canvas的使用\"></a>1.canvas的使用</h2><p><code>CanvasRenderingContext2D</code> 接口提供的 2D 渲染背景用来绘制<a href=\"https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/canvas\">canvas</a>元素,为了获得这个接口的对象,需要在<code><canvas></code>上调用 <a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext\">getContext()</a> ,并提供一个 <code>"2d"</code> 的参数:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">var</span> canvas = <span class=\"built_in\">document</span>.getElementById(<span class=\"string\">'tutorial'</span>);</div><div class=\"line\"><span class=\"keyword\">var</span> ctx = canvas.getContext(<span class=\"string\">'2d'</span>);</div></pre></td></tr></table></figure>\n<p>一旦你得到 2D 渲染背景后,你可以像下面一样绘制:</p>\n<p>(以绘制<code>路径</code>为例,此外矩形、文本、图像等)</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div></pre></td><td class=\"code\"><pre><div class=\"line\">ctx.beginPath();</div><div class=\"line\">ctx.strokeStyle = <span class=\"string\">'blue'</span>;</div><div class=\"line\">ctx.moveTo(<span class=\"number\">10</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">200</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.stroke();</div></pre></td></tr></table></figure>\n<p>绘制效果如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas2.png\" alt=\"ScreenClip1\"></p>\n<h2 id=\"2-绘制折线\"><a href=\"#2-绘制折线\" class=\"headerlink\" title=\"2.绘制折线\"></a>2.绘制折线</h2><p>对以上代码稍作改变,使直线变为折线:</p>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\">ctx.beginPath();</div><div class=\"line\">ctx.strokeStyle = <span class=\"string\">'blue'</span>;</div><div class=\"line\">ctx.moveTo(<span class=\"number\">10</span>,<span class=\"number\">50</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">100</span>,<span class=\"number\">80</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">200</span>,<span class=\"number\">20</span>);</div><div class=\"line\">ctx.lineTo(<span class=\"number\">300</span>,<span class=\"number\">40</span>);</div><div class=\"line\">ctx.stroke();</div><div class=\"line\">ctx.closePath();</div></pre></td></tr></table></figure>\n<p>绘制效果如下:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas3.png\" alt=\"ScreenClip2\"></p>\n<p>此时,一条与最终要实现的背景彩带在大体形状上已初具雏形。只是缺少自动绘制、路径宽度和其中每一段路径上随机的颜色。</p>\n<h2 id=\"3-绘制背景彩带\"><a href=\"#3-绘制背景彩带\" class=\"headerlink\" title=\"3.绘制背景彩带\"></a>3.绘制背景彩带</h2><p>以下是我的源代码,其中已有详细的注释信息,相信你一定能够看懂的。复制一下代码,保存为html文件,浏览器打开即可运行查看。</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">charset</span>=<span class=\"string\">\"UTF-8\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">name</span>=<span class=\"string\">\"viewport\"</span></div><div class=\"line\"> <span class=\"attr\">content</span>=<span class=\"string\">\"width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">meta</span> <span class=\"attr\">http-equiv</span>=<span class=\"string\">\"X-UA-Compatible\"</span> <span class=\"attr\">content</span>=<span class=\"string\">\"ie=edge\"</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">title</span>></span>Document<span class=\"tag\"></<span class=\"name\">title</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">canvas</span>></span><span class=\"tag\"></<span class=\"name\">canvas</span>></span></div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></div><div class=\"line\"> <span class=\"built_in\">document</span>.addEventListener(<span class=\"string\">'touchmove'</span>, <span class=\"function\"><span class=\"keyword\">function</span> (<span class=\"params\">e</span>) </span>{</div><div class=\"line\"> e.preventDefault()</div><div class=\"line\"> });</div><div class=\"line\"> <span class=\"keyword\">var</span> canvasRibbon = <span class=\"built_in\">document</span>.getElementsByTagName(<span class=\"string\">'canvas'</span>)[<span class=\"number\">0</span>],</div><div class=\"line\"> ctx = canvasRibbon.getContext(<span class=\"string\">'2d'</span>), <span class=\"comment\">// 获取canvas 2d上下文</span></div><div class=\"line\"> dpr = <span class=\"built_in\">window</span>.devicePixelRatio || <span class=\"number\">1</span>, <span class=\"comment\">// the size of one CSS pixel to the size of one physical pixel.</span></div><div class=\"line\"> width = <span class=\"built_in\">window</span>.innerWidth, <span class=\"comment\">// 返回窗口的文档显示区的宽高</span></div><div class=\"line\"> height = <span class=\"built_in\">window</span>.innerHeight,</div><div class=\"line\"> RIBBON_WIDE = <span class=\"number\">90</span>,</div><div class=\"line\"> path,</div><div class=\"line\"> math = <span class=\"built_in\">Math</span>,</div><div class=\"line\"> r = <span class=\"number\">0</span>,</div><div class=\"line\"> PI_2 = math.PI * <span class=\"number\">2</span>, <span class=\"comment\">// 圆周率*2</span></div><div class=\"line\"> cos = math.cos, <span class=\"comment\">// cos函数返回一个数值的余弦值(-1~1)</span></div><div class=\"line\"> random = math.random; <span class=\"comment\">// 返回0-1随机数</span></div><div class=\"line\"></div><div class=\"line\"> canvasRibbon.width = width * dpr; <span class=\"comment\">// 返回实际宽高</span></div><div class=\"line\"> canvasRibbon.height = height * dpr;</div><div class=\"line\"> ctx.scale(dpr, dpr); <span class=\"comment\">// 水平、竖直方向缩放</span></div><div class=\"line\"> ctx.globalAlpha = <span class=\"number\">0.6</span>; <span class=\"comment\">// 图形透明度</span></div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">init</span>(<span class=\"params\"></span>) </span>{</div><div class=\"line\"> ctx.clearRect(<span class=\"number\">0</span>, <span class=\"number\">0</span>, width, height); <span class=\"comment\">// 擦除之前绘制内容</span></div><div class=\"line\"> path = [{<span class=\"attr\">x</span>: <span class=\"number\">0</span>, <span class=\"attr\">y</span>: height * <span class=\"number\">0.7</span> + RIBBON_WIDE}, {<span class=\"attr\">x</span>: <span class=\"number\">0</span>, <span class=\"attr\">y</span>: height * <span class=\"number\">0.7</span> - RIBBON_WIDE}];</div><div class=\"line\"> <span class=\"comment\">// 路径没有填满屏幕宽度时,绘制路径</span></div><div class=\"line\"> <span class=\"keyword\">while</span> (path[<span class=\"number\">1</span>].x < width + RIBBON_WIDE) {</div><div class=\"line\"> draw(path[<span class=\"number\">0</span>], path[<span class=\"number\">1</span>]) <span class=\"comment\">// 调用绘制方法</span></div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 绘制彩带每一段路径</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">draw</span>(<span class=\"params\">start, end</span>) </span>{</div><div class=\"line\"> ctx.beginPath(); <span class=\"comment\">// 创建一个新的路径</span></div><div class=\"line\"> ctx.moveTo(start.x, start.y); <span class=\"comment\">// path起点</span></div><div class=\"line\"> ctx.lineTo(end.x, end.y); <span class=\"comment\">// path终点</span></div><div class=\"line\"> <span class=\"keyword\">var</span> nextX = end.x + (random() * <span class=\"number\">2</span> - <span class=\"number\">0.25</span>) * RIBBON_WIDE,</div><div class=\"line\"> nextY = geneY(end.y);</div><div class=\"line\"> ctx.lineTo(nextX, nextY);</div><div class=\"line\"> ctx.closePath();</div><div class=\"line\"></div><div class=\"line\"> r -= PI_2 / <span class=\"number\">-50</span>;</div><div class=\"line\"> <span class=\"comment\">// 随机生成并设置canvas路径16进制颜色</span></div><div class=\"line\"> ctx.fillStyle = <span class=\"string\">'#'</span> + (cos(r) * <span class=\"number\">127</span> + <span class=\"number\">128</span> << <span class=\"number\">16</span> | cos(r + PI_2 / <span class=\"number\">3</span>) * <span class=\"number\">127</span> + <span class=\"number\">128</span> << <span class=\"number\">8</span> | cos(r + PI_2 / <span class=\"number\">3</span> * <span class=\"number\">2</span>) * <span class=\"number\">127</span> + <span class=\"number\">128</span>).toString(<span class=\"number\">16</span>);</div><div class=\"line\"> ctx.fill(); <span class=\"comment\">// 根据当前样式填充路径</span></div><div class=\"line\"> path[<span class=\"number\">0</span>] = path[<span class=\"number\">1</span>]; <span class=\"comment\">// 起点更新为当前终点</span></div><div class=\"line\"> path[<span class=\"number\">1</span>] = {<span class=\"attr\">x</span>: nextX, <span class=\"attr\">y</span>: nextY} <span class=\"comment\">// 更新终点</span></div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 获取下一路径终点的y坐标值</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">geneY</span>(<span class=\"params\">y</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> temp = y + (random() * <span class=\"number\">2</span> - <span class=\"number\">1.1</span>) * RIBBON_WIDE;</div><div class=\"line\"> <span class=\"keyword\">return</span> (temp > height || temp < <span class=\"number\">0</span>) ? geneY(y) : temp</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"built_in\">document</span>.onclick = init;</div><div class=\"line\"> <span class=\"built_in\">document</span>.ontouchstart = init;</div><div class=\"line\"> init();</div><div class=\"line\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>此外我还提供<a href=\"https://github.com/zproo/canvas-ribbon\">简单一条命令为你的网页添加canvas-ribbon背景彩带</a>(Github源码)的方法。你可以直接访问我的github仓库获得,只需要一行代码就可以为你的网站添加上面介绍的canvas-ribbon背景彩带了。</p>\n<h1 id=\"后记\"><a href=\"#后记\" class=\"headerlink\" title=\"后记\"></a>后记</h1><p>在为我自己的博客添加成功后,我还对Hexo 的Next主题添加了这一功能(只适用于Next的Pisces主题),并给Next作者发了PR。</p>\n<p>现在此提交已被作者Merge,所以如果你的博客使用了Hexo的Next主题,只需要在<code>主题配置文件</code>中找到<code>canvas-ribbon</code>属性,并设置为<code>true</code>,即可拥有背景彩带的效果。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/canvas4.png\" alt=\"ScreenClip3\"></p>\n<h1 id=\"参考资料\"><a href=\"#参考资料\" class=\"headerlink\" title=\"参考资料\"></a>参考资料</h1><ul>\n<li><a href=\"https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/beginPath\">CanvasRenderingContext2D-路径</a></li>\n<li><a href=\"http://evanyou.me/\">evanyou</a></li>\n</ul>\n"},{"title":"从0到有 如何搭建个人博客","comment":true,"date":"2017-04-04T12:57:25.000Z","cover":"http://ortur5wom.bkt.clouddn.com/cover-blog.jpg","_content":"\n初衷: 搭建一片属于自己的天地,然后开始默默耕耘。\n\n![hexo jekyll](http://ortur5wom.bkt.clouddn.com/vs.png)\n\n个人博客是一个能够让人写写画画的地方,记录生活中偶然遇见的一件趣事、有感而发时的胡言乱语、忧郁烦躁时的倾诉抱怨又或是分享自己的对于世界的看法。而写博客的过程是一个客观的、全面的、独立思考的过程,我们在写博客的过程中思考遇到的各种事、各种人,然后让自身得到成长。\n\n对于技术人员程序员来说,拥有自己的技术博客又是尤其重要。写一篇技术博客就是详细的记录“发现-思考-解决”一个自己碰到的技术难点的过程。写技术博客拥有很多的好处:\n\n- 让自己可以对某一技术点得到全面、深入的掌握\n- 记录自己的成长过程,审视来路获得成长\n- 通过记录分享让后来者少踩一些没有必要的坑\n\n综上,其实很早之前就想搭建自己的个人博客 ,但是对于一个拖延症病入膏肓的人来说,终于还是等到现在才着手来做。\n\n其实有很多第三方的博客系统可以直接使用,像博客园、简书等。其中简书支持md语法,界面也算简洁漂亮,注册账号后即可开始使用,确实有着不错的体验。但是,个人博客要寄存在第三方站点,一是一定会有很多的限制,二是多少让人感觉有些不爽。而对于程序员来说,就更加倾向于自己动手搭建博客了。所以第三方博客系统被pass掉,那么如何搭建真正的个人博客呢。\n\n# 博客系统选择\n\n想要自己搭建博客系统,主流的方法有两种。\n\n1. 自己购买域名、购买虚拟主机作为网站服务器,使用wordpress快速建站系统来搭建个人博客网站。\n2. 使用Github Pages作为免费服务器,Jekyll或者Hexo作为静态网页生成器搭建博客网站。\n\n第一种方法中的域名和虚拟主机都是要收费的,并且私人域名还要通过审核。而第二种方法只要求有github账号就可以了。不仅完全免费,且采用方法二搭建静态博客网站,拥有诸多优势:\n\n- 不用配置服务器\n- 不用数据库\n- 支持markdown方式书写\n- 此外,还可以享受github的版本控制功能\n\n所以我选择了Github+静态网站生成器的方式搭建个人博客。\n\n# 什么是Github Pages\n\n如果你使用过git,那就一定听说过Github,被称为全球最大的同性交友网站,很多著名的开源软件项目都托管在上面。\n\n而Github Pages是github推出的一项功能。Github Pages被设计为专门用来托管由用户编写的静态网站。简单的说,你在本地使用html+css+js写了一个可以用本地浏览器打开的网页。然后你把网页的源码上传到你的Github代码仓库,gihub就会自动生成并托管整个网站,别人就可以访问你的网页了。\n\n此时的Github就充当了免费服务器的功能。\n\n# 什么是静态网站生成器(Jekyll vs Hexo)\n\nhexo和jekyll一样都是静态网站生成工具。\n\n顾名思义,他们的工作就是生成一个静态网站的源码。比如说把你用md语法写的md格式的文章,他们会自动的把它转化为可以在浏览器展示的html文件。\n\nhexo是使用node js开发的,jekyll则是用ruby开发。由于两者的功能是一样的,而我又对js比较熟悉,自然选择了Hexo。其实使用这两个工具你并不需要懂ruby或js,他们的官网都有完善的使用说明,并不需要实际编程。并且两者都有非常多开箱即用的主题,只需要简单的几条命令便可以搭建出一个漂亮的博客。但是如果你有自定义主题的需求,那就最好在你熟悉的语言环境下了。鉴于Hexo越来越火,所以我还是推荐使用Hexo。\n\n现在搭建博客的大体步骤就就很清晰了:\n\n你先在本地通过Hexo生成静态网页源码,然后上传到github,由github生成并托管整个网站。\n\n# 实例操作\n\n至于使用Github+Hexo搭建博客的具体步骤,本来我是想写一篇手把手教学的。但是网上这些文章实在是太多了。一来进行重复工作毫无意义,二来我对于是不是能比他们写的更清晰详细也没有把握。\n\n所以在下面放上两篇使用Github+Hexo搭建博客的详细教程供大家学习!\n\n- [史上最详细的Hexo博客搭建图文教程](https://xuanwo.org/2015/03/26/hexo-intor/)\n\n\n\n","source":"_posts/从0到有-如何搭建个人博客.md","raw":"---\ntitle: 从0到有 如何搭建个人博客\ncomment: true\ndate: 2017-04-04 20:57:25\ntags: [Hexo, GitHub, Git]\ncover: http://ortur5wom.bkt.clouddn.com/cover-blog.jpg\n---\n\n初衷: 搭建一片属于自己的天地,然后开始默默耕耘。\n\n![hexo jekyll](http://ortur5wom.bkt.clouddn.com/vs.png)\n\n个人博客是一个能够让人写写画画的地方,记录生活中偶然遇见的一件趣事、有感而发时的胡言乱语、忧郁烦躁时的倾诉抱怨又或是分享自己的对于世界的看法。而写博客的过程是一个客观的、全面的、独立思考的过程,我们在写博客的过程中思考遇到的各种事、各种人,然后让自身得到成长。\n\n对于技术人员程序员来说,拥有自己的技术博客又是尤其重要。写一篇技术博客就是详细的记录“发现-思考-解决”一个自己碰到的技术难点的过程。写技术博客拥有很多的好处:\n\n- 让自己可以对某一技术点得到全面、深入的掌握\n- 记录自己的成长过程,审视来路获得成长\n- 通过记录分享让后来者少踩一些没有必要的坑\n\n综上,其实很早之前就想搭建自己的个人博客 ,但是对于一个拖延症病入膏肓的人来说,终于还是等到现在才着手来做。\n\n其实有很多第三方的博客系统可以直接使用,像博客园、简书等。其中简书支持md语法,界面也算简洁漂亮,注册账号后即可开始使用,确实有着不错的体验。但是,个人博客要寄存在第三方站点,一是一定会有很多的限制,二是多少让人感觉有些不爽。而对于程序员来说,就更加倾向于自己动手搭建博客了。所以第三方博客系统被pass掉,那么如何搭建真正的个人博客呢。\n\n# 博客系统选择\n\n想要自己搭建博客系统,主流的方法有两种。\n\n1. 自己购买域名、购买虚拟主机作为网站服务器,使用wordpress快速建站系统来搭建个人博客网站。\n2. 使用Github Pages作为免费服务器,Jekyll或者Hexo作为静态网页生成器搭建博客网站。\n\n第一种方法中的域名和虚拟主机都是要收费的,并且私人域名还要通过审核。而第二种方法只要求有github账号就可以了。不仅完全免费,且采用方法二搭建静态博客网站,拥有诸多优势:\n\n- 不用配置服务器\n- 不用数据库\n- 支持markdown方式书写\n- 此外,还可以享受github的版本控制功能\n\n所以我选择了Github+静态网站生成器的方式搭建个人博客。\n\n# 什么是Github Pages\n\n如果你使用过git,那就一定听说过Github,被称为全球最大的同性交友网站,很多著名的开源软件项目都托管在上面。\n\n而Github Pages是github推出的一项功能。Github Pages被设计为专门用来托管由用户编写的静态网站。简单的说,你在本地使用html+css+js写了一个可以用本地浏览器打开的网页。然后你把网页的源码上传到你的Github代码仓库,gihub就会自动生成并托管整个网站,别人就可以访问你的网页了。\n\n此时的Github就充当了免费服务器的功能。\n\n# 什么是静态网站生成器(Jekyll vs Hexo)\n\nhexo和jekyll一样都是静态网站生成工具。\n\n顾名思义,他们的工作就是生成一个静态网站的源码。比如说把你用md语法写的md格式的文章,他们会自动的把它转化为可以在浏览器展示的html文件。\n\nhexo是使用node js开发的,jekyll则是用ruby开发。由于两者的功能是一样的,而我又对js比较熟悉,自然选择了Hexo。其实使用这两个工具你并不需要懂ruby或js,他们的官网都有完善的使用说明,并不需要实际编程。并且两者都有非常多开箱即用的主题,只需要简单的几条命令便可以搭建出一个漂亮的博客。但是如果你有自定义主题的需求,那就最好在你熟悉的语言环境下了。鉴于Hexo越来越火,所以我还是推荐使用Hexo。\n\n现在搭建博客的大体步骤就就很清晰了:\n\n你先在本地通过Hexo生成静态网页源码,然后上传到github,由github生成并托管整个网站。\n\n# 实例操作\n\n至于使用Github+Hexo搭建博客的具体步骤,本来我是想写一篇手把手教学的。但是网上这些文章实在是太多了。一来进行重复工作毫无意义,二来我对于是不是能比他们写的更清晰详细也没有把握。\n\n所以在下面放上两篇使用Github+Hexo搭建博客的详细教程供大家学习!\n\n- [史上最详细的Hexo博客搭建图文教程](https://xuanwo.org/2015/03/26/hexo-intor/)\n\n\n\n","slug":"从0到有-如何搭建个人博客","published":1,"updated":"2017-10-14T12:25:12.752Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k72000kwsv7hnpfln3v","content":"<p>初衷: 搭建一片属于自己的天地,然后开始默默耕耘。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/vs.png\" alt=\"hexo jekyll\"></p>\n<p>个人博客是一个能够让人写写画画的地方,记录生活中偶然遇见的一件趣事、有感而发时的胡言乱语、忧郁烦躁时的倾诉抱怨又或是分享自己的对于世界的看法。而写博客的过程是一个客观的、全面的、独立思考的过程,我们在写博客的过程中思考遇到的各种事、各种人,然后让自身得到成长。</p>\n<p>对于技术人员程序员来说,拥有自己的技术博客又是尤其重要。写一篇技术博客就是详细的记录“发现-思考-解决”一个自己碰到的技术难点的过程。写技术博客拥有很多的好处:</p>\n<ul>\n<li>让自己可以对某一技术点得到全面、深入的掌握</li>\n<li>记录自己的成长过程,审视来路获得成长</li>\n<li>通过记录分享让后来者少踩一些没有必要的坑</li>\n</ul>\n<p>综上,其实很早之前就想搭建自己的个人博客 ,但是对于一个拖延症病入膏肓的人来说,终于还是等到现在才着手来做。</p>\n<p>其实有很多第三方的博客系统可以直接使用,像博客园、简书等。其中简书支持md语法,界面也算简洁漂亮,注册账号后即可开始使用,确实有着不错的体验。但是,个人博客要寄存在第三方站点,一是一定会有很多的限制,二是多少让人感觉有些不爽。而对于程序员来说,就更加倾向于自己动手搭建博客了。所以第三方博客系统被pass掉,那么如何搭建真正的个人博客呢。</p>\n<h1 id=\"博客系统选择\"><a href=\"#博客系统选择\" class=\"headerlink\" title=\"博客系统选择\"></a>博客系统选择</h1><p>想要自己搭建博客系统,主流的方法有两种。</p>\n<ol>\n<li>自己购买域名、购买虚拟主机作为网站服务器,使用wordpress快速建站系统来搭建个人博客网站。</li>\n<li>使用Github Pages作为免费服务器,Jekyll或者Hexo作为静态网页生成器搭建博客网站。</li>\n</ol>\n<p>第一种方法中的域名和虚拟主机都是要收费的,并且私人域名还要通过审核。而第二种方法只要求有github账号就可以了。不仅完全免费,且采用方法二搭建静态博客网站,拥有诸多优势:</p>\n<ul>\n<li>不用配置服务器</li>\n<li>不用数据库</li>\n<li>支持markdown方式书写</li>\n<li>此外,还可以享受github的版本控制功能</li>\n</ul>\n<p>所以我选择了Github+静态网站生成器的方式搭建个人博客。</p>\n<h1 id=\"什么是Github-Pages\"><a href=\"#什么是Github-Pages\" class=\"headerlink\" title=\"什么是Github Pages\"></a>什么是Github Pages</h1><p>如果你使用过git,那就一定听说过Github,被称为全球最大的同性交友网站,很多著名的开源软件项目都托管在上面。</p>\n<p>而Github Pages是github推出的一项功能。Github Pages被设计为专门用来托管由用户编写的静态网站。简单的说,你在本地使用html+css+js写了一个可以用本地浏览器打开的网页。然后你把网页的源码上传到你的Github代码仓库,gihub就会自动生成并托管整个网站,别人就可以访问你的网页了。</p>\n<p>此时的Github就充当了免费服务器的功能。</p>\n<h1 id=\"什么是静态网站生成器(Jekyll-vs-Hexo)\"><a href=\"#什么是静态网站生成器(Jekyll-vs-Hexo)\" class=\"headerlink\" title=\"什么是静态网站生成器(Jekyll vs Hexo)\"></a>什么是静态网站生成器(Jekyll vs Hexo)</h1><p>hexo和jekyll一样都是静态网站生成工具。</p>\n<p>顾名思义,他们的工作就是生成一个静态网站的源码。比如说把你用md语法写的md格式的文章,他们会自动的把它转化为可以在浏览器展示的html文件。</p>\n<p>hexo是使用node js开发的,jekyll则是用ruby开发。由于两者的功能是一样的,而我又对js比较熟悉,自然选择了Hexo。其实使用这两个工具你并不需要懂ruby或js,他们的官网都有完善的使用说明,并不需要实际编程。并且两者都有非常多开箱即用的主题,只需要简单的几条命令便可以搭建出一个漂亮的博客。但是如果你有自定义主题的需求,那就最好在你熟悉的语言环境下了。鉴于Hexo越来越火,所以我还是推荐使用Hexo。</p>\n<p>现在搭建博客的大体步骤就就很清晰了:</p>\n<p>你先在本地通过Hexo生成静态网页源码,然后上传到github,由github生成并托管整个网站。</p>\n<h1 id=\"实例操作\"><a href=\"#实例操作\" class=\"headerlink\" title=\"实例操作\"></a>实例操作</h1><p>至于使用Github+Hexo搭建博客的具体步骤,本来我是想写一篇手把手教学的。但是网上这些文章实在是太多了。一来进行重复工作毫无意义,二来我对于是不是能比他们写的更清晰详细也没有把握。</p>\n<p>所以在下面放上两篇使用Github+Hexo搭建博客的详细教程供大家学习!</p>\n<ul>\n<li><a href=\"https://xuanwo.org/2015/03/26/hexo-intor/\" target=\"_blank\" rel=\"external\">史上最详细的Hexo博客搭建图文教程</a></li>\n</ul>\n","excerpt":"","more":"<p>初衷: 搭建一片属于自己的天地,然后开始默默耕耘。</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/vs.png\" alt=\"hexo jekyll\"></p>\n<p>个人博客是一个能够让人写写画画的地方,记录生活中偶然遇见的一件趣事、有感而发时的胡言乱语、忧郁烦躁时的倾诉抱怨又或是分享自己的对于世界的看法。而写博客的过程是一个客观的、全面的、独立思考的过程,我们在写博客的过程中思考遇到的各种事、各种人,然后让自身得到成长。</p>\n<p>对于技术人员程序员来说,拥有自己的技术博客又是尤其重要。写一篇技术博客就是详细的记录“发现-思考-解决”一个自己碰到的技术难点的过程。写技术博客拥有很多的好处:</p>\n<ul>\n<li>让自己可以对某一技术点得到全面、深入的掌握</li>\n<li>记录自己的成长过程,审视来路获得成长</li>\n<li>通过记录分享让后来者少踩一些没有必要的坑</li>\n</ul>\n<p>综上,其实很早之前就想搭建自己的个人博客 ,但是对于一个拖延症病入膏肓的人来说,终于还是等到现在才着手来做。</p>\n<p>其实有很多第三方的博客系统可以直接使用,像博客园、简书等。其中简书支持md语法,界面也算简洁漂亮,注册账号后即可开始使用,确实有着不错的体验。但是,个人博客要寄存在第三方站点,一是一定会有很多的限制,二是多少让人感觉有些不爽。而对于程序员来说,就更加倾向于自己动手搭建博客了。所以第三方博客系统被pass掉,那么如何搭建真正的个人博客呢。</p>\n<h1 id=\"博客系统选择\"><a href=\"#博客系统选择\" class=\"headerlink\" title=\"博客系统选择\"></a>博客系统选择</h1><p>想要自己搭建博客系统,主流的方法有两种。</p>\n<ol>\n<li>自己购买域名、购买虚拟主机作为网站服务器,使用wordpress快速建站系统来搭建个人博客网站。</li>\n<li>使用Github Pages作为免费服务器,Jekyll或者Hexo作为静态网页生成器搭建博客网站。</li>\n</ol>\n<p>第一种方法中的域名和虚拟主机都是要收费的,并且私人域名还要通过审核。而第二种方法只要求有github账号就可以了。不仅完全免费,且采用方法二搭建静态博客网站,拥有诸多优势:</p>\n<ul>\n<li>不用配置服务器</li>\n<li>不用数据库</li>\n<li>支持markdown方式书写</li>\n<li>此外,还可以享受github的版本控制功能</li>\n</ul>\n<p>所以我选择了Github+静态网站生成器的方式搭建个人博客。</p>\n<h1 id=\"什么是Github-Pages\"><a href=\"#什么是Github-Pages\" class=\"headerlink\" title=\"什么是Github Pages\"></a>什么是Github Pages</h1><p>如果你使用过git,那就一定听说过Github,被称为全球最大的同性交友网站,很多著名的开源软件项目都托管在上面。</p>\n<p>而Github Pages是github推出的一项功能。Github Pages被设计为专门用来托管由用户编写的静态网站。简单的说,你在本地使用html+css+js写了一个可以用本地浏览器打开的网页。然后你把网页的源码上传到你的Github代码仓库,gihub就会自动生成并托管整个网站,别人就可以访问你的网页了。</p>\n<p>此时的Github就充当了免费服务器的功能。</p>\n<h1 id=\"什么是静态网站生成器(Jekyll-vs-Hexo)\"><a href=\"#什么是静态网站生成器(Jekyll-vs-Hexo)\" class=\"headerlink\" title=\"什么是静态网站生成器(Jekyll vs Hexo)\"></a>什么是静态网站生成器(Jekyll vs Hexo)</h1><p>hexo和jekyll一样都是静态网站生成工具。</p>\n<p>顾名思义,他们的工作就是生成一个静态网站的源码。比如说把你用md语法写的md格式的文章,他们会自动的把它转化为可以在浏览器展示的html文件。</p>\n<p>hexo是使用node js开发的,jekyll则是用ruby开发。由于两者的功能是一样的,而我又对js比较熟悉,自然选择了Hexo。其实使用这两个工具你并不需要懂ruby或js,他们的官网都有完善的使用说明,并不需要实际编程。并且两者都有非常多开箱即用的主题,只需要简单的几条命令便可以搭建出一个漂亮的博客。但是如果你有自定义主题的需求,那就最好在你熟悉的语言环境下了。鉴于Hexo越来越火,所以我还是推荐使用Hexo。</p>\n<p>现在搭建博客的大体步骤就就很清晰了:</p>\n<p>你先在本地通过Hexo生成静态网页源码,然后上传到github,由github生成并托管整个网站。</p>\n<h1 id=\"实例操作\"><a href=\"#实例操作\" class=\"headerlink\" title=\"实例操作\"></a>实例操作</h1><p>至于使用Github+Hexo搭建博客的具体步骤,本来我是想写一篇手把手教学的。但是网上这些文章实在是太多了。一来进行重复工作毫无意义,二来我对于是不是能比他们写的更清晰详细也没有把握。</p>\n<p>所以在下面放上两篇使用Github+Hexo搭建博客的详细教程供大家学习!</p>\n<ul>\n<li><a href=\"https://xuanwo.org/2015/03/26/hexo-intor/\">史上最详细的Hexo博客搭建图文教程</a></li>\n</ul>\n"},{"title":"动手实现redis数据锁","comment":true,"date":"2017-10-18T02:18:20.000Z","_content":"\n# 1.问题:\n\n1. redis安装使用工作原理,\n2. 操纵方式(使用jedis的 特定语言java下的数据操作方式)\n3. jedis数据锁实现方式\n4. 为什么要使用redis([为什么要使用redis?](http://blog.csdn.net/yujin2010good/article/details/54729939))\n\n# 2.redis安装使用:\n\n可以从菜鸟[redis教程](http://www.runoob.com/redis/redis-install.html)(主要看下安装配置)快速顺下来 ,然后看最后的java使用。\n# 3.jedis使用\n\n使用Jedis需要的第三方jar包:\n\n> jedis-2.9.0.jar\n>\n> commons-pool2-2.4.2.jar (Jedis包依赖的包 - 抽象的池的管理工具)\n\n简单jedis包类图:(Redis客户端:Jedis)\nJedis包类图:\n![Jedis类图](http://ortur5wom.bkt.clouddn.com/redis.png)\n\n> Jedis类是整个客户端的入口,通过Jedis可以建立与Redis Server的连接并发送命令。Jedis继承自BinaryJedis,同时Jedis和BinaryJedis都实现了很多接口,通过一张类图来描述:每一个接口都代表了一类Redis命令,例如JedisCommands中包含了SET GET等命令,MultiKeyCommands中包含了针对多个Key的MSET MGET等命令。一部分命令有两个版本的接口,如JedisCommands和BinaryJedisCommands。JedisCommands是字符串参数版本命令,会在Jedis内部将参数转换成UTF-8编码的字节数组。BinaryJedisCommands提供的是字节参数版本,允许用户自己决定编码等细节。ClusterCommands和SentinelCommands与集群、高可用等相关的命令只有一个版本。\n>\n\n# 4.动手实现redis数据锁\n\n**重要:** ***(以下所有讨论涉及的代码下载链接,包含封装良好的加锁代码)***\n\n## 4.1redis并发问题 \n\n**问题:**\n\n有个键,假设名称为`myNum`,里面保存的是阿拉伯数字,假设现在值为1,存在多个连接对`myNum`进行操作的情况,这个时候就会有并发的问题。假设有两个连接`linkA`和`linkB`,这两个连接都执行下面的操作,取出`myNum`的值`+1`,然后再存回去,看看下面的交互:\n\n```\nlinkA get myNum => 1\nlinkB get myNum => 1\nlinkA set muNum => 2\nlinkB set myNum => 2\n```\n\n\n\n执行完操作之后,结果可能是2,这和我们预期的3不一致。\n\n## 4.2尝试使用redis事务解决问题:\n\n\n\nredis中也是有事务的,不过这个事务没有mysql中的完善,只保证了一致性和隔离性,不满足原子性和持久性。\n\nredis事务使用multi、exec命令 - [菜鸟教程:redis事务的基本操作](http://www.runoob.com/redis/redis-transactions.html)\n\n> 原子性,redis会将事务中的所有命令执行一遍,哪怕是中间有执行失败也不会回滚。kill信号、宿主机宕机等导致事务执行失败,redis也不会进行重试或者回滚。\n>\n> 持久性,redis事务的持久性依赖于redis所使用的持久化模式,遗憾的是各种持久化模式也都不是持久化的。\n>\n> 隔离性,redis是单进程,开启事务之后,会执行完当前连接的所有命令直到遇到exec命令,才处理其他连接的命令\n>\n\n经过代码实验,redis事务解决不了上面的问题。\n\n当然了redis还有一个watch命令,这个命令可以解决这个问题,看下面的例子,对一个键执行watch,然后执行事务,由于watch的存在,他会监测键a,当a被修该之后,后面的事务就会**执行失败**,这就确保了多个连接同时来了,都监测着a,\n\n**注意:**\n\n 使用watch也只是保证了几个操作不能同时进行,但最终结果是几个并行操作中只有第一个操作执行成功,其他的都执行失败并不再执行。\n\n即解决了能同时修改的问题,但是却只执行了单个任务,冲突的任务都没有执行。所以说使用redis内置事务解决不了问题,接下来尝试了解redis锁相关内容解决问题。\n\n## 4.3为redis中的数据加锁\n\n上面给出了源码链接,源码中已经将加锁操作进行了封装,可用在生产环境中没有问题。\n\n**核心函数:**\n\nredis中的setnx函数:\n\n> 官方:Set `key` to hold string `value` if `key` does not exist.\n\n使用`SETNX mykey \"Hello\"` ,有两种情况:\n\n1. mykey不存在,新建`mykey`并设为`Hello`,返回值`1`\n2. mykey已存在,不做操作,返回值`0`\n\n``` java\n// 为“aa”加字段锁\nRedisLock lock = new RedisLock(\"aa\",redisPool);\nlock.lock(10000);\n```\n\n``` java\n /**\n * @param timeout 超时时间\n * @param expire 锁的超时时间(秒),过期删除\n * @return 成功或失败标志\n */\n public boolean lock(long timeout, int expire) {\n long nano = System.nanoTime();\n timeout *= MILLI_NANO_CONVERSION;\n try {\n while ((System.nanoTime() - nano) < timeout) {\n // 多个并行用户同时请求为字段\"aa\"加锁,只有一个能够加锁成功\n // 只允许加锁成功的用户对字段\"aa\"进行操作,即实现了字段锁的效果 \n if (this.jedis.setnx(this.key, LOCKED) == 1) {\n this.jedis.expire(this.key, expire);\n this.locked = true;\n return this.locked;\n }\n // 短暂休眠,避免出现活锁\n Thread.sleep(3, RANDOM.nextInt(500));\n }\n } catch (Exception e) {\n throw new RuntimeException(\"Locking error\", e);\n }\n return false;\n }\n```\n\n结束。\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","source":"_posts/动手实现redis数据锁.md","raw":"---\ntitle: 动手实现redis数据锁\ncomment: true\ndate: 2017-10-18 10:18:20\ntags: [redis, Jedis, Java, 事务, 字段锁]\n---\n\n# 1.问题:\n\n1. redis安装使用工作原理,\n2. 操纵方式(使用jedis的 特定语言java下的数据操作方式)\n3. jedis数据锁实现方式\n4. 为什么要使用redis([为什么要使用redis?](http://blog.csdn.net/yujin2010good/article/details/54729939))\n\n# 2.redis安装使用:\n\n可以从菜鸟[redis教程](http://www.runoob.com/redis/redis-install.html)(主要看下安装配置)快速顺下来 ,然后看最后的java使用。\n# 3.jedis使用\n\n使用Jedis需要的第三方jar包:\n\n> jedis-2.9.0.jar\n>\n> commons-pool2-2.4.2.jar (Jedis包依赖的包 - 抽象的池的管理工具)\n\n简单jedis包类图:(Redis客户端:Jedis)\nJedis包类图:\n![Jedis类图](http://ortur5wom.bkt.clouddn.com/redis.png)\n\n> Jedis类是整个客户端的入口,通过Jedis可以建立与Redis Server的连接并发送命令。Jedis继承自BinaryJedis,同时Jedis和BinaryJedis都实现了很多接口,通过一张类图来描述:每一个接口都代表了一类Redis命令,例如JedisCommands中包含了SET GET等命令,MultiKeyCommands中包含了针对多个Key的MSET MGET等命令。一部分命令有两个版本的接口,如JedisCommands和BinaryJedisCommands。JedisCommands是字符串参数版本命令,会在Jedis内部将参数转换成UTF-8编码的字节数组。BinaryJedisCommands提供的是字节参数版本,允许用户自己决定编码等细节。ClusterCommands和SentinelCommands与集群、高可用等相关的命令只有一个版本。\n>\n\n# 4.动手实现redis数据锁\n\n**重要:** ***(以下所有讨论涉及的代码下载链接,包含封装良好的加锁代码)***\n\n## 4.1redis并发问题 \n\n**问题:**\n\n有个键,假设名称为`myNum`,里面保存的是阿拉伯数字,假设现在值为1,存在多个连接对`myNum`进行操作的情况,这个时候就会有并发的问题。假设有两个连接`linkA`和`linkB`,这两个连接都执行下面的操作,取出`myNum`的值`+1`,然后再存回去,看看下面的交互:\n\n```\nlinkA get myNum => 1\nlinkB get myNum => 1\nlinkA set muNum => 2\nlinkB set myNum => 2\n```\n\n\n\n执行完操作之后,结果可能是2,这和我们预期的3不一致。\n\n## 4.2尝试使用redis事务解决问题:\n\n\n\nredis中也是有事务的,不过这个事务没有mysql中的完善,只保证了一致性和隔离性,不满足原子性和持久性。\n\nredis事务使用multi、exec命令 - [菜鸟教程:redis事务的基本操作](http://www.runoob.com/redis/redis-transactions.html)\n\n> 原子性,redis会将事务中的所有命令执行一遍,哪怕是中间有执行失败也不会回滚。kill信号、宿主机宕机等导致事务执行失败,redis也不会进行重试或者回滚。\n>\n> 持久性,redis事务的持久性依赖于redis所使用的持久化模式,遗憾的是各种持久化模式也都不是持久化的。\n>\n> 隔离性,redis是单进程,开启事务之后,会执行完当前连接的所有命令直到遇到exec命令,才处理其他连接的命令\n>\n\n经过代码实验,redis事务解决不了上面的问题。\n\n当然了redis还有一个watch命令,这个命令可以解决这个问题,看下面的例子,对一个键执行watch,然后执行事务,由于watch的存在,他会监测键a,当a被修该之后,后面的事务就会**执行失败**,这就确保了多个连接同时来了,都监测着a,\n\n**注意:**\n\n 使用watch也只是保证了几个操作不能同时进行,但最终结果是几个并行操作中只有第一个操作执行成功,其他的都执行失败并不再执行。\n\n即解决了能同时修改的问题,但是却只执行了单个任务,冲突的任务都没有执行。所以说使用redis内置事务解决不了问题,接下来尝试了解redis锁相关内容解决问题。\n\n## 4.3为redis中的数据加锁\n\n上面给出了源码链接,源码中已经将加锁操作进行了封装,可用在生产环境中没有问题。\n\n**核心函数:**\n\nredis中的setnx函数:\n\n> 官方:Set `key` to hold string `value` if `key` does not exist.\n\n使用`SETNX mykey \"Hello\"` ,有两种情况:\n\n1. mykey不存在,新建`mykey`并设为`Hello`,返回值`1`\n2. mykey已存在,不做操作,返回值`0`\n\n``` java\n// 为“aa”加字段锁\nRedisLock lock = new RedisLock(\"aa\",redisPool);\nlock.lock(10000);\n```\n\n``` java\n /**\n * @param timeout 超时时间\n * @param expire 锁的超时时间(秒),过期删除\n * @return 成功或失败标志\n */\n public boolean lock(long timeout, int expire) {\n long nano = System.nanoTime();\n timeout *= MILLI_NANO_CONVERSION;\n try {\n while ((System.nanoTime() - nano) < timeout) {\n // 多个并行用户同时请求为字段\"aa\"加锁,只有一个能够加锁成功\n // 只允许加锁成功的用户对字段\"aa\"进行操作,即实现了字段锁的效果 \n if (this.jedis.setnx(this.key, LOCKED) == 1) {\n this.jedis.expire(this.key, expire);\n this.locked = true;\n return this.locked;\n }\n // 短暂休眠,避免出现活锁\n Thread.sleep(3, RANDOM.nextInt(500));\n }\n } catch (Exception e) {\n throw new RuntimeException(\"Locking error\", e);\n }\n return false;\n }\n```\n\n结束。\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","slug":"动手实现redis数据锁","published":1,"updated":"2017-10-30T07:32:18.492Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k72000nwsv71ivjbcfn","content":"<h1 id=\"1-问题:\"><a href=\"#1-问题:\" class=\"headerlink\" title=\"1.问题:\"></a>1.问题:</h1><ol>\n<li>redis安装使用工作原理,</li>\n<li>操纵方式(使用jedis的 特定语言java下的数据操作方式)</li>\n<li>jedis数据锁实现方式</li>\n<li>为什么要使用redis(<a href=\"http://blog.csdn.net/yujin2010good/article/details/54729939\" target=\"_blank\" rel=\"external\">为什么要使用redis?</a>)</li>\n</ol>\n<h1 id=\"2-redis安装使用:\"><a href=\"#2-redis安装使用:\" class=\"headerlink\" title=\"2.redis安装使用:\"></a>2.redis安装使用:</h1><p>可以从菜鸟<a href=\"http://www.runoob.com/redis/redis-install.html\" target=\"_blank\" rel=\"external\">redis教程</a>(主要看下安装配置)快速顺下来 ,然后看最后的java使用。</p>\n<h1 id=\"3-jedis使用\"><a href=\"#3-jedis使用\" class=\"headerlink\" title=\"3.jedis使用\"></a>3.jedis使用</h1><p>使用Jedis需要的第三方jar包:</p>\n<blockquote>\n<p>jedis-2.9.0.jar</p>\n<p>commons-pool2-2.4.2.jar (Jedis包依赖的包 - 抽象的池的管理工具)</p>\n</blockquote>\n<p>简单jedis包类图:(Redis客户端:Jedis)<br>Jedis包类图:<br><img src=\"http://ortur5wom.bkt.clouddn.com/redis.png\" alt=\"Jedis类图\"></p>\n<blockquote>\n<p>Jedis类是整个客户端的入口,通过Jedis可以建立与Redis Server的连接并发送命令。Jedis继承自BinaryJedis,同时Jedis和BinaryJedis都实现了很多接口,通过一张类图来描述:每一个接口都代表了一类Redis命令,例如JedisCommands中包含了SET GET等命令,MultiKeyCommands中包含了针对多个Key的MSET MGET等命令。一部分命令有两个版本的接口,如JedisCommands和BinaryJedisCommands。JedisCommands是字符串参数版本命令,会在Jedis内部将参数转换成UTF-8编码的字节数组。BinaryJedisCommands提供的是字节参数版本,允许用户自己决定编码等细节。ClusterCommands和SentinelCommands与集群、高可用等相关的命令只有一个版本。</p>\n</blockquote>\n<h1 id=\"4-动手实现redis数据锁\"><a href=\"#4-动手实现redis数据锁\" class=\"headerlink\" title=\"4.动手实现redis数据锁\"></a>4.动手实现redis数据锁</h1><p><strong>重要:</strong> <strong><em>(以下所有讨论涉及的代码下载链接,包含封装良好的加锁代码)</em></strong></p>\n<h2 id=\"4-1redis并发问题\"><a href=\"#4-1redis并发问题\" class=\"headerlink\" title=\"4.1redis并发问题\"></a>4.1redis并发问题</h2><p><strong>问题:</strong></p>\n<p>有个键,假设名称为<code>myNum</code>,里面保存的是阿拉伯数字,假设现在值为1,存在多个连接对<code>myNum</code>进行操作的情况,这个时候就会有并发的问题。假设有两个连接<code>linkA</code>和<code>linkB</code>,这两个连接都执行下面的操作,取出<code>myNum</code>的值<code>+1</code>,然后再存回去,看看下面的交互:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">linkA get myNum => 1</div><div class=\"line\">linkB get myNum => 1</div><div class=\"line\">linkA set muNum => 2</div><div class=\"line\">linkB set myNum => 2</div></pre></td></tr></table></figure>\n<p>执行完操作之后,结果可能是2,这和我们预期的3不一致。</p>\n<h2 id=\"4-2尝试使用redis事务解决问题:\"><a href=\"#4-2尝试使用redis事务解决问题:\" class=\"headerlink\" title=\"4.2尝试使用redis事务解决问题:\"></a>4.2尝试使用redis事务解决问题:</h2><p>redis中也是有事务的,不过这个事务没有mysql中的完善,只保证了一致性和隔离性,不满足原子性和持久性。</p>\n<p>redis事务使用multi、exec命令 - <a href=\"http://www.runoob.com/redis/redis-transactions.html\" target=\"_blank\" rel=\"external\">菜鸟教程:redis事务的基本操作</a></p>\n<blockquote>\n<p>原子性,redis会将事务中的所有命令执行一遍,哪怕是中间有执行失败也不会回滚。kill信号、宿主机宕机等导致事务执行失败,redis也不会进行重试或者回滚。</p>\n<p>持久性,redis事务的持久性依赖于redis所使用的持久化模式,遗憾的是各种持久化模式也都不是持久化的。</p>\n<p>隔离性,redis是单进程,开启事务之后,会执行完当前连接的所有命令直到遇到exec命令,才处理其他连接的命令</p>\n</blockquote>\n<p>经过代码实验,redis事务解决不了上面的问题。</p>\n<p>当然了redis还有一个watch命令,这个命令可以解决这个问题,看下面的例子,对一个键执行watch,然后执行事务,由于watch的存在,他会监测键a,当a被修该之后,后面的事务就会<strong>执行失败</strong>,这就确保了多个连接同时来了,都监测着a,</p>\n<p><strong>注意:</strong></p>\n<p> 使用watch也只是保证了几个操作不能同时进行,但最终结果是几个并行操作中只有第一个操作执行成功,其他的都执行失败并不再执行。</p>\n<p>即解决了能同时修改的问题,但是却只执行了单个任务,冲突的任务都没有执行。所以说使用redis内置事务解决不了问题,接下来尝试了解redis锁相关内容解决问题。</p>\n<h2 id=\"4-3为redis中的数据加锁\"><a href=\"#4-3为redis中的数据加锁\" class=\"headerlink\" title=\"4.3为redis中的数据加锁\"></a>4.3为redis中的数据加锁</h2><p>上面给出了源码链接,源码中已经将加锁操作进行了封装,可用在生产环境中没有问题。</p>\n<p><strong>核心函数:</strong></p>\n<p>redis中的setnx函数:</p>\n<blockquote>\n<p>官方:Set <code>key</code> to hold string <code>value</code> if <code>key</code> does not exist.</p>\n</blockquote>\n<p>使用<code>SETNX mykey "Hello"</code> ,有两种情况:</p>\n<ol>\n<li>mykey不存在,新建<code>mykey</code>并设为<code>Hello</code>,返回值<code>1</code></li>\n<li>mykey已存在,不做操作,返回值<code>0</code></li>\n</ol>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 为“aa”加字段锁</span></div><div class=\"line\">RedisLock lock = <span class=\"keyword\">new</span> RedisLock(<span class=\"string\">\"aa\"</span>,redisPool);</div><div class=\"line\">lock.lock(<span class=\"number\">10000</span>);</div></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * <span class=\"doctag\">@param</span> timeout 超时时间</div><div class=\"line\"> * <span class=\"doctag\">@param</span> expire 锁的超时时间(秒),过期删除</div><div class=\"line\"> * <span class=\"doctag\">@return</span> 成功或失败标志</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">lock</span><span class=\"params\">(<span class=\"keyword\">long</span> timeout, <span class=\"keyword\">int</span> expire)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">long</span> nano = System.nanoTime();</div><div class=\"line\"> timeout *= MILLI_NANO_CONVERSION;</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">while</span> ((System.nanoTime() - nano) < timeout) {</div><div class=\"line\"> <span class=\"comment\">// 多个并行用户同时请求为字段\"aa\"加锁,只有一个能够加锁成功</span></div><div class=\"line\"> <span class=\"comment\">// 只允许加锁成功的用户对字段\"aa\"进行操作,即实现了字段锁的效果 </span></div><div class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">this</span>.jedis.setnx(<span class=\"keyword\">this</span>.key, LOCKED) == <span class=\"number\">1</span>) {</div><div class=\"line\"> <span class=\"keyword\">this</span>.jedis.expire(<span class=\"keyword\">this</span>.key, expire);</div><div class=\"line\"> <span class=\"keyword\">this</span>.locked = <span class=\"keyword\">true</span>;</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">this</span>.locked;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"comment\">// 短暂休眠,避免出现活锁</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">3</span>, RANDOM.nextInt(<span class=\"number\">500</span>));</div><div class=\"line\"> }</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> RuntimeException(<span class=\"string\">\"Locking error\"</span>, e);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>结束。</p>\n","excerpt":"","more":"<h1 id=\"1-问题:\"><a href=\"#1-问题:\" class=\"headerlink\" title=\"1.问题:\"></a>1.问题:</h1><ol>\n<li>redis安装使用工作原理,</li>\n<li>操纵方式(使用jedis的 特定语言java下的数据操作方式)</li>\n<li>jedis数据锁实现方式</li>\n<li>为什么要使用redis(<a href=\"http://blog.csdn.net/yujin2010good/article/details/54729939\">为什么要使用redis?</a>)</li>\n</ol>\n<h1 id=\"2-redis安装使用:\"><a href=\"#2-redis安装使用:\" class=\"headerlink\" title=\"2.redis安装使用:\"></a>2.redis安装使用:</h1><p>可以从菜鸟<a href=\"http://www.runoob.com/redis/redis-install.html\">redis教程</a>(主要看下安装配置)快速顺下来 ,然后看最后的java使用。</p>\n<h1 id=\"3-jedis使用\"><a href=\"#3-jedis使用\" class=\"headerlink\" title=\"3.jedis使用\"></a>3.jedis使用</h1><p>使用Jedis需要的第三方jar包:</p>\n<blockquote>\n<p>jedis-2.9.0.jar</p>\n<p>commons-pool2-2.4.2.jar (Jedis包依赖的包 - 抽象的池的管理工具)</p>\n</blockquote>\n<p>简单jedis包类图:(Redis客户端:Jedis)<br>Jedis包类图:<br><img src=\"http://ortur5wom.bkt.clouddn.com/redis.png\" alt=\"Jedis类图\"></p>\n<blockquote>\n<p>Jedis类是整个客户端的入口,通过Jedis可以建立与Redis Server的连接并发送命令。Jedis继承自BinaryJedis,同时Jedis和BinaryJedis都实现了很多接口,通过一张类图来描述:每一个接口都代表了一类Redis命令,例如JedisCommands中包含了SET GET等命令,MultiKeyCommands中包含了针对多个Key的MSET MGET等命令。一部分命令有两个版本的接口,如JedisCommands和BinaryJedisCommands。JedisCommands是字符串参数版本命令,会在Jedis内部将参数转换成UTF-8编码的字节数组。BinaryJedisCommands提供的是字节参数版本,允许用户自己决定编码等细节。ClusterCommands和SentinelCommands与集群、高可用等相关的命令只有一个版本。</p>\n</blockquote>\n<h1 id=\"4-动手实现redis数据锁\"><a href=\"#4-动手实现redis数据锁\" class=\"headerlink\" title=\"4.动手实现redis数据锁\"></a>4.动手实现redis数据锁</h1><p><strong>重要:</strong> <strong><em>(以下所有讨论涉及的代码下载链接,包含封装良好的加锁代码)</em></strong></p>\n<h2 id=\"4-1redis并发问题\"><a href=\"#4-1redis并发问题\" class=\"headerlink\" title=\"4.1redis并发问题\"></a>4.1redis并发问题</h2><p><strong>问题:</strong></p>\n<p>有个键,假设名称为<code>myNum</code>,里面保存的是阿拉伯数字,假设现在值为1,存在多个连接对<code>myNum</code>进行操作的情况,这个时候就会有并发的问题。假设有两个连接<code>linkA</code>和<code>linkB</code>,这两个连接都执行下面的操作,取出<code>myNum</code>的值<code>+1</code>,然后再存回去,看看下面的交互:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">linkA get myNum => 1</div><div class=\"line\">linkB get myNum => 1</div><div class=\"line\">linkA set muNum => 2</div><div class=\"line\">linkB set myNum => 2</div></pre></td></tr></table></figure>\n<p>执行完操作之后,结果可能是2,这和我们预期的3不一致。</p>\n<h2 id=\"4-2尝试使用redis事务解决问题:\"><a href=\"#4-2尝试使用redis事务解决问题:\" class=\"headerlink\" title=\"4.2尝试使用redis事务解决问题:\"></a>4.2尝试使用redis事务解决问题:</h2><p>redis中也是有事务的,不过这个事务没有mysql中的完善,只保证了一致性和隔离性,不满足原子性和持久性。</p>\n<p>redis事务使用multi、exec命令 - <a href=\"http://www.runoob.com/redis/redis-transactions.html\">菜鸟教程:redis事务的基本操作</a></p>\n<blockquote>\n<p>原子性,redis会将事务中的所有命令执行一遍,哪怕是中间有执行失败也不会回滚。kill信号、宿主机宕机等导致事务执行失败,redis也不会进行重试或者回滚。</p>\n<p>持久性,redis事务的持久性依赖于redis所使用的持久化模式,遗憾的是各种持久化模式也都不是持久化的。</p>\n<p>隔离性,redis是单进程,开启事务之后,会执行完当前连接的所有命令直到遇到exec命令,才处理其他连接的命令</p>\n</blockquote>\n<p>经过代码实验,redis事务解决不了上面的问题。</p>\n<p>当然了redis还有一个watch命令,这个命令可以解决这个问题,看下面的例子,对一个键执行watch,然后执行事务,由于watch的存在,他会监测键a,当a被修该之后,后面的事务就会<strong>执行失败</strong>,这就确保了多个连接同时来了,都监测着a,</p>\n<p><strong>注意:</strong></p>\n<p> 使用watch也只是保证了几个操作不能同时进行,但最终结果是几个并行操作中只有第一个操作执行成功,其他的都执行失败并不再执行。</p>\n<p>即解决了能同时修改的问题,但是却只执行了单个任务,冲突的任务都没有执行。所以说使用redis内置事务解决不了问题,接下来尝试了解redis锁相关内容解决问题。</p>\n<h2 id=\"4-3为redis中的数据加锁\"><a href=\"#4-3为redis中的数据加锁\" class=\"headerlink\" title=\"4.3为redis中的数据加锁\"></a>4.3为redis中的数据加锁</h2><p>上面给出了源码链接,源码中已经将加锁操作进行了封装,可用在生产环境中没有问题。</p>\n<p><strong>核心函数:</strong></p>\n<p>redis中的setnx函数:</p>\n<blockquote>\n<p>官方:Set <code>key</code> to hold string <code>value</code> if <code>key</code> does not exist.</p>\n</blockquote>\n<p>使用<code>SETNX mykey "Hello"</code> ,有两种情况:</p>\n<ol>\n<li>mykey不存在,新建<code>mykey</code>并设为<code>Hello</code>,返回值<code>1</code></li>\n<li>mykey已存在,不做操作,返回值<code>0</code></li>\n</ol>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">// 为“aa”加字段锁</span></div><div class=\"line\">RedisLock lock = <span class=\"keyword\">new</span> RedisLock(<span class=\"string\">\"aa\"</span>,redisPool);</div><div class=\"line\">lock.lock(<span class=\"number\">10000</span>);</div></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">/**</div><div class=\"line\"> * <span class=\"doctag\">@param</span> timeout 超时时间</div><div class=\"line\"> * <span class=\"doctag\">@param</span> expire 锁的超时时间(秒),过期删除</div><div class=\"line\"> * <span class=\"doctag\">@return</span> 成功或失败标志</div><div class=\"line\"> */</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">boolean</span> <span class=\"title\">lock</span><span class=\"params\">(<span class=\"keyword\">long</span> timeout, <span class=\"keyword\">int</span> expire)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">long</span> nano = System.nanoTime();</div><div class=\"line\"> timeout *= MILLI_NANO_CONVERSION;</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> <span class=\"keyword\">while</span> ((System.nanoTime() - nano) < timeout) {</div><div class=\"line\"> <span class=\"comment\">// 多个并行用户同时请求为字段\"aa\"加锁,只有一个能够加锁成功</span></div><div class=\"line\"> <span class=\"comment\">// 只允许加锁成功的用户对字段\"aa\"进行操作,即实现了字段锁的效果 </span></div><div class=\"line\"> <span class=\"keyword\">if</span> (<span class=\"keyword\">this</span>.jedis.setnx(<span class=\"keyword\">this</span>.key, LOCKED) == <span class=\"number\">1</span>) {</div><div class=\"line\"> <span class=\"keyword\">this</span>.jedis.expire(<span class=\"keyword\">this</span>.key, expire);</div><div class=\"line\"> <span class=\"keyword\">this</span>.locked = <span class=\"keyword\">true</span>;</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">this</span>.locked;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"comment\">// 短暂休眠,避免出现活锁</span></div><div class=\"line\"> Thread.sleep(<span class=\"number\">3</span>, RANDOM.nextInt(<span class=\"number\">500</span>));</div><div class=\"line\"> }</div><div class=\"line\"> } <span class=\"keyword\">catch</span> (Exception e) {</div><div class=\"line\"> <span class=\"keyword\">throw</span> <span class=\"keyword\">new</span> RuntimeException(<span class=\"string\">\"Locking error\"</span>, e);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"keyword\">false</span>;</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<p>结束。</p>\n"},{"title":"微信开发模式接入","comment":true,"date":"2017-06-22T09:16:50.000Z","_content":"# 微信开发模式\n\n由于微信的广泛使用,微信作为一个集成用户信息、地理位置信息、支付等多种功能的强大平台的优势和便利越来越明显。微信公众号+小程序开发也提供了丰富的功能接口,让第三方平台可以容易的使用这些功能,避免了自己去构建这些功能的麻烦。比如“用户系统”,使用微信账户信息比起构建自己的用户系统还拥有更好的用户基础和用户友好性。而微信开发模式的接入和开发规范是一套固定的流程, 所以对于这种可以复用的代码,仔细的梳理一遍会为以后省去不少麻烦。\n\n接入微信公众平台,我们需要完成三步\n\n# 1、填写服务器配置\n\n![Image](http://ortur5wom.bkt.clouddn.com/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E6%8E%A5%E5%85%A5.png)\n\n注释: \n\n> url: 开发者用来接收微信消息和事件的接口URL\n> token: 由开发者可以任意填写,用作生成签名\n> EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥\n\n# 2、验证消息的确来自微信服务器\n\n验证服务器地址的有效性上面配置好后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示\n\n\n| 参数 | 意义 |\n| --------- | ---------------------------------------- |\n| signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |\n| timestamp | 时间戳 |\n| nonce | 随机数 |\n| echostr | 随机字符串 |\n\n我们接入代码要做的:\n\n> 1)将token、timestamp、nonce三个参数进行字典序排序\n> 2)将三个参数字符串拼接成一个字符串进行sha1加密\n> 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信\n\n# 3、依据接口文档实现业务逻辑\n\n我们使用基本的servlet来实现接入的处理逻辑\n\n## 1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息\n\n\n```java\npackage com.immoc.servlet;\n\nimport com.imooc.util.CheckUtil;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n/**\n * Created by zproo on 2017/6/22.\n */\npublic class WeixinServlet extends HttpServlet {\n @Override\n protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n String signature = req.getParameter(\"signature\");\n String timestamp = req.getParameter(\"timestamp\");\n String nonce = req.getParameter(\"nonce\");\n String echostr = req.getParameter(\"echostr\");\n\n PrintWriter out = resp.getWriter();\n if (CheckUtil.checkSignature(signature, timestamp, nonce)) {\n out.print(echostr);\n }\n }\n\n @Override\n protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n super.doPost(req, resp);\n }\n}\n```\n\n## 2.把微信服务器发来信息的处理函数封装在CheckUtil类中\n\n```java\npackage com.imooc.util;\n\nimport java.lang.reflect.Array;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\n\n/**\n * Created by zproo on 2017/6/22.\n */\npublic class CheckUtil {\n private static final String token = \"zproo\";\n\n public static boolean checkSignature(String signature, String timestamp, String nonce) {\n String[] arr = new String[]{token, timestamp, nonce};\n\n // 排序\n Arrays.sort(arr);\n // 生成字符串\n StringBuffer content = new StringBuffer();\n for (int i = 0; i < arr.length; i++) {\n content.append(arr[i]);\n }\n\n // sha1加密\n String temp = SHA1(content.toString());\n\n return temp.equals(signature);\n }\n\n /**\n * SHA1加密算法\n * @param decript\n * @return\n */\n public static String SHA1(String decript) {\n try {\n MessageDigest digest = MessageDigest.getInstance(\"SHA-1\");\n digest.update(decript.getBytes());\n byte messageDigest[] = digest.digest();\n StringBuffer hexString = new StringBuffer();\n for (int i = 0; i < messageDigest.length; i++) {\n String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);\n if (shaHex.length() < 2) {\n hexString.append(0);\n }\n hexString.append(shaHex);\n }\n return hexString.toString();\n\n } catch (NoSuchAlgorithmException e) {\n e.printStackTrace();\n }\n return \"\";\n }\n}\n```\n\n## 3.在web.xml配置servlet\n\n```xml\n<servlet>\n <servlet-name>weixinServlet</servlet-name>\n <servlet-class>com.immoc.servlet.WeixinServlet</servlet-class>\n </servlet>\n <servlet-mapping>\n <servlet-name>weixinServlet</servlet-name>\n <url-pattern>/wx.do</url-pattern>\n </servlet-mapping>\n```","source":"_posts/微信开发模式接入.md","raw":"---\ntitle: 微信开发模式接入\ncomment: true\ndate: 2017-06-22 17:16:50\ntags: [ Servlet, Java, 微信开发]\n---\n# 微信开发模式\n\n由于微信的广泛使用,微信作为一个集成用户信息、地理位置信息、支付等多种功能的强大平台的优势和便利越来越明显。微信公众号+小程序开发也提供了丰富的功能接口,让第三方平台可以容易的使用这些功能,避免了自己去构建这些功能的麻烦。比如“用户系统”,使用微信账户信息比起构建自己的用户系统还拥有更好的用户基础和用户友好性。而微信开发模式的接入和开发规范是一套固定的流程, 所以对于这种可以复用的代码,仔细的梳理一遍会为以后省去不少麻烦。\n\n接入微信公众平台,我们需要完成三步\n\n# 1、填写服务器配置\n\n![Image](http://ortur5wom.bkt.clouddn.com/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E6%8E%A5%E5%85%A5.png)\n\n注释: \n\n> url: 开发者用来接收微信消息和事件的接口URL\n> token: 由开发者可以任意填写,用作生成签名\n> EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥\n\n# 2、验证消息的确来自微信服务器\n\n验证服务器地址的有效性上面配置好后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示\n\n\n| 参数 | 意义 |\n| --------- | ---------------------------------------- |\n| signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |\n| timestamp | 时间戳 |\n| nonce | 随机数 |\n| echostr | 随机字符串 |\n\n我们接入代码要做的:\n\n> 1)将token、timestamp、nonce三个参数进行字典序排序\n> 2)将三个参数字符串拼接成一个字符串进行sha1加密\n> 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信\n\n# 3、依据接口文档实现业务逻辑\n\n我们使用基本的servlet来实现接入的处理逻辑\n\n## 1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息\n\n\n```java\npackage com.immoc.servlet;\n\nimport com.imooc.util.CheckUtil;\n\nimport javax.servlet.ServletException;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n/**\n * Created by zproo on 2017/6/22.\n */\npublic class WeixinServlet extends HttpServlet {\n @Override\n protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n String signature = req.getParameter(\"signature\");\n String timestamp = req.getParameter(\"timestamp\");\n String nonce = req.getParameter(\"nonce\");\n String echostr = req.getParameter(\"echostr\");\n\n PrintWriter out = resp.getWriter();\n if (CheckUtil.checkSignature(signature, timestamp, nonce)) {\n out.print(echostr);\n }\n }\n\n @Override\n protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {\n super.doPost(req, resp);\n }\n}\n```\n\n## 2.把微信服务器发来信息的处理函数封装在CheckUtil类中\n\n```java\npackage com.imooc.util;\n\nimport java.lang.reflect.Array;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\n\n/**\n * Created by zproo on 2017/6/22.\n */\npublic class CheckUtil {\n private static final String token = \"zproo\";\n\n public static boolean checkSignature(String signature, String timestamp, String nonce) {\n String[] arr = new String[]{token, timestamp, nonce};\n\n // 排序\n Arrays.sort(arr);\n // 生成字符串\n StringBuffer content = new StringBuffer();\n for (int i = 0; i < arr.length; i++) {\n content.append(arr[i]);\n }\n\n // sha1加密\n String temp = SHA1(content.toString());\n\n return temp.equals(signature);\n }\n\n /**\n * SHA1加密算法\n * @param decript\n * @return\n */\n public static String SHA1(String decript) {\n try {\n MessageDigest digest = MessageDigest.getInstance(\"SHA-1\");\n digest.update(decript.getBytes());\n byte messageDigest[] = digest.digest();\n StringBuffer hexString = new StringBuffer();\n for (int i = 0; i < messageDigest.length; i++) {\n String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);\n if (shaHex.length() < 2) {\n hexString.append(0);\n }\n hexString.append(shaHex);\n }\n return hexString.toString();\n\n } catch (NoSuchAlgorithmException e) {\n e.printStackTrace();\n }\n return \"\";\n }\n}\n```\n\n## 3.在web.xml配置servlet\n\n```xml\n<servlet>\n <servlet-name>weixinServlet</servlet-name>\n <servlet-class>com.immoc.servlet.WeixinServlet</servlet-class>\n </servlet>\n <servlet-mapping>\n <servlet-name>weixinServlet</servlet-name>\n <url-pattern>/wx.do</url-pattern>\n </servlet-mapping>\n```","slug":"微信开发模式接入","published":1,"updated":"2017-10-14T12:25:12.753Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k72000pwsv7sgxve0x8","content":"<h1 id=\"微信开发模式\"><a href=\"#微信开发模式\" class=\"headerlink\" title=\"微信开发模式\"></a>微信开发模式</h1><p>由于微信的广泛使用,微信作为一个集成用户信息、地理位置信息、支付等多种功能的强大平台的优势和便利越来越明显。微信公众号+小程序开发也提供了丰富的功能接口,让第三方平台可以容易的使用这些功能,避免了自己去构建这些功能的麻烦。比如“用户系统”,使用微信账户信息比起构建自己的用户系统还拥有更好的用户基础和用户友好性。而微信开发模式的接入和开发规范是一套固定的流程, 所以对于这种可以复用的代码,仔细的梳理一遍会为以后省去不少麻烦。</p>\n<p>接入微信公众平台,我们需要完成三步</p>\n<h1 id=\"1、填写服务器配置\"><a href=\"#1、填写服务器配置\" class=\"headerlink\" title=\"1、填写服务器配置\"></a>1、填写服务器配置</h1><p><img src=\"http://ortur5wom.bkt.clouddn.com/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E6%8E%A5%E5%85%A5.png\" alt=\"Image\"></p>\n<p>注释: </p>\n<blockquote>\n<p>url: 开发者用来接收微信消息和事件的接口URL<br>token: 由开发者可以任意填写,用作生成签名<br>EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥</p>\n</blockquote>\n<h1 id=\"2、验证消息的确来自微信服务器\"><a href=\"#2、验证消息的确来自微信服务器\" class=\"headerlink\" title=\"2、验证消息的确来自微信服务器\"></a>2、验证消息的确来自微信服务器</h1><p>验证服务器地址的有效性上面配置好后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示</p>\n<table>\n<thead>\n<tr>\n<th>参数</th>\n<th>意义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>signature</td>\n<td>微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</td>\n</tr>\n<tr>\n<td>timestamp</td>\n<td>时间戳</td>\n</tr>\n<tr>\n<td>nonce</td>\n<td>随机数</td>\n</tr>\n<tr>\n<td>echostr</td>\n<td>随机字符串</td>\n</tr>\n</tbody>\n</table>\n<p>我们接入代码要做的:</p>\n<blockquote>\n<p>1)将token、timestamp、nonce三个参数进行字典序排序<br>2)将三个参数字符串拼接成一个字符串进行sha1加密<br>3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信</p>\n</blockquote>\n<h1 id=\"3、依据接口文档实现业务逻辑\"><a href=\"#3、依据接口文档实现业务逻辑\" class=\"headerlink\" title=\"3、依据接口文档实现业务逻辑\"></a>3、依据接口文档实现业务逻辑</h1><p>我们使用基本的servlet来实现接入的处理逻辑</p>\n<h2 id=\"1-写一个servlet-WeixinServlet-处理微信服务器发来的信息\"><a href=\"#1-写一个servlet-WeixinServlet-处理微信服务器发来的信息\" class=\"headerlink\" title=\"1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息\"></a>1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.immoc.servlet;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> com.imooc.util.CheckUtil;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.ServletException;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServlet;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServletRequest;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServletResponse;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.IOException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.PrintWriter;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * Created by zproo on 2017/6/22.</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">WeixinServlet</span> <span class=\"keyword\">extends</span> <span class=\"title\">HttpServlet</span> </span>{</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">doGet</span><span class=\"params\">(HttpServletRequest req, HttpServletResponse resp)</span> <span class=\"keyword\">throws</span> ServletException, IOException </span>{</div><div class=\"line\"> String signature = req.getParameter(<span class=\"string\">\"signature\"</span>);</div><div class=\"line\"> String timestamp = req.getParameter(<span class=\"string\">\"timestamp\"</span>);</div><div class=\"line\"> String nonce = req.getParameter(<span class=\"string\">\"nonce\"</span>);</div><div class=\"line\"> String echostr = req.getParameter(<span class=\"string\">\"echostr\"</span>);</div><div class=\"line\"></div><div class=\"line\"> PrintWriter out = resp.getWriter();</div><div class=\"line\"> <span class=\"keyword\">if</span> (CheckUtil.checkSignature(signature, timestamp, nonce)) {</div><div class=\"line\"> out.print(echostr);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">doPost</span><span class=\"params\">(HttpServletRequest req, HttpServletResponse resp)</span> <span class=\"keyword\">throws</span> ServletException, IOException </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>.doPost(req, resp);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"2-把微信服务器发来信息的处理函数封装在CheckUtil类中\"><a href=\"#2-把微信服务器发来信息的处理函数封装在CheckUtil类中\" class=\"headerlink\" title=\"2.把微信服务器发来信息的处理函数封装在CheckUtil类中\"></a>2.把微信服务器发来信息的处理函数封装在CheckUtil类中</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.imooc.util;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> java.lang.reflect.Array;</div><div class=\"line\"><span class=\"keyword\">import</span> java.security.MessageDigest;</div><div class=\"line\"><span class=\"keyword\">import</span> java.security.NoSuchAlgorithmException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.Arrays;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">/**</span></div><div class=\"line\"> * Created by zproo on 2017/6/22.</div><div class=\"line\"> */</div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">CheckUtil</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">static</span> <span class=\"keyword\">final</span> String token = <span class=\"string\">\"zproo\"</span>;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">boolean</span> <span class=\"title\">checkSignature</span><span class=\"params\">(String signature, String timestamp, String nonce)</span> </span>{</div><div class=\"line\"> String[] arr = <span class=\"keyword\">new</span> String[]{token, timestamp, nonce};</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 排序</span></div><div class=\"line\"> Arrays.sort(arr);</div><div class=\"line\"> <span class=\"comment\">// 生成字符串</span></div><div class=\"line\"> StringBuffer content = <span class=\"keyword\">new</span> StringBuffer();</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < arr.length; i++) {</div><div class=\"line\"> content.append(arr[i]);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// sha1加密</span></div><div class=\"line\"> String temp = SHA1(content.toString());</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">return</span> temp.equals(signature);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</span></div><div class=\"line\"> * SHA1加密算法</div><div class=\"line\"> * <span class=\"doctag\">@param</span> decript</div><div class=\"line\"> * <span class=\"doctag\">@return</span></div><div class=\"line\"> */</div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> String <span class=\"title\">SHA1</span><span class=\"params\">(String decript)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> MessageDigest digest = MessageDigest.getInstance(<span class=\"string\">\"SHA-1\"</span>);</div><div class=\"line\"> digest.update(decript.getBytes());</div><div class=\"line\"> <span class=\"keyword\">byte</span> messageDigest[] = digest.digest();</div><div class=\"line\"> StringBuffer hexString = <span class=\"keyword\">new</span> StringBuffer();</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < messageDigest.length; i++) {</div><div class=\"line\"> String shaHex = Integer.toHexString(messageDigest[i] & <span class=\"number\">0xFF</span>);</div><div class=\"line\"> <span class=\"keyword\">if</span> (shaHex.length() < <span class=\"number\">2</span>) {</div><div class=\"line\"> hexString.append(<span class=\"number\">0</span>);</div><div class=\"line\"> }</div><div class=\"line\"> hexString.append(shaHex);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> hexString.toString();</div><div class=\"line\"></div><div class=\"line\"> } <span class=\"keyword\">catch</span> (NoSuchAlgorithmException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">\"\"</span>;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"3-在web-xml配置servlet\"><a href=\"#3-在web-xml配置servlet\" class=\"headerlink\" title=\"3.在web.xml配置servlet\"></a>3.在web.xml配置servlet</h2><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">servlet</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-name</span>></span>weixinServlet<span class=\"tag\"></<span class=\"name\">servlet-name</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-class</span>></span>com.immoc.servlet.WeixinServlet<span class=\"tag\"></<span class=\"name\">servlet-class</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">servlet</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-mapping</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-name</span>></span>weixinServlet<span class=\"tag\"></<span class=\"name\">servlet-name</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">url-pattern</span>></span>/wx.do<span class=\"tag\"></<span class=\"name\">url-pattern</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">servlet-mapping</span>></span></div></pre></td></tr></table></figure>","excerpt":"","more":"<h1 id=\"微信开发模式\"><a href=\"#微信开发模式\" class=\"headerlink\" title=\"微信开发模式\"></a>微信开发模式</h1><p>由于微信的广泛使用,微信作为一个集成用户信息、地理位置信息、支付等多种功能的强大平台的优势和便利越来越明显。微信公众号+小程序开发也提供了丰富的功能接口,让第三方平台可以容易的使用这些功能,避免了自己去构建这些功能的麻烦。比如“用户系统”,使用微信账户信息比起构建自己的用户系统还拥有更好的用户基础和用户友好性。而微信开发模式的接入和开发规范是一套固定的流程, 所以对于这种可以复用的代码,仔细的梳理一遍会为以后省去不少麻烦。</p>\n<p>接入微信公众平台,我们需要完成三步</p>\n<h1 id=\"1、填写服务器配置\"><a href=\"#1、填写服务器配置\" class=\"headerlink\" title=\"1、填写服务器配置\"></a>1、填写服务器配置</h1><p><img src=\"http://ortur5wom.bkt.clouddn.com/%E5%BE%AE%E4%BF%A1%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E6%8E%A5%E5%85%A5.png\" alt=\"Image\"></p>\n<p>注释: </p>\n<blockquote>\n<p>url: 开发者用来接收微信消息和事件的接口URL<br>token: 由开发者可以任意填写,用作生成签名<br>EncodingAESKey: 由开发者手动填写或随机生成,将用作消息体加解密密钥</p>\n</blockquote>\n<h1 id=\"2、验证消息的确来自微信服务器\"><a href=\"#2、验证消息的确来自微信服务器\" class=\"headerlink\" title=\"2、验证消息的确来自微信服务器\"></a>2、验证消息的确来自微信服务器</h1><p>验证服务器地址的有效性上面配置好后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示</p>\n<table>\n<thead>\n<tr>\n<th>参数</th>\n<th>意义</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>signature</td>\n<td>微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。</td>\n</tr>\n<tr>\n<td>timestamp</td>\n<td>时间戳</td>\n</tr>\n<tr>\n<td>nonce</td>\n<td>随机数</td>\n</tr>\n<tr>\n<td>echostr</td>\n<td>随机字符串</td>\n</tr>\n</tbody>\n</table>\n<p>我们接入代码要做的:</p>\n<blockquote>\n<p>1)将token、timestamp、nonce三个参数进行字典序排序<br>2)将三个参数字符串拼接成一个字符串进行sha1加密<br>3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信</p>\n</blockquote>\n<h1 id=\"3、依据接口文档实现业务逻辑\"><a href=\"#3、依据接口文档实现业务逻辑\" class=\"headerlink\" title=\"3、依据接口文档实现业务逻辑\"></a>3、依据接口文档实现业务逻辑</h1><p>我们使用基本的servlet来实现接入的处理逻辑</p>\n<h2 id=\"1-写一个servlet-WeixinServlet-处理微信服务器发来的信息\"><a href=\"#1-写一个servlet-WeixinServlet-处理微信服务器发来的信息\" class=\"headerlink\" title=\"1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息\"></a>1. 写一个servlet(WeixinServlet)处理微信服务器发来的信息</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.immoc.servlet;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> com.imooc.util.CheckUtil;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.ServletException;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServlet;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServletRequest;</div><div class=\"line\"><span class=\"keyword\">import</span> javax.servlet.http.HttpServletResponse;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.IOException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.io.PrintWriter;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">/**</div><div class=\"line\"> * Created by zproo on 2017/6/22.</div><div class=\"line\"> */</span></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">WeixinServlet</span> <span class=\"keyword\">extends</span> <span class=\"title\">HttpServlet</span> </span>{</div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">doGet</span><span class=\"params\">(HttpServletRequest req, HttpServletResponse resp)</span> <span class=\"keyword\">throws</span> ServletException, IOException </span>{</div><div class=\"line\"> String signature = req.getParameter(<span class=\"string\">\"signature\"</span>);</div><div class=\"line\"> String timestamp = req.getParameter(<span class=\"string\">\"timestamp\"</span>);</div><div class=\"line\"> String nonce = req.getParameter(<span class=\"string\">\"nonce\"</span>);</div><div class=\"line\"> String echostr = req.getParameter(<span class=\"string\">\"echostr\"</span>);</div><div class=\"line\"></div><div class=\"line\"> PrintWriter out = resp.getWriter();</div><div class=\"line\"> <span class=\"keyword\">if</span> (CheckUtil.checkSignature(signature, timestamp, nonce)) {</div><div class=\"line\"> out.print(echostr);</div><div class=\"line\"> }</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"meta\">@Override</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">protected</span> <span class=\"keyword\">void</span> <span class=\"title\">doPost</span><span class=\"params\">(HttpServletRequest req, HttpServletResponse resp)</span> <span class=\"keyword\">throws</span> ServletException, IOException </span>{</div><div class=\"line\"> <span class=\"keyword\">super</span>.doPost(req, resp);</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"2-把微信服务器发来信息的处理函数封装在CheckUtil类中\"><a href=\"#2-把微信服务器发来信息的处理函数封装在CheckUtil类中\" class=\"headerlink\" title=\"2.把微信服务器发来信息的处理函数封装在CheckUtil类中\"></a>2.把微信服务器发来信息的处理函数封装在CheckUtil类中</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"keyword\">package</span> com.imooc.util;</div><div class=\"line\"></div><div class=\"line\"><span class=\"keyword\">import</span> java.lang.reflect.Array;</div><div class=\"line\"><span class=\"keyword\">import</span> java.security.MessageDigest;</div><div class=\"line\"><span class=\"keyword\">import</span> java.security.NoSuchAlgorithmException;</div><div class=\"line\"><span class=\"keyword\">import</span> java.util.Arrays;</div><div class=\"line\"></div><div class=\"line\"><span class=\"comment\">/**</div><div class=\"line\"> * Created by zproo on 2017/6/22.</div><div class=\"line\"> */</span></div><div class=\"line\"><span class=\"keyword\">public</span> <span class=\"class\"><span class=\"keyword\">class</span> <span class=\"title\">CheckUtil</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">private</span> <span class=\"keyword\">static</span> <span class=\"keyword\">final</span> String token = <span class=\"string\">\"zproo\"</span>;</div><div class=\"line\"></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">boolean</span> <span class=\"title\">checkSignature</span><span class=\"params\">(String signature, String timestamp, String nonce)</span> </span>{</div><div class=\"line\"> String[] arr = <span class=\"keyword\">new</span> String[]{token, timestamp, nonce};</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// 排序</span></div><div class=\"line\"> Arrays.sort(arr);</div><div class=\"line\"> <span class=\"comment\">// 生成字符串</span></div><div class=\"line\"> StringBuffer content = <span class=\"keyword\">new</span> StringBuffer();</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < arr.length; i++) {</div><div class=\"line\"> content.append(arr[i]);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">// sha1加密</span></div><div class=\"line\"> String temp = SHA1(content.toString());</div><div class=\"line\"></div><div class=\"line\"> <span class=\"keyword\">return</span> temp.equals(signature);</div><div class=\"line\"> }</div><div class=\"line\"></div><div class=\"line\"> <span class=\"comment\">/**</div><div class=\"line\"> * SHA1加密算法</div><div class=\"line\"> * <span class=\"doctag\">@param</span> decript</div><div class=\"line\"> * <span class=\"doctag\">@return</span></div><div class=\"line\"> */</span></div><div class=\"line\"> <span class=\"function\"><span class=\"keyword\">public</span> <span class=\"keyword\">static</span> String <span class=\"title\">SHA1</span><span class=\"params\">(String decript)</span> </span>{</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> MessageDigest digest = MessageDigest.getInstance(<span class=\"string\">\"SHA-1\"</span>);</div><div class=\"line\"> digest.update(decript.getBytes());</div><div class=\"line\"> <span class=\"keyword\">byte</span> messageDigest[] = digest.digest();</div><div class=\"line\"> StringBuffer hexString = <span class=\"keyword\">new</span> StringBuffer();</div><div class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"keyword\">int</span> i = <span class=\"number\">0</span>; i < messageDigest.length; i++) {</div><div class=\"line\"> String shaHex = Integer.toHexString(messageDigest[i] & <span class=\"number\">0xFF</span>);</div><div class=\"line\"> <span class=\"keyword\">if</span> (shaHex.length() < <span class=\"number\">2</span>) {</div><div class=\"line\"> hexString.append(<span class=\"number\">0</span>);</div><div class=\"line\"> }</div><div class=\"line\"> hexString.append(shaHex);</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> hexString.toString();</div><div class=\"line\"></div><div class=\"line\"> } <span class=\"keyword\">catch</span> (NoSuchAlgorithmException e) {</div><div class=\"line\"> e.printStackTrace();</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">\"\"</span>;</div><div class=\"line\"> }</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"3-在web-xml配置servlet\"><a href=\"#3-在web-xml配置servlet\" class=\"headerlink\" title=\"3.在web.xml配置servlet\"></a>3.在web.xml配置servlet</h2><figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"tag\"><<span class=\"name\">servlet</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-name</span>></span>weixinServlet<span class=\"tag\"></<span class=\"name\">servlet-name</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-class</span>></span>com.immoc.servlet.WeixinServlet<span class=\"tag\"></<span class=\"name\">servlet-class</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">servlet</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-mapping</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">servlet-name</span>></span>weixinServlet<span class=\"tag\"></<span class=\"name\">servlet-name</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">url-pattern</span>></span>/wx.do<span class=\"tag\"></<span class=\"name\">url-pattern</span>></span></div><div class=\"line\"> <span class=\"tag\"></<span class=\"name\">servlet-mapping</span>></span></div></pre></td></tr></table></figure>"},{"title":"记一次数据库查询优化","comment":true,"date":"2017-12-06T08:33:24.000Z","_content":"\n# 1. 问题描述\n\nmysql中速度慢的查询语句:\n\n``` mysql\nSELECT\n COUNT(*)\nFROM\n ms_rp_flowlog\nWHERE ms_rp_flowlog.`userid` = \"当前登录用户\"\n AND ms_rp_flowlog.`activityid` = \"当前活动id\"\n```\n\n发生场景:\n\n随着`ms_rp_flowlog`表数据量的不断增加,当达到50万条记录时上述语句的平均查询耗时将达到`5s~8s`。用户的日常使用场景会感受到明显的卡顿。\n\n# 2. 解决方法:\n\n\n\n根据项目实际应用场景以及数据库索引的使用方法,为查询语句中的限制条件字段添加数据库索引。添加索引后的查询效率将会提升几十倍。\n\n\n\n# 3. 数据库索引原理\n\n## 3.1 没有索引的情况\n\n索引可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么可能需要把所有单词看一遍才能找到你想要的。如果我想找到m开头的单词呢?或者ze开头的单词呢?如果没有索引,这个事情几乎无法完成。\n\n## 3.2 索引原理\n\n> 说白了,索引问题就是一个查找问题。\n\n回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。\n\n但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树 (二叉排序树),其平均复杂度是logN,具有不错的查询性能。\n\n但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的,数据库实现比较复杂,数据保存在磁盘上,而为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景,因为频繁的磁盘io开销巨大。\n\n所以一个高度可控的多路搜索树应运而生,它就是B+树。\n\n## 3.3 B+树应用简介\n\n![B+树数据结构](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/B+%E6%A0%91.png)\n\n如图所示,如果要查找数据项29,\n\n- 那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO\n- 在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO\n- 29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO\n- 同时内存中做二分查找找到29,结束查询,总计三次IO。\n\n真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。\n\n# 4. 索引创建的几大原则\n\n1. 最左前缀匹配原则,非常重要的原则。\n\n mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配, 比如 a = 1 and b = 2 and c>3 and d=4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。\n\n2. =和in可以乱序\n\n 比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式\n\n3. 尽量选择区分度高的列作为索引\n\n 区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录\n\n4. 索引列不能参与计算,保持列“干净”\n\n 比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);\n\n5. 尽量的扩展索引,不要新建索引。\n\n 比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可\n\n\n\n# 参考文献:\n\n- [MySQL索引原理及慢查询优化](https://tech.meituan.com/mysql-index.html)\n\n- [数据库索引的实现原理](http://blog.csdn.net/kennyrose/article/details/7532032)","source":"_posts/记一次数据库查询优化.md","raw":"---\ntitle: 记一次数据库查询优化\ncomment: true\ndate: 2017-12-06 16:33:24\ntags: [mysql, B+树, 数据库索引]\n---\n\n# 1. 问题描述\n\nmysql中速度慢的查询语句:\n\n``` mysql\nSELECT\n COUNT(*)\nFROM\n ms_rp_flowlog\nWHERE ms_rp_flowlog.`userid` = \"当前登录用户\"\n AND ms_rp_flowlog.`activityid` = \"当前活动id\"\n```\n\n发生场景:\n\n随着`ms_rp_flowlog`表数据量的不断增加,当达到50万条记录时上述语句的平均查询耗时将达到`5s~8s`。用户的日常使用场景会感受到明显的卡顿。\n\n# 2. 解决方法:\n\n\n\n根据项目实际应用场景以及数据库索引的使用方法,为查询语句中的限制条件字段添加数据库索引。添加索引后的查询效率将会提升几十倍。\n\n\n\n# 3. 数据库索引原理\n\n## 3.1 没有索引的情况\n\n索引可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么可能需要把所有单词看一遍才能找到你想要的。如果我想找到m开头的单词呢?或者ze开头的单词呢?如果没有索引,这个事情几乎无法完成。\n\n## 3.2 索引原理\n\n> 说白了,索引问题就是一个查找问题。\n\n回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。\n\n但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树 (二叉排序树),其平均复杂度是logN,具有不错的查询性能。\n\n但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的,数据库实现比较复杂,数据保存在磁盘上,而为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景,因为频繁的磁盘io开销巨大。\n\n所以一个高度可控的多路搜索树应运而生,它就是B+树。\n\n## 3.3 B+树应用简介\n\n![B+树数据结构](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/B+%E6%A0%91.png)\n\n如图所示,如果要查找数据项29,\n\n- 那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO\n- 在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO\n- 29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO\n- 同时内存中做二分查找找到29,结束查询,总计三次IO。\n\n真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。\n\n# 4. 索引创建的几大原则\n\n1. 最左前缀匹配原则,非常重要的原则。\n\n mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配, 比如 a = 1 and b = 2 and c>3 and d=4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。\n\n2. =和in可以乱序\n\n 比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式\n\n3. 尽量选择区分度高的列作为索引\n\n 区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录\n\n4. 索引列不能参与计算,保持列“干净”\n\n 比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);\n\n5. 尽量的扩展索引,不要新建索引。\n\n 比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可\n\n\n\n# 参考文献:\n\n- [MySQL索引原理及慢查询优化](https://tech.meituan.com/mysql-index.html)\n\n- [数据库索引的实现原理](http://blog.csdn.net/kennyrose/article/details/7532032)","slug":"记一次数据库查询优化","published":1,"updated":"2017-12-11T02:59:13.992Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k7h000rwsv7m7v3sf2w","content":"<h1 id=\"1-问题描述\"><a href=\"#1-问题描述\" class=\"headerlink\" title=\"1. 问题描述\"></a>1. 问题描述</h1><p>mysql中速度慢的查询语句:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">SELECT</div><div class=\"line\"> COUNT(*)</div><div class=\"line\">FROM</div><div class=\"line\"> ms_rp_flowlog</div><div class=\"line\">WHERE ms_rp_flowlog.`userid` = "当前登录用户"</div><div class=\"line\"> AND ms_rp_flowlog.`activityid` = "当前活动id"</div></pre></td></tr></table></figure>\n<p>发生场景:</p>\n<p>随着<code>ms_rp_flowlog</code>表数据量的不断增加,当达到50万条记录时上述语句的平均查询耗时将达到<code>5s~8s</code>。用户的日常使用场景会感受到明显的卡顿。</p>\n<h1 id=\"2-解决方法:\"><a href=\"#2-解决方法:\" class=\"headerlink\" title=\"2. 解决方法:\"></a>2. 解决方法:</h1><p>根据项目实际应用场景以及数据库索引的使用方法,为查询语句中的限制条件字段添加数据库索引。添加索引后的查询效率将会提升几十倍。</p>\n<h1 id=\"3-数据库索引原理\"><a href=\"#3-数据库索引原理\" class=\"headerlink\" title=\"3. 数据库索引原理\"></a>3. 数据库索引原理</h1><h2 id=\"3-1-没有索引的情况\"><a href=\"#3-1-没有索引的情况\" class=\"headerlink\" title=\"3.1 没有索引的情况\"></a>3.1 没有索引的情况</h2><p>索引可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么可能需要把所有单词看一遍才能找到你想要的。如果我想找到m开头的单词呢?或者ze开头的单词呢?如果没有索引,这个事情几乎无法完成。</p>\n<h2 id=\"3-2-索引原理\"><a href=\"#3-2-索引原理\" class=\"headerlink\" title=\"3.2 索引原理\"></a>3.2 索引原理</h2><blockquote>\n<p>说白了,索引问题就是一个查找问题。</p>\n</blockquote>\n<p>回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段……这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。</p>\n<p>但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树 (二叉排序树),其平均复杂度是logN,具有不错的查询性能。</p>\n<p>但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的,数据库实现比较复杂,数据保存在磁盘上,而为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景,因为频繁的磁盘io开销巨大。</p>\n<p>所以一个高度可控的多路搜索树应运而生,它就是B+树。</p>\n<h2 id=\"3-3-B-树应用简介\"><a href=\"#3-3-B-树应用简介\" class=\"headerlink\" title=\"3.3 B+树应用简介\"></a>3.3 B+树应用简介</h2><p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/B+%E6%A0%91.png\" alt=\"B+树数据结构\"></p>\n<p>如图所示,如果要查找数据项29,</p>\n<ul>\n<li>那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO</li>\n<li>在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO</li>\n<li>29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO</li>\n<li>同时内存中做二分查找找到29,结束查询,总计三次IO。</li>\n</ul>\n<p>真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。</p>\n<h1 id=\"4-索引创建的几大原则\"><a href=\"#4-索引创建的几大原则\" class=\"headerlink\" title=\"4. 索引创建的几大原则\"></a>4. 索引创建的几大原则</h1><ol>\n<li><p>最左前缀匹配原则,非常重要的原则。</p>\n<p>mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配, 比如 a = 1 and b = 2 and c>3 and d=4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。</p>\n</li>\n<li><p>=和in可以乱序</p>\n<p>比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式</p>\n</li>\n<li><p>尽量选择区分度高的列作为索引</p>\n<p>区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录</p>\n</li>\n<li><p>索引列不能参与计算,保持列“干净”</p>\n<p>比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);</p>\n</li>\n<li><p>尽量的扩展索引,不要新建索引。</p>\n<p>比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可</p>\n</li>\n</ol>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><p><a href=\"https://tech.meituan.com/mysql-index.html\" target=\"_blank\" rel=\"external\">MySQL索引原理及慢查询优化</a></p>\n</li>\n<li><p><a href=\"http://blog.csdn.net/kennyrose/article/details/7532032\" target=\"_blank\" rel=\"external\">数据库索引的实现原理</a></p>\n</li>\n</ul>\n","excerpt":"","more":"<h1 id=\"1-问题描述\"><a href=\"#1-问题描述\" class=\"headerlink\" title=\"1. 问题描述\"></a>1. 问题描述</h1><p>mysql中速度慢的查询语句:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\">SELECT</div><div class=\"line\"> COUNT(*)</div><div class=\"line\">FROM</div><div class=\"line\"> ms_rp_flowlog</div><div class=\"line\">WHERE ms_rp_flowlog.`userid` = "当前登录用户"</div><div class=\"line\"> AND ms_rp_flowlog.`activityid` = "当前活动id"</div></pre></td></tr></table></figure>\n<p>发生场景:</p>\n<p>随着<code>ms_rp_flowlog</code>表数据量的不断增加,当达到50万条记录时上述语句的平均查询耗时将达到<code>5s~8s</code>。用户的日常使用场景会感受到明显的卡顿。</p>\n<h1 id=\"2-解决方法:\"><a href=\"#2-解决方法:\" class=\"headerlink\" title=\"2. 解决方法:\"></a>2. 解决方法:</h1><p>根据项目实际应用场景以及数据库索引的使用方法,为查询语句中的限制条件字段添加数据库索引。添加索引后的查询效率将会提升几十倍。</p>\n<h1 id=\"3-数据库索引原理\"><a href=\"#3-数据库索引原理\" class=\"headerlink\" title=\"3. 数据库索引原理\"></a>3. 数据库索引原理</h1><h2 id=\"3-1-没有索引的情况\"><a href=\"#3-1-没有索引的情况\" class=\"headerlink\" title=\"3.1 没有索引的情况\"></a>3.1 没有索引的情况</h2><p>索引可以类比字典,如果要查“mysql”这个单词,我们肯定需要定位到m字母,然后从下往下找到y字母,再找到剩下的sql。如果没有索引,那么可能需要把所有单词看一遍才能找到你想要的。如果我想找到m开头的单词呢?或者ze开头的单词呢?如果没有索引,这个事情几乎无法完成。</p>\n<h2 id=\"3-2-索引原理\"><a href=\"#3-2-索引原理\" class=\"headerlink\" title=\"3.2 索引原理\"></a>3.2 索引原理</h2><blockquote>\n<p>说白了,索引问题就是一个查找问题。</p>\n</blockquote>\n<p>回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段……这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。</p>\n<p>但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树 (二叉排序树),其平均复杂度是logN,具有不错的查询性能。</p>\n<p>但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的,数据库实现比较复杂,数据保存在磁盘上,而为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景,因为频繁的磁盘io开销巨大。</p>\n<p>所以一个高度可控的多路搜索树应运而生,它就是B+树。</p>\n<h2 id=\"3-3-B-树应用简介\"><a href=\"#3-3-B-树应用简介\" class=\"headerlink\" title=\"3.3 B+树应用简介\"></a>3.3 B+树应用简介</h2><p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/B+%E6%A0%91.png\" alt=\"B+树数据结构\"></p>\n<p>如图所示,如果要查找数据项29,</p>\n<ul>\n<li>那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO</li>\n<li>在内存中用二分查找确定29在17和35之间,锁定磁盘块1的P2指针,内存时间因为非常短(相比磁盘的IO)可以忽略不计,通过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO</li>\n<li>29在26和30之间,锁定磁盘块3的P2指针,通过指针加载磁盘块8到内存,发生第三次IO</li>\n<li>同时内存中做二分查找找到29,结束查询,总计三次IO。</li>\n</ul>\n<p>真实的情况是,3层的b+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提高将是巨大的,如果没有索引,每个数据项都要发生一次IO,那么总共需要百万次的IO,显然成本非常非常高。</p>\n<h1 id=\"4-索引创建的几大原则\"><a href=\"#4-索引创建的几大原则\" class=\"headerlink\" title=\"4. 索引创建的几大原则\"></a>4. 索引创建的几大原则</h1><ol>\n<li><p>最左前缀匹配原则,非常重要的原则。</p>\n<p>mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配, 比如 a = 1 and b = 2 and c>3 and d=4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整。</p>\n</li>\n<li><p>=和in可以乱序</p>\n<p>比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式</p>\n</li>\n<li><p>尽量选择区分度高的列作为索引</p>\n<p>区分度的公式是count(distinct col)/count(*),表示字段不重复的比例,比例越大我们扫描的记录数越少,唯一键的区分度是1,而一些状态、性别字段可能在大数据面前区分度就是0,那可能有人会问,这个比例有什么经验值吗?使用场景不同,这个值也很难确定,一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录</p>\n</li>\n<li><p>索引列不能参与计算,保持列“干净”</p>\n<p>比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很简单,b+树中存的都是数据表中的字段值,但进行检索时,需要把所有元素都应用函数才能比较,显然成本太大。所以语句应该写成create_time = unix_timestamp(’2014-05-29’);</p>\n</li>\n<li><p>尽量的扩展索引,不要新建索引。</p>\n<p>比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可</p>\n</li>\n</ol>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><p><a href=\"https://tech.meituan.com/mysql-index.html\">MySQL索引原理及慢查询优化</a></p>\n</li>\n<li><p><a href=\"http://blog.csdn.net/kennyrose/article/details/7532032\">数据库索引的实现原理</a></p>\n</li>\n</ul>\n"},{"title":"计算丢失精度解决方法","comment":true,"date":"2017-11-08T06:44:05.000Z","_content":"\n# Double类型计算丢失精度问题解决\n**说明**\n\n1. 本文档里使用的方法只试用于常见项目出现的浮点数据类型计算丢失精度问题\n2. 在计算时还好考虑 所用计算机语言支持的 各类型数字的最大值与最小值\n\n\n# 1. Java场景\n\n## 1.1 问题重现\n\n``` java\nSystem.out.println(\"0.05 + 0.01 = \" + (0.05 + 0.01)); 输出:0.060000000000000005\n\nSystem.out.println(\"1.0 - 0.42 = \" + (1.0 - 0.42)); 输出:0.5800000000000001\n\nSystem.out.println(\"4.015 * 100 = \" + (4.015 * 100)); 输出:401.49999999999994\n\nSystem.out.println(\"123.3 / 100 = \" + (123.3 / 100)); 输出:1.2329999999999999\n```\n## 1.2 解决思路\n\n1. 需要调用java.math.BigDecimal 类\n2. 把double类型转换为BigDecimal 类型 \n `BigDecimal bigDecimal = new BigDecimal(Double.toString());`\n3. 通过BigDecimal中的加、减、乘、除 的方法进行计算\n\n ```\n bigDecimal1.add(bigDecimal2) //加\n bigDecimal1.subtract(bigDecimal2) //减\n bigDecimal1.multiply(bigDecimal2) //乘\n bigDecimal1.divide(bigDecimal2) //除\n ```\n\n \n\n\n## 1.3 封装相关方法\n\n``` java\n//加\npublic Double add(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.add(b2)).doubleValue();\n}\n//减\npublic Double sub(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.subtract(b2)).doubleValue();\n}\n//乘\npublic Double mul(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.multiply(b2)).doubleValue();\n}\n//除\npublic Double div(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.divide(b2)).doubleValue();\n}\n\n```\n\n## 1.4 测试\n\n``` java\nSystem.out.println(\"0.05 + 0.01 = \" + BigDecimalUtil.add(0.05, 0.01)); 输出:0.06\nSystem.out.println(\"1.0 - 0.42 = \" + BigDecimalUtil.sub(1.0, 0.42)); 输出:0.58\nSystem.out.println(\"4.015 * 100 = \" + BigDecimalUtil.mul(4.015 ,100.00)); 输出:401.5\nSystem.out.println(\"123.3 / 100 = \" + BigDecimalUtil.div(123.3, 100.00)); 输出:41.07\n```\n\n### 1.4.1 异常处理\n\n如果除不尽会报下面异常\n\n``` java\nSystem.out.println(\"123.2 / 3 = \" + r.div(123.2, 3.0));\n结果:\nException in thread \"main\" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.\n at java.math.BigDecimal.divide(Unknown Source)\n\n```\n\n处理方法:四舍五入保留两位小数\n\n``` java\n //除法改造四舍五入,保留2位小数\npublic Double div2(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.divide(b2,2,BigDecimal.ROUND_HALF_UP)).doubleValue();//四舍五入,保留2位小数\n }\n\n```\n\n测试结果:\n\n``` java\nSystem.out.println(\"123.2 / 3 = \" + BigDecimalUtil .div2(123.2, 3.0)); 输出:41.07\n```\n\n# 2. 数据库场景\n\n## 2.1 问题重现\n\n表结构(表明doubleTab):\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A61.png)\n\n表数据:\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A62.png)\n\n问题展示:\n\n1. 查询sql:\n\n``` mysql\n\nSELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result \nfrom doubleTab d WHERE d.id = 1\nUNION\nSELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result \nfrom doubleTab d WHERE d.id = 2\nUNION\nSELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result \nfrom doubleTab d WHERE d.id = 3\nUNION\nSELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result \nfrom doubleTab d WHERE d.id = 4\n\n```\n\n2. 结果:\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A63.png)\n\n## 2.2 解决思路\n\n用decimal 类型替换表结构中的 double类型\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A64.png)\n\n## 2.3 结果展示\n\n1. 查询sql\n\n``` mysql\nSELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result \nfrom doubleTab d WHERE d.id = 1\nUNION\nSELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result \nfrom doubleTab d WHERE d.id = 2\nUNION\nSELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result \nfrom doubleTab d WHERE d.id = 3\nUNION\nSELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result \nfrom doubleTab d WHERE d.id = 4\n\n```\n\n2. 结果\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A65.png)\n\n\n\n# 3. Javascript场景\n\n## 3.1 问题重现\n\n页面代码:\n\n``` html\n<!DOCTYPE HTML> \n<html> \n<head> \n<script src=\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"></script>;\n<script>\n$(function(){\n $('#add').text(0.05 + 0.01)\n $('#sub').text(1.0 - 0.42)\n $('#mul').text(4.015 * 100)\n $('#div').text(123.3 / 100)\n})\n</script>\n</head> \n<body>\n <p >0.05 + 0.01 = <span id=\"add\"></span></p>\n <p >1.0 - 0.42 = <span id=\"sub\"></span></p>\n <p >4.015 * 100 = <span id=\"mul\"></span></p>\n <p >123.3 / 100 = <span id=\"div\"></span></p>\n</body> \n</html>\n\n```\n\n页面显示:\n\n``` \n0.05 + 0.01 = 0.060000000000000005\n1.0 - 0.42 = 0.5800000000000001\n4.015 * 100 = 401.49999999999994\n123.3 / 100 = 1.2329999999999999\n```\n\n## 3.2 解决思路\n\n1. 对于乘法与除法\n\n 算出两个参数一共有几位小数,把两个参数的小数点去掉进行 乘法或除法运算 结果再除以10的参数小数点后面位数和次幂\n\n2. 对于加法与减法\n\n 算出两个参数一共有几位小数,把两个参数分别用写好的乘法运算 乘以10的参数小数点后面位数和次幂,然后在把两个参数进行激发或减法运算,结果再除以10的参数小数点后面位数和次幂\n\n``` javascript\n//加法\nfunction add(arg1, arg2) {\n var m = 0,s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n \n return (arg1 + arg2) / Math.pow(10, m);\n}\n//减法\nfunction sub(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n return (arg1 - arg2) / Math.pow(10, m);\n}\n//乘法\nfunction mul(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) * Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n//除法\nfunction div(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) /Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n\n```\n\n## 3.3 结果展示\n\n``` html\n<!DOCTYPE HTML> \n<html> \n<head> \n<script src=\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"></script>;\n<script>\n$(function(){\n $('#add').text(add(0.05,0.01))\n $('#sub').text(sub(1.0,0.42))\n $('#mul').text(mul(4.015 ,100))\n $('#div').text(div(123.3,100))\n})\n//加法\nfunction add(arg1, arg2) {\n var m = 0,s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n \n return (arg1 + arg2) / Math.pow(10, m);\n}\n//减法\nfunction sub(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n return (arg1 - arg2) / Math.pow(10, m);\n}\n//乘法\nfunction mul(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) * Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n//除法\nfunction div(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) /Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n</script>\n</head> \n<body>\n <p >0.05 + 0.01 = <span id=\"add\"></span></p>\n <p >1.0 - 0.42 = <span id=\"sub\"></span></p>\n <p >4.015 * 100 = <span id=\"mul\"></span></p>\n <p >123.3 / 100 = <span id=\"div\"></span></p>\n</body> \n</html>\n\n```\n\n页面显示:\n\n```\n0.05 + 0.01 = 0.06\n1.0 - 0.42 = 0.58\n4.015 * 100 = 401.5\n123.3 / 100 = 1.233\n\n```\n\n\n\n# 参考文献:\n\n- [Java BigDecimal详解](http://blog.csdn.net/jackiehff/article/details/8582449)\n\n- [使用BigDecimal进行精确运算](http://www.cnblogs.com/chenssy/archive/2012/09/09/2677279.html)\n\n- [javascript小数相减会出现一长串的小数位数的原因(javascript的bug)](http://blog.sina.com.cn/s/blog_025270e90101a24l.html)\n\n- [Javascript 浮点运算问题分析与解决](http://madscript.com/javascript/javscript-float-number-compute-problem/)\n\n\n\n\n","source":"_posts/计算丢失精度解决方法.md","raw":"---\ntitle: 计算丢失精度解决方法\ncomment: true\ndate: 2017-11-08 14:44:05\ntags: [Java, 浮点数计算精度, Javascript, BigDecimal]\n---\n\n# Double类型计算丢失精度问题解决\n**说明**\n\n1. 本文档里使用的方法只试用于常见项目出现的浮点数据类型计算丢失精度问题\n2. 在计算时还好考虑 所用计算机语言支持的 各类型数字的最大值与最小值\n\n\n# 1. Java场景\n\n## 1.1 问题重现\n\n``` java\nSystem.out.println(\"0.05 + 0.01 = \" + (0.05 + 0.01)); 输出:0.060000000000000005\n\nSystem.out.println(\"1.0 - 0.42 = \" + (1.0 - 0.42)); 输出:0.5800000000000001\n\nSystem.out.println(\"4.015 * 100 = \" + (4.015 * 100)); 输出:401.49999999999994\n\nSystem.out.println(\"123.3 / 100 = \" + (123.3 / 100)); 输出:1.2329999999999999\n```\n## 1.2 解决思路\n\n1. 需要调用java.math.BigDecimal 类\n2. 把double类型转换为BigDecimal 类型 \n `BigDecimal bigDecimal = new BigDecimal(Double.toString());`\n3. 通过BigDecimal中的加、减、乘、除 的方法进行计算\n\n ```\n bigDecimal1.add(bigDecimal2) //加\n bigDecimal1.subtract(bigDecimal2) //减\n bigDecimal1.multiply(bigDecimal2) //乘\n bigDecimal1.divide(bigDecimal2) //除\n ```\n\n \n\n\n## 1.3 封装相关方法\n\n``` java\n//加\npublic Double add(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.add(b2)).doubleValue();\n}\n//减\npublic Double sub(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.subtract(b2)).doubleValue();\n}\n//乘\npublic Double mul(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.multiply(b2)).doubleValue();\n}\n//除\npublic Double div(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.divide(b2)).doubleValue();\n}\n\n```\n\n## 1.4 测试\n\n``` java\nSystem.out.println(\"0.05 + 0.01 = \" + BigDecimalUtil.add(0.05, 0.01)); 输出:0.06\nSystem.out.println(\"1.0 - 0.42 = \" + BigDecimalUtil.sub(1.0, 0.42)); 输出:0.58\nSystem.out.println(\"4.015 * 100 = \" + BigDecimalUtil.mul(4.015 ,100.00)); 输出:401.5\nSystem.out.println(\"123.3 / 100 = \" + BigDecimalUtil.div(123.3, 100.00)); 输出:41.07\n```\n\n### 1.4.1 异常处理\n\n如果除不尽会报下面异常\n\n``` java\nSystem.out.println(\"123.2 / 3 = \" + r.div(123.2, 3.0));\n结果:\nException in thread \"main\" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.\n at java.math.BigDecimal.divide(Unknown Source)\n\n```\n\n处理方法:四舍五入保留两位小数\n\n``` java\n //除法改造四舍五入,保留2位小数\npublic Double div2(Double v1,Double v2){\n BigDecimal b1 = new BigDecimal(v1.toString());\n BigDecimal b2 = new BigDecimal(v2.toString());\n return (b1.divide(b2,2,BigDecimal.ROUND_HALF_UP)).doubleValue();//四舍五入,保留2位小数\n }\n\n```\n\n测试结果:\n\n``` java\nSystem.out.println(\"123.2 / 3 = \" + BigDecimalUtil .div2(123.2, 3.0)); 输出:41.07\n```\n\n# 2. 数据库场景\n\n## 2.1 问题重现\n\n表结构(表明doubleTab):\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A61.png)\n\n表数据:\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A62.png)\n\n问题展示:\n\n1. 查询sql:\n\n``` mysql\n\nSELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result \nfrom doubleTab d WHERE d.id = 1\nUNION\nSELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result \nfrom doubleTab d WHERE d.id = 2\nUNION\nSELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result \nfrom doubleTab d WHERE d.id = 3\nUNION\nSELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result \nfrom doubleTab d WHERE d.id = 4\n\n```\n\n2. 结果:\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A63.png)\n\n## 2.2 解决思路\n\n用decimal 类型替换表结构中的 double类型\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A64.png)\n\n## 2.3 结果展示\n\n1. 查询sql\n\n``` mysql\nSELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result \nfrom doubleTab d WHERE d.id = 1\nUNION\nSELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result \nfrom doubleTab d WHERE d.id = 2\nUNION\nSELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result \nfrom doubleTab d WHERE d.id = 3\nUNION\nSELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result \nfrom doubleTab d WHERE d.id = 4\n\n```\n\n2. 结果\n\n![浮点数精度1](http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A65.png)\n\n\n\n# 3. Javascript场景\n\n## 3.1 问题重现\n\n页面代码:\n\n``` html\n<!DOCTYPE HTML> \n<html> \n<head> \n<script src=\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"></script>;\n<script>\n$(function(){\n $('#add').text(0.05 + 0.01)\n $('#sub').text(1.0 - 0.42)\n $('#mul').text(4.015 * 100)\n $('#div').text(123.3 / 100)\n})\n</script>\n</head> \n<body>\n <p >0.05 + 0.01 = <span id=\"add\"></span></p>\n <p >1.0 - 0.42 = <span id=\"sub\"></span></p>\n <p >4.015 * 100 = <span id=\"mul\"></span></p>\n <p >123.3 / 100 = <span id=\"div\"></span></p>\n</body> \n</html>\n\n```\n\n页面显示:\n\n``` \n0.05 + 0.01 = 0.060000000000000005\n1.0 - 0.42 = 0.5800000000000001\n4.015 * 100 = 401.49999999999994\n123.3 / 100 = 1.2329999999999999\n```\n\n## 3.2 解决思路\n\n1. 对于乘法与除法\n\n 算出两个参数一共有几位小数,把两个参数的小数点去掉进行 乘法或除法运算 结果再除以10的参数小数点后面位数和次幂\n\n2. 对于加法与减法\n\n 算出两个参数一共有几位小数,把两个参数分别用写好的乘法运算 乘以10的参数小数点后面位数和次幂,然后在把两个参数进行激发或减法运算,结果再除以10的参数小数点后面位数和次幂\n\n``` javascript\n//加法\nfunction add(arg1, arg2) {\n var m = 0,s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n \n return (arg1 + arg2) / Math.pow(10, m);\n}\n//减法\nfunction sub(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n return (arg1 - arg2) / Math.pow(10, m);\n}\n//乘法\nfunction mul(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) * Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n//除法\nfunction div(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) /Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n\n```\n\n## 3.3 结果展示\n\n``` html\n<!DOCTYPE HTML> \n<html> \n<head> \n<script src=\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"></script>;\n<script>\n$(function(){\n $('#add').text(add(0.05,0.01))\n $('#sub').text(sub(1.0,0.42))\n $('#mul').text(mul(4.015 ,100))\n $('#div').text(div(123.3,100))\n})\n//加法\nfunction add(arg1, arg2) {\n var m = 0,s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n \n return (arg1 + arg2) / Math.pow(10, m);\n}\n//减法\nfunction sub(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n \n arg1 = mul(arg1,Math.pow(10, m))\n arg2 = mul(arg2,Math.pow(10, m))\n return (arg1 - arg2) / Math.pow(10, m);\n}\n//乘法\nfunction mul(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) * Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n//除法\nfunction div(arg1, arg2) {\n var m = 0, s1 = arg1.toString(), s2 = arg2.toString();\n try {\n m += s1.split(\".\")[1].length;\n }\n catch (e) {\n }\n try {\n m += s2.split(\".\")[1].length;\n }\n catch (e) {\n }\n return Number(s1.replace(\".\", \"\")) /Number(s2.replace(\".\", \"\")) / Math.pow(10, m);\n}\n</script>\n</head> \n<body>\n <p >0.05 + 0.01 = <span id=\"add\"></span></p>\n <p >1.0 - 0.42 = <span id=\"sub\"></span></p>\n <p >4.015 * 100 = <span id=\"mul\"></span></p>\n <p >123.3 / 100 = <span id=\"div\"></span></p>\n</body> \n</html>\n\n```\n\n页面显示:\n\n```\n0.05 + 0.01 = 0.06\n1.0 - 0.42 = 0.58\n4.015 * 100 = 401.5\n123.3 / 100 = 1.233\n\n```\n\n\n\n# 参考文献:\n\n- [Java BigDecimal详解](http://blog.csdn.net/jackiehff/article/details/8582449)\n\n- [使用BigDecimal进行精确运算](http://www.cnblogs.com/chenssy/archive/2012/09/09/2677279.html)\n\n- [javascript小数相减会出现一长串的小数位数的原因(javascript的bug)](http://blog.sina.com.cn/s/blog_025270e90101a24l.html)\n\n- [Javascript 浮点运算问题分析与解决](http://madscript.com/javascript/javscript-float-number-compute-problem/)\n\n\n\n\n","slug":"计算丢失精度解决方法","published":1,"updated":"2017-12-11T02:59:13.992Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cjemy9k7h000twsv7xkej1zzf","content":"<h1 id=\"Double类型计算丢失精度问题解决\"><a href=\"#Double类型计算丢失精度问题解决\" class=\"headerlink\" title=\"Double类型计算丢失精度问题解决\"></a>Double类型计算丢失精度问题解决</h1><p><strong>说明</strong></p>\n<ol>\n<li>本文档里使用的方法只试用于常见项目出现的浮点数据类型计算丢失精度问题</li>\n<li>在计算时还好考虑 所用计算机语言支持的 各类型数字的最大值与最小值</li>\n</ol>\n<h1 id=\"1-Java场景\"><a href=\"#1-Java场景\" class=\"headerlink\" title=\"1. Java场景\"></a>1. Java场景</h1><h2 id=\"1-1-问题重现\"><a href=\"#1-1-问题重现\" class=\"headerlink\" title=\"1.1 问题重现\"></a>1.1 问题重现</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"0.05 + 0.01 = \"</span> + (<span class=\"number\">0.05</span> + <span class=\"number\">0.01</span>)); 输出:<span class=\"number\">0.060000000000000005</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"1.0 - 0.42 = \"</span> + (<span class=\"number\">1.0</span> - <span class=\"number\">0.42</span>)); 输出:<span class=\"number\">0.5800000000000001</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"4.015 * 100 = \"</span> + (<span class=\"number\">4.015</span> * <span class=\"number\">100</span>)); 输出:<span class=\"number\">401.49999999999994</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"123.3 / 100 = \"</span> + (<span class=\"number\">123.3</span> / <span class=\"number\">100</span>)); 输出:<span class=\"number\">1.2329999999999999</span></div></pre></td></tr></table></figure>\n<h2 id=\"1-2-解决思路\"><a href=\"#1-2-解决思路\" class=\"headerlink\" title=\"1.2 解决思路\"></a>1.2 解决思路</h2><ol>\n<li>需要调用java.math.BigDecimal 类</li>\n<li>把double类型转换为BigDecimal 类型<br><code>BigDecimal bigDecimal = new BigDecimal(Double.toString());</code></li>\n<li><p>通过BigDecimal中的加、减、乘、除 的方法进行计算</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">bigDecimal1.add(bigDecimal2) //加</div><div class=\"line\">bigDecimal1.subtract(bigDecimal2) //减</div><div class=\"line\">bigDecimal1.multiply(bigDecimal2) //乘</div><div class=\"line\">bigDecimal1.divide(bigDecimal2) //除</div></pre></td></tr></table></figure>\n<p></p>\n</li>\n</ol>\n<h2 id=\"1-3-封装相关方法\"><a href=\"#1-3-封装相关方法\" class=\"headerlink\" title=\"1.3 封装相关方法\"></a>1.3 封装相关方法</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">//加</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">add</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.add(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">sub</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.subtract(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">mul</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.multiply(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">div</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.divide(b2)).doubleValue();</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"1-4-测试\"><a href=\"#1-4-测试\" class=\"headerlink\" title=\"1.4 测试\"></a>1.4 测试</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"0.05 + 0.01 = \"</span> + BigDecimalUtil.add(<span class=\"number\">0.05</span>, <span class=\"number\">0.01</span>)); 输出:<span class=\"number\">0.06</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"1.0 - 0.42 = \"</span> + BigDecimalUtil.sub(<span class=\"number\">1.0</span>, <span class=\"number\">0.42</span>)); 输出:<span class=\"number\">0.58</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"4.015 * 100 = \"</span> + BigDecimalUtil.mul(<span class=\"number\">4.015</span> ,<span class=\"number\">100.00</span>)); 输出:<span class=\"number\">401.5</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"123.3 / 100 = \"</span> + BigDecimalUtil.div(<span class=\"number\">123.3</span>, <span class=\"number\">100.00</span>)); 输出:<span class=\"number\">41.07</span></div></pre></td></tr></table></figure>\n<h3 id=\"1-4-1-异常处理\"><a href=\"#1-4-1-异常处理\" class=\"headerlink\" title=\"1.4.1 异常处理\"></a>1.4.1 异常处理</h3><p>如果除不尽会报下面异常</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"123.2 / 3 = \"</span> + r.div(<span class=\"number\">123.2</span>, <span class=\"number\">3.0</span>));</div><div class=\"line\">结果:</div><div class=\"line\">Exception in thread <span class=\"string\">\"main\"</span> java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.</div><div class=\"line\"> at java.math.BigDecimal.divide(Unknown Source)</div></pre></td></tr></table></figure>\n<p>处理方法:四舍五入保留两位小数</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"> <span class=\"comment\">//除法改造四舍五入,保留2位小数</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">div2</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.divide(b2,<span class=\"number\">2</span>,BigDecimal.ROUND_HALF_UP)).doubleValue();<span class=\"comment\">//四舍五入,保留2位小数</span></div><div class=\"line\"> }</div></pre></td></tr></table></figure>\n<p>测试结果:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"123.2 / 3 = \"</span> + BigDecimalUtil .div2(<span class=\"number\">123.2</span>, <span class=\"number\">3.0</span>)); 输出:<span class=\"number\">41.07</span></div></pre></td></tr></table></figure>\n<h1 id=\"2-数据库场景\"><a href=\"#2-数据库场景\" class=\"headerlink\" title=\"2. 数据库场景\"></a>2. 数据库场景</h1><h2 id=\"2-1-问题重现\"><a href=\"#2-1-问题重现\" class=\"headerlink\" title=\"2.1 问题重现\"></a>2.1 问题重现</h2><p>表结构(表明doubleTab):</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A61.png\" alt=\"浮点数精度1\"></p>\n<p>表数据:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A62.png\" alt=\"浮点数精度1\"></p>\n<p>问题展示:</p>\n<ol>\n<li>查询sql:</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"></div><div class=\"line\">SELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 1</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 2</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 3</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 4</div></pre></td></tr></table></figure>\n<ol>\n<li>结果:</li>\n</ol>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A63.png\" alt=\"浮点数精度1\"></p>\n<h2 id=\"2-2-解决思路\"><a href=\"#2-2-解决思路\" class=\"headerlink\" title=\"2.2 解决思路\"></a>2.2 解决思路</h2><p>用decimal 类型替换表结构中的 double类型</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A64.png\" alt=\"浮点数精度1\"></p>\n<h2 id=\"2-3-结果展示\"><a href=\"#2-3-结果展示\" class=\"headerlink\" title=\"2.3 结果展示\"></a>2.3 结果展示</h2><ol>\n<li>查询sql</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">SELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 1</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 2</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 3</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 4</div></pre></td></tr></table></figure>\n<ol>\n<li>结果</li>\n</ol>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A65.png\" alt=\"浮点数精度1\"></p>\n<h1 id=\"3-Javascript场景\"><a href=\"#3-Javascript场景\" class=\"headerlink\" title=\"3. Javascript场景\"></a>3. Javascript场景</h1><h2 id=\"3-1-问题重现\"><a href=\"#3-1-问题重现\" class=\"headerlink\" title=\"3.1 问题重现\"></a>3.1 问题重现</h2><p>页面代码:</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><!DOCTYPE HTML></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span> <span class=\"attr\">src</span>=<span class=\"string\">\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"</span>></span><span class=\"undefined\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span>;</div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></span></div><div class=\"line\">$(<span class=\"function\"><span class=\"keyword\">function</span>(<span class=\"params\"></span>)</span>{</div><div class=\"line\"> $(<span class=\"string\">'#add'</span>).text(<span class=\"number\">0.05</span> + <span class=\"number\">0.01</span>)</div><div class=\"line\"> $(<span class=\"string\">'#sub'</span>).text(<span class=\"number\">1.0</span> - <span class=\"number\">0.42</span>)</div><div class=\"line\"> $(<span class=\"string\">'#mul'</span>).text(<span class=\"number\">4.015</span> * <span class=\"number\">100</span>)</div><div class=\"line\"> $(<span class=\"string\">'#div'</span>).text(<span class=\"number\">123.3</span> / <span class=\"number\">100</span>)</div><div class=\"line\">})</div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>0.05 + 0.01 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"add\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>1.0 - 0.42 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"sub\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>4.015 * 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"mul\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>123.3 / 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"div\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span> </div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>页面显示:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">0.05 + 0.01 = 0.060000000000000005</div><div class=\"line\">1.0 - 0.42 = 0.5800000000000001</div><div class=\"line\">4.015 * 100 = 401.49999999999994</div><div class=\"line\">123.3 / 100 = 1.2329999999999999</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-解决思路\"><a href=\"#3-2-解决思路\" class=\"headerlink\" title=\"3.2 解决思路\"></a>3.2 解决思路</h2><ol>\n<li><p>对于乘法与除法</p>\n<p>算出两个参数一共有几位小数,把两个参数的小数点去掉进行 乘法或除法运算 结果再除以10的参数小数点后面位数和次幂</p>\n</li>\n<li><p>对于加法与减法</p>\n<p>算出两个参数一共有几位小数,把两个参数分别用写好的乘法运算 乘以10的参数小数点后面位数和次幂,然后在把两个参数进行激发或减法运算,结果再除以10的参数小数点后面位数和次幂</p>\n</li>\n</ol>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">//加法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">add</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>,s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 + arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">sub</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 - arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">mul</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) * <span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">div</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) /<span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"3-3-结果展示\"><a href=\"#3-3-结果展示\" class=\"headerlink\" title=\"3.3 结果展示\"></a>3.3 结果展示</h2><figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><!DOCTYPE HTML></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span> <span class=\"attr\">src</span>=<span class=\"string\">\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"</span>></span><span class=\"undefined\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span>;</div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></span></div><div class=\"line\">$(<span class=\"function\"><span class=\"keyword\">function</span>(<span class=\"params\"></span>)</span>{</div><div class=\"line\"> $(<span class=\"string\">'#add'</span>).text(add(<span class=\"number\">0.05</span>,<span class=\"number\">0.01</span>))</div><div class=\"line\"> $(<span class=\"string\">'#sub'</span>).text(sub(<span class=\"number\">1.0</span>,<span class=\"number\">0.42</span>))</div><div class=\"line\"> $(<span class=\"string\">'#mul'</span>).text(mul(<span class=\"number\">4.015</span> ,<span class=\"number\">100</span>))</div><div class=\"line\"> $(<span class=\"string\">'#div'</span>).text(div(<span class=\"number\">123.3</span>,<span class=\"number\">100</span>))</div><div class=\"line\">})</div><div class=\"line\"><span class=\"comment\">//加法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">add</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>,s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 + arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">sub</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 - arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">mul</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) * <span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">div</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) /<span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>0.05 + 0.01 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"add\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>1.0 - 0.42 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"sub\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>4.015 * 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"mul\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>123.3 / 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"div\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span> </div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>页面显示:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">0.05 + 0.01 = 0.06</div><div class=\"line\">1.0 - 0.42 = 0.58</div><div class=\"line\">4.015 * 100 = 401.5</div><div class=\"line\">123.3 / 100 = 1.233</div></pre></td></tr></table></figure>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><p><a href=\"http://blog.csdn.net/jackiehff/article/details/8582449\" target=\"_blank\" rel=\"external\">Java BigDecimal详解</a></p>\n</li>\n<li><p><a href=\"http://www.cnblogs.com/chenssy/archive/2012/09/09/2677279.html\" target=\"_blank\" rel=\"external\">使用BigDecimal进行精确运算</a></p>\n</li>\n<li><p><a href=\"http://blog.sina.com.cn/s/blog_025270e90101a24l.html\" target=\"_blank\" rel=\"external\">javascript小数相减会出现一长串的小数位数的原因(javascript的bug)</a></p>\n</li>\n<li><p><a href=\"http://madscript.com/javascript/javscript-float-number-compute-problem/\" target=\"_blank\" rel=\"external\">Javascript 浮点运算问题分析与解决</a></p>\n</li>\n</ul>\n","excerpt":"","more":"<h1 id=\"Double类型计算丢失精度问题解决\"><a href=\"#Double类型计算丢失精度问题解决\" class=\"headerlink\" title=\"Double类型计算丢失精度问题解决\"></a>Double类型计算丢失精度问题解决</h1><p><strong>说明</strong></p>\n<ol>\n<li>本文档里使用的方法只试用于常见项目出现的浮点数据类型计算丢失精度问题</li>\n<li>在计算时还好考虑 所用计算机语言支持的 各类型数字的最大值与最小值</li>\n</ol>\n<h1 id=\"1-Java场景\"><a href=\"#1-Java场景\" class=\"headerlink\" title=\"1. Java场景\"></a>1. Java场景</h1><h2 id=\"1-1-问题重现\"><a href=\"#1-1-问题重现\" class=\"headerlink\" title=\"1.1 问题重现\"></a>1.1 问题重现</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"0.05 + 0.01 = \"</span> + (<span class=\"number\">0.05</span> + <span class=\"number\">0.01</span>)); 输出:<span class=\"number\">0.060000000000000005</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"1.0 - 0.42 = \"</span> + (<span class=\"number\">1.0</span> - <span class=\"number\">0.42</span>)); 输出:<span class=\"number\">0.5800000000000001</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"4.015 * 100 = \"</span> + (<span class=\"number\">4.015</span> * <span class=\"number\">100</span>)); 输出:<span class=\"number\">401.49999999999994</span></div><div class=\"line\"></div><div class=\"line\">System.out.println(<span class=\"string\">\"123.3 / 100 = \"</span> + (<span class=\"number\">123.3</span> / <span class=\"number\">100</span>)); 输出:<span class=\"number\">1.2329999999999999</span></div></pre></td></tr></table></figure>\n<h2 id=\"1-2-解决思路\"><a href=\"#1-2-解决思路\" class=\"headerlink\" title=\"1.2 解决思路\"></a>1.2 解决思路</h2><ol>\n<li>需要调用java.math.BigDecimal 类</li>\n<li>把double类型转换为BigDecimal 类型<br><code>BigDecimal bigDecimal = new BigDecimal(Double.toString());</code></li>\n<li><p>通过BigDecimal中的加、减、乘、除 的方法进行计算</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">bigDecimal1.add(bigDecimal2) //加</div><div class=\"line\">bigDecimal1.subtract(bigDecimal2) //减</div><div class=\"line\">bigDecimal1.multiply(bigDecimal2) //乘</div><div class=\"line\">bigDecimal1.divide(bigDecimal2) //除</div></pre></td></tr></table></figure>\n<p></p>\n</li>\n</ol>\n<h2 id=\"1-3-封装相关方法\"><a href=\"#1-3-封装相关方法\" class=\"headerlink\" title=\"1.3 封装相关方法\"></a>1.3 封装相关方法</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">//加</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">add</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.add(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">sub</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.subtract(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">mul</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.multiply(b2)).doubleValue();</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">div</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.divide(b2)).doubleValue();</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"1-4-测试\"><a href=\"#1-4-测试\" class=\"headerlink\" title=\"1.4 测试\"></a>1.4 测试</h2><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"0.05 + 0.01 = \"</span> + BigDecimalUtil.add(<span class=\"number\">0.05</span>, <span class=\"number\">0.01</span>)); 输出:<span class=\"number\">0.06</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"1.0 - 0.42 = \"</span> + BigDecimalUtil.sub(<span class=\"number\">1.0</span>, <span class=\"number\">0.42</span>)); 输出:<span class=\"number\">0.58</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"4.015 * 100 = \"</span> + BigDecimalUtil.mul(<span class=\"number\">4.015</span> ,<span class=\"number\">100.00</span>)); 输出:<span class=\"number\">401.5</span></div><div class=\"line\">System.out.println(<span class=\"string\">\"123.3 / 100 = \"</span> + BigDecimalUtil.div(<span class=\"number\">123.3</span>, <span class=\"number\">100.00</span>)); 输出:<span class=\"number\">41.07</span></div></pre></td></tr></table></figure>\n<h3 id=\"1-4-1-异常处理\"><a href=\"#1-4-1-异常处理\" class=\"headerlink\" title=\"1.4.1 异常处理\"></a>1.4.1 异常处理</h3><p>如果除不尽会报下面异常</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"123.2 / 3 = \"</span> + r.div(<span class=\"number\">123.2</span>, <span class=\"number\">3.0</span>));</div><div class=\"line\">结果:</div><div class=\"line\">Exception in thread <span class=\"string\">\"main\"</span> java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.</div><div class=\"line\"> at java.math.BigDecimal.divide(Unknown Source)</div></pre></td></tr></table></figure>\n<p>处理方法:四舍五入保留两位小数</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div></pre></td><td class=\"code\"><pre><div class=\"line\"> <span class=\"comment\">//除法改造四舍五入,保留2位小数</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">public</span> Double <span class=\"title\">div2</span><span class=\"params\">(Double v1,Double v2)</span></span>{</div><div class=\"line\"> BigDecimal b1 = <span class=\"keyword\">new</span> BigDecimal(v1.toString());</div><div class=\"line\"> BigDecimal b2 = <span class=\"keyword\">new</span> BigDecimal(v2.toString());</div><div class=\"line\"> <span class=\"keyword\">return</span> (b1.divide(b2,<span class=\"number\">2</span>,BigDecimal.ROUND_HALF_UP)).doubleValue();<span class=\"comment\">//四舍五入,保留2位小数</span></div><div class=\"line\"> }</div></pre></td></tr></table></figure>\n<p>测试结果:</p>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div></pre></td><td class=\"code\"><pre><div class=\"line\">System.out.println(<span class=\"string\">\"123.2 / 3 = \"</span> + BigDecimalUtil .div2(<span class=\"number\">123.2</span>, <span class=\"number\">3.0</span>)); 输出:<span class=\"number\">41.07</span></div></pre></td></tr></table></figure>\n<h1 id=\"2-数据库场景\"><a href=\"#2-数据库场景\" class=\"headerlink\" title=\"2. 数据库场景\"></a>2. 数据库场景</h1><h2 id=\"2-1-问题重现\"><a href=\"#2-1-问题重现\" class=\"headerlink\" title=\"2.1 问题重现\"></a>2.1 问题重现</h2><p>表结构(表明doubleTab):</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A61.png\" alt=\"浮点数精度1\"></p>\n<p>表数据:</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A62.png\" alt=\"浮点数精度1\"></p>\n<p>问题展示:</p>\n<ol>\n<li>查询sql:</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div></pre></td><td class=\"code\"><pre><div class=\"line\"></div><div class=\"line\">SELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 1</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 2</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 3</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 4</div></pre></td></tr></table></figure>\n<ol>\n<li>结果:</li>\n</ol>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A63.png\" alt=\"浮点数精度1\"></p>\n<h2 id=\"2-2-解决思路\"><a href=\"#2-2-解决思路\" class=\"headerlink\" title=\"2.2 解决思路\"></a>2.2 解决思路</h2><p>用decimal 类型替换表结构中的 double类型</p>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A64.png\" alt=\"浮点数精度1\"></p>\n<h2 id=\"2-3-结果展示\"><a href=\"#2-3-结果展示\" class=\"headerlink\" title=\"2.3 结果展示\"></a>2.3 结果展示</h2><ol>\n<li>查询sql</li>\n</ol>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div></pre></td><td class=\"code\"><pre><div class=\"line\">SELECT double1,'加' as arithmetic,double2,(d.double1 + d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 1</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'减' as arithmetic,double2,(d.double1 - d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 2</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'乘' as arithmetic,double2,(d.double1 * d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 3</div><div class=\"line\">UNION</div><div class=\"line\">SELECT double1,'除' as arithmetic,double2,(d.double1 / d.double2) as result </div><div class=\"line\">from doubleTab d WHERE d.id = 4</div></pre></td></tr></table></figure>\n<ol>\n<li>结果</li>\n</ol>\n<p><img src=\"http://ortur5wom.bkt.clouddn.com/image/GithubBlog/%E6%B5%AE%E7%82%B9%E6%95%B0%E7%B2%BE%E5%BA%A65.png\" alt=\"浮点数精度1\"></p>\n<h1 id=\"3-Javascript场景\"><a href=\"#3-Javascript场景\" class=\"headerlink\" title=\"3. Javascript场景\"></a>3. Javascript场景</h1><h2 id=\"3-1-问题重现\"><a href=\"#3-1-问题重现\" class=\"headerlink\" title=\"3.1 问题重现\"></a>3.1 问题重现</h2><p>页面代码:</p>\n<figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><!DOCTYPE HTML></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span> <span class=\"attr\">src</span>=<span class=\"string\">\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"</span>></span><span class=\"undefined\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span>;</div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></div><div class=\"line\">$(<span class=\"function\"><span class=\"keyword\">function</span>(<span class=\"params\"></span>)</span>{</div><div class=\"line\"> $(<span class=\"string\">'#add'</span>).text(<span class=\"number\">0.05</span> + <span class=\"number\">0.01</span>)</div><div class=\"line\"> $(<span class=\"string\">'#sub'</span>).text(<span class=\"number\">1.0</span> - <span class=\"number\">0.42</span>)</div><div class=\"line\"> $(<span class=\"string\">'#mul'</span>).text(<span class=\"number\">4.015</span> * <span class=\"number\">100</span>)</div><div class=\"line\"> $(<span class=\"string\">'#div'</span>).text(<span class=\"number\">123.3</span> / <span class=\"number\">100</span>)</div><div class=\"line\">})</div><div class=\"line\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>0.05 + 0.01 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"add\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>1.0 - 0.42 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"sub\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>4.015 * 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"mul\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>123.3 / 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"div\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span> </div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>页面显示:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">0.05 + 0.01 = 0.060000000000000005</div><div class=\"line\">1.0 - 0.42 = 0.5800000000000001</div><div class=\"line\">4.015 * 100 = 401.49999999999994</div><div class=\"line\">123.3 / 100 = 1.2329999999999999</div></pre></td></tr></table></figure>\n<h2 id=\"3-2-解决思路\"><a href=\"#3-2-解决思路\" class=\"headerlink\" title=\"3.2 解决思路\"></a>3.2 解决思路</h2><ol>\n<li><p>对于乘法与除法</p>\n<p>算出两个参数一共有几位小数,把两个参数的小数点去掉进行 乘法或除法运算 结果再除以10的参数小数点后面位数和次幂</p>\n</li>\n<li><p>对于加法与减法</p>\n<p>算出两个参数一共有几位小数,把两个参数分别用写好的乘法运算 乘以10的参数小数点后面位数和次幂,然后在把两个参数进行激发或减法运算,结果再除以10的参数小数点后面位数和次幂</p>\n</li>\n</ol>\n<figure class=\"highlight javascript\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"comment\">//加法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">add</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>,s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 + arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">sub</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 - arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">mul</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) * <span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">div</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) /<span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div></pre></td></tr></table></figure>\n<h2 id=\"3-3-结果展示\"><a href=\"#3-3-结果展示\" class=\"headerlink\" title=\"3.3 结果展示\"></a>3.3 结果展示</h2><figure class=\"highlight html\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div><div class=\"line\">5</div><div class=\"line\">6</div><div class=\"line\">7</div><div class=\"line\">8</div><div class=\"line\">9</div><div class=\"line\">10</div><div class=\"line\">11</div><div class=\"line\">12</div><div class=\"line\">13</div><div class=\"line\">14</div><div class=\"line\">15</div><div class=\"line\">16</div><div class=\"line\">17</div><div class=\"line\">18</div><div class=\"line\">19</div><div class=\"line\">20</div><div class=\"line\">21</div><div class=\"line\">22</div><div class=\"line\">23</div><div class=\"line\">24</div><div class=\"line\">25</div><div class=\"line\">26</div><div class=\"line\">27</div><div class=\"line\">28</div><div class=\"line\">29</div><div class=\"line\">30</div><div class=\"line\">31</div><div class=\"line\">32</div><div class=\"line\">33</div><div class=\"line\">34</div><div class=\"line\">35</div><div class=\"line\">36</div><div class=\"line\">37</div><div class=\"line\">38</div><div class=\"line\">39</div><div class=\"line\">40</div><div class=\"line\">41</div><div class=\"line\">42</div><div class=\"line\">43</div><div class=\"line\">44</div><div class=\"line\">45</div><div class=\"line\">46</div><div class=\"line\">47</div><div class=\"line\">48</div><div class=\"line\">49</div><div class=\"line\">50</div><div class=\"line\">51</div><div class=\"line\">52</div><div class=\"line\">53</div><div class=\"line\">54</div><div class=\"line\">55</div><div class=\"line\">56</div><div class=\"line\">57</div><div class=\"line\">58</div><div class=\"line\">59</div><div class=\"line\">60</div><div class=\"line\">61</div><div class=\"line\">62</div><div class=\"line\">63</div><div class=\"line\">64</div><div class=\"line\">65</div><div class=\"line\">66</div><div class=\"line\">67</div><div class=\"line\">68</div><div class=\"line\">69</div><div class=\"line\">70</div><div class=\"line\">71</div><div class=\"line\">72</div><div class=\"line\">73</div><div class=\"line\">74</div><div class=\"line\">75</div><div class=\"line\">76</div><div class=\"line\">77</div><div class=\"line\">78</div><div class=\"line\">79</div><div class=\"line\">80</div><div class=\"line\">81</div><div class=\"line\">82</div><div class=\"line\">83</div><div class=\"line\">84</div><div class=\"line\">85</div><div class=\"line\">86</div><div class=\"line\">87</div></pre></td><td class=\"code\"><pre><div class=\"line\"><span class=\"meta\"><!DOCTYPE HTML></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">html</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span> <span class=\"attr\">src</span>=<span class=\"string\">\"http://cdn.static.runoob.com/libs/jquery/2.0.0/jquery.min.js\"</span>></span><span class=\"undefined\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span>;</div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">script</span>></span><span class=\"javascript\"></div><div class=\"line\">$(<span class=\"function\"><span class=\"keyword\">function</span>(<span class=\"params\"></span>)</span>{</div><div class=\"line\"> $(<span class=\"string\">'#add'</span>).text(add(<span class=\"number\">0.05</span>,<span class=\"number\">0.01</span>))</div><div class=\"line\"> $(<span class=\"string\">'#sub'</span>).text(sub(<span class=\"number\">1.0</span>,<span class=\"number\">0.42</span>))</div><div class=\"line\"> $(<span class=\"string\">'#mul'</span>).text(mul(<span class=\"number\">4.015</span> ,<span class=\"number\">100</span>))</div><div class=\"line\"> $(<span class=\"string\">'#div'</span>).text(div(<span class=\"number\">123.3</span>,<span class=\"number\">100</span>))</div><div class=\"line\">})</div><div class=\"line\"><span class=\"comment\">//加法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">add</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>,s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> </div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 + arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//减法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">sub</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> </div><div class=\"line\"> arg1 = mul(arg1,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> arg2 = mul(arg2,<span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m))</div><div class=\"line\"> <span class=\"keyword\">return</span> (arg1 - arg2) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//乘法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">mul</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) * <span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"><span class=\"comment\">//除法</span></div><div class=\"line\"><span class=\"function\"><span class=\"keyword\">function</span> <span class=\"title\">div</span>(<span class=\"params\">arg1, arg2</span>) </span>{</div><div class=\"line\"> <span class=\"keyword\">var</span> m = <span class=\"number\">0</span>, s1 = arg1.toString(), s2 = arg2.toString();</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s1.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">try</span> {</div><div class=\"line\"> m += s2.split(<span class=\"string\">\".\"</span>)[<span class=\"number\">1</span>].length;</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">catch</span> (e) {</div><div class=\"line\"> }</div><div class=\"line\"> <span class=\"keyword\">return</span> <span class=\"built_in\">Number</span>(s1.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) /<span class=\"built_in\">Number</span>(s2.replace(<span class=\"string\">\".\"</span>, <span class=\"string\">\"\"</span>)) / <span class=\"built_in\">Math</span>.pow(<span class=\"number\">10</span>, m);</div><div class=\"line\">}</div><div class=\"line\"></span><span class=\"tag\"></<span class=\"name\">script</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">head</span>></span> </div><div class=\"line\"><span class=\"tag\"><<span class=\"name\">body</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>0.05 + 0.01 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"add\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>1.0 - 0.42 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"sub\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>4.015 * 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"mul\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"> <span class=\"tag\"><<span class=\"name\">p</span> ></span>123.3 / 100 = <span class=\"tag\"><<span class=\"name\">span</span> <span class=\"attr\">id</span>=<span class=\"string\">\"div\"</span>></span><span class=\"tag\"></<span class=\"name\">span</span>></span><span class=\"tag\"></<span class=\"name\">p</span>></span></div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">body</span>></span> </div><div class=\"line\"><span class=\"tag\"></<span class=\"name\">html</span>></span></div></pre></td></tr></table></figure>\n<p>页面显示:</p>\n<figure class=\"highlight plain\"><table><tr><td class=\"gutter\"><pre><div class=\"line\">1</div><div class=\"line\">2</div><div class=\"line\">3</div><div class=\"line\">4</div></pre></td><td class=\"code\"><pre><div class=\"line\">0.05 + 0.01 = 0.06</div><div class=\"line\">1.0 - 0.42 = 0.58</div><div class=\"line\">4.015 * 100 = 401.5</div><div class=\"line\">123.3 / 100 = 1.233</div></pre></td></tr></table></figure>\n<h1 id=\"参考文献:\"><a href=\"#参考文献:\" class=\"headerlink\" title=\"参考文献:\"></a>参考文献:</h1><ul>\n<li><p><a href=\"http://blog.csdn.net/jackiehff/article/details/8582449\">Java BigDecimal详解</a></p>\n</li>\n<li><p><a href=\"http://www.cnblogs.com/chenssy/archive/2012/09/09/2677279.html\">使用BigDecimal进行精确运算</a></p>\n</li>\n<li><p><a href=\"http://blog.sina.com.cn/s/blog_025270e90101a24l.html\">javascript小数相减会出现一长串的小数位数的原因(javascript的bug)</a></p>\n</li>\n<li><p><a href=\"http://madscript.com/javascript/javscript-float-number-compute-problem/\">Javascript 浮点运算问题分析与解决</a></p>\n</li>\n</ul>\n"}],"PostAsset":[],"PostCategory":[],"PostTag":[{"post_id":"cjemy9k5b0001wsv7kz6b5og5","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k72000jwsv7zktgly1f"},{"post_id":"cjemy9k5b0001wsv7kz6b5og5","tag_id":"cjemy9k6m000bwsv7ob15igs4","_id":"cjemy9k72000lwsv7i76k840q"},{"post_id":"cjemy9k5b0001wsv7kz6b5og5","tag_id":"cjemy9k6m000ewsv75u372vi5","_id":"cjemy9k72000owsv7dl93ind1"},{"post_id":"cjemy9k5r0003wsv7bodrzlux","tag_id":"cjemy9k72000hwsv7qj7uqo22","_id":"cjemy9k7h000swsv749w2p6km"},{"post_id":"cjemy9k5r0003wsv7bodrzlux","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k7h000uwsv7i5uf72do"},{"post_id":"cjemy9k660006wsv7a6kh9wrx","tag_id":"cjemy9k7h000qwsv7jqz3r4vh","_id":"cjemy9k7h0010wsv7nw4b5ufv"},{"post_id":"cjemy9k660006wsv7a6kh9wrx","tag_id":"cjemy9k7h000vwsv7823qzzzj","_id":"cjemy9k7h0011wsv7ti2rs0vf"},{"post_id":"cjemy9k660006wsv7a6kh9wrx","tag_id":"cjemy9k7h000wwsv76e0kbmx6","_id":"cjemy9k7h0013wsv71m0xq7nf"},{"post_id":"cjemy9k660006wsv7a6kh9wrx","tag_id":"cjemy9k7h000xwsv7868uopoq","_id":"cjemy9k7h0014wsv7kdedcxoq"},{"post_id":"cjemy9k660006wsv7a6kh9wrx","tag_id":"cjemy9k7h000ywsv74ieoye21","_id":"cjemy9k7h0016wsv7ulgz0x5s"},{"post_id":"cjemy9k660008wsv71oh4iqhz","tag_id":"cjemy9k7h000zwsv7ttv33pn7","_id":"cjemy9k7x0019wsv78r06kgjn"},{"post_id":"cjemy9k660008wsv71oh4iqhz","tag_id":"cjemy9k7h0012wsv7ijsct6ev","_id":"cjemy9k7x001awsv7uojq3nv1"},{"post_id":"cjemy9k660008wsv71oh4iqhz","tag_id":"cjemy9k7h0015wsv7xjoh20ay","_id":"cjemy9k7x001cwsv7kb5ncs1n"},{"post_id":"cjemy9k660008wsv71oh4iqhz","tag_id":"cjemy9k7h0017wsv7vxcbg20r","_id":"cjemy9k7x001dwsv7dat1emqj"},{"post_id":"cjemy9k6m000awsv7xccwnc3k","tag_id":"cjemy9k7x0018wsv7e6ggkn6f","_id":"cjemy9k7x001fwsv7z9yqtdaw"},{"post_id":"cjemy9k6m000awsv7xccwnc3k","tag_id":"cjemy9k7x001bwsv7op5oxkdn","_id":"cjemy9k7x001gwsv75bu16coa"},{"post_id":"cjemy9k6m000cwsv7ye77iubb","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k7x001iwsv7nstm0ne7"},{"post_id":"cjemy9k6m000cwsv7ye77iubb","tag_id":"cjemy9k7x001ewsv7r8xaek1b","_id":"cjemy9k7x001jwsv7svzyitxo"},{"post_id":"cjemy9k6m000dwsv7pm68tbzi","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k7x001mwsv77rccwqdx"},{"post_id":"cjemy9k6m000dwsv7pm68tbzi","tag_id":"cjemy9k7x001ewsv7r8xaek1b","_id":"cjemy9k7x001nwsv76hmd1q3o"},{"post_id":"cjemy9k6m000dwsv7pm68tbzi","tag_id":"cjemy9k7x001kwsv73dy1sbcx","_id":"cjemy9k7x001pwsv7lwnykkp6"},{"post_id":"cjemy9k6m000fwsv7hdzt67n2","tag_id":"cjemy9k7x001lwsv7tzyi7e3i","_id":"cjemy9k8c001swsv77j40d8m4"},{"post_id":"cjemy9k6m000fwsv7hdzt67n2","tag_id":"cjemy9k7x001owsv7lt28hvre","_id":"cjemy9k8c001twsv7u547a8w3"},{"post_id":"cjemy9k6m000fwsv7hdzt67n2","tag_id":"cjemy9k8c001qwsv78a5uj2oq","_id":"cjemy9k8c001vwsv7vmxrcafo"},{"post_id":"cjemy9k6m000gwsv7pzipgtm7","tag_id":"cjemy9k8c001rwsv72fuanhrh","_id":"cjemy9k8c001ywsv7jl83yiue"},{"post_id":"cjemy9k6m000gwsv7pzipgtm7","tag_id":"cjemy9k8c001uwsv7cw3db4o1","_id":"cjemy9k8c001zwsv71pms6rhs"},{"post_id":"cjemy9k6m000gwsv7pzipgtm7","tag_id":"cjemy9k8c001wwsv7su8jbc9p","_id":"cjemy9k8c0021wsv7wnddqlav"},{"post_id":"cjemy9k72000iwsv7g7xzdin1","tag_id":"cjemy9k7x0018wsv7e6ggkn6f","_id":"cjemy9k8c0026wsv7zwjy4840"},{"post_id":"cjemy9k72000iwsv7g7xzdin1","tag_id":"cjemy9k7x001bwsv7op5oxkdn","_id":"cjemy9k8c0027wsv7rwy1jucu"},{"post_id":"cjemy9k72000iwsv7g7xzdin1","tag_id":"cjemy9k8c0022wsv7z4y4gsso","_id":"cjemy9k8c0029wsv7spr0yo5o"},{"post_id":"cjemy9k72000iwsv7g7xzdin1","tag_id":"cjemy9k8c0023wsv7xxbygch4","_id":"cjemy9k8c002awsv7246ryzf2"},{"post_id":"cjemy9k72000iwsv7g7xzdin1","tag_id":"cjemy9k8c0024wsv75rqtobn5","_id":"cjemy9k8c002cwsv7hkl3by7s"},{"post_id":"cjemy9k72000kwsv7hnpfln3v","tag_id":"cjemy9k7x0018wsv7e6ggkn6f","_id":"cjemy9k8c002ewsv72qz3yo85"},{"post_id":"cjemy9k72000kwsv7hnpfln3v","tag_id":"cjemy9k7x001bwsv7op5oxkdn","_id":"cjemy9k8s002fwsv7a7pryt4o"},{"post_id":"cjemy9k72000kwsv7hnpfln3v","tag_id":"cjemy9k7h0012wsv7ijsct6ev","_id":"cjemy9k8s002hwsv7vkksvxl9"},{"post_id":"cjemy9k72000nwsv71ivjbcfn","tag_id":"cjemy9k8c002dwsv7as0hhwlr","_id":"cjemy9k8s002lwsv73fmpga4q"},{"post_id":"cjemy9k72000nwsv71ivjbcfn","tag_id":"cjemy9k8s002gwsv713u1uk8p","_id":"cjemy9k8s002mwsv7jche52t8"},{"post_id":"cjemy9k72000nwsv71ivjbcfn","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k8s002owsv70uoe6ctw"},{"post_id":"cjemy9k72000nwsv71ivjbcfn","tag_id":"cjemy9k8s002iwsv7kwec6v1d","_id":"cjemy9k8s002pwsv7qzqgh3s4"},{"post_id":"cjemy9k72000nwsv71ivjbcfn","tag_id":"cjemy9k8s002jwsv7lpgqk7s9","_id":"cjemy9k8s002rwsv7ihnf3sdv"},{"post_id":"cjemy9k72000pwsv7sgxve0x8","tag_id":"cjemy9k8s002kwsv7wwbepkm2","_id":"cjemy9k8s002swsv7llrzsi2i"},{"post_id":"cjemy9k72000pwsv7sgxve0x8","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k8s002uwsv7kw40vqr4"},{"post_id":"cjemy9k72000pwsv7sgxve0x8","tag_id":"cjemy9k8c001wwsv7su8jbc9p","_id":"cjemy9k8s002vwsv7rvpy5ibb"},{"post_id":"cjemy9k7h000rwsv7m7v3sf2w","tag_id":"cjemy9k8s002qwsv7az36grzi","_id":"cjemy9k98002ywsv7g1i9cm36"},{"post_id":"cjemy9k7h000rwsv7m7v3sf2w","tag_id":"cjemy9k8s002twsv7tw80hv1h","_id":"cjemy9k98002zwsv7ya8rnow8"},{"post_id":"cjemy9k7h000rwsv7m7v3sf2w","tag_id":"cjemy9k8s002wwsv7u9subjhy","_id":"cjemy9k980031wsv7w2vn99cu"},{"post_id":"cjemy9k7h000twsv7xkej1zzf","tag_id":"cjemy9k5r0005wsv7oo8rnvpy","_id":"cjemy9k980033wsv7j82llkww"},{"post_id":"cjemy9k7h000twsv7xkej1zzf","tag_id":"cjemy9k8s002xwsv75a5bscx0","_id":"cjemy9k980034wsv7ku4puz0w"},{"post_id":"cjemy9k7h000twsv7xkej1zzf","tag_id":"cjemy9k980030wsv7s24eec8e","_id":"cjemy9k980035wsv7j0820sib"},{"post_id":"cjemy9k7h000twsv7xkej1zzf","tag_id":"cjemy9k980032wsv7682j12cw","_id":"cjemy9k980036wsv7s6gte9di"}],"Tag":[{"name":"Java","_id":"cjemy9k5r0005wsv7oo8rnvpy"},{"name":"JavaWeb","_id":"cjemy9k6m000bwsv7ob15igs4"},{"name":"JsWeb","_id":"cjemy9k6m000ewsv75u372vi5"},{"name":"HttpClient","_id":"cjemy9k72000hwsv7qj7uqo22"},{"name":"jade","_id":"cjemy9k7h000qwsv7jqz3r4vh"},{"name":"模板引擎","_id":"cjemy9k7h000vwsv7823qzzzj"},{"name":"angualr","_id":"cjemy9k7h000wwsv76e0kbmx6"},{"name":"mvc","_id":"cjemy9k7h000xwsv7868uopoq"},{"name":"Nodejs","_id":"cjemy9k7h000ywsv74ieoye21"},{"name":"Git bash","_id":"cjemy9k7h000zwsv7ttv33pn7"},{"name":"Git","_id":"cjemy9k7h0012wsv7ijsct6ev"},{"name":"Scheme","_id":"cjemy9k7h0015wsv7xjoh20ay"},{"name":"Shell","_id":"cjemy9k7h0017wsv7vxcbg20r"},{"name":"Hexo","_id":"cjemy9k7x0018wsv7e6ggkn6f"},{"name":"GitHub","_id":"cjemy9k7x001bwsv7op5oxkdn"},{"name":"多线程","_id":"cjemy9k7x001ewsv7r8xaek1b"},{"name":"CountDownLatch","_id":"cjemy9k7x001kwsv73dy1sbcx"},{"name":"jsp","_id":"cjemy9k7x001lwsv7tzyi7e3i"},{"name":"session","_id":"cjemy9k7x001owsv7lt28hvre"},{"name":"el表达式","_id":"cjemy9k8c001qwsv78a5uj2oq"},{"name":"ngrok","_id":"cjemy9k8c001rwsv72fuanhrh"},{"name":"外网映射","_id":"cjemy9k8c001uwsv7cw3db4o1"},{"name":"微信开发","_id":"cjemy9k8c001wwsv7su8jbc9p"},{"name":"Canvas","_id":"cjemy9k8c0022wsv7z4y4gsso"},{"name":"Next","_id":"cjemy9k8c0023wsv7xxbygch4"},{"name":"JavaScript","_id":"cjemy9k8c0024wsv75rqtobn5"},{"name":"redis","_id":"cjemy9k8c002dwsv7as0hhwlr"},{"name":"Jedis","_id":"cjemy9k8s002gwsv713u1uk8p"},{"name":"事务","_id":"cjemy9k8s002iwsv7kwec6v1d"},{"name":"字段锁","_id":"cjemy9k8s002jwsv7lpgqk7s9"},{"name":"Servlet","_id":"cjemy9k8s002kwsv7wwbepkm2"},{"name":"mysql","_id":"cjemy9k8s002qwsv7az36grzi"},{"name":"B+树","_id":"cjemy9k8s002twsv7tw80hv1h"},{"name":"数据库索引","_id":"cjemy9k8s002wwsv7u9subjhy"},{"name":"浮点数计算精度","_id":"cjemy9k8s002xwsv75a5bscx0"},{"name":"Javascript","_id":"cjemy9k980030wsv7s24eec8e"},{"name":"BigDecimal","_id":"cjemy9k980032wsv7682j12cw"}]}}