-
Notifications
You must be signed in to change notification settings - Fork 0
/
db.json
1 lines (1 loc) · 338 KB
/
db.json
1
{"meta":{"version":1,"warehouse":"4.0.0"},"models":{"Asset":[{"_id":"source/CNAME","path":"CNAME","modified":0,"renderable":0},{"_id":"themes/Chic/source/favicon.ico","path":"favicon.ico","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/base.styl","path":"css/base.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/custom.styl","path":"css/custom.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/font.styl","path":"css/font.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/media.styl","path":"css/media.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/layout.styl","path":"css/layout.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/style.styl","path":"css/style.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/normalize.styl","path":"css/normalize.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/css/variable.styl","path":"css/variable.styl","modified":0,"renderable":1},{"_id":"themes/Chic/source/image/avatar.jpeg","path":"image/avatar.jpeg","modified":0,"renderable":1},{"_id":"themes/Chic/source/js/mathjax2.7.5.js","path":"js/mathjax2.7.5.js","modified":0,"renderable":1},{"_id":"themes/Chic/source/js/script.js","path":"js/script.js","modified":0,"renderable":1},{"_id":"themes/Chic/source/js/tocbot.min.js","path":"js/tocbot.min.js","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/lanting/lanting.TTF","path":"fonts/lanting/lanting.TTF","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/lanting/lanting.eot","path":"fonts/lanting/lanting.eot","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/lanting/lanting.otf","path":"fonts/lanting/lanting.otf","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/lanting/lanting.woff","path":"fonts/lanting/lanting.woff","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/lanting/lanting.woff2","path":"fonts/lanting/lanting.woff2","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/demo.css","path":"fonts/iconfont/demo.css","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/demo_index.html","path":"fonts/iconfont/demo_index.html","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.css","path":"fonts/iconfont/iconfont.css","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.eot","path":"fonts/iconfont/iconfont.eot","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.json","path":"fonts/iconfont/iconfont.json","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.svg","path":"fonts/iconfont/iconfont.svg","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.woff","path":"fonts/iconfont/iconfont.woff","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.ttf","path":"fonts/iconfont/iconfont.ttf","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.woff2","path":"fonts/iconfont/iconfont.woff2","modified":0,"renderable":1},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.js","path":"fonts/iconfont/iconfont.js","modified":0,"renderable":1}],"Cache":[{"_id":"source/CNAME","hash":"63ee80322b2ea44c5ccb2b16e65a4ee0f0fbc1a4","modified":1648521108685},{"_id":"source/_posts/Part01-博客页面划分.md","hash":"0b7dd2a9b5688c89c7c59c7fd2731ecd4ba84516","modified":1648521108685},{"_id":"source/_posts/Part02-MyBatis-Plus 的使用.md","hash":"c39f4ba054a7e6c2124ff8cbe0fa116f181e85c2","modified":1648521108686},{"_id":"source/_posts/Part03-Controller 控制层接口.md","hash":"2a1ff6693ed1203642a5388ce2cf6d5260a93ee4","modified":1648521108686},{"_id":"source/_posts/Part04-自定义 Freemaker 标签.md","hash":"55bb3bec32f24fec7e749650dedd48a1b23a09e7","modified":1648521108686},{"_id":"source/_posts/Part05-项目启动前加载导航栏.md","hash":"f68feb4c3417307589cbe44430082b34c2c58a39","modified":1648521108686},{"_id":"source/_posts/Part06-集成 Redis 实现本周热议.md","hash":"b7d5c80692c76f2ccffbd0331540755df60e74e7","modified":1648521108688},{"_id":"source/about/index.md","hash":"3dddcf9ea5af4d0773a6d7436610daec4f7208c3","modified":1648521108688},{"_id":"source/_posts/Part07-集成 Redis 实现访问量.md","hash":"e68a21eaf0c4e76c21b557749c7ed8534ff44695","modified":1648521108688},{"_id":"source/tag/index.md","hash":"cd73bd3a2695bdcf3016903ca381f0c261d4ce2f","modified":1648521108688},{"_id":"source/category/index.md","hash":"c3434fc4f2e6acda7c7f5f24a3b3c3e0f87e2ca6","modified":1648521108688},{"_id":"themes/Chic/ChangeLogs.md","hash":"fab83fcf3eda5cc5b4a6092554e4c57b3a36630e","modified":1648521108689},{"_id":"themes/Chic/LICENSE.md","hash":"632b916dd7e4f5c11790ab808388cda6610210ed","modified":1648521108689},{"_id":"themes/Chic/README.md","hash":"b33e7d4a20dde46667050db2fb14c783fcd1a6c7","modified":1648521108690},{"_id":"themes/Chic/_config.yml","hash":"e486f2e8a608338d7dfb5fa6ffd729faeea7951f","modified":1648521108690},{"_id":"themes/Chic/languages/default.yml","hash":"f26a34a7983d4bc17c65c7f0f14da598e62ce66d","modified":1648521108691},{"_id":"themes/Chic/package.json","hash":"55d477f0e6c76fa767b782ca0f5e0fede8d2ea28","modified":1648521108698},{"_id":"themes/Chic/languages/de.yml","hash":"d45cea36c5c83d7d09afcd1c26fff4a4c513c25b","modified":1648521108691},{"_id":"themes/Chic/languages/fr.yml","hash":"8cb0fe4b6913b4d5b662cdd0108a923c90025f85","modified":1648521108691},{"_id":"themes/Chic/languages/es.yml","hash":"e3b4937da4cd2d0393b8a0ba310e70fc605cc431","modified":1648521108691},{"_id":"themes/Chic/README-CN.md","hash":"e0b616b7546d05a50bd7bf046858af8e221fd0fc","modified":1648521108690},{"_id":"themes/Chic/languages/ja.yml","hash":"3e2fedca096678c0c234ebffa4637828979296fa","modified":1648521108691},{"_id":"themes/Chic/languages/ko.yml","hash":"11330316e3c1262474a2b496e40dbc29f93fe01b","modified":1648521108692},{"_id":"themes/Chic/languages/nl.yml","hash":"3d82ec703d0b3287739d7cb4750a715ae83bfcb3","modified":1648521108692},{"_id":"themes/Chic/languages/no.yml","hash":"ddf2035e920a5ecb9076138c184257d9f51896a7","modified":1648521108692},{"_id":"themes/Chic/languages/pt.yml","hash":"ae2c61b30e638f74f1a42c9ce39ac08d063b30f5","modified":1648521108692},{"_id":"themes/Chic/languages/ru.yml","hash":"2a476b4c6e04900914c81378941640ac5d58a1f0","modified":1648521108692},{"_id":"themes/Chic/languages/zh-TW.yml","hash":"f5f0ca88185da7a8457760d84bf221781473bd7c","modified":1648521108693},{"_id":"themes/Chic/layout/archive.ejs","hash":"48cdf67b628eb6a1c24d484ed252f5b0e3f06ddf","modified":1648521108697},{"_id":"themes/Chic/languages/zh-CN.yml","hash":"b057f389c6713010f97d461e48ec959b0b6f3b44","modified":1648521108693},{"_id":"themes/Chic/layout/category.ejs","hash":"78c93c3a13f9678fa0f27061fa3a91a82edbcc17","modified":1648521108697},{"_id":"themes/Chic/layout/index.ejs","hash":"b44f40dd5b866e1d6a840654aa8323054f061dac","modified":1648521108697},{"_id":"themes/Chic/layout/page.ejs","hash":"92c2d419faea7ec7d984a3d960f5668608d36842","modified":1648521108697},{"_id":"themes/Chic/scripts/imageTag.js","hash":"21c67e132584333eaa7b0c015fdd37d2e56ea934","modified":1648521108698},{"_id":"themes/Chic/layout/layout.ejs","hash":"c2ab5ebca1c0f7ac2fa7e5999f95788861dcefd7","modified":1648521108697},{"_id":"themes/Chic/layout/post.ejs","hash":"a23f83d6c559ce88588472267468a54488d50e8e","modified":1648521108698},{"_id":"themes/Chic/layout/tag.ejs","hash":"f6a48442749c2a743e47fde26bddabaaa2d7d95b","modified":1648521108698},{"_id":"themes/Chic/source/favicon.ico","hash":"96b9a549337c2bec483c2879eeafa4d1f8748fed","modified":1648521108721},{"_id":"themes/Chic/layout/_page/archive.ejs","hash":"074ef6ede857a3404a454684b2a3bf6121d53bf3","modified":1648521108693},{"_id":"themes/Chic/layout/_page/category.ejs","hash":"607bbfd724c47649a5b4c54d0509194ec1f6bbbd","modified":1648521108694},{"_id":"themes/Chic/layout/_page/page.ejs","hash":"90559c37712ec3d7cdd58ad15d14d5662816bce1","modified":1648521108694},{"_id":"themes/Chic/layout/_page/post.ejs","hash":"354e4a74681c10b3e6481c1a2ced03b606a0dd9f","modified":1648521108694},{"_id":"themes/Chic/layout/_partial/footer.ejs","hash":"5ae3880e3badf8f413e503a7a2662c41219b3b82","modified":1648521108695},{"_id":"themes/Chic/layout/_page/profile.ejs","hash":"0f8584965cdb9c2fabb4f81dae7973022b9ff422","modified":1648521108694},{"_id":"themes/Chic/layout/_partial/header.ejs","hash":"2d4be1a3899d4512892fb951e11c9cd47d38ed56","modified":1648521108696},{"_id":"themes/Chic/layout/_page/tag.ejs","hash":"271bbaf9549a62cffbe7b5aab7afdabb4eea5ebc","modified":1648521108695},{"_id":"themes/Chic/layout/_partial/head.ejs","hash":"ff8fd108858018e92e632ec9db43a413079984f6","modified":1648521108695},{"_id":"themes/Chic/layout/_partial/paginator.ejs","hash":"8ad8d7752378f71708ce9d25e19f06f316eacce0","modified":1648521108696},{"_id":"themes/Chic/layout/_partial/toc.ejs","hash":"ced91b79bfa99e4141b3e37e3ac22648729474d2","modified":1648521108696},{"_id":"themes/Chic/layout/_plugins/mathjax.ejs","hash":"56722622edf8cb6e7bb138ad1d0329e2125d9c38","modified":1648521108696},{"_id":"themes/Chic/source/css/base.styl","hash":"b4fe58e7b149e5ee54bedf234d3c32d037749b65","modified":1648521108720},{"_id":"themes/Chic/source/css/custom.styl","hash":"730200ab0f2a18cb51633c707252d42d03a17fa1","modified":1648521108721},{"_id":"themes/Chic/source/css/font.styl","hash":"9df612c7773050b99d2e281f1a6ff21db45d5d25","modified":1648521108721},{"_id":"themes/Chic/source/css/media.styl","hash":"512311f047b94f886163f664e1236f58798e5677","modified":1648521108721},{"_id":"themes/Chic/source/css/layout.styl","hash":"5e43163d7da6e535d211522ed5ac93356d6447ee","modified":1648521108721},{"_id":"themes/Chic/source/css/style.styl","hash":"f87c15993e8b7c3c0bd885b51a11377fa5d2cfe3","modified":1648521108721},{"_id":"themes/Chic/source/css/normalize.styl","hash":"df9ca719f651c45a88ab4d6afa6d29edf51aeba9","modified":1648521108721},{"_id":"themes/Chic/source/css/variable.styl","hash":"4fbb2ffdc00cad2f5cd6ff0dd689836d6f20d227","modified":1648521108721},{"_id":"themes/Chic/source/image/avatar.jpeg","hash":"8ac19974281023905ec8cc8355926e4019e47d2c","modified":1648521108811},{"_id":"themes/Chic/source/js/mathjax2.7.5.js","hash":"fd54df22584629c604511acf67c9e992d362a5e3","modified":1648521108811},{"_id":"themes/Chic/source/js/script.js","hash":"b69c0facab01049908ad936d63ea705d33dea731","modified":1648521108811},{"_id":"themes/Chic/source/js/tocbot.min.js","hash":"bae97e8a24a05a99335f8e725641c8ca9c50502a","modified":1648521108811},{"_id":"themes/Chic/source/css/_highlight/agate.styl","hash":"fc289ba8f47ead6331ec3a51533cfa93251c5634","modified":1648521108698},{"_id":"themes/Chic/source/css/_highlight/androidstudio.styl","hash":"4d67bdab6cc9c614486ca42f98199a04d053e7f0","modified":1648521108699},{"_id":"themes/Chic/source/css/_highlight/arduino-light.styl","hash":"591962bfc758a521b4cb907750c19a1a2423b4d5","modified":1648521108700},{"_id":"themes/Chic/source/css/_highlight/ascetic.styl","hash":"ca087a3c70998c7ac6b0b42d5cf7a653b8707591","modified":1648521108700},{"_id":"themes/Chic/source/css/_highlight/arta.styl","hash":"262167aaebcf28de7f85af7ac77a76fa1fa284f7","modified":1648521108700},{"_id":"themes/Chic/source/css/_highlight/atelier-cave-dark.styl","hash":"7e83c7f2acaaaa98864660afe2794745c36c8e51","modified":1648521108700},{"_id":"themes/Chic/source/css/_highlight/atelier-cave-light.styl","hash":"f47de0b9d66617728f68096ed48371dd6bb9e67a","modified":1648521108700},{"_id":"themes/Chic/source/css/_highlight/atelier-dune-dark.styl","hash":"68584ed0e99c7d0e49ef8a2e67cd4dcdad359de4","modified":1648521108701},{"_id":"themes/Chic/source/css/_highlight/atelier-dune-light.styl","hash":"657fe215931fd06e21b56374df699a94890f7ab4","modified":1648521108701},{"_id":"themes/Chic/source/css/_highlight/atelier-estuary-dark.styl","hash":"1cecd13e0d6b24042ff86372f0596c1441bb834a","modified":1648521108701},{"_id":"themes/Chic/source/css/_highlight/atelier-estuary-light.styl","hash":"2b416a0567a53aa0fa8898b196ddd44315c1a5f3","modified":1648521108701},{"_id":"themes/Chic/source/css/_highlight/atelier-forest-dark.styl","hash":"a741eba35cdfe2cfd67dfbf109655f253d6b4795","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-forest-light.styl","hash":"8d7c7242974aa2454fa792c5d7a47c5f9632355a","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-heath-dark.styl","hash":"f186b357dcebded89b7bcc77389b2cff76533d72","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-heath-light.styl","hash":"c1db353e8613607580d40b12ddc162d029560576","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-lakeside-dark.styl","hash":"802979cea895a0a384645cb30a43de9572cb0e3f","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-lakeside-light.styl","hash":"8659eaae6a0c2e00b4b9199803e50adf4ff0128d","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-plateau-dark.styl","hash":"0d51ddc580ccb0a291271fa9632bc91dab632df6","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-plateau-light.styl","hash":"96181544eeadc5b0749229f11607e7c01f81e078","modified":1648521108702},{"_id":"themes/Chic/source/css/_highlight/atelier-savanna-dark.styl","hash":"bbad7a9512b4873294e73ce806e36e43973e6ed8","modified":1648521108703},{"_id":"themes/Chic/source/css/_highlight/atelier-savanna-light.styl","hash":"8a5207a0c30262a0bf5e1a41411a306f7a89a7e7","modified":1648521108703},{"_id":"themes/Chic/source/css/_highlight/atelier-seaside-dark.styl","hash":"2f008271299042f2443bca98c9bcadbc8c45e837","modified":1648521108703},{"_id":"themes/Chic/source/css/_highlight/atelier-sulphurpool-dark.styl","hash":"18dcb00ab9c62eb810d492047214331c51bb654f","modified":1648521108703},{"_id":"themes/Chic/source/css/_highlight/atelier-seaside-light.styl","hash":"08e2df313c272d5c70c93e713639663c168180d0","modified":1648521108703},{"_id":"themes/Chic/source/css/_highlight/atelier-sulphurpool-light.styl","hash":"add3d88c9d12567dcfae7a8e49984d119fc72227","modified":1648521108704},{"_id":"themes/Chic/source/css/_highlight/brown-paper.styl","hash":"e45a5e2ae53c90334e9bc8be1e45f3c3aa3d785d","modified":1648521108704},{"_id":"themes/Chic/source/css/_highlight/codepen-embed.styl","hash":"1de45e603e2c71c7f6b0c1372a3ba00b1bc153a8","modified":1648521108704},{"_id":"themes/Chic/source/css/_highlight/brown-papersq.png","hash":"3a1332ede3a75a3d24f60b6ed69035b72da5e182","modified":1648521108704},{"_id":"themes/Chic/source/css/_highlight/dark.styl","hash":"98d7884806838a0b46132d759d60ac27c0c4bd9c","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/color-brewer.styl","hash":"9c4905eab730d0b389e6972e907057577f7e25f1","modified":1648521108705},{"_id":"themes/Chic/source/css/_highlight/docco.styl","hash":"7bd3389ce16d20488ab336d557056cc703c921c7","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/darkula.styl","hash":"8965ad6920601c275ca97e617beff5536925a266","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/github-gist.styl","hash":"71f4b0fca91a587e6eba15a5306dca963bb8f441","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/github.styl","hash":"a84eb710b302006120c3e7f8ca18f9e6fbc231c3","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/googlecode.styl","hash":"7f5082ae008925a23eb713f160773fe647eb3ff7","modified":1648521108707},{"_id":"themes/Chic/source/css/_highlight/foundation.styl","hash":"28c59a31467c33bd51cbf3b6085782c2a724ff6c","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/grayscale.styl","hash":"c83804abe39faebd80f8f4ff64fbd7137674cb1c","modified":1648521108707},{"_id":"themes/Chic/source/css/_highlight/far.styl","hash":"8da83d66724f2ce508a40f21b4f6dc0d704be562","modified":1648521108706},{"_id":"themes/Chic/source/css/_highlight/gruvbox-dark.styl","hash":"f66403ce77dcb16b1f98a5061b72f7581630d69f","modified":1648521108707},{"_id":"themes/Chic/source/css/_highlight/highlightjs.styl","hash":"192611c56d6fe4da343718548de21c31a75919db","modified":1648521108707},{"_id":"themes/Chic/source/css/_highlight/hopscotch.styl","hash":"dd3c78c42d4a865f11623235e5e5f6829d789706","modified":1648521108708},{"_id":"themes/Chic/source/css/_highlight/idea.styl","hash":"e284c1760e8da0848f56cd5601d867ceeb0192d7","modified":1648521108708},{"_id":"themes/Chic/source/css/_highlight/hybrid.styl","hash":"4906456025787de04b48a87c42bb704c5ff67065","modified":1648521108708},{"_id":"themes/Chic/source/css/_highlight/index.styl","hash":"36c44375229613a5bb9ee84a8e90214978070439","modified":1648521108708},{"_id":"themes/Chic/source/css/_highlight/ir-black.styl","hash":"aa31b30069ebee39e2c3ebb75e2c96ba8678eb14","modified":1648521108709},{"_id":"themes/Chic/source/css/_highlight/kimbie.dark.styl","hash":"3b998c640eeb2c6192fee24bc78b4137de475dd7","modified":1648521108709},{"_id":"themes/Chic/source/css/_highlight/kimbie.light.styl","hash":"e901738455ec9a1bddde7b62bbd8595de6033e1e","modified":1648521108709},{"_id":"themes/Chic/source/css/_highlight/kimbie.styl","hash":"13113af220dfed09cb49d85102babb352c3eff97","modified":1648521108710},{"_id":"themes/Chic/source/css/_highlight/magula.styl","hash":"ab179306c12a1cf2949482beaca328e379ef034a","modified":1648521108710},{"_id":"themes/Chic/source/css/_highlight/mono-blue.styl","hash":"14fb8678739b77f35771b6d63101ddbf1e7a9fbc","modified":1648521108710},{"_id":"themes/Chic/source/css/_highlight/monokai-sublime.styl","hash":"84a27bd29d939105d65f4164c219d6cc2e09ae60","modified":1648521108710},{"_id":"themes/Chic/source/css/_highlight/monokai.styl","hash":"c3a3bfae1eb864505fbc8748db734600057af1af","modified":1648521108711},{"_id":"themes/Chic/source/css/_highlight/obsidian.styl","hash":"efba069860181d2b709e1548dd16cf102ca267fa","modified":1648521108711},{"_id":"themes/Chic/source/css/_highlight/paraiso-dark.styl","hash":"50f1cee8a5b3b165b4184ead0a99dc564b62ef4f","modified":1648521108711},{"_id":"themes/Chic/source/css/_highlight/paraiso-light.styl","hash":"e428e8202b01e83b0f018a96058d806e7f4c76bf","modified":1648521108711},{"_id":"themes/Chic/source/css/_highlight/paraiso.styl","hash":"846a06a57fa0b3db7f83ec7ac2bf34911f32cf66","modified":1648521108711},{"_id":"themes/Chic/source/css/_highlight/pojoaque.jpg","hash":"c5fe6533b88b21f8d90d3d03954c6b29baa67791","modified":1648521108712},{"_id":"themes/Chic/source/css/_highlight/pojoaque.styl","hash":"37436c1018394f799a1f3dfd326309da8df89742","modified":1648521108712},{"_id":"themes/Chic/source/css/_highlight/rainbow.styl","hash":"95246afef181bd96f9adb1a2e84fb3ef302d4598","modified":1648521108712},{"_id":"themes/Chic/source/css/_highlight/railscasts.styl","hash":"5dc9ce33cecee87fe9ca8f2ed9342602194484ec","modified":1648521108712},{"_id":"themes/Chic/source/css/_highlight/school-book.png","hash":"711ec983c874e093bb89eb77afcbdf6741fa61ee","modified":1648521108713},{"_id":"themes/Chic/source/css/_highlight/school-book.styl","hash":"6d685307f4362d3b2b0868f7b0a94b930db66e6a","modified":1648521108713},{"_id":"themes/Chic/source/css/_highlight/solarized-dark.styl","hash":"9fc9400d3a8cae97eb5761c284140acb0f847538","modified":1648521108713},{"_id":"themes/Chic/source/css/_highlight/solarized-light.styl","hash":"bb04944fc06c12ecd7b56ad933dbedde60c2259a","modified":1648521108713},{"_id":"themes/Chic/source/css/_highlight/tomorrow-night-blue.styl","hash":"92f4423d4964fcfe34ff7ca6cb21012b5738c697","modified":1648521108714},{"_id":"themes/Chic/source/css/_highlight/sunburst.styl","hash":"e6e4c009b10b9805f0c593446bf013edec47d146","modified":1648521108713},{"_id":"themes/Chic/source/css/_highlight/tomorrow-night-bright.styl","hash":"e6b025b247e4027fb3c1b7833588f5a5b04a549c","modified":1648521108714},{"_id":"themes/Chic/source/css/_highlight/tomorrow-night-eighties.styl","hash":"8b16876cf205111d5d5454100de712bc3ea8f477","modified":1648521108714},{"_id":"themes/Chic/source/css/_highlight/tomorrow-night.styl","hash":"eb8441364bb1664ecebde77b965dc36c91133aa0","modified":1648521108714},{"_id":"themes/Chic/source/css/_highlight/tomorrow.styl","hash":"502335f0fac07ed74ca78207bcf3ef8dd2252cf6","modified":1648521108715},{"_id":"themes/Chic/source/css/_highlight/vs.styl","hash":"14fbb0c43af440a290280b26968c8a5c0786b27f","modified":1648521108715},{"_id":"themes/Chic/source/css/_highlight/xcode.styl","hash":"5fa8999c7f807c1aae29c7a1cdf681678576fb69","modified":1648521108715},{"_id":"themes/Chic/source/css/_highlight/zenburn.styl","hash":"f63534764dd6598e81177d64714a184f98153b11","modified":1648521108715},{"_id":"themes/Chic/source/css/_lib/tocbot.css","hash":"f646f2bb75bcd1eb65b2788ac7bf15d4fd243ce9","modified":1648521108716},{"_id":"themes/Chic/source/css/_page/archive.styl","hash":"edc8ee7f34629c59fd4d31f2889d5c069e9d63ac","modified":1648521108718},{"_id":"themes/Chic/source/css/_lib/looper.css","hash":"f4ee39f122059c1e7793b8dc1d72fcbc5fa5ea15","modified":1648521108715},{"_id":"themes/Chic/source/css/_page/category.styl","hash":"9b0c89a525b2b4f0163f6ff1bf1d208277c8bb1f","modified":1648521108718},{"_id":"themes/Chic/source/css/_page/profile.styl","hash":"da31d90eb4529499f9e43eed612967a81f8244c1","modified":1648521108719},{"_id":"themes/Chic/source/css/_page/page.styl","hash":"b2cf99b15965f6851129d52d23f26ed91dc2ede7","modified":1648521108719},{"_id":"themes/Chic/source/css/_page/tag.styl","hash":"715f3fb46c9ccd7c1b701bcf5aac87051ecb3d17","modified":1648521108719},{"_id":"themes/Chic/source/css/_partial/footer.styl","hash":"578a744914f05bab4eae73838076b1cdb8130929","modified":1648521108720},{"_id":"themes/Chic/source/css/_partial/header.styl","hash":"9e4d9b67cc2dbbb92b190be3f9ebcd77e093f057","modified":1648521108720},{"_id":"themes/Chic/source/css/_partial/paginator.styl","hash":"fbe7e3ce8234e5e1a18764113f997b98d777ee5f","modified":1648521108720},{"_id":"themes/Chic/source/fonts/iconfont/demo.css","hash":"53456972a11d52af67187fc17999e6665f9f06fe","modified":1648521108722},{"_id":"themes/Chic/source/fonts/iconfont/demo_index.html","hash":"55c47c8924542a89da4741fcce7eca7e5f881e77","modified":1648521108722},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.css","hash":"496a69ed5e5232feecfd8e1390877b77003e405c","modified":1648521108722},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.eot","hash":"d18736f7885569e497698d17f49b9167add67dc6","modified":1648521108723},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.json","hash":"cb99651b9be2f87afcd5989480dd7360b4bf4643","modified":1648521108724},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.svg","hash":"8f1d735e4fae3757dac1866dc3e30147140811e2","modified":1648521108724},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.woff","hash":"a57593c49b56c16ac1def0e1f3dbca3f658b3579","modified":1648521108725},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.ttf","hash":"41c4f4dc82e42452dcfd19caed6c7dc333ee769e","modified":1648521108725},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.woff2","hash":"39d97a0f72417487f5c1e0a0abf8e27dd6ebda31","modified":1648521108725},{"_id":"themes/Chic/source/fonts/iconfont/iconfont.js","hash":"87bfdaae31251f4d605646c5ae9c67196f6cc4e2","modified":1648521108723},{"_id":"themes/Chic/source/css/_page/_post/post_code.styl","hash":"7b57bafe7e8e375372055f4a775bb42a3c190c95","modified":1648521108717},{"_id":"themes/Chic/source/css/_page/_post/post_content.styl","hash":"8fa506bf4dd38c7cb6d5f48445ab170de4cd6868","modified":1648521108717},{"_id":"themes/Chic/source/css/_page/_post/post_copyright.styl","hash":"e1851fabb110414a624a1be634129dc6b0ce8d03","modified":1648521108717},{"_id":"themes/Chic/source/css/_page/_post/post_header.styl","hash":"6ea0ede34416dfaddda04a903f658325572f91a4","modified":1648521108717},{"_id":"themes/Chic/source/css/_page/_post/post_nav.styl","hash":"9c73772ad0d2b1e67007aa2816ee9b97d5152ffa","modified":1648521108717},{"_id":"themes/Chic/source/css/_page/_post/post_toc.styl","hash":"6c64f313146416a17b087d0a2fc90362cd977776","modified":1648521108718},{"_id":"themes/Chic/source/css/_page/_post/post_tags.styl","hash":"bd16f8c0e5ee2e302b61b861470ab993b6af709b","modified":1648521108718},{"_id":"themes/Chic/source/fonts/lanting/lanting.woff2","hash":"5f325fcd2726a5b44e08b7004a5219e14847cbfa","modified":1648521108810},{"_id":"themes/Chic/source/fonts/lanting/lanting.woff","hash":"642ad1f17d27d4b1010d1a0571d1b44cbc823d9d","modified":1648521108806},{"_id":"themes/Chic/source/fonts/lanting/lanting.eot","hash":"3e184614f037939a6f98d607da3ed7dffb350e65","modified":1648521108771},{"_id":"themes/Chic/source/fonts/lanting/lanting.TTF","hash":"97e9a4538cceef4b17d54c7dc589524905d1b685","modified":1648521108749},{"_id":"themes/Chic/source/fonts/lanting/lanting.otf","hash":"4e184da596772d3ef6e5763cdee3e46a1ce2f2dd","modified":1648521108800},{"_id":"public/tag/index.html","hash":"e773521cf6e18e521bb468fa16dfd91f3bae4638","modified":1648521383778},{"_id":"public/about/index.html","hash":"d445d77c36ffdca60d749a613e079adfbbb3ccb7","modified":1648521383778},{"_id":"public/Part01-博客页面划分.html","hash":"058feec88df380e1167ef74b49ff05af870d1993","modified":1648521383778},{"_id":"public/category/index.html","hash":"2c0a3161873719ddbd233f2336e6fc108f765f9b","modified":1648521383778},{"_id":"public/Part05-项目启动前加载导航栏.html","hash":"e9071defeebf1bf9de6ae50bfaf5301815b6978f","modified":1648521383778},{"_id":"public/Part04-自定义 Freemaker 标签.html","hash":"be681ba43f0034a0b8cea56b632a1da21cd9441a","modified":1648521383778},{"_id":"public/archives/index.html","hash":"4b1c3ac7df07f222f29ecdfe64f11d9a29377725","modified":1648521383778},{"_id":"public/index.html","hash":"e8bcf928aebc884c0f6dc18b3d98471170eb1eff","modified":1648521383778},{"_id":"public/archives/2020/index.html","hash":"1df24719a213d74c950363cc9ce9e1d4e6dfa531","modified":1648521383778},{"_id":"public/Part02-MyBatis-Plus 的使用.html","hash":"68dd21dc127615be28458e5bc6be74d020a8e0b6","modified":1648521383778},{"_id":"public/Part06-集成 Redis 实现本周热议.html","hash":"c983cf043da443d87f1a6e8cf5c59801d7f4c8c4","modified":1648521383778},{"_id":"public/Part03-Controller 控制层接口.html","hash":"a4b97d0a3531b0dfe5e2c3962adb948c2bd82bba","modified":1648521383778},{"_id":"public/Part07-集成 Redis 实现访问量.html","hash":"43cce36d9b330d673fd00b980c38fac1f6b52e1b","modified":1648521383778},{"_id":"public/tags/Java/index.html","hash":"0eb9dc83155370ba004c7f8ba4fd390a858ecc0c","modified":1648521383778},{"_id":"public/archives/2020/03/index.html","hash":"6620bba4ba9a210aedf50318a64579129e687514","modified":1648521383778},{"_id":"public/categories/blog/index.html","hash":"0fcab22046b4d236716725df02a155eafdd0507e","modified":1648521383778},{"_id":"public/CNAME","hash":"63ee80322b2ea44c5ccb2b16e65a4ee0f0fbc1a4","modified":1648521383778},{"_id":"public/favicon.ico","hash":"96b9a549337c2bec483c2879eeafa4d1f8748fed","modified":1648521383778},{"_id":"public/image/avatar.jpeg","hash":"8ac19974281023905ec8cc8355926e4019e47d2c","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.eot","hash":"d18736f7885569e497698d17f49b9167add67dc6","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.svg","hash":"8f1d735e4fae3757dac1866dc3e30147140811e2","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.woff","hash":"a57593c49b56c16ac1def0e1f3dbca3f658b3579","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.woff2","hash":"39d97a0f72417487f5c1e0a0abf8e27dd6ebda31","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.ttf","hash":"41c4f4dc82e42452dcfd19caed6c7dc333ee769e","modified":1648521383778},{"_id":"public/css/base.css","hash":"ea2d491ce6242c6b7087a2652a1135694c292137","modified":1648521383778},{"_id":"public/css/media.css","hash":"5023ee404900a47d61ca0591b2d4e9eace0fe88e","modified":1648521383778},{"_id":"public/css/custom.css","hash":"da39a3ee5e6b4b0d3255bfef95601890afd80709","modified":1648521383778},{"_id":"public/css/layout.css","hash":"c81e2e01ff5e95a3e613064b8490045ff936c305","modified":1648521383778},{"_id":"public/css/font.css","hash":"87059edd1f2bfc4296f5599e73208893f2b06458","modified":1648521383778},{"_id":"public/css/normalize.css","hash":"2d4b663b6a4c68295b6ba240fa2dd9fb3863093c","modified":1648521383778},{"_id":"public/css/variable.css","hash":"cb4180b3bbad471e30cf52ebb40e998d58a30d7d","modified":1648521383778},{"_id":"public/js/script.js","hash":"93694e4e16893f83611daa5ba3723b14ecc80abb","modified":1648521383778},{"_id":"public/js/tocbot.min.js","hash":"bae97e8a24a05a99335f8e725641c8ca9c50502a","modified":1648521383778},{"_id":"public/fonts/iconfont/demo.css","hash":"65c50db528a5abe06426b1a20735feaf1f2a0d9b","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.css","hash":"1e5540dca41dc53879226750f936e72daf616662","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.json","hash":"3123aa840109e385d58a75d34e88a2d621e1ada8","modified":1648521383778},{"_id":"public/css/style.css","hash":"534ca54902458408412998bd6254ecfb3c50ad35","modified":1648521383778},{"_id":"public/fonts/iconfont/demo_index.html","hash":"16e01463756a77b4acd15ade4e6b73f0376d75e1","modified":1648521383778},{"_id":"public/fonts/iconfont/iconfont.js","hash":"87bfdaae31251f4d605646c5ae9c67196f6cc4e2","modified":1648521383778},{"_id":"public/js/mathjax2.7.5.js","hash":"7ba18c783d543cfb4b45a0118ccb73d3f68cd46e","modified":1648521383778},{"_id":"public/fonts/lanting/lanting.woff2","hash":"5f325fcd2726a5b44e08b7004a5219e14847cbfa","modified":1648521383778},{"_id":"public/fonts/lanting/lanting.woff","hash":"642ad1f17d27d4b1010d1a0571d1b44cbc823d9d","modified":1648521383778},{"_id":"public/fonts/lanting/lanting.eot","hash":"3e184614f037939a6f98d607da3ed7dffb350e65","modified":1648521383778},{"_id":"public/fonts/lanting/lanting.TTF","hash":"97e9a4538cceef4b17d54c7dc589524905d1b685","modified":1648521383778},{"_id":"public/fonts/lanting/lanting.otf","hash":"4e184da596772d3ef6e5763cdee3e46a1ce2f2dd","modified":1648521383778}],"Category":[{"name":"blog","_id":"cl1bj2h360004powv1tzr0zku"}],"Data":[],"Page":[{"title":"About me","layout":"page","_content":"\n-----------------------------------------\n\n## Hi there 👋\n\n- 🔭 I’m a Student\n- 🌱 I’m currently learning Java\n- ⚡ Hobby: Play / Surfing\n- ⛵ Motto:Don't let joy take you down !\n","source":"about/index.md","raw":"---\ntitle: About me\nlayout: page\n---\n\n-----------------------------------------\n\n## Hi there 👋\n\n- 🔭 I’m a Student\n- 🌱 I’m currently learning Java\n- ⚡ Hobby: Play / Surfing\n- ⛵ Motto:Don't let joy take you down !\n","date":"2022-03-29T02:31:48.688Z","updated":"2022-03-29T02:31:48.688Z","path":"about/index.html","comments":1,"_id":"cl1bj2h2s0000powv47j43iin","content":"<hr>\n<h2 id=\"Hi-there-👋\"><a href=\"#Hi-there-👋\" class=\"headerlink\" title=\"Hi there 👋\"></a>Hi there 👋</h2><ul>\n<li>🔭 I’m a Student</li>\n<li>🌱 I’m currently learning Java</li>\n<li>⚡ Hobby: Play / Surfing</li>\n<li>⛵ Motto:Don’t let joy take you down !</li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<hr>\n<h2 id=\"Hi-there-👋\"><a href=\"#Hi-there-👋\" class=\"headerlink\" title=\"Hi there 👋\"></a>Hi there 👋</h2><ul>\n<li>🔭 I’m a Student</li>\n<li>🌱 I’m currently learning Java</li>\n<li>⚡ Hobby: Play / Surfing</li>\n<li>⛵ Motto:Don’t let joy take you down !</li>\n</ul>\n"},{"title":"Tag","layout":"tag","_content":"","source":"tag/index.md","raw":"---\ntitle: Tag\nlayout: tag\n---\n","date":"2022-03-29T02:31:48.688Z","updated":"2022-03-29T02:31:48.688Z","path":"tag/index.html","comments":1,"_id":"cl1bj2h330002powvcq96d47r","content":"","site":{"data":{}},"excerpt":"","more":""},{"title":"Category","layout":"category","_content":"","source":"category/index.md","raw":"---\ntitle: Category\nlayout: category\n---\n","date":"2022-03-29T02:31:48.688Z","updated":"2022-03-29T02:31:48.688Z","path":"category/index.html","comments":1,"_id":"cl1bj2h390006powva7anfzob","content":"","site":{"data":{}},"excerpt":"","more":""}],"Post":[{"title":"1. 博客页面划分","date":"2020-03-19T06:59:53.000Z","_content":"\n## 1. 博客页面划分\n### 1.1 导航栏(header.ftl)\n- 图标\n- 登录/注册\n\n### 1.2 分类(header-panel.ftl)\n- 首页\n- 提问、分享、讨论、建议\n\n### 1.3 左侧md8(left.ftl)\n\n### 1.4 右侧md4(right.ftl)\n\n### 1.5 宏(common.ftl)\n- 分页:`<@paging XXX></@paging>`\n- 一条数据 posting:`<@plisting XXX></@plisting>`\n\n### 1.6 布局(layout.ftl)\n- 宏:macro 定义脚本,名为 layout,参数为 title\n- 划分:header.ftl、<#nested/>、footer.ftl","source":"_posts/Part01-博客页面划分.md","raw":"---\ntitle: 1. 博客页面划分\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 1. 博客页面划分\n### 1.1 导航栏(header.ftl)\n- 图标\n- 登录/注册\n\n### 1.2 分类(header-panel.ftl)\n- 首页\n- 提问、分享、讨论、建议\n\n### 1.3 左侧md8(left.ftl)\n\n### 1.4 右侧md4(right.ftl)\n\n### 1.5 宏(common.ftl)\n- 分页:`<@paging XXX></@paging>`\n- 一条数据 posting:`<@plisting XXX></@plisting>`\n\n### 1.6 布局(layout.ftl)\n- 宏:macro 定义脚本,名为 layout,参数为 title\n- 划分:header.ftl、<#nested/>、footer.ftl","slug":"Part01-博客页面划分","published":1,"updated":"2022-03-29T02:31:48.685Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h2y0001powvg9iv7f3v","content":"<h2 id=\"1-博客页面划分\"><a href=\"#1-博客页面划分\" class=\"headerlink\" title=\"1. 博客页面划分\"></a>1. 博客页面划分</h2><h3 id=\"1-1-导航栏(header-ftl)\"><a href=\"#1-1-导航栏(header-ftl)\" class=\"headerlink\" title=\"1.1 导航栏(header.ftl)\"></a>1.1 导航栏(header.ftl)</h3><ul>\n<li>图标</li>\n<li>登录/注册</li>\n</ul>\n<h3 id=\"1-2-分类(header-panel-ftl)\"><a href=\"#1-2-分类(header-panel-ftl)\" class=\"headerlink\" title=\"1.2 分类(header-panel.ftl)\"></a>1.2 分类(header-panel.ftl)</h3><ul>\n<li>首页</li>\n<li>提问、分享、讨论、建议</li>\n</ul>\n<h3 id=\"1-3-左侧md8(left-ftl)\"><a href=\"#1-3-左侧md8(left-ftl)\" class=\"headerlink\" title=\"1.3 左侧md8(left.ftl)\"></a>1.3 左侧md8(left.ftl)</h3><h3 id=\"1-4-右侧md4(right-ftl)\"><a href=\"#1-4-右侧md4(right-ftl)\" class=\"headerlink\" title=\"1.4 右侧md4(right.ftl)\"></a>1.4 右侧md4(right.ftl)</h3><h3 id=\"1-5-宏(common-ftl)\"><a href=\"#1-5-宏(common-ftl)\" class=\"headerlink\" title=\"1.5 宏(common.ftl)\"></a>1.5 宏(common.ftl)</h3><ul>\n<li>分页:<code><@paging XXX></@paging></code></li>\n<li>一条数据 posting:<code><@plisting XXX></@plisting></code></li>\n</ul>\n<h3 id=\"1-6-布局(layout-ftl)\"><a href=\"#1-6-布局(layout-ftl)\" class=\"headerlink\" title=\"1.6 布局(layout.ftl)\"></a>1.6 布局(layout.ftl)</h3><ul>\n<li>宏:macro 定义脚本,名为 layout,参数为 title</li>\n<li>划分:header.ftl、<#nested/>、footer.ftl</li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"1-博客页面划分\"><a href=\"#1-博客页面划分\" class=\"headerlink\" title=\"1. 博客页面划分\"></a>1. 博客页面划分</h2><h3 id=\"1-1-导航栏(header-ftl)\"><a href=\"#1-1-导航栏(header-ftl)\" class=\"headerlink\" title=\"1.1 导航栏(header.ftl)\"></a>1.1 导航栏(header.ftl)</h3><ul>\n<li>图标</li>\n<li>登录/注册</li>\n</ul>\n<h3 id=\"1-2-分类(header-panel-ftl)\"><a href=\"#1-2-分类(header-panel-ftl)\" class=\"headerlink\" title=\"1.2 分类(header-panel.ftl)\"></a>1.2 分类(header-panel.ftl)</h3><ul>\n<li>首页</li>\n<li>提问、分享、讨论、建议</li>\n</ul>\n<h3 id=\"1-3-左侧md8(left-ftl)\"><a href=\"#1-3-左侧md8(left-ftl)\" class=\"headerlink\" title=\"1.3 左侧md8(left.ftl)\"></a>1.3 左侧md8(left.ftl)</h3><h3 id=\"1-4-右侧md4(right-ftl)\"><a href=\"#1-4-右侧md4(right-ftl)\" class=\"headerlink\" title=\"1.4 右侧md4(right.ftl)\"></a>1.4 右侧md4(right.ftl)</h3><h3 id=\"1-5-宏(common-ftl)\"><a href=\"#1-5-宏(common-ftl)\" class=\"headerlink\" title=\"1.5 宏(common.ftl)\"></a>1.5 宏(common.ftl)</h3><ul>\n<li>分页:<code><@paging XXX></@paging></code></li>\n<li>一条数据 posting:<code><@plisting XXX></@plisting></code></li>\n</ul>\n<h3 id=\"1-6-布局(layout-ftl)\"><a href=\"#1-6-布局(layout-ftl)\" class=\"headerlink\" title=\"1.6 布局(layout.ftl)\"></a>1.6 布局(layout.ftl)</h3><ul>\n<li>宏:macro 定义脚本,名为 layout,参数为 title</li>\n<li>划分:header.ftl、<#nested/>、footer.ftl</li>\n</ul>\n"},{"title":"2. MyBatis-Plus 的使用","date":"2020-03-19T06:59:53.000Z","_content":"\n## 2. MyBatis-Plus 的使用\n### 2.1 代码生成器\n- 项目依赖:mybatis-plus-boot-starter、mysql-connector-java、mybatis-plus-generator、druid-spring-boot-starter、spring-boot-starter-freemarker\n```xml\n<dependencies>\n <!--SpringMVC-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-web</artifactId>\n </dependency>\n\n <!--mp、druid、mysql、mp-generator(MyBatis-Plus 从 3.0.3后移除了代码生成器与模板引擎的默认依赖)、MP支持的SQL分析器-->\n <dependency>\n <groupId>com.baomidou</groupId>\n <artifactId>mybatis-plus-boot-starter</artifactId>\n <version>3.2.0</version>\n </dependency>\n<!-- <dependency>-->\n<!-- <groupId>com.alibaba</groupId>-->\n<!-- <artifactId>druid-spring-boot-starter</artifactId>-->\n<!-- <version>1.1.10</version>-->\n<!-- </dependency>-->\n <dependency>\n <groupId>mysql</groupId>\n <artifactId>mysql-connector-java</artifactId>\n <scope>runtime</scope>\n </dependency>\n <dependency>\n <groupId>com.baomidou</groupId>\n <artifactId>mybatis-plus-generator</artifactId>\n <version>3.2.0</version>\n </dependency>\n <dependency>\n <groupId>p6spy</groupId>\n <artifactId>p6spy</artifactId>\n <version>3.8.6</version>\n </dependency>\n\n <!--Freemarker-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-freemarker</artifactId>\n </dependency>\n</dependencies>\n```\n\n### 2.2 分页插件\n- 配置类,SpringBoot 的使用方式\n```java\n@Configuration\n@EnableTransactionManagement\n@MapperScan(\"org.myslayers.mapper\")\npublic class MyBatisPlusConfig {\n\n /**\n * 分页插件\n */\n @Bean\n public PaginationInterceptor paginationInterceptor() {\n PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n return paginationInterceptor;\n }\n}\n```\n\n### 2.3 执行 SQL 分析打印\n- 该功能依赖 p6spy 组件,其中 datasource、freemarker、mybatis-plus 的配置如下:\n```yaml\nspring:\n datasource:\n # driver-class-name: com.mysql.cj.jdbc.Driver\n driver-class-name: com.p6spy.engine.spy.P6SpyDriver\n url: jdbc:p6spy:mysql://127.0.0.1:3306/xblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\n username: root\n password: 4023615\n freemarker:\n settings:\n classic_compatible: true\n datetime_format: yyyy-MM-dd HH:mm\n number_format: 0.##\n\nmybatis-plus:\n mapper-locations: classpath*:/mapper/**Mapper.xml\n```\n- p6spy 组件对应的 spy.properties 配置如下:\n```properties\n#3.2.1以下使用或者不配置\nmodule.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory\n# 自定义日志打印\nlogMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger\n#日志输出到控制台\nappender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger\n# 使用日志系统记录 sql\n#appender=com.p6spy.engine.spy.appender.Slf4JLogger\n# 设置 p6spy driver 代理\nderegisterdrivers=true\n# 取消JDBC URL前缀\nuseprefix=true\n# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.\nexcludecategories=info,debug,result,batch,resultset\n# 日期格式\ndateformat=yyyy-MM-dd HH:mm:ss\n# 实际驱动可多个\n#driverlist=org.h2.Driver\n# 是否开启慢SQL记录\noutagedetection=true\n# 慢SQL记录标准 2 秒\noutagedetectioninterval=2\n```\n\n### 2.4 条件构造器\n- AbstractWrapper、QueryWrapper、UpdateWrapper\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n @Autowired\n PostMapper postMapper;\n\n @Override\n public IPage<PostVo> selectPosts(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {\n if (level == null) level = -1;\n QueryWrapper wrapper = new QueryWrapper<Post>()\n .eq(categoryId != null, \"category_id\", categoryId)\n .eq(userId != null, \"user_id\", userId)\n .eq(level == 0, \"level\", 0)\n .gt(level > 0, \"level\", 0)\n .orderByDesc(order != null, order);\n return postMapper.selectPosts(page, wrapper);\n }\n\n @Override\n public PostVo selectOnePost(QueryWrapper<Post> warapper) {\n return postMapper.selectOnePost(warapper);\n }\n}\n```","source":"_posts/Part02-MyBatis-Plus 的使用.md","raw":"---\ntitle: 2. MyBatis-Plus 的使用\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 2. MyBatis-Plus 的使用\n### 2.1 代码生成器\n- 项目依赖:mybatis-plus-boot-starter、mysql-connector-java、mybatis-plus-generator、druid-spring-boot-starter、spring-boot-starter-freemarker\n```xml\n<dependencies>\n <!--SpringMVC-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-web</artifactId>\n </dependency>\n\n <!--mp、druid、mysql、mp-generator(MyBatis-Plus 从 3.0.3后移除了代码生成器与模板引擎的默认依赖)、MP支持的SQL分析器-->\n <dependency>\n <groupId>com.baomidou</groupId>\n <artifactId>mybatis-plus-boot-starter</artifactId>\n <version>3.2.0</version>\n </dependency>\n<!-- <dependency>-->\n<!-- <groupId>com.alibaba</groupId>-->\n<!-- <artifactId>druid-spring-boot-starter</artifactId>-->\n<!-- <version>1.1.10</version>-->\n<!-- </dependency>-->\n <dependency>\n <groupId>mysql</groupId>\n <artifactId>mysql-connector-java</artifactId>\n <scope>runtime</scope>\n </dependency>\n <dependency>\n <groupId>com.baomidou</groupId>\n <artifactId>mybatis-plus-generator</artifactId>\n <version>3.2.0</version>\n </dependency>\n <dependency>\n <groupId>p6spy</groupId>\n <artifactId>p6spy</artifactId>\n <version>3.8.6</version>\n </dependency>\n\n <!--Freemarker-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-freemarker</artifactId>\n </dependency>\n</dependencies>\n```\n\n### 2.2 分页插件\n- 配置类,SpringBoot 的使用方式\n```java\n@Configuration\n@EnableTransactionManagement\n@MapperScan(\"org.myslayers.mapper\")\npublic class MyBatisPlusConfig {\n\n /**\n * 分页插件\n */\n @Bean\n public PaginationInterceptor paginationInterceptor() {\n PaginationInterceptor paginationInterceptor = new PaginationInterceptor();\n return paginationInterceptor;\n }\n}\n```\n\n### 2.3 执行 SQL 分析打印\n- 该功能依赖 p6spy 组件,其中 datasource、freemarker、mybatis-plus 的配置如下:\n```yaml\nspring:\n datasource:\n # driver-class-name: com.mysql.cj.jdbc.Driver\n driver-class-name: com.p6spy.engine.spy.P6SpyDriver\n url: jdbc:p6spy:mysql://127.0.0.1:3306/xblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC\n username: root\n password: 4023615\n freemarker:\n settings:\n classic_compatible: true\n datetime_format: yyyy-MM-dd HH:mm\n number_format: 0.##\n\nmybatis-plus:\n mapper-locations: classpath*:/mapper/**Mapper.xml\n```\n- p6spy 组件对应的 spy.properties 配置如下:\n```properties\n#3.2.1以下使用或者不配置\nmodule.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory\n# 自定义日志打印\nlogMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger\n#日志输出到控制台\nappender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger\n# 使用日志系统记录 sql\n#appender=com.p6spy.engine.spy.appender.Slf4JLogger\n# 设置 p6spy driver 代理\nderegisterdrivers=true\n# 取消JDBC URL前缀\nuseprefix=true\n# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.\nexcludecategories=info,debug,result,batch,resultset\n# 日期格式\ndateformat=yyyy-MM-dd HH:mm:ss\n# 实际驱动可多个\n#driverlist=org.h2.Driver\n# 是否开启慢SQL记录\noutagedetection=true\n# 慢SQL记录标准 2 秒\noutagedetectioninterval=2\n```\n\n### 2.4 条件构造器\n- AbstractWrapper、QueryWrapper、UpdateWrapper\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n @Autowired\n PostMapper postMapper;\n\n @Override\n public IPage<PostVo> selectPosts(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {\n if (level == null) level = -1;\n QueryWrapper wrapper = new QueryWrapper<Post>()\n .eq(categoryId != null, \"category_id\", categoryId)\n .eq(userId != null, \"user_id\", userId)\n .eq(level == 0, \"level\", 0)\n .gt(level > 0, \"level\", 0)\n .orderByDesc(order != null, order);\n return postMapper.selectPosts(page, wrapper);\n }\n\n @Override\n public PostVo selectOnePost(QueryWrapper<Post> warapper) {\n return postMapper.selectOnePost(warapper);\n }\n}\n```","slug":"Part02-MyBatis-Plus 的使用","published":1,"updated":"2022-03-29T02:31:48.686Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h340003powvb9vzh7ep","content":"<h2 id=\"2-MyBatis-Plus-的使用\"><a href=\"#2-MyBatis-Plus-的使用\" class=\"headerlink\" title=\"2. MyBatis-Plus 的使用\"></a>2. MyBatis-Plus 的使用</h2><h3 id=\"2-1-代码生成器\"><a href=\"#2-1-代码生成器\" class=\"headerlink\" title=\"2.1 代码生成器\"></a>2.1 代码生成器</h3><ul>\n<li>项目依赖:mybatis-plus-boot-starter、mysql-connector-java、mybatis-plus-generator、druid-spring-boot-starter、spring-boot-starter-freemarker<figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"tag\"><<span class=\"name\">dependencies</span>></span></span><br><span class=\"line\"> <span class=\"comment\"><!--SpringMVC--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-web<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--mp、druid、mysql、mp-generator(MyBatis-Plus 从 3.0.3后移除了代码生成器与模板引擎的默认依赖)、MP支持的SQL分析器--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>com.baomidou<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mybatis-plus-boot-starter<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.2.0<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <dependency>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <groupId>com.alibaba</groupId>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <artifactId>druid-spring-boot-starter</artifactId>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <version>1.1.10</version>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- </dependency>--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>mysql<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mysql-connector-java<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">scope</span>></span>runtime<span class=\"tag\"></<span class=\"name\">scope</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>com.baomidou<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mybatis-plus-generator<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.2.0<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>p6spy<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>p6spy<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.8.6<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--Freemarker--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-freemarker<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"tag\"></<span class=\"name\">dependencies</span>></span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-2-分页插件\"><a href=\"#2-2-分页插件\" class=\"headerlink\" title=\"2.2 分页插件\"></a>2.2 分页插件</h3><ul>\n<li>配置类,SpringBoot 的使用方式<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"meta\">@EnableTransactionManagement</span></span><br><span class=\"line\"><span class=\"meta\">@MapperScan("org.myslayers.mapper")</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">MyBatisPlusConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分页插件</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Bean</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> PaginationInterceptor <span class=\"title function_\">paginationInterceptor</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"type\">PaginationInterceptor</span> <span class=\"variable\">paginationInterceptor</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">PaginationInterceptor</span>();</span><br><span class=\"line\"> <span class=\"keyword\">return</span> paginationInterceptor;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-3-执行-SQL-分析打印\"><a href=\"#2-3-执行-SQL-分析打印\" class=\"headerlink\" title=\"2.3 执行 SQL 分析打印\"></a>2.3 执行 SQL 分析打印</h3><ul>\n<li>该功能依赖 p6spy 组件,其中 datasource、freemarker、mybatis-plus 的配置如下:<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"attr\">spring:</span></span><br><span class=\"line\"> <span class=\"attr\">datasource:</span></span><br><span class=\"line\"> <span class=\"comment\"># driver-class-name: com.mysql.cj.jdbc.Driver</span></span><br><span class=\"line\"> <span class=\"attr\">driver-class-name:</span> <span class=\"string\">com.p6spy.engine.spy.P6SpyDriver</span></span><br><span class=\"line\"> <span class=\"attr\">url:</span> <span class=\"string\">jdbc:p6spy:mysql://127.0.0.1:3306/xblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC</span></span><br><span class=\"line\"> <span class=\"attr\">username:</span> <span class=\"string\">root</span></span><br><span class=\"line\"> <span class=\"attr\">password:</span> <span class=\"number\">4023615</span></span><br><span class=\"line\"> <span class=\"attr\">freemarker:</span></span><br><span class=\"line\"> <span class=\"attr\">settings:</span></span><br><span class=\"line\"> <span class=\"attr\">classic_compatible:</span> <span class=\"literal\">true</span></span><br><span class=\"line\"> <span class=\"attr\">datetime_format:</span> <span class=\"string\">yyyy-MM-dd</span> <span class=\"string\">HH:mm</span></span><br><span class=\"line\"> <span class=\"attr\">number_format:</span> <span class=\"number\">0</span><span class=\"string\">.##</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">mybatis-plus:</span></span><br><span class=\"line\"> <span class=\"attr\">mapper-locations:</span> <span class=\"string\">classpath*:/mapper/**Mapper.xml</span></span><br></pre></td></tr></table></figure></li>\n<li>p6spy 组件对应的 spy.properties 配置如下:<figure class=\"highlight properties\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">#3.2.1以下使用或者不配置</span></span><br><span class=\"line\"><span class=\"attr\">module.log</span>=<span class=\"string\">com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory</span></span><br><span class=\"line\"><span class=\"comment\"># 自定义日志打印</span></span><br><span class=\"line\"><span class=\"attr\">logMessageFormat</span>=<span class=\"string\">com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger</span></span><br><span class=\"line\"><span class=\"comment\">#日志输出到控制台</span></span><br><span class=\"line\"><span class=\"attr\">appender</span>=<span class=\"string\">com.baomidou.mybatisplus.extension.p6spy.StdoutLogger</span></span><br><span class=\"line\"><span class=\"comment\"># 使用日志系统记录 sql</span></span><br><span class=\"line\"><span class=\"comment\">#appender=com.p6spy.engine.spy.appender.Slf4JLogger</span></span><br><span class=\"line\"><span class=\"comment\"># 设置 p6spy driver 代理</span></span><br><span class=\"line\"><span class=\"attr\">deregisterdrivers</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 取消JDBC URL前缀</span></span><br><span class=\"line\"><span class=\"attr\">useprefix</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.</span></span><br><span class=\"line\"><span class=\"attr\">excludecategories</span>=<span class=\"string\">info,debug,result,batch,resultset</span></span><br><span class=\"line\"><span class=\"comment\"># 日期格式</span></span><br><span class=\"line\"><span class=\"attr\">dateformat</span>=<span class=\"string\">yyyy-MM-dd HH:mm:ss</span></span><br><span class=\"line\"><span class=\"comment\"># 实际驱动可多个</span></span><br><span class=\"line\"><span class=\"comment\">#driverlist=org.h2.Driver</span></span><br><span class=\"line\"><span class=\"comment\"># 是否开启慢SQL记录</span></span><br><span class=\"line\"><span class=\"attr\">outagedetection</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 慢SQL记录标准 2 秒</span></span><br><span class=\"line\"><span class=\"attr\">outagedetectioninterval</span>=<span class=\"string\">2</span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-4-条件构造器\"><a href=\"#2-4-条件构造器\" class=\"headerlink\" title=\"2.4 条件构造器\"></a>2.4 条件构造器</h3><ul>\n<li>AbstractWrapper、QueryWrapper、UpdateWrapper<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostMapper postMapper;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> IPage<PostVo> <span class=\"title function_\">selectPosts</span><span class=\"params\">(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (level == <span class=\"literal\">null</span>) level = -<span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">QueryWrapper</span> <span class=\"variable\">wrapper</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>()</span><br><span class=\"line\"> .eq(categoryId != <span class=\"literal\">null</span>, <span class=\"string\">"category_id"</span>, categoryId)</span><br><span class=\"line\"> .eq(userId != <span class=\"literal\">null</span>, <span class=\"string\">"user_id"</span>, userId)</span><br><span class=\"line\"> .eq(level == <span class=\"number\">0</span>, <span class=\"string\">"level"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> .gt(level > <span class=\"number\">0</span>, <span class=\"string\">"level"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> .orderByDesc(order != <span class=\"literal\">null</span>, order);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> postMapper.selectPosts(page, wrapper);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> PostVo <span class=\"title function_\">selectOnePost</span><span class=\"params\">(QueryWrapper<Post> warapper)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> postMapper.selectOnePost(warapper);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"2-MyBatis-Plus-的使用\"><a href=\"#2-MyBatis-Plus-的使用\" class=\"headerlink\" title=\"2. MyBatis-Plus 的使用\"></a>2. MyBatis-Plus 的使用</h2><h3 id=\"2-1-代码生成器\"><a href=\"#2-1-代码生成器\" class=\"headerlink\" title=\"2.1 代码生成器\"></a>2.1 代码生成器</h3><ul>\n<li>项目依赖:mybatis-plus-boot-starter、mysql-connector-java、mybatis-plus-generator、druid-spring-boot-starter、spring-boot-starter-freemarker<figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"tag\"><<span class=\"name\">dependencies</span>></span></span><br><span class=\"line\"> <span class=\"comment\"><!--SpringMVC--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-web<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--mp、druid、mysql、mp-generator(MyBatis-Plus 从 3.0.3后移除了代码生成器与模板引擎的默认依赖)、MP支持的SQL分析器--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>com.baomidou<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mybatis-plus-boot-starter<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.2.0<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <dependency>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <groupId>com.alibaba</groupId>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <artifactId>druid-spring-boot-starter</artifactId>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- <version>1.1.10</version>--></span></span><br><span class=\"line\"><span class=\"comment\"><!-- </dependency>--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>mysql<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mysql-connector-java<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">scope</span>></span>runtime<span class=\"tag\"></<span class=\"name\">scope</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>com.baomidou<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>mybatis-plus-generator<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.2.0<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>p6spy<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>p6spy<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>3.8.6<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--Freemarker--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-freemarker<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"tag\"></<span class=\"name\">dependencies</span>></span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-2-分页插件\"><a href=\"#2-2-分页插件\" class=\"headerlink\" title=\"2.2 分页插件\"></a>2.2 分页插件</h3><ul>\n<li>配置类,SpringBoot 的使用方式<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"meta\">@EnableTransactionManagement</span></span><br><span class=\"line\"><span class=\"meta\">@MapperScan("org.myslayers.mapper")</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">MyBatisPlusConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分页插件</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Bean</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> PaginationInterceptor <span class=\"title function_\">paginationInterceptor</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"type\">PaginationInterceptor</span> <span class=\"variable\">paginationInterceptor</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">PaginationInterceptor</span>();</span><br><span class=\"line\"> <span class=\"keyword\">return</span> paginationInterceptor;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-3-执行-SQL-分析打印\"><a href=\"#2-3-执行-SQL-分析打印\" class=\"headerlink\" title=\"2.3 执行 SQL 分析打印\"></a>2.3 执行 SQL 分析打印</h3><ul>\n<li>该功能依赖 p6spy 组件,其中 datasource、freemarker、mybatis-plus 的配置如下:<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"attr\">spring:</span></span><br><span class=\"line\"> <span class=\"attr\">datasource:</span></span><br><span class=\"line\"> <span class=\"comment\"># driver-class-name: com.mysql.cj.jdbc.Driver</span></span><br><span class=\"line\"> <span class=\"attr\">driver-class-name:</span> <span class=\"string\">com.p6spy.engine.spy.P6SpyDriver</span></span><br><span class=\"line\"> <span class=\"attr\">url:</span> <span class=\"string\">jdbc:p6spy:mysql://127.0.0.1:3306/xblog?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=UTC</span></span><br><span class=\"line\"> <span class=\"attr\">username:</span> <span class=\"string\">root</span></span><br><span class=\"line\"> <span class=\"attr\">password:</span> <span class=\"number\">4023615</span></span><br><span class=\"line\"> <span class=\"attr\">freemarker:</span></span><br><span class=\"line\"> <span class=\"attr\">settings:</span></span><br><span class=\"line\"> <span class=\"attr\">classic_compatible:</span> <span class=\"literal\">true</span></span><br><span class=\"line\"> <span class=\"attr\">datetime_format:</span> <span class=\"string\">yyyy-MM-dd</span> <span class=\"string\">HH:mm</span></span><br><span class=\"line\"> <span class=\"attr\">number_format:</span> <span class=\"number\">0</span><span class=\"string\">.##</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"attr\">mybatis-plus:</span></span><br><span class=\"line\"> <span class=\"attr\">mapper-locations:</span> <span class=\"string\">classpath*:/mapper/**Mapper.xml</span></span><br></pre></td></tr></table></figure></li>\n<li>p6spy 组件对应的 spy.properties 配置如下:<figure class=\"highlight properties\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">#3.2.1以下使用或者不配置</span></span><br><span class=\"line\"><span class=\"attr\">module.log</span>=<span class=\"string\">com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory</span></span><br><span class=\"line\"><span class=\"comment\"># 自定义日志打印</span></span><br><span class=\"line\"><span class=\"attr\">logMessageFormat</span>=<span class=\"string\">com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger</span></span><br><span class=\"line\"><span class=\"comment\">#日志输出到控制台</span></span><br><span class=\"line\"><span class=\"attr\">appender</span>=<span class=\"string\">com.baomidou.mybatisplus.extension.p6spy.StdoutLogger</span></span><br><span class=\"line\"><span class=\"comment\"># 使用日志系统记录 sql</span></span><br><span class=\"line\"><span class=\"comment\">#appender=com.p6spy.engine.spy.appender.Slf4JLogger</span></span><br><span class=\"line\"><span class=\"comment\"># 设置 p6spy driver 代理</span></span><br><span class=\"line\"><span class=\"attr\">deregisterdrivers</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 取消JDBC URL前缀</span></span><br><span class=\"line\"><span class=\"attr\">useprefix</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.</span></span><br><span class=\"line\"><span class=\"attr\">excludecategories</span>=<span class=\"string\">info,debug,result,batch,resultset</span></span><br><span class=\"line\"><span class=\"comment\"># 日期格式</span></span><br><span class=\"line\"><span class=\"attr\">dateformat</span>=<span class=\"string\">yyyy-MM-dd HH:mm:ss</span></span><br><span class=\"line\"><span class=\"comment\"># 实际驱动可多个</span></span><br><span class=\"line\"><span class=\"comment\">#driverlist=org.h2.Driver</span></span><br><span class=\"line\"><span class=\"comment\"># 是否开启慢SQL记录</span></span><br><span class=\"line\"><span class=\"attr\">outagedetection</span>=<span class=\"string\">true</span></span><br><span class=\"line\"><span class=\"comment\"># 慢SQL记录标准 2 秒</span></span><br><span class=\"line\"><span class=\"attr\">outagedetectioninterval</span>=<span class=\"string\">2</span></span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"2-4-条件构造器\"><a href=\"#2-4-条件构造器\" class=\"headerlink\" title=\"2.4 条件构造器\"></a>2.4 条件构造器</h3><ul>\n<li>AbstractWrapper、QueryWrapper、UpdateWrapper<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostMapper postMapper;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> IPage<PostVo> <span class=\"title function_\">selectPosts</span><span class=\"params\">(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (level == <span class=\"literal\">null</span>) level = -<span class=\"number\">1</span>;</span><br><span class=\"line\"> <span class=\"type\">QueryWrapper</span> <span class=\"variable\">wrapper</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>()</span><br><span class=\"line\"> .eq(categoryId != <span class=\"literal\">null</span>, <span class=\"string\">"category_id"</span>, categoryId)</span><br><span class=\"line\"> .eq(userId != <span class=\"literal\">null</span>, <span class=\"string\">"user_id"</span>, userId)</span><br><span class=\"line\"> .eq(level == <span class=\"number\">0</span>, <span class=\"string\">"level"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> .gt(level > <span class=\"number\">0</span>, <span class=\"string\">"level"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> .orderByDesc(order != <span class=\"literal\">null</span>, order);</span><br><span class=\"line\"> <span class=\"keyword\">return</span> postMapper.selectPosts(page, wrapper);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> PostVo <span class=\"title function_\">selectOnePost</span><span class=\"params\">(QueryWrapper<Post> warapper)</span> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> postMapper.selectOnePost(warapper);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n"},{"title":"3. Controller 控制层接口","date":"2020-03-19T06:59:53.000Z","_content":"\n## 3. Controller 控制层接口\n### 3.1 `indexController` 数据接口\n- 渲染分类:首页 `index` -> 分类(`传入 id`) -> 渲染分类 -> `currentCategoryId`\n- 接口数据:首页 `index` -> 多条(`post 实体类、PostVo 实体类`) -> `postVoDatas`\n```java\n@Controller\npublic class IndexController extends BaseController {\n\n /**\n * 首页index\n */\n @RequestMapping({\"\", \"/\", \"/index\",\"/index.html\"})\n public String index() {\n /**\n * 多条(post实体类、PostVo实体类):分页集合results\n */\n //多条:selectPosts(分页信息、分类id、用户id、置顶、精选、排序)\n IPage<PostVo> results = postService.selectPosts(getPage(), null, null, null, null, \"created\");\n req.setAttribute(\"postVoDatas\", results);\n\n /**\n * 分类(传入id) -> 渲染分类\n */\n //req:根据传入category表中当前页的id -> 【渲染】分类\n req.setAttribute(\"currentCategoryId\", 0);\n\n return \"index\";\n }\n}\n```\n\n### 3.2 `PostController` 数据接口\n- 渲染分类:分类 `category` -> 分类(`传入 id`)-> 渲染分类 -> `currentCategoryId`\n- 解决数据:分类 `category` -> `<@details categoryId=currentCategoryId pn=pn size=2>`无法传入参数 `pn` 的方法:`让 pn 直接从 req 请求中获取 -> 作为传入 posts 方法的参数`\n- 接口数据:详情 `detail` -> 一条(`post 实体类、PostVo 实体类`) -> `postVoData`\n- 接口数据:详情 `detail` -> 评论(`comment 实体类`) -> `commentVoDatas`\n```java\n@Controller\npublic class PostController extends BaseController {\n\n /**\n * 分类category\n */\n @RequestMapping(\"/category/{id:\\\\d*}\")\n public String category(@PathVariable(name = \"id\") long id) {\n /**\n * 分类(传入id)-> 渲染分类\n */\n //req:根据传入category表中当前页的id -> 【渲染】分类\n req.setAttribute(\"currentCategoryId\", id);\n\n //req:解决使用<@details categoryId=currentCategoryId pn=pn size=2>时,无法传入参数pn的方法:让pn直接从req请求中获取 -> 作为传入posts方法的参数\n req.setAttribute(\"pn\", ServletRequestUtils.getIntParameter(req, \"pn\", 1));\n\n return \"post/category\";\n }\n\n /**\n * 详情detail\n */\n @RequestMapping(\"/detail/{id:\\\\d*}\")\n public String detail(@PathVariable(name = \"id\") long id) {\n /**\n * 一条(post实体类、PostVo实体类)\n */\n //一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id\n PostVo postVo = postService.selectOnePost(new QueryWrapper<Post>().eq(\"p.id\", id));\n //req:PostVo实体类 -> CategoryId属性\n req.setAttribute(\"currentCategoryId\", postVo.getCategoryId());\n //req:PostVo实体类(回调)\n req.setAttribute(\"postVoData\", postVo);\n\n /**\n * 评论(comment实体类)\n */\n //评论:page(分页信息、文章id、用户id、排序)\n IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), null, \"created\");\n //req:CommentVo分页集合\n req.setAttribute(\"commentVoDatas\", results);\n\n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n postService.putViewCount(postVo);\n\n return \"post/detail\";\n }\n}\n```\n- 配置类:项目启动时,会同时调用该 `run` 方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其 `list` 放入 `servletContext` 上下文对象:\n```java\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n /**\n * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n}\n```","source":"_posts/Part03-Controller 控制层接口.md","raw":"---\ntitle: 3. Controller 控制层接口\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 3. Controller 控制层接口\n### 3.1 `indexController` 数据接口\n- 渲染分类:首页 `index` -> 分类(`传入 id`) -> 渲染分类 -> `currentCategoryId`\n- 接口数据:首页 `index` -> 多条(`post 实体类、PostVo 实体类`) -> `postVoDatas`\n```java\n@Controller\npublic class IndexController extends BaseController {\n\n /**\n * 首页index\n */\n @RequestMapping({\"\", \"/\", \"/index\",\"/index.html\"})\n public String index() {\n /**\n * 多条(post实体类、PostVo实体类):分页集合results\n */\n //多条:selectPosts(分页信息、分类id、用户id、置顶、精选、排序)\n IPage<PostVo> results = postService.selectPosts(getPage(), null, null, null, null, \"created\");\n req.setAttribute(\"postVoDatas\", results);\n\n /**\n * 分类(传入id) -> 渲染分类\n */\n //req:根据传入category表中当前页的id -> 【渲染】分类\n req.setAttribute(\"currentCategoryId\", 0);\n\n return \"index\";\n }\n}\n```\n\n### 3.2 `PostController` 数据接口\n- 渲染分类:分类 `category` -> 分类(`传入 id`)-> 渲染分类 -> `currentCategoryId`\n- 解决数据:分类 `category` -> `<@details categoryId=currentCategoryId pn=pn size=2>`无法传入参数 `pn` 的方法:`让 pn 直接从 req 请求中获取 -> 作为传入 posts 方法的参数`\n- 接口数据:详情 `detail` -> 一条(`post 实体类、PostVo 实体类`) -> `postVoData`\n- 接口数据:详情 `detail` -> 评论(`comment 实体类`) -> `commentVoDatas`\n```java\n@Controller\npublic class PostController extends BaseController {\n\n /**\n * 分类category\n */\n @RequestMapping(\"/category/{id:\\\\d*}\")\n public String category(@PathVariable(name = \"id\") long id) {\n /**\n * 分类(传入id)-> 渲染分类\n */\n //req:根据传入category表中当前页的id -> 【渲染】分类\n req.setAttribute(\"currentCategoryId\", id);\n\n //req:解决使用<@details categoryId=currentCategoryId pn=pn size=2>时,无法传入参数pn的方法:让pn直接从req请求中获取 -> 作为传入posts方法的参数\n req.setAttribute(\"pn\", ServletRequestUtils.getIntParameter(req, \"pn\", 1));\n\n return \"post/category\";\n }\n\n /**\n * 详情detail\n */\n @RequestMapping(\"/detail/{id:\\\\d*}\")\n public String detail(@PathVariable(name = \"id\") long id) {\n /**\n * 一条(post实体类、PostVo实体类)\n */\n //一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id\n PostVo postVo = postService.selectOnePost(new QueryWrapper<Post>().eq(\"p.id\", id));\n //req:PostVo实体类 -> CategoryId属性\n req.setAttribute(\"currentCategoryId\", postVo.getCategoryId());\n //req:PostVo实体类(回调)\n req.setAttribute(\"postVoData\", postVo);\n\n /**\n * 评论(comment实体类)\n */\n //评论:page(分页信息、文章id、用户id、排序)\n IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), null, \"created\");\n //req:CommentVo分页集合\n req.setAttribute(\"commentVoDatas\", results);\n\n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n postService.putViewCount(postVo);\n\n return \"post/detail\";\n }\n}\n```\n- 配置类:项目启动时,会同时调用该 `run` 方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其 `list` 放入 `servletContext` 上下文对象:\n```java\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n /**\n * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n}\n```","slug":"Part03-Controller 控制层接口","published":1,"updated":"2022-03-29T02:31:48.686Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h3a0007powv4aye54hd","content":"<h2 id=\"3-Controller-控制层接口\"><a href=\"#3-Controller-控制层接口\" class=\"headerlink\" title=\"3. Controller 控制层接口\"></a>3. Controller 控制层接口</h2><h3 id=\"3-1-indexController-数据接口\"><a href=\"#3-1-indexController-数据接口\" class=\"headerlink\" title=\"3.1 indexController 数据接口\"></a>3.1 <code>indexController</code> 数据接口</h3><ul>\n<li>渲染分类:首页 <code>index</code> -> 分类(<code>传入 id</code>) -> 渲染分类 -> <code>currentCategoryId</code></li>\n<li>接口数据:首页 <code>index</code> -> 多条(<code>post 实体类、PostVo 实体类</code>) -> <code>postVoDatas</code><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">IndexController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 首页index</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping({"", "/", "/index","/index.html"})</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">index</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 多条(post实体类、PostVo实体类):分页集合results</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//多条:selectPosts(分页信息、分类id、用户id、置顶、精选、排序)</span></span><br><span class=\"line\"> IPage<PostVo> results = postService.selectPosts(getPage(), <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类(传入id) -> 渲染分类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//req:根据传入category表中当前页的id -> 【渲染】分类</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"index"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"3-2-PostController-数据接口\"><a href=\"#3-2-PostController-数据接口\" class=\"headerlink\" title=\"3.2 PostController 数据接口\"></a>3.2 <code>PostController</code> 数据接口</h3><ul>\n<li>渲染分类:分类 <code>category</code> -> 分类(<code>传入 id</code>)-> 渲染分类 -> <code>currentCategoryId</code></li>\n<li>解决数据:分类 <code>category</code> -> <code><@details categoryId=currentCategoryId pn=pn size=2></code>无法传入参数 <code>pn</code> 的方法:<code>让 pn 直接从 req 请求中获取 -> 作为传入 posts 方法的参数</code></li>\n<li>接口数据:详情 <code>detail</code> -> 一条(<code>post 实体类、PostVo 实体类</code>) -> <code>postVoData</code></li>\n<li>接口数据:详情 <code>detail</code> -> 评论(<code>comment 实体类</code>) -> <code>commentVoDatas</code><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类category</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/category/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">category</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类(传入id)-> 渲染分类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//req:根据传入category表中当前页的id -> 【渲染】分类</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, id);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//req:解决使用<@details categoryId=currentCategoryId pn=pn size=2>时,无法传入参数pn的方法:让pn直接从req请求中获取 -> 作为传入posts方法的参数</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"pn"</span>, ServletRequestUtils.getIntParameter(req, <span class=\"string\">"pn"</span>, <span class=\"number\">1</span>));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/category"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 详情detail</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/detail/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">detail</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 一条(post实体类、PostVo实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id</span></span><br><span class=\"line\"> <span class=\"type\">PostVo</span> <span class=\"variable\">postVo</span> <span class=\"operator\">=</span> postService.selectOnePost(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().eq(<span class=\"string\">"p.id"</span>, id));</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类 -> CategoryId属性</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, postVo.getCategoryId());</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类(回调)</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoData"</span>, postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 评论(comment实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//评论:page(分页信息、文章id、用户id、排序)</span></span><br><span class=\"line\"> IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> <span class=\"comment\">//req:CommentVo分页集合</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"commentVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> postService.putViewCount(postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/detail"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li>配置类:项目启动时,会同时调用该 <code>run</code> 方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其 <code>list</code> 放入 <code>servletContext</code> 上下文对象:<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"3-Controller-控制层接口\"><a href=\"#3-Controller-控制层接口\" class=\"headerlink\" title=\"3. Controller 控制层接口\"></a>3. Controller 控制层接口</h2><h3 id=\"3-1-indexController-数据接口\"><a href=\"#3-1-indexController-数据接口\" class=\"headerlink\" title=\"3.1 indexController 数据接口\"></a>3.1 <code>indexController</code> 数据接口</h3><ul>\n<li>渲染分类:首页 <code>index</code> -> 分类(<code>传入 id</code>) -> 渲染分类 -> <code>currentCategoryId</code></li>\n<li>接口数据:首页 <code>index</code> -> 多条(<code>post 实体类、PostVo 实体类</code>) -> <code>postVoDatas</code><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">IndexController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 首页index</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping({"", "/", "/index","/index.html"})</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">index</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 多条(post实体类、PostVo实体类):分页集合results</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//多条:selectPosts(分页信息、分类id、用户id、置顶、精选、排序)</span></span><br><span class=\"line\"> IPage<PostVo> results = postService.selectPosts(getPage(), <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类(传入id) -> 渲染分类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//req:根据传入category表中当前页的id -> 【渲染】分类</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, <span class=\"number\">0</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"index"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"3-2-PostController-数据接口\"><a href=\"#3-2-PostController-数据接口\" class=\"headerlink\" title=\"3.2 PostController 数据接口\"></a>3.2 <code>PostController</code> 数据接口</h3><ul>\n<li>渲染分类:分类 <code>category</code> -> 分类(<code>传入 id</code>)-> 渲染分类 -> <code>currentCategoryId</code></li>\n<li>解决数据:分类 <code>category</code> -> <code><@details categoryId=currentCategoryId pn=pn size=2></code>无法传入参数 <code>pn</code> 的方法:<code>让 pn 直接从 req 请求中获取 -> 作为传入 posts 方法的参数</code></li>\n<li>接口数据:详情 <code>detail</code> -> 一条(<code>post 实体类、PostVo 实体类</code>) -> <code>postVoData</code></li>\n<li>接口数据:详情 <code>detail</code> -> 评论(<code>comment 实体类</code>) -> <code>commentVoDatas</code><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类category</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/category/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">category</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 分类(传入id)-> 渲染分类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//req:根据传入category表中当前页的id -> 【渲染】分类</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, id);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//req:解决使用<@details categoryId=currentCategoryId pn=pn size=2>时,无法传入参数pn的方法:让pn直接从req请求中获取 -> 作为传入posts方法的参数</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"pn"</span>, ServletRequestUtils.getIntParameter(req, <span class=\"string\">"pn"</span>, <span class=\"number\">1</span>));</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/category"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 详情detail</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/detail/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">detail</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 一条(post实体类、PostVo实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id</span></span><br><span class=\"line\"> <span class=\"type\">PostVo</span> <span class=\"variable\">postVo</span> <span class=\"operator\">=</span> postService.selectOnePost(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().eq(<span class=\"string\">"p.id"</span>, id));</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类 -> CategoryId属性</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, postVo.getCategoryId());</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类(回调)</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoData"</span>, postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 评论(comment实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//评论:page(分页信息、文章id、用户id、排序)</span></span><br><span class=\"line\"> IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> <span class=\"comment\">//req:CommentVo分页集合</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"commentVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> postService.putViewCount(postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/detail"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n<li>配置类:项目启动时,会同时调用该 <code>run</code> 方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其 <code>list</code> 放入 <code>servletContext</code> 上下文对象:<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n"},{"title":"4. 自定义 Freemaker 标签","date":"2020-03-19T06:59:53.000Z","_content":"\n## 4. 自定义 Freemaker 标签\n### 4.1 方式一:实现 `TemplateDirectiveModel` 接口,重写 `excute` 方法\n```java\npublic interface TemplateDirectiveModel extends TemplateModel {\n public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException;\n}\n```\n上述方法的参数说明:\n- env:系统环境变量,通常用它来输出相关内容,如 Writer out = env.getOut()\n- params:自定义标签传过来的对象,其 key = 自定义标签的参数名,value 值是 TemplateModel 类型,而 TemplateModel 是一个接口类型,通常我们都使用 TemplateScalarModel 接口来替代它获取一个 String 值,如 TemplateScalarModel.getAsString(); 当然还有其它常用的替代接口,如 TemplateNumberModel 获取 number,TemplateHashModel 等。\n- loopVars 循环替代变量\n- body 用于处理自定义标签中的内容,如 <@myDirective> 将要被处理的内容;当标签是<@myDirective /> 格式时,body=null\n\n### 4.2 方式二:采用 `mblog` 项目对该 `TemplateDirectiveModel` 接口进行封装\n- 实现 `TemplateDirectiveModel` 接口较为复杂,故我们可以直接使用 `mblog` 项目中已经封装好的类:`org.myslayers.common.templates.DirectiveHandler`、`TemplateDirective`、`TemplateModelUtils`;\n- 其中,我们只需要重写 `TemplateDirective` 类中的 `getName`()和 `excute(DirectiveHandler handler)`,本次使用 `PostsTemplate`、`TimeAgoMethod` 进行开发使用;\n- 最后,使用 `FreemarkerConfig` 类在 `Springboot` 中对 `PostsTemplate`、`TimeAgoMethod` 进行标签的声明`<timeAgo></timeAgo>`、`<details></details>`。\n```java\npublic class DirectiveHandler {\n \n}\npublic abstract class TemplateDirective implements TemplateDirectiveModel {\n \n}\npublic class TemplateModelUtils {\n \n}\n```\n```java\npublic class TimeAgoMethod extends DirectiveHandler.BaseMethod {\n \n}\npublic class PostsTemplate extends TemplateDirective {\n \n}\n```\n```java\n/**\n * Freemarker配置类\n */\n@Configuration\npublic class FreemarkerConfig {\n\n @Autowired\n private freemarker.template.Configuration configuration;\n\n @Autowired\n TimeAgoMethod timeAgoMethod;\n\n @Autowired\n PostsTemplate postsTemplate;\n\n @Autowired\n HotsTemplate hotsTemplate;\n\n /**\n * 注册为“timeAgo”函数:快速实现日期转换\n * 注册为“posts”函数:快速实现分页\n */\n @PostConstruct\n public void setUp() {\n configuration.setSharedVariable(\"timeAgo\", timeAgoMethod);\n configuration.setSharedVariable(\"details\", postsTemplate);\n }\n}\n```","source":"_posts/Part04-自定义 Freemaker 标签.md","raw":"---\ntitle: 4. 自定义 Freemaker 标签\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 4. 自定义 Freemaker 标签\n### 4.1 方式一:实现 `TemplateDirectiveModel` 接口,重写 `excute` 方法\n```java\npublic interface TemplateDirectiveModel extends TemplateModel {\n public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException;\n}\n```\n上述方法的参数说明:\n- env:系统环境变量,通常用它来输出相关内容,如 Writer out = env.getOut()\n- params:自定义标签传过来的对象,其 key = 自定义标签的参数名,value 值是 TemplateModel 类型,而 TemplateModel 是一个接口类型,通常我们都使用 TemplateScalarModel 接口来替代它获取一个 String 值,如 TemplateScalarModel.getAsString(); 当然还有其它常用的替代接口,如 TemplateNumberModel 获取 number,TemplateHashModel 等。\n- loopVars 循环替代变量\n- body 用于处理自定义标签中的内容,如 <@myDirective> 将要被处理的内容;当标签是<@myDirective /> 格式时,body=null\n\n### 4.2 方式二:采用 `mblog` 项目对该 `TemplateDirectiveModel` 接口进行封装\n- 实现 `TemplateDirectiveModel` 接口较为复杂,故我们可以直接使用 `mblog` 项目中已经封装好的类:`org.myslayers.common.templates.DirectiveHandler`、`TemplateDirective`、`TemplateModelUtils`;\n- 其中,我们只需要重写 `TemplateDirective` 类中的 `getName`()和 `excute(DirectiveHandler handler)`,本次使用 `PostsTemplate`、`TimeAgoMethod` 进行开发使用;\n- 最后,使用 `FreemarkerConfig` 类在 `Springboot` 中对 `PostsTemplate`、`TimeAgoMethod` 进行标签的声明`<timeAgo></timeAgo>`、`<details></details>`。\n```java\npublic class DirectiveHandler {\n \n}\npublic abstract class TemplateDirective implements TemplateDirectiveModel {\n \n}\npublic class TemplateModelUtils {\n \n}\n```\n```java\npublic class TimeAgoMethod extends DirectiveHandler.BaseMethod {\n \n}\npublic class PostsTemplate extends TemplateDirective {\n \n}\n```\n```java\n/**\n * Freemarker配置类\n */\n@Configuration\npublic class FreemarkerConfig {\n\n @Autowired\n private freemarker.template.Configuration configuration;\n\n @Autowired\n TimeAgoMethod timeAgoMethod;\n\n @Autowired\n PostsTemplate postsTemplate;\n\n @Autowired\n HotsTemplate hotsTemplate;\n\n /**\n * 注册为“timeAgo”函数:快速实现日期转换\n * 注册为“posts”函数:快速实现分页\n */\n @PostConstruct\n public void setUp() {\n configuration.setSharedVariable(\"timeAgo\", timeAgoMethod);\n configuration.setSharedVariable(\"details\", postsTemplate);\n }\n}\n```","slug":"Part04-自定义 Freemaker 标签","published":1,"updated":"2022-03-29T02:31:48.686Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h3c0008powv2tcg3npa","content":"<h2 id=\"4-自定义-Freemaker-标签\"><a href=\"#4-自定义-Freemaker-标签\" class=\"headerlink\" title=\"4. 自定义 Freemaker 标签\"></a>4. 自定义 Freemaker 标签</h2><h3 id=\"4-1-方式一:实现-TemplateDirectiveModel-接口,重写-excute-方法\"><a href=\"#4-1-方式一:实现-TemplateDirectiveModel-接口,重写-excute-方法\" class=\"headerlink\" title=\"4.1 方式一:实现 TemplateDirectiveModel 接口,重写 excute 方法\"></a>4.1 方式一:实现 <code>TemplateDirectiveModel</code> 接口,重写 <code>excute</code> 方法</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">interface</span> <span class=\"title class_\">TemplateDirectiveModel</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateModel</span> {</span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">execute</span><span class=\"params\">(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)</span> <span class=\"keyword\">throws</span> TemplateException, IOException;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>上述方法的参数说明:</p>\n<ul>\n<li>env:系统环境变量,通常用它来输出相关内容,如 Writer out = env.getOut()</li>\n<li>params:自定义标签传过来的对象,其 key = 自定义标签的参数名,value 值是 TemplateModel 类型,而 TemplateModel 是一个接口类型,通常我们都使用 TemplateScalarModel 接口来替代它获取一个 String 值,如 TemplateScalarModel.getAsString(); 当然还有其它常用的替代接口,如 TemplateNumberModel 获取 number,TemplateHashModel 等。</li>\n<li>loopVars 循环替代变量</li>\n<li>body 用于处理自定义标签中的内容,如 <@myDirective> 将要被处理的内容;当标签是<@myDirective /> 格式时,body=null</li>\n</ul>\n<h3 id=\"4-2-方式二:采用-mblog-项目对该-TemplateDirectiveModel-接口进行封装\"><a href=\"#4-2-方式二:采用-mblog-项目对该-TemplateDirectiveModel-接口进行封装\" class=\"headerlink\" title=\"4.2 方式二:采用 mblog 项目对该 TemplateDirectiveModel 接口进行封装\"></a>4.2 方式二:采用 <code>mblog</code> 项目对该 <code>TemplateDirectiveModel</code> 接口进行封装</h3><ul>\n<li>实现 <code>TemplateDirectiveModel</code> 接口较为复杂,故我们可以直接使用 <code>mblog</code> 项目中已经封装好的类:<code>org.myslayers.common.templates.DirectiveHandler</code>、<code>TemplateDirective</code>、<code>TemplateModelUtils</code>;</li>\n<li>其中,我们只需要重写 <code>TemplateDirective</code> 类中的 <code>getName</code>()和 <code>excute(DirectiveHandler handler)</code>,本次使用 <code>PostsTemplate</code>、<code>TimeAgoMethod</code> 进行开发使用;</li>\n<li>最后,使用 <code>FreemarkerConfig</code> 类在 <code>Springboot</code> 中对 <code>PostsTemplate</code>、<code>TimeAgoMethod</code> 进行标签的声明<code><timeAgo></timeAgo></code>、<code><details></details></code>。<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">DirectiveHandler</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">abstract</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TemplateDirective</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">TemplateDirectiveModel</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TemplateModelUtils</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TimeAgoMethod</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">DirectiveHandler</span>.BaseMethod {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostsTemplate</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateDirective</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Freemarker配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">FreemarkerConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> <span class=\"keyword\">private</span> freemarker.template.Configuration configuration;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> TimeAgoMethod timeAgoMethod;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostsTemplate postsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> HotsTemplate hotsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“timeAgo”函数:快速实现日期转换</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“posts”函数:快速实现分页</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@PostConstruct</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setUp</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"timeAgo"</span>, timeAgoMethod);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"details"</span>, postsTemplate);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"4-自定义-Freemaker-标签\"><a href=\"#4-自定义-Freemaker-标签\" class=\"headerlink\" title=\"4. 自定义 Freemaker 标签\"></a>4. 自定义 Freemaker 标签</h2><h3 id=\"4-1-方式一:实现-TemplateDirectiveModel-接口,重写-excute-方法\"><a href=\"#4-1-方式一:实现-TemplateDirectiveModel-接口,重写-excute-方法\" class=\"headerlink\" title=\"4.1 方式一:实现 TemplateDirectiveModel 接口,重写 excute 方法\"></a>4.1 方式一:实现 <code>TemplateDirectiveModel</code> 接口,重写 <code>excute</code> 方法</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">interface</span> <span class=\"title class_\">TemplateDirectiveModel</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateModel</span> {</span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">execute</span><span class=\"params\">(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body)</span> <span class=\"keyword\">throws</span> TemplateException, IOException;</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<p>上述方法的参数说明:</p>\n<ul>\n<li>env:系统环境变量,通常用它来输出相关内容,如 Writer out = env.getOut()</li>\n<li>params:自定义标签传过来的对象,其 key = 自定义标签的参数名,value 值是 TemplateModel 类型,而 TemplateModel 是一个接口类型,通常我们都使用 TemplateScalarModel 接口来替代它获取一个 String 值,如 TemplateScalarModel.getAsString(); 当然还有其它常用的替代接口,如 TemplateNumberModel 获取 number,TemplateHashModel 等。</li>\n<li>loopVars 循环替代变量</li>\n<li>body 用于处理自定义标签中的内容,如 <@myDirective> 将要被处理的内容;当标签是<@myDirective /> 格式时,body=null</li>\n</ul>\n<h3 id=\"4-2-方式二:采用-mblog-项目对该-TemplateDirectiveModel-接口进行封装\"><a href=\"#4-2-方式二:采用-mblog-项目对该-TemplateDirectiveModel-接口进行封装\" class=\"headerlink\" title=\"4.2 方式二:采用 mblog 项目对该 TemplateDirectiveModel 接口进行封装\"></a>4.2 方式二:采用 <code>mblog</code> 项目对该 <code>TemplateDirectiveModel</code> 接口进行封装</h3><ul>\n<li>实现 <code>TemplateDirectiveModel</code> 接口较为复杂,故我们可以直接使用 <code>mblog</code> 项目中已经封装好的类:<code>org.myslayers.common.templates.DirectiveHandler</code>、<code>TemplateDirective</code>、<code>TemplateModelUtils</code>;</li>\n<li>其中,我们只需要重写 <code>TemplateDirective</code> 类中的 <code>getName</code>()和 <code>excute(DirectiveHandler handler)</code>,本次使用 <code>PostsTemplate</code>、<code>TimeAgoMethod</code> 进行开发使用;</li>\n<li>最后,使用 <code>FreemarkerConfig</code> 类在 <code>Springboot</code> 中对 <code>PostsTemplate</code>、<code>TimeAgoMethod</code> 进行标签的声明<code><timeAgo></timeAgo></code>、<code><details></details></code>。<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">DirectiveHandler</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">abstract</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TemplateDirective</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">TemplateDirectiveModel</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TemplateModelUtils</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">TimeAgoMethod</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">DirectiveHandler</span>.BaseMethod {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostsTemplate</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateDirective</span> {</span><br><span class=\"line\"> </span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Freemarker配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">FreemarkerConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> <span class=\"keyword\">private</span> freemarker.template.Configuration configuration;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> TimeAgoMethod timeAgoMethod;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostsTemplate postsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> HotsTemplate hotsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“timeAgo”函数:快速实现日期转换</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“posts”函数:快速实现分页</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@PostConstruct</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setUp</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"timeAgo"</span>, timeAgoMethod);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"details"</span>, postsTemplate);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n"},{"title":"5. 项目启动前预加载导航栏","date":"2020-03-19T06:59:53.000Z","_content":"\n## 5. 项目启动前预加载导航栏\n### 5.1 `ContextStartup` 配置类\n```java\n/**\n * Context配置类\n */\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n /**\n * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n\n}\n```\n\n### 5.2 使用\n```injectedfreemarker\n<#--【二、分类】-->\n<div class=\"fly-panel fly-column\">\n <div class=\"layui-container\">\n <ul class=\"layui-clear\">\n\n <#--首页-->\n <li class=\"${(0 == currentCategoryId)?string('layui-hide-xs layui-this', '')}\"><a href=\"/\">首页</a></li>\n <#--提问、分享、讨论、建议-->\n <#list categorys as item>\n <li class=\"${(item.id == currentCategoryId)?string('layui-hide-xs layui-this', '')}\"><a href=\"/category/${item.id}\">${item.name}</a></li>\n </#list>\n\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><span class=\"fly-mid\"></span></li>\n <!-- 用户登入后显示 -->\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><a href=\"user/index.html\">我发表的贴</a></li>\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><a href=\"user/index.html#collection\">我收藏的贴</a>\n </li>\n </ul>\n\n <div class=\"fly-column-right layui-hide-xs\">\n <span class=\"fly-search\"><i class=\"layui-icon\"></i></span>\n <a href=\"jie/add.html\" class=\"layui-btn\">发表新帖</a>\n </div>\n <div class=\"layui-hide-sm layui-show-xs-block\"\n style=\"margin-top: -10px; padding-bottom: 10px; text-align: center;\">\n <a href=\"jie/add.html\" class=\"layui-btn\">发表新帖</a>\n </div>\n </div>\n</div>\n```","source":"_posts/Part05-项目启动前加载导航栏.md","raw":"---\ntitle: 5. 项目启动前预加载导航栏\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 5. 项目启动前预加载导航栏\n### 5.1 `ContextStartup` 配置类\n```java\n/**\n * Context配置类\n */\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n /**\n * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n\n}\n```\n\n### 5.2 使用\n```injectedfreemarker\n<#--【二、分类】-->\n<div class=\"fly-panel fly-column\">\n <div class=\"layui-container\">\n <ul class=\"layui-clear\">\n\n <#--首页-->\n <li class=\"${(0 == currentCategoryId)?string('layui-hide-xs layui-this', '')}\"><a href=\"/\">首页</a></li>\n <#--提问、分享、讨论、建议-->\n <#list categorys as item>\n <li class=\"${(item.id == currentCategoryId)?string('layui-hide-xs layui-this', '')}\"><a href=\"/category/${item.id}\">${item.name}</a></li>\n </#list>\n\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><span class=\"fly-mid\"></span></li>\n <!-- 用户登入后显示 -->\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><a href=\"user/index.html\">我发表的贴</a></li>\n <li class=\"layui-hide-xs layui-hide-sm layui-show-md-inline-block\"><a href=\"user/index.html#collection\">我收藏的贴</a>\n </li>\n </ul>\n\n <div class=\"fly-column-right layui-hide-xs\">\n <span class=\"fly-search\"><i class=\"layui-icon\"></i></span>\n <a href=\"jie/add.html\" class=\"layui-btn\">发表新帖</a>\n </div>\n <div class=\"layui-hide-sm layui-show-xs-block\"\n style=\"margin-top: -10px; padding-bottom: 10px; text-align: center;\">\n <a href=\"jie/add.html\" class=\"layui-btn\">发表新帖</a>\n </div>\n </div>\n</div>\n```","slug":"Part05-项目启动前加载导航栏","published":1,"updated":"2022-03-29T02:31:48.686Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h3d0009powvglrq5x2f","content":"<h2 id=\"5-项目启动前预加载导航栏\"><a href=\"#5-项目启动前预加载导航栏\" class=\"headerlink\" title=\"5. 项目启动前预加载导航栏\"></a>5. 项目启动前预加载导航栏</h2><h3 id=\"5-1-ContextStartup-配置类\"><a href=\"#5-1-ContextStartup-配置类\" class=\"headerlink\" title=\"5.1 ContextStartup 配置类\"></a>5.1 <code>ContextStartup</code> 配置类</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Context配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"5-2-使用\"><a href=\"#5-2-使用\" class=\"headerlink\" title=\"5.2 使用\"></a>5.2 使用</h3><figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><#--【二、分类】--></span><br><span class=\"line\"><div class="fly-panel fly-column"></span><br><span class=\"line\"> <div class="layui-container"></span><br><span class=\"line\"> <ul class="layui-clear"></span><br><span class=\"line\"></span><br><span class=\"line\"> <#--首页--></span><br><span class=\"line\"> <li class="${(0 == currentCategoryId)?string('layui-hide-xs layui-this', '')}"><a href="/">首页</a></li></span><br><span class=\"line\"> <#--提问、分享、讨论、建议--></span><br><span class=\"line\"> <#list categorys as item></span><br><span class=\"line\"> <li class="${(item.id == currentCategoryId)?string('layui-hide-xs layui-this', '')}"><a href="/category/${item.id}">${item.name}</a></li></span><br><span class=\"line\"> </#list></span><br><span class=\"line\"></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><span class="fly-mid"></span></li></span><br><span class=\"line\"> <!-- 用户登入后显示 --></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><a href="user/index.html">我发表的贴</a></li></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><a href="user/index.html#collection">我收藏的贴</a></span><br><span class=\"line\"> </li></span><br><span class=\"line\"> </ul></span><br><span class=\"line\"></span><br><span class=\"line\"> <div class="fly-column-right layui-hide-xs"></span><br><span class=\"line\"> <span class="fly-search"><i class="layui-icon"></i></span></span><br><span class=\"line\"> <a href="jie/add.html" class="layui-btn">发表新帖</a></span><br><span class=\"line\"> </div></span><br><span class=\"line\"> <div class="layui-hide-sm layui-show-xs-block"</span><br><span class=\"line\"> style="margin-top: -10px; padding-bottom: 10px; text-align: center;"></span><br><span class=\"line\"> <a href="jie/add.html" class="layui-btn">发表新帖</a></span><br><span class=\"line\"> </div></span><br><span class=\"line\"> </div></span><br><span class=\"line\"></div></span><br></pre></td></tr></table></figure>","site":{"data":{}},"excerpt":"","more":"<h2 id=\"5-项目启动前预加载导航栏\"><a href=\"#5-项目启动前预加载导航栏\" class=\"headerlink\" title=\"5. 项目启动前预加载导航栏\"></a>5. 项目启动前预加载导航栏</h2><h3 id=\"5-1-ContextStartup-配置类\"><a href=\"#5-1-ContextStartup-配置类\" class=\"headerlink\" title=\"5.1 ContextStartup 配置类\"></a>5.1 <code>ContextStartup</code> 配置类</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Context配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:提前加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"5-2-使用\"><a href=\"#5-2-使用\" class=\"headerlink\" title=\"5.2 使用\"></a>5.2 使用</h3><figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><#--【二、分类】--></span><br><span class=\"line\"><div class="fly-panel fly-column"></span><br><span class=\"line\"> <div class="layui-container"></span><br><span class=\"line\"> <ul class="layui-clear"></span><br><span class=\"line\"></span><br><span class=\"line\"> <#--首页--></span><br><span class=\"line\"> <li class="${(0 == currentCategoryId)?string('layui-hide-xs layui-this', '')}"><a href="/">首页</a></li></span><br><span class=\"line\"> <#--提问、分享、讨论、建议--></span><br><span class=\"line\"> <#list categorys as item></span><br><span class=\"line\"> <li class="${(item.id == currentCategoryId)?string('layui-hide-xs layui-this', '')}"><a href="/category/${item.id}">${item.name}</a></li></span><br><span class=\"line\"> </#list></span><br><span class=\"line\"></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><span class="fly-mid"></span></li></span><br><span class=\"line\"> <!-- 用户登入后显示 --></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><a href="user/index.html">我发表的贴</a></li></span><br><span class=\"line\"> <li class="layui-hide-xs layui-hide-sm layui-show-md-inline-block"><a href="user/index.html#collection">我收藏的贴</a></span><br><span class=\"line\"> </li></span><br><span class=\"line\"> </ul></span><br><span class=\"line\"></span><br><span class=\"line\"> <div class="fly-column-right layui-hide-xs"></span><br><span class=\"line\"> <span class="fly-search"><i class="layui-icon"></i></span></span><br><span class=\"line\"> <a href="jie/add.html" class="layui-btn">发表新帖</a></span><br><span class=\"line\"> </div></span><br><span class=\"line\"> <div class="layui-hide-sm layui-show-xs-block"</span><br><span class=\"line\"> style="margin-top: -10px; padding-bottom: 10px; text-align: center;"></span><br><span class=\"line\"> <a href="jie/add.html" class="layui-btn">发表新帖</a></span><br><span class=\"line\"> </div></span><br><span class=\"line\"> </div></span><br><span class=\"line\"></div></span><br></pre></td></tr></table></figure>"},{"title":"6. 集成 Redis 实现本周热议","date":"2020-03-19T06:59:53.000Z","_content":"\n## 6. 集成 Redis 实现本周热议\n### 6.1 环境搭建\n- 添加 redis 依赖,使用 utils 包下的 RedisUtil 对内置 RedisTemplate 进行封装\n- 添加 hutool 依赖,使用 DateUtil 类中的 offsetDay()、format()\n- 考虑到 redis 序列化后出现乱码问题,使用 RedisConfig 配置类进行编码的处理\n```xml\n<dependencies>\n <!--Redis-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-data-redis</artifactId>\n </dependency>\n\n <!--hutool:工具包,例如DateUtils工具类...-->\n <dependency>\n <groupId>cn.hutool</groupId>\n <artifactId>hutool-all</artifactId>\n <version>4.1.17</version>\n </dependency>\n</dependencies>\n```\n```java\n/**\n * 指定Redis的序列化后的格式\n */\n@Configuration\npublic class RedisConfig {\n\n @Bean\n public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {\n RedisTemplate<Object, Object> template = new RedisTemplate();\n template.setConnectionFactory(redisConnectionFactory);\n\n Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);\n jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());\n\n template.setKeySerializer(new StringRedisSerializer());\n template.setValueSerializer(jackson2JsonRedisSerializer);\n\n template.setHashKeySerializer(new StringRedisSerializer());\n template.setHashValueSerializer(jackson2JsonRedisSerializer);\n\n return template;\n }\n\n}\n```\n\n### 6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现\n- 缓存热评文章——哈希表 Hash\n- 评论数量排行——有序列表 sortedSet:ZADD(添加)、ZREVRANGE(展示)、ZUNIONSTORE(并集)\n - ZADD key score member [[score member] [score member] ...] \n ```\n 127.0.0.1:6379> ZADD day:18 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:19 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:20 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:21 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:22 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:23 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:24 10 post:1 6 post:2 4 post:3\n (integer) 3\n ```\n - ZREVRANGE key start stop [WITHSCORES]\n ```\n 127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores\n 1) \"post:1\"\n 2) \"10\"\n 3) \"post:2\"\n 4) \"6\"\n 5) \"post:3\"\n 6) \"4\"\n ```\n - ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]\n ```\n 127.0.0.1:6379> ZUNIONSTORE week:rank 7 day:18 day:19 day:20 day:21 day:22 day:23 day:24\n 1) \"post:1\"\n 2) \"post:2\"\n ```\n - 查看排行榜\n ```\n 127.0.0.1:6379> ZREVRANGE week:rank 0 -1 withscores\n 1) \"post:1\"\n 2) \"70\"\n 3) \"post:2\"\n 4) \"42\"\n 5) \"post:3\"\n 6) \"28\"\n ```\n - 添加/删除评论\n ```\n 127.0.0.1:6379> ZINCRBY day:18 10 post:1\n \"20\"\n 127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores\n 1) \"post:1\"\n 2) \"20\"\n 3) \"post:2\"\n 4) \"6\"\n 5) \"post:3\"\n 6) \"4\"\n 127.0.0.1:6379> ZINCRBY day:18 -10 post:1\n \"10\"\n ```\n \n### 6.3 本周热议的【初始化操作】\n- 项目启动前,获取【近 7 天文章】\n- 初始化【近 7 天文章】的总评论量(先使用 SortedSet 集合对【排行榜 7 天内全部文章】进行 zadd 操作,并设置它们 expire 为 7 天;再使用 Hash 哈希表对【排行榜 7 天内全部文章】进行 hexists 判断,再 hset 缓存操作)\n - 添加 add——将【近 7 天文章】创建日期时间作为 key 值,每篇文章对应的 id 作为它的 value 值,每篇文章对应的评论 comment 作为它的 score 值,并使用 redis 的工具类(RedisUtil),对文章的具体属性进行 zSet()缓存操作\n - 过期 expire——让【近 7 天文章】的 key 过期: 7-(当前时间-创建时间)= 过期时间\n - 缓存——缓存【近 7 天文章】的一些基本信息,例如文章 id,标题 title,评论数量,作者信息...方便访问【近 7 天文章】时,直接 redis,而非 MySQL\n - 先对文章进行 EXISTS 判断其缓存是否存在\n - 如果 false 不存在,则再 hset 缓存操作\n- 对【近 7 天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n```java\n/**\n * Context配置类\n */\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n @Autowired\n PostService postService;\n\n /**\n * 项目启动时,会同时调用该run方法:\n *\n * 加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n * 加载本周热议\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n\n postService.initWeekRank();\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n}\n```\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n\n @Autowired\n RedisUtil redisUtil;\n\n /**\n * 项目启动前,初始化本周热议(近7天全部文章评论量的排行榜)\n */\n @Override\n public void initWeekRank() {\n //1.获取【近7天文章】\n List<Post> posts = this.list(new QueryWrapper<Post>()\n .gt(\"created\", DateUtil.offsetDay(new Date(), -6)) //根据created时间,对最近7天内的文章进行筛选\n .select(\"id, title, user_id, comment_count, view_count, created\") //对文章的属性进行筛选,加快查询速率\n );\n\n //2.初始化【近7天文章】的总评论量(先使用SortedSet集合对【排行榜7天内全部文章】进行zadd操作,并设置它们expire为7天;再使用Hash哈希表对【排行榜7天内全部文章】进行hexists判断,再hset缓存操作)\n for (Post post : posts) {\n //1.添加add——|day:rank:20210202--0208|,将【近7天文章】创建日期时间作为key值,每篇文章对应的id作为它的value值,每篇文章对应的评论comment作为它的score值,并使用redis的工具类(RedisUtil),对文章的具体属性进行zSet()缓存操作\n String zKey = \"day:rank:\" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);\n redisUtil.zSet(zKey, post.getId(), post.getCommentCount());//阅读redisUtil工具类,可知zSet等同于zadd\n\n //2.过期expire——|day:rank:20210202--0208|,让【近7天文章】的key过期: 7-(当前时间-创建时间)= 过期时间\n long expireTime = (7 - DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY)) * 24 * 60 * 60;\n redisUtil.expire(zKey, expireTime);\n\n //3.缓存——|day:rank:post:1~16|,缓存【近7天文章】的一些基本信息,例如文章id,标题title,评论数量,作者信息...方便访问【近7天文章】时,直接redis,而非MySQL\n //3.1先对文章进行EXISTS判断其缓存是否存在\n String hKey = \"day:rank:post:\" + post.getId();\n if (!redisUtil.hasKey(hKey)) {\n //3.2如果false不存在,则再hset缓存操作\n redisUtil.hset(hKey, \"post-id\", post.getId(), expireTime);\n redisUtil.hset(hKey, \"post-title\", post.getTitle(), expireTime);\n redisUtil.hset(hKey, \"post-commentCount\", post.getCommentCount(), expireTime);\n redisUtil.hset(hKey, \"post-viewCount\", post.getViewCount(), expireTime);\n }\n }\n\n //3.对【近7天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n String currentKey = \"day:rank:\" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);\n List<String> otherKeys = new ArrayList<>();\n for (int i = -6; i < 0; i++) {\n String temp = \"day:rank:\" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);\n otherKeys.add(temp);\n }\n String destKey = \"week:rank\";\n redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);\n }\n}\n```\n\n### 6.4 本周热议的【初始化操作】:自定义标签【hots】\n```java\n/**\n * 本周热议\n */\n@Component\npublic class HotsTemplate extends TemplateDirective {\n\n @Autowired\n RedisUtil redisUtil;\n\n @Override\n public String getName() {\n return \"hots\";\n }\n\n @Override\n public void execute(DirectiveHandler handler) throws Exception {\n List<Map> hostPost = new ArrayList<>();\n\n // 获取有序集 key 中成员 member 的排名,其中有序集成员按 score 值递减 (从大到小) 排序\n Set<ZSetOperations.TypedTuple> typedTuples = redisUtil.getZSetRank(\"week:rank\", 0, 6);\n for (ZSetOperations.TypedTuple typedTuple : typedTuples) {\n Map<String, Object> map = new HashMap<>();\n\n //zSet(key, value, score) -> zSet(文章日期, 文章id, 文章评论数commentCount),此处取出zSet中的value,即文章id\n String postHashKey = \"day:rank:post:\" + typedTuple.getValue();\n\n map.put(\"id\", redisUtil.hget(postHashKey, \"post-id\"));\n map.put(\"title\", redisUtil.hget(postHashKey, \"post-title\"));\n map.put(\"commentCount\", redisUtil.hget(postHashKey, \"post-commentCount\"));\n map.put(\"viewCount\", redisUtil.hget(postHashKey, \"post-viewCount\"));\n\n hostPost.add(map);\n }\n\n handler.put(RESULTS, hostPost).render();\n }\n}\n```\n```java\n/**\n * Freemarker配置类\n */\n@Configuration\npublic class FreemarkerConfig {\n\n @Autowired\n private freemarker.template.Configuration configuration;\n\n @Autowired\n TimeAgoMethod timeAgoMethod;\n\n @Autowired\n PostsTemplate postsTemplate;\n\n @Autowired\n HotsTemplate hotsTemplate;\n\n /**\n * 注册为“timeAgo”函数:快速实现日期转换\n * 注册为“posts”函数:快速实现分页\n * 注册为\"hots\"函数:快速实现本周热议\n */\n @PostConstruct\n public void setUp() {\n configuration.setSharedVariable(\"timeAgo\", timeAgoMethod);\n configuration.setSharedVariable(\"details\", postsTemplate);\n configuration.setSharedVariable(\"hots\", hotsTemplate);\n }\n}\n```\n\n### 6.4 本周热议的【更新操作】\n- 自增/自减评论数\n- 更新这篇文章的缓存时间,并更新这篇文章的基本信息\n- 对【近 7 天文章】重新做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n\n @Autowired\n RedisUtil redisUtil;\n\n /**\n * 本周热议:增加评论后,通过自增/自减评论数、再对排行榜做并集运算\n */\n @Override\n public void incrCommentCountAndUnionForWeekRank(Post post, boolean isIncr) {\n //1.自增/自减评论数\n String currentKey = \"day:rank:\" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);\n redisUtil.zIncrementScore(currentKey, post.getId(), isIncr ? 1 : -1);\n\n //2.更新这篇文章的缓存时间,并更新这篇文章的基本信息\n String zKey = \"day:rank:\" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);\n long expireTime = (7 - DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY)) * 24 * 60 * 60;\n redisUtil.expire(zKey, expireTime);\n String hKey = \"day:rank:post:\" + post.getId();\n if (!redisUtil.hasKey(hKey)) {\n //3.2如果false不存在,则再hset缓存操作\n redisUtil.hset(hKey, \"post-id\", post.getId(), expireTime);\n redisUtil.hset(hKey, \"post-title\", post.getTitle(), expireTime);\n redisUtil.hset(hKey, \"post-commentCount\", post.getCommentCount(), expireTime);\n redisUtil.hset(hKey, \"post-viewCount\", post.getViewCount(), expireTime);\n }\n\n //3.对【近7天文章】重新做并集运算(zUnionAndStore)\n List<String> otherKeys = new ArrayList<>();\n for (int i = -6; i < 0; i++) {\n String temp = \"day:rank:\" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);\n otherKeys.add(temp);\n }\n String destKey = \"week:rank\";\n redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);\n }\n}\n```","source":"_posts/Part06-集成 Redis 实现本周热议.md","raw":"---\ntitle: 6. 集成 Redis 实现本周热议\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 6. 集成 Redis 实现本周热议\n### 6.1 环境搭建\n- 添加 redis 依赖,使用 utils 包下的 RedisUtil 对内置 RedisTemplate 进行封装\n- 添加 hutool 依赖,使用 DateUtil 类中的 offsetDay()、format()\n- 考虑到 redis 序列化后出现乱码问题,使用 RedisConfig 配置类进行编码的处理\n```xml\n<dependencies>\n <!--Redis-->\n <dependency>\n <groupId>org.springframework.boot</groupId>\n <artifactId>spring-boot-starter-data-redis</artifactId>\n </dependency>\n\n <!--hutool:工具包,例如DateUtils工具类...-->\n <dependency>\n <groupId>cn.hutool</groupId>\n <artifactId>hutool-all</artifactId>\n <version>4.1.17</version>\n </dependency>\n</dependencies>\n```\n```java\n/**\n * 指定Redis的序列化后的格式\n */\n@Configuration\npublic class RedisConfig {\n\n @Bean\n public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {\n RedisTemplate<Object, Object> template = new RedisTemplate();\n template.setConnectionFactory(redisConnectionFactory);\n\n Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);\n jackson2JsonRedisSerializer.setObjectMapper(new ObjectMapper());\n\n template.setKeySerializer(new StringRedisSerializer());\n template.setValueSerializer(jackson2JsonRedisSerializer);\n\n template.setHashKeySerializer(new StringRedisSerializer());\n template.setHashValueSerializer(jackson2JsonRedisSerializer);\n\n return template;\n }\n\n}\n```\n\n### 6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现\n- 缓存热评文章——哈希表 Hash\n- 评论数量排行——有序列表 sortedSet:ZADD(添加)、ZREVRANGE(展示)、ZUNIONSTORE(并集)\n - ZADD key score member [[score member] [score member] ...] \n ```\n 127.0.0.1:6379> ZADD day:18 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:19 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:20 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:21 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:22 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:23 10 post:1 6 post:2 4 post:3\n (integer) 3\n 127.0.0.1:6379> ZADD day:24 10 post:1 6 post:2 4 post:3\n (integer) 3\n ```\n - ZREVRANGE key start stop [WITHSCORES]\n ```\n 127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores\n 1) \"post:1\"\n 2) \"10\"\n 3) \"post:2\"\n 4) \"6\"\n 5) \"post:3\"\n 6) \"4\"\n ```\n - ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]\n ```\n 127.0.0.1:6379> ZUNIONSTORE week:rank 7 day:18 day:19 day:20 day:21 day:22 day:23 day:24\n 1) \"post:1\"\n 2) \"post:2\"\n ```\n - 查看排行榜\n ```\n 127.0.0.1:6379> ZREVRANGE week:rank 0 -1 withscores\n 1) \"post:1\"\n 2) \"70\"\n 3) \"post:2\"\n 4) \"42\"\n 5) \"post:3\"\n 6) \"28\"\n ```\n - 添加/删除评论\n ```\n 127.0.0.1:6379> ZINCRBY day:18 10 post:1\n \"20\"\n 127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores\n 1) \"post:1\"\n 2) \"20\"\n 3) \"post:2\"\n 4) \"6\"\n 5) \"post:3\"\n 6) \"4\"\n 127.0.0.1:6379> ZINCRBY day:18 -10 post:1\n \"10\"\n ```\n \n### 6.3 本周热议的【初始化操作】\n- 项目启动前,获取【近 7 天文章】\n- 初始化【近 7 天文章】的总评论量(先使用 SortedSet 集合对【排行榜 7 天内全部文章】进行 zadd 操作,并设置它们 expire 为 7 天;再使用 Hash 哈希表对【排行榜 7 天内全部文章】进行 hexists 判断,再 hset 缓存操作)\n - 添加 add——将【近 7 天文章】创建日期时间作为 key 值,每篇文章对应的 id 作为它的 value 值,每篇文章对应的评论 comment 作为它的 score 值,并使用 redis 的工具类(RedisUtil),对文章的具体属性进行 zSet()缓存操作\n - 过期 expire——让【近 7 天文章】的 key 过期: 7-(当前时间-创建时间)= 过期时间\n - 缓存——缓存【近 7 天文章】的一些基本信息,例如文章 id,标题 title,评论数量,作者信息...方便访问【近 7 天文章】时,直接 redis,而非 MySQL\n - 先对文章进行 EXISTS 判断其缓存是否存在\n - 如果 false 不存在,则再 hset 缓存操作\n- 对【近 7 天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n```java\n/**\n * Context配置类\n */\n@Component\npublic class ContextStartup implements ApplicationRunner, ServletContextAware {\n\n @Autowired\n CategoryService categoryService;\n\n ServletContext servletContext;\n\n @Autowired\n PostService postService;\n\n /**\n * 项目启动时,会同时调用该run方法:\n *\n * 加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象\n * 加载本周热议\n */\n @Override\n public void run(ApplicationArguments args) throws Exception {\n List<Category> categories = categoryService.list(new QueryWrapper<Category>()\n .eq(\"status\", 0)\n );\n servletContext.setAttribute(\"categorys\", categories);\n\n postService.initWeekRank();\n }\n\n /**\n * servletContext上下文对象\n */\n @Override\n public void setServletContext(ServletContext servletContext) {\n this.servletContext = servletContext;\n }\n}\n```\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n\n @Autowired\n RedisUtil redisUtil;\n\n /**\n * 项目启动前,初始化本周热议(近7天全部文章评论量的排行榜)\n */\n @Override\n public void initWeekRank() {\n //1.获取【近7天文章】\n List<Post> posts = this.list(new QueryWrapper<Post>()\n .gt(\"created\", DateUtil.offsetDay(new Date(), -6)) //根据created时间,对最近7天内的文章进行筛选\n .select(\"id, title, user_id, comment_count, view_count, created\") //对文章的属性进行筛选,加快查询速率\n );\n\n //2.初始化【近7天文章】的总评论量(先使用SortedSet集合对【排行榜7天内全部文章】进行zadd操作,并设置它们expire为7天;再使用Hash哈希表对【排行榜7天内全部文章】进行hexists判断,再hset缓存操作)\n for (Post post : posts) {\n //1.添加add——|day:rank:20210202--0208|,将【近7天文章】创建日期时间作为key值,每篇文章对应的id作为它的value值,每篇文章对应的评论comment作为它的score值,并使用redis的工具类(RedisUtil),对文章的具体属性进行zSet()缓存操作\n String zKey = \"day:rank:\" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);\n redisUtil.zSet(zKey, post.getId(), post.getCommentCount());//阅读redisUtil工具类,可知zSet等同于zadd\n\n //2.过期expire——|day:rank:20210202--0208|,让【近7天文章】的key过期: 7-(当前时间-创建时间)= 过期时间\n long expireTime = (7 - DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY)) * 24 * 60 * 60;\n redisUtil.expire(zKey, expireTime);\n\n //3.缓存——|day:rank:post:1~16|,缓存【近7天文章】的一些基本信息,例如文章id,标题title,评论数量,作者信息...方便访问【近7天文章】时,直接redis,而非MySQL\n //3.1先对文章进行EXISTS判断其缓存是否存在\n String hKey = \"day:rank:post:\" + post.getId();\n if (!redisUtil.hasKey(hKey)) {\n //3.2如果false不存在,则再hset缓存操作\n redisUtil.hset(hKey, \"post-id\", post.getId(), expireTime);\n redisUtil.hset(hKey, \"post-title\", post.getTitle(), expireTime);\n redisUtil.hset(hKey, \"post-commentCount\", post.getCommentCount(), expireTime);\n redisUtil.hset(hKey, \"post-viewCount\", post.getViewCount(), expireTime);\n }\n }\n\n //3.对【近7天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n String currentKey = \"day:rank:\" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);\n List<String> otherKeys = new ArrayList<>();\n for (int i = -6; i < 0; i++) {\n String temp = \"day:rank:\" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);\n otherKeys.add(temp);\n }\n String destKey = \"week:rank\";\n redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);\n }\n}\n```\n\n### 6.4 本周热议的【初始化操作】:自定义标签【hots】\n```java\n/**\n * 本周热议\n */\n@Component\npublic class HotsTemplate extends TemplateDirective {\n\n @Autowired\n RedisUtil redisUtil;\n\n @Override\n public String getName() {\n return \"hots\";\n }\n\n @Override\n public void execute(DirectiveHandler handler) throws Exception {\n List<Map> hostPost = new ArrayList<>();\n\n // 获取有序集 key 中成员 member 的排名,其中有序集成员按 score 值递减 (从大到小) 排序\n Set<ZSetOperations.TypedTuple> typedTuples = redisUtil.getZSetRank(\"week:rank\", 0, 6);\n for (ZSetOperations.TypedTuple typedTuple : typedTuples) {\n Map<String, Object> map = new HashMap<>();\n\n //zSet(key, value, score) -> zSet(文章日期, 文章id, 文章评论数commentCount),此处取出zSet中的value,即文章id\n String postHashKey = \"day:rank:post:\" + typedTuple.getValue();\n\n map.put(\"id\", redisUtil.hget(postHashKey, \"post-id\"));\n map.put(\"title\", redisUtil.hget(postHashKey, \"post-title\"));\n map.put(\"commentCount\", redisUtil.hget(postHashKey, \"post-commentCount\"));\n map.put(\"viewCount\", redisUtil.hget(postHashKey, \"post-viewCount\"));\n\n hostPost.add(map);\n }\n\n handler.put(RESULTS, hostPost).render();\n }\n}\n```\n```java\n/**\n * Freemarker配置类\n */\n@Configuration\npublic class FreemarkerConfig {\n\n @Autowired\n private freemarker.template.Configuration configuration;\n\n @Autowired\n TimeAgoMethod timeAgoMethod;\n\n @Autowired\n PostsTemplate postsTemplate;\n\n @Autowired\n HotsTemplate hotsTemplate;\n\n /**\n * 注册为“timeAgo”函数:快速实现日期转换\n * 注册为“posts”函数:快速实现分页\n * 注册为\"hots\"函数:快速实现本周热议\n */\n @PostConstruct\n public void setUp() {\n configuration.setSharedVariable(\"timeAgo\", timeAgoMethod);\n configuration.setSharedVariable(\"details\", postsTemplate);\n configuration.setSharedVariable(\"hots\", hotsTemplate);\n }\n}\n```\n\n### 6.4 本周热议的【更新操作】\n- 自增/自减评论数\n- 更新这篇文章的缓存时间,并更新这篇文章的基本信息\n- 对【近 7 天文章】重新做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n\n @Autowired\n RedisUtil redisUtil;\n\n /**\n * 本周热议:增加评论后,通过自增/自减评论数、再对排行榜做并集运算\n */\n @Override\n public void incrCommentCountAndUnionForWeekRank(Post post, boolean isIncr) {\n //1.自增/自减评论数\n String currentKey = \"day:rank:\" + DateUtil.format(new Date(), DatePattern.PURE_DATE_FORMAT);\n redisUtil.zIncrementScore(currentKey, post.getId(), isIncr ? 1 : -1);\n\n //2.更新这篇文章的缓存时间,并更新这篇文章的基本信息\n String zKey = \"day:rank:\" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);\n long expireTime = (7 - DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY)) * 24 * 60 * 60;\n redisUtil.expire(zKey, expireTime);\n String hKey = \"day:rank:post:\" + post.getId();\n if (!redisUtil.hasKey(hKey)) {\n //3.2如果false不存在,则再hset缓存操作\n redisUtil.hset(hKey, \"post-id\", post.getId(), expireTime);\n redisUtil.hset(hKey, \"post-title\", post.getTitle(), expireTime);\n redisUtil.hset(hKey, \"post-commentCount\", post.getCommentCount(), expireTime);\n redisUtil.hset(hKey, \"post-viewCount\", post.getViewCount(), expireTime);\n }\n\n //3.对【近7天文章】重新做并集运算(zUnionAndStore)\n List<String> otherKeys = new ArrayList<>();\n for (int i = -6; i < 0; i++) {\n String temp = \"day:rank:\" + DateUtil.format(DateUtil.offsetDay(new Date(), i), DatePattern.PURE_DATE_FORMAT);\n otherKeys.add(temp);\n }\n String destKey = \"week:rank\";\n redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);\n }\n}\n```","slug":"Part06-集成 Redis 实现本周热议","published":1,"updated":"2022-03-29T02:31:48.688Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h3h000dpowv8kcih81d","content":"<h2 id=\"6-集成-Redis-实现本周热议\"><a href=\"#6-集成-Redis-实现本周热议\" class=\"headerlink\" title=\"6. 集成 Redis 实现本周热议\"></a>6. 集成 Redis 实现本周热议</h2><h3 id=\"6-1-环境搭建\"><a href=\"#6-1-环境搭建\" class=\"headerlink\" title=\"6.1 环境搭建\"></a>6.1 环境搭建</h3><ul>\n<li>添加 redis 依赖,使用 utils 包下的 RedisUtil 对内置 RedisTemplate 进行封装</li>\n<li>添加 hutool 依赖,使用 DateUtil 类中的 offsetDay()、format()</li>\n<li>考虑到 redis 序列化后出现乱码问题,使用 RedisConfig 配置类进行编码的处理<figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"tag\"><<span class=\"name\">dependencies</span>></span></span><br><span class=\"line\"> <span class=\"comment\"><!--Redis--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-data-redis<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--hutool:工具包,例如DateUtils工具类...--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>cn.hutool<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>hutool-all<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>4.1.17<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"tag\"></<span class=\"name\">dependencies</span>></span></span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 指定Redis的序列化后的格式</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">RedisConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Bean</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> RedisTemplate <span class=\"title function_\">redisTemplate</span><span class=\"params\">(RedisConnectionFactory redisConnectionFactory)</span> {</span><br><span class=\"line\"> RedisTemplate<Object, Object> template = <span class=\"keyword\">new</span> <span class=\"title class_\">RedisTemplate</span>();</span><br><span class=\"line\"> template.setConnectionFactory(redisConnectionFactory);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">Jackson2JsonRedisSerializer</span> <span class=\"variable\">jackson2JsonRedisSerializer</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">Jackson2JsonRedisSerializer</span>(Object.class);</span><br><span class=\"line\"> jackson2JsonRedisSerializer.setObjectMapper(<span class=\"keyword\">new</span> <span class=\"title class_\">ObjectMapper</span>());</span><br><span class=\"line\"></span><br><span class=\"line\"> template.setKeySerializer(<span class=\"keyword\">new</span> <span class=\"title class_\">StringRedisSerializer</span>());</span><br><span class=\"line\"> template.setValueSerializer(jackson2JsonRedisSerializer);</span><br><span class=\"line\"></span><br><span class=\"line\"> template.setHashKeySerializer(<span class=\"keyword\">new</span> <span class=\"title class_\">StringRedisSerializer</span>());</span><br><span class=\"line\"> template.setHashValueSerializer(jackson2JsonRedisSerializer);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> template;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"6-2-本周热议的【基本原理】:利用-Redis-的-zet-有序集合实现\"><a href=\"#6-2-本周热议的【基本原理】:利用-Redis-的-zet-有序集合实现\" class=\"headerlink\" title=\"6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现\"></a>6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现</h3><ul>\n<li>缓存热评文章——哈希表 Hash</li>\n<li>评论数量排行——有序列表 sortedSet:ZADD(添加)、ZREVRANGE(展示)、ZUNIONSTORE(并集)<ul>\n<li>ZADD key score member [[score member] [score member] …] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZADD day:18 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:19 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:20 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:21 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:22 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:23 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:24 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br></pre></td></tr></table></figure></li>\n<li>ZREVRANGE key start stop [WITHSCORES] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "10"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "6"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "4"</span><br></pre></td></tr></table></figure></li>\n<li>ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZUNIONSTORE week:rank 7 day:18 day:19 day:20 day:21 day:22 day:23 day:24</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "post:2"</span><br></pre></td></tr></table></figure></li>\n<li>查看排行榜 <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZREVRANGE week:rank 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "70"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "42"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "28"</span><br></pre></td></tr></table></figure></li>\n<li>添加/删除评论 <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZINCRBY day:18 10 post:1</span><br><span class=\"line\">"20"</span><br><span class=\"line\">127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "20"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "6"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "4"</span><br><span class=\"line\">127.0.0.1:6379> ZINCRBY day:18 -10 post:1</span><br><span class=\"line\">"10"</span><br></pre></td></tr></table></figure></li>\n</ul>\n</li>\n</ul>\n<h3 id=\"6-3-本周热议的【初始化操作】\"><a href=\"#6-3-本周热议的【初始化操作】\" class=\"headerlink\" title=\"6.3 本周热议的【初始化操作】\"></a>6.3 本周热议的【初始化操作】</h3><ul>\n<li>项目启动前,获取【近 7 天文章】</li>\n<li>初始化【近 7 天文章】的总评论量(先使用 SortedSet 集合对【排行榜 7 天内全部文章】进行 zadd 操作,并设置它们 expire 为 7 天;再使用 Hash 哈希表对【排行榜 7 天内全部文章】进行 hexists 判断,再 hset 缓存操作)<ul>\n<li>添加 add——将【近 7 天文章】创建日期时间作为 key 值,每篇文章对应的 id 作为它的 value 值,每篇文章对应的评论 comment 作为它的 score 值,并使用 redis 的工具类(RedisUtil),对文章的具体属性进行 zSet()缓存操作</li>\n<li>过期 expire——让【近 7 天文章】的 key 过期: 7-(当前时间-创建时间)= 过期时间</li>\n<li>缓存——缓存【近 7 天文章】的一些基本信息,例如文章 id,标题 title,评论数量,作者信息…方便访问【近 7 天文章】时,直接 redis,而非 MySQL<ul>\n<li>先对文章进行 EXISTS 判断其缓存是否存在</li>\n<li>如果 false 不存在,则再 hset 缓存操作</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>对【近 7 天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Context配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostService postService;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:</span></span><br><span class=\"line\"><span class=\"comment\"> *</span></span><br><span class=\"line\"><span class=\"comment\"> * 加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> * 加载本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"></span><br><span class=\"line\"> postService.initWeekRank();</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动前,初始化本周热议(近7天全部文章评论量的排行榜)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">initWeekRank</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.获取【近7天文章】</span></span><br><span class=\"line\"> List<Post> posts = <span class=\"built_in\">this</span>.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>()</span><br><span class=\"line\"> .gt(<span class=\"string\">"created"</span>, DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), -<span class=\"number\">6</span>)) <span class=\"comment\">//根据created时间,对最近7天内的文章进行筛选</span></span><br><span class=\"line\"> .select(<span class=\"string\">"id, title, user_id, comment_count, view_count, created"</span>) <span class=\"comment\">//对文章的属性进行筛选,加快查询速率</span></span><br><span class=\"line\"> );</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.初始化【近7天文章】的总评论量(先使用SortedSet集合对【排行榜7天内全部文章】进行zadd操作,并设置它们expire为7天;再使用Hash哈希表对【排行榜7天内全部文章】进行hexists判断,再hset缓存操作)</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Post post : posts) {</span><br><span class=\"line\"> <span class=\"comment\">//1.添加add——|day:rank:20210202--0208|,将【近7天文章】创建日期时间作为key值,每篇文章对应的id作为它的value值,每篇文章对应的评论comment作为它的score值,并使用redis的工具类(RedisUtil),对文章的具体属性进行zSet()缓存操作</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">zKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> redisUtil.zSet(zKey, post.getId(), post.getCommentCount());<span class=\"comment\">//阅读redisUtil工具类,可知zSet等同于zadd</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.过期expire——|day:rank:20210202--0208|,让【近7天文章】的key过期: 7-(当前时间-创建时间)= 过期时间</span></span><br><span class=\"line\"> <span class=\"type\">long</span> <span class=\"variable\">expireTime</span> <span class=\"operator\">=</span> (<span class=\"number\">7</span> - DateUtil.between(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), post.getCreated(), DateUnit.DAY)) * <span class=\"number\">24</span> * <span class=\"number\">60</span> * <span class=\"number\">60</span>;</span><br><span class=\"line\"> redisUtil.expire(zKey, expireTime);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.缓存——|day:rank:post:1~16|,缓存【近7天文章】的一些基本信息,例如文章id,标题title,评论数量,作者信息...方便访问【近7天文章】时,直接redis,而非MySQL</span></span><br><span class=\"line\"> <span class=\"comment\">//3.1先对文章进行EXISTS判断其缓存是否存在</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + post.getId();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!redisUtil.hasKey(hKey)) {</span><br><span class=\"line\"> <span class=\"comment\">//3.2如果false不存在,则再hset缓存操作</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-id"</span>, post.getId(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-title"</span>, post.getTitle(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-commentCount"</span>, post.getCommentCount(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, post.getViewCount(), expireTime);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.对【近7天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">currentKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> List<String> otherKeys = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> <span class=\"variable\">i</span> <span class=\"operator\">=</span> -<span class=\"number\">6</span>; i < <span class=\"number\">0</span>; i++) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">temp</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), i), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> otherKeys.add(temp);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">destKey</span> <span class=\"operator\">=</span> <span class=\"string\">"week:rank"</span>;</span><br><span class=\"line\"> redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"6-4-本周热议的【初始化操作】:自定义标签【hots】\"><a href=\"#6-4-本周热议的【初始化操作】:自定义标签【hots】\" class=\"headerlink\" title=\"6.4 本周热议的【初始化操作】:自定义标签【hots】\"></a>6.4 本周热议的【初始化操作】:自定义标签【hots】</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">HotsTemplate</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateDirective</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">getName</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"hots"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">execute</span><span class=\"params\">(DirectiveHandler handler)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Map> hostPost = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 获取有序集 key 中成员 member 的排名,其中有序集成员按 score 值递减 (从大到小) 排序</span></span><br><span class=\"line\"> Set<ZSetOperations.TypedTuple> typedTuples = redisUtil.getZSetRank(<span class=\"string\">"week:rank"</span>, <span class=\"number\">0</span>, <span class=\"number\">6</span>);</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (ZSetOperations.TypedTuple typedTuple : typedTuples) {</span><br><span class=\"line\"> Map<String, Object> map = <span class=\"keyword\">new</span> <span class=\"title class_\">HashMap</span><>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//zSet(key, value, score) -> zSet(文章日期, 文章id, 文章评论数commentCount),此处取出zSet中的value,即文章id</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">postHashKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + typedTuple.getValue();</span><br><span class=\"line\"></span><br><span class=\"line\"> map.put(<span class=\"string\">"id"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-id"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"title"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-title"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"commentCount"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-commentCount"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"viewCount"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-viewCount"</span>));</span><br><span class=\"line\"></span><br><span class=\"line\"> hostPost.add(map);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> handler.put(RESULTS, hostPost).render();</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Freemarker配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">FreemarkerConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> <span class=\"keyword\">private</span> freemarker.template.Configuration configuration;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> TimeAgoMethod timeAgoMethod;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostsTemplate postsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> HotsTemplate hotsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“timeAgo”函数:快速实现日期转换</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“posts”函数:快速实现分页</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为"hots"函数:快速实现本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@PostConstruct</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setUp</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"timeAgo"</span>, timeAgoMethod);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"details"</span>, postsTemplate);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"hots"</span>, hotsTemplate);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"6-4-本周热议的【更新操作】\"><a href=\"#6-4-本周热议的【更新操作】\" class=\"headerlink\" title=\"6.4 本周热议的【更新操作】\"></a>6.4 本周热议的【更新操作】</h3><ul>\n<li>自增/自减评论数</li>\n<li>更新这篇文章的缓存时间,并更新这篇文章的基本信息</li>\n<li>对【近 7 天文章】重新做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 本周热议:增加评论后,通过自增/自减评论数、再对排行榜做并集运算</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">incrCommentCountAndUnionForWeekRank</span><span class=\"params\">(Post post, <span class=\"type\">boolean</span> isIncr)</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.自增/自减评论数</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">currentKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> redisUtil.zIncrementScore(currentKey, post.getId(), isIncr ? <span class=\"number\">1</span> : -<span class=\"number\">1</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.更新这篇文章的缓存时间,并更新这篇文章的基本信息</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">zKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> <span class=\"type\">long</span> <span class=\"variable\">expireTime</span> <span class=\"operator\">=</span> (<span class=\"number\">7</span> - DateUtil.between(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), post.getCreated(), DateUnit.DAY)) * <span class=\"number\">24</span> * <span class=\"number\">60</span> * <span class=\"number\">60</span>;</span><br><span class=\"line\"> redisUtil.expire(zKey, expireTime);</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + post.getId();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!redisUtil.hasKey(hKey)) {</span><br><span class=\"line\"> <span class=\"comment\">//3.2如果false不存在,则再hset缓存操作</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-id"</span>, post.getId(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-title"</span>, post.getTitle(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-commentCount"</span>, post.getCommentCount(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, post.getViewCount(), expireTime);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.对【近7天文章】重新做并集运算(zUnionAndStore)</span></span><br><span class=\"line\"> List<String> otherKeys = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> <span class=\"variable\">i</span> <span class=\"operator\">=</span> -<span class=\"number\">6</span>; i < <span class=\"number\">0</span>; i++) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">temp</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), i), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> otherKeys.add(temp);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">destKey</span> <span class=\"operator\">=</span> <span class=\"string\">"week:rank"</span>;</span><br><span class=\"line\"> redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"6-集成-Redis-实现本周热议\"><a href=\"#6-集成-Redis-实现本周热议\" class=\"headerlink\" title=\"6. 集成 Redis 实现本周热议\"></a>6. 集成 Redis 实现本周热议</h2><h3 id=\"6-1-环境搭建\"><a href=\"#6-1-环境搭建\" class=\"headerlink\" title=\"6.1 环境搭建\"></a>6.1 环境搭建</h3><ul>\n<li>添加 redis 依赖,使用 utils 包下的 RedisUtil 对内置 RedisTemplate 进行封装</li>\n<li>添加 hutool 依赖,使用 DateUtil 类中的 offsetDay()、format()</li>\n<li>考虑到 redis 序列化后出现乱码问题,使用 RedisConfig 配置类进行编码的处理<figure class=\"highlight xml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"tag\"><<span class=\"name\">dependencies</span>></span></span><br><span class=\"line\"> <span class=\"comment\"><!--Redis--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>org.springframework.boot<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>spring-boot-starter-data-redis<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\"><!--hutool:工具包,例如DateUtils工具类...--></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">groupId</span>></span>cn.hutool<span class=\"tag\"></<span class=\"name\">groupId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">artifactId</span>></span>hutool-all<span class=\"tag\"></<span class=\"name\">artifactId</span>></span></span><br><span class=\"line\"> <span class=\"tag\"><<span class=\"name\">version</span>></span>4.1.17<span class=\"tag\"></<span class=\"name\">version</span>></span></span><br><span class=\"line\"> <span class=\"tag\"></<span class=\"name\">dependency</span>></span></span><br><span class=\"line\"><span class=\"tag\"></<span class=\"name\">dependencies</span>></span></span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 指定Redis的序列化后的格式</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">RedisConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Bean</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> RedisTemplate <span class=\"title function_\">redisTemplate</span><span class=\"params\">(RedisConnectionFactory redisConnectionFactory)</span> {</span><br><span class=\"line\"> RedisTemplate<Object, Object> template = <span class=\"keyword\">new</span> <span class=\"title class_\">RedisTemplate</span>();</span><br><span class=\"line\"> template.setConnectionFactory(redisConnectionFactory);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">Jackson2JsonRedisSerializer</span> <span class=\"variable\">jackson2JsonRedisSerializer</span> <span class=\"operator\">=</span> <span class=\"keyword\">new</span> <span class=\"title class_\">Jackson2JsonRedisSerializer</span>(Object.class);</span><br><span class=\"line\"> jackson2JsonRedisSerializer.setObjectMapper(<span class=\"keyword\">new</span> <span class=\"title class_\">ObjectMapper</span>());</span><br><span class=\"line\"></span><br><span class=\"line\"> template.setKeySerializer(<span class=\"keyword\">new</span> <span class=\"title class_\">StringRedisSerializer</span>());</span><br><span class=\"line\"> template.setValueSerializer(jackson2JsonRedisSerializer);</span><br><span class=\"line\"></span><br><span class=\"line\"> template.setHashKeySerializer(<span class=\"keyword\">new</span> <span class=\"title class_\">StringRedisSerializer</span>());</span><br><span class=\"line\"> template.setHashValueSerializer(jackson2JsonRedisSerializer);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> template;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"6-2-本周热议的【基本原理】:利用-Redis-的-zet-有序集合实现\"><a href=\"#6-2-本周热议的【基本原理】:利用-Redis-的-zet-有序集合实现\" class=\"headerlink\" title=\"6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现\"></a>6.2 本周热议的【基本原理】:利用 Redis 的 zet 有序集合实现</h3><ul>\n<li>缓存热评文章——哈希表 Hash</li>\n<li>评论数量排行——有序列表 sortedSet:ZADD(添加)、ZREVRANGE(展示)、ZUNIONSTORE(并集)<ul>\n<li>ZADD key score member [[score member] [score member] …] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZADD day:18 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:19 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:20 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:21 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:22 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:23 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br><span class=\"line\">127.0.0.1:6379> ZADD day:24 10 post:1 6 post:2 4 post:3</span><br><span class=\"line\">(integer) 3</span><br></pre></td></tr></table></figure></li>\n<li>ZREVRANGE key start stop [WITHSCORES] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "10"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "6"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "4"</span><br></pre></td></tr></table></figure></li>\n<li>ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX] <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZUNIONSTORE week:rank 7 day:18 day:19 day:20 day:21 day:22 day:23 day:24</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "post:2"</span><br></pre></td></tr></table></figure></li>\n<li>查看排行榜 <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZREVRANGE week:rank 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "70"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "42"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "28"</span><br></pre></td></tr></table></figure></li>\n<li>添加/删除评论 <figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">127.0.0.1:6379> ZINCRBY day:18 10 post:1</span><br><span class=\"line\">"20"</span><br><span class=\"line\">127.0.0.1:6379> ZREVRANGE day:18 0 -1 withscores</span><br><span class=\"line\">1) "post:1"</span><br><span class=\"line\">2) "20"</span><br><span class=\"line\">3) "post:2"</span><br><span class=\"line\">4) "6"</span><br><span class=\"line\">5) "post:3"</span><br><span class=\"line\">6) "4"</span><br><span class=\"line\">127.0.0.1:6379> ZINCRBY day:18 -10 post:1</span><br><span class=\"line\">"10"</span><br></pre></td></tr></table></figure></li>\n</ul>\n</li>\n</ul>\n<h3 id=\"6-3-本周热议的【初始化操作】\"><a href=\"#6-3-本周热议的【初始化操作】\" class=\"headerlink\" title=\"6.3 本周热议的【初始化操作】\"></a>6.3 本周热议的【初始化操作】</h3><ul>\n<li>项目启动前,获取【近 7 天文章】</li>\n<li>初始化【近 7 天文章】的总评论量(先使用 SortedSet 集合对【排行榜 7 天内全部文章】进行 zadd 操作,并设置它们 expire 为 7 天;再使用 Hash 哈希表对【排行榜 7 天内全部文章】进行 hexists 判断,再 hset 缓存操作)<ul>\n<li>添加 add——将【近 7 天文章】创建日期时间作为 key 值,每篇文章对应的 id 作为它的 value 值,每篇文章对应的评论 comment 作为它的 score 值,并使用 redis 的工具类(RedisUtil),对文章的具体属性进行 zSet()缓存操作</li>\n<li>过期 expire——让【近 7 天文章】的 key 过期: 7-(当前时间-创建时间)= 过期时间</li>\n<li>缓存——缓存【近 7 天文章】的一些基本信息,例如文章 id,标题 title,评论数量,作者信息…方便访问【近 7 天文章】时,直接 redis,而非 MySQL<ul>\n<li>先对文章进行 EXISTS 判断其缓存是否存在</li>\n<li>如果 false 不存在,则再 hset 缓存操作</li>\n</ul>\n</li>\n</ul>\n</li>\n<li>对【近 7 天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Context配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ContextStartup</span> <span class=\"keyword\">implements</span> <span class=\"title class_\">ApplicationRunner</span>, ServletContextAware {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> CategoryService categoryService;</span><br><span class=\"line\"></span><br><span class=\"line\"> ServletContext servletContext;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostService postService;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动时,会同时调用该run方法:</span></span><br><span class=\"line\"><span class=\"comment\"> *</span></span><br><span class=\"line\"><span class=\"comment\"> * 加载导航栏中的“提问、分享、讨论、建议”,并将其list放入servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> * 加载本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">run</span><span class=\"params\">(ApplicationArguments args)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Category> categories = categoryService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Category>()</span><br><span class=\"line\"> .eq(<span class=\"string\">"status"</span>, <span class=\"number\">0</span>)</span><br><span class=\"line\"> );</span><br><span class=\"line\"> servletContext.setAttribute(<span class=\"string\">"categorys"</span>, categories);</span><br><span class=\"line\"></span><br><span class=\"line\"> postService.initWeekRank();</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * servletContext上下文对象</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setServletContext</span><span class=\"params\">(ServletContext servletContext)</span> {</span><br><span class=\"line\"> <span class=\"built_in\">this</span>.servletContext = servletContext;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 项目启动前,初始化本周热议(近7天全部文章评论量的排行榜)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">initWeekRank</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.获取【近7天文章】</span></span><br><span class=\"line\"> List<Post> posts = <span class=\"built_in\">this</span>.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>()</span><br><span class=\"line\"> .gt(<span class=\"string\">"created"</span>, DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), -<span class=\"number\">6</span>)) <span class=\"comment\">//根据created时间,对最近7天内的文章进行筛选</span></span><br><span class=\"line\"> .select(<span class=\"string\">"id, title, user_id, comment_count, view_count, created"</span>) <span class=\"comment\">//对文章的属性进行筛选,加快查询速率</span></span><br><span class=\"line\"> );</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.初始化【近7天文章】的总评论量(先使用SortedSet集合对【排行榜7天内全部文章】进行zadd操作,并设置它们expire为7天;再使用Hash哈希表对【排行榜7天内全部文章】进行hexists判断,再hset缓存操作)</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Post post : posts) {</span><br><span class=\"line\"> <span class=\"comment\">//1.添加add——|day:rank:20210202--0208|,将【近7天文章】创建日期时间作为key值,每篇文章对应的id作为它的value值,每篇文章对应的评论comment作为它的score值,并使用redis的工具类(RedisUtil),对文章的具体属性进行zSet()缓存操作</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">zKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> redisUtil.zSet(zKey, post.getId(), post.getCommentCount());<span class=\"comment\">//阅读redisUtil工具类,可知zSet等同于zadd</span></span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.过期expire——|day:rank:20210202--0208|,让【近7天文章】的key过期: 7-(当前时间-创建时间)= 过期时间</span></span><br><span class=\"line\"> <span class=\"type\">long</span> <span class=\"variable\">expireTime</span> <span class=\"operator\">=</span> (<span class=\"number\">7</span> - DateUtil.between(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), post.getCreated(), DateUnit.DAY)) * <span class=\"number\">24</span> * <span class=\"number\">60</span> * <span class=\"number\">60</span>;</span><br><span class=\"line\"> redisUtil.expire(zKey, expireTime);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.缓存——|day:rank:post:1~16|,缓存【近7天文章】的一些基本信息,例如文章id,标题title,评论数量,作者信息...方便访问【近7天文章】时,直接redis,而非MySQL</span></span><br><span class=\"line\"> <span class=\"comment\">//3.1先对文章进行EXISTS判断其缓存是否存在</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + post.getId();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!redisUtil.hasKey(hKey)) {</span><br><span class=\"line\"> <span class=\"comment\">//3.2如果false不存在,则再hset缓存操作</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-id"</span>, post.getId(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-title"</span>, post.getTitle(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-commentCount"</span>, post.getCommentCount(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, post.getViewCount(), expireTime);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.对【近7天文章】做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">currentKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> List<String> otherKeys = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> <span class=\"variable\">i</span> <span class=\"operator\">=</span> -<span class=\"number\">6</span>; i < <span class=\"number\">0</span>; i++) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">temp</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), i), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> otherKeys.add(temp);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">destKey</span> <span class=\"operator\">=</span> <span class=\"string\">"week:rank"</span>;</span><br><span class=\"line\"> redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"6-4-本周热议的【初始化操作】:自定义标签【hots】\"><a href=\"#6-4-本周热议的【初始化操作】:自定义标签【hots】\" class=\"headerlink\" title=\"6.4 本周热议的【初始化操作】:自定义标签【hots】\"></a>6.4 本周热议的【初始化操作】:自定义标签【hots】</h3><figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">HotsTemplate</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">TemplateDirective</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">getName</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"hots"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">execute</span><span class=\"params\">(DirectiveHandler handler)</span> <span class=\"keyword\">throws</span> Exception {</span><br><span class=\"line\"> List<Map> hostPost = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">// 获取有序集 key 中成员 member 的排名,其中有序集成员按 score 值递减 (从大到小) 排序</span></span><br><span class=\"line\"> Set<ZSetOperations.TypedTuple> typedTuples = redisUtil.getZSetRank(<span class=\"string\">"week:rank"</span>, <span class=\"number\">0</span>, <span class=\"number\">6</span>);</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (ZSetOperations.TypedTuple typedTuple : typedTuples) {</span><br><span class=\"line\"> Map<String, Object> map = <span class=\"keyword\">new</span> <span class=\"title class_\">HashMap</span><>();</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//zSet(key, value, score) -> zSet(文章日期, 文章id, 文章评论数commentCount),此处取出zSet中的value,即文章id</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">postHashKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + typedTuple.getValue();</span><br><span class=\"line\"></span><br><span class=\"line\"> map.put(<span class=\"string\">"id"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-id"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"title"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-title"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"commentCount"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-commentCount"</span>));</span><br><span class=\"line\"> map.put(<span class=\"string\">"viewCount"</span>, redisUtil.hget(postHashKey, <span class=\"string\">"post-viewCount"</span>));</span><br><span class=\"line\"></span><br><span class=\"line\"> hostPost.add(map);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> handler.put(RESULTS, hostPost).render();</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * Freemarker配置类</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Configuration</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">FreemarkerConfig</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> <span class=\"keyword\">private</span> freemarker.template.Configuration configuration;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> TimeAgoMethod timeAgoMethod;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostsTemplate postsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> HotsTemplate hotsTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“timeAgo”函数:快速实现日期转换</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为“posts”函数:快速实现分页</span></span><br><span class=\"line\"><span class=\"comment\"> * 注册为"hots"函数:快速实现本周热议</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@PostConstruct</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">setUp</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"timeAgo"</span>, timeAgoMethod);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"details"</span>, postsTemplate);</span><br><span class=\"line\"> configuration.setSharedVariable(<span class=\"string\">"hots"</span>, hotsTemplate);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n\n<h3 id=\"6-4-本周热议的【更新操作】\"><a href=\"#6-4-本周热议的【更新操作】\" class=\"headerlink\" title=\"6.4 本周热议的【更新操作】\"></a>6.4 本周热议的【更新操作】</h3><ul>\n<li>自增/自减评论数</li>\n<li>更新这篇文章的缓存时间,并更新这篇文章的基本信息</li>\n<li>对【近 7 天文章】重新做并集运算(zUnionAndStore), 并使用根据评论量的数量从大到小进行展示(zrevrange)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 本周热议:增加评论后,通过自增/自减评论数、再对排行榜做并集运算</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">incrCommentCountAndUnionForWeekRank</span><span class=\"params\">(Post post, <span class=\"type\">boolean</span> isIncr)</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.自增/自减评论数</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">currentKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> redisUtil.zIncrementScore(currentKey, post.getId(), isIncr ? <span class=\"number\">1</span> : -<span class=\"number\">1</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.更新这篇文章的缓存时间,并更新这篇文章的基本信息</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">zKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> <span class=\"type\">long</span> <span class=\"variable\">expireTime</span> <span class=\"operator\">=</span> (<span class=\"number\">7</span> - DateUtil.between(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), post.getCreated(), DateUnit.DAY)) * <span class=\"number\">24</span> * <span class=\"number\">60</span> * <span class=\"number\">60</span>;</span><br><span class=\"line\"> redisUtil.expire(zKey, expireTime);</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + post.getId();</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (!redisUtil.hasKey(hKey)) {</span><br><span class=\"line\"> <span class=\"comment\">//3.2如果false不存在,则再hset缓存操作</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-id"</span>, post.getId(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-title"</span>, post.getTitle(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-commentCount"</span>, post.getCommentCount(), expireTime);</span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, post.getViewCount(), expireTime);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.对【近7天文章】重新做并集运算(zUnionAndStore)</span></span><br><span class=\"line\"> List<String> otherKeys = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (<span class=\"type\">int</span> <span class=\"variable\">i</span> <span class=\"operator\">=</span> -<span class=\"number\">6</span>; i < <span class=\"number\">0</span>; i++) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">temp</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:"</span> + DateUtil.format(DateUtil.offsetDay(<span class=\"keyword\">new</span> <span class=\"title class_\">Date</span>(), i), DatePattern.PURE_DATE_FORMAT);</span><br><span class=\"line\"> otherKeys.add(temp);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">destKey</span> <span class=\"operator\">=</span> <span class=\"string\">"week:rank"</span>;</span><br><span class=\"line\"> redisUtil.zUnionAndStore(currentKey, otherKeys, destKey);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n"},{"title":"7. 集成 Redis 实现访问量","date":"2020-03-19T06:59:53.000Z","_content":"\n## 7. 集成 Redis 实现访问量\n### 7.1 数据一致性\n- 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个 BUG,只与点击链接的次数相关,没有与用户的 id 进行绑定\n```java\n@Controller\npublic class PostController extends BaseController {\n /**\n * 详情detail\n */\n @RequestMapping(\"/detail/{id:\\\\d*}\")\n public String detail(@PathVariable(name = \"id\") long id) {\n /**\n * 一条(post实体类、PostVo实体类)\n */\n //一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id\n PostVo postVo = postService.selectOnePost(new QueryWrapper<Post>().eq(\"p.id\", id));\n //req:PostVo实体类 -> CategoryId属性\n req.setAttribute(\"currentCategoryId\", postVo.getCategoryId());\n //req:PostVo实体类(回调)\n req.setAttribute(\"postVoData\", postVo);\n\n /**\n * 评论(comment实体类)\n */\n //评论:page(分页信息、文章id、用户id、排序)\n IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), null, \"created\");\n //req:CommentVo分页集合\n req.setAttribute(\"commentVoDatas\", results);\n\n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n postService.putViewCount(postVo);\n\n return \"post/detail\";\n }\n}\n```\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n @Autowired\n RedisUtil redisUtil;\n \n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n @Override\n public void putViewCount(PostVo postVo) {\n //1.从缓存中获取当前访问量viewCount\n String hKey = \"day:rank:post:\" + postVo.getId();\n Integer viewCount = (Integer)redisUtil.hget(hKey, \"post-viewCount\");\n\n //2.若缓存中存在viewCount,则viewCount+1;若不存在,则postVo.getViewCount()+1\n // 注意一点,项目启动前会对【7天内的文章】进行缓存,因此,还会存在【7天前的文章】未进行缓存\n if (viewCount != null) {\n postVo.setViewCount(viewCount + 1);\n } else {\n postVo.setViewCount(postVo.getViewCount() + 1);\n }\n\n //3.将viewCount同步到缓存中\n redisUtil.hset(hKey, \"post-viewCount\", postVo.getViewCount());\n }\n}\n```\n\n### 7.2 定时器定时更新\n- 每分钟同步一次(缓存 -> 同步到数据库)\n```java\n@EnableScheduling//开启定时器\n@SpringBootApplication\npublic class Application {\n\n public static void main(String[] args) {\n SpringApplication.run(Application.class, args);\n System.out.println(\"http://localhost:8080\");\n }\n}\n```\n```java\n/**\n * 定时器定时更新\n */\n@Component\npublic class ViewCountSyncTask {\n\n @Autowired\n RedisUtil redisUtil;\n\n @Autowired\n RedisTemplate redisTemplate;\n\n @Autowired\n PostService postService;\n\n //每分钟同步一次(缓存 -> 同步到数据库)\n @Scheduled(cron = \"0/5 * * * * *\")\n public void task() {\n //1.查询缓存中\"day:rank:post:\"的全部key\n Set<String> keys = redisTemplate.keys(\"day:rank:post:\" + \"*\");\n\n //2.遍历全部key,如果某个key中含有“post-viewCount”,则通过ArrayList数组依次将【带有post-viewCount的文章postId】存放\n List<String> ids = new ArrayList<>();\n for (String key : keys) {\n if (redisUtil.hHasKey(key, \"post-viewCount\")) {\n String postId = key.substring(\"day:rank:post:\".length());\n ids.add(postId);\n }\n }\n\n //3.将【全部缓存中的postId】同步到数据库\n if (ids.isEmpty()) {\n //3.1 如果[没有需要更新阅读量的文章】,则直接返回\n return;\n } else {\n //3.2 如果[存在需要更新阅读量的文章】,则先【根据ids查询全部的文章】,再【从缓存中获取该postId对应的访问量】,然后【给Post重新赋值viewCount】\n List<Post> posts = postService.list(new QueryWrapper<Post>().in(\"id\", ids));\n for (Post post : posts) {\n Integer viewCount = (Integer) redisUtil.hget(\"day:rank:post:\" + post.getId(), \"post-viewCount\");\n post.setViewCount(viewCount);\n }\n\n //3.3 同步操作\n if (posts.isEmpty()) {\n //如果【数据库中刚好删除完全部文章,即不存在文章】,则直接返回\n return;\n } else {\n //同步数据,并删除缓存\n if (postService.updateBatchById(posts)) {\n for (String id : ids) {\n redisUtil.hdel(\"day:rank:post:\" + id, \"post-viewCount\");\n System.out.println(id + \"---------------------->同步成功\");\n }\n }\n }\n }\n }\n}\n```\n\n\n\n\n","source":"_posts/Part07-集成 Redis 实现访问量.md","raw":"---\ntitle: 7. 集成 Redis 实现访问量\ndate: 2020-03-19 14:59:53\ntags: Java\ncategories: blog\n---\n\n## 7. 集成 Redis 实现访问量\n### 7.1 数据一致性\n- 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个 BUG,只与点击链接的次数相关,没有与用户的 id 进行绑定\n```java\n@Controller\npublic class PostController extends BaseController {\n /**\n * 详情detail\n */\n @RequestMapping(\"/detail/{id:\\\\d*}\")\n public String detail(@PathVariable(name = \"id\") long id) {\n /**\n * 一条(post实体类、PostVo实体类)\n */\n //一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id\n PostVo postVo = postService.selectOnePost(new QueryWrapper<Post>().eq(\"p.id\", id));\n //req:PostVo实体类 -> CategoryId属性\n req.setAttribute(\"currentCategoryId\", postVo.getCategoryId());\n //req:PostVo实体类(回调)\n req.setAttribute(\"postVoData\", postVo);\n\n /**\n * 评论(comment实体类)\n */\n //评论:page(分页信息、文章id、用户id、排序)\n IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), null, \"created\");\n //req:CommentVo分页集合\n req.setAttribute(\"commentVoDatas\", results);\n\n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n postService.putViewCount(postVo);\n\n return \"post/detail\";\n }\n}\n```\n```java\n@Service\npublic class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {\n @Autowired\n RedisUtil redisUtil;\n \n /**\n * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定\n */\n @Override\n public void putViewCount(PostVo postVo) {\n //1.从缓存中获取当前访问量viewCount\n String hKey = \"day:rank:post:\" + postVo.getId();\n Integer viewCount = (Integer)redisUtil.hget(hKey, \"post-viewCount\");\n\n //2.若缓存中存在viewCount,则viewCount+1;若不存在,则postVo.getViewCount()+1\n // 注意一点,项目启动前会对【7天内的文章】进行缓存,因此,还会存在【7天前的文章】未进行缓存\n if (viewCount != null) {\n postVo.setViewCount(viewCount + 1);\n } else {\n postVo.setViewCount(postVo.getViewCount() + 1);\n }\n\n //3.将viewCount同步到缓存中\n redisUtil.hset(hKey, \"post-viewCount\", postVo.getViewCount());\n }\n}\n```\n\n### 7.2 定时器定时更新\n- 每分钟同步一次(缓存 -> 同步到数据库)\n```java\n@EnableScheduling//开启定时器\n@SpringBootApplication\npublic class Application {\n\n public static void main(String[] args) {\n SpringApplication.run(Application.class, args);\n System.out.println(\"http://localhost:8080\");\n }\n}\n```\n```java\n/**\n * 定时器定时更新\n */\n@Component\npublic class ViewCountSyncTask {\n\n @Autowired\n RedisUtil redisUtil;\n\n @Autowired\n RedisTemplate redisTemplate;\n\n @Autowired\n PostService postService;\n\n //每分钟同步一次(缓存 -> 同步到数据库)\n @Scheduled(cron = \"0/5 * * * * *\")\n public void task() {\n //1.查询缓存中\"day:rank:post:\"的全部key\n Set<String> keys = redisTemplate.keys(\"day:rank:post:\" + \"*\");\n\n //2.遍历全部key,如果某个key中含有“post-viewCount”,则通过ArrayList数组依次将【带有post-viewCount的文章postId】存放\n List<String> ids = new ArrayList<>();\n for (String key : keys) {\n if (redisUtil.hHasKey(key, \"post-viewCount\")) {\n String postId = key.substring(\"day:rank:post:\".length());\n ids.add(postId);\n }\n }\n\n //3.将【全部缓存中的postId】同步到数据库\n if (ids.isEmpty()) {\n //3.1 如果[没有需要更新阅读量的文章】,则直接返回\n return;\n } else {\n //3.2 如果[存在需要更新阅读量的文章】,则先【根据ids查询全部的文章】,再【从缓存中获取该postId对应的访问量】,然后【给Post重新赋值viewCount】\n List<Post> posts = postService.list(new QueryWrapper<Post>().in(\"id\", ids));\n for (Post post : posts) {\n Integer viewCount = (Integer) redisUtil.hget(\"day:rank:post:\" + post.getId(), \"post-viewCount\");\n post.setViewCount(viewCount);\n }\n\n //3.3 同步操作\n if (posts.isEmpty()) {\n //如果【数据库中刚好删除完全部文章,即不存在文章】,则直接返回\n return;\n } else {\n //同步数据,并删除缓存\n if (postService.updateBatchById(posts)) {\n for (String id : ids) {\n redisUtil.hdel(\"day:rank:post:\" + id, \"post-viewCount\");\n System.out.println(id + \"---------------------->同步成功\");\n }\n }\n }\n }\n }\n}\n```\n\n\n\n\n","slug":"Part07-集成 Redis 实现访问量","published":1,"updated":"2022-03-29T02:31:48.688Z","comments":1,"layout":"post","photos":[],"link":"","_id":"cl1bj2h3n000rpowv7bb957x2","content":"<h2 id=\"7-集成-Redis-实现访问量\"><a href=\"#7-集成-Redis-实现访问量\" class=\"headerlink\" title=\"7. 集成 Redis 实现访问量\"></a>7. 集成 Redis 实现访问量</h2><h3 id=\"7-1-数据一致性\"><a href=\"#7-1-数据一致性\" class=\"headerlink\" title=\"7.1 数据一致性\"></a>7.1 数据一致性</h3><ul>\n<li>文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个 BUG,只与点击链接的次数相关,没有与用户的 id 进行绑定<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 详情detail</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/detail/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">detail</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 一条(post实体类、PostVo实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id</span></span><br><span class=\"line\"> <span class=\"type\">PostVo</span> <span class=\"variable\">postVo</span> <span class=\"operator\">=</span> postService.selectOnePost(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().eq(<span class=\"string\">"p.id"</span>, id));</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类 -> CategoryId属性</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, postVo.getCategoryId());</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类(回调)</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoData"</span>, postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 评论(comment实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//评论:page(分页信息、文章id、用户id、排序)</span></span><br><span class=\"line\"> IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> <span class=\"comment\">//req:CommentVo分页集合</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"commentVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> postService.putViewCount(postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/detail"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">putViewCount</span><span class=\"params\">(PostVo postVo)</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.从缓存中获取当前访问量viewCount</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + postVo.getId();</span><br><span class=\"line\"> <span class=\"type\">Integer</span> <span class=\"variable\">viewCount</span> <span class=\"operator\">=</span> (Integer)redisUtil.hget(hKey, <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.若缓存中存在viewCount,则viewCount+1;若不存在,则postVo.getViewCount()+1</span></span><br><span class=\"line\"> <span class=\"comment\">// 注意一点,项目启动前会对【7天内的文章】进行缓存,因此,还会存在【7天前的文章】未进行缓存</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (viewCount != <span class=\"literal\">null</span>) {</span><br><span class=\"line\"> postVo.setViewCount(viewCount + <span class=\"number\">1</span>);</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> postVo.setViewCount(postVo.getViewCount() + <span class=\"number\">1</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.将viewCount同步到缓存中</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, postVo.getViewCount());</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"7-2-定时器定时更新\"><a href=\"#7-2-定时器定时更新\" class=\"headerlink\" title=\"7.2 定时器定时更新\"></a>7.2 定时器定时更新</h3><ul>\n<li>每分钟同步一次(缓存 -> 同步到数据库)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@EnableScheduling</span><span class=\"comment\">//开启定时器</span></span><br><span class=\"line\"><span class=\"meta\">@SpringBootApplication</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">Application</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title function_\">main</span><span class=\"params\">(String[] args)</span> {</span><br><span class=\"line\"> SpringApplication.run(Application.class, args);</span><br><span class=\"line\"> System.out.println(<span class=\"string\">"http://localhost:8080"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 定时器定时更新</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ViewCountSyncTask</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisTemplate redisTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostService postService;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//每分钟同步一次(缓存 -> 同步到数据库)</span></span><br><span class=\"line\"> <span class=\"meta\">@Scheduled(cron = "0/5 * * * * *")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">task</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.查询缓存中"day:rank:post:"的全部key</span></span><br><span class=\"line\"> Set<String> keys = redisTemplate.keys(<span class=\"string\">"day:rank:post:"</span> + <span class=\"string\">"*"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.遍历全部key,如果某个key中含有“post-viewCount”,则通过ArrayList数组依次将【带有post-viewCount的文章postId】存放</span></span><br><span class=\"line\"> List<String> ids = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (String key : keys) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (redisUtil.hHasKey(key, <span class=\"string\">"post-viewCount"</span>)) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">postId</span> <span class=\"operator\">=</span> key.substring(<span class=\"string\">"day:rank:post:"</span>.length());</span><br><span class=\"line\"> ids.add(postId);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.将【全部缓存中的postId】同步到数据库</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ids.isEmpty()) {</span><br><span class=\"line\"> <span class=\"comment\">//3.1 如果[没有需要更新阅读量的文章】,则直接返回</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">//3.2 如果[存在需要更新阅读量的文章】,则先【根据ids查询全部的文章】,再【从缓存中获取该postId对应的访问量】,然后【给Post重新赋值viewCount】</span></span><br><span class=\"line\"> List<Post> posts = postService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().in(<span class=\"string\">"id"</span>, ids));</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Post post : posts) {</span><br><span class=\"line\"> <span class=\"type\">Integer</span> <span class=\"variable\">viewCount</span> <span class=\"operator\">=</span> (Integer) redisUtil.hget(<span class=\"string\">"day:rank:post:"</span> + post.getId(), <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"> post.setViewCount(viewCount);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.3 同步操作</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (posts.isEmpty()) {</span><br><span class=\"line\"> <span class=\"comment\">//如果【数据库中刚好删除完全部文章,即不存在文章】,则直接返回</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">//同步数据,并删除缓存</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (postService.updateBatchById(posts)) {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (String id : ids) {</span><br><span class=\"line\"> redisUtil.hdel(<span class=\"string\">"day:rank:post:"</span> + id, <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"> System.out.println(id + <span class=\"string\">"---------------------->同步成功"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n","site":{"data":{}},"excerpt":"","more":"<h2 id=\"7-集成-Redis-实现访问量\"><a href=\"#7-集成-Redis-实现访问量\" class=\"headerlink\" title=\"7. 集成 Redis 实现访问量\"></a>7. 集成 Redis 实现访问量</h2><h3 id=\"7-1-数据一致性\"><a href=\"#7-1-数据一致性\" class=\"headerlink\" title=\"7.1 数据一致性\"></a>7.1 数据一致性</h3><ul>\n<li>文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个 BUG,只与点击链接的次数相关,没有与用户的 id 进行绑定<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Controller</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostController</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">BaseController</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 详情detail</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@RequestMapping("/detail/{id:\\\\d*}")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> String <span class=\"title function_\">detail</span><span class=\"params\">(<span class=\"meta\">@PathVariable(name = "id")</span> <span class=\"type\">long</span> id)</span> {</span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 一条(post实体类、PostVo实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//一条:selectOnePost(表 文章id = 传 文章id),因为Mapper中select信息中,id过多引起歧义,故采用p.id</span></span><br><span class=\"line\"> <span class=\"type\">PostVo</span> <span class=\"variable\">postVo</span> <span class=\"operator\">=</span> postService.selectOnePost(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().eq(<span class=\"string\">"p.id"</span>, id));</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类 -> CategoryId属性</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"currentCategoryId"</span>, postVo.getCategoryId());</span><br><span class=\"line\"> <span class=\"comment\">//req:PostVo实体类(回调)</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"postVoData"</span>, postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 评论(comment实体类)</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"comment\">//评论:page(分页信息、文章id、用户id、排序)</span></span><br><span class=\"line\"> IPage<CommentVo> results = commentService.selectComments(getPage(), postVo.getId(), <span class=\"literal\">null</span>, <span class=\"string\">"created"</span>);</span><br><span class=\"line\"> <span class=\"comment\">//req:CommentVo分页集合</span></span><br><span class=\"line\"> req.setAttribute(<span class=\"string\">"commentVoDatas"</span>, results);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> postService.putViewCount(postVo);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> <span class=\"string\">"post/detail"</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@Service</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">PostServiceImpl</span> <span class=\"keyword\">extends</span> <span class=\"title class_\">ServiceImpl</span><PostMapper, Post> <span class=\"keyword\">implements</span> <span class=\"title class_\">PostService</span> {</span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"> </span><br><span class=\"line\"> <span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 文章阅读【缓存实现访问量】:减少访问数据库的次数,存在一个BUG,只与点击链接的次数相关,没有与用户的id进行绑定</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"> <span class=\"meta\">@Override</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">putViewCount</span><span class=\"params\">(PostVo postVo)</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.从缓存中获取当前访问量viewCount</span></span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">hKey</span> <span class=\"operator\">=</span> <span class=\"string\">"day:rank:post:"</span> + postVo.getId();</span><br><span class=\"line\"> <span class=\"type\">Integer</span> <span class=\"variable\">viewCount</span> <span class=\"operator\">=</span> (Integer)redisUtil.hget(hKey, <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.若缓存中存在viewCount,则viewCount+1;若不存在,则postVo.getViewCount()+1</span></span><br><span class=\"line\"> <span class=\"comment\">// 注意一点,项目启动前会对【7天内的文章】进行缓存,因此,还会存在【7天前的文章】未进行缓存</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (viewCount != <span class=\"literal\">null</span>) {</span><br><span class=\"line\"> postVo.setViewCount(viewCount + <span class=\"number\">1</span>);</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> postVo.setViewCount(postVo.getViewCount() + <span class=\"number\">1</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.将viewCount同步到缓存中</span></span><br><span class=\"line\"> redisUtil.hset(hKey, <span class=\"string\">"post-viewCount"</span>, postVo.getViewCount());</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n<h3 id=\"7-2-定时器定时更新\"><a href=\"#7-2-定时器定时更新\" class=\"headerlink\" title=\"7.2 定时器定时更新\"></a>7.2 定时器定时更新</h3><ul>\n<li>每分钟同步一次(缓存 -> 同步到数据库)<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">@EnableScheduling</span><span class=\"comment\">//开启定时器</span></span><br><span class=\"line\"><span class=\"meta\">@SpringBootApplication</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">Application</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">static</span> <span class=\"keyword\">void</span> <span class=\"title function_\">main</span><span class=\"params\">(String[] args)</span> {</span><br><span class=\"line\"> SpringApplication.run(Application.class, args);</span><br><span class=\"line\"> System.out.println(<span class=\"string\">"http://localhost:8080"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n<figure class=\"highlight java\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\">/**</span></span><br><span class=\"line\"><span class=\"comment\"> * 定时器定时更新</span></span><br><span class=\"line\"><span class=\"comment\"> */</span></span><br><span class=\"line\"><span class=\"meta\">@Component</span></span><br><span class=\"line\"><span class=\"keyword\">public</span> <span class=\"keyword\">class</span> <span class=\"title class_\">ViewCountSyncTask</span> {</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisUtil redisUtil;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> RedisTemplate redisTemplate;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"meta\">@Autowired</span></span><br><span class=\"line\"> PostService postService;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//每分钟同步一次(缓存 -> 同步到数据库)</span></span><br><span class=\"line\"> <span class=\"meta\">@Scheduled(cron = "0/5 * * * * *")</span></span><br><span class=\"line\"> <span class=\"keyword\">public</span> <span class=\"keyword\">void</span> <span class=\"title function_\">task</span><span class=\"params\">()</span> {</span><br><span class=\"line\"> <span class=\"comment\">//1.查询缓存中"day:rank:post:"的全部key</span></span><br><span class=\"line\"> Set<String> keys = redisTemplate.keys(<span class=\"string\">"day:rank:post:"</span> + <span class=\"string\">"*"</span>);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//2.遍历全部key,如果某个key中含有“post-viewCount”,则通过ArrayList数组依次将【带有post-viewCount的文章postId】存放</span></span><br><span class=\"line\"> List<String> ids = <span class=\"keyword\">new</span> <span class=\"title class_\">ArrayList</span><>();</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (String key : keys) {</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (redisUtil.hHasKey(key, <span class=\"string\">"post-viewCount"</span>)) {</span><br><span class=\"line\"> <span class=\"type\">String</span> <span class=\"variable\">postId</span> <span class=\"operator\">=</span> key.substring(<span class=\"string\">"day:rank:post:"</span>.length());</span><br><span class=\"line\"> ids.add(postId);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.将【全部缓存中的postId】同步到数据库</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (ids.isEmpty()) {</span><br><span class=\"line\"> <span class=\"comment\">//3.1 如果[没有需要更新阅读量的文章】,则直接返回</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">//3.2 如果[存在需要更新阅读量的文章】,则先【根据ids查询全部的文章】,再【从缓存中获取该postId对应的访问量】,然后【给Post重新赋值viewCount】</span></span><br><span class=\"line\"> List<Post> posts = postService.list(<span class=\"keyword\">new</span> <span class=\"title class_\">QueryWrapper</span><Post>().in(<span class=\"string\">"id"</span>, ids));</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (Post post : posts) {</span><br><span class=\"line\"> <span class=\"type\">Integer</span> <span class=\"variable\">viewCount</span> <span class=\"operator\">=</span> (Integer) redisUtil.hget(<span class=\"string\">"day:rank:post:"</span> + post.getId(), <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"> post.setViewCount(viewCount);</span><br><span class=\"line\"> }</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"comment\">//3.3 同步操作</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (posts.isEmpty()) {</span><br><span class=\"line\"> <span class=\"comment\">//如果【数据库中刚好删除完全部文章,即不存在文章】,则直接返回</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span>;</span><br><span class=\"line\"> } <span class=\"keyword\">else</span> {</span><br><span class=\"line\"> <span class=\"comment\">//同步数据,并删除缓存</span></span><br><span class=\"line\"> <span class=\"keyword\">if</span> (postService.updateBatchById(posts)) {</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (String id : ids) {</span><br><span class=\"line\"> redisUtil.hdel(<span class=\"string\">"day:rank:post:"</span> + id, <span class=\"string\">"post-viewCount"</span>);</span><br><span class=\"line\"> System.out.println(id + <span class=\"string\">"---------------------->同步成功"</span>);</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure></li>\n</ul>\n"}],"PostAsset":[],"PostCategory":[{"post_id":"cl1bj2h3c0008powv2tcg3npa","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3i000fpowv5mp03mdd"},{"post_id":"cl1bj2h2y0001powvg9iv7f3v","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3k000jpowvcqpn1cd3"},{"post_id":"cl1bj2h3d0009powvglrq5x2f","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3l000lpowvbbns738l"},{"post_id":"cl1bj2h3h000dpowv8kcih81d","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3l000npowvbml68t33"},{"post_id":"cl1bj2h340003powvb9vzh7ep","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3l000ppowv7xqq66y9"},{"post_id":"cl1bj2h3a0007powv4aye54hd","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3m000qpowvhakt7kw7"},{"post_id":"cl1bj2h3n000rpowv7bb957x2","category_id":"cl1bj2h360004powv1tzr0zku","_id":"cl1bj2h3p000tpowvb8zd6szw"}],"PostTag":[{"post_id":"cl1bj2h3c0008powv2tcg3npa","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3h000cpowvhfvkae42"},{"post_id":"cl1bj2h2y0001powvg9iv7f3v","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3i000epowveyk3brvz"},{"post_id":"cl1bj2h3d0009powvglrq5x2f","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3k000ipowvaghp6brp"},{"post_id":"cl1bj2h3h000dpowv8kcih81d","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3l000kpowv4vojaxbc"},{"post_id":"cl1bj2h340003powvb9vzh7ep","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3l000mpowv7l1ie4av"},{"post_id":"cl1bj2h3a0007powv4aye54hd","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3l000opowva9x59les"},{"post_id":"cl1bj2h3n000rpowv7bb957x2","tag_id":"cl1bj2h390005powv9oc69jes","_id":"cl1bj2h3p000spowve20rhkp9"}],"Tag":[{"name":"Java","_id":"cl1bj2h390005powv9oc69jes"}]}}