[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-VPZNSTxr":3,"public-project-articles-VPZNSTxr":17},{"id":4,"uuid":5,"project_id":6,"title":7,"content":8,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},548,"VPZNSTxr",47,"14. SpringBoot3+Vue3实现富文本编辑器功能","## wangeditor5官网\n\n[https:\u002F\u002Fwww.wangeditor.com\u002F](https:\u002F\u002Fwww.wangeditor.com\u002F)\n\n## 安装wangeditor5\n\n```javascript\nnpm install @wangeditor\u002Feditor --save\nnpm install @wangeditor\u002Feditor-for-vue@next --save\n```\n\n## 引入和使用 wangeditor5\n\n```javascript\nimport '@wangeditor\u002Feditor\u002Fdist\u002Fcss\u002Fstyle.css' \u002F\u002F 引入 css\nimport {onBeforeUnmount, ref, shallowRef} from \"vue\";\nimport { Editor, Toolbar } from '@wangeditor\u002Feditor-for-vue'\n```\n\n初始化（表单中）\n\nwangEditor 5 富文本字段可以直接和form中的字段使用v-model进行绑定\n\n```html\n\u003Cdiv style=\"border: 1px solid #ccc; width: 100%\">\n  \u003CToolbar\n      style=\"border-bottom: 1px solid #ccc\"\n      :editor=\"editorRef\"\n      :mode=\"mode\"\n  \u002F>\n  \u003CEditor\n      style=\"height: 500px; overflow-y: hidden;\"\n      v-model=\"data.form.content\"\n      :mode=\"mode\"\n      :defaultConfig=\"editorConfig\"\n      @onCreated=\"handleCreated\"\n  \u002F>\n\u003C\u002Fdiv>\n```\n\n```javascript\n\u002F* wangEditor5 初始化开始 *\u002F\nconst baseUrl = 'http:\u002F\u002Flocalhost:9090'\nconst editorRef = shallowRef()  \u002F\u002F 编辑器实例，必须用 shallowRef\nconst mode = 'default' \nconst editorConfig = { MENU_CONF: {} }\n\u002F\u002F 图片上传配置\neditorConfig.MENU_CONF['uploadImage'] = {\n  server: baseUrl + '\u002Ffiles\u002Fwang\u002Fupload',  \u002F\u002F 服务端图片上传接口\n  fieldName: 'file'  \u002F\u002F 服务端图片上传接口参数\n}\n\u002F\u002F 组件销毁时，也及时销毁编辑器，否则可能会造成内存泄漏\nonBeforeUnmount(() => {\n  const editor = editorRef.value\n  if (editor == null) return\n  editor.destroy()\n})\n\u002F\u002F 记录 editor 实例，重要！\nconst handleCreated = (editor) => {\n  editorRef.value = editor \n}\n\u002F* wangEditor5 初始化结束 *\u002F\n```\n\n## 在表格里查看富文本内容\n\n```vue\n\u003Cel-table-column label=\"内容\">\n  \u003Ctemplate #default=\"scope\">\n    \u003Cel-button type=\"primary\" @click=\"view(scope.row.content)\">查看内容\u003C\u002Fel-button>\n  \u003C\u002Ftemplate>\n\u003C\u002Fel-table-column>\n\n\u003Cel-dialog title=\"内容\" v-model=\"data.viewVisible\" width=\"50%\" :close-on-click-modal=\"false\" destroy-on-close>\n  \u003Cdiv class=\"editor-content-view\" style=\"padding: 20px\" v-html=\"data.content\">\u003C\u002Fdiv>\n  \u003Ctemplate #footer>\n    \u003Cspan class=\"dialog-footer\">\n      \u003Cel-button @click=\"data.viewVisible = false\">关 闭\u003C\u002Fel-button>\n    \u003C\u002Fspan>\n  \u003C\u002Ftemplate>\n\u003C\u002Fel-dialog>             \n\nconst view = (content) => {\n  data.content = content\n  data.viewVisible = true\n}\n\ndata: {\n  viewVisible: false,\n  content: null    \n}\n```\n\n## 富文本对应的后端文件上传接口\n\n文件上传要求按照下面的格式来 提供\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729762490894-13ea338b-ccb8-4b0f-a8f4-65d4b8b01536.png)\n\n```java\n\u002F**\n * wang-editor编辑器文件上传接口\n *\u002F\n@PostMapping(\"\u002Fwang\u002Fupload\")\npublic Map\u003CString, Object> wangEditorUpload(MultipartFile file) {\n    String originalFilename = file.getOriginalFilename();  \n    if (!FileUtil.isDirectory(filePath)) {  \n        FileUtil.mkdir(filePath);  \u002F\u002F 创建一个 files 目录\n    }\n    \u002F\u002F 提供文件存储的完整的路径\n    \u002F\u002F 给文件名 加一个唯一的标识\n    String fileName = System.currentTimeMillis() + \"_\" + originalFilename;  \u002F\u002F 156723232322_xxx.png\n    String realPath = filePath + fileName;   \u002F\u002F 完整的文件路径\n    try {\n        FileUtil.writeBytes(file.getBytes(), realPath);\n    } catch (IOException e) {\n        e.printStackTrace();\n        throw new CustomException(\"500\", \"文件上传失败\");\n    }\n    String url = \"http:\u002F\u002Flocalhost:9090\u002Ffiles\u002Fdownload\u002F\" + fileName;\n   \u002F\u002F wangEditor上传图片成功后， 需要返回的参数\n    Map\u003CString, Object> resMap = new HashMap\u003C>();\n    List\u003CMap\u003CString, Object>> list = new ArrayList\u003C>();\n    Map\u003CString, Object> urlMap = new HashMap\u003C>();\n    urlMap.put(\"url\", url);\n    list.add(urlMap);\n    resMap.put(\"errno\", 0);\n    resMap.put(\"data\", list);\n    return resMap;\n}\n```\n\n## 外部引入 view.css （可选）\n\n```css\n.editor-content-view {\n    padding: 0 10px;\n    margin-top: 20px;\n    overflow-x: auto;\n}\n\n.editor-content-view p,\n.editor-content-view li {\n    white-space: pre-wrap; \u002F* 保留空格 *\u002F\n}\n\n.editor-content-view blockquote {\n    border-left: 8px solid #d0e5f2;\n    padding: 10px 10px;\n    margin: 10px 0;\n    background-color: #f1f1f1;\n}\n\n.editor-content-view code {\n    font-family: monospace;\n    background-color: #eee;\n    padding: 3px;\n    border-radius: 3px;\n}\n.editor-content-view pre>code {\n    display: block;\n    padding: 10px;\n}\n\n.editor-content-view table {\n    border-collapse: collapse;\n}\n.editor-content-view td,\n.editor-content-view th {\n    border: 1px solid #ccc;\n    min-width: 50px;\n    height: 20px;\n}\n.editor-content-view th {\n    background-color: #f1f1f1;\n}\n\n.editor-content-view ul,\n.editor-content-view ol {\n    padding-left: 20px;\n}\n\n.editor-content-view input[type=\"checkbox\"] {\n    margin-right: 5px;\n}\n```\n\n## 新模块：文章管理\n\n### 创建数据库表article\n\n```sql\nCREATE TABLE `article` (\n  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',\n  `title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '标题',\n  `img` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '封面',\n  `description` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '简介',\n  `content` longtext COLLATE utf8mb4_unicode_ci COMMENT '内容',\n  `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '发布时间',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='文章信息';\n```\n\n### 开发后端接口\n\n先创建实体类 Article， 直接复制 Admin 相关的  controller、service、mapper、mapper.xml  做一下修改即可\n\n```java\npublic class Article {\n    private Integer id;\n    private String title;\n    private String img;\n    private String description;\n    private String content;\n    private String time;\n}\n```\n\n### 开发页面\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-input style=\"width: 240px; margin-right: 10px\" v-model=\"data.title\" placeholder=\"请输入标题查询\" prefix-icon=\"Search\">\u003C\u002Fel-input>\n      \u003Cel-button type=\"primary\" @click=\"load\">查 询\u003C\u002Fel-button>\n      \u003Cel-button type=\"warning\" @click=\"reset\">重 置\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-button type=\"primary\" @click=\"handleAdd\">新 增\u003C\u002Fel-button>\n      \u003Cel-button type=\"danger\" @click=\"delBatch\">批量删除\u003C\u002Fel-button>\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"card\" style=\"margin-bottom: 5px\">\n      \u003Cel-table :data=\"data.tableData\" stripe @selection-change=\"handleSelectionChange\">\n        \u003Cel-table-column type=\"selection\" width=\"55\" \u002F>\n        \u003Cel-table-column label=\"标题\" prop=\"title\" \u002F>\n        \u003Cel-table-column label=\"封面\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-image v-if=\"scope.row.img\" :src=\"scope.row.img\" :preview-src-list=[scope.row.img] preview-teleported style=\"display: block; width: 100px; height: 60px;\" \u002F>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"简介\" prop=\"description\" show-overflow-tooltip \u002F>\n        \u003Cel-table-column label=\"内容\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button type=\"primary\" @click=\"view(scope.row.content)\">查看内容\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n        \u003Cel-table-column label=\"发布时间\" prop=\"time\" \u002F>\n        \u003Cel-table-column label=\"操作\" width=\"120\">\n          \u003Ctemplate #default=\"scope\">\n            \u003Cel-button @click=\"handleUpdate(scope.row)\" type=\"primary\" :icon=\"Edit\" circle>\u003C\u002Fel-button>\n            \u003Cel-button @click=\"del(scope.row.id)\" type=\"danger\" :icon=\"Delete\" circle>\u003C\u002Fel-button>\n          \u003C\u002Ftemplate>\n        \u003C\u002Fel-table-column>\n      \u003C\u002Fel-table>\n      \u003Cdiv style=\"margin-top: 15px\">\n        \u003Cel-pagination\n            @size-change=\"load\"\n            @current-change=\"load\"\n            v-model:current-page=\"data.pageNum\"\n            v-model:page-size=\"data.pageSize\"\n            :page-sizes=\"[5, 10, 15, 20]\"\n            background\n            layout=\"total, sizes, prev, pager, next, jumper\"\n            :total=\"data.total\"\n        \u002F>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n    \u003Cel-dialog title=\"文章信息\" v-model=\"data.formVisible\" width=\"50%\" destroy-on-close>\n      \u003Cel-form ref=\"formRef\" :model=\"data.form\" label-width=\"80px\" style=\"padding-right: 40px; padding-top: 20px\">\n        \u003Cel-form-item label=\"标题\" prop=\"title\">\n          \u003Cel-input v-model=\"data.form.title\" autocomplete=\"off\" placeholder=\"请输入标题\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"封面\">\n          \u003Cel-upload\n              action=\"http:\u002F\u002Flocalhost:9090\u002Ffiles\u002Fupload\"\n              list-type=\"picture\"\n              :on-success=\"handleImgSuccess\"\n          >\n            \u003Cel-button type=\"primary\">上传封面\u003C\u002Fel-button>\n          \u003C\u002Fel-upload>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"简介\" prop=\"description\">\n          \u003Cel-input type=\"textarea\" :rows=\"3\" v-model=\"data.form.description\" autocomplete=\"off\" placeholder=\"请输入简介\" \u002F>\n        \u003C\u002Fel-form-item>\n        \u003Cel-form-item label=\"内容\">\n          \u003Cdiv style=\"border: 1px solid #ccc; width: 100%\">\n            \u003CToolbar\n                style=\"border-bottom: 1px solid #ccc\"\n                :editor=\"editorRef\"\n                :mode=\"mode\"\n            \u002F>\n            \u003CEditor\n                style=\"height: 500px; overflow-y: hidden;\"\n                v-model=\"data.form.content\"\n                :mode=\"mode\"\n                :defaultConfig=\"editorConfig\"\n                @onCreated=\"handleCreated\"\n            \u002F>\n          \u003C\u002Fdiv>\n        \u003C\u002Fel-form-item>\n      \u003C\u002Fel-form>\n      \u003Ctemplate #footer>\n        \u003Cdiv class=\"dialog-footer\">\n          \u003Cel-button @click=\"data.formVisible = false\">取 消\u003C\u002Fel-button>\n          \u003Cel-button type=\"primary\" @click=\"save\">保 存\u003C\u002Fel-button>\n        \u003C\u002Fdiv>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n    \u003Cel-dialog title=\"内容\" v-model=\"data.viewVisible\" width=\"50%\" :close-on-click-modal=\"false\" destroy-on-close>\n      \u003Cdiv class=\"editor-content-view\" style=\"padding: 20px\" v-html=\"data.content\">\u003C\u002Fdiv>\n      \u003Ctemplate #footer>\n    \u003Cspan class=\"dialog-footer\">\n      \u003Cel-button @click=\"data.viewVisible = false\">关 闭\u003C\u002Fel-button>\n    \u003C\u002Fspan>\n      \u003C\u002Ftemplate>\n    \u003C\u002Fel-dialog>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { reactive, ref } from \"vue\";\nimport {Edit, Delete, Search} from \"@element-plus\u002Ficons-vue\"\nimport request from \"@\u002Futils\u002Frequest.js\";\nimport {ElMessage, ElMessageBox} from \"element-plus\";\n\nimport '@wangeditor\u002Feditor\u002Fdist\u002Fcss\u002Fstyle.css' \u002F\u002F 引入 css\nimport {onBeforeUnmount, shallowRef} from \"vue\";\nimport { Editor, Toolbar } from '@wangeditor\u002Feditor-for-vue'\nimport '@\u002Fassets\u002Fview.css'\n\nconst data = reactive({\n  title: null,\n  tableData: [],\n  pageNum: 1,\n  pageSize: 10,\n  total: 0,\n  formVisible: false,\n  form: {},\n  ids: [],\n  viewVisible: false,\n  content: null\n})\n\n\u002F* wangEditor5 初始化开始 *\u002F\nconst baseUrl = 'http:\u002F\u002Flocalhost:9090'\nconst editorRef = shallowRef()  \u002F\u002F 编辑器实例，必须用 shallowRef\nconst mode = 'default'\nconst editorConfig = { MENU_CONF: {} }\n\u002F\u002F 图片上传配置\neditorConfig.MENU_CONF['uploadImage'] = {\n  server: baseUrl + '\u002Ffiles\u002Fwang\u002Fupload',  \u002F\u002F 服务端图片上传接口\n  fieldName: 'file'  \u002F\u002F 服务端图片上传接口参数\n}\n\u002F\u002F 组件销毁时，也及时销毁编辑器，否则可能会造成内存泄漏\nonBeforeUnmount(() => {\n  const editor = editorRef.value\n  if (editor == null) return\n  editor.destroy()\n})\n\u002F\u002F 记录 editor 实例，重要！\nconst handleCreated = (editor) => {\n  editorRef.value = editor\n}\n\u002F* wangEditor5 初始化结束 *\u002F\n\nconst view = (content) => {\n  data.content = content\n  data.viewVisible = true\n}\n\n\nconst load = () => {\n  request.get('\u002Farticle\u002FselectPage', { \u002F\u002F ?pageNum=1&pageSize=10\n    params: {\n      pageNum: data.pageNum,\n      pageSize: data.pageSize,\n      name: data.name\n    }\n  }).then(res => {\n    data.tableData = res.data.list\n    data.total = res.data.total\n  })\n}\nload()\n\nconst handleImgSuccess = (res) => {\n  data.form.img = res.data\n}\n\nconst reset = () => {\n  data.name = null\n  load()\n}\n\nconst handleAdd = () => {\n  data.formVisible = true\n  data.form = {}\n}\n\nconst save = () => { \u002F\u002F 在一个保存方法里面做2个操作  一个是新增 一个是编辑\n  data.form.id ? update() : add()\n}\n\nconst add = () => {\n  request.post('\u002Farticle\u002Fadd', data.form).then(res => {   \u002F\u002F 新增的对象里面没有id\n    if (res.code === '200') {\n      data.formVisible = false\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 新增后一定要重新加载最新的数据\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst handleUpdate = (row) => {\n  data.form = JSON.parse(JSON.stringify(row)) \u002F\u002F 深拷贝一个新的对象 用于编辑  这样就不会影响行对象\n  data.formVisible = true\n}\n\nconst update = () => {\n  request.put('\u002Farticle\u002Fupdate', data.form).then(res => {  \u002F\u002F 编辑的对象里面包含id\n    if (res.code === '200') {\n      data.formVisible = false\n      ElMessage.success('操作成功')\n      load()  \u002F\u002F 更新后一定要重新加载最新的数据\n    } else {\n      ElMessage.error(res.msg)\n    }\n  })\n}\n\nconst del = (id) => {\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Farticle\u002FdeleteById\u002F' +id).then(res => {\n      if (res.code === '200') {\n        ElMessage.success('操作成功')\n        load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n}\n\nconst handleSelectionChange = (rows) => {  \u002F\u002F 返回所有选中的行对象数组\n  \u002F\u002F 从选中的行数组里面取出所有行的id组成一个新的数组\n  data.ids = rows.map(row => row.id)\n  console.log(data.ids)\n}\n\nconst delBatch = () => {\n  if (data.ids.length === 0) {\n    ElMessage.warning('请选择数据')\n    return\n  }\n  ElMessageBox.confirm('删除数据后无法恢复，您确认删除吗？', '删除确认', { type: 'warning' }).then(() => {\n    request.delete('\u002Farticle\u002FdeleteBatch', { data: data.ids }).then(res => {\n      if (res.code === '200') {\n        ElMessage.success('操作成功')\n        load()  \u002F\u002F 删除后一定要重新加载最新的数据\n      } else {\n        ElMessage.error(res.msg)\n      }\n    })\n  }).catch()\n}\n\u003C\u002Fscript>\n```\n\n## 问题：为什么我跟着敲完了  数据没写到数据库里面 页面也不显示数据？？？\n\n你注意看一下  文件上传的回调方法写的对不对？？？\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729761107949-40159b01-ebc3-402e-bcb2-61d9ff15e22c.png)\n\n注意：复制虽然很爽，但也会经常翻车，属性写的对不对？？\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729761242527-f005d3fd-4051-4220-b0f0-fa33d148503f.png)\n\n如果是后端 sql 问题，要耐心、细心看下你的 sql 到底写的对不对\n\n![](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2024\u002Fpng\u002F751015\u002F1729761366881-4033ce92-6dd7-483a-a34f-0fdb070cc992.png)\n\n## 在表格里面显示预览图片\n\n```vue\n\u003Cel-table-column label=\"封面\">\n  \u003Ctemplate #default=\"scope\">\n    \u003Cel-image v-if=\"scope.row.img\" :src=\"scope.row.img\" :preview-src-list=[scope.row.img] preview-teleported style=\"display: block; width: 100px; height: 60px;\" \u002F>\n  \u003C\u002Ftemplate>\n\u003C\u002Fel-table-column>\n```\n\n","coding",1,3931,1072,"2024-10-24 17:38:21","2026-05-03 22:49:02","1天学会SpringBoot3+Vue3实战项目开发","learn-springboot-vue",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,27,34,42,49,56,63,70,77,84,91,98,105,112,113,120],{"id":21,"uuid":22,"project_id":6,"title":23,"type":9,"status":10,"public_enabled":10,"views":24,"sort":25,"created_at":26,"updated_at":14,"project_title":15,"project_slug":16},475,"OgrBbww7","01. 1天学会SpringBoot3+Vue3实战项目课程介绍",17862,910,"2024-10-11 16:50:50",{"id":28,"uuid":29,"project_id":6,"title":30,"type":9,"status":10,"public_enabled":10,"views":31,"sort":32,"created_at":33,"updated_at":14,"project_title":15,"project_slug":16},476,"U58ISSFR","02. 从0带你搭建Vue3工程",12899,911,"2024-10-11 16:47:49",{"id":35,"uuid":36,"project_id":6,"title":37,"type":9,"status":10,"public_enabled":10,"views":38,"sort":39,"created_at":40,"updated_at":41,"project_title":15,"project_slug":16},478,"tK3YUYq8","03. Vue3集成Element-Plus",9899,919,"2024-10-14 22:18:17","2026-05-07 15:33:28.189425+00",{"id":43,"uuid":44,"project_id":6,"title":45,"type":9,"status":10,"public_enabled":10,"views":46,"sort":47,"created_at":48,"updated_at":14,"project_title":15,"project_slug":16},488,"J2MV6UAG","04. Element-Plus组件使用速成",8093,938,"2024-10-11 16:49:40",{"id":50,"uuid":51,"project_id":6,"title":52,"type":9,"status":10,"public_enabled":10,"views":53,"sort":54,"created_at":55,"updated_at":14,"project_title":15,"project_slug":16},489,"zGi4XJsb","05. Vue3集成Vue-Router实现路由跳转",7443,939,"2024-10-12 15:44:41",{"id":57,"uuid":58,"project_id":6,"title":59,"type":9,"status":10,"public_enabled":10,"views":60,"sort":61,"created_at":62,"updated_at":14,"project_title":15,"project_slug":16},499,"cwsTdvo9","06. Vue3搭建后台管理系统",7421,964,"2024-10-14 16:02:49",{"id":64,"uuid":65,"project_id":6,"title":66,"type":9,"status":10,"public_enabled":10,"views":67,"sort":68,"created_at":69,"updated_at":14,"project_title":15,"project_slug":16},501,"JlXltpKA","07. Mysql语法简介（速成）",5208,973,"2024-10-15 16:52:18",{"id":71,"uuid":72,"project_id":6,"title":73,"type":9,"status":10,"public_enabled":10,"views":74,"sort":75,"created_at":76,"updated_at":14,"project_title":15,"project_slug":16},509,"c3XrOTcU","08. 从0带你搭建SpringBoot3工程",9397,992,"2024-10-16 15:43:13",{"id":78,"uuid":79,"project_id":6,"title":80,"type":9,"status":10,"public_enabled":10,"views":81,"sort":82,"created_at":83,"updated_at":14,"project_title":15,"project_slug":16},516,"QsKwbDX7","09. SpringBoot3集成Mybatis",10348,1004,"2024-10-17 16:36:15",{"id":85,"uuid":86,"project_id":6,"title":87,"type":9,"status":10,"public_enabled":10,"views":88,"sort":89,"created_at":90,"updated_at":14,"project_title":15,"project_slug":16},519,"qKG13ySo","10. SpringBoot3+Vue3实现基本的增删改查功能",9572,1013,"2024-10-18 16:34:55",{"id":92,"uuid":93,"project_id":6,"title":94,"type":9,"status":10,"public_enabled":10,"views":95,"sort":96,"created_at":97,"updated_at":14,"project_title":15,"project_slug":16},527,"7uED9n7e","11. Vue3开发登录注册页面",7106,1031,"2024-10-21 17:35:30",{"id":99,"uuid":100,"project_id":6,"title":101,"type":9,"status":10,"public_enabled":10,"views":102,"sort":103,"created_at":104,"updated_at":14,"project_title":15,"project_slug":16},535,"poUfWrWc","12. Vue3管理系统开发个人信息、修改密码页面",5777,1050,"2024-10-22 17:50:30",{"id":106,"uuid":107,"project_id":6,"title":108,"type":9,"status":10,"public_enabled":10,"views":109,"sort":110,"created_at":111,"updated_at":14,"project_title":15,"project_slug":16},542,"FxHR3hNR","13. SpringBoot3+Vue3实现文件上传下载功能",4489,1057,"2024-10-23 17:31:02",{"id":4,"uuid":5,"project_id":6,"title":7,"type":9,"status":10,"public_enabled":10,"views":11,"sort":12,"created_at":13,"updated_at":14,"project_title":15,"project_slug":16},{"id":114,"uuid":115,"project_id":6,"title":116,"type":9,"status":10,"public_enabled":10,"views":117,"sort":118,"created_at":119,"updated_at":14,"project_title":15,"project_slug":16},555,"nal0yVxM","15. SpringBoot3+Vue3实现数据批量导入导出功能",3577,1090,"2024-10-28 17:39:21",{"id":121,"uuid":122,"project_id":6,"title":123,"type":9,"status":10,"public_enabled":10,"views":124,"sort":125,"created_at":126,"updated_at":14,"project_title":15,"project_slug":16},564,"XxSPPFGi","16. SpringBoot3+Vue3实现数据统计图表功能",4236,1109,"2025-01-09 09:40:57"]