{"id":25,"date":"2026-07-28T13:42:21","date_gmt":"2026-07-28T05:42:21","guid":{"rendered":"http:\/\/www.dxkua.cn\/index.php\/2026\/07\/28\/%f0%9f%8f%aa-%e5%9c%a8%e7%ba%bf%e5%95%86%e5%9f%8e%e9%a1%b9%e7%9b%ae-%e9%9b%b6%e5%9f%ba%e7%a1%80%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%af%bb%e6%96%87%e6%a1%a3\/"},"modified":"2026-07-28T13:58:12","modified_gmt":"2026-07-28T05:58:12","slug":"%f0%9f%8f%aa-%e5%9c%a8%e7%ba%bf%e5%95%86%e5%9f%8e%e9%a1%b9%e7%9b%ae-%e9%9b%b6%e5%9f%ba%e7%a1%80%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%af%bb%e6%96%87%e6%a1%a3","status":"publish","type":"post","link":"https:\/\/www.dxkua.cn\/index.php\/2026\/07\/28\/%f0%9f%8f%aa-%e5%9c%a8%e7%ba%bf%e5%95%86%e5%9f%8e%e9%a1%b9%e7%9b%ae-%e9%9b%b6%e5%9f%ba%e7%a1%80%e5%ae%8c%e5%85%a8%e8%a7%a3%e8%af%bb%e6%96%87%e6%a1%a3\/","title":{"rendered":"\ud83c\udfea \u5728\u7ebf\u5546\u57ce\u9879\u76ee \u2014 \u96f6\u57fa\u7840\u5b8c\u5168\u89e3\u8bfb\u6587\u6863"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n\n\n<p class=\"wp-block-paragraph\"><strong>\u9605\u8bfb\u5bf9\u8c61<\/strong>\uff1a\u96f6\u57fa\u7840\u5b66\u4e60\u8005\uff08\u65e0\u540e\u7aef\/\u524d\u7aef\u7ecf\u9a8c\u4e5f\u53ef\u9605\u8bfb\uff09<br \/>\n<strong>\u8986\u76d6\u8303\u56f4<\/strong>\uff1a\u9879\u76ee\u67b6\u6784\u3001\u6570\u636e\u5e93\u8bbe\u8ba1\u3001\u540e\u7aef\u5fae\u670d\u52a1\u3001\u524d\u7aefSPA\u3001\u652f\u4ed8\u5b9d\u652f\u4ed8\u3001\u5168\u90e829\u6761Bug\u4fee\u590d<br \/>\n<strong>\u5b66\u4e60\u8def\u5f84\u5efa\u8bae<\/strong>\uff1a\u5148\u770b\u7b2c1\u7ae0\u4e86\u89e3\u57fa\u7840\u6982\u5ff5 \u2192 \u7b2c2\u7ae0\u770b\u6574\u4f53\u67b6\u6784 \u2192 \u7b2c5-8\u7ae0\u6df1\u5165\u540e\u7aef \u2192 \u7b2c10\u7ae0\u770b\u524d\u7aef \u2192 \u7b2c14\u7ae0\u770bBug\u4fee\u6b63\u662f\u6700\u5b9e\u6218\u7684\u90e8\u5206<\/p>\n\n\n<\/blockquote>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">\u76ee\u5f55<\/h2>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e00\u90e8\u5206\uff1a\u5165\u95e8\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#1-\u9884\u5907\u77e5\u8bc6\">1. \u9884\u5907\u77e5\u8bc6\uff1a\u7528\u5927\u767d\u8bdd\u7406\u89e3\u8fd9\u4e2a\u9879\u76ee\u7528\u5230\u7684\u6240\u6709\u6280\u672f<\/a><\/li>\n<li><a href=\"#2-\u9879\u76ee\u4e00\u77a5\">2. \u9879\u76ee\u4e00\u77a5\uff1a\u8fd9\u4e2a\u5546\u57ce\u80fd\u505a\u4ec0\u4e48<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e8c\u90e8\u5206\uff1a\u67b6\u6784\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#3-\u6574\u4f53\u67b6\u6784\">3. \u6574\u4f53\u67b6\u6784\uff1a\u4e00\u5f20\u56fe\u770b\u61c2\u6240\u6709\u6a21\u5757<\/a><\/li>\n<li><a href=\"#4-\u8bf7\u6c42\u6d41\u5411\">4. \u8bf7\u6c42\u6d41\u5411\uff1a\u4e00\u4e2a&#8221;\u52a0\u5165\u8d2d\u7269\u8f66&#8221;\u8bf7\u6c42\u7684\u5b8c\u6574\u65c5\u7a0b<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e09\u90e8\u5206\uff1a\u6570\u636e\u5e93\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#5-\u6570\u636e\u5e93\u8bbe\u8ba1\">5. \u6570\u636e\u5e93\uff1a\u5546\u57ce\u7684\u6570\u636e\u5b58\u5728\u54ea\u91cc\u3001\u600e\u4e48\u5b58\u7684<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u56db\u90e8\u5206\uff1a\u540e\u7aef\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#6-common\u516c\u5171\u6a21\u5757\">6. common\u516c\u5171\u6a21\u5757\uff1a\u6240\u6709\u5fae\u670d\u52a1\u5171\u4eab\u7684&#8221;\u5de5\u5177\u7bb1&#8221;<\/a><\/li>\n<li><a href=\"#7-admin_service\u7ba1\u7406\u5458\u670d\u52a1\">7. admin_service\uff1a\u7ba1\u7406\u5458\u670d\u52a1\u548c\u540e\u53f0\u7edf\u8ba1<\/a><\/li>\n<li><a href=\"#8-user_service\u7528\u6237\u670d\u52a1\">8. user_service\uff1a\u7528\u6237\u3001\u6536\u85cf\u3001\u6536\u8d27\u5730\u5740<\/a><\/li>\n<li><a href=\"#9-goods_service\u5546\u54c1\u670d\u52a1\">9. goods_service\uff1a\u5546\u54c1\u7ba1\u7406\u548c\u5e93\u5b58\u6263\u51cf<\/a><\/li>\n<li><a href=\"#10-order_service\u8ba2\u5355\u670d\u52a1\">10. order_service\uff1a\u8ba2\u5355\u7ed3\u7b97+\u652f\u4ed8\u5b9d\u652f\u4ed8+\u5b9a\u65f6\u53d6\u6d88<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e94\u90e8\u5206\uff1a\u524d\u7aef\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#11-\u524d\u7aef\u57fa\u7840\">11. \u524d\u7aef\u57fa\u7840\uff1aVue\u9879\u76ee\u662f\u600e\u4e48\u7ec4\u7ec7\u8d77\u6765\u7684<\/a><\/li>\n<li><a href=\"#12-http\u5c42\">12. HTTP\u5c42\uff1a\u524d\u7aef\u600e\u4e48\u548c\u540e\u7aef\u901a\u4fe1\u7684<\/a><\/li>\n<li><a href=\"#13-\u6838\u5fc3\u9875\u9762\">13. \u6838\u5fc3\u9875\u9762\uff1a\u4ece\u767b\u5f55\u5230\u652f\u4ed8\u7684\u5168\u94fe\u8def<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u516d\u90e8\u5206\uff1a\u8fd0\u7ef4\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#14-nginx\u53cd\u5411\u4ee3\u7406\">14. nginx\u53cd\u5411\u4ee3\u7406\uff1a\u4e00\u4e2a\u57df\u540d\u80cc\u540e\u56db\u4e2a\u5fae\u670d\u52a1<\/a><\/li>\n<li><a href=\"#15-\u652f\u4ed8\u5b9d\u652f\u4ed8\">15. \u652f\u4ed8\u5b9d\u652f\u4ed8\uff1a\u5b8c\u6574\u94fe\u8def\u4e0e\u53cc\u901a\u9053\u901a\u77e5\u673a\u5236<\/a><\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">\u7b2c\u4e03\u90e8\u5206\uff1a\u5b9e\u6218\u7bc7<\/h3>\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"#16-api\u8def\u7531\u5168\u8868\">16. API\u8def\u7531\u5168\u8868<\/a><\/li>\n<li><a href=\"#17-bug\u4fee\u6b63\u8bb0\u5f55\">17. Bug\u4fee\u6b63\u8bb0\u5f55\uff1a29\u6761Bug\u7684\u75c5\u56e0\u3001\u75c7\u72b6\u3001\u836f\u65b9<\/a><\/li>\n<li><a href=\"#18-\u672f\u8bed\u8868\">18. \u672f\u8bed\u8868<\/a><\/li>\n\n<\/ul>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">1. \u9884\u5907\u77e5\u8bc6<\/h2>\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n\n\n<p class=\"wp-block-paragraph\">\u5982\u679c\u4f60\u5df2\u7ecf\u6709\u7f16\u7a0b\u57fa\u7840\uff0c\u53ef\u4ee5\u76f4\u63a5\u8df3\u5230\u7b2c3\u7ae0\u3002\u8fd9\u4e00\u7ae0\u662f\u4e3a\u96f6\u57fa\u7840\u8bfb\u8005\u51c6\u5907\u7684\u6280\u672f\u6982\u5ff5\u901f\u6210\u8bfe\u3002<\/p>\n\n\n<\/blockquote>\n\n\n<h3 class=\"wp-block-heading\">1.1 \u4ec0\u4e48\u662f&#8221;\u524d\u540e\u7aef\u5206\u79bb&#8221;<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u4f20\u7edf\u7684\u7f51\u7ad9\u5f00\u53d1\uff0c\u540e\u7aef\u8d1f\u8d23\u4e00\u5207\u2014\u2014\u5904\u7406\u6570\u636e\u3001\u6e32\u67d3HTML\u9875\u9762\u3001\u8fd4\u56de\u7ed9\u6d4f\u89c8\u5668\u3002\u4e00\u4e2aJava\u7a0b\u5e8f\u5458\u8981\u540c\u65f6\u5199\u6570\u636e\u5e93\u67e5\u8be2\u548cHTML\u9875\u9762\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u524d\u540e\u7aef\u5206\u79bb<\/strong>\u628a\u8fd9\u4efd\u5de5\u4f5c\u62c6\u6210\u4e24\u90e8\u5206\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u7528\u6237\u6d4f\u89c8\u5668\n    \u2502\n    \u251c\u2500\u2500 \u770b\u5230\u6f02\u4eae\u7684\u9875\u9762\u3001\u6309\u94ae\u3001\u8868\u683c\uff08\u524d\u7aef\u8d1f\u8d23\uff09\n    \u2502\n    \u2514\u2500\u2500 \u70b9\u51fb\u6309\u94ae\u540e\uff0c\u6d4f\u89c8\u5668\u5077\u5077\u53d1HTTP\u8bf7\u6c42\u5230\u670d\u52a1\u5668\n             \u2502\n             \u2514\u2500\u2500 \u670d\u52a1\u5668\u67e5\u6570\u636e\u5e93\u3001\u7b97\u6570\u636e\u3001\u8fd4\u56de\u7eafJSON\uff08\u540e\u7aef\u8d1f\u8d23\uff09<\/code><\/pre>\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>\u524d\u7aef<\/strong>\u53ea\u5173\u5fc3&#8221;\u7528\u6237\u770b\u5230\u4ec0\u4e48&#8221;\u2014\u2014\u9875\u9762\u957f\u4ec0\u4e48\u6837\u3001\u70b9\u4e86\u6309\u94ae\u4f1a\u53d1\u751f\u4ec0\u4e48<\/li>\n<li><strong>\u540e\u7aef<\/strong>\u53ea\u5173\u5fc3&#8221;\u6570\u636e\u600e\u4e48\u5904\u7406&#8221;\u2014\u2014\u6570\u636e\u5e93\u91cc\u6709\u4ec0\u4e48\u3001\u600e\u4e48\u67e5\u3001\u600e\u4e48\u7b97\u3001\u600e\u4e48\u8fd4\u56de<\/li>\n<li>\u524d\u540e\u7aef\u901a\u8fc7 <strong>JSON<\/strong>\uff08\u4e00\u79cd\u7eaf\u6587\u672c\u7684\u6570\u636e\u683c\u5f0f\uff09\u6c9f\u901a<\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">1.2 \u4ec0\u4e48\u662fJSON<\/h3>\n\n\n<p class=\"wp-block-paragraph\">JSON\u5c31\u662f\u628a\u6570\u636e\u7ec4\u7ec7\u6210&#8221;\u952e:\u503c&#8221;\u7684\u7eaf\u6587\u672c\u3002\u6bd4\u5982\u4e00\u4e2a\u8ba2\u5355\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>{\n    \"orderId\": 123456789,\n    \"username\": \"\u5f20\u4e09\",\n    \"totalPrice\": 5999.00,\n    \"items\": [\n        {\"name\": \"\u5c0f\u7c7314\", \"count\": 2, \"price\": 2999.50},\n        {\"name\": \"\u534e\u4e3aMate60\", \"count\": 1, \"price\": 6999.00}\n    ]\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">\u524d\u7aef\u6536\u5230\u8fd9\u4e2aJSON\u540e\uff0c\u628a\u5b83\u89e3\u6790\u6210JavaScript\u5bf9\u8c61\uff0c\u7136\u540e\u6e32\u67d3\u6210\u8868\u683c\u6216\u5361\u7247\u3002\u540e\u7aef\u6536\u5230\u524d\u7aef\u53d1\u7684JSON\u540e\uff0c\u628a\u91cc\u9762\u7684\u6570\u636e\u53d6\u51fa\u6765\u5b58\u8fdb\u6570\u636e\u5e93\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">1.3 \u4ec0\u4e48\u662f\u5fae\u670d\u52a1<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u4f20\u7edf\u505a\u6cd5\u662f\u628a\u6240\u6709\u4ee3\u7801\u5199\u5728\u4e00\u4e2a\u5927\u9879\u76ee\u91cc\uff0c\u53eb\u505a&#8221;\u5355\u4f53\u5e94\u7528&#8221;\u3002\u5c31\u50cf\u4e00\u4e2a\u5927\u8d85\u5e02\uff0c\u5356\u83dc\u3001\u5356\u7535\u5668\u3001\u5356\u670d\u88c5\u90fd\u5728\u4e00\u8d77\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5fae\u670d\u52a1<\/strong>\u628a\u5927\u9879\u76ee\u62c6\u6210\u591a\u4e2a\u5c0f\u9879\u76ee\uff08&#8221;\u670d\u52a1&#8221;\uff09\uff0c\u6bcf\u4e2a\u670d\u52a1\u53ea\u505a\u4e00\u7c7b\u4e8b\u60c5\u3002\u5c31\u50cf\u628a\u5927\u8d85\u5e02\u62c6\u6210\u4e13\u95e8\u7684\u852c\u83dc\u5e97\u3001\u7535\u5668\u5e97\u3001\u670d\u88c5\u5e97\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\">\u672c\u9879\u76ee\u67094\u4e2a\u5fae\u670d\u52a1\uff1a<\/p>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u5fae\u670d\u52a1<\/th>\n<th>\u804c\u8d23<\/th>\n<th>\u4e00\u53e5\u8bdd<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>admin_service<\/td>\n<td>\u7ba1\u7406\u5458\u76f8\u5173<\/td>\n<td>\u7ba1\u7406\u5458\u600e\u4e48\u767b\u5f55\u7684\u3001\u540e\u53f0\u6570\u636e\u600e\u4e48\u7edf\u8ba1\u7684<\/td>\n<\/tr>\n<tr>\n<td>user_service<\/td>\n<td>\u7528\u6237\u76f8\u5173<\/td>\n<td>\u7528\u6237\u600e\u4e48\u6ce8\u518c\u7684\u3001\u6536\u8d27\u5730\u5740\u600e\u4e48\u5b58\u7684<\/td>\n<\/tr>\n<tr>\n<td>goods_service<\/td>\n<td>\u5546\u54c1\u76f8\u5173<\/td>\n<td>\u5546\u54c1\u5206\u7c7b\u3001\u5546\u54c1\u4fe1\u606f\u3001\u5e93\u5b58\u6263\u51cf<\/td>\n<\/tr>\n<tr>\n<td>order_service<\/td>\n<td>\u8ba2\u5355\u76f8\u5173<\/td>\n<td>\u8d2d\u7269\u8f66\u3001\u4e0b\u5355\u3001\u652f\u4ed8\u5b9d\u652f\u4ed8<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u597d\u5904<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u4e00\u4e2a\u670d\u52a1\u6302\u4e86\u4e0d\u5f71\u54cd\u5176\u4ed6\uff08\u5546\u54c1\u53ef\u4ee5\u6b63\u5e38\u6d4f\u89c8\uff0c\u53ea\u662f\u4e0d\u80fd\u4e0b\u5355\uff09<\/li>\n<li>\u6bcf\u4e2a\u670d\u52a1\u53ef\u4ee5\u7528\u4e0d\u540c\u7684\u6280\u672f\uff08\u867d\u7136\u672c\u9879\u76ee\u7edf\u4e00\u7528Spring Boot\uff09<\/li>\n<li>\u56e2\u961f\u53ef\u4ee5\u5206\u5de5\uff1aA\u5199\u5546\u54c1\u670d\u52a1\uff0cB\u5199\u8ba2\u5355\u670d\u52a1<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u574f\u5904<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u670d\u52a1\u4e4b\u95f4\u901a\u4fe1\u6709\u989d\u5916\u5f00\u9500\uff08\u7f51\u7edc\u5ef6\u8fdf\uff09<\/li>\n<li>\u9700\u8981\u989d\u5916\u7684\u7ec4\u4ef6\uff08ZooKeeper\uff09\u6765\u534f\u8c03\u670d\u52a1\u4e4b\u95f4\u5982\u4f55\u53d1\u73b0\u5f7c\u6b64<\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">1.4 \u4ec0\u4e48\u662fDubbo\uff08RPC\u6846\u67b6\uff09<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u5fae\u670d\u52a1\u62c6\u5206\u540e\uff0c\u4e00\u4e2a\u95ee\u9898\u51fa\u73b0\u4e86\uff1aorder_service\uff08\u8ba2\u5355\uff09\u9700\u8981\u67e5\u5546\u54c1\u4fe1\u606f\uff0c\u4f46\u5546\u54c1\u4fe1\u606f\u5728goods_service\uff08\u5546\u54c1\uff09\u90a3\u91cc\uff0c\u600e\u4e48\u529e\uff1f<\/p>\n\n\n<pre class=\"wp-block-code\"><code>order_service \u8bf4\uff1a\"\u6211\u9700\u8981\u77e5\u9053\u5546\u54c1#45\u7684\u540d\u5b57\u548c\u4ef7\u683c\"\ngoods_service \u8bf4\uff1a\"\u6211\u8fd9\u91cc\u6709\uff0c\u6211\u7ed9\u4f60\"\n\n\u5b83\u4eec\u600e\u4e48\u901a\u4fe1\uff1f<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Dubbo\u5c31\u662f\u4e00\u4e2a\u8ba9Java\u670d\u52a1\u4e4b\u95f4\u4e92\u76f8\u8c03\u7528\u7684\u6846\u67b6<\/strong>\u3002\u5b83\u7684\u5de5\u4f5c\u65b9\u5f0f\uff1a<\/p>\n\n\n<ol class=\"wp-block-list\">\n\n<li>\u6bcf\u4e2a\u670d\u52a1\u542f\u52a8\u65f6\uff0c\u5411ZooKeeper\uff08&#8221;\u6ce8\u518c\u4e2d\u5fc3&#8221;\uff09\u62a5\u5230\uff1a&#8221;\u6211\u662fgoods_service\uff0c\u6211\u7684\u5730\u5740\u662f192.168.1.5:38090&#8243;<\/li>\n<li>order_service\u9700\u8981\u8c03goods_service\u65f6\uff0c\u5148\u95eeZooKeeper\uff1a&#8221;goods_service\u5728\u54ea\u513f\uff1f&#8221;<\/li>\n<li>ZooKeeper\u544a\u8bc9\u5b83\u5730\u5740\uff0corder_service\u76f4\u63a5\u8fde\u8fc7\u53bb\u8c03\u7528<\/li>\n<li>\u5bf9\u7a0b\u5e8f\u5458\u6765\u8bf4\uff0c\u8c03\u7528\u8fdc\u7a0b\u670d\u52a1\u548c\u8c03\u7528\u672c\u5730\u65b9\u6cd5\u5dee\u4e0d\u591a\uff08\u90fd\u662f<code>goodsService.selectById(45)<\/code>\uff09<\/li>\n\n<\/ol>\n\n\n<pre class=\"wp-block-code\"><code>@DubboReference          \/\/ \u2190 \u8fd9\u884c\u6ce8\u89e3\u544a\u8bc9Dubbo\uff1a\"\u8fd9\u4e2a\u5b57\u6bb5\u7684\u503c\u6765\u81ea\u8fdc\u7a0b\u670d\u52a1\"\nprivate GoodsService goodsService;\n\n\/\/ \u7136\u540e\u5728\u4ee3\u7801\u91cc\u76f4\u63a5\u8c03\u7528\uff0c\u5c31\u50cf\u8c03\u7528\u672c\u5730\u65b9\u6cd5\u4e00\u6837\nGoods goods = goodsService.selectById(45);  \/\/ \u2190 \u5b9e\u9645\u662f\u8de8\u7f51\u7edc\u8c03\u7528goods_service<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">1.5 \u4ec0\u4e48\u662fMyBatis\uff08ORM\u6846\u67b6\uff09<\/h3>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u95ee\u9898<\/strong>\uff1aJava\u662f\u9762\u5411\u5bf9\u8c61\u7684\uff08\u6709User\u7c7b\u3001Order\u7c7b\uff09\uff0c\u4f46MySQL\u662f\u5173\u7cfb\u578b\u6570\u636e\u5e93\uff08\u6709user\u8868\u3001order\u8868\uff09\u3002\u4e24\u8005\u6570\u636e\u7ed3\u6784\u4e0d\u540c\u2014\u2014Java\u91cc\u662f<code>user.getUsername()<\/code>\uff0cMySQL\u91cc\u662f<code>SELECT username FROM user<\/code>\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>MyBatis\u89e3\u51b3\u4e86\u8fd9\u4e2a&#8221;\u8303\u5f0f\u4e0d\u5339\u914d&#8221;\u95ee\u9898<\/strong>\u3002\u5b83\u8ba9\u4f60\u7528XML\u5199SQL\u8bed\u53e5\uff0c\u5e76\u81ea\u52a8\u628a\u6570\u636e\u5e93\u7684\u884c\u6620\u5c04\u6210Java\u5bf9\u8c61\u3002<\/p>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- MyBatis\u7684XML\u6587\u4ef6: UserMapper.xml --&gt;\n\n&lt;!-- \u5b9a\u4e49\"\u6620\u5c04\u5173\u7cfb\"\uff1a\u6570\u636e\u5e93\u5217 &lt;-&gt; Java\u5bf9\u8c61\u5c5e\u6027 --&gt;\n&lt;select id=\"selectById\" resultType=\"user\"&gt;\n    SELECT id, username, phone, reg_time\n    FROM user\n    WHERE id = #{id}\n&lt;\/select&gt;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">\u5f53Java\u4ee3\u7801\u8c03\u7528<code>userMapper.selectById(3)<\/code>\u65f6\uff1a<\/p>\n\n\n<ol class=\"wp-block-list\">\n\n<li>MyBatis\u627e\u5230\u5bf9\u5e94\u7684SQL\uff1a<code>SELECT ... FROM user WHERE id = 3<\/code><\/li>\n<li>\u628aSQL\u53d1\u7ed9MySQL\u6267\u884c<\/li>\n<li>MySQL\u8fd4\u56de\u4e00\u884c\u6570\u636e\uff1a<code>{id:3, username:\"\u5f20\u4e09\", phone:\"13322332233\", reg_time:\"2024-09-01\"}<\/code><\/li>\n<li>MyBatis\u6839\u636e<code>map-underscore-to-camel-case=true<\/code>\u914d\u7f6e\uff0c\u81ea\u52a8\u628a<code>reg_time<\/code>\uff08\u6570\u636e\u5e93\u4e0b\u5212\u7ebf\uff09\u8f6c\u6210<code>regTime<\/code>\uff08Java\u9a7c\u5cf0\uff09<\/li>\n<li>\u521b\u5efa\u4e00\u4e2aUser\u5bf9\u8c61\uff0c\u628a\u503c\u586b\u8fdb\u53bb\uff0c\u8fd4\u56de\u7ed9Java\u4ee3\u7801<\/li>\n\n<\/ol>\n\n\n<h3 class=\"wp-block-heading\">1.6 \u4ec0\u4e48\u662fJWT\uff08JSON Web Token\uff09<\/h3>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u95ee\u9898<\/strong>\uff1aHTTP\u8bf7\u6c42\u662f\u65e0\u72b6\u6001\u7684\u2014\u2014\u6bcf\u6b21\u8bf7\u6c42\u90fd\u662f\u72ec\u7acb\u7684\uff0c\u670d\u52a1\u5668\u4e0d\u77e5\u9053&#8221;\u8fd9\u6b21\u8bf7\u6c42\u548c\u4e0a\u6b21\u8bf7\u6c42\u662f\u540c\u4e00\u4e2a\u4eba\u5417&#8221;\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\">\u4f20\u7edf\u65b9\u6848\u53eb<strong>Session<\/strong>\uff1a\u7528\u6237\u767b\u5f55\u540e\uff0c\u670d\u52a1\u5668\u5728\u5185\u5b58\u91cc\u5b58\u4e00\u4efd&#8221;\u5f20\u4e09\u5df2\u767b\u5f55&#8221;\u7684\u8bb0\u5f55\uff0c\u8fd4\u56de\u4e00\u4e2asessionId\u3002\u4e0b\u6b21\u8bf7\u6c42\u5e26\u4e0asessionId\uff0c\u670d\u52a1\u5668\u67e5\u5230\u5bf9\u5e94\u7684session\u5c31\u77e5\u9053\u4f60\u662f\u8c01\u4e86\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\">JWT\u65b9\u6848\u66f4\u7b80\u5355\u2014\u2014<strong>\u4e0d\u9700\u8981\u670d\u52a1\u5668\u8bb0\u5f55\u4efb\u4f55\u4e1c\u897f<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u767b\u5f55\u65f6\uff1a\n  \u670d\u52a1\u5668\u751f\u6210\u4e00\u4e2aJWT\uff1a3\u6bb5Base64\u5b57\u7b26\u4e32\uff0c\u7528\u70b9\u53f7\u5206\u9694\n  xxxxxx.yyyyyy.zzzzzz\n    \u2191       \u2191       \u2191\n  \u5934\u90e8    \u8f7d\u8377    \u7b7e\u540d\n  (\u7b97\u6cd5)  (\u7528\u6237ID  (\u9632\u7be1\u6539\u7684\n          \u548c\u89d2\u8272)  \u6570\u5b57\u6307\u7eb9)\n\n\u6bcf\u6b21\u8bf7\u6c42\u65f6\uff1a\n  \u524d\u7aef\u628aJWT\u653e\u5728HTTP\u5934\u91cc\n  \u540e\u7aef\u89e3\u6790JWT\uff0c\u9a8c\u8bc1\u7b7e\u540d\u6ca1\u88ab\u6539\u8fc7\uff0c\u63d0\u53d6\u7528\u6237ID\n  \u5b8c\u4e8b\uff01<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u7528JWT\u800c\u4e0d\u662fSession<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>JWT\u4e0d\u9700\u8981\u670d\u52a1\u5668\u5b58\u72b6\u6001 \u2192 \u5fae\u670d\u52a1\u67b6\u6784\u4e0b\u6240\u6709\u670d\u52a1\u5171\u4eab\u4e00\u4e2aJWT\u5bc6\u94a5\u5c31\u80fd\u89e3\u6790<\/li>\n<li>Session\u9700\u8981Redis\u6216\u5171\u4eab\u5185\u5b58 \u2192 \u589e\u52a0\u8fd0\u7ef4\u590d\u6742\u5ea6<\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">1.7 \u4ec0\u4e48\u662fnginx\uff08\u53cd\u5411\u4ee3\u7406\uff09<\/h3>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u95ee\u9898<\/strong>\uff1a4\u4e2a\u5fae\u670d\u52a1\u5404\u8dd1\u5728\u4e0d\u540c\u7aef\u53e3\u4e0a\uff088090, 8091, 8092, 8093\uff09\uff0c\u524d\u7aefAjax\u8bf7\u6c42\u4e0d\u80fd\u8de8\u7aef\u53e3\u2014\u2014<code>http:\/\/www.dxkua.cn:80<\/code>\u600e\u4e48\u5206\u522b\u8bbf\u95ee4\u4e2a\u4e0d\u540c\u7aef\u53e3\u7684\u670d\u52a1\uff1f<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>nginx\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898<\/strong>\u3002\u5b83\u76d1\u542c80\u7aef\u53e3\uff08HTTP\u9ed8\u8ba4\u7aef\u53e3\uff09\uff0c\u6536\u5230\u8bf7\u6c42\u540e\u6309URL\u8def\u5f84&#8221;\u5206\u53d1&#8221;\u7ed9\u4e0d\u540c\u7684\u540e\u7aef\u670d\u52a1\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>nginx: \"\u6536\u5230 GET \/goods\/45 \u2192 \u8fd9\u662f\u5546\u54c1\u8bf7\u6c42\uff0c\u8f6c\u53d1\u7ed98090\u7aef\u53e3\"\nnginx: \"\u6536\u5230 GET \/user\/info \u2192 \u8fd9\u662f\u7528\u6237\u8bf7\u6c42\uff0c\u8f6c\u53d1\u7ed98092\u7aef\u53e3\"\nnginx: \"\u6536\u5230 POST \/order \u2192 \u8fd9\u662f\u8ba2\u5355\u8bf7\u6c42\uff0c\u8f6c\u53d1\u7ed98093\u7aef\u53e3\"<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">\u5bf9\u5916\u53ea\u66b4\u973280\u7aef\u53e3\u4e00\u4e2a\u5165\u53e3\uff0c\u5bf9\u5185\u6309\u8def\u5f84\u89c4\u5219\u5206\u53d1\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">1.8 \u4ec0\u4e48\u662f\u652f\u4ed8\u5b9dPC\u7f51\u7ad9\u652f\u4ed8\uff08alipay.trade.page.pay\uff09<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u8fd9\u662f\u652f\u4ed8\u5b9d\u63d0\u4f9b\u7684\u4e00\u79cd\u652f\u4ed8\u65b9\u5f0f\uff0c\u6d41\u7a0b\u662f\uff1a<\/p>\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>\u5546\u5bb6\u540e\u53f0<\/strong>\uff08\u6211\u4eec\uff09\u8c03\u7528\u652f\u4ed8\u5b9dAPI\uff1a&#8221;\u6211\u8981\u521b\u5efa\u4e00\u7b14\u8ba2\u5355\uff0c\u91d1\u989d5999\u5143\uff0c\u5546\u54c1\u662f\u5c0f\u7c7314&#8243;<\/li>\n<li><strong>\u652f\u4ed8\u5b9d<\/strong>\u8fd4\u56de\u4e00\u6bb5HTML\u8868\u5355\uff08\u5305\u542b\u7b7e\u540d\u3001\u8ba2\u5355\u53f7\u3001\u91d1\u989d\u7b49\u52a0\u5bc6\u5b57\u6bb5\uff09<\/li>\n<li><strong>\u524d\u7aef<\/strong>\u628a\u8fd9\u6bb5HTML\u63d0\u4ea4\u5230\u652f\u4ed8\u5b9d\u7f51\u7ad9<\/li>\n<li><strong>\u7528\u6237\u5728\u652f\u4ed8\u5b9d\u81ea\u5df1\u7684\u9875\u9762\u4e0a<\/strong>\u767b\u5f55\u3001\u8f93\u652f\u4ed8\u5bc6\u7801\u3001\u4ed8\u6b3e<\/li>\n<li><strong>\u4ed8\u6b3e\u5b8c\u6210\u540e<\/strong>\uff0c\u652f\u4ed8\u5b9d\u901a\u8fc7\u4e24\u4e2a\u6e20\u9053\u901a\u77e5\u6211\u4eec\uff1a\n<ul class=\"wp-block-list\">\n\n<li><strong>\u540c\u6b65\u901a\u77e5\uff08\u6d4f\u89c8\u5668\u8df3\u8f6c\uff09<\/strong>\uff1a\u7528\u6237\u6d4f\u89c8\u5668\u4ece\u652f\u4ed8\u5b9d\u9875\u9762\u8df3\u56de\u6211\u4eec\u7684&#8221;\u652f\u4ed8\u7ed3\u679c\u9875&#8221;<\/li>\n<li><strong>\u5f02\u6b65\u901a\u77e5\uff08\u670d\u52a1\u5668\u63a8\u9001\uff09<\/strong>\uff1a\u652f\u4ed8\u5b9d\u670d\u52a1\u5668\u76f4\u63a5POST\u6211\u4eec\u7684notifyUrl\uff0c\u544a\u77e5\u652f\u4ed8\u7ed3\u679c<\/li>\n\n<\/ul>\n\n<\/li>\n\n<\/ol>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u9700\u8981\u4e24\u4e2a\u901a\u77e5<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u540c\u6b65\u901a\u77e5\u53ef\u80fd\u4e22\u5931\uff08\u7528\u6237\u4ed8\u6b3e\u540e\u7acb\u523b\u5173\u6d4f\u89c8\u5668 \u2192 \u8df3\u8f6c\u4e0d\u6267\u884c\uff09<\/li>\n<li>\u5f02\u6b65\u901a\u77e5\u6700\u53ef\u9760\uff08\u652f\u4ed8\u5b9d\u670d\u52a1\u5668\u4fdd\u8bc1\u81f3\u5c11\u53d1\u4e00\u6b21\uff09\uff0c\u4f46\u53ef\u80fd\u6709\u7f51\u7edc\u9632\u706b\u5899\u95ee\u9898<\/li>\n<li>\u4e24\u4e2a\u4e92\u8865\uff0c\u4fdd\u8bc1\u4e07\u65e0\u4e00\u5931<\/li>\n\n<\/ul>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">2. \u9879\u76ee\u4e00\u77a5<\/h2>\n\n\n<h3 class=\"wp-block-heading\">2.1 \u529f\u80fd\u5730\u56fe<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\u5728\u7ebf\u5546\u57ce\n\u2502\n\u251c\u2500\u2500 \u7528\u6237\u7aef (\u666e\u901a\u987e\u5ba2\u7528\u7684)\n\u2502   \u251c\u2500\u2500 \u9996\u9875\uff08\u8f6e\u64ad\u56fe+\u63a8\u8350\u5546\u54c1\uff09\n\u2502   \u251c\u2500\u2500 \u641c\u7d22\u5546\u54c1\uff08\u6309\u5206\u7c7b\/\u540d\u79f0\u641c\u7d22\uff09\n\u2502   \u251c\u2500\u2500 \u5546\u54c1\u8be6\u60c5\uff08\u56fe\u7247\u8f6e\u64ad+\u52a0\u5165\u8d2d\u7269\u8f66+\u6536\u85cf+\u76f4\u63a5\u8d2d\u4e70\uff09\n\u2502   \u251c\u2500\u2500 \u8d2d\u7269\u8f66\uff08\u591a\u9009+\u6570\u91cf\u4fee\u6539+\u7ed3\u7b97\uff09\n\u2502   \u251c\u2500\u2500 \u7ed3\u7b97\u9875\uff08\u9009\u5730\u5740+\u652f\u4ed8+\u8df3\u8f6c\u652f\u4ed8\u5b9d\u6c99\u7bb1\uff09\n\u2502   \u251c\u2500\u2500 \u652f\u4ed8\u7ed3\u679c\u9875\uff08\u67e5\u652f\u4ed8\u72b6\u6001\uff09\n\u2502   \u251c\u2500\u2500 \u4e2a\u4eba\u4e2d\u5fc3\n\u2502   \u2502   \u251c\u2500\u2500 \u4e2a\u4eba\u4fe1\u606f\u4fee\u6539\n\u2502   \u2502   \u251c\u2500\u2500 \u4fee\u6539\u5bc6\u7801\n\u2502   \u2502   \u251c\u2500\u2500 \u6211\u7684\u6536\u85cf\uff08\u5546\u54c1\u5361\u7247\u7f51\u683c+\u53d6\u6d88\u6536\u85cf\uff09\n\u2502   \u2502   \u251c\u2500\u2500 \u5730\u5740\u7ba1\u7406\uff08\u65b0\u589e\/\u7f16\u8f91\/\u5220\u9664\/\u8bbe\u4e3a\u9ed8\u8ba4\uff09\n\u2502   \u2502   \u2514\u2500\u2500 \u6211\u7684\u8ba2\u5355\uff08\u8ba2\u5355\u5217\u8868+\u53bb\u652f\u4ed8+\u53d6\u6d88\u8ba2\u5355\uff09\n\u2502   \u251c\u2500\u2500 \u767b\u5f55\/\u6ce8\u518c\uff08\u56fe\u5f62\u9a8c\u8bc1\u7801\uff09\n\u2502   \u2514\u2500\u2500 \u5728\u7ebf\u804a\u5929(AI\u5ba2\u670d)\n\u2502\n\u2514\u2500\u2500 \u7ba1\u7406\u7aef (\u7ba1\u7406\u5458\u7528\u7684)\n    \u251c\u2500\u2500 \u767b\u5f55\n    \u251c\u2500\u2500 \u4eea\u8868\u76d8\uff08\u603b\u8ba2\u5355\/\u603b\u7528\u6237\/\u4eca\u65e5\u9500\u552e\u989d\/\u72b6\u6001\u5206\u5e03\uff09\n    \u251c\u2500\u2500 \u5546\u54c1\u7ba1\u7406\uff08\u589e\u5220\u6539\u67e5+\u56fe\u7247\u4e0a\u4f20+\u5bcc\u6587\u672c\u7f16\u8f91\u5668\uff09\n    \u251c\u2500\u2500 \u5206\u7c7b\u7ba1\u7406\uff08\u589e\u5220\u6539\u67e5+\u56fe\u7247\u4e0a\u4f20\uff09\n    \u251c\u2500\u2500 \u7528\u6237\u7ba1\u7406\uff08\u641c\u7d22+\u5c01\u7981\/\u89e3\u5c01+\u5220\u9664\uff09\n    \u251c\u2500\u2500 \u8ba2\u5355\u7ba1\u7406\uff08\u641c\u7d22+\u6539\u72b6\u6001+\u5220\u9664\uff09\n    \u2514\u2500\u2500 \u7ba1\u7406\u5458\u7ba1\u7406\uff08\u589e\u5220\u6539\u67e5\uff09<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">2.2 \u6838\u5fc3\u4e1a\u52a1\u6d41\u7a0b<\/h3>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5b8c\u6574\u7684\u8d2d\u7269\u6d41\u7a0b<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u6d4f\u89c8\u5546\u54c1 \u2192 \u52a0\u5165\u8d2d\u7269\u8f66 \u2192 \u53bb\u8d2d\u7269\u8f66\u52fe\u9009\u7ed3\u7b97\n    \u2502                          \u2502\n    \u2502                          \u251c\u2500\u2500 \u9009\u6536\u8d27\u5730\u5740\n    \u2502                          \u251c\u2500\u2500 \u9009\u652f\u4ed8\u65b9\u5f0f\n    \u2502                          \u2514\u2500\u2500 \u63d0\u4ea4\u8ba2\u5355\n    \u2502                              \u2502\n    \u2502                        \u8ba2\u5355\u521b\u5efa\u6210\u529f (status=0 \u5f85\u4ed8\u6b3e)\n    \u2502                              \u2502\n    \u2502                        \u8df3\u8f6c\u652f\u4ed8\u5b9d\u6c99\u7bb1\u4ed8\u6b3e\n    \u2502                              \u2502\n    \u2502                        \u4ed8\u6b3e\u6210\u529f (status=1 \u5df2\u4ed8\u6b3e)\n    \u2502                              \u2502\n    \u2502                        notify\/query \u6263\u5e93\u5b58\n    \u2502                              \u2502\n    \u2502                        \u7ba1\u7406\u5458\u540e\u53f0\u53d1\u8d27(status=2)\n    \u2502                              \u2502\n    \u2502                        \u7528\u6237\u786e\u8ba4\u6536\u8d27(status=3)\n    \u2502\n    \u2514\u2500\u2500 \u76f4\u63a5\u8d2d\u4e70\uff08\u8df3\u8fc7\u8d2d\u7269\u8f66\uff0c\u4e00\u6b65\u5230\u7ed3\u7b97\u9875\uff09<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">3. \u6574\u4f53\u67b6\u6784<\/h2>\n\n\n<h3 class=\"wp-block-heading\">3.1 \u4e00\u5f20\u56fe\u770b\u61c2\u5168\u90e8\u6a21\u5757<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                      \u7528\u6237\u6d4f\u89c8\u5668                              \u2502\n\u2502            http:\/\/www.dxkua.cn (80\u7aef\u53e3)                    \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n              \u2502\n              \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502                       nginx (80\u7aef\u53e3)                         \u2502\n\u2502                                                              \u2502\n\u2502  \u6839\u636eURL\u8def\u5f84\u5206\u53d1\u8bf7\u6c42\uff1a                                         \u2502\n\u2502  \/           \u2192 \u524d\u7aef\u9759\u6001\u6587\u4ef6 (index.html + JS\/CSS)             \u2502\n\u2502  \/category\/* \u2192 127.0.0.1:8090  goods_service                \u2502\n\u2502  \/goods\/*    \u2192 127.0.0.1:8090  goods_service                \u2502\n\u2502  \/admin\/*    \u2192 127.0.0.1:8091  admin_service                \u2502\n\u2502  \/user\/*     \u2192 127.0.0.1:8092  user_service                 \u2502\n\u2502  \/collect\/*  \u2192 127.0.0.1:8092  user_service                 \u2502\n\u2502  \/addr\/*     \u2192 127.0.0.1:8092  user_service \u2605\u65b0\u589e           \u2502\n\u2502  \/cart\/*     \u2192 127.0.0.1:8093  order_service                \u2502\n\u2502  \/order\/*    \u2192 127.0.0.1:8093  order_service \u2605\u65b0\u589e           \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n              \u2502\n    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n    \u25bc         \u25bc         \u25bc         \u25bc\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u25028090  \u2502 \u25028091  \u2502 \u25028092  \u2502 \u25028093  \u2502\n\u2502goods \u2502 \u2502admin \u2502 \u2502user  \u2502 \u2502order \u2502\n\u2502\u5546\u54c1   \u2502 \u2502\u7ba1\u7406\u5458\u2502 \u2502\u7528\u6237   \u2502 \u2502\u8ba2\u5355   \u2502\n\u2502\u5206\u7c7b   \u2502 \u2502\u7edf\u8ba1  \u2502 \u2502\u6536\u85cf   \u2502 \u2502\u8d2d\u7269\u8f66\u2502\n\u2502\u4e0a\u4f20   \u2502 \u2502      \u2502 \u2502\u5730\u5740   \u2502 \u2502\u652f\u4ed8   \u2502\n\u2502\u5e93\u5b58   \u2502 \u2502      \u2502 \u2502      \u2502 \u2502      \u2502\n\u2514\u2500\u2500\u252c\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u252c\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u252c\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u252c\u2500\u2500\u2500\u2518\n   \u2502        \u2502        \u2502        \u2502\n   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n                 \u2502\n    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n    \u2502    MySQL (3306\u7aef\u53e3)      \u2502\n    \u2502    \u6570\u636e\u5e93\u540d\uff1amall         \u2502\n    \u2502    \u5171\u4eab\u4e00\u4e2a\u6570\u636e\u5e93         \u2502\n    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510    \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502ZooKeeper \u2502    \u2502  Redis   \u2502\n\u25022181\u7aef\u53e3   \u2502    \u25026379\u7aef\u53e3   \u2502\n\u2502Dubbo\u6ce8\u518c  \u2502    \u2502\u9a8c\u8bc1\u7801\u7f13\u5b58 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518    \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">3.2 \u670d\u52a1\u95f4\u901a\u4fe1\u7684\u4e24\u79cd\u60c5\u51b5<\/h3>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u60c5\u51b5\u4e00\uff1a\u76f4\u63a5\u67e5\u81ea\u5df1\u7684\u6570\u636e\u5e93\uff08\u5927\u591a\u6570\u60c5\u51b5\uff09<\/strong><\/p>\n\n\n<p class=\"wp-block-paragraph\">\u5927\u90e8\u5206\u65f6\u5019\uff0c\u6bcf\u4e2a\u5fae\u670d\u52a1\u7528\u81ea\u5df1\u7684Mapper\u76f4\u63a5\u67e5\u6570\u636e\u5e93\uff0c\u4e0d\u7ecf\u8fc7\u5176\u4ed6\u670d\u52a1\u3002\u6bd4\u5982\uff1auser_service\u67e5user\u8868\u3001order_service\u67e5order\u8868\u3001goods_service\u67e5goods\u8868\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u60c5\u51b5\u4e8c\uff1a\u8de8\u670d\u52a1\u8c03\u7528\uff08\u901a\u8fc7Dubbo RPC\uff09<\/strong><\/p>\n\n\n<p class=\"wp-block-paragraph\">\u5c11\u6570\u65f6\u5019\u4e00\u4e2a\u670d\u52a1\u9700\u8981\u53e6\u4e00\u4e2a\u670d\u52a1\u7684\u6570\u636e\u3002\u6bd4\u5982order_service\u4e0b\u5355\u65f6\u9700\u8981\u67e5\u5546\u54c1\u7684\u5f53\u524d\u4ef7\u683c\u548c\u5e93\u5b58\uff0c\u8fd9\u5c31\u5f97\u8c03goods_service\u3002<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u5728 order_service \u7684 OrderServiceImpl \u4e2d\n@DubboReference                    \/\/ \"\u8fd9\u662f\u4e00\u4e2a\u8fdc\u7a0b\u670d\u52a1\u7684\u5f15\u7528\"\nprivate GoodsService goodsService;  \/\/ \"\u5b83\u5b9e\u73b0\u4e86GoodsService\u63a5\u53e3\"\n\n\/\/ \u4f7f\u7528\u65b9\u5f0f\uff1a\u5c31\u50cf\u672c\u5730\u65b9\u6cd5\u8c03\u7528\u4e00\u6837\nGoods goods = goodsService.selectById(goodsId);\n\/\/ \u2191 \u5b9e\u9645\u53d1\u751f\u7684\u4e8b\u60c5\uff1a\n\/\/ \u2460 Dubbo\u5411ZooKeeper\u67e5\u8be2\"goods_service\u5728\u54ea\u91cc\uff1f\"\n\/\/ \u2461 ZooKeeper\u8fd4\u56de\u5730\u5740 \"192.168.x.x:38090\"\n\/\/ \u2462 Dubbo\u901a\u8fc7\u7f51\u7edc\u628agoodsId\u53d1\u9001\u7ed9goods_service\n\/\/ \u2463 goods_service\u67e5\u6570\u636e\u5e93 \u2192 \u8fd4\u56deGoods\u5bf9\u8c61\n\/\/ \u2464 Dubbo\u628aGoods\u5bf9\u8c61\u5e8f\u5217\u5316 \u2192 \u4f20\u8f93 \u2192 \u53cd\u5e8f\u5217\u5316 \u2192 \u8fd4\u56de\u7ed9order_service<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u8fd9\u4e5f\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48order_service\u53ef\u4ee5\u76f4\u63a5\u67e5addr\u8868<\/strong>\uff1a\u56e0\u4e3a\u6240\u6709\u670d\u52a1\u5171\u4eab\u540c\u4e00\u4e2aMySQL\u6570\u636e\u5e93\uff0corder_service\u53ef\u4ee5\u76f4\u63a5<code>SELECT * FROM addr WHERE id = ?<\/code>\uff0c\u4e0d\u9700\u8981\u8fdc\u7a0b\u8c03\u7528\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">3.3 \u8ba4\u8bc1\u7684\u5b8c\u6574\u6d41\u7a0b\uff08\u4e3a\u4ec0\u4e48\u6bcf\u6b21\u8bf7\u6c42\u90fd\u4f1a&#8221;\u81ea\u52a8\u767b\u5f55&#8221;\uff09<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\u6b65\u9aa4\u2460\uff1a\u767b\u5f55\n  \u7528\u6237\u8f93\u5165\u7528\u6237\u540d+\u5bc6\u7801+\u9a8c\u8bc1\u7801 \u2192 POST \/user\/login\n  \u540e\u7aef\u9a8c\u8bc1\u901a\u8fc7 \u2192 \u751f\u6210JWT = JwtUtil.generateJwt({id:3, username:\"zs\", role:\"user\"})\n  \u540e\u7aef\u8fd4\u56de {\"code\":200, \"data\":\"eyJhbGc...\u5b8c\u6574JWT\u5b57\u7b26\u4e32...\"}\n\n\u6b65\u9aa4\u2461\uff1a\u524d\u7aef\u5b58\u50a8JWT\n  \u524d\u7aef\u6536\u5230JWT \u2192 \u4fdd\u5b58\u5230Pinia store \u2192 pinia-plugin-persistedstate\u81ea\u52a8\u5199\u5165 sessionStorage\n  \u6d4f\u89c8\u5668\u5173\u95ed\u524dJWT\u4e00\u76f4\u6709\u6548\uff1b\u5173\u95ed\u6d4f\u89c8\u5668\u540esessionStorage\u6e05\u7a7a\u2192\u9700\u91cd\u65b0\u767b\u5f55\n\n\u6b65\u9aa4\u2462\uff1a\u6bcf\u6b21\u8bf7\u6c42\u81ea\u52a8\u5e26JWT\n  Axios\u8bf7\u6c42\u62e6\u622a\u5668\uff1a\u6bcf\u6b21\u53d1\u8bf7\u6c42\u524d\uff0c\u4ecestore\u53d6\u51faJWT\uff0c\u5199\u5165 req.headers.token\n  \u7b49\u4e8e\u6bcf\u6b21HTTP\u8bf7\u6c42\u81ea\u52a8\u5728\"\u8bf7\u6c42\u5934\"\u91cc\u544a\u8bc9\u540e\u7aef\"\u6211\u662f\u8c01\"\n\n\u6b65\u9aa4\u2463\uff1a\u540e\u7aef\u9a8c\u8bc1JWT\n  JwtInterceptor\u62e6\u622a\u9700\u8981\u8ba4\u8bc1\u7684\u8def\u5f84\uff08\u5982\/admin\/**\u3001\/cart\/**\uff09\n  \u4ece\u8bf7\u6c42\u5934\u53d6token \u2192 JwtUtil.parseJwtToMap(token) \u9a8c\u8bc1\u7b7e\u540d\u548c\u6709\u6548\u671f\n  \u2192 \u9a8c\u8bc1\u901a\u8fc7 \u2192 \u751f\u6210\u65b0JWT\u653e\u54cd\u5e94\u5934\uff08\u5237\u65b0\u8fc7\u671f\u65f6\u95f4\uff09\u2192 \u653e\u884c\n  \u2192 \u9a8c\u8bc1\u5931\u8d25 \u2192 \u8fd4\u56de403 \u2192 \u524d\u7aef\u5f39\"\u4ee4\u724c\u9519\u8bef\"\u2192 \u8df3\u767b\u5f55\u9875\n\n\u6b65\u9aa4\u2464\uff1aController\u83b7\u53d6\u5f53\u524d\u7528\u6237\n  \u4e0d\u9700\u8981\u62e6\u622a\u5668\u7684\u7aef\u70b9\uff08\u5982\/addr\/**\uff09\uff0cController\u81ea\u5df1\u53d6token\u89e3\u6790\uff1a\n  Integer userId = (Integer) JwtUtil.parseJwtToMap(token).get(\"id\");<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">4. \u8bf7\u6c42\u6d41\u5411<\/h2>\n\n\n<h3 class=\"wp-block-heading\">4.1 \u5b8c\u6574\u6848\u4f8b\uff1a\u7528\u6237\u70b9\u51fb&#8221;\u52a0\u5165\u8d2d\u7269\u8f66&#8221;<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u4ece\u6d4f\u89c8\u5668\u70b9\u51fb\u6309\u94ae\u5230\u5f39&#8221;\u6dfb\u52a0\u6210\u529f&#8221;\uff0c\u8fd9\u80cc\u540e\u4e00\u5171\u67097\u4e2a\u6b65\u9aa4\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u6b65\u9aa4\u2460\uff1a\u7528\u6237\u70b9\u51fb [\u52a0\u5165\u8d2d\u7269\u8f66]\n  GoodsView.vue \u7b2c166\u884c\uff1a\n  &lt;el-button @click=\"insertCart\"&gt;\u52a0\u5165\u8d2d\u7269\u8f66&lt;\/el-button&gt;\n\n\u6b65\u9aa4\u2461\uff1aJavaScript\u51fd\u6570\u6267\u884c\n  GoodsView.vue insertCart()\u51fd\u6570\uff1a\n  cartApi.insert(goods.value.id)     \/\/ \u8c03\u7528API\u51fd\u6570\uff0c\u53c2\u6570\u662f\u5546\u54c1ID\n     .then(resp =&gt; {\n       if (resp.code === 200) {\n         ElMessageBox.confirm('\u52a0\u5165\u8d2d\u7269\u8f66\u6210\u529f\uff0c\u662f\u5426\u8df3\u8f6c\u5230\u8d2d\u7269\u8f66\u9875\u9762')\n       }\n     });\n\n\u6b65\u9aa4\u2462\uff1aAPI\u51fd\u6570\u53d1\u8d77HTTP\u8bf7\u6c42\n  cartApi.js\uff1a\n  insert(goodsId) {\n    return Service.post(`\/cart\/${goodsId}`);  \/\/ POST \/cart\/45\n  }\n\n  Service\u662faxios\u5b9e\u4f8b\uff0cbaseURL = \"http:\/\/www.dxkua.cn\"\n\n\u6b65\u9aa4\u2463\uff1a\u8bf7\u6c42\u62e6\u622a\u5668\u81ea\u52a8\u5e72\u4e24\u4ef6\u4e8b\n  api\/index.js \u8bf7\u6c42\u62e6\u622a\u5668\uff1a\n  req.headers.token = tokenStore.tokenStr;  \/\/ \u9644\u4e0aJWT\n\n  \u6240\u4ee5\u5b9e\u9645\u53d1\u9001\u7684HTTP\u8bf7\u6c42\u662f\uff1a\n  POST http:\/\/www.dxkua.cn\/cart\/45\n  Headers: { token: \"eyJhbGci...\" }\n\n\u6b65\u9aa4\u2464\uff1anginx\u63a5\u6536\u5230\u8bf7\u6c42\uff0c\u6309URL\u8def\u5f84\u8f6c\u53d1\n  nginx.conf:\n  location \/cart { proxy_pass http:\/\/localhost:8093; }\n\n  \u8bf7\u6c42\u88ab\u8f6c\u53d1\u5230 \u2192 http:\/\/localhost:8093\/cart\/45\n\n\u6b65\u9aa4\u2465\uff1aorder_service\u5904\u7406\u8bf7\u6c42\n  CartController:\n  @PostMapping(\"\/{goodsId}\")\n  public RespBean insert(@PathVariable(\"goodsId\") Integer goodsId,\n                         @RequestHeader(\"token\") String token) {\n      Map&lt;String,Object&gt; map = JwtUtil.parseJwtToMap(token);\n      Integer userId = (Integer) map.get(\"id\");   \/\/ \u2192 3\uff08\u5047\u8bbe\u5f53\u524d\u7528\u6237ID\u662f3\uff09\n\n      Cart cart = new Cart();\n      cart.setUserId(3);\n      cart.setGoodsId(45);\n      cartService.insert(cart);  \/\/ \u2192 \u8c03service\u5c42\n\n      return RespBean.success(\"\u6dfb\u52a0\u8d2d\u7269\u8f66\u6210\u529f\");\n  }\n\n  CartServiceImpl.insert():\n  \/\/ \u68c0\u67e5\u8fd9\u4e2a\u5546\u54c1\u662f\u5426\u5df2\u7ecf\u5728\u8d2d\u7269\u8f66\u91cc\u4e86\n  Cart existing = cartMapper.selectByGoodsIdAndUserId(45, 3);\n  if (existing == null) {\n      \/\/ \u7b2c\u4e00\u6b21\u52a0\u5165 \u2192 \u6570\u91cf\u8bbe\u4e3a1 \u2192 \u63d2\u5165\u65b0\u8bb0\u5f55\n      cart.setCount(1);\n      cartMapper.insert(cart);\n  } else {\n      \/\/ \u5df2\u7ecf\u5728\u8d2d\u7269\u8f66 \u2192 \u6570\u91cf+1 \u2192 \u66f4\u65b0\n      existing.setCount(existing.getCount() + 1);\n      cartMapper.update(existing);\n  }\n\n\u6b65\u9aa4\u2466\uff1a\u54cd\u5e94\u6cbf\u7740\u6765\u8def\u8fd4\u56de\n  order_service \u2192 nginx \u2192 \u6d4f\u89c8\u5668\n  \u54cd\u5e94\u62e6\u622a\u5668\u68c0\u67e5 resp.headers.token \u2192 \u6709\u65b0JWT\u5c31\u66f4\u65b0\u672c\u5730\n  \u8fd4\u56de resp.data \u2192 \u5373 {\"code\":200, \"msg\":\"\u6dfb\u52a0\u8d2d\u7269\u8f66\u6210\u529f\", \"data\":null}\n\n\u6b65\u9aa4\u2467\uff1a\u524d\u7aef.then()\u6267\u884c\n  if (resp.code === 200) {\n    ElMessageBox.confirm('\u6dfb\u52a0\u8d2d\u7269\u8f66\u6210\u529f\uff0c\u662f\u5426\u8df3\u8f6c\u5230\u8d2d\u7269\u8f66\u9875\u9762');\n  }\n\n\u5168\u7a0b\u8017\u65f6\uff1a\u901a\u5e38100-300ms\uff08\u5c40\u57df\u7f51\u73af\u5883\uff09<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">5. \u6570\u636e\u5e93\u8bbe\u8ba1<\/h2>\n\n\n<h3 class=\"wp-block-heading\">5.1 \u4e3a\u4ec0\u4e48\u6570\u636e\u5e93\u8bbe\u8ba1\u91cd\u8981<\/h3>\n\n\n<p class=\"wp-block-paragraph\">\u6570\u636e\u5e93\u662f\u6574\u4e2a\u9879\u76ee\u7684&#8221;\u5730\u57fa&#8221;\u3002\u6240\u6709\u529f\u80fd\u672c\u8d28\u4e0a\u5c31\u662f\u5bf9\u6570\u636e\u5e93\u7684&#8221;\u589e\u5220\u6539\u67e5&#8221;\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u6ce8\u518c = INSERT INTO user<\/li>\n<li>\u641c\u7d22\u5546\u54c1 = SELECT FROM goods WHERE &#8230;<\/li>\n<li>\u4e0b\u5355 = INSERT INTO order<\/li>\n<li>\u652f\u4ed8\u6210\u529f = UPDATE order SET status=1<\/li>\n<li>\u5e93\u5b58\u6263\u51cf = UPDATE goods SET count=count-N<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\">\u6570\u636e\u5e93\u5b57\u6bb5\u5b9a\u4e49\u9519\u4e86 \u2192 \u540e\u7aef\u8981\u5199\u5f88\u591a\u989d\u5916\u4ee3\u7801\u6765\u8865\u6551 \u2192 \u524d\u7aef\u5c55\u793a\u4e5f\u53ef\u80fd\u6709\u95ee\u9898\u3002\u6240\u4ee5\u4e00\u4e2a\u597d\u7684\u6570\u636e\u5e93\u8bbe\u8ba1\u80fd\u8ba9\u540e\u9762\u7684\u5f00\u53d1\u4e8b\u534a\u529f\u500d\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">5.2 \u6838\u5fc3\u8868\u8be6\u7ec6\u8bf4\u660e<\/h3>\n\n\n<h4 class=\"wp-block-heading\">addr \u2014 \u7528\u6237\u6536\u8d27\u5730\u5740<\/h4>\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE `addr` (\n    `id`       int UNSIGNED    NOT NULL AUTO_INCREMENT  COMMENT '\u81ea\u589e\u4e3b\u952e',\n    `contact`  varchar(20)     NOT NULL                 COMMENT '\u6536\u8d27\u4eba\u59d3\u540d',\n    `phone`    varchar(11)     NOT NULL                 COMMENT '\u6536\u8d27\u4eba\u624b\u673a\u53f7',\n    `province` varchar(20)     DEFAULT NULL             COMMENT '\u7701\u4efd',\n    `city`     varchar(20)     DEFAULT NULL             COMMENT '\u57ce\u5e02',\n    `district` varchar(20)     DEFAULT NULL             COMMENT '\u533a\u53bf',\n    `street`   varchar(20)     DEFAULT NULL             COMMENT '\u8857\u9053',\n    `address`  varchar(255)    NOT NULL                 COMMENT '\u8be6\u7ec6\u95e8\u724c\u53f7',\n    `user_id`  int UNSIGNED    NOT NULL                 COMMENT '\u8fd9\u4e2a\u5730\u5740\u662f\u8c01\u7684',\n    `status`   tinyint         DEFAULT 0                COMMENT '0=\u666e\u901a\u5730\u5740 1=\u9ed8\u8ba4\u6536\u8d27\u5730\u5740',\n    PRIMARY KEY (`id`),\n    INDEX `user_id`(`user_id`),\n    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE\n) COMMENT='\u7528\u6237\u6536\u8d27\u5730\u5740\u8868';<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u7701\u5e02\u533a\u8857\u9053\u5206\u5f00\u5b58\uff0c\u800c\u4e0d\u662f\u5b58\u5728\u4e00\u4e2a\u5927\u5b57\u6bb5\u91cc\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u5206\u5f00\u5b58\u53ef\u4ee5\u505a\u7edf\u8ba1\u5206\u6790\uff1a\u54ea\u4e2a\u57ce\u5e02\u7684\u7528\u6237\u6700\u591a<\/li>\n<li>\u5206\u5f00\u5b58\u53ef\u4ee5\u505a\u7701\u5e02\u533a\u4e09\u7ea7\u8054\u52a8\u9009\u62e9\u5668\uff08\u524d\u7aefUI\u7ec4\u4ef6\uff09<\/li>\n<li>\u5206\u5f00\u5b58\u6bd4\u4e00\u4e2a\u5927\u5b57\u6bb5\u7075\u6d3b<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48<code>status=1<\/code>\u662f\u9ed8\u8ba4\u5730\u5740\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>0<\/code>\u5728\u6570\u636e\u5e93\u4e2d\u901a\u5e38\u662f&#8221;\u5426&#8221;\u7684\u610f\u601d\uff0c<code>1<\/code>\u662f&#8221;\u662f&#8221;<\/li>\n<li>\u6bcf\u4e2a\u7528\u6237\u540c\u4e00\u65f6\u95f4\u53ea\u80fd\u6709\u4e00\u4e2a\u9ed8\u8ba4\u5730\u5740\u2192\u8bbe\u65b0\u9ed8\u8ba4\u65f6\u5148\u628a\u6240\u6709\u5730\u5740\u7684\u90fd\u6e05\u62100\uff0c\u518d\u628a\u76ee\u6807\u7f6e\u62101<\/li>\n<li>\u8fd9\u662f\u6700\u7b80\u6d01\u7684\u8868\u793a\u65b9\u5f0f\uff0c\u4e0d\u9700\u8981\u989d\u5916\u4e00\u5f20&#8221;\u9ed8\u8ba4\u5730\u5740\u6620\u5c04\u8868&#8221;<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>ON DELETE CASCADE \u662f\u4ec0\u4e48\u610f\u601d\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u5982\u679cuser\u8868\u91cc\u5220\u4e86\u4e00\u4e2a\u7528\u6237\uff0c\u4ed6\u6240\u6709\u7684\u6536\u8d27\u5730\u5740\u81ea\u52a8\u5220\u9664<\/li>\n<li>\u907f\u514d&#8221;\u5b64\u513f\u6570\u636e&#8221;\uff1a\u5730\u5740\u8fd8\u5728\u4f46\u7528\u6237\u5df2\u7ecf\u4e0d\u5b58\u5728\u4e86<\/li>\n\n<\/ul>\n\n\n<h4 class=\"wp-block-heading\">order \u2014 \u8ba2\u5355<\/h4>\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE `order` (\n    `id`          bigint UNSIGNED NOT NULL               COMMENT '\u8ba2\u5355\u53f7',\n    `user_id`     int UNSIGNED    NOT NULL               COMMENT '\u8c01\u4e0b\u7684\u5355',\n    `create_time` datetime        DEFAULT CURRENT_TIMESTAMP COMMENT '\u4e0b\u5355\u65f6\u95f4',\n    `express`     varchar(50)     DEFAULT NULL           COMMENT '\u5feb\u9012\u5355\u53f7\uff08\u53d1\u8d27\u540e\u624d\u6709\uff09',\n    `pay_type`    tinyint         DEFAULT NULL           COMMENT '1=\u652f\u4ed8\u5b9d 2=\u5fae\u4fe1 3=\u94f6\u884c\u5361',\n    `addr_id`     int UNSIGNED    NOT NULL               COMMENT '\u54ea\u4e2a\u5730\u5740\u9001',\n    `addr_detail` varchar(255)    NOT NULL               COMMENT '\u5b8c\u6574\u7684\u5730\u5740\u6587\u672c\uff08\u4e0b\u5355\u65f6\u7684\u5feb\u7167\uff09',\n    `status`      tinyint         DEFAULT 0              COMMENT '0\u5f85\u4ed8\u6b3e 1\u5df2\u4ed8\u6b3e 2\u5df2\u53d1\u8d27 3\u5df2\u5b8c\u6210 4\u5df2\u53d6\u6d88',\n    `items`       text            DEFAULT NULL           COMMENT '\u2605\u8ba2\u5355\u91cc\u4e70\u4e86\u4ec0\u4e48\uff08JSON\u683c\u5f0f\uff09',\n    PRIMARY KEY (`id`),\n    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`),\n    FOREIGN KEY (`addr_id`) REFERENCES `addr`(`id`)\n) COMMENT='\u8ba2\u5355\u4e3b\u8868';<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u8ba2\u5355ID\u7528bigint\uff08\u96ea\u82b1\u7b97\u6cd5\uff09\u800c\u4e0d\u662fauto_increment\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u96ea\u82b1\u7b97\u6cd5\u751f\u6210\u7684ID\u662f\u5168\u5c40\u552f\u4e00\u7684\u5206\u5e03\u5f0fID\uff0c\u4e0d\u4f9d\u8d56\u6570\u636e\u5e93\u81ea\u589e<\/li>\n<li>\u591a\u4e2a\u5fae\u670d\u52a1\u53ef\u80fd\u540c\u65f6\u521b\u5efa\u8ba2\u5355\uff0c\u81ea\u589eID\u5728\u9ad8\u5e76\u53d1\u4e0b\u53ef\u80fd\u51b2\u7a81\u6216\u6709\u6027\u80fd\u74f6\u9888<\/li>\n<li>\u96ea\u82b1ID\u7684\u7f3a\u70b9\u662f\u5b83\u662f19\u4f4d\u6570\u5b57\u2192JS\u7684Number\u5b58\u4e0d\u4e0b\u2192\u9700\u8981\u5e8f\u5217\u5316\u6210String<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48<code>addr_detail<\/code>\u8981\u5b58\u4e00\u4efd\u5feb\u7167\uff0c\u800c\u4e0d\u662f\u53ea\u5b58<code>addr_id<\/code>\u53bb\u67e5\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u7528\u6237\u4e0b\u5355\u540e\u53ef\u80fd\u628a\u6536\u8d27\u5730\u5740\u6539\u4e86\/\u5220\u4e86\u2192\u5982\u679c\u53ea\u5b58addr_id\uff0c\u67e5\u5230\u7684\u5730\u5740\u5df2\u7ecf\u4e0d\u662f\u4e0b\u5355\u65f6\u7684\u5730\u5740\u4e86<\/li>\n<li>\u8d2d\u7269\u5386\u53f2\u8bb0\u5f55\u5fc5\u987b\u4fdd\u7559\u539f\u59cb\u6570\u636e\uff0c\u8fd9\u662f\u4e00\u6761\u5546\u4e1a\u539f\u5219<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48<code>items<\/code>\u7528JSON\u4e2d\u6587\u800c\u4e0d\u662f\u65b0\u5efa\u4e00\u5f20<code>order_detail<\/code>\u8868\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u8fd9\u662f\u672c\u6b21\u5f00\u53d1\u7684\u53d6\u820d\uff1a\u4e0d\u5efa\u65b0\u8868\uff0c\u51cf\u5c11\u6570\u636e\u5e93\u53d8\u66f4<\/li>\n<li>JSON\u65b9\u5f0f\u7684\u4f18\u70b9\uff1a\u4e00\u4e2a\u8ba2\u5355\u7684\u6240\u6709\u5546\u54c1\u4fe1\u606f\u5b58\u5728\u4e00\u884c\u91cc\uff0c\u67e5\u8be2\u5feb\uff1b\u7ed3\u6784\u7075\u6d3b\uff0c\u60f3\u52a0\u5b57\u6bb5\u76f4\u63a5\u6539JSON<\/li>\n<li>JSON\u65b9\u5f0f\u7684\u7f3a\u70b9\uff1a\u4e0d\u80fd\u7528SQL\u76f4\u63a5\u5728\u6570\u636e\u5e93\u91cc\u7edf\u8ba1&#8221;\u672c\u6708\u54ea\u4e2a\u5546\u54c1\u5356\u5f97\u6700\u597d&#8221;\uff08\u9700\u8981\u5728Java\u4ee3\u7801\u91cc\u89e3\u6790JSON\u7136\u540e\u8ba1\u7b97\uff09<\/li>\n<li>\u751f\u4ea7\u73af\u5883\u5efa\u8bae\u7528order_detail\u8868\uff0c\u4f46\u672c\u9879\u76ee\u9009\u62e9&#8221;\u4e0d\u5efa\u65b0\u8868&#8221;\u6765\u51cf\u5c11\u6570\u636e\u5e93\u53d8\u66f4<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>items\u5217\u7684JSON\u5185\u5bb9\u793a\u4f8b<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>[\n    {\n        \"goodsId\": 1,\n        \"goodsName\": \"\u5c0f\u7c7314 Ultra\",\n        \"goodsPic\": \"abc123.jpg\",\n        \"price\": 5999.00,\n        \"count\": 2,\n        \"subtotal\": 11998.00\n    }\n]<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u8ba2\u5355\u72b6\u6001\u673a<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>0(\u5f85\u4ed8\u6b3e) \u2500\u2500\u4ed8\u6b3e\u2500\u2500\u2192 1(\u5df2\u4ed8\u6b3e) \u2500\u2500\u53d1\u8d27\u2500\u2500\u2192 2(\u5df2\u53d1\u8d27) \u2500\u2500\u786e\u8ba4\u2500\u2500\u2192 3(\u5df2\u5b8c\u6210)\n    \u2502                      \u2502                      \u2502\n    \u2514\u2500\u2500\u53d6\u6d88\u2500\u2500\u2192 4(\u5df2\u53d6\u6d88)    \u2514\u2500\u2500\u53d6\u6d88\u2500\u2500\u2192 4(\u5df2\u53d6\u6d88)  \u2514\u2500\u2500\u53d6\u6d88\u2500\u2500\u2192 4(\u5df2\u53d6\u6d88)\n\n\u5b9a\u65f6\u4efb\u52a1\uff1astatus=0 \u8d85\u8fc730\u5206\u949f \u2192 \u81ea\u52a8 \u2192 4(\u5df2\u53d6\u6d88)<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\">goods \u2014 \u5546\u54c1<\/h4>\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE `goods` (\n    `id`             int UNSIGNED    NOT NULL AUTO_INCREMENT,\n    `name`           varchar(100)    NOT NULL            COMMENT '\u5546\u54c1\u540d\u79f0',\n    `decp`           varchar(255)    DEFAULT NULL        COMMENT '\u4e00\u53e5\u8bdd\u63cf\u8ff0',\n    `detail`         text            DEFAULT NULL        COMMENT '\u8be6\u7ec6\u56fe\u6587\u63cf\u8ff0\uff08\u5bcc\u6587\u672cHTML\uff09',\n    `price`          decimal(10,2)   NOT NULL            COMMENT '\u5b9e\u9645\u552e\u4ef7',\n    `market_price`   decimal(10,2)   DEFAULT NULL        COMMENT '\u5e02\u573a\u53c2\u8003\u4ef7',\n    `purchase_price` decimal(10,2)   DEFAULT NULL        COMMENT '\u8fdb\u8d27\u4ef7',\n    `color`          varchar(50)     DEFAULT NULL        COMMENT '\u989c\u8272',\n    `version`        varchar(50)     DEFAULT NULL        COMMENT '\u7248\u672c',\n    `count`          int UNSIGNED    DEFAULT 0           COMMENT '\u5f53\u524d\u5e93\u5b58\u6570\u91cf',\n    `recom`          tinyint         DEFAULT 0           COMMENT '0\u4e0d\u63a8\u8350 1\u9996\u9875\u63a8\u8350',\n    `category_id`    int UNSIGNED    NOT NULL            COMMENT '\u6240\u5c5e\u5206\u7c7bID',\n    `score`          float           DEFAULT 0           COMMENT '\u5e73\u5747\u8bc4\u5206',\n    `status`         tinyint         DEFAULT 0           COMMENT '0\u4e0b\u67b6 1\u4e0a\u67b6',\n    PRIMARY KEY (`id`),\n    FOREIGN KEY (`category_id`) REFERENCES `category`(`id`)\n);<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u4ef7\u683c\u7528decimal(10,2)\u800c\u4e0d\u662ffloat\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>float\u662f\u8fd1\u4f3c\u503c\uff0c\u505a\u8ba1\u7b97\u4f1a\u6709\u7cbe\u5ea6\u8bef\u5dee\uff080.1+0.2!=0.3\u8fd9\u79cd\u7ecf\u5178\u7684\u6d6e\u70b9\u6570\u95ee\u9898\uff09<\/li>\n<li>decimal\u662f\u7cbe\u786e\u503c\uff0c\u505a\u91d1\u989d\u8ba1\u7b97\u4e0d\u4f1a\u4e22\u7cbe\u5ea6\u2192\u4e8b\u5173\u91d1\u94b1\uff0c\u5fc5\u987b\u7528decimal<\/li>\n<li>(10,2)\u8868\u793a\u603b\u517110\u4f4d\u6570\u5b57\uff0c\u5176\u4e2d2\u4f4d\u662f\u5c0f\u6570\u2192\u6700\u591a99999999.99\u5143<\/li>\n\n<\/ul>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u540c\u540d\u79f0+\u540c\u989c\u8272+\u540c\u7248\u672c=\u91cd\u590d\u5546\u54c1\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u8fd9\u662fGoodsServiceImpl\u91ccinsert\u65b9\u6cd5\u5b9a\u4e49\u7684\u552f\u4e00\u6027\u7ea6\u675f<\/li>\n<li>&#8220;\u5c0f\u7c7314\u3001\u9ed1\u8272\u300116+512GB&#8221;\u548c&#8221;\u5c0f\u7c7314\u3001\u767d\u8272\u30018+256GB&#8221;\u662f\u4e0d\u540c\u7684\u5546\u54c1<\/li>\n<li>\u4e09\u8005\u5fc5\u987b\u5b8c\u5168\u76f8\u540c\u624d\u7b97\u91cd\u590d<\/li>\n\n<\/ul>\n\n\n<h4 class=\"wp-block-heading\">collect \u2014 \u6536\u85cf<\/h4>\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE `collect` (\n    `id`          int UNSIGNED NOT NULL AUTO_INCREMENT,\n    `goods_id`    int UNSIGNED NOT NULL,\n    `user_id`     int UNSIGNED NOT NULL,\n    `create_time` datetime     DEFAULT CURRENT_TIMESTAMP,\n    PRIMARY KEY (`id`),\n    FOREIGN KEY (`goods_id`) REFERENCES `goods`(`id`) ON DELETE CASCADE,\n    FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE\n);<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48goods_id\u548cuser_id\u7528\u5916\u952e\u7ea6\u675f\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u9632\u6b62\u810f\u6570\u636e\uff1a\u5982\u679c\u5546\u54c1\u88ab\u5220\u4e86(cascade)\uff0c\u6536\u85cf\u8bb0\u5f55\u81ea\u52a8\u5220\u6389\uff0c\u907f\u514d\u7528\u6237\u6536\u85cf\u91cc\u51fa\u73b0&#8221;\u5e7d\u7075\u5546\u54c1&#8221;<\/li>\n<li>\u4e00\u5bf9(goods_id, user_id)\u552f\u4e00\uff1aCoullectServiceImpl.insert\u91cc\u4f1a\u5148\u67e5\u662f\u5426\u5df2\u6536\u85cf\uff0c\u907f\u514d\u540c\u4e00\u7528\u6237\u91cd\u590d\u6536\u85cf\u540c\u4e00\u5546\u54c1<\/li>\n\n<\/ul>\n\n\n<h4 class=\"wp-block-heading\">Other tables \u2014 \u5176\u4ed6\u8868\uff08\u7b80\u8ff0\uff09<\/h4>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u8868<\/th>\n<th>\u7528\u9014<\/th>\n<th>\u5173\u952e\u5b57\u6bb5<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>user<\/code><\/td>\n<td>\u7528\u6237<\/td>\n<td>username(\u552f\u4e00)\u3001password(MD5+salt\u52a0\u5bc6)\u3001status(0\u672a\u8ba4\u8bc1\/1\u6b63\u5e38\/2\u7981\u7528\/3\u6ce8\u9500)<\/td>\n<\/tr>\n<tr>\n<td><code>admin<\/code><\/td>\n<td>\u7ba1\u7406\u5458<\/td>\n<td>\u540cuser\u8868\u7ed3\u6784\uff0cstatus(0\u6b63\u5e38\/1\u7981\u7528)<\/td>\n<\/tr>\n<tr>\n<td><code>cart<\/code><\/td>\n<td>\u8d2d\u7269\u8f66<\/td>\n<td>user_id + goods_id + count(\u6570\u91cf)<\/td>\n<\/tr>\n<tr>\n<td><code>category<\/code><\/td>\n<td>\u5546\u54c1\u5206\u7c7b<\/td>\n<td>parent_id(\u81ea\u5f15\u7528\uff1a0=\u9876\u7ea7\u5206\u7c7b\uff0c\u5176\u4ed6=\u7236\u5206\u7c7bID)\uff0c\u5f62\u6210\u6811\u5f62\u7ed3\u6784<\/td>\n<\/tr>\n<tr>\n<td><code>goods_pic<\/code><\/td>\n<td>\u5546\u54c1\u56fe\u7247<\/td>\n<td>url(\u56fe\u7247\u6587\u4ef6\u540d) + goods_id(\u6240\u5c5e\u5546\u54c1)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">6. common\u516c\u5171\u6a21\u5757<\/h2>\n\n\n<p class=\"wp-block-paragraph\">common\u6a21\u5757\u662f\u6240\u6709\u5fae\u670d\u52a1\u7684&#8221;\u5171\u4eab\u5de5\u5177\u7bb1&#8221;\u2014\u2014\u8fd9\u91cc\u9762\u7684\u4ee3\u78014\u4e2a\u5fae\u670d\u52a1\u90fd\u4f1a\u7528\u5230\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">6.1 JacksonConfig \u2014 \u6551\u547d\u7684\u914d\u7f6e<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\u8def\u5f84\uff1acommon\/...\/config\/JacksonConfig.java\n\npackage org.example.mall.common.config;\n\nimport com.fasterxml.jackson.databind.ser.std.ToStringSerializer;\nimport org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n\/**\n * Jackson \u5168\u5c40\u5e8f\u5217\u5316\u914d\u7f6e\n * \n * \u3010\u8981\u89e3\u51b3\u4ec0\u4e48\u95ee\u9898\u3011\n * \u8ba2\u5355\u53f7\u662f\u96ea\u82b1\u7b97\u6cd5\u751f\u6210\u768419\u4f4dLong\uff1a1876543210987654321\n * JavaScript\u7684 Number \u7c7b\u578b\u6700\u5927\u5b89\u5168\u6574\u6570\u662f 9007199254740992\uff0816\u4f4d\uff09\n * 19\u4f4d\u7684Long\u7ecfJSON\u5e8f\u5217\u5316\u6210\u6570\u5b57\u540e\uff0c\u524d\u7aefJSON.parse\u4f1a\u4e22\u5931\u672b\u5c3e\u51e0\u4f4d\u7684\u503c\n * \u6bd4\u5982\u540e\u7aef\u8fd4\u56de {\"id\":1876543210987654321}\n *    \u524d\u7aef\u89e3\u6790\u53d8\u6210 {\"id\":1876543210987654400}  \u2190 \u672b\u5c3e79\u88ab\u622a\u65ad\uff01\n *    \u4e4b\u540e\u7528\u8fd9\u4e2a\u9519\u7684id\u53bb\u652f\u4ed8\/\u53d6\u6d88\/\u67e5\u8be2 \u2192 \u5168\u90e8\u5931\u8d25\n * \n * \u3010\u600e\u4e48\u89e3\u51b3\u7684\u3011\n * \u628a\u6240\u6709\u7684Long\/long\u5728\u5e8f\u5217\u5316\u65f6\u8f93\u51fa\u4e3a\u5b57\u7b26\u4e32\n * \u540e\u7aef\u8fd4\u56de {\"id\":\"1876543210987654321\"}\n * \u524d\u7aefJSON.parse\u62ff\u5230\u5b57\u7b26\u4e32 \"1876543210987654321\" \u2192 \u4e0d\u4e22\u7cbe\u5ea6\n * \n * \u3010\u4e3a\u4ec0\u4e48\u4e0d\u5f71\u54cd\u5176\u4ed6\u4ee3\u7801\u3011\n * - String\u2192Long\u7684\u53cd\u5e8f\u5217\u5316Jackson\u539f\u751f\u652f\u6301\uff08JSON \"123\" \u2192 Java Long 123\uff09\n * - Spring MVC\u7684@PathVariable\u4e5f\u662f\u7528String\u2192Long\u7684\u8f6c\u6362\u5668\n * - \u672c\u9879\u76ee\u53ea\u6709Order.id\u662fLong\uff0c\u5176\u4ed6Bean\u5168\u662fInteger \u2192 \u53ea\u5f71\u54cd\u8ba2\u5355\u53f7\n *\/\n@Configuration\npublic class JacksonConfig {\n\n    @Bean\n    public Jackson2ObjectMapperBuilderCustomizer longToStringCustomizer() {\n        return builder -&gt; {\n            \/\/ Long\u662f\u5305\u88c5\u7c7b\u578b\uff08\u53ef\u80fd\u4e3anull\uff09\uff0clong\u662f\u57fa\u672c\u7c7b\u578b\uff08\u4e0d\u80fd\u4e3anull\uff09\n            \/\/ \u4e24\u4e2a\u90fd\u8981\u8bbe\u7f6e\n            builder.serializerByType(Long.class, ToStringSerializer.instance);\n            builder.serializerByType(long.class, ToStringSerializer.instance);\n        };\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>@Configuration<\/code> \u544a\u8bc9Spring\uff1a&#8221;\u8fd9\u662f\u4e00\u4e2a\u914d\u7f6e\u7c7b\uff0c\u542f\u52a8\u65f6\u52a0\u8f7d\u5b83&#8221;\n<code>@Bean<\/code> \u544a\u8bc9Spring\uff1a&#8221;\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de\u7684\u5bf9\u8c61\u8981\u653e\u5230Spring\u5bb9\u5668\u91cc\uff0c\u5176\u4ed6\u5730\u65b9\u53ef\u4ee5\u7528&#8221;\n<code>Jackson2ObjectMapperBuilderCustomizer<\/code> \u662fSpring Boot\u63d0\u4f9b\u7684&#8221;\u81ea\u5b9a\u4e49Jackson\u884c\u4e3a\u7684\u94a9\u5b50&#8221;\n<code>ToStringSerializer.instance<\/code> \u662fJackson\u63d0\u4f9b\u7684&#8221;\u628a\u4efb\u4f55\u5bf9\u8c61\u8f6c\u6210String&#8221;\u7684\u5e8f\u5217\u5316\u5668<\/p>\n\n\n<h3 class=\"wp-block-heading\">6.2 RespBean \u2014 \u7edf\u4e00\u54cd\u5e94\u683c\u5f0f<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\u8def\u5f84\uff1acommon\/...\/bean\/RespBean.java\n\npackage org.example.mall.common.bean;\n\nimport lombok.AllArgsConstructor;\nimport lombok.Data;\nimport lombok.NoArgsConstructor;\n\n\/**\n * \u7edf\u4e00\u54cd\u5e94\u4f53\uff1a\u6240\u6709\u540e\u7aef\u63a5\u53e3\u8fd4\u56de\u7684\u6570\u636e\u90fd\u7528\u8fd9\u4e2a\u683c\u5f0f\u5305\u88c5\n * \n * \u3010\u4e3a\u4ec0\u4e48\u9700\u8981\u7edf\u4e00\u683c\u5f0f\u3011\n * \u5982\u679c\u4e0d\u7edf\u4e00\uff1a\n *   \u6709\u7684\u63a5\u53e3\u8fd4\u56de {\"status\":\"ok\", \"user\":{\"name\":\"\u5f20\u4e09\"}}\n *   \u6709\u7684\u63a5\u53e3\u8fd4\u56de {\"code\":200, \"message\":\"\u6210\u529f\", \"result\":{\"name\":\"\u5f20\u4e09\"}}\n * \u524d\u7aef\u8981\u9488\u5bf9\u6bcf\u4e2a\u63a5\u53e3\u5199\u4e0d\u540c\u7684\u89e3\u6790\u903b\u8f91\uff0c\u7ef4\u62a4\u6210\u672c\u6781\u9ad8\n * \n * \u7edf\u4e00\u683c\u5f0f\u540e\uff1a\n *   \u6240\u6709\u63a5\u53e3\u8fd4\u56de {\"code\":200, \"msg\":\"\u6210\u529f\", \"data\":{...}}\n *   \u524d\u7aef\u53ea\u9700\u8981\u68c0\u67e5 resp.code === 200 \u2192 \u53d6 resp.data\n *\/\n@Data\n@NoArgsConstructor\n@AllArgsConstructor\npublic class RespBean {\n    private Integer code;   \/\/ 200=\u6210\u529f, 500=\u5931\u8d25\n    private String  msg;    \/\/ \u63d0\u793a\u4fe1\u606f\uff08\u524d\u7aef\u76f4\u63a5\u62ff\u6765\u5f39toast\uff09\n    private Object  data;   \/\/ \u4e1a\u52a1\u6570\u636e\uff08\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\uff1a\u5bf9\u8c61\u3001\u5217\u8868\u3001\u5b57\u7b26\u4e32\u3001null\uff09\n\n    \/\/ \u5de5\u5382\u65b9\u6cd5\uff1a\u7701\u53bb\u6bcf\u6b21\u624b\u52a8 new RespBean(200, msg, null)\n    public static RespBean success(String msg) {\n        return new RespBean(200, msg, null);\n    }\n    public static RespBean success(String msg, Object data) {\n        return new RespBean(200, msg, data);\n    }\n    public static RespBean error(String msg) {\n        return new RespBean(500, msg, null);\n    }\n    public static RespBean error(Integer code, String msg) {\n        return new RespBean(code, msg, null);\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>@Data<\/code> = Lombok\u81ea\u52a8\u751f\u6210 getter\/setter\/toString\/equals\/hashCode\n<code>@NoArgsConstructor<\/code> = \u81ea\u52a8\u751f\u6210\u65e0\u53c2\u6784\u9020\u51fd\u6570\uff08<code>new RespBean()<\/code>\uff09\n<code>@AllArgsConstructor<\/code> = \u81ea\u52a8\u751f\u6210\u5168\u53c2\u6784\u9020\u51fd\u6570\uff08<code>new RespBean(200, \"\u6210\u529f\", null)<\/code>\uff09<\/p>\n\n\n<h3 class=\"wp-block-heading\">6.3 JwtInterceptor \u2014 \u8ba4\u8bc1\u62e6\u622a\u5668<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\u8def\u5f84\uff1acommon\/...\/intercepter\/JwtInterceptor.java\n\npackage org.example.mall.common.intercepter;\n\n@Component\npublic class JwtInterceptor implements HandlerInterceptor {\n\n    @Autowired\n    private WhiteListConfig whiteListConfig;  \/\/ \u767d\u540d\u5355\u914d\u7f6e\uff08\u54ea\u4e9b\u8def\u5f84\u4e0d\u7528\u767b\u5f55\uff09\n\n    @Override\n    public boolean preHandle(HttpServletRequest request,\n                             HttpServletResponse response,\n                             Object handler) throws Exception {\n\n        String path = request.getRequestURI();     \/\/ \u5f53\u524d\u8bf7\u6c42\u7684URL\u8def\u5f84\n        String method = request.getMethod();        \/\/ GET \/ POST \/ PUT \/ DELETE\n\n        \/\/ ====== \u7b2c\u4e00\u6b65\uff1a\u767d\u540d\u5355\u68c0\u67e5 ======\n        \/\/ \u5982\u679c\u5f53\u524d\u8def\u5f84\u5728\u767d\u540d\u5355\u91cc\uff0c\u76f4\u63a5\u653e\u884c\uff0c\u4e0d\u68c0\u67e5token\n        if (whiteListConfig.getRules() != null &amp;&amp;\n            whiteListConfig.getRules().stream()\n                .anyMatch(rule -&gt;\n                    rule.getMethod().equalsIgnoreCase(method) &amp;&amp;  \/\/ \u65b9\u6cd5\u5339\u914d\uff08\u5982GET\uff09\n                    path.matches(rule.getRegpath()))) {            \/\/ \u8def\u5f84\u5339\u914d\uff08\u6b63\u5219\uff09\n            return true;  \/\/ \u2190 return true = \u653e\u884c\n        }\n\n        \/\/ ====== \u7b2c\u4e8c\u6b65\uff1aOPTIONS\u9884\u68c0\u653e\u884c ======\n        \/\/ \u6d4f\u89c8\u5668\u5728\u8de8\u57df\u8bf7\u6c42\u524d\u4f1a\u5148\u53d1\u4e00\u4e2aOPTIONS\u8bf7\u6c42\"\u63a2\u8def\"\n        \/\/ \u8fd9\u4e2a\u8bf7\u6c42\u4e0d\u6d89\u53ca\u8ba4\u8bc1\uff0c\u76f4\u63a5\u653e\u884c\n        if (\"OPTIONS\".equals(request.getMethod().toUpperCase())) {\n            return true;\n        }\n\n        \/\/ ====== \u7b2c\u4e09\u6b65\uff1a\u4ece\u8bf7\u6c42\u5934\u53d6token ======\n        String token = request.getHeader(\"token\");\n        RespBean respBean = null;\n\n        try {\n            \/\/ ====== \u7b2c\u56db\u6b65\uff1a\u89e3\u6790JWT ======\n            \/\/ \u8fd9\u91cc\u4f1a\u9a8c\u8bc1\u7b7e\u540d\u3001\u68c0\u67e5\u8fc7\u671f\u65f6\u95f4\n            \/\/ \u5982\u679c\u51fa\u9519\uff0c\u4f1a\u629b\u4e0b\u97624\u79cd\u5f02\u5e38\u4e4b\u4e00\n            Map&lt;String, Object&gt; map = JwtUtil.parseJwtToMap(token);\n\n            \/\/ ====== \u7b2c\u4e94\u6b65\uff1a\u751f\u6210\u65b0JWT\uff08\u5237\u65b0\u8fc7\u671f\u65f6\u95f4\uff09=====\n            \/\/ \u6bcf\u6b21\u8bf7\u6c42\u90fd\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684JWT\u2192\u53ea\u8981\u7528\u6237\u6301\u7eed\u64cd\u4f5c\uff0c\u5c31\u4e0d\u4f1a\u8fc7\u671f\n            String jwt = JwtUtil.generateJwt(map);\n\n            \/\/ \u628a\u65b0JWT\u653e\u5728\u54cd\u5e94\u5934\u91cc\u2192\u524d\u7aef\u54cd\u5e94\u62e6\u622a\u5668\u4f1a\u81ea\u52a8\u53d1\u73b0\u5e76\u66f4\u65b0\n            response.setHeader(\"token\", jwt);\n            \/\/ \u544a\u8bc9\u6d4f\u89c8\u5668\"token\"\u8fd9\u4e2a\u54cd\u5e94\u5934\u524d\u7aef\u53ef\u4ee5\u8bfb\uff08\u5b89\u5168\u7b56\u7565\u9ed8\u8ba4\u4e0d\u8ba9\u8bfb\u81ea\u5b9a\u4e49\u5934\uff09\n            response.setHeader(\"Access-Control-Expose-Headers\", \"token\");\n\n            return true;  \/\/ \u653e\u884c\n\n        } catch (SignatureVerificationException e) {\n            \/\/ JWT\u7b7e\u540d\u9a8c\u8bc1\u5931\u8d25 \u2192 \u8bf4\u660eJWT\u88ab\u7be1\u6539\u8fc7\n            respBean = RespBean.error(\"\u65e0\u6548\u7b7e\u540d\");\n        } catch (TokenExpiredException e) {\n            \/\/ JWT\u5df2\u8fc7\u671f\n            respBean = RespBean.error(\"\u4ee4\u724c\u8d85\u65f6\");\n        } catch (AlgorithmMismatchException e) {\n            \/\/ \u52a0\u5bc6\u7b97\u6cd5\u4e0d\u5339\u914d\uff08\u6bd4\u5982\u4ee5\u524d\u7528HS256\u73b0\u5728\u7528RS256\uff09\n            respBean = RespBean.error(\"\u7b97\u6cd5\u4e0d\u5339\u914d\");\n        } catch (Exception e) {\n            \/\/ \u5176\u4ed6\u4efb\u4f55JWT\u89e3\u6790\u5f02\u5e38\n            respBean = RespBean.error(\"\u4ee4\u724c\u65e0\u6548\");\n        }\n\n        \/\/ ====== \u7b2c\u516d\u6b65\uff1a\u8fd4\u56de403\u9519\u8bef ======\n        \/\/ HttpServletResponse.SC_FORBIDDEN = 403\n        \/\/ \u6ce8\u610f\uff1a\u8fd9\u91cc\u76f4\u63a5\u7528Jackson\u5199JSON\u5230\u54cd\u5e94\u6d41\uff0c\u4e0d\u7ecf\u8fc7Spring\u7684@ResponseBody\n        \/\/ \u56e0\u4e3aHandlerInterceptor\u53d1\u751f\u5728Controller\u4e4b\u524d\uff0c\u5fc5\u987b\u81ea\u5df1\u5199\u54cd\u5e94\n        ObjectMapper objectMapper = new ObjectMapper();\n        response.setStatus(HttpServletResponse.SC_FORBIDDEN);\n        response.setContentType(\"application\/json;charset=utf-8\");\n        objectMapper.writeValue(response.getOutputStream(), respBean);\n\n        return false;  \/\/ \u2190 return false = \u62e6\u622a\uff0c\u8bf7\u6c42\u4e0d\u4f1a\u518d\u5f80\u4e0b\u8d70\u5230Controller\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>HandlerInterceptor\u7684\u751f\u547d\u5468\u671f<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u8bf7\u6c42\u8fdb\u6765\n  \u2192 preHandle() \u6267\u884c\uff08\u6b64\u5904\u9a8c\u8bc1JWT\uff09\n  \u2192 \u5982\u679creturn true \u2192 Controller\u65b9\u6cd5\u6267\u884c\n  \u2192 postHandle() \u6267\u884c\uff08Controller\u6267\u884c\u5b8c\u3001\u6e32\u67d3\u89c6\u56fe\u524d\uff09\n  \u2192 afterCompletion() \u6267\u884c\uff08\u89c6\u56fe\u6e32\u67d3\u540e\uff0c\u505a\u6e05\u7406\u5de5\u4f5c\uff09\n\n\u5982\u679cpreHandle return false \u2192 \u76f4\u63a5\u505c\u5728\u8fd9\u91cc\uff0cController\u6839\u672c\u4e0d\u4f1a\u6267\u884c<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">6.4 JwtUtil \u2014 JWT\u751f\u6210\u548c\u89e3\u6790<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\u8def\u5f84\uff1acommon\/...\/utils\/JwtUtil.java\n\npublic class JwtUtil {\n    \/\/ \u2605\u5bc6\u94a5\uff1a\u7528\u4e8e\u7b7e\u540dJWT\u3002\u6cc4\u9732\u540e\u53ef\u4f2a\u9020\u4efb\u4f55\u4eba\u8eab\u4efd\uff01\n    \/\/ \u751f\u4ea7\u73af\u5883\u5fc5\u987b\u901a\u8fc7\u73af\u5883\u53d8\u91cf\u6ce8\u5165\uff0c\u4e0d\u80fd\u5199\u6b7b\u5728\u4ee3\u7801\u91cc\n    private static final String SECRET = \"mall_secret_key\";\n\n    \/**\n     * \u751f\u6210JWT\n     * @param map \u8981\u5b58\u8fdbJWT\u7684\u8f7d\u8377\u6570\u636e\uff0c\u5982 {id:3, username:\"zs\", role:\"user\"}\n     * @return JWT\u5b57\u7b26\u4e32\uff0c\u4e09\u6bb5Base64\uff0c\u7528\u70b9\u53f7\u5206\u9694\n     *\/\n    public static String generateJwt(Map&lt;String, Object&gt; map) {\n        return JWT.create()\n            .withPayload(map)                       \/\/ \u8f7d\u8377\n            .withExpiresAt(new Date(                \/\/ \u8fc7\u671f\u65f6\u95f4\n                System.currentTimeMillis() + 7*24*3600*1000L))  \/\/ 7\u5929\u540e\n            .sign(Algorithm.HMAC256(SECRET));       \/\/ \u7528\u5bc6\u94a5\u7b7e\u540d\n    }\n\n    \/**\n     * \u89e3\u6790JWT\n     * @param token JWT\u5b57\u7b26\u4e32\n     * @return \u8f7d\u8377\u91cc\u7684Map {id:3, username:\"zs\", role:\"user\"}\n     * @throws TokenExpiredException      \u5982\u679cJWT\u5df2\u8fc7\u671f\n     * @throws SignatureVerificationException \u5982\u679c\u7b7e\u540d\u4e0d\u5bf9\uff08\u88ab\u7be1\u6539\uff09\n     *\/\n    public static Map&lt;String, Object&gt; parseJwtToMap(String token) {\n        return JWT.require(Algorithm.HMAC256(SECRET))   \/\/ \u7528\u540c\u6837\u7684\u5bc6\u94a5\u9a8c\u8bc1\n            .build()\n            .verify(token)                               \/\/ \u9a8c\u8bc1\uff08\u53ef\u80fd\u629b\u5f02\u5e38\uff09\n            .getClaims()                                 \/\/ \u83b7\u53d6\u5168\u90e8\u58f0\u660e\n            .stream()\n            .collect(Collectors.toMap(Claim::getKey, Claim::asObject));\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>JWT\u7684\u7ed3\u6784<\/strong>\uff08\u4e09\u6bb5Base64\uff0c\u7528<code>.<\/code>\u5206\u9694\uff09\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>eyJhbGciOiJIUzI1NiJ9          \u2190 \u5934\u90e8\uff1a{\"alg\":\"HS256\"} \u2192 Base64\u7f16\u7801\n.                              \u2190 \u70b9\u53f7\u5206\u9694\neyJpZCI6MywidXNlcm5hbWUiOiJ6    \u2190 \u8f7d\u8377\uff1a{\"id\":3,\"username\":\"zs\",\"role\":\"user\"} \u2192 Base64\ncyIsInJvbGUiOiJ1c2VyIn0       \uff08\u8f7d\u8377\u53ea\u662f\u7f16\u7801\u4e0d\u662f\u52a0\u5bc6\u2192\u4e0d\u8981\u653e\u5bc6\u7801\u7b49\u654f\u611f\u6570\u636e\uff01\uff09\n.                              \u2190 \u70b9\u53f7\u5206\u9694\nXbZ3y-H8kL9mN2vP7qR4sT1uW6Y    \u2190 \u7b7e\u540d\uff1aHMAC256(\u5934\u90e8+\u8f7d\u8377+\u5bc6\u94a5) \u2192 \u9632\u7be1\u6539<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">7. admin_service\u7ba1\u7406\u5458\u670d\u52a1<\/h2>\n\n\n<h3 class=\"wp-block-heading\">7.1 DashboardMapper.xml \u2014 \u4eea\u8868\u76d8\u7edf\u8ba1SQL<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1aadmin_service\/...\/mapper\/DashboardMapper.xml --&gt;\n\n&lt;!-- \u2460 \u603b\u8ba2\u5355\u6570\uff1a\u76f4\u63a5 COUNT(*) --&gt;\n&lt;select id=\"countOrders\" resultType=\"int\"&gt;\n    SELECT COUNT(*) FROM `order`\n&lt;\/select&gt;\n\n&lt;!-- \u2461 \u603b\u7528\u6237\u6570 --&gt;\n&lt;select id=\"countUsers\" resultType=\"int\"&gt;\n    SELECT COUNT(*) FROM `user`\n&lt;\/select&gt;\n\n&lt;!-- \u2462 \u5728\u552e\u5546\u54c1\u6570\uff1a\u53ea\u7edf\u8ba1\u4e0a\u67b6(status=1)\u7684 --&gt;\n&lt;select id=\"countGoods\" resultType=\"int\"&gt;\n    SELECT COUNT(*) FROM `goods` WHERE `status` = 1\n&lt;\/select&gt;\n\n&lt;!-- \u2463 \u4eca\u65e5\u8ba2\u5355\u6570 --&gt;\n&lt;select id=\"countTodayOrders\" resultType=\"int\"&gt;\n    SELECT COUNT(*) FROM `order`\n    WHERE DATE(`create_time`) = CURDATE()\n    &lt;!-- DATE()\u53ea\u53d6\u65e5\u671f\u90e8\u5206\uff08\u5ffd\u7565\u65f6\u5206\u79d2\uff09\uff0cCURDATE()\u662f\u4eca\u5929\u7684\u65e5\u671f --&gt;\n    &lt;!-- \u4f8b\uff1aWHERE DATE('2026-07-28 14:30:00') = '2026-07-28' --&gt;\n&lt;\/select&gt;\n\n&lt;!-- \u2464 \u4eca\u65e5\u5df2\u4ed8\u6b3e\u8ba2\u5355\u7684items\u5217\uff08\u7528\u4e8e\u8ba1\u7b97\u4eca\u65e5\u9500\u552e\u989d\uff09 --&gt;\n&lt;select id=\"selectTodayOrderItems\" resultType=\"string\"&gt;\n    SELECT `items` FROM `order`\n    WHERE DATE(`create_time`) = CURDATE()\n      AND `items` IS NOT NULL\n      AND `status` IN (1, 2, 3)\n    &lt;!-- \u2605\u5173\u952e\uff1astatus IN(1,2,3) = \u5df2\u4ed8\u6b3e\/\u5df2\u53d1\u8d27\/\u5df2\u5b8c\u6210\n         \u4e0d\u5305\u62ec\u5f85\u4ed8\u6b3e(0)\u548c\u5df2\u53d6\u6d88(4)\n         \u5426\u5219\u9500\u552e\u989d\u4f1a\u865a\u9ad8\uff08\u628a\u6ca1\u4ed8\u94b1\u7684\u4e5f\u7b97\u8fdb\u53bb\uff09 --&gt;\n&lt;\/select&gt;\n\n&lt;!-- \u2465 \u6700\u8fd15\u6761\u8ba2\u5355\uff08\u53ea\u67e5\u4eea\u8868\u76d8\u9700\u8981\u7684\u5b57\u6bb5\uff09 --&gt;\n&lt;select id=\"selectRecentOrders\"\n        resultType=\"org.example.mall.common.bean.Order\"&gt;\n    SELECT o.id,\n           o.user_id    AS userId,\n           o.status,\n           o.create_time AS createTime,\n           u.username    -- \u6765\u81eauser\u8868\u7684join\n    FROM `order` o\n    LEFT JOIN `user` u ON o.user_id = u.id\n    ORDER BY o.create_time DESC\n    LIMIT #{limit}\n    &lt;!-- \u2605\u6ce8\u610f\uff1a\u6ca1\u6709\u67e5 o.*\uff0c\u56e0\u4e3a items \u5217\u5f88\u5927\uff08JSON\u6587\u672c\uff09\uff0c\n         \u4eea\u8868\u76d8\u4e0d\u9700\u8981\u770b\u5546\u54c1\u660e\u7ec6\uff0c\u67e5\u4e86\u53cd\u800c\u6d6a\u8d39\u5e26\u5bbd --&gt;\n&lt;\/select&gt;\n\n&lt;!-- \u2466 \u6700\u8fd15\u6761\u6ce8\u518c\u7528\u6237 --&gt;\n&lt;select id=\"selectRecentUsers\"\n        resultType=\"org.example.mall.common.bean.User\"&gt;\n    SELECT id, username, phone, email,\n           reg_time AS regTime,  -- \u2605\u624b\u52a8\u522b\u540d\uff1areg_time \u2192 regTime\n           status\n    FROM `user`\n    ORDER BY reg_time DESC\n    LIMIT #{limit}\n&lt;\/select&gt;\n\n&lt;!-- \u2467 \u6309\u72b6\u6001\u5206\u7ec4\u7edf\u8ba1\u8ba2\u5355\u6570 --&gt;\n&lt;select id=\"countOrdersByStatus\" resultType=\"java.util.HashMap\"&gt;\n    SELECT `status`, COUNT(*) AS cnt\n    FROM `order`\n    GROUP BY `status`\n&lt;\/select&gt;\n&lt;!-- \u8fd4\u56de\u793a\u4f8b\uff1a\n  [{status:0, cnt:10}, {status:1, cnt:80}, {status:3, cnt:5}]\n  \u6bcf\u4e2a\u5143\u7d20\u662f\u4e00\u4e2aHashMap\uff0ckey=\u5217\u540d\uff0cvalue=\u5217\u503c --&gt;<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">7.2 DashboardController \u2014 \u4eea\u8868\u76d8JSON\u63a5\u53e3<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1aadmin_service\/...\/controller\/DashboardController.java\n\n@RestController\n@RequestMapping(\"\/admin\/dashboard\")\npublic class DashboardController {\n\n    @Autowired\n    private DashboardMapper dashboardMapper;\n\n    @GetMapping\n    public RespBean index() {\n        Map&lt;String, Object&gt; data = new HashMap&lt;&gt;();\n\n        \/\/ \u57fa\u7840\u7edf\u8ba1\u6570\u5b57 \u2192 \u76f4\u63a5\u653e\u8fdb\u53bb\n        data.put(\"totalOrders\", dashboardMapper.countOrders());\n        data.put(\"totalUsers\",  dashboardMapper.countUsers());\n        data.put(\"totalGoods\",  dashboardMapper.countGoods());\n        data.put(\"todayOrders\", dashboardMapper.countTodayOrders());\n\n        \/\/ \u2605\u4eca\u65e5\u9500\u552e\u989d\uff1a\u9700\u8981\u624b\u52a8\u8ba1\u7b97\n        \/\/ \u56e0\u4e3a\u8ba2\u5355\u5546\u54c1\u5b58\u7684\u662fJSON\u6587\u672c\uff0c\u4e0d\u80fd\u76f4\u63a5\u5728SQL\u91ccSUM\n        \/\/ \u6240\u4ee5\u5728Java\u4ee3\u7801\u91cc\u9010\u6761\u89e3\u6790JSON\uff0c\u7d2f\u52a0subtotal\n        BigDecimal todaySales = BigDecimal.ZERO;\n        List&lt;String&gt; itemsList = dashboardMapper.selectTodayOrderItems();\n        for (String itemsJson : itemsList) {\n            if (itemsJson == null || itemsJson.isEmpty()) continue;\n            try {\n                \/\/ Hutool\u7684JSONUtil\uff1a\u628aJSON\u5b57\u7b26\u4e32\u89e3\u6790\u6210List&lt;OrderDetail&gt;\n                List&lt;OrderDetail&gt; details =\n                    JSONUtil.toList(itemsJson, OrderDetail.class);\n                for (OrderDetail d : details) {\n                    if (d.getSubtotal() != null) {\n                        todaySales = todaySales.add(d.getSubtotal());\n                    }\n                }\n            } catch (Exception ignored) {\n                \/\/ \u5982\u679c\u67d0\u6761\u8ba2\u5355\u7684JSON\u683c\u5f0f\u574f\u4e86\uff08\u4e0d\u592a\u53ef\u80fd\u4f46\u5b89\u5168\u7b2c\u4e00\uff09\uff0c\u8df3\u8fc7\n            }\n        }\n        data.put(\"todaySales\", todaySales);\n\n        \/\/ \u8ba2\u5355\u72b6\u6001\u5206\u5e03\uff1a\u628aSQL\u67e5\u51fa\u6765\u7684\u539f\u59cb\u5217\u8868\u8f6c\u6362\u6210\u524d\u7aef\u597d\u7528\u7684Map\n        \/\/ SQL\u8fd4\u56de [{status:0,cnt:10}, {status:1,cnt:80}] \n        \/\/ \u2192 \u53d8\u6210 {pending:10, paid:80, shipped:0, completed:5, cancelled:0}\n        List&lt;Map&lt;String, Object&gt;&gt; statusList =\n            dashboardMapper.countOrdersByStatus();\n        Map&lt;String, Integer&gt; statusMap = new HashMap&lt;&gt;();\n        \/\/ \u5148\u7ed9\u6240\u6709\u72b6\u6001\u586b\u9ed8\u8ba4\u503c0\uff08\u907f\u514d\u524d\u7aef\u8bfb\u5230undefined\uff09\n        statusMap.put(\"pending\", 0);   \/\/ \u5bf9\u5e94status=0\n        statusMap.put(\"paid\", 0);      \/\/ \u5bf9\u5e94status=1\n        statusMap.put(\"shipped\", 0);   \/\/ \u5bf9\u5e94status=2\n        statusMap.put(\"completed\", 0); \/\/ \u5bf9\u5e94status=3\n        statusMap.put(\"cancelled\", 0); \/\/ \u5bf9\u5e94status=4\n\n        for (Map&lt;String, Object&gt; row : statusList) {\n            int st  = ((Number) row.get(\"status\")).intValue();  \/\/ \u72b6\u6001\u503c\n            int cnt = ((Number) row.get(\"cnt\")).intValue();     \/\/ \u8be5\u72b6\u6001\u7684\u6570\u91cf\n            \/\/ \u6839\u636e\u72b6\u6001\u503c\u586b\u5230\u5bf9\u5e94\u7684key\u91cc\n            switch (st) {\n                case 0: statusMap.put(\"pending\", cnt);   break;\n                case 1: statusMap.put(\"paid\", cnt);      break;\n                case 2: statusMap.put(\"shipped\", cnt);   break;\n                case 3: statusMap.put(\"completed\", cnt); break;\n                case 4: statusMap.put(\"cancelled\", cnt); break;\n            }\n        }\n        data.put(\"statusCnt\", statusMap);\n\n        \/\/ \u6700\u8fd1\u8bb0\u5f55\n        data.put(\"recentOrders\", dashboardMapper.selectRecentOrders(5));\n        data.put(\"recentUsers\",  dashboardMapper.selectRecentUsers(5));\n\n        return RespBean.success(\"\", data);\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4eca\u65e5\u9500\u552e\u989d\u4e3a\u4ec0\u4e48\u4e0d\u80fd\u5728SQL\u91cc\u76f4\u63a5SUM\uff1f<\/strong><\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u56e0\u4e3a\u8ba2\u5355\u7684\u5546\u54c1\u5feb\u7167\u5b58\u7684\u662fJSON\u6587\u672c\uff0c\u4e0d\u662f\u7ed3\u6784\u5316\u5217<\/li>\n<li>SQL\u7684\u805a\u5408\u51fd\u6570SUM\u4e0d\u80fd\u76f4\u63a5\u4f5c\u7528\u4e8eJSON\u5b57\u6bb5<\/li>\n<li>\u6240\u4ee5\u9700\u8981\u628a\u6bcf\u6761\u8ba2\u5355\u7684items JSON\u53d6\u51fa\u6765\uff0c\u5728Java\u4ee3\u7801\u91cc\u89e3\u6790\u2192\u7d2f\u52a0<\/li>\n\n<\/ul>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">8. user_service\u7528\u6237\u670d\u52a1<\/h2>\n\n\n<h3 class=\"wp-block-heading\">8.1 AddrServiceImpl \u2014 \u5730\u5740\u7ba1\u7406\u4e1a\u52a1\u903b\u8f91<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1auser_service\/...\/service\/AddrServiceImpl.java\n\n@Service\npublic class AddrServiceImpl implements AddrService {\n\n    @Autowired\n    private AddrMapper addrMapper;\n\n    \/**\n     * \u65b0\u589e\u5730\u5740\n     * \u4e1a\u52a1\u89c4\u5219\uff1a\u5982\u679c\u662f\u7528\u6237\u7684\u7b2c\u4e00\u6761\u5730\u5740\uff0c\u81ea\u52a8\u8bbe\u4e3a\u9ed8\u8ba4\n     *\/\n    @Override\n    public boolean insert(Addr addr) throws StException {\n        List&lt;Addr&gt; existing = addrMapper.selectByUserId(addr.getUserId());\n        if (existing == null || existing.isEmpty()) {\n            \/\/ \u8fd9\u662f\u7528\u6237\u7684\u7b2c\u4e00\u6761\u5730\u5740 \u2192 \u81ea\u52a8\u8bbe\u4e3a\u9ed8\u8ba4\n            addr.setStatus(1);\n        } else {\n            \/\/ \u7528\u6237\u5df2\u6709\u5730\u5740 \u2192 \u4fdd\u6301\u524d\u7aef\u4f20\u7684\u72b6\u6001\uff0c\n            \/\/ \u5982\u679c\u524d\u7aef\u6ca1\u4f20\uff08null\uff09\uff0c\u9ed8\u8ba4\u4e3a0\uff08\u975e\u9ed8\u8ba4\uff09\n            addr.setStatus(addr.getStatus() != null ? addr.getStatus() : 0);\n        }\n        return addrMapper.insert(addr) == 1;\n    }\n\n    \/**\n     * \u4fee\u6539\u5730\u5740\n     * \u5b89\u5168\u89c4\u5219\uff1a\u2460\u5730\u5740\u5fc5\u987b\u5b58\u5728 \u2461\u53ea\u80fd\u6539\u81ea\u5df1\u7684\u5730\u5740 \u2462userId\u5b57\u6bb5\u4e0d\u5141\u8bb8\u4fee\u6539\n     *\/\n    @Override\n    public boolean update(Addr addr, Integer userId) throws StException {\n        Addr existing = addrMapper.selectById(addr.getId());\n        if (existing == null) {\n            throw new StException(\"\u5730\u5740\u4e0d\u5b58\u5728\");\n        }\n        \/\/ \u2605\u5f52\u5c5e\u6821\u9a8c\uff1a\u9632\u6b62\u7528\u6237A\u901a\u8fc7\u731cID\u6765\u4fee\u6539\u7528\u6237B\u7684\u5730\u5740\n        if (!existing.getUserId().equals(userId)) {\n            throw new StException(\"\u65e0\u6743\u64cd\u4f5c\u8be5\u5730\u5740\");\n        }\n        \/\/ \u2605\u9632\u7be1\u6539\uff1a\u628auserId\u7f6enull\uff0c\u8fd9\u6837\u5373\u4f7f\u524d\u7aef\u6076\u610f\u4f20\u4e86userId\u4e5f\u4f1a\u88ab\u5ffd\u7565\n        addr.setUserId(null);\n        return addrMapper.update(addr) == 1;\n    }\n\n    \/**\n     * \u5220\u9664\u5730\u5740\uff08\u540c\u6837\u8981\u505a\u5f52\u5c5e\u6821\u9a8c\uff09\n     *\/\n    @Override\n    public boolean delete(Integer id, Integer userId) throws StException {\n        Addr existing = addrMapper.selectById(id);\n        if (existing == null) throw new StException(\"\u5730\u5740\u4e0d\u5b58\u5728\");\n        if (!existing.getUserId().equals(userId))\n            throw new StException(\"\u65e0\u6743\u64cd\u4f5c\u8be5\u5730\u5740\");\n        return addrMapper.delete(id) == 1;\n    }\n\n    \/**\n     * \u8bbe\u4e3a\u9ed8\u8ba4\u5730\u5740\n     * \u2605\u4e8b\u52a1\u4fdd\u8bc1\u539f\u5b50\u6027\uff1a\u5982\u679c\u7b2c\u4e00\u6b65\u6210\u529f\u7b2c\u4e8c\u6b65\u5931\u8d25\uff0c\u72b6\u6001\u4e0d\u4e00\u81f4\n     * \u4f8b\u5982\u7528\u6237\u6709\u5730\u5740A(\u9ed8\u8ba4)\u548cB\uff0c\u60f3\u8bbeB\u4e3a\u9ed8\u8ba4\uff1a\n     * \u7b2c\u4e00\u6b65 UPDATE SET status=0 WHERE user_id=3  \u2192 A\u548cB\u90fd\u53d8\u6210\u975e\u9ed8\u8ba4\n     * \u7b2c\u4e8c\u6b65 UPDATE SET status=1 WHERE id=B       \u2192 B\u53d8\u6210\u9ed8\u8ba4\n     * \u5982\u679c\u53ea\u6267\u884c\u4e86\u7b2c\u4e00\u6b65 \u2192 \u7528\u6237\u6ca1\u6709\u9ed8\u8ba4\u5730\u5740\u4e86\uff01\n     *\/\n    @Override\n    @Transactional   \/\/ \u2605\u4e8b\u52a1\u6ce8\u89e3\uff1a\u4e24\u6b65\u64cd\u4f5c\u8981\u4e48\u5168\u6210\u529f\uff0c\u8981\u4e48\u5168\u56de\u6eda\n    public boolean setDefault(Integer id, Integer userId) throws StException {\n        Addr existing = addrMapper.selectById(id);\n        if (existing == null) throw new StException(\"\u5730\u5740\u4e0d\u5b58\u5728\");\n        if (!existing.getUserId().equals(userId))\n            throw new StException(\"\u65e0\u6743\u64cd\u4f5c\u8be5\u5730\u5740\");\n\n        addrMapper.clearDefault(userId);  \/\/ \u2460 \u6e05\u7a7a\u8be5\u7528\u6237\u6240\u6709\u9ed8\u8ba4\u72b6\u6001\n        return addrMapper.setDefault(id) == 1;  \/\/ \u2461 \u628a\u76ee\u6807\u8bbe\u4e3a\u9ed8\u8ba4\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong><code>@Transactional<\/code>\u7684\u5de5\u4f5c\u539f\u7406<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u65b9\u6cd5\u5f00\u59cb \u2192 \u5f00\u542f\u6570\u636e\u5e93\u4e8b\u52a1\n  \u2192 clearDefault(userId)  \u2192 \u6267\u884cSQL\uff0c\u4f46\u8fd8\u6ca1\u63d0\u4ea4\n  \u2192 setDefault(id)        \u2192 \u6267\u884cSQL\uff0c\u4f46\u8fd8\u6ca1\u63d0\u4ea4\n  \u2192 \u5982\u679c\u4e24\u4e2a\u90fd\u6210\u529f \u2192 return \u2192 \u4e8b\u52a1\u63d0\u4ea4\uff08COMMIT\uff09 \u2192 \u4e24\u6761SQL\u4e00\u8d77\u751f\u6548\n  \u2192 \u5982\u679csetDefault\u629b\u5f02\u5e38 \u2192 \u4e8b\u52a1\u56de\u6eda\uff08ROLLBACK\uff09\u2192 \u4e24\u6761SQL\u90fd\u64a4\u9500<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u9700\u8981\u5f52\u5c5e\u6821\u9a8c<\/strong>\uff1f<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u5982\u679c\u6ca1\u6709\u5f52\u5c5e\u6821\u9a8c\uff0c\u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\uff1a\nPOST \/addr  body: {\"id\": 999, \"contact\": \"\u9ed1\u5ba2\"}\n\/\/ \u5c31\u628a\u522b\u4eba\u7684\u5730\u5740\u6539\u4e86\n\n\/\/ \u6709\u5f52\u5c5e\u6821\u9a8c\u540e\uff1a\nAddr existing = addrMapper.selectById(999);  \/\/ \u67e5\u51fa\u5730\u5740\u7684\u539f\u4e3b\u4eba\nif (!existing.getUserId().equals(userId))    \/\/ \u539f\u4e3b\u4eba != \u5f53\u524d\u767b\u5f55\u7528\u6237\n    throw new StException(\"\u65e0\u6743\u64cd\u4f5c\");        \/\/ \u2192 \u62d2\u7edd<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">8.2 CollectMapper.xml \u2014 \u6536\u85cf\u5217\u8868\u67e5\u8be2<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1auser_service\/...\/mapper\/CollectMapper.xml --&gt;\n\n&lt;!--\n  resultMap \u662f MyBatis \u7684\u6838\u5fc3\u529f\u80fd\u4e4b\u4e00\u3002\n  \u5b83\u5b9a\u4e49\"SQL\u67e5\u51fa\u6765\u7684\u884c\u600e\u4e48\u6620\u5c04\u6210\u5d4c\u5957\u7684Java\u5bf9\u8c61\"\u3002\n\n  \u8fd9\u91cc\u7684\u6620\u5c04\u5173\u7cfb\uff1a\n  collect\u8868\uff08\u6536\u85cf\u8bb0\u5f55\uff09\n    \u2514\u2500\u2500 goods\uff08\u6536\u85cf\u7684\u5546\u54c1\uff09\n          \u2514\u2500\u2500 picList\uff08\u5546\u54c1\u7684\u56fe\u7247\u5217\u8868\uff09\n\n  \u4e00\u6761\u6536\u85cf SQL \u4f1a JOIN \u4e09\u5f20\u8868\uff1a\n    collect c LEFT JOIN goods g ON c.goods_id = g.id\n              LEFT JOIN goods_pic gp ON g.id = gp.goods_id\n--&gt;\n&lt;resultMap id=\"collectWithGoods\" type=\"collect\"&gt;\n    &lt;!-- \u6536\u85cf\u8bb0\u5f55\u672c\u8eab\u7684\u5b57\u6bb5 --&gt;\n    &lt;id column=\"c_id\" property=\"id\"\/&gt;\n    &lt;result column=\"goods_id\" property=\"goodsId\"\/&gt;\n    &lt;result column=\"user_id\" property=\"userId\"\/&gt;\n    &lt;result column=\"c_create_time\" property=\"createTime\"\/&gt;\n\n    &lt;!--\n      \u5d4c\u5957\u7684 Goods \u5bf9\u8c61\uff08association = 1\u5bf91\u5173\u8054\uff09\n      \u67e5\u51fa\u6765\u7684 g_id, g_name \u7b49\u5217\u4f1a\u81ea\u52a8\u586b\u5165 Goods \u5bf9\u8c61\u7684\u5bf9\u5e94\u5c5e\u6027\n    --&gt;\n    &lt;association property=\"goods\"\n                 javaType=\"org.example.mall.common.bean.Goods\"&gt;\n        &lt;id column=\"g_id\" property=\"id\"\/&gt;\n        &lt;result column=\"g_name\" property=\"name\"\/&gt;\n        &lt;result column=\"g_price\" property=\"price\"\/&gt;\n        &lt;result column=\"g_market_price\" property=\"marketPrice\"\/&gt;\n        &lt;result column=\"g_status\" property=\"status\"\/&gt;\n        &lt;result column=\"g_color\" property=\"color\"\/&gt;\n        &lt;result column=\"g_version\" property=\"version\"\/&gt;\n        &lt;result column=\"g_count\" property=\"count\"\/&gt;\n\n        &lt;!--\n          Goods \u5bf9\u8c61\u91cc\u7684\u56fe\u7247\u5217\u8868\uff08collection = 1\u5bf9\u591a\u5173\u8054\uff09\n          \u540c\u4e00 goods_id \u4e0b\u53ef\u80fd\u6709\u591a\u6761 goods_pic \u884c\uff0c\n          MyBatis \u4f1a\u81ea\u52a8\u5408\u5e76\u6210\u4e00\u4e2a List&lt;GoodsPic&gt;\n        --&gt;\n        &lt;collection property=\"picList\"\n                    ofType=\"org.example.mall.common.bean.GoodsPic\"&gt;\n            &lt;id column=\"gp_id\" property=\"id\"\/&gt;\n            &lt;result column=\"gp_url\" property=\"url\"\/&gt;\n            &lt;result column=\"gp_goods_id\" property=\"goodsId\"\/&gt;\n        &lt;\/collection&gt;\n    &lt;\/association&gt;\n&lt;\/resultMap&gt;\n\n&lt;select id=\"selectByUserId\" resultMap=\"collectWithGoods\"&gt;\n    SELECT\n        c.id AS c_id,\n        c.goods_id,\n        c.user_id,\n        c.create_time AS c_create_time,\n        g.id AS g_id,\n        g.name AS g_name,\n        g.price AS g_price,\n        g.market_price AS g_market_price,\n        g.status AS g_status,\n        g.color AS g_color,\n        g.version AS g_version,\n        g.count AS g_count,\n        gp.id AS gp_id,\n        gp.url AS gp_url,\n        gp.goods_id AS gp_goods_id\n    FROM `collect` c\n    LEFT JOIN `goods` g ON c.goods_id = g.id\n    LEFT JOIN `goods_pic` gp ON g.id = gp.goods_id\n    WHERE c.user_id = #{userId}\n    ORDER BY c.create_time DESC\n&lt;\/select&gt;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e3a\u4ec0\u4e48\u4e4b\u524d\u7528<code>&lt;collection select=\"...\"\/&gt;<\/code>\u5b50\u67e5\u8be2\u4f1a\u51fa\u9519\uff1f<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u274c \u9519\u8bef\u7684\u505a\u6cd5\uff08\u4e4b\u524d\u5c1d\u8bd5\u8fc7\u7684\uff09 --&gt;\n&lt;collection column=\"c_id\" property=\"picList\"\n            ofType=\"goodsPic\"\n            select=\"org.example.mall.goods_service.mapper.GoodsPicMapper.selectByGoodsId\"\/&gt;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">\u95ee\u9898\uff1a<code>GoodsPicMapper<\/code> \u5728 <code>goods_service<\/code> \u6a21\u5757\u91cc\uff0c\u800c <code>CollectMapper<\/code> \u5728 <code>user_service<\/code> \u6a21\u5757\u91cc\u3002\u867d\u7136\u5b83\u4eec\u8fde\u540c\u4e00\u4e2aMySQL\u6570\u636e\u5e93\uff0c\u4f46 MyBatis \u7684 <code>SqlSessionFactory<\/code> \u662f\u5404\u81ea\u72ec\u7acb\u7684\u2014\u2014<code>user_service<\/code> \u4e0d\u77e5\u9053 <code>goods_service<\/code> \u6709\u4ec0\u4e48 Mapper\u3002\u8de8\u6a21\u5757\u5f15\u7528\u4f1a\u629b <code>MapperStatementNotFoundException<\/code>\u3002<\/p>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u89e3\u51b3\u65b9\u6848<\/strong>\uff1a\u4e0d\u7528\u5b50\u67e5\u8be2\uff0c\u76f4\u63a5\u5728SQL\u91cc<code>LEFT JOIN goods_pic<\/code>\uff0c\u7528 <code>resultMap<\/code> \u7684 <code>&lt;collection&gt;<\/code> \u6620\u5c04\u3002\u4e00\u6b21SQL\u641e\u5b9a\u6240\u6709\u6570\u636e\u3002<\/p>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">9. goods_service\u5546\u54c1\u670d\u52a1<\/h2>\n\n\n<h3 class=\"wp-block-heading\">9.1 \u5e93\u5b58\u6263\u51cf \u2014 \u5e76\u53d1\u5b89\u5168\u7684\u6838\u5fc3<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1agoods_service\/...\/mapper\/GoodsMapper.xml --&gt;\n\n&lt;!--\n  \u6263\u51cf\u5e93\u5b58 SQL\n  \u8fd9\u662f\u6574\u4e2a\u9879\u76ee\u4e2d\u6700\u5173\u952e\u7684\u5e76\u53d1\u5b89\u5168\u8bbe\u8ba1\n\n  \u3010MySQL\u7684\u884c\u7ea7\u9501\u673a\u5236\u3011\n  UPDATE\u8bed\u53e5\u5728\u6267\u884c\u65f6\u4f1a\u81ea\u52a8\u52a0\u884c\u7ea7\u9501\n  \u4e24\u6761\u5e76\u53d1\u7684 UPDATE goods SET count=count-1 WHERE id=45 AND count&gt;=1\n  \u4e0d\u7ba1\u8c01\u5148\u6267\u884c\u8c01\u540e\u6267\u884c\uff0c\u53ea\u6709\u5e93\u5b58\u591f\u7684\u90a3\u6761\u4f1a\u6210\u529f\uff08\u53d7\u5f71\u54cd\u884c\u6570=1\uff09\n  \u5e93\u5b58\u4e0d\u591f\u7684\u90a3\u6761\u56e0\u4e3a \"count&gt;=1\" \u6761\u4ef6\u4e0d\u6ee1\u8db3 \u2192 \u53d7\u5f71\u54cd\u884c\u6570=0\n\n  \u6240\u4ee5\u4e0d\u9700\u8981\u5728Java\u4ee3\u7801\u91cc\u5199 synchronized \u6216\u9501\uff08\u90a3\u6837\u4f1a\u8ba9\u6574\u4e2a\u670d\u52a1\u6392\u961f\uff09\n  \u6570\u636e\u5e93\u5e2e\u6211\u4eec\u5904\u7406\u4e86\u5e76\u53d1\uff01\n--&gt;\n&lt;update id=\"reduceStock\"&gt;\n    UPDATE `goods`\n    SET `count` = `count` - #{count}\n    WHERE `id` = #{id} AND `count` &gt;= #{count}\n    &lt;!--      \u6ce8\u610f\u8fd9\u4e2a\u6761\u4ef6 \u2191            --&gt;\n    &lt;!--      \u53ea\u6709\u5f53\u524d\u5e93\u5b58 &gt;= \u8981\u6263\u7684\u6570\u91cf\u65f6\u624d\u6267\u884c --&gt;\n    &lt;!--      \u8fd9\u5c31\u662f\u9632\u8d85\u5356\u7684\u6838\u5fc3\uff01 --&gt;\n&lt;\/update&gt;<\/code><\/pre>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1agoods_service\/...\/service\/GoodsServiceImpl.java\n\n@Override\npublic boolean reduceStock(Integer goodsId, Integer count) {\n    if (goodsId == null || count == null || count &lt;= 0) {\n        return false;\n    }\n    \/\/ reduceStock\u8fd4\u56de\u53d7\u5f71\u54cd\u7684\u884c\u6570\uff1a\n    \/\/   1 = \u6263\u51cf\u6210\u529f\uff08\u5e93\u5b58\u591f+UPDATE\u6267\u884c\u4e86\uff09\n    \/\/   0 = \u6263\u51cf\u5931\u8d25\uff08\u5e93\u5b58\u4e0d\u591f\u88abWHERE\u62e6\u622a\u4e86\uff09\n    return goodsMapper.reduceStock(goodsId, count) == 1;\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5e76\u53d1\u573a\u666f\u6f14\u793a<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>\u5047\u8bbe\u5f53\u524d\u5e93\u5b58 count = 5\n\n\u65f6\u523bT1\uff1a\u7528\u6237A\u4e0b\u5355\u4e703\u4ef6     \u2192 UPDATE SET count=count-3 WHERE id=45 AND count&gt;=3\n\u65f6\u523bT2\uff1a\u7528\u6237B\u4e0b\u5355\u4e703\u4ef6     \u2192 UPDATE SET count=count-3 WHERE id=45 AND count&gt;=3\n\u65f6\u523bT3\uff1a\u7528\u6237C\u4e0b\u5355\u4e702\u4ef6     \u2192 UPDATE SET count=count-2 WHERE id=45 AND count&gt;=2\n\nMySQL\u5904\u7406\u987a\u5e8f\uff1a\nT1\u5148\u6267\u884c\uff1acount=5&gt;=3 \u2192 \u6210\u529f \u2192 count\u53d8\u62102\nT2\u63a5\u7740\u6267\u884c\uff1acount=2&lt;3 \u2192 \u5931\u8d25 \u2192 \u53d7\u5f71\u54cd\u884c\u6570=0 \u2192 reduceStock\u8fd4\u56defalse\n   \u2191 \u8fd9\u662fMySQL\u7684\u884c\u7ea7\u9501\u4fdd\u8bc1\u7684\uff1aT1\u6267\u884c\u65f6\u9501\u4f4f\u4e86id=45\u8fd9\u4e00\u884c\uff0cT2\u5fc5\u987b\u7b49T1\u63d0\u4ea4\u540e\u624d\u80fd\u6267\u884c\nT3\u540c\u7406\u7b49\u5f85\u2192count=2&gt;=2 \u2192 \u6210\u529f \u2192 count\u53d8\u62100<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">9.2 GoodsMapper.xml \u2014 resultMap\u5173\u8054\u5206\u7c7b\u548c\u56fe\u7247<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1agoods_service\/...\/mapper\/GoodsMapper.xml --&gt;\n\n&lt;!-- \u8fd9\u4e2aresultMap\u5b9a\u4e49\u4e86\"\u67e5goods\u8868\u65f6\u81ea\u52a8\u5e26\u51fa\u5206\u7c7b\u548c\u56fe\u7247\" --&gt;\n&lt;resultMap id=\"goodsMap\" type=\"goods\"&gt;\n    &lt;id column=\"id\" property=\"id\"\/&gt;\n    &lt;!-- ... \u5176\u4ed6\u5b57\u6bb5 ... --&gt;\n    &lt;result column=\"category_id\" property=\"categoryId\"\/&gt;\n\n    &lt;!-- association: 1\u5bf91\uff08\u4e00\u4e2a\u5546\u54c1\u53ea\u5c5e\u4e8e\u4e00\u4e2a\u5206\u7c7b\uff09 --&gt;\n    &lt;association column=\"category_id\" property=\"category\"\n                 javaType=\"category\"\n                 select=\"org.example...CategoryMapper.selectById\"\/&gt;\n    &lt;!-- \u2191 MyBatis\u4f1a\u8c03\u7528\u8fd9\u4e2a\u5b50\u67e5\u8be2\uff1aSELECT * FROM category WHERE id = goods.category_id --&gt;\n\n    &lt;!-- collection: 1\u5bf9\u591a\uff08\u4e00\u4e2a\u5546\u54c1\u6709\u591a\u5f20\u56fe\u7247\uff09 --&gt;\n    &lt;collection column=\"id\" property=\"picList\"\n                ofType=\"goodsPic\"\n                select=\"org.example...GoodsPicMapper.selectByGoodsId\"\/&gt;\n    &lt;!-- \u2191 MyBatis\u4f1a\u8c03\u7528\u8fd9\u4e2a\u5b50\u67e5\u8be2\uff1aSELECT * FROM goods_pic WHERE goods_id = goods.id\n         \u6ce8\u610f\uff1a\u8fd9\u91cc\u662f\u540c\u6a21\u5757\u5185\u7684\u5f15\u7528\uff08GoodsPicMapper\u4e5f\u5728goods_service\u91cc\uff09\uff0c\u6240\u4ee5\u6ca1\u95ee\u9898 --&gt;\n&lt;\/resultMap&gt;<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">10. order_service\u8ba2\u5355\u670d\u52a1<\/h2>\n\n\n<p class=\"wp-block-paragraph\">\u8fd9\u662f\u672c\u9879\u76ee\u6700\u590d\u6742\u7684\u5fae\u670d\u52a1\uff0c\u5305\u542b\u4e0b\u5355\u3001\u652f\u4ed8\u3001\u56de\u8c03\u3001\u5b9a\u65f6\u53d6\u6d88\u7b49\u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u3002\u6211\u4eec\u5c06\u9010\u6bb5\u6df1\u5165\u5206\u6790\u3002<\/p>\n\n\n<h3 class=\"wp-block-heading\">10.1 OrderServiceImpl \u2014 \u4e0b\u5355\u6838\u5fc3<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1aorder_service\/...\/service\/OrderServiceImpl.java\n\n@Service\npublic class OrderServiceImpl implements OrderService {\n\n    private static final Logger log =\n        Logger.getLogger(OrderServiceImpl.class.getName());\n\n    @Autowired private OrderMapper orderMapper;      \/\/ \u8ba2\u5355\u6570\u636e\u5e93\u64cd\u4f5c\n    @Autowired private CartMapper cartMapper;        \/\/ \u8d2d\u7269\u8f66\u6570\u636e\u5e93\u64cd\u4f5c\n    @Autowired private AlipayClient alipayClient;     \/\/ \u652f\u4ed8\u5b9dSDK\u5ba2\u6237\u7aef\n    @Autowired private AlipayConfig alipayConfig;      \/\/ \u652f\u4ed8\u5b9d\u914d\u7f6e\n\n    @DubboReference  \/\/ \u2190 \u8fdc\u7a0b\u8c03\u7528goods_service\n    private GoodsService goodsService;\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u5de5\u5177\u65b9\u6cd5\uff1a\u89e3\u6790items JSON \u2192 \u8ba1\u7b97totalPrice\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    \/**\n     * \u628a\u8ba2\u5355\u7684items JSON\u5b57\u7b26\u4e32\u89e3\u6790\u6210 detailList\uff08\u5546\u54c1\u5217\u8868\uff09\n     * \u5e76\u8ba1\u7b97\u51fa totalPrice\uff08\u8ba2\u5355\u603b\u91d1\u989d\uff09\n     * \n     * \u6bcf\u5f53\u4ece\u6570\u636e\u5e93\u67e5\u51faOrder\u5bf9\u8c61\u65f6\uff0c\u90fd\u8981\u8c03\u7528\u8fd9\u4e2a\u65b9\u6cd5\u6765\u56de\u586b\u6570\u636e\n     *\/\n    private void fillDetailAndPrice(Order order) {\n        if (order == null) return;\n\n        \/\/ \u89e3\u6790items JSON \u2192 List&lt;OrderDetail&gt;\n        if (order.getItems() != null &amp;&amp; !order.getItems().isEmpty()) {\n            order.setDetailList(\n                JSONUtil.toList(order.getItems(), OrderDetail.class)\n            );\n        } else {\n            order.setDetailList(new ArrayList&lt;&gt;());  \/\/ \u7a7a\u5217\u8868\uff0c\u907f\u514dnull\n        }\n\n        \/\/ \u7d2f\u52a0\u6bcf\u9879\u5546\u54c1\u7684subtotal\uff0c\u5f97\u5230\u8ba2\u5355\u603b\u91d1\u989d\n        BigDecimal total = BigDecimal.ZERO;\n        for (OrderDetail d : order.getDetailList()) {\n            if (d.getSubtotal() != null) {\n                total = total.add(d.getSubtotal());\n            } else if (d.getPrice() != null &amp;&amp; d.getCount() != null) {\n                \/\/ \u517c\u5bb9\u65e7\u6570\u636e\uff1a\u5982\u679csubtotal\u6ca1\u5b58\uff0c\u7528price\u00d7count\u8ba1\u7b97\n                total = total.add(\n                    d.getPrice().multiply(new BigDecimal(d.getCount()))\n                );\n            }\n        }\n        order.setTotalPrice(total);\n    }\n\n    \/**\n     * \u53d6\u5546\u54c1\u7684\u7b2c\u4e00\u5f20\u56fe\u7247URL\n     *\/\n    private String firstPic(Goods goods) {\n        if (goods != null &amp;&amp;\n            goods.getPicList() != null &amp;&amp;\n            !goods.getPicList().isEmpty()) {\n            GoodsPic pic = goods.getPicList().get(0);\n            return pic == null ? null : pic.getUrl();\n        }\n        return null;\n    }\n\n    \/**\n     * \u62fc\u63a5\u6536\u8d27\u5730\u5740\u7684\u5b8c\u6574\u6587\u672c\n     * \u628a\u7701\/\u5e02\/\u533a\/\u8857\u9053\/\u95e8\u724c\u53f7\/\u6536\u4ef6\u4eba\/\u624b\u673a\u53f7\u62fc\u6210\u4e00\u884c\uff1a\n     * \"\u5c71\u4e1c\u7701\u9752\u5c9b\u5e02\u57ce\u9633\u533a\u57ce\u9633\u8857\u9053 \u519c\u5927\u897f\u82d1A\u5ea7 - \u6c64\u59c6 - 13322332233\"\n     * \n     * \u2605\u8fd9\u5c31\u662f\"\u5730\u5740\u5feb\u7167\"\uff1a\u4e0b\u5355\u65f6\u62fc\u597d\u5b58\u8fdborder\uff0c\u4ee5\u540e\u5730\u5740\u6539\u4e86\u4e5f\u4e0d\u5f71\u54cd\u5386\u53f2\u8ba2\u5355\n     *\/\n    private String buildAddrDetail(Integer addrId) throws StException {\n        Addr addr = orderMapper.selectAddrById(addrId);\n        if (addr == null) {\n            throw new StException(\"\u6536\u8d27\u5730\u5740\u4e0d\u5b58\u5728\");\n        }\n        StringBuilder sb = new StringBuilder();\n        if (addr.getProvince() != null) sb.append(addr.getProvince());\n        if (addr.getCity() != null)     sb.append(addr.getCity());\n        if (addr.getDistrict() != null) sb.append(addr.getDistrict());\n        if (addr.getStreet() != null)   sb.append(addr.getStreet());\n        sb.append(\" \").append(addr.getAddress());\n        sb.append(\" - \").append(addr.getContact());\n        sb.append(\" - \").append(addr.getPhone());\n        return sb.toString();\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u8d2d\u7269\u8f66\u7ed3\u7b97\u4e0b\u5355\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    \/**\n     * \u4ece\u8d2d\u7269\u8f66\u7ed3\u7b97\uff1a\u628a\u591a\u4e2a\u8d2d\u7269\u8f66\u9879\u53d8\u6210\u4e00\u4e2a\u8ba2\u5355\n     * \n     * @param order    \u524d\u7aef\u4f20\u6765\u7684\u8ba2\u5355\u53c2\u6570\uff08\u5730\u5740ID\u3001\u652f\u4ed8\u65b9\u5f0f\uff09\n     * @param cartIds  \u7528\u6237\u9009\u4e2d\u7684\u8d2d\u7269\u8f66\u9879ID\u5217\u8868\n     * @param userId   \u5f53\u524d\u767b\u5f55\u7528\u6237ID\uff08\u4eceJWT\u89e3\u6790\u5f97\u6765\uff09\n     * \n     * @Transactional \u4fdd\u8bc1\u8ba2\u5355\u63d2\u5165+\u8d2d\u7269\u8f66\u5220\u9664\u5728\u540c\u4e00\u4e8b\u52a1\u91cc\n     *   \u5982\u679c\u63d2\u5165\u8ba2\u5355\u6210\u529f\u4e86\u4f46\u5220\u9664\u8d2d\u7269\u8f66\u5931\u8d25\u4e86 \u2192 \u4e8b\u52a1\u56de\u6eda \u2192 \u8ba2\u5355\u4e5f\u64a4\u9500\n     *   \u2192 \u7528\u6237\u4e0b\u6b21\u8fd8\u53ef\u4ee5\u91cd\u65b0\u7ed3\u7b97\uff08\u4e0d\u4f1a\u51fa\u73b0\"\u8ba2\u5355\u5df2\u521b\u5efa\u4f46\u8d2d\u7269\u8f66\u6ca1\u6e05\"\u7684\u810f\u72b6\u6001\uff09\n     *\/\n    @Override\n    @Transactional(rollbackFor = StException.class)\n    public Order create(Order order, List&lt;Integer&gt; cartIds, Integer userId)\n            throws StException {\n\n        if (cartIds == null || cartIds.isEmpty()) {\n            throw new StException(\"\u8bf7\u9009\u62e9\u8981\u7ed3\u7b97\u7684\u5546\u54c1\");\n        }\n\n        List&lt;OrderDetail&gt; detailList = new ArrayList&lt;&gt;();\n\n        \/\/ \u904d\u5386\u6bcf\u4e2a\u9009\u4e2d\u7684\u8d2d\u7269\u8f66\u9879\n        for (Integer cartId : cartIds) {\n            \/\/ \u2460 \u67e5\u8d2d\u7269\u8f66\u9879\n            Cart cart = cartMapper.selectById(cartId);\n            if (cart == null)\n                throw new StException(\"\u8d2d\u7269\u8f66\u9879\u4e0d\u5b58\u5728\uff1a\" + cartId);\n\n            \/\/ \u2461 \u9a8c\u8bc1\u8d2d\u7269\u8f66\u5f52\u5c5e\uff08\u4e0d\u80fd\u7ed3\u7b97\u522b\u4eba\u7684\u8d2d\u7269\u8f66\uff09\n            if (!cart.getUserId().equals(userId))\n                throw new StException(\"\u65e0\u6743\u7ed3\u7b97\u8be5\u8d2d\u7269\u8f66\u9879\uff1a\" + cartId);\n\n            \/\/ \u2462 \u901a\u8fc7Dubbo\u67e5\u5546\u54c1\u4fe1\u606f\uff08\u8de8\u670d\u52a1\u8c03\u7528goods_service\uff09\n            Goods goods = goodsService.selectById(cart.getGoodsId());\n            if (goods == null)\n                throw new StException(\"\u5546\u54c1\u4e0d\u5b58\u5728\u6216\u5df2\u4e0b\u67b6\");\n\n            \/\/ \u2463 \u68c0\u67e5\u5e93\u5b58\uff08\u6ce8\u610f\uff1a\u53ea\u68c0\u67e5\u4e0d\u6263\u51cf\uff0c\u771f\u6b63\u7684\u6263\u51cf\u53d1\u751f\u5728\u652f\u4ed8\u6210\u529f\u540e\uff09\n            if (cart.getCount() &gt; goods.getCount())\n                throw new StException(\"\u5546\u54c1\u3010\" + goods.getName() + \"\u3011\u5e93\u5b58\u4e0d\u8db3\");\n\n            \/\/ \u2464 \u6784\u9020\u8ba2\u5355\u660e\u7ec6\u5feb\u7167\n            \/\/    \u8bb0\u5f55\u4e0b\u5355\u65f6\u7684\u4ef7\u683c\uff08snapshot\uff09\uff0c\u4ee5\u540e\u5546\u54c1\u8c03\u4ef7\u4e0d\u5f71\u54cd\u5386\u53f2\u8ba2\u5355\n            BigDecimal subtotal =\n                goods.getPrice().multiply(new BigDecimal(cart.getCount()));\n\n            detailList.add(new OrderDetail(\n                goods.getId(),       \/\/ \u5546\u54c1ID\n                goods.getName(),     \/\/ \u5546\u54c1\u540d\uff08\u5feb\u7167\uff09\n                firstPic(goods),     \/\/ \u5546\u54c1\u4e3b\u56fe\uff08\u5feb\u7167\uff09\n                goods.getPrice(),    \/\/ \u2605\u4e0b\u5355\u65f6\u7684\u552e\u4ef7\uff08\u5feb\u7167\uff09\n                cart.getCount(),     \/\/ \u8d2d\u4e70\u6570\u91cf\n                subtotal             \/\/ \u5c0f\u8ba1\n            ));\n        }\n\n        \/\/ \u2465 \u7edf\u4e00\u843d\u5e93\n        return persistOrder(order, userId, detailList, cartIds);\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u76f4\u63a5\u8d2d\u4e70\u4e0b\u5355\uff08\u4ece\u5546\u54c1\u8be6\u60c5\u9875\uff0c\u8df3\u8fc7\u8d2d\u7269\u8f66\uff09\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    @Override\n    @Transactional(rollbackFor = StException.class)\n    public Order createDirect(Integer goodsId, Integer count,\n            Integer addrId, Integer payType, Integer userId)\n            throws StException {\n\n        if (goodsId == null || count == null || count &lt;= 0)\n            throw new StException(\"\u8d2d\u4e70\u4fe1\u606f\u4e0d\u5408\u6cd5\");\n\n        Goods goods = goodsService.selectById(goodsId);\n        if (goods == null)\n            throw new StException(\"\u5546\u54c1\u4e0d\u5b58\u5728\u6216\u5df2\u4e0b\u67b6\");\n        if (count &gt; goods.getCount())\n            throw new StException(\"\u5546\u54c1\u5e93\u5b58\u4e0d\u8db3\");\n\n        BigDecimal subtotal =\n            goods.getPrice().multiply(new BigDecimal(count));\n\n        List&lt;OrderDetail&gt; detailList = new ArrayList&lt;&gt;();\n        detailList.add(new OrderDetail(\n            goods.getId(), goods.getName(), firstPic(goods),\n            goods.getPrice(), count, subtotal));\n\n        Order order = new Order();\n        order.setAddrId(addrId);\n        order.setPayType(payType);\n\n        \/\/ cartIds\u4f20null \u2192 \u4e0d\u5220\u8d2d\u7269\u8f66\n        return persistOrder(order, userId, detailList, null);\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u7edf\u4e00\u843d\u5e93\u903b\u8f91\uff08\u8d2d\u7269\u8f66\u7ed3\u7b97\u548c\u76f4\u63a5\u8d2d\u4e70\u5171\u7528\uff09\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    private Order persistOrder(Order order, Integer userId,\n            List&lt;OrderDetail&gt; detailList, List&lt;Integer&gt; cartIds)\n            throws StException {\n\n        \/\/ \u2460 \u751f\u6210\u96ea\u82b1\u7b97\u6cd5\u8ba2\u5355\u53f7\n        order.setId(IdUtil.getSnowflakeNextId());\n        \/\/ \u2461 \u8bbe\u7f6e\u7528\u6237ID\n        order.setUserId(userId);\n        \/\/ \u2462 \u521d\u59cb\u72b6\u6001\uff1a\u5f85\u4ed8\u6b3e\n        order.setStatus(0);\n        \/\/ \u2463 \u751f\u6210\u5730\u5740\u5feb\u7167\n        order.setAddrDetail(buildAddrDetail(order.getAddrId()));\n        \/\/ \u2464 \u628a\u5546\u54c1\u5217\u8868\u5e8f\u5217\u5316\u6210JSON\u5b57\u7b26\u4e32\n        order.setItems(JSONUtil.toJsonStr(detailList));\n        \/\/ \u2465 \u63d2\u5165\u8ba2\u5355\u8868\n        orderMapper.insert(order);\n\n        \/\/ \u2466 \u5982\u679c\u662f\u4ece\u8d2d\u7269\u8f66\u7ed3\u7b97\u7684 \u2192 \u5220\u9664\u5df2\u8d2d\u4e70\u7684\u8d2d\u7269\u8f66\u9879\n        \/\/    \u8fd9\u4e00\u6b65\u548c\u2465\u5728\u540c\u4e00\u4e8b\u52a1\u4e2d\uff08@Transactional\uff09\n        if (cartIds != null &amp;&amp; !cartIds.isEmpty()) {\n            cartMapper.deleteByIds(cartIds);\n        }\n\n        \/\/ \u2467 \u56de\u586bdetailList\u548ctotalPrice\uff08\u8fd4\u56de\u7ed9\u524d\u7aef\u5c55\u793a\uff09\n        order.setDetailList(detailList);\n        fillDetailAndPrice(order);\n        return order;\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u652f\u4ed8\u5b9d\u652f\u4ed8\uff1a\u751f\u6210\u8df3\u8f6c\u8868\u5355\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    @Override\n    public String pay(Long id, Integer userId) throws StException {\n        \/\/ \u2460 \u67e5\u8ba2\u5355\n        Order order = orderMapper.selectById(id);\n        if (order == null) throw new StException(\"\u8ba2\u5355\u4e0d\u5b58\u5728\");\n\n        \/\/ \u2461 \u4e09\u5c42\u6821\u9a8c\n        if (!order.getUserId().equals(userId))\n            throw new StException(\"\u65e0\u6743\u64cd\u4f5c\u8be5\u8ba2\u5355\");  \/\/ \u5f52\u5c5e\u6821\u9a8c\n        if (order.getStatus() != 0)\n            throw new StException(\"\u8ba2\u5355\u72b6\u6001\u4e0d\u5141\u8bb8\u652f\u4ed8\"); \/\/ \u72b6\u6001\u6821\u9a8c\n\n        \/\/ \u2462 \u89e3\u6790items JSON \u2192 \u83b7\u53d6\u8ba2\u5355\u603b\u91d1\u989d\n        fillDetailAndPrice(order);\n        if (order.getTotalPrice().compareTo(BigDecimal.ZERO) &lt;= 0)\n            throw new StException(\"\u8ba2\u5355\u91d1\u989d\u5f02\u5e38\");      \/\/ \u91d1\u989d\u6821\u9a8c\n\n        \/\/ \u2463 \u6784\u9020\u652f\u4ed8\u5b9dPC\u7f51\u7ad9\u652f\u4ed8\u8bf7\u6c42\n        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();\n        request.setNotifyUrl(alipayConfig.getNotifyUrl());  \/\/ \u5f02\u6b65\u901a\u77e5URL\n        request.setReturnUrl(alipayConfig.getReturnUrl());  \/\/ \u540c\u6b65\u8df3\u8f6cURL\n\n        \/\/ \u2605\u7528JSONObject\u6784\u9020bizContent\uff0c\u4e0d\u7528\u624b\u62fc\u5b57\u7b26\u4e32\uff08\u907f\u514d\u5f15\u53f7\/\u7279\u6b8a\u5b57\u7b26\u95ee\u9898\uff09\n        JSONObject biz = new JSONObject();\n        biz.set(\"out_trade_no\", String.valueOf(order.getId()));      \/\/ \u5546\u6237\u8ba2\u5355\u53f7\n        biz.set(\"total_amount\", order.getTotalPrice().toPlainString()); \/\/ \u91d1\u989d\n        biz.set(\"subject\", \"\u5728\u7ebf\u5546\u57ce\u8ba2\u5355\" + order.getId());          \/\/ \u8ba2\u5355\u6807\u9898\n        biz.set(\"product_code\", \"FAST_INSTANT_TRADE_PAY\");          \/\/ \u4ea7\u54c1\u7801\n        biz.set(\"timeout_express\", \"30m\");  \/\/ \u260530\u5206\u949f\u672a\u4ed8\u6b3e\u2192\u652f\u4ed8\u5b9d\u81ea\u52a8\u5173\u95ed\u4ea4\u6613\n        request.setBizContent(biz.toString());\n\n        \/\/ \u2464 \u8c03\u7528\u652f\u4ed8\u5b9dSDK \u2192 \u62ff\u5230\u81ea\u63d0\u4ea4\u8868\u5355\u7684HTML\u5b57\u7b26\u4e32\n        try {\n            return alipayClient.pageExecute(request).getBody();\n        } catch (Exception e) {\n            throw new StException(\"\u751f\u6210\u652f\u4ed8\u8868\u5355\u5931\u8d25\uff1a\" + e.getMessage());\n        }\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u652f\u4ed8\u5b9d\u5f02\u6b65\u56de\u8c03\uff08notifyUrl\uff09\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    @Override\n    public boolean notifyPay(Map&lt;String, String&gt; params) {\n        try {\n            \/\/ \u2460 \u7b7e\u9a8c\uff1a\u786e\u4fdd\u8bf7\u6c42\u786e\u5b9e\u6765\u81ea\u652f\u4ed8\u5b9d\uff08\u4e0d\u662f\u4f2a\u9020\u7684\uff09\n            boolean signOk = AlipaySignature.rsaCheckV1(\n                params,\n                alipayConfig.getPublicKey(),  \/\/ \u652f\u4ed8\u5b9d\u516c\u94a5\n                \"UTF-8\",\n                alipayConfig.getSignType()    \/\/ \"RSA2\"\n            );\n            if (!signOk) {\n                return false;  \/\/ \u7b7e\u540d\u4e0d\u5bf9 \u2192 \u8fd4\u56de\"failure\"\n            }\n\n            \/\/ \u2461 \u68c0\u67e5\u4ea4\u6613\u72b6\u6001\n            String tradeStatus = params.get(\"trade_status\");\n            if (!\"TRADE_SUCCESS\".equals(tradeStatus) &amp;&amp;\n                !\"TRADE_FINISHED\".equals(tradeStatus)) {\n                \/\/ \u4e0d\u662f\u652f\u4ed8\u6210\u529f\u7684\u72b6\u6001\uff08\u53ef\u80fd\u662f\"\u7b49\u5f85\u4ed8\u6b3e\"\u7b49\uff09\u2192 \u8fd4\u56desuccess\u4f46\u4e0d\u5904\u7406\n                return true;\n            }\n\n            \/\/ \u2462 \u4ece\u652f\u4ed8\u5b9d\u8fd4\u56de\u7684\u53c2\u6570\u4e2d\u63d0\u53d6\u8ba2\u5355\u53f7\uff0c\u7136\u540e\u66f4\u65b0\u8ba2\u5355\u72b6\u6001\n            Long orderId = Long.valueOf(params.get(\"out_trade_no\"));\n            return markPaid(orderId);\n\n        } catch (Exception e) {\n            log.warning(\"notifyPay \u5f02\u5e38: \" + e.getMessage());\n            return false;\n        }\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u4e3b\u52a8\u67e5\u8be2\u652f\u4ed8\u5b9d\uff08returnUrl\u515c\u5e95\u65b9\u6848\uff09\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    @Override\n    public boolean queryAndUpdate(Long id) {\n        \/\/ \u53ea\u5904\u7406\u5f85\u4ed8\u6b3e\u7684\u8ba2\u5355\uff08\u5df2\u5904\u7406\u8fc7\u7684\u8df3\u8fc7\uff09\n        Order order = orderMapper.selectById(id);\n        if (order == null || order.getStatus() != 0) {\n            return false;\n        }\n\n        try {\n            \/\/ \u6784\u9020\u652f\u4ed8\u5b9d\u67e5\u8be2\u8bf7\u6c42\n            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();\n            JSONObject biz = new JSONObject()\n                .set(\"out_trade_no\", String.valueOf(id));\n            request.setBizContent(biz.toString());\n\n            \/\/ \u8c03\u7528\u652f\u4ed8\u5b9d\u67e5\u8be2\u63a5\u53e3\n            AlipayTradeQueryResponse response = alipayClient.execute(request);\n            if (response == null) return false;\n\n            \/\/ \u652f\u4ed8\u5b9d\u8bf4\u652f\u4ed8\u6210\u529f\u4e86 \u2192 \u66f4\u65b0\u8ba2\u5355\n            if (\"TRADE_SUCCESS\".equals(response.getTradeStatus())) {\n                return markPaid(id);\n            }\n\n            return false;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u6807\u8bb0\u8ba2\u5355\u4e3a\"\u5df2\u4ed8\u6b3e\"\uff08\u5e42\u7b49\u64cd\u4f5c\uff09\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    \/**\n     * \u2605\u5e42\u7b49\u8bbe\u8ba1\uff1a\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u88ab\u591a\u6b21\u8c03\u7528\uff0c\u4f46\u53ea\u6709\u7b2c\u4e00\u6b21\u771f\u6b63\u6267\u884c\n     * \u652f\u4ed8\u5b9d\u53ef\u80fd\u57281\u79d2\u5185\u8fde\u7eed\u53d1\u591a\u6b21notify\uff08\u7f51\u7edc\u91cd\u8bd5\uff09\n     * \u5982\u679c\u6ca1\u6709\u5e42\u7b49\u4fdd\u62a4 \u2192 \u7b2c\u4e00\u6b21\u6539status=1\u6210\u529f\uff0c\u7b2c\u4e8c\u6b21\u53c8\u6263\u4e00\u6b21\u5e93\u5b58 \u2192 \u91cd\u590d\u6263\n     * \n     * \u5e42\u7b49\u4fdd\u62a4\uff1astatus!=0 \u2192 return true\uff08\u4ec0\u4e48\u90fd\u4e0d\u505a\uff09\n     * \u7b2c\u4e00\u6b21\u8c03\u7528\uff1astatus=0 \u2192 \u6539status=1 \u2192 \u6263\u5e93\u5b58 \u2192 return true\n     * \u7b2c\u4e8c\u6b21\u8c03\u7528\uff1astatus=1\uff08\u5df2\u88ab\u7b2c\u4e00\u6b21\u6539\u4e86\uff09\u2192 return true\uff08\u8df3\u8fc7\uff09\n     * \n     * \u2605\u6ca1\u6709@Transactional\uff1a\u6539status\u662f\u5355\u6761UPDATE\uff08MySQL\u81ea\u5df1\u4fdd\u8bc1\u539f\u5b50\u6027\uff09\n     * \u6263\u5e93\u5b58\u662fDubbo RPC\uff08\u72ec\u7acb\u4e8b\u52a1\uff09\uff0c\u4e0d\u653e\u5728\u540c\u4e00\u672c\u5730\u4e8b\u52a1\u91cc\n     * \u5148\u6539\u72b6\u6001\uff08\u4fdd\u8bc1\u652f\u4ed8\u95ed\u73af\uff1a\u94b1\u5df2\u4ed8\uff0c\u5fc5\u987b\u663e\u793a\"\u5df2\u4ed8\u6b3e\"\uff09\n     * \u518d\u6263\u5e93\u5b58\uff08\u5c3d\u529b\u800c\u4e3a\uff1a\u5931\u8d25\u8bb0\u65e5\u5fd7\uff0c\u4eba\u5de5\u8865\u8d27\/\u9000\u6b3e\uff09\n     *\/\n    private boolean markPaid(Long orderId) {\n        \/\/ \u2605\u5e42\u7b49\u68c0\u67e5\n        Order order = orderMapper.selectById(orderId);\n        if (order == null || order.getStatus() != 0) {\n            return true;  \/\/ \u5df2\u7ecf\u5904\u7406\u8fc7\u4e86\n        }\n\n        fillDetailAndPrice(order);\n\n        \/\/ \u2460 \u6539\u8ba2\u5355\u72b6\u6001\uff08\u5148\u505a\uff0c\u4fdd\u8bc1\u94b1\u4e0d\u767d\u4ed8\uff09\n        Order upd = new Order();\n        upd.setId(orderId);\n        upd.setStatus(1);  \/\/ \u5f85\u4ed8\u6b3e \u2192 \u5df2\u4ed8\u6b3e\n        orderMapper.updateById(upd);\n        \/\/ \u8fd9\u4e00\u6761UPDATE\u662f\u539f\u5b50\u64cd\u4f5c\uff0c\u4e0d\u9700\u8981\u4e8b\u52a1\u5305\u88f9\n\n        \/\/ \u2461 \u6263\u5e93\u5b58\uff08\u5c3d\u529b\u800c\u4e3a\uff0c\u4e0d\u8ba1\u8f83\u6210\u8d25\uff09\n        for (OrderDetail d : order.getDetailList()) {\n            try {\n                if (!goodsService.reduceStock(d.getGoodsId(), d.getCount())) {\n                    log.warning(\"\u5e93\u5b58\u6263\u51cf\u5931\u8d25: orderId=\" + orderId +\n                        \" goodsId=\" + d.getGoodsId() +\n                        \" goodsName=\" + d.getGoodsName());\n                }\n            } catch (Exception e) {\n                log.warning(\"\u5e93\u5b58\u6263\u51cf\u5f02\u5e38: orderId=\" + orderId +\n                    \" goodsId=\" + d.getGoodsId() + \" \" + e.getMessage());\n            }\n        }\n\n        return true;\n    }\n\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n    \/\/ \u67e5\u8be2\u7528\u6237\u8ba2\u5355\u5217\u8868\n    \/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n    @Override\n    public List&lt;Order&gt; selectByUserId(Integer userId) {\n        List&lt;Order&gt; list = orderMapper.selectByUserId(userId);\n        \/\/ \u6bcf\u6761\u8ba2\u5355\u90fd\u8981\u89e3\u6790items \u2192 \u586bdetailList\u548ctotalPrice\n        list.forEach(this::fillDetailAndPrice);\n        return list;\n    }\n\n    \/\/ ... search, selectById, updateStatus, delete \u7b49\u65b9\u6cd5\u540c\u6837\u5904\u7406\n}<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">10.2 OrderMapper.xml \u2014 \u8ba2\u5355SQL<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1aorder_service\/...\/mapper\/OrderMapper.xml --&gt;\n\n&lt;!-- \u63d2\u5165\u8ba2\u5355\uff1aid\u7531\u7a0b\u5e8f\u751f\u6210\uff08\u96ea\u82b1\u7b97\u6cd5\uff09\u3001create_time\u7528MySQL\u7684NOW() --&gt;\n&lt;insert id=\"insert\" parameterType=\"org.example.mall.common.bean.Order\"&gt;\n    INSERT INTO `order`(id, user_id, pay_type, express,\n                        addr_id, addr_detail, status, items, create_time)\n    VALUES (#{id}, #{userId}, #{payType}, #{express},\n            #{addrId}, #{addrDetail}, #{status}, #{items}, NOW())\n&lt;\/insert&gt;\n\n&lt;!-- \u67e5\u8be2\u7528\u6237\u8ba2\u5355\u5217\u8868\uff08\u5e26\u7528\u6237\u540d\uff09 --&gt;\n&lt;select id=\"selectByUserId\" resultMap=\"orderMap\"&gt;\n    SELECT o.*, u.username\n    FROM `order` o\n    LEFT JOIN `user` u ON o.user_id = u.id\n    WHERE o.user_id = #{userId}\n    ORDER BY o.create_time DESC\n&lt;\/select&gt;\n\n&lt;!-- \u67e5\u8be2\u5730\u5740\u8868\uff08\u4f9bbuildAddrDetail\u7528\uff09 --&gt;\n&lt;select id=\"selectAddrById\" resultType=\"org.example.mall.common.bean.Addr\"&gt;\n    SELECT * FROM `addr` WHERE `id` = #{id}\n&lt;\/select&gt;\n\n&lt;!-- \u5b9a\u65f6\u53d6\u6d88\u8d85\u65f6\u672a\u4ed8\u8ba2\u5355 --&gt;\n&lt;update id=\"cancelExpiredOrders\"&gt;\n    UPDATE `order` SET `status` = 4\n    WHERE `status` = 0\n      AND `create_time` &amp;lt; #{before}\n    &lt;!-- &amp;lt; \u662f &lt; \u7684XML\u8f6c\u4e49\u5199\u6cd5 --&gt;\n&lt;\/update&gt;<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">10.3 OrderTimeoutTask \u2014 \u5b9a\u65f6\u53d6\u6d88<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1aorder_service\/...\/task\/OrderTimeoutTask.java\n\n@Component  \/\/ Spring\u7ba1\u7406\u7684\u7ec4\u4ef6\npublic class OrderTimeoutTask {\n\n    private static final Logger log =\n        Logger.getLogger(OrderTimeoutTask.class.getName());\n\n    \/** \u8d85\u65f6\u9608\u503c\uff1a30\u5206\u949f *\/\n    private static final long TIMEOUT_MS = 30L * 60 * 1000;\n\n    @Autowired\n    private OrderMapper orderMapper;\n\n    \/**\n     * @Scheduled\uff1aSpring\u7684\u5b9a\u65f6\u4efb\u52a1\u6ce8\u89e3\n     * fixedRate = 5 * 60 * 1000 = \u6bcf5\u5206\u949f\u6267\u884c\u4e00\u6b21\n     * \n     * \u6267\u884c\u903b\u8f91\uff1a\u67e5\u51fa\u6240\u6709\u8d85\u8fc730\u5206\u949f\u8fd8\u6ca1\u4ed8\u6b3e\u7684\u8ba2\u5355\uff0c\u6279\u91cf\u8bbe\u4e3a\"\u5df2\u53d6\u6d88\"\n     *\/\n    @Scheduled(fixedRate = 5 * 60 * 1000)\n    public void cancelExpiredOrders() {\n        \/\/ \u8ba1\u7b97\"30\u5206\u949f\u524d\"\u7684\u65f6\u95f4\u70b9\n        Date before = new Date(System.currentTimeMillis() - TIMEOUT_MS);\n\n        \/\/ \u6279\u91cf\u66f4\u65b0\n        int n = orderMapper.cancelExpiredOrders(before);\n        if (n &gt; 0) {\n            log.info(\"\u5df2\u81ea\u52a8\u53d6\u6d88\u8d85\u65f6\u672a\u652f\u4ed8\u8ba2\u5355 \" + n + \" \u7b14\");\n        }\n    }\n}<\/code><\/pre>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u542f\u7528\u5b9a\u65f6\u4efb\u52a1\uff1a\u5728\u542f\u52a8\u7c7b\u4e0a\u52a0 @EnableScheduling\n\/\/ \u6587\u4ef6\uff1aorder_service\/...\/OrderServiceApplication.java\n\n@SpringBootApplication(scanBasePackages = {\"org.example.mall\"})\n@MapperScan(basePackages = \"org.example.mall.order_service.mapper\")\n@EnableDubbo         \/\/ \u542f\u7528Dubbo\uff08\u4f5c\u4e3a\u6d88\u8d39\u8005\u8c03\u7528goods_service\uff09\n@EnableScheduling    \/\/ \u2605\u542f\u7528\u5b9a\u65f6\u4efb\u52a1\npublic class OrderServiceApplication {\n    \/\/ ...\n}<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">10.4 OrderController \u2014 \u53d6\u6d88\u8ba2\u5355\u7684\u5f52\u5c5e\u6821\u9a8c<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1aorder_service\/...\/controller\/OrderController.java\n\n\/**\n * \u2605\u5173\u952e\uff1a\u7528\u6237\u53d6\u6d88\u81ea\u5df1\u7684\u8ba2\u5355\uff08\u548c\u540e\u53f0\u7ba1\u7406\u5458\u6539\u72b6\u6001\u662f\u4e0d\u540c\u7684\u63a5\u53e3\uff09\n * \n * \u4e3a\u4ec0\u4e48\u8981\u533a\u5206\uff1f\n * \u540e\u53f0 PUT \/order\/status \u4e0d\u5e94\u8be5\u505a\u5f52\u5c5e\u6821\u9a8c\uff08\u7ba1\u7406\u5458\u53ef\u4ee5\u6539\u4efb\u4f55\u8ba2\u5355\u7684\u72b6\u6001\uff09\n * \u524d\u53f0\u7528\u6237\u53ea\u80fd\u53d6\u6d88\u81ea\u5df1\u7684\u8ba2\u5355\uff0c\u5fc5\u987b\u505a\u5f52\u5c5e\u6821\u9a8c\n * \u5982\u679c\u524d\u53f0\u7528\u6237\u8c03\u7528\u540e\u53f0\u63a5\u53e3 PUT \/order\/status \u4e5f\u53ef\u4ee5\u53d6\u6d88\u8ba2\u5355\uff0c\n *    \u800c\u4e14\u6ca1\u6709\u5f52\u5c5e\u6821\u9a8c \u2192 \u7528\u6237\u53ef\u4ee5\u53d6\u6d88\u4efb\u4f55\u4eba\u7684\u8ba2\u5355\uff01\n *\/\n@PutMapping(\"\/cancel\/{id}\")\npublic RespBean cancel(@PathVariable Long id,\n                       @RequestHeader String token) throws StException {\n    Integer userId = (Integer) JwtUtil.parseJwtToMap(token).get(\"id\");\n\n    Order order = orderService.selectById(id);\n    if (order == null)\n        throw new StException(\"\u8ba2\u5355\u4e0d\u5b58\u5728\");           \/\/ \u7b2c\u4e00\u5c42\uff1a\u5b58\u5728\u6027\n\n    if (!order.getUserId().equals(userId))\n        throw new StException(\"\u65e0\u6743\u64cd\u4f5c\u8be5\u8ba2\u5355\");       \/\/ \u7b2c\u4e8c\u5c42\uff1a\u5f52\u5c5e\n\n    if (order.getStatus() != 0)\n        throw new StException(\"\u8be5\u8ba2\u5355\u72b6\u6001\u65e0\u6cd5\u53d6\u6d88\");    \/\/ \u7b2c\u4e09\u5c42\uff1a\u72b6\u6001\n\n    Order upd = new Order();\n    upd.setId(id);\n    upd.setStatus(4);  \/\/ \u5df2\u53d6\u6d88\n    orderService.updateStatus(upd);\n\n    return RespBean.success(\"\u8ba2\u5355\u5df2\u53d6\u6d88\");\n}<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">11. \u524d\u7aef\u57fa\u7840<\/h2>\n\n\n<h3 class=\"wp-block-heading\">11.1 Vue 3\u5355\u6587\u4ef6\u7ec4\u4ef6\u7684\u7ed3\u6784<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1afront\/src\/views\/user\/GoodsView.vue\uff08\u7b80\u5316\u7248\uff09 --&gt;\n\n&lt;script setup&gt;\n\/\/ \u2190 setup=\u8bed\u6cd5\u7cd6\uff0c\u4e0d\u9700\u8981\u5199 export default {}\n\/\/   \u53d8\u91cf\u3001\u51fd\u6570\u76f4\u63a5\u66b4\u9732\u7ed9\u6a21\u677f\u4f7f\u7528\n\nimport { ref } from \"vue\";\n\/\/ ref() \u662fVue\u7684\u54cd\u5e94\u5f0fAPI\uff1a\u503c\u53d8\u4e86\u6a21\u677f\u81ea\u52a8\u91cd\u65b0\u6e32\u67d3\n\nconst goods = ref({});\n\/\/      \u2191   \u2191\n\/\/      |   \u521d\u59cb\u503c\uff08\u5f53\u6570\u636e\u8fd8\u6ca1\u4ece\u540e\u7aef\u52a0\u8f7d\u65f6\uff0c\u6a21\u677f\u53ef\u4ee5\u7528\u8fd9\u4e2a\u7a7a\u5bf9\u8c61\u5360\u4f4d\uff09\n\/\/      \u5305\u88c5\u540e\u7684\u54cd\u5e94\u5f0f\u53d8\u91cf\n\nfunction selectById() {\n    let id = route.query.id;\n    goodsApi.selectById(id).then(resp =&gt; {\n        goods.value = resp.data;  \/\/ \u2190 .value \u4fee\u6539ref\u7684\u503c\n        \/\/ \u8fd9\u4e00\u884c\u6267\u884c\u540e\uff0c\u6a21\u677f\u91cc {{ goods.name }} \u4f1a\u81ea\u52a8\u66f4\u65b0\n    });\n}\n&lt;\/script&gt;\n\n&lt;template&gt;\n    &lt;!-- \u6a21\u677f\u4e2d\u53ef\u4ee5\u7701\u7565 .value\uff0c\u76f4\u63a5\u5199 goods.name --&gt;\n    &lt;div class=\"name\"&gt;{{ goods.name }}&lt;\/div&gt;\n    &lt;div class=\"price\"&gt;\uffe5{{ goods.price }}&lt;\/div&gt;\n    &lt;el-button @click=\"selectById\"&gt;\u52a0\u8f7d\u5546\u54c1&lt;\/el-button&gt;\n&lt;\/template&gt;\n\n&lt;style scoped&gt;\n\/* scoped = \u53ea\u4f5c\u7528\u4e8e\u5f53\u524d\u7ec4\u4ef6\uff0c\u4e0d\u5f71\u54cd\u5176\u4ed6\u7ec4\u4ef6 *\/\n.name { font-weight: bold; font-size: 25px; }\n.price { color: #FF6800; }\n&lt;\/style&gt;<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">11.2 \u9879\u76ee\u5165\u53e3\u548c\u5168\u5c40\u914d\u7f6e<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1afront\/src\/main.js\n\nimport { createApp } from 'vue'\nimport { createPinia } from 'pinia'\nimport ElementPlus from 'element-plus'\nimport 'element-plus\/dist\/index.css'\nimport * as ElementPlusIconsVue from '@element-plus\/icons-vue'\nimport App from '.\/App.vue'\nimport router from '.\/router'\nimport piniaPluginPersistedstate from 'pinia-plugin-persistedstate'\n\nconst app = createApp(App)    \/\/ \u521b\u5efaVue\u5e94\u7528\u5b9e\u4f8b\n\n\/\/ \u2605\u5168\u5c40\u6ce8\u518c\u6240\u6709Element Plus\u56fe\u6807\n\/\/ \u8fd9\u6837\u6a21\u677f\u91cc\u53ef\u4ee5\u76f4\u63a5\u7528 &lt;HomeFilled\/&gt; &lt;User\/&gt; \u7b49\u56fe\u6807\uff0c\u4e0d\u7528\u6bcf\u4e2a\u9875\u9762\u5355\u72ecimport\nfor (const [key, component] of Object.entries(ElementPlusIconsVue)) {\n    app.component(key, component)\n}\n\n\/\/ \u914d\u7f6ePinia\u72b6\u6001\u7ba1\u7406 + \u6301\u4e45\u5316\u63d2\u4ef6\nconst pinia = createPinia()\npinia.use(piniaPluginPersistedstate)  \/\/ \u2190 \u81ea\u52a8\u628astore\u6570\u636e\u5b58\u5230sessionStorage\n\napp.use(pinia)         \/\/ \u6ce8\u518c\u72b6\u6001\u7ba1\u7406\napp.use(router)         \/\/ \u6ce8\u518c\u8def\u7531\napp.use(ElementPlus)    \/\/ \u6ce8\u518cUI\u7ec4\u4ef6\u5e93\napp.mount('#app')       \/\/ \u6302\u8f7d\u5230index.html\u7684&lt;div id=\"app\"&gt;<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">11.3 \u5e97\u94fa\u5168\u5c40CSS\u53d8\u91cf<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/* \u6587\u4ef6\uff1afront\/src\/assets\/base.css *\/\n\n:root {\n    --theme-color: #FF6800;         \/* \u4e3b\u8272\u8c03\uff1a\u6a59\u8272 *\/\n    --theme-bg-color: #303133;      \/* \u6df1\u8272\u80cc\u666f\u8272 *\/\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\">\u6574\u4e2a\u9879\u76ee\u4e2d\u6240\u6709\u7528\u5230\u4e3b\u9898\u8272\u7684\u5730\u65b9\u90fd\u5199 <code>var(--theme-color)<\/code>\uff0c\u5982\u679c\u8981\u6362\u989c\u8272\uff0c\u53ea\u6539\u8fd9\u4e00\u4e2a\u5730\u65b9\u5c31\u884c\u3002<\/p>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">12. HTTP\u5c42<\/h2>\n\n\n<h3 class=\"wp-block-heading\">12.1 Axios\u5b9e\u4f8b + \u62e6\u622a\u5668\u53cc\u5411\u81ea\u52a8\u5316<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1afront\/src\/api\/index.js\n\nimport axios from \"axios\";\nimport { userTokenStore } from \"@\/stores\/token.js\";\nimport { ElMessage } from \"element-plus\";\nimport router from \"@\/router\/index.js\";\n\n\/\/ \u521b\u5efaAxios\u5b9e\u4f8b\uff0c\u914d\u7f6e\u57fa\u7840URL\nconst service = axios.create({\n    baseURL: import.meta.env.VITE_SERVER_ADDR  \/\/ \u6253\u5305\u65f6\u4ece.env\u6ce8\u5165\n    \/\/ \u5f00\u53d1\/\u751f\u4ea7\u73af\u5883\u81ea\u52a8\u5207\u6362\uff1a\u672c\u5730npm run dev\u7528\u5f00\u53d1\u5730\u5740\uff0c\u6253\u5305\u540e\u7528\u751f\u4ea7\u5730\u5740\n});\n\n\/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\/\/ \u2605\u8bf7\u6c42\u62e6\u622a\u5668\uff1a\u53d1\u8bf7\u6c42\u524d\u81ea\u52a8\u5e72\u7684\u4e8b\n\/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nservice.interceptors.request.use(req =&gt; {\n    \/\/ \u4ecePinia store\u53d6\u51fa\u5f53\u524dtoken\n    const tokenStore = userTokenStore();\n    if (tokenStore.tokenStr) {\n        req.headers.token = tokenStore.tokenStr;  \/\/ \u653e\u8bf7\u6c42\u5934\u91cc\n    }\n    return req;  \/\/ \u8fd4\u56de\u4fee\u6539\u540e\u7684\u8bf7\u6c42\u914d\u7f6e\n}, error =&gt; {});\n\n\/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\/\/ \u2605\u54cd\u5e94\u62e6\u622a\u5668\uff1a\u6536\u5230\u54cd\u5e94\u540e\u81ea\u52a8\u5e72\u7684\u4e8b\n\/\/ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nservice.interceptors.response.use(resp =&gt; {\n    \/\/ \u2460 \u540e\u7aef\u6bcf\u6b21\u8fd4\u56de\u65b0JWT \u2192 \u81ea\u52a8\u66f4\u65b0\u672c\u5730\n    const token = resp.headers.token;\n    if (token) {\n        const tokenStore = userTokenStore();\n        tokenStore.updateToken(token);\n    }\n\n    \/\/ \u2461 \u2605\u76f4\u63a5\u8fd4\u56deresp.data\uff08JSON\u5bf9\u8c61\uff09\uff0c\u4e0d\u662f\u6574\u4e2aAxios\u54cd\u5e94\n    \/\/ \u8fd9\u6837\u8c03\u7528\u65b9\u5199\u7684\u662f resp.code \u800c\u4e0d\u662f resp.data.code\n    return resp.data;\n\n}, error =&gt; {\n    \/\/ \u2462 403\u9519\u8bef \u2192 \u5f39\u63d0\u793a + \u6e05token + \u8df3\u767b\u5f55\u9875\n    if (error.status === 403) {\n        ElMessage.error({\n            message: \"\u4ee4\u724c\u9519\u8bef\uff0c\u91cd\u65b0\u767b\u5f55\",\n            duration: 1200,\n            onClose: () =&gt; {\n                const tokenStore = userTokenStore();\n                tokenStore.$reset();\n                let currentPath = router.currentRoute.value.path;\n                if (currentPath.startsWith(\"\/admin\")) {\n                    router.push(\"\/admin\/login\");\n                } else {\n                    router.push(\"\/user\/login\");\n                }\n            }\n        });\n    }\n});\n\nexport default service;<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u5173\u952e\u8bbe\u8ba1<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>baseURL<\/code> \u7edf\u4e00\u914d\u7f6e \u2192 \u4e0d\u9700\u8981\u5728\u6bcf\u4e2aAPI\u51fd\u6570\u91cc\u5199\u5b8c\u6574URL<\/li>\n<li>\u8bf7\u6c42\u62e6\u622a\u5668\u81ea\u52a8\u5e26token \u2192 \u6bcf\u4e2aAPI\u51fd\u6570\u4e0d\u7528\u624b\u52a8\u4f20token<\/li>\n<li>\u54cd\u5e94\u62e6\u622a\u5668\u81ea\u52a8\u5237\u65b0token \u2192 \u7528\u6237\u53ea\u8981\u6301\u7eed\u64cd\u4f5c\u5c31\u4e0d\u4f1a\u8fc7\u671f<\/li>\n<li>\u8fd4\u56de<code>resp.data<\/code> \u2192 \u8c03\u7528\u65b9\u62ff\u5230\u7684\u662f\u89e3\u6790\u597d\u7684JSON\u5bf9\u8c61\uff0c\u7b80\u6d01<\/li>\n\n<\/ul>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">13. \u6838\u5fc3\u9875\u9762<\/h2>\n\n\n<h3 class=\"wp-block-heading\">13.1 CreateOrderView \u2014 \u7ed3\u7b97\u9875\u5b8c\u6574\u4ee3\u7801\u5206\u6790<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;!-- \u6587\u4ef6\uff1afront\/src\/views\/user\/CreateOrderView.vue --&gt;\n\n&lt;script setup&gt;\nimport { ref, computed, onMounted } from \"vue\";\nimport { useRoute, useRouter } from \"vue-router\";\nimport { ElMessage } from \"element-plus\";\nimport cartApi from \"@\/api\/cartApi.js\";\nimport goodsApi from \"@\/api\/GoodsApi.js\";\nimport addrApi from \"@\/api\/addrApi.js\";\nimport orderApi from \"@\/api\/orderApi.js\";\n\nconst route = useRoute();\nconst router = useRouter();\nconst SERVER_ADDR = ref(import.meta.env.VITE_SERVER_ADDR);\n\n\/\/ ====== \u72b6\u6001\u7ba1\u7406 ======\n\n\/\/ \u7ed3\u7b97\u6a21\u5f0f\uff1acart=\u8d2d\u7269\u8f66\u7ed3\u7b97\uff0cdirect=\u76f4\u63a5\u8d2d\u4e70\nconst mode = ref(\"cart\");\n\n\/\/ \u8d2d\u7269\u8f66\u7ed3\u7b97\u7684cartId\u6570\u5b57\u6570\u7ec4\nconst cartIdArr = ref([]);\n\n\/\/ \u5546\u54c1\u660e\u7ec6\uff1a\u7edf\u4e00\u7684\u663e\u793a\u683c\u5f0f\uff08\u4e0d\u7ba1\u6765\u81ea\u8d2d\u7269\u8f66\u8fd8\u662f\u76f4\u63a5\u8d2d\u4e70\uff09\nconst detailList = ref([]);\n\n\/\/ \u6536\u8d27\u5730\u5740\nconst addrList = ref([]);\nconst selectedAddrId = ref(null);\n\n\/\/ \u652f\u4ed8\u65b9\u5f0f\uff1a1\u652f\u4ed8\u5b9d 2\u5fae\u4fe1 3\u94f6\u884c\u5361\uff08\u652f\u4ed8\u5b9d\u6c99\u7bb1\uff1a\u53ea\u67091\u662f\u771f\u6b63\u53ef\u652f\u4ed8\u7684\uff09\nconst payType = ref(1);\n\nconst submitting = ref(false);\n\n\/\/ ====== \u8ba1\u7b97\u5c5e\u6027 ======\n\n\/\/ \u8ba2\u5355\u603b\u91d1\u989d = \u6240\u6709\u5546\u54c1\u5c0f\u8ba1\u7684\u7d2f\u52a0\nconst totalPrice = computed(() =&gt;\n    detailList.value.reduce((sum, d) =&gt; sum + Number(d.subtotal || 0), 0)\n);\n\n\/\/ ====== \u6570\u636e\u52a0\u8f7d ======\n\nfunction loadAddrs() {\n    addrApi.selectByUserId().then(resp =&gt; {\n        if (resp.code === 200) {\n            addrList.value = resp.data || [];\n            \/\/ \u81ea\u52a8\u9009\u4e2d\u9ed8\u8ba4\u5730\u5740\n            const def = addrList.value.find(a =&gt; a.status === 1);\n            selectedAddrId.value = def ? def.id : (addrList.value[0]?.id || null);\n        }\n    });\n}\n\n\/\/ \u8d2d\u7269\u8f66\u7ed3\u7b97\u6a21\u5f0f\uff1a\u6839\u636ecartIds\u52a0\u8f7d\u5bf9\u5e94\u7684\u8d2d\u7269\u8f66\u9879\nfunction loadCartItems(cartIds) {\n    cartApi.selectBycodition().then(resp =&gt; {\n        const all = resp.data || [];\n        detailList.value = all\n            .filter(c =&gt; cartIds.includes(c.id))  \/\/ \u53ea\u4fdd\u7559\u9009\u4e2d\u7684\n            .map(c =&gt; ({                          \/\/ \u8f6c\u6362\u6210\u7edf\u4e00\u683c\u5f0f\n                goodsId: c.goodsId,\n                goodsName: c.goods ? c.goods.name : \"\u5546\u54c1\u5df2\u4e0b\u67b6\",\n                goodsPic: c.goods?.picList?.[0]?.url || null,\n                price: c.goods ? c.goods.price : 0,\n                count: c.count,\n                subtotal: c.goods ? (c.goods.price * c.count).toFixed(2) : 0\n            }));\n    });\n}\n\n\/\/ \u76f4\u63a5\u8d2d\u4e70\u6a21\u5f0f\uff1a\u6839\u636egoodsId+count\u52a0\u8f7d\u5355\u4e2a\u5546\u54c1\nfunction loadDirectGoods(goodsId, count) {\n    goodsApi.selectById(goodsId).then(resp =&gt; {\n        const g = resp.data;\n        detailList.value = [{\n            goodsId: g.id,\n            goodsName: g.name,\n            goodsPic: g.picList?.[0]?.url || null,\n            price: g.price,\n            count: count,\n            subtotal: (g.price * count).toFixed(2)\n        }];\n    });\n}\n\n\/\/ ====== \u63d0\u4ea4\u8ba2\u5355 \u2192 \u652f\u4ed8 ======\n\n\/**\n * \u2605\u6838\u5fc3\u6d41\u7a0b\uff1a\u4e0b\u5355 AND \u652f\u4ed8\u4e32\u6210\u4e00\u6761\u94fe\n * \n * \u4e3a\u4ec0\u4e48\u8fd9\u6837\u505a\uff1f\u56e0\u4e3a\u4e4b\u524d\u5206\u5f00\"\u4e0b\u5355\u6210\u529f\"\u548c\"\u652f\u4ed8\u5931\u8d25\"\u4e24\u6761\u6d88\u606f\u5f88\u56f0\u60d1\n * \u73b0\u5728\uff1a\n *   - \u4e0b\u5355\u6210\u529f + \u652f\u4ed8\u6210\u529f \u2192 \u76f4\u63a5\u8df3\u8f6c\u652f\u4ed8\u5b9d\uff08\u7528\u6237\u770b\u5230\u7684\u662f\u8df3\u8f6c\u52a8\u4f5c\uff09\n *   - \u4e0b\u5355\u6210\u529f + \u652f\u4ed8\u5931\u8d25 \u2192 \u5f39\u4e00\u6761\u6d88\u606f\uff1a\"\u8ba2\u5355\u5df2\u521b\u5efa\uff0c\u8bf7\u5230\u6211\u7684\u8ba2\u5355\u91cd\u65b0\u652f\u4ed8\"\n *   - \u4e0b\u5355\u5931\u8d25 \u2192 \u5f39\u4e00\u6761\u6d88\u606f\uff1a\"\u4e0b\u5355\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5\"\n *\/\nfunction submitOrder() {\n    \/\/ \u524d\u7f6e\u68c0\u67e5\n    if (!selectedAddrId.value) { ElMessage.warning(\"\u8bf7\u9009\u62e9\u6536\u8d27\u5730\u5740\"); return; }\n    if (detailList.value.length === 0) { ElMessage.warning(\"\u6ca1\u6709\u53ef\u7ed3\u7b97\u7684\u5546\u54c1\"); return; }\n\n    submitting.value = true;\n\n    \/\/ \u7b2c\u4e00\u6b65\uff1a\u4e0b\u5355\n    const apiCall = mode.value === \"cart\"\n        ? orderApi.create({ addrId: selectedAddrId.value, payType: payType.value, cartIds: cartIdArr.value })\n        : orderApi.createDirect({ goodsId: Number(route.query.goodsId), count: Number(route.query.count || 1), addrId: selectedAddrId.value, payType: payType.value });\n\n    apiCall.then(resp =&gt; {\n        if (resp.code !== 200) { ElMessage.error(resp.msg); return null; }\n        return resp.data;  \/\/ \u8ba2\u5355\u521b\u5efa\u6210\u529f \u2192 \u8fd4\u56deOrder\u5bf9\u8c61 \u2192 \u4e0d\u5f39\u63d0\u793a\n    })\n    \/\/ \u7b2c\u4e8c\u6b65\uff1a\u83b7\u53d6\u652f\u4ed8\u8868\u5355\n    .then(order =&gt; {\n        if (!order) return;\n        orderApi.pay(order.id).then(payResp =&gt; {\n            if (payResp.code === 200 &amp;&amp; payResp.data) {\n                submitAlipayForm(payResp.data);  \/\/ \u2605\u8df3\u8f6c\u652f\u4ed8\u5b9d\n            } else {\n                ElMessage.error(\"\u8ba2\u5355\u5df2\u521b\u5efa\uff0c\u652f\u4ed8\u53d1\u8d77\u5931\u8d25\uff0c\u8bf7\u5230\u300c\u6211\u7684\u8ba2\u5355\u300d\u91cd\u65b0\u652f\u4ed8\");\n            }\n        }).catch(() =&gt; ElMessage.error(\"\u8ba2\u5355\u5df2\u521b\u5efa\uff0c\u652f\u4ed8\u53d1\u8d77\u5931\u8d25\"));\n    })\n    .catch(() =&gt; ElMessage.error(\"\u4e0b\u5355\u5931\u8d25\uff0c\u8bf7\u91cd\u8bd5\"))\n    .finally(() =&gt; submitting.value = false);\n}\n\n\/**\n * \u2605\u66ff\u4ee3 document.write \u7684\u652f\u4ed8\u8868\u5355\u63d0\u4ea4\u65b9\u6cd5\n * \n * \u4ee5\u524d\u7684\u505a\u6cd5\uff1adocument.write(html) \u2192 \u6574\u4e2aVue\u5e94\u7528\u88ab\u6e05\u7a7a \u2192 \u8868\u5355\u5f02\u5e38\u65f6\u767d\u5c4f\n * \u73b0\u5728\u7684\u505a\u6cd5\uff1a\u521b\u5efa\u9690\u85cfdiv \u2192 innerHTML \u2192 \u627e\u5230form \u2192 form.submit()\n *   - \u5982\u679cform\u5b58\u5728 \u2192 \u63d0\u4ea4\u8df3\u8f6c\u5230\u652f\u4ed8\u5b9d\uff08\u9875\u9762\u8df3\u8f6c\u524dVue\u8fd8\u6d3b\u7740\uff09\n *   - \u5982\u679cform\u4e0d\u5b58\u5728 \u2192 \u5f39\u9519\u8bef\u63d0\u793a + \u6e05\u7406DOM\uff08\u4e0d\u4f1a\u767d\u5c4f\uff09\n *\/\nfunction submitAlipayForm(html) {\n    const container = document.createElement('div');\n    container.style.display = 'none';\n    container.innerHTML = html;\n    document.body.appendChild(container);\n    const form = container.querySelector('form');\n    if (form) {\n        form.submit();  \/\/ \u8df3\u8f6c\u5230\u652f\u4ed8\u5b9d\n    } else {\n        ElMessage.error('\u652f\u4ed8\u8868\u5355\u5f02\u5e38\uff0c\u8bf7\u5230\u300c\u6211\u7684\u8ba2\u5355\u300d\u91cd\u65b0\u652f\u4ed8');\n        document.body.removeChild(container);\n    }\n}\n\n\/\/ ====== \u7ec4\u4ef6\u521d\u59cb\u5316 ======\n\nonMounted(() =&gt; {\n    loadAddrs();  \/\/ \u5148\u52a0\u8f7d\u5730\u5740\u5217\u8868\n\n    \/\/ \u5224\u65ad\u662f\u8d2d\u7269\u8f66\u7ed3\u7b97\u8fd8\u662f\u76f4\u63a5\u8d2d\u4e70\n    if (route.query.cartIds) {\n        mode.value = \"cart\";\n        \/\/ \u2605\u517c\u5bb9\u5904\u7406\uff1aVue Router\u7684query\u6570\u7ec4\u53ef\u80fd\u662f\u6570\u7ec4\u3001\u5355\u5b57\u7b26\u4e32\u3001\u6216cartIds[]\u683c\u5f0f\n        const raw = route.query.cartIds || route.query[\"cartIds[]\"];\n        if (Array.isArray(raw)) {\n            cartIdArr.value = raw.map(v =&gt; Number(v));\n        } else {\n            cartIdArr.value = String(raw).split(\",\").map(v =&gt; Number(v));\n        }\n        cartIdArr.value = cartIdArr.value.filter(v =&gt; !isNaN(v));\n        loadCartItems(cartIdArr.value);\n    } else if (route.query.goodsId) {\n        mode.value = \"direct\";\n        loadDirectGoods(Number(route.query.goodsId), Number(route.query.count || 1));\n    } else {\n        ElMessage.warning(\"\u672a\u9009\u62e9\u5546\u54c1\uff0c\u8bf7\u8fd4\u56de\u91cd\u65b0\u9009\u62e9\");\n    }\n});\n&lt;\/script&gt;<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">13.2 UserCenterView \u2014 \u4e2a\u4eba\u4e2d\u5fc3\u6570\u636e\u52a0\u8f7d\u7b56\u7565<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1afront\/src\/views\/user\/UserCenterView.vue\uff08\u7b80\u5316\u6458\u5f55\uff09\n\n\/**\n * \u2605\u6309\u9700\u52a0\u8f7d\u7b56\u7565\uff1a\u5207\u6362tab\u65f6\u624d\u52a0\u8f7d\u5bf9\u5e94\u6570\u636e\n * \u4e0d\u662f\u4e00\u8fdb\u5165\u4e2a\u4eba\u4e2d\u5fc3\u5c31\u52a0\u8f7d\u6240\u67095\u4e2a\u9762\u677f\u7684\u6570\u636e\n * \u800c\u662f\u53ea\u6709\u7528\u6237\u5207\u6362\u5230\"\u6211\u7684\u6536\u85cf\"\u65f6\uff0c\u624d\u53bb\u52a0\u8f7d\u6536\u85cf\u6570\u636e\n * \u8fd9\u6837\u53ef\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u7f51\u7edc\u8bf7\u6c42\n *\/\nfunction onTabChange(key) {\n    if (key === 'collect') loadCollects();  \/\/ \u5207\u5230\u6536\u85cf \u2192 \u52a0\u8f7d\u6536\u85cf\n    if (key === 'addr')    loadAddrs();     \/\/ \u5207\u5230\u5730\u5740 \u2192 \u52a0\u8f7d\u5730\u5740\n    if (key === 'orders')  loadOrders();    \/\/ \u5207\u5230\u8ba2\u5355 \u2192 \u52a0\u8f7d\u8ba2\u5355\n}<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">13.3 Admin IndexView \u2014 \u4eea\u8868\u76d8\u5b89\u5168\u5408\u5e76\u6570\u636e<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1afront\/src\/views\/admin\/IndexView.vue\uff08\u5173\u952e\u7247\u6bb5\uff09\n\n\/**\n * \u4eea\u8868\u76d8\u6570\u636e\u52a0\u8f7d\n * \n * \u2605\u4e3a\u4ec0\u4e48\u4e0d\u80fd\u76f4\u63a5 dash.value = resp.data\uff1f\n * \u56e0\u4e3a\u540e\u7aef\u53ef\u80fd\u4e0d\u8fd4\u56de\u67d0\u4e2a\u5b57\u6bb5\uff08\u6bd4\u5982todaySales\u53ef\u80fd\u5728\u65e9\u671f\u7684\u4ee3\u7801\u7248\u672c\u91cc\u6ca1\u6709\uff09\n * \u76f4\u63a5\u8986\u76d6 \u2192 \u90a3\u4e2a\u5b57\u6bb5\u53d8\u6210undefined \u2192 \u6a21\u677f\u91cc Number(undefined) = NaN \u2192 \u5d29\u6e83\n * \n * \u5b89\u5168\u5408\u5e76\uff1a\u53ea\u8986\u76d6\u540e\u7aef\u6709\u503c\u7684\u5b57\u6bb5\uff0c\u6ca1\u503c\u7684\u4fdd\u6301\u521d\u59cb\u9ed8\u8ba4\u503c\n *\/\nfunction loadDashboard() {\n    loading.value = true;\n    Service.get(\"\/admin\/dashboard\").then(resp =&gt; {\n        if (resp.code === 200 &amp;&amp; resp.data) {\n            const d = resp.data;\n\n            \/\/ \u666e\u901a\u5b57\u6bb5\uff1a\u9010\u4e2a\u68c0\u67e5\u6709\u503c\u624d\u8986\u76d6\n            ['totalOrders','totalUsers','totalGoods','todayOrders',\n             'todaySales','recentOrders','recentUsers']\n                .forEach(k =&gt; {\n                    if (d[k] != null) dash.value[k] = d[k];\n                    \/\/                  \u2191 != null \u540c\u65f6\u6392\u9664 null \u548c undefined\n                });\n\n            \/\/ statusCnt\uff1a\u7528Object.assign\u9010key\u8986\u76d6\n            \/\/ \u5982\u679c\u540e\u7aef\u53ea\u8fd4\u56de\u4e863\u4e2a\u72b6\u6001 \u2192 \u53e6\u59162\u4e2a\u72b6\u6001\u4fdd\u6301\u9ed8\u8ba4\u503c0\n            if (d.statusCnt) {\n                Object.assign(dash.value.statusCnt, d.statusCnt);\n            }\n        }\n    }).catch(() =&gt; ElMessage.error(\"\u52a0\u8f7d\u4eea\u8868\u76d8\u5931\u8d25\"))\n      .finally(() =&gt; loading.value = false);\n}<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">13.4 PayResultView \u2014 \u652f\u4ed8\u7ed3\u679c\u67e5\u8be2<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>&lt;script setup&gt;\nimport { ref, onMounted } from \"vue\";\nimport { useRoute, useRouter } from \"vue-router\";\nimport { ElMessage } from \"element-plus\";\nimport orderApi from \"@\/api\/orderApi.js\";\nimport { CircleCheck, Clock } from \"@element-plus\/icons-vue\";\n\nconst route = useRoute();\nconst router = useRouter();\nconst loading = ref(true);\nconst paid = ref(false);\nconst orderInfo = ref(null);\n\n\/**\n * \u652f\u4ed8\u5b9d\u8df3\u56de\u6765\u65f6\uff0cURL\u662f\uff1a\n * http:\/\/www.dxkua.cn\/#\/user\/payResult?out_trade_no=1876543210987654321\n * \n * route.query.out_trade_no \u5c31\u662f\u8ba2\u5355\u53f7\n * \n * \u8c03\/order\/query\/{id} \u2192 \u540e\u7aef\u4e3b\u52a8\u67e5\u652f\u4ed8\u5b9d \u2192 \u5982\u679c\u652f\u4ed8\u6210\u529f\u540c\u6b65\u72b6\u6001\n *\/\nonMounted(() =&gt; {\n    const orderId = route.query.out_trade_no;\n    if (!orderId) { loading.value = false; return; }\n\n    orderApi.queryStatus(orderId).then(resp =&gt; {\n        if (resp.code === 200) {\n            orderInfo.value = resp.data;\n            paid.value = resp.data &amp;&amp; resp.data.status === 1;\n        }\n    }).catch(() =&gt; ElMessage.error(\"\u67e5\u8be2\u652f\u4ed8\u72b6\u6001\u5931\u8d25\"))\n      .finally(() =&gt; loading.value = false);\n});\n&lt;\/script&gt;<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">14. nginx\u53cd\u5411\u4ee3\u7406<\/h2>\n\n\n<pre class=\"wp-block-code\"><code># \u6587\u4ef6\uff1anginx\/conf\/nginx.conf\n\n# worker_processes = nginx\u7684\u5de5\u4f5c\u8fdb\u7a0b\u6570\uff08\u901a\u5e38\u8bbe\u4e3aCPU\u6838\u5fc3\u6570\uff09\nworker_processes 1;\n\nevents {\n    worker_connections 1024;  # \u6bcf\u4e2a\u5de5\u4f5c\u8fdb\u7a0b\u5141\u8bb8\u7684\u6700\u5927\u5e76\u53d1\u8fde\u63a5\u6570\n}\n\nhttp {\n    include mime.types;       # \u5305\u542bMIME\u7c7b\u578b\u6620\u5c04\uff08\u544a\u8bc9\u6d4f\u89c8\u5668\u6587\u4ef6\u662f\u4ec0\u4e48\u7c7b\u578b\uff09\n    default_type application\/octet-stream;\n    sendfile on;\n    keepalive_timeout 65;\n\n    server {\n        listen 80;            # \u76d1\u542cHTTP\u9ed8\u8ba4\u7aef\u53e3\n        server_name localhost;\n\n        # \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n        # \u6bcf\u4e2a location \u5757 = \u4e00\u6761\u8f6c\u53d1\u89c4\u5219\n        # \u683c\u5f0f\uff1alocation \/\u8def\u5f84\u524d\u7f00 { proxy_pass \u540e\u7aef\u5730\u5740; }\n        # \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n        location \/category {\n            proxy_pass http:\/\/localhost:8090;\n            # proxy_pass \u53ea\u8f6c\u53d1\u8bf7\u6c42\uff0c\u4e0d\u4fee\u6539\u8def\u5f84\n            # \u8bf7\u6c42 \/category\/search \u2192 \u8f6c\u53d1\u5230 http:\/\/localhost:8090\/category\/search\n        }\n\n        location \/goods    { proxy_pass http:\/\/localhost:8090; }\n        location \/admin    { proxy_pass http:\/\/localhost:8091; }\n        location \/user     { proxy_pass http:\/\/localhost:8092; }\n        location \/collect  { proxy_pass http:\/\/localhost:8092; }\n        location \/addr     { proxy_pass http:\/\/localhost:8092; }  # \u2605\u65b0\u589e\n        location \/cart     { proxy_pass http:\/\/localhost:8093; }\n        location \/order    { proxy_pass http:\/\/localhost:8093; }  # \u2605\u65b0\u589e\n\n        # \u2605\u6ce8\u610f\uff1a\u5982\u679c\u56fe\u7247\u4e0a\u4f20\u5230\u672c\u5730\u76ee\u5f55\uff0c\u8fd8\u9700\u8981\u914d\u7f6e\u9759\u6001\u6587\u4ef6\u8bbf\u95ee\n        # \u672c\u9879\u76ee\u56fe\u7247\u901a\u8fc7Spring Boot\u7684 ResourceHandler \u76f4\u63a5\u63d0\u4f9b\n        # \u6240\u4ee5 nginx \u4e0d\u9700\u8981\u989d\u5916\u914d\u7f6e\u56fe\u7247\u8def\u5f84\n\n        error_page 500 502 503 504 \/50x.html;\n        location = \/50x.html { root html; }\n    }\n}<\/code><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6d4b\u8bd5\u914d\u7f6e\u5e76\u91cd\u8f7d<\/strong>\uff1a<\/p>\n\n\n<pre class=\"wp-block-code\"><code>nginx -t          # \u6d4b\u8bd5\u914d\u7f6e\u6587\u4ef6\u8bed\u6cd5\u662f\u5426\u6b63\u786e\nnginx -s reload   # \u5e73\u6ed1\u91cd\u8f7d\uff08\u4e0d\u4e2d\u65ad\u73b0\u6709\u8fde\u63a5\uff09<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">15. \u652f\u4ed8\u5b9d\u652f\u4ed8<\/h2>\n\n\n<h3 class=\"wp-block-heading\">15.1 \u5b8c\u6574\u65f6\u5e8f\u56fe<\/h3>\n\n\n<pre class=\"wp-block-code\"><code>\u65f6\u95f4\u7ebf               \u7528\u6237\u6d4f\u89c8\u5668                \u524d\u7aef\u4ee3\u7801              \u540e\u7aef\u4ee3\u7801              \u652f\u4ed8\u5b9d\u670d\u52a1\u5668\n\u2500\u2500\u2500\u2500\u2500\u2500              \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500                \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500              \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500              \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nT0 \u7528\u6237\u70b9\u51fb              \u2502                       \u2502                    \u2502                    \u2502\n[\u63d0\u4ea4\u8ba2\u5355\u5e76\u652f\u4ed8]        \u2502                       \u2502                    \u2502                    \u2502\n                        \u2502                       \u2502 \u2192 submitOrder()     \u2502                    \u2502\n                        \u2502                       \u2502   POST \/order       \u2502                    \u2502\n                        \u2502                       \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192 \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502 create():           \u2502\n                        \u2502                       \u2502                    \u2502 - \u904d\u5386cartIds       \u2502\n                        \u2502                       \u2502                    \u2502 - Dubbo\u67e5\u5546\u54c1\u4fe1\u606f   \u2502\n                        \u2502                       \u2502                    \u2502 - \u6784\u9020OrderDetail   \u2502\n                        \u2502                       \u2502                    \u2502 - \u96ea\u82b1ID+items JSON  \u2502\n                        \u2502                       \u2502                    \u2502 - INSERT order      \u2502\n                        \u2502                       \u2502                    \u2502 - DELETE cart       \u2502\n                        \u2502                       \u2502   {code:200,        \u2502 \u2190 all in @Transactional\n                        \u2502                       \u2502    data:{id:\"187..\"}}\u2502                    \u2502\n                        \u2502                       \u2502 \u2190\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502                    \u2502\n                        \u2502                       \u2502 \u2192 \u94fe\u5f0f\u8c03\u7528pay       \u2502                    \u2502\n                        \u2502                       \u2502   GET \/order\/pay\/   \u2502                    \u2502\n                        \u2502                       \u2502   {id}              \u2502                    \u2502\n                        \u2502                       \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192 \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502 pay():              \u2502\n                        \u2502                       \u2502                    \u2502 - \u6821\u9a8c\u5f52\u5c5e+status=0 \u2502\n                        \u2502                       \u2502                    \u2502 - fillDetailAndPrice\u2502\n                        \u2502                       \u2502                    \u2502 - \u6784\u9020bizContent    \u2502\n                        \u2502                       \u2502                    \u2502 - pageExecute()     \u2502\n                        \u2502                       \u2502   {code:200,        \u2502   \u2192 Alipay API     \u2502\n                        \u2502                       \u2502    data:\"&lt;form...&gt;\"}\u2502 \u2190 HTML\u8868\u5355\u5b57\u7b26\u4e32    \u2502\n                        \u2502                       \u2502 \u2190\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502                    \u2502\n                        \u2502                       \u2502 submitAlipayForm()   \u2502                    \u2502\n                        \u2502                       \u2502 - \u521b\u5efa\u9690\u85cfdiv       \u2502                    \u2502\n                        \u2502                       \u2502 - innerHTML=\u8868\u5355   \u2502                    \u2502\n                        \u2502                       \u2502 - form.submit()     \u2502                    \u2502\n                        \u2502                       \u2502 \u2193                  \u2502                    \u2502\n                        \u2502 \u6d4f\u89c8\u5668\u8df3\u8f6c\u5230\u652f\u4ed8\u5b9d     \u2502                    \u2502                    \u2502\n                        \u2502 \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2192 \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502                    \u2502 \u652f\u4ed8\u5b9d\u6c99\u7bb1\u9875\u9762\n                        \u2502                       \u2502                    \u2502                    \u2502 \u7528\u6237\u8f93\u5165\u8d26\u53f7\u5bc6\u7801\nT1 \u7528\u6237\u5728\u652f\u4ed8\u5b9d\u4ed8\u6b3e     \u2502                       \u2502                    \u2502                    \u2502 \u786e\u8ba4\u652f\u4ed8\n                        \u2502                       \u2502                    \u2502                    \u2502\n                        \u2502                       \u2502                    \u2502                    \u2502 \u6263\u6b3e\u6210\u529f\uff01\n                        \u2502                       \u2502                    \u2502                    \u2502\nT2 \u53cc\u901a\u9053\u901a\u77e5           \u2502                       \u2502                    \u2502                    \u2502\n   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u540c\u6b65\u901a\u9053 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n   \u2502 \u6d4f\u89c8\u5668\u88ab\u91cd\u5b9a\u5411\u5230    \u2502                       \u2502                    \u2502      \u2502 GET returnUrl\n   \u2502 \/#\/user\/payResult   \u2502                       \u2502                    \u2502      \u2502 ?out_trade_no=xxx\n   \u2502 ?out_trade_no=xxx   \u2502                       \u2502                    \u2502      \u2502\n   \u2502                      \u2502 PayResultView\u6302\u8f7d     \u2502                    \u2502      \u2502\n   \u2502                      \u2502 GET \/order\/query\/{id} \u2502                    \u2502      \u2502\n   \u2502                      \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192                    \u2502      \u2502\n   \u2502                      \u2502                      \u2502 queryAndUpdate()    \u2502      \u2502\n   \u2502                      \u2502                      \u2502 - \u8c03\u652f\u4ed8\u5b9d\u67e5\u8be2\u63a5\u53e3  \u2502      \u2502\n   \u2502                      \u2502                      \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192\u2502      \u2502\n   \u2502                      \u2502                      \u2502 \u2190 TRADE_SUCCESS \u2500\u2500\u2500\u2502      \u2502\n   \u2502                      \u2502                      \u2502 - markPaid(id)      \u2502      \u2502\n   \u2502                      \u2502                      \u2502   UPDATE status=1   \u2502      \u2502\n   \u2502                      \u2502                      \u2502   \u6263\u5e93\u5b58(\u5c3d\u529b\u800c\u4e3a)   \u2502      \u2502\n   \u2502                      \u2502 {code:200,            \u2502                    \u2502      \u2502\n   \u2502                      \u2502  data:{status:1,..}} \u2502                    \u2502      \u2502\n   \u2502                      \u2502 \u2190\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500                      \u2502      \u2502\n   \u2502                      \u2502 \u663e\u793a\"\u652f\u4ed8\u6210\u529f\"        \u2502                    \u2502      \u2502\n   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n   \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u5f02\u6b65\u901a\u9053 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n   \u2502                      \u2502                       \u2502                    \u2502 POST notifyUrl    \u2502\n   \u2502                      \u2502                       \u2502 \u2190 \/order\/notify \u2500\u2500\u2502                   \u2502\n   \u2502                      \u2502                       \u2502 rsaCheckV1\u9a8c\u7b7e    \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 TRADE_SUCCESS     \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 markPaid(id)      \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 \u5e42\u7b49\u68c0\u67e5:status=1  \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 \u2192 \u5df2\u5904\u7406\u8fc7, return \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 response=\"success\" \u2502                   \u2502\n   \u2502                      \u2502                       \u2502 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2192\u2502                   \u2502\n   \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\">15.2 \u53cc\u901a\u9053\u7684\u5fc5\u8981\u6027<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u901a\u9053<\/th>\n<th>\u89e6\u53d1\u65b9<\/th>\n<th>\u53ef\u9760\u6027<\/th>\n<th>\u5931\u8d25\u5904\u7406<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><strong>\u540c\u6b65<\/strong>\uff08returnUrl\uff09<\/td>\n<td>\u7528\u6237\u6d4f\u89c8\u5668GET<\/td>\n<td>\u4e0d\u53ef\u9760\uff08\u7528\u6237\u53ef\u80fd\u4ed8\u6b3e\u540e\u7acb\u523b\u5173\u95ed\u9875\u9762\uff09<\/td>\n<td><code>queryAndUpdate<\/code>\u4e3b\u52a8\u67e5\u652f\u4ed8\u5b9d<\/td>\n<\/tr>\n<tr>\n<td><strong>\u5f02\u6b65<\/strong>\uff08notifyUrl\uff09<\/td>\n<td>\u652f\u4ed8\u5b9d\u670d\u52a1\u5668POST<\/td>\n<td>\u8f83\u53ef\u9760\uff08\u652f\u4ed8\u5b9d\u4f1a\u91cd\u8bd5\uff09<\/td>\n<td>\u8fd4\u56de&#8221;failure&#8221; \u2192 \u652f\u4ed8\u5b9d\u91cd\u65b0\u53d1\u9001<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<p class=\"wp-block-paragraph\"><strong>\u4e24\u8005\u7f3a\u4e00\u4e0d\u53ef<\/strong>\uff1a<\/p>\n\n\n<ul class=\"wp-block-list\">\n\n<li>\u5982\u679c\u53ea\u6709\u540c\u6b65\u6ca1\u6709\u5f02\u6b65\uff1a\u7528\u6237\u4ed8\u6b3e\u540e\u7acb\u523b\u5173\u9875\u9762 \u2192 \u8ba2\u5355\u6c38\u8fdc\u5361\u5728&#8221;\u5f85\u4ed8\u6b3e&#8221;<\/li>\n<li>\u5982\u679c\u53ea\u6709\u5f02\u6b65\u6ca1\u6709\u540c\u6b65\uff1anotifyUrl\u53ef\u80fd\u88ab\u9632\u706b\u5899\u62e6\uff08\u672c\u5730\u5f00\u53d1\u65f6\u7edd\u5bf9\u4e0d\u53ef\u8fbe\uff09 \u2192 \u6ca1\u6709\u515c\u5e95<\/li>\n<li>\u73b0\u5728\u4e24\u8005\u90fd\u6709\uff1a\u5f02\u6b65\u662f\u4e3b\u529b\uff08\u652f\u4ed8\u5b9d\u670d\u52a1\u5668\u63a8\u9001\uff09\uff0c\u540c\u6b65\u662f\u515c\u5e95\uff08\u7528\u6237\u6d4f\u89c8\u5668\u67e5\uff09<\/li>\n\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\">15.3 AlipayConfig \u2014 \u914d\u7f6e\u8bf4\u660e<\/h3>\n\n\n<pre class=\"wp-block-code\"><code># \u6587\u4ef6\uff1aorder_service\/...\/application.yml\n\nalipay:\n  # \u5e94\u7528ID\uff08\u5728\u652f\u4ed8\u5b9d\u5f00\u653e\u5e73\u53f0\/\u6c99\u7bb1\u63a7\u5236\u53f0\u83b7\u53d6\uff09\n  appId: ${ALIPAY_APP_ID:}\n  # \u2191 ${KEY:\u9ed8\u8ba4\u503c} = \u5148\u8bfb\u73af\u5883\u53d8\u91cfKEY\uff0c\u6ca1\u6709\u5219\u4f7f\u7528\u9ed8\u8ba4\u503c\n\n  # \u5e94\u7528\u79c1\u94a5\uff08\u7528\u4e8e\u7b7e\u540d\u8bf7\u6c42\uff09\u2014 \u2605\u7edd\u4e0d\u80fd\u5199\u6b7b\u5728\u8fd9\u91cc\uff0c\u5fc5\u987b\u73af\u5883\u53d8\u91cf\u6ce8\u5165\n  privateKey: ${ALIPAY_PRIVATE_KEY:}\n\n  # \u652f\u4ed8\u5b9d\u516c\u94a5\uff08\u7528\u4e8e\u9a8c\u8bc1\u652f\u4ed8\u5b9d\u8fd4\u56de\u7684\u7b7e\u540d\uff09\n  publicKey: ${ALIPAY_PUBLIC_KEY:}\n\n  # \u6c99\u7bb1\u7f51\u5173\uff08\u6b63\u5f0f\u73af\u5883\u6362\u6210 https:\/\/openapi.alipay.com\/gateway.do\uff09\n  gateway: ${ALIPAY_GATEWAY:https:\/\/openapi-sandbox.dl.alipaydev.com\/gateway.do}\n\n  # \u7b7e\u540d\u7b97\u6cd5\uff08RSA2=\u4f7f\u7528SHA-256\u7684RSA\u7b7e\u540d\uff09\n  signType: RSA2\n\n  # \u652f\u4ed8\u5b8c\u6210\u540e\u6d4f\u89c8\u5668\u8df3\u56de\u7684\u524d\u7aefURL\n  returnUrl: ${ALIPAY_RETURN_URL:http:\/\/www.dxkua.cn\/#\/user\/payResult}\n\n  # \u652f\u4ed8\u5b8c\u6210\u540e\u652f\u4ed8\u5b9d\u670d\u52a1\u5668POST\u7684\u540e\u7aefURL\n  notifyUrl: ${ALIPAY_NOTIFY_URL:http:\/\/www.dxkua.cn\/order\/notify}<\/code><\/pre>\n\n\n<pre class=\"wp-block-code\"><code>\/\/ \u6587\u4ef6\uff1aorder_service\/...\/config\/AlipayConfig.java\n\n@Data\n@Configuration\n@ConfigurationProperties(prefix = \"alipay\")\npublic class AlipayConfig {\n    private String appId;       \/\/ \u2190 Spring\u81ea\u52a8\u4eceyml\u7684 alipay.app-id \u8bfb\u53d6\n    private String privateKey;  \/\/ \u2190 \u81ea\u52a8\u4ece alipay.private-key \u8bfb\u53d6\n    private String publicKey;   \/\/ \u2190 kebab-case \u2194 camelCase \u81ea\u52a8\u8f6c\u6362\n    private String gateway;\n    private String signType = \"RSA2\";  \/\/ \u2190 \u9ed8\u8ba4\u503c\uff1a\u5982\u679cyml\u6ca1\u914d\u5c31\u7528RSA2\n    private String returnUrl;\n    private String notifyUrl;\n\n    @Bean\n    public AlipayClient alipayClient() {\n        \/\/ DefaultAlipayClient\u662f\u652f\u4ed8\u5b9dSDK\u7684\u6838\u5fc3\u7c7b\n        return new DefaultAlipayClient(\n            gateway,       \/\/ \u652f\u4ed8\u5b9d\u7f51\u5173\u5730\u5740\n            appId,         \/\/ \u5e94\u7528ID\n            privateKey,    \/\/ \u5e94\u7528\u79c1\u94a5\uff08\u7528\u4e8e\u7b7e\u540d\uff09\n            \"json\",        \/\/ \u8bf7\u6c42\u683c\u5f0f\n            \"UTF-8\",       \/\/ \u5b57\u7b26\u7f16\u7801\n            publicKey,     \/\/ \u652f\u4ed8\u5b9d\u516c\u94a5\uff08\u7528\u4e8e\u9a8c\u7b7e\uff09\n            signType       \/\/ \u7b7e\u540d\u7b97\u6cd5\n        );\n    }\n}<\/code><\/pre>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">16. API\u8def\u7531\u5168\u8868<\/h2>\n\n\n<h3 class=\"wp-block-heading\">admin_service (8091 \u2192 nginx \/admin)<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u65b9\u6cd5<\/th>\n<th>\u8def\u5f84<\/th>\n<th>\u8bf4\u660e<\/th>\n<th>\u767b\u5f55\u8981\u6c42<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GET<\/td>\n<td><code>\/admin\/captcha<\/code><\/td>\n<td>\u83b7\u53d6\u56fe\u5f62\u9a8c\u8bc1\u7801<\/td>\n<td>\u5426<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/admin\/login<\/code><\/td>\n<td>\u7ba1\u7406\u5458\u767b\u5f55<\/td>\n<td>\u5426<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/admin\/info<\/code><\/td>\n<td>\u83b7\u53d6\u5f53\u524d\u7ba1\u7406\u5458\u4fe1\u606f<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/admin\/chgPwd<\/code><\/td>\n<td>\u4fee\u6539\u5bc6\u7801<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/admin\/chgInfo<\/code><\/td>\n<td>\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/admin\/search<\/code><\/td>\n<td>\u641c\u7d22\u7ba1\u7406\u5458\u5217\u8868<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/admin<\/code><\/td>\n<td>\u65b0\u589e\u7ba1\u7406\u5458<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/admin<\/code><\/td>\n<td>\u4fee\u6539\u7ba1\u7406\u5458<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/admin\/{id}<\/code><\/td>\n<td>\u5220\u9664\u7ba1\u7406\u5458<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/admin\/{id}<\/code><\/td>\n<td>\u67e5\u5355\u6761\u7ba1\u7406\u5458<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/admin\/dashboard<\/code><\/td>\n<td>\u4eea\u8868\u76d8\u7edf\u8ba1(\u603b\u6570\/\u4eca\u65e5\/\u72b6\u6001\u5206\u5e03\/\u6700\u8fd1\u8bb0\u5f55)<\/td>\n<td>\u662f<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">user_service (8092 \u2192 nginx \/user, \/collect, \/addr)<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u65b9\u6cd5<\/th>\n<th>\u8def\u5f84<\/th>\n<th>\u8bf4\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GET<\/td>\n<td><code>\/user\/captcha<\/code><\/td>\n<td>\u56fe\u5f62\u9a8c\u8bc1\u7801<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/user\/login<\/code><\/td>\n<td>\u7528\u6237\u767b\u5f55<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/user\/reg<\/code><\/td>\n<td>\u6ce8\u518c<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/user\/info<\/code><\/td>\n<td>\u5f53\u524d\u7528\u6237\u4fe1\u606f<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/user\/chgPwd<\/code><\/td>\n<td>\u4fee\u6539\u5bc6\u7801<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/user\/chgInfo<\/code><\/td>\n<td>\u4fee\u6539\u4e2a\u4eba\u4fe1\u606f<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/user\/search<\/code><\/td>\n<td>\u540e\u53f0\u641c\u7d22\u7528\u6237<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/user\/status<\/code><\/td>\n<td>\u6539\u72b6\u6001(\u540e\u53f0)<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/user\/{id}<\/code><\/td>\n<td>\u5220\u9664\u7528\u6237(\u540e\u53f0)<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/collect\/{goodsId}<\/code><\/td>\n<td>\u6536\u85cf\u5546\u54c1<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/collect\/{id}<\/code><\/td>\n<td>\u53d6\u6d88\u6536\u85cf<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/collect\/{goodsId}<\/code><\/td>\n<td>\u67e5\u662f\u5426\u5df2\u6536\u85cf<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/collect\/list<\/code><\/td>\n<td>\u5206\u9875\u6536\u85cf\u5217\u8868<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/addr<\/code><\/td>\n<td>\u5730\u5740\u5217\u8868<\/td>\n<\/tr>\n<tr>\n<td>\u2605POST<\/td>\n<td><code>\/addr<\/code><\/td>\n<td>\u65b0\u589e\u5730\u5740<\/td>\n<\/tr>\n<tr>\n<td>\u2605PUT<\/td>\n<td><code>\/addr<\/code><\/td>\n<td>\u4fee\u6539\u5730\u5740<\/td>\n<\/tr>\n<tr>\n<td>\u2605DELETE<\/td>\n<td><code>\/addr\/{id}<\/code><\/td>\n<td>\u5220\u9664\u5730\u5740<\/td>\n<\/tr>\n<tr>\n<td>\u2605PUT<\/td>\n<td><code>\/addr\/default\/{id}<\/code><\/td>\n<td>\u8bbe\u4e3a\u9ed8\u8ba4<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/addr\/{id}<\/code><\/td>\n<td>\u67e5\u5355\u6761<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">goods_service (8090 \u2192 nginx \/goods, \/category)<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u65b9\u6cd5<\/th>\n<th>\u8def\u5f84<\/th>\n<th>\u8bf4\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>GET<\/td>\n<td><code>\/category\/search<\/code><\/td>\n<td>\u5206\u9875\u5206\u7c7b\u5217\u8868<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/category\/allParent<\/code><\/td>\n<td>\u67e5\u6240\u6709\u7236\u5206\u7c7b(\u7ea7\u8054\u9009\u62e9\u5668\u7528)<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/category\/{id}<\/code><\/td>\n<td>\u67e5\u5355\u6761<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/category<\/code><\/td>\n<td>\u65b0\u589e<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/category<\/code><\/td>\n<td>\u4fee\u6539<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/category\/{id}<\/code><\/td>\n<td>\u5220\u9664<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/goods<\/code><\/td>\n<td>\u5206\u9875\u5546\u54c1\u5217\u8868<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/goods\/search<\/code><\/td>\n<td>\u641c\u7d22\u5546\u54c1(\u542b\u5b50\u5206\u7c7b)<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/goods\/{id}<\/code><\/td>\n<td>\u67e5\u5355\u6761(\u542b\u5206\u7c7b+\u56fe\u7247)<\/td>\n<\/tr>\n<tr>\n<td>POST<\/td>\n<td><code>\/goods<\/code><\/td>\n<td>\u65b0\u589e(\u542b\u56fe\u7247\u4e0a\u4f20)<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/goods<\/code><\/td>\n<td>\u4fee\u6539<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/goods\/{id}<\/code><\/td>\n<td>\u5220\u9664<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">order_service (8093 \u2192 nginx \/cart, \/order)<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u65b9\u6cd5<\/th>\n<th>\u8def\u5f84<\/th>\n<th>\u8bf4\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>POST<\/td>\n<td><code>\/cart\/{goodsId}<\/code><\/td>\n<td>\u52a0\u5165\u8d2d\u7269\u8f66<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/cart<\/code><\/td>\n<td>\u8d2d\u7269\u8f66\u5217\u8868(\u542b\u5546\u54c1\u8be6\u60c5)<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/cart<\/code><\/td>\n<td>\u4fee\u6539\u8d2d\u7269\u8f66\u6570\u91cf<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/cart\/{id}<\/code><\/td>\n<td>\u5220\u5355\u6761<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/cart<\/code><\/td>\n<td>\u6279\u91cf\u5220\u9664(body\u4f20ids)<\/td>\n<\/tr>\n<tr>\n<td>\u2605POST<\/td>\n<td><code>\/order<\/code><\/td>\n<td>\u8d2d\u7269\u8f66\u7ed3\u7b97\u4e0b\u5355<\/td>\n<\/tr>\n<tr>\n<td>\u2605POST<\/td>\n<td><code>\/order\/direct<\/code><\/td>\n<td>\u76f4\u63a5\u8d2d\u4e70\u4e0b\u5355<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/order\/pay\/{id}<\/code><\/td>\n<td>\u83b7\u53d6\u652f\u4ed8\u5b9d\u652f\u4ed8\u8868\u5355HTML<\/td>\n<\/tr>\n<tr>\n<td>\u2605POST<\/td>\n<td><code>\/order\/notify<\/code><\/td>\n<td>\u652f\u4ed8\u5b9d\u5f02\u6b65\u56de\u8c03(\u8fd4\u56de\u7eaf\u6587\u672c)<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/order\/query\/{id}<\/code><\/td>\n<td>\u67e5\u652f\u4ed8\u72b6\u6001+\u540c\u6b65(\u7cbe\u7b80\u8fd4\u56de)<\/td>\n<\/tr>\n<tr>\n<td>\u2605PUT<\/td>\n<td><code>\/order\/cancel\/{id}<\/code><\/td>\n<td>\u7528\u6237\u53d6\u6d88\u8ba2\u5355(\u6821\u9a8c\u5f52\u5c5e)<\/td>\n<\/tr>\n<tr>\n<td>\u2605GET<\/td>\n<td><code>\/order\/myOrders<\/code><\/td>\n<td>\u7528\u6237\u8ba2\u5355\u5217\u8868<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/order\/search<\/code><\/td>\n<td>\u540e\u53f0\u641c\u7d22(\u7ba1\u7406\u5458)<\/td>\n<\/tr>\n<tr>\n<td>GET<\/td>\n<td><code>\/order\/{id}<\/code><\/td>\n<td>\u67e5\u5355\u6761(\u542bitems\u89e3\u6790)<\/td>\n<\/tr>\n<tr>\n<td>PUT<\/td>\n<td><code>\/order\/status<\/code><\/td>\n<td>\u540e\u53f0\u6539\u72b6\u6001(\u7ba1\u7406\u5458)<\/td>\n<\/tr>\n<tr>\n<td>DELETE<\/td>\n<td><code>\/order\/{id}<\/code><\/td>\n<td>\u540e\u53f0\u5220\u9664(\u7ba1\u7406\u5458)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">17. Bug\u4fee\u6b63\u8bb0\u5f55<\/h2>\n\n\n<h3 class=\"wp-block-heading\">P0: \u5fc5\u987b\u7acb\u5373\u4fee\u590d\uff08\u5bfc\u81f4\u6570\u636e\u9519\u8bef\u6216\u529f\u80fd\u5b8c\u5168\u4e0d\u53ef\u7528\uff09<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>#<\/th>\n<th>\u95ee\u9898<\/th>\n<th>\u75c7\u72b6<\/th>\n<th>\u6839\u56e0<\/th>\n<th>\u4fee\u590d<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>B01<\/td>\n<td>Long\u7cbe\u5ea6\u4e22\u5931<\/td>\n<td>\u4e0b\u5355\u8fd4\u56de\u7684id\u548c\u652f\u4ed8\u65f6\u4f20\u7684id\u5bf9\u4e0d\u4e0a\u2192&#8221;\u8ba2\u5355\u4e0d\u5b58\u5728&#8221;<\/td>\n<td>JS Number\u6700\u5927\u5b89\u5168\u6574\u65709e15\uff0816\u4f4d\uff09\uff0c\u96ea\u82b1ID\u4e3a19\u4f4d\u3002Jackson\u9ed8\u8ba4Long\u2192Number<\/td>\n<td>\u5168\u5c40JacksonConfig\uff1a\u6240\u6709Long\u5e8f\u5217\u5316\u4e3aString<\/td>\n<\/tr>\n<tr>\n<td>B02<\/td>\n<td>\u5bc6\u94a5\u786c\u7f16\u7801<\/td>\n<td>\u79c1\u94a5\u5b8c\u6574\u5199\u8fdbyml\u5e76\u63a8\u5165Git<\/td>\n<td>\u9ed8\u8ba4\u503c\u5199\u4e86\u5b8c\u6574\u79c1\u94a5<\/td>\n<td>\u6e05\u7a7a\u9ed8\u8ba4\u503c\u2192\u73af\u5883\u53d8\u91cf\u6ce8\u5165<\/td>\n<\/tr>\n<tr>\n<td>B03<\/td>\n<td>\u8d85\u5356<\/td>\n<td>\u591a\u7528\u6237\u4ed8\u4e86\u94b1\u6ca1\u8d27\uff08\u94b1\u5df2\u6263\u5e93\u5b58\u4e0d\u591f\uff09<\/td>\n<td>\u4e0b\u5355\u53ea\u68c0\u67e5\u4e0d\u6539\u5e93\u5b58 + \u4ed8\u6b3e\u540e\u6263\u5931\u8d25\u53ea\u8bb0log<\/td>\n<td>markPaid\u5148\u6539status=1\u518d\u6263\u5e93\u5b58\uff08\u5c3d\u529b\u800c\u4e3a+\u65e5\u5fd7\uff09<\/td>\n<\/tr>\n<tr>\n<td>B04<\/td>\n<td>AdminView status\u9519\u8bef<\/td>\n<td>\u6dfb\u52a0\u7ba1\u7406\u5458\u540e\u5f39\u7a97\u91cc\u9ed8\u8ba4\u663e\u793a&#8221;\u7981\u7528&#8221;<\/td>\n<td>\u4ee3\u7801\u5199\u6b7b<code>status:1<\/code><\/td>\n<td>\u6539\u4e3a<code>status:0<\/code><\/td>\n<\/tr>\n<tr>\n<td>B05<\/td>\n<td>Collect.java\u5b57\u6bb5\u7c7b\u578b\u9519\u8bef<\/td>\n<td>goods\u5b57\u6bb5\u662fDate\u7c7b\u578b<\/td>\n<td>\u5e94\u8be5\u662fGoods\u5bf9\u8c61<\/td>\n<td>\u6539\u4e3a<code>private Goods goods<\/code><\/td>\n<\/tr>\n<tr>\n<td>B06<\/td>\n<td>CollectMapper\u8de8\u6a21\u5757\u5f15\u7528<\/td>\n<td>\u67e5\u8be2\u6536\u85cf\u5217\u8868\u62a5\u9519<\/td>\n<td>user_service\u5f15\u7528\u4e86goods_service\u7684mapper<\/td>\n<td>\u6539LEFT JOIN\u4e00\u6b21\u6027\u67e5\u8be2<\/td>\n<\/tr>\n<tr>\n<td>B07<\/td>\n<td>\u652f\u4ed8\u53d1\u8d77\u540c\u65f6\u5f39\u51fa\u4e24\u6761\u6d88\u606f<\/td>\n<td>&#8220;\u4e0b\u5355\u6210\u529f&#8221;+&#8221;\u652f\u4ed8\u53d1\u8d77\u5931\u8d25&#8221;\u540c\u65f6\u51fa\u73b0<\/td>\n<td>create\u6210\u529f\u65f6\u7acb\u5373\u5f39success\u2192goPay\u5931\u8d25\u5f39error<\/td>\n<td>\u4e32\u6210\u94fe\uff1acreate\u4e0d\u5f39\u2192pay\u6210\u529f\u8df3\u8f6c\u2192\u5931\u8d25\u5f39\u4e00\u6761<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">P1: \u91cd\u8981\uff08\u5f71\u54cd\u529f\u80fd\u53ef\u7528\u6027\u6216\u5b89\u5168\uff09<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>#<\/th>\n<th>\u95ee\u9898<\/th>\n<th>\u4fee\u590d<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>B08<\/td>\n<td>returnUrl\/notifyUrl\u5199\u6b7blocalhost<\/td>\n<td>\u6539\u4e3a\u516c\u7f51IP <code>www.dxkua.cn<\/code><\/td>\n<\/tr>\n<tr>\n<td>B09<\/td>\n<td>notify\u957f\u4e8b\u52a1\u5305Dubbo<\/td>\n<td>\u53bb\u6389<code>@Transactional<\/code>\uff08\u5355UPDATE\u5df2\u539f\u5b50\uff09<\/td>\n<\/tr>\n<tr>\n<td>B10<\/td>\n<td>\/query\/{id}\u65e0\u9274\u6743<\/td>\n<td>\u8fd4\u56de\u7cbe\u7b80summary\uff08\u4ec5id\/status\/totalPrice\uff09<\/td>\n<\/tr>\n<tr>\n<td>B11<\/td>\n<td>\u7528\u6237\u53ef\u53d6\u6d88\u522b\u4eba\u8ba2\u5355<\/td>\n<td>\u65b0\u5efa<code>\/cancel\/{id}<\/code>\u7aef\u70b9\uff08\u5f52\u5c5e\u4e09\u8fde\u67e5\uff09<\/td>\n<\/tr>\n<tr>\n<td>B12<\/td>\n<td>nginx\u7f3a\/addr\u548c\/order<\/td>\n<td>\u65b0\u589e\u4e24\u4e2alocation\u5757\u2192<code>nginx -s reload<\/code><\/td>\n<\/tr>\n<tr>\n<td>B13<\/td>\n<td>AlipayClient\u65e0\u8d85\u65f6<\/td>\n<td>\u5efa\u8bae\u540e\u7eed\u52a0\uff08\u672c\u6b21\u672a\u4fee\uff09<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">P2: \u4e00\u822c\uff08\u529f\u80fd\u53ef\u7528\u4f46\u4e0d\u5b8c\u5584\uff09<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>#<\/th>\n<th>\u95ee\u9898<\/th>\n<th>\u4fee\u590d<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>B14<\/td>\n<td>document.write\u6e05\u7a7aSPA<\/td>\n<td>\u6539\u4e3asubmitAlipayForm\uff08\u9690\u85cfform\u63d0\u4ea4\uff09<\/td>\n<\/tr>\n<tr>\n<td>B15<\/td>\n<td>\u624b\u62fcJSON\u5b57\u7b26\u4e32<\/td>\n<td>\u6539\u4e3aHutool JSONObject\u6784\u9020<\/td>\n<\/tr>\n<tr>\n<td>B16<\/td>\n<td>\u65e0\u8d85\u65f6\u53d6\u6d88\u673a\u5236<\/td>\n<td>\u652f\u4ed8\u5b9d<code>timeout_express=30m<\/code> + <code>@Scheduled<\/code>\u672c\u5730\u53d6\u6d88<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n\n<h3 class=\"wp-block-heading\">P3: \u4f53\u9a8c\uff08\u7528\u6237\u611f\u53d7\u4e0d\u6b63\u5e38\uff09<\/h3>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>#<\/th>\n<th>\u95ee\u9898<\/th>\n<th>\u4fee\u590d<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>B17<\/td>\n<td>HomeView\u6587\u6848\u9519\u8bef<\/td>\n<td>&#8220;\u7528\u6237\u7ba1\u7406\u7ba1\u7406&#8221;\u2192&#8221;\u7528\u6237\u7ba1\u7406&#8221;\u7b49<\/td>\n<\/tr>\n<tr>\n<td>B18<\/td>\n<td>\u5220\u9664\u786e\u8ba4\u6587\u6848&#8221;\u5220\u9664\u8be5\u5458\u5de5&#8221;<\/td>\n<td>\u6539\u4e3a&#8221;\u5546\u54c1&#8221;\/&#8221;\u5206\u7c7b&#8221;\/&#8221;\u7ba1\u7406\u5458&#8221;<\/td>\n<\/tr>\n<tr>\n<td>B19<\/td>\n<td>\u641c\u7d22\u6846\u6bcf\u5b57\u53d1\u8bf7\u6c42<\/td>\n<td><code>@input<\/code>\u2192<code>@keyup.enter<\/code>+<code>@clear<\/code><\/td>\n<\/tr>\n<tr>\n<td>B20<\/td>\n<td>cartIds query\u89e3\u6790\u4e0d\u5065\u58ee<\/td>\n<td>\u517c\u5bb9\u6570\u7ec4\/\u5355\u5b57\u7b26\u4e32\/<code>[]<\/code>\u683c\u5f0f<\/td>\n<\/tr>\n<tr>\n<td>B21<\/td>\n<td>parameterType\u522b\u540d\u9519\u8bef<\/td>\n<td><code>collection<\/code>\u2192<code>collect<\/code><\/td>\n<\/tr>\n<tr>\n<td>B22<\/td>\n<td>PayResultView\u56fe\u6807\u65e0import<\/td>\n<td>\u52a0<code>CircleCheck,Clock<\/code> import<\/td>\n<\/tr>\n<tr>\n<td>B23<\/td>\n<td>\u4eea\u8868\u76d8\u6570\u636e\u5168\u91cf\u8986\u76d6<\/td>\n<td>\u9010\u5b57\u6bb5\u5b89\u5168\u5408\u5e76+Object.assign<\/td>\n<\/tr>\n<tr>\n<td>B24<\/td>\n<td>\u4eea\u8868\u76d8\u65e0loading<\/td>\n<td>\u52a0<code>v-loading<\/code><\/td>\n<\/tr>\n<tr>\n<td>B25<\/td>\n<td>recentOrders\u67e5o.*<\/td>\n<td>\u6539\u67e55\u4e2a\u5b57\u6bb5\u4e0d\u67e5items<\/td>\n<\/tr>\n<tr>\n<td>B26<\/td>\n<td>\u4eca\u65e5\u9500\u552e\u989d\u7edf\u8ba1\u542b\u5f85\u4ed8\u6b3e<\/td>\n<td><code>status IN(1,2,3)<\/code><\/td>\n<\/tr>\n<tr>\n<td>B27<\/td>\n<td>chgPwd\u8bef\u5efa\u65b0ref<\/td>\n<td><code>chgPwdobj.value = {...}<\/code><\/td>\n<\/tr>\n<tr>\n<td>B28<\/td>\n<td>\u5404\u670d\u52a1JWT\u62e6\u622a\u5668\u672a\u8986\u76d6\u65b0\u589e<\/td>\n<td>\u4e0d\u62e6\u622a\u4f46Controller\u624b\u52a8token\u6821\u9a8c<\/td>\n<\/tr>\n<tr>\n<td>B29<\/td>\n<td>Admin\/User\/OrderView\u7f3a\u5206\u9875<\/td>\n<td>\u540e\u52a0el-pagination<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n<hr \/>\n\n<h2 class=\"wp-block-heading\">18. \u672f\u8bed\u8868<\/h2>\n\n\n<figure class=\"wp-block-table\">\n<table>\n<thead>\n<tr>\n<th>\u672f\u8bed<\/th>\n<th>\u5168\u79f0<\/th>\n<th>\u89e3\u91ca<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>SPA<\/td>\n<td>Single Page Application<\/td>\n<td>\u5355\u9875\u5e94\u7528\u2014\u2014\u6d4f\u89c8\u5668\u53ea\u52a0\u8f7d\u4e00\u6b21HTML\uff0c\u540e\u7eed\u9875\u9762\u5207\u6362\u901a\u8fc7JS\u52a8\u6001\u6e32\u67d3<\/td>\n<\/tr>\n<tr>\n<td>API<\/td>\n<td>Application Programming Interface<\/td>\n<td>\u5e94\u7528\u7a0b\u5e8f\u63a5\u53e3\u2014\u2014\u524d\u7aef\u548c\u540e\u7aef\u7ea6\u5b9a\u597d\u7684&#8221;\u51fd\u6570\u8c03\u7528&#8221;\u89c4\u5219<\/td>\n<\/tr>\n<tr>\n<td>JSON<\/td>\n<td>JavaScript Object Notation<\/td>\n<td>\u4e00\u79cd\u8f7b\u91cf\u7ea7\u7684\u6570\u636e\u4ea4\u6362\u683c\u5f0f\uff0c\u524d\u7aef\u540e\u7aef\u90fd\u8bfb\u5f97\u61c2<\/td>\n<\/tr>\n<tr>\n<td>REST<\/td>\n<td>Representational State Transfer<\/td>\n<td>\u4e00\u79cdAPI\u8bbe\u8ba1\u98ce\u683c\uff1a\u7528HTTP\u65b9\u6cd5(GET\/POST\/PUT\/DELETE)\u8868\u8fbe\u64cd\u4f5c\u610f\u56fe<\/td>\n<\/tr>\n<tr>\n<td>ORM<\/td>\n<td>Object-Relational Mapping<\/td>\n<td>\u5bf9\u8c61\u5173\u7cfb\u6620\u5c04\u2014\u2014\u628a\u6570\u636e\u5e93\u7684\u884c\u81ea\u52a8\u8f6c\u6210Java\u5bf9\u8c61<\/td>\n<\/tr>\n<tr>\n<td>JWT<\/td>\n<td>JSON Web Token<\/td>\n<td>\u4e00\u79cd\u65e0\u72b6\u6001\u7684\u8eab\u4efd\u8ba4\u8bc1\u4ee4\u724c\uff0c\u4e09\u6bb5Base64\u7ec4\u6210<\/td>\n<\/tr>\n<tr>\n<td>RPC<\/td>\n<td>Remote Procedure Call<\/td>\n<td>\u8fdc\u7a0b\u8fc7\u7a0b\u8c03\u7528\u2014\u2014\u50cf\u8c03\u7528\u672c\u5730\u65b9\u6cd5\u4e00\u6837\u8c03\u7528\u8fdc\u7a0b\u670d\u52a1\u7684\u65b9\u6cd5<\/td>\n<\/tr>\n<tr>\n<td>Dubbo<\/td>\n<td>&#8211;<\/td>\n<td>\u963f\u91cc\u5df4\u5df4\u5f00\u6e90\u7684Java RPC\u6846\u67b6<\/td>\n<\/tr>\n<tr>\n<td>MyBatis<\/td>\n<td>&#8211;<\/td>\n<td>Java\u7684ORM\u6846\u67b6\uff0cXML\u5199SQL+\u81ea\u52a8\u6620\u5c04<\/td>\n<\/tr>\n<tr>\n<td>Hutool<\/td>\n<td>&#8211;<\/td>\n<td>Java\u5de5\u5177\u5e93\uff0c\u63d0\u4f9b\u96ea\u82b1ID\u3001JSON\u3001MD5\u7b49\u4fbf\u6377\u65b9\u6cd5<\/td>\n<\/tr>\n<tr>\n<td>nginx<\/td>\n<td>&#8211;<\/td>\n<td>\u9ad8\u6027\u80fdHTTP\u670d\u52a1\u5668\/\u53cd\u5411\u4ee3\u7406<\/td>\n<\/tr>\n<tr>\n<td>ZooKeeper<\/td>\n<td>&#8211;<\/td>\n<td>\u5206\u5e03\u5f0f\u534f\u8c03\u670d\u52a1\uff0c\u672c\u9879\u76ee\u7528\u4e8eDubbo\u670d\u52a1\u6ce8\u518c\u53d1\u73b0<\/td>\n<\/tr>\n<tr>\n<td>Redis<\/td>\n<td>&#8211;<\/td>\n<td>\u5185\u5b58\u952e\u503c\u5b58\u50a8\uff0c\u672c\u9879\u76ee\u7528\u4e8e\u9a8c\u8bc1\u7801\u4e34\u65f6\u7f13\u5b58<\/td>\n<\/tr>\n<tr>\n<td>Maven<\/td>\n<td>&#8211;<\/td>\n<td>Java\u9879\u76ee\u7684\u6784\u5efa\u548c\u4f9d\u8d56\u7ba1\u7406\u5de5\u5177<\/td>\n<\/tr>\n<tr>\n<td>npm \/ Vite<\/td>\n<td>&#8211;<\/td>\n<td>JavaScript\u7684\u5305\u7ba1\u7406 \/ \u524d\u7aef\u6784\u5efa\u5de5\u5177<\/td>\n<\/tr>\n<tr>\n<td>EC 2<\/td>\n<td>&#8211;<\/td>\n<td>\u963f\u91cc\u4e91\u865a\u62df\u673a\u5b9e\u4f8b\uff08\u90e8\u7f72\u7528\uff09<\/td>\n<\/tr>\n<tr>\n<td>\u96ea\u82b1\u7b97\u6cd5<\/td>\n<td>Snowflake<\/td>\n<td>Twitter\u5f00\u6e90\u7684\u5206\u5e03\u5f0f\u552f\u4e00ID\u751f\u6210\u7b97\u6cd5<\/td>\n<\/tr>\n<tr>\n<td>\u5e42\u7b49<\/td>\n<td>Idempotent<\/td>\n<td>\u540c\u4e00\u4e2a\u64cd\u4f5c\u6267\u884c\u591a\u6b21\u548c\u6267\u884c\u4e00\u6b21\u7ed3\u679c\u76f8\u540c<\/td>\n<\/tr>\n<tr>\n<td>\u4e8b\u52a1<\/td>\n<td>Transaction<\/td>\n<td>\u6570\u636e\u5e93\u7684\u4e00\u7ec4\u64cd\u4f5c\u8981\u4e48\u5168\u90e8\u6210\u529f\u8981\u4e48\u5168\u90e8\u64a4\u9500<\/td>\n<\/tr>\n<tr>\n<td>Spring Boot<\/td>\n<td>&#8211;<\/td>\n<td>\u7b80\u5316Spring\u5e94\u7528\u7684\u521b\u5efa\u548c\u914d\u7f6e\u7684\u6846\u67b6<\/td>\n<\/tr>\n<tr>\n<td>Spring MVC<\/td>\n<td>&#8211;<\/td>\n<td>Spring\u7684Web\u5c42\u6846\u67b6\uff0c\u5904\u7406HTTP\u8bf7\u6c42<\/td>\n<\/tr>\n<tr>\n<td>@Autowired<\/td>\n<td>&#8211;<\/td>\n<td>Spring\u6ce8\u89e3\uff1a\u81ea\u52a8\u6ce8\u5165\u4e00\u4e2aBean<\/td>\n<\/tr>\n<tr>\n<td>@Bean<\/td>\n<td>&#8211;<\/td>\n<td>Spring\u6ce8\u89e3\uff1a\u628a\u65b9\u6cd5\u8fd4\u56de\u503c\u6ce8\u518c\u5230\u5bb9\u5668<\/td>\n<\/tr>\n<tr>\n<td>Pinia<\/td>\n<td>&#8211;<\/td>\n<td>Vue 3\u7684\u72b6\u6001\u7ba1\u7406\u5e93\uff08\u66ff\u4ee3Vuex\uff09<\/td>\n<\/tr>\n<tr>\n<td>Axios<\/td>\n<td>&#8211;<\/td>\n<td>\u6d4f\u89c8\u5668\u7aefHTTP\u8bf7\u6c42\u5e93<\/td>\n<\/tr>\n<tr>\n<td>Element Plus<\/td>\n<td>&#8211;<\/td>\n<td>Vue 3\u7684UI\u7ec4\u4ef6\u5e93\uff08\u6309\u94ae\/\u8868\u683c\/\u5bf9\u8bdd\u6846\u7b49\uff09<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/figure>\n\n<hr \/>\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n\n\n<p class=\"wp-block-paragraph\"><strong>\u6587\u6863\u7248\u672c<\/strong>\uff1a2026-07-28<br \/>\n<strong>\u76ee\u6807\u8bfb\u8005<\/strong>\uff1a\u4ece\u96f6\u57fa\u7840\u5230\u8fdb\u9636\uff0c\u9002\u5408\u8fb9\u770b\u4ee3\u7801\u8fb9\u5bf9\u7167\u6b64\u6587\u7406\u89e3\u6bcf\u4e00\u884c\u4ee3\u7801\u7684&#8221;\u4e3a\u4ec0\u4e48&#8221;\n<strong>\u9605\u8bfb\u5efa\u8bae<\/strong>\uff1a\u5148\u5728IDEA\u91cc\u6253\u5f00\u9879\u76ee\uff0c\u7136\u540e\u6309\u7ae0\u8282\u987a\u5e8f\u9605\u8bfb\uff0c\u9047\u5230\u4e0d\u61c2\u7684\u6280\u672f\u672f\u8bed\u67e5\u7b2c18\u7ae0\u672f\u8bed\u8868<\/p>\n\n\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\u9605\u8bfb\u5bf9\u8c61\uff1a\u96f6\u57fa\u7840\u5b66\u4e60\u8005\uff08\u65e0\u540e\u7aef\/\u524d\u7aef\u7ecf\u9a8c\u4e5f\u53ef\u9605\u8bfb\uff09 \u8986\u76d6\u8303\u56f4\uff1a\u9879\u76ee\u67b6\u6784\u3001\u6570\u636e\u5e93\u8bbe\u8ba1\u3001\u540e\u7aef\u5fae\u670d\u52a1\u3001\u524d\u7aefSPA\u3001\u652f [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-25","post","type-post","status-publish","format-standard","hentry","category-mall"],"_links":{"self":[{"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/posts\/25","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/comments?post=25"}],"version-history":[{"count":1,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/posts\/25\/revisions"}],"predecessor-version":[{"id":30,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/posts\/25\/revisions\/30"}],"wp:attachment":[{"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/media?parent=25"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/categories?post=25"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dxkua.cn\/index.php\/wp-json\/wp\/v2\/tags?post=25"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}