[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-public-d53BPIQs":3,"public-project-articles-d53BPIQs":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},44,"d53BPIQs",39,"11. Vue登录（含验证码）、注册页面开发","login.png\n\n\n## ![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692620836406-45180804-b804-4029-bb56-53cde5abe098.png#averageHue=%23f98546&clientId=ucdbeb0aa-8a0c-4&from=paste&height=819&id=uc552b5d4&originHeight=1024&originWidth=1024&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=98287&status=done&style=none&taskId=ub38b87df-3e72-44d7-9eda-3368108af6b&title=&width=819.2)\n\nregister.png\n![register.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692620844064-e228a12e-6176-4c15-8bec-2a510b84d3a2.png#averageHue=%23fccba6&clientId=ucdbeb0aa-8a0c-4&from=paste&height=819&id=u7df88f88&originHeight=1024&originWidth=1024&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=150263&status=done&style=none&taskId=u59f4f301-6758-4711-b556-acf92c0a010&title=&width=819.2)\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692621326892-a7e5b9bf-892f-4eb8-bca3-55be60956904.png#averageHue=%23fff8f7&clientId=ucdbeb0aa-8a0c-4&from=paste&height=716&id=u52a5fa82&originHeight=895&originWidth=1920&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=40979&status=done&style=none&taskId=u1bcf7ece-6fd8-4b89-b802-fee325e5a2c&title=&width=1536)\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692621684836-efe9d28d-22c3-48a4-8eaf-177b147932d2.png#averageHue=%23aaab9e&clientId=ucdbeb0aa-8a0c-4&from=paste&height=501&id=uf1ca48f2&originHeight=626&originWidth=1295&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=80570&status=done&style=none&taskId=u41187f4b-d5c0-4c09-8204-3af37b60a01&title=&width=1036)\n\n## 页面效果\n\n登录\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692626833305-00ed7b86-4e77-4287-a7d4-fae925f32059.png#averageHue=%230f9876&clientId=ucdbeb0aa-8a0c-4&from=paste&height=716&id=u166e83d3&originHeight=895&originWidth=1920&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=85610&status=done&style=none&taskId=u236be09b-5017-40ff-a9e6-1d7e82c869c&title=&width=1536)\n注册\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692626854167-df4f48ec-a7d8-40e1-b4bb-65ed1f1bf1ee.png#averageHue=%23cee5f5&clientId=ucdbeb0aa-8a0c-4&from=paste&height=716&id=uae318ec4&originHeight=895&originWidth=1920&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=75470&status=done&style=none&taskId=ufebb50b1-4ed8-417f-9029-523e4c9645c&title=&width=1536)\n\n## 登录 Login.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv style=\"height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #0f9876\">\n    \u003Cdiv style=\"display: flex; background-color: white; width: 50%; border-radius: 5px; overflow: hidden\">\n      \u003Cdiv style=\"flex: 1\">\n        \u003Cimg src=\"@\u002Fassets\u002Flogin.png\" alt=\"\" style=\"width: 100%\">\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"flex: 1; display: flex; align-items: center; justify-content: center\">\n        \u003Cel-form :model=\"user\" style=\"width: 80%\" :rules=\"rules\" ref=\"loginRef\">\n          \u003Cdiv style=\"font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 20px\">欢迎登录后台管理系统\u003C\u002Fdiv>\n          \u003Cel-form-item prop=\"username\">\n            \u003Cel-input prefix-icon=\"el-icon-user\" size=\"medium\" placeholder=\"请输入账号\" v-model=\"user.username\">\u003C\u002Fel-input>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item prop=\"password\">\n            \u003Cel-input prefix-icon=\"el-icon-lock\" size=\"medium\" show-password placeholder=\"请输入密码\" v-model=\"user.password\">\u003C\u002Fel-input>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item prop=\"code\">\n            \u003Cdiv style=\"display: flex\">\n              \u003Cel-input placeholder=\"请输入验证码\" prefix-icon=\"el-icon-circle-check\" size=\"medium\" style=\"flex: 1\" v-model=\"user.code\">\u003C\u002Fel-input>\n              \u003Cdiv style=\"flex: 1; height: 36px\">\n                \u003Cvalid-code @update:value=\"getCode\" \u002F>\n              \u003C\u002Fdiv>\n            \u003C\u002Fdiv>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item>\n            \u003Cel-button type=\"primary\" style=\"width: 100%\" @click=\"login\">登 录\u003C\u002Fel-button>\n          \u003C\u002Fel-form-item>\n          \u003Cdiv style=\"display: flex\">\n            \u003Cdiv style=\"flex: 1\">还没有账号？请 \u003Cspan style=\"color: #0f9876; cursor: pointer\" @click=\"$router.push('\u002Fregister')\">注册\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv style=\"flex: 1; text-align: right\">\u003Cspan style=\"color: #0f9876; cursor: pointer\">忘记密码\u003C\u002Fspan>\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fel-form>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nimport ValidCode from \"@\u002Fconponents\u002FValidCode\";\n\nexport default {\n  name: \"Login\",\n  components: {\n    ValidCode\n  },\n  data() {\n\n    \u002F\u002F 验证码校验\n    const validateCode = (rule, value, callback) => {\n      if (value === '') {\n        callback(new Error('请输入验证码'))\n      } else if (value.toLowerCase() !== this.code) {\n        callback(new Error('验证码错误'))\n      } else {\n        callback()\n      }\n    }\n\n    return {\n      code: '',  \u002F\u002F 验证码组件传递过来的code\n      user: {\n        code: '',   \u002F\u002F 表单里用户输入的code 验证码\n        username: '',\n        password: ''\n      },\n      rules: {\n        username: [\n          { required: true, message: '请输入账号', trigger: 'blur' },\n        ],\n        password: [\n          { required: true, message: '请输入密码', trigger: 'blur' },\n        ],\n        code: [\n          { validator: validateCode, trigger: 'blur' }\n        ],\n      }\n    }\n  },\n  created() {\n\n  },\n  methods: {\n    getCode(code) {\n      this.code = code.toLowerCase()\n    },\n    login() {\n      this.$refs['loginRef'].validate((valid) => {\n        if (valid) {\n          \u002F\u002F 验证通过\n          this.$request.post('\u002Flogin', this.user).then(res => {\n            if (res.code === '200') {\n              this.$router.push('\u002F')\n              this.$message.success('登录成功')\n              localStorage.setItem(\"honey-user\", JSON.stringify(res.data))  \u002F\u002F 存储用户数据\n            } else {\n              this.$message.error(res.msg)\n            }\n          })\n        }\n      })\n    }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n\n\u003C\u002Fstyle>\n```\n\n## 验证码 ValidCode.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv class=\"ValidCode disabled-select\" style=\"width: 100%; height: 100%\" @click=\"refreshCode\">\n    \u003Cspan v-for=\"(item, index) in codeList\" :key=\"index\" :style=\"getStyle(item)\">{{item.code}}\u003C\u002Fspan>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\nexport default {\n  name: 'validCode',\n  data () {\n    return {\n      length: 4,\n      codeList: []\n    }\n  },\n  mounted () {\n    this.createdCode()\n  },\n  methods: {\n    refreshCode () {\n      this.createdCode()\n    },\n    createdCode () {\n      let len = this.length,\n          codeList = [],\n          chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789',\n          charsLen = chars.length\n      \u002F\u002F 生成\n      for (let i = 0; i \u003C len; i++) {\n        let rgb = [Math.round(Math.random() * 220), Math.round(Math.random() * 240), Math.round(Math.random() * 200)]\n        codeList.push({\n          code: chars.charAt(Math.floor(Math.random() * charsLen)),\n          color: `rgb(${rgb})`,\n          padding: `${[Math.floor(Math.random() * 10)]}px`,\n          transform: `rotate(${Math.floor(Math.random() * 90) - Math.floor(Math.random() * 90)}deg)`\n        })\n      }\n      \u002F\u002F 指向\n      this.codeList = codeList\n      \u002F\u002F 将当前数据派发出去\n      this.$emit('update:value', codeList.map(item => item.code).join(''))\n    },\n    getStyle (data) {\n      return `color: ${data.color}; font-size: ${data.fontSize}; padding: ${data.padding}; transform: ${data.transform}`\n    }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle>\n.ValidCode{\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  cursor: pointer;\n}\n.ValidCode span {\n  display: inline-block;\n  font-size: 18px;\n}\n\u003C\u002Fstyle>\n```\n\n## 注册 Register.vue\n\n```vue\n\u003Ctemplate>\n  \u003Cdiv style=\"height: 100vh; display: flex; align-items: center; justify-content: center; background-color: #669fef\">\n    \u003Cdiv style=\"display: flex; background-color: white; width: 50%; border-radius: 5px; overflow: hidden\">\n      \u003Cdiv style=\"flex: 1\">\n        \u003Cimg src=\"@\u002Fassets\u002Fregister.png\" alt=\"\" style=\"width: 100%\">\n      \u003C\u002Fdiv>\n      \u003Cdiv style=\"flex: 1; display: flex; align-items: center; justify-content: center\">\n        \u003Cel-form :model=\"user\" style=\"width: 80%\" :rules=\"rules\" ref=\"registerRef\">\n          \u003Cdiv style=\"font-size: 20px; font-weight: bold; text-align: center; margin-bottom: 20px\">欢迎注册后台管理系统\u003C\u002Fdiv>\n          \u003Cel-form-item prop=\"username\">\n            \u003Cel-input prefix-icon=\"el-icon-user\" size=\"medium\" placeholder=\"请输入账号\" v-model=\"user.username\">\u003C\u002Fel-input>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item prop=\"password\">\n            \u003Cel-input prefix-icon=\"el-icon-lock\" size=\"medium\" show-password placeholder=\"请输入密码\" v-model=\"user.password\">\u003C\u002Fel-input>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item prop=\"confirmPass\">\n            \u003Cel-input prefix-icon=\"el-icon-lock\" size=\"medium\" show-password placeholder=\"请确认密码\" v-model=\"user.confirmPass\">\u003C\u002Fel-input>\n          \u003C\u002Fel-form-item>\n          \u003Cel-form-item>\n            \u003Cel-button type=\"info\" style=\"width: 100%\" @click=\"register\">注 册\u003C\u002Fel-button>\n          \u003C\u002Fel-form-item>\n          \u003Cdiv style=\"display: flex\">\n            \u003Cdiv style=\"flex: 1\">已经有账号了？请 \u003Cspan style=\"color: #6e77f2; cursor: pointer\" @click=\"$router.push('\u002Flogin')\">登录\u003C\u002Fspan>\u003C\u002Fdiv>\n          \u003C\u002Fdiv>\n        \u003C\u002Fel-form>\n      \u003C\u002Fdiv>\n    \u003C\u002Fdiv>\n\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript>\n\nexport default {\n  name: \"Register\",\n  data() {\n    \u002F\u002F 验证码校验\n    const validatePassword = (rule, confirmPass, callback) => {\n      if (confirmPass === '') {\n        callback(new Error('请确认密码'))\n      } else if (confirmPass !== this.user.password) {\n        callback(new Error('两次输入的密码不一致'))\n      } else {\n        callback()\n      }\n    }\n    return {\n      user: {\n        username: '',\n        password: '',\n        confirmPass: ''\n      },\n      rules: {\n        username: [\n          { required: true, message: '请输入账号', trigger: 'blur' },\n        ],\n        password: [\n          { required: true, message: '请输入密码', trigger: 'blur' },\n        ],\n        confirmPass: [\n          { validator: validatePassword, trigger: 'blur' }\n        ],\n      }\n    }\n  },\n  created() {\n\n  },\n  methods: {\n    register() {\n      this.$refs['registerRef'].validate((valid) => {\n        if (valid) {\n          \u002F\u002F 验证通过\n          this.$request.post('\u002Fregister', this.user).then(res => {\n            if (res.code === '200') {\n              this.$router.push('\u002Flogin')\n              this.$message.success('注册成功')\n            } else {\n              this.$message.error(res.msg)\n            }\n          })\n        }\n      })\n    }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Cstyle scoped>\n\n\u003C\u002Fstyle>\n```\n\n## 加入 hutool\n\n国产的工具类依赖\n\n```xml\n\u003Cdependency>\n  \u003CgroupId>cn.hutool\u003C\u002FgroupId>\n  \u003CartifactId>hutool-all\u003C\u002FartifactId>\n  \u003Cversion>5.8.18\u003C\u002Fversion>\n\u003C\u002Fdependency>\n```\n\n遇到了跨域的错误：\n\n![image.png](https:\u002F\u002Fcdn.nlark.com\u002Fyuque\u002F0\u002F2023\u002Fpng\u002F751015\u002F1692624477450-f21c6374-6a08-4062-8670-15f0909f6f14.png#averageHue=%23fef1f0&clientId=ucdbeb0aa-8a0c-4&from=paste&height=195&id=uae47bd44&originHeight=244&originWidth=1896&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=42513&status=done&style=none&taskId=u91049a5a-f862-495a-ab34-fb0f982aba5&title=&width=1516.8)\n\n## SpringBoot 解决跨域问题 CorsConfig\n\n```java\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.cors.CorsConfiguration;\nimport org.springframework.web.cors.UrlBasedCorsConfigurationSource;\nimport org.springframework.web.filter.CorsFilter;\n\n@Configuration\npublic class CorsConfig {\n\n    \u002F\u002F 当前跨域请求最大有效时长。这里默认1天\n    private static final long MAX_AGE = 24 * 60 * 60;\n\n    @Bean\n    public CorsFilter corsFilter() {\n        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();\n        CorsConfiguration corsConfiguration = new CorsConfiguration();\n        corsConfiguration.addAllowedOrigin(\"*\"); \u002F\u002F 1 设置访问源地址\n        corsConfiguration.addAllowedHeader(\"*\"); \u002F\u002F 2 设置访问源请求头\n        corsConfiguration.addAllowedMethod(\"*\"); \u002F\u002F 3 设置访问源请求方法\n        corsConfiguration.setMaxAge(MAX_AGE);\n        source.registerCorsConfiguration(\"\u002F**\", corsConfiguration); \u002F\u002F 4 对接口配置跨域设置\n        return new CorsFilter(source);\n    }\n}\n\n```\n\n**前端登录逻辑**\n当后台返回的 code 是 200 的时候，表示验证通过\n这时候要存储用户信息，然后跳转到主页\n\n**后端的登录逻辑**\n验证用户名和密码不为空\n通过用户名查询数据库，如果数据库没有数据，说明用户不存在，报错\n如果密码不匹配，说明账号的密码输入错误，报错\n然后验证通过，返回 200\n\n## 后台代码\n\nWebController\n\n```java\nimport cn.hutool.core.util.StrUtil;\nimport com.example.springboot.common.Result;\nimport com.example.springboot.entity.User;\nimport com.example.springboot.service.UserService;\nimport org.springframework.web.bind.annotation.GetMapping;\nimport org.springframework.web.bind.annotation.PostMapping;\nimport org.springframework.web.bind.annotation.RequestBody;\nimport org.springframework.web.bind.annotation.RestController;\n\nimport javax.annotation.Resource;\n\n\u002F**\n * 功能：提供接口返回数据\n * 作者：程序员青戈\n * 日期：2023\u002F8\u002F13 15:55\n *\u002F\n@RestController\npublic class WebController {\n\n    @Resource\n    UserService userService;\n\n    @GetMapping(\"\u002F\")\n    public Result hello() {\n        return Result.success(\"success\");\n    }\n\n    @PostMapping(\"\u002Flogin\")\n    public Result login(@RequestBody User user) {\n        if (StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPassword())) {\n            return Result.error(\"数据输入不合法\");\n        }\n        user = userService.login(user);\n        return Result.success(user);\n    }\n\n    @PostMapping(\"\u002Fregister\")\n    public Result register(@RequestBody User user) {\n        if (StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPassword())) {\n            return Result.error(\"数据输入不合法\");\n        }\n        if (user.getUsername().length() > 10 || user.getPassword().length() > 20) {\n            return Result.error(\"数据输入不合法\");\n        }\n        user = userService.register(user);\n        return Result.success(user);\n    }\n\n}\n\n```\n\nUserService\n\n```java\n \u002F\u002F 验证用户账户是否合法\n    public User login(User user) {\n        \u002F\u002F 根据用户名查询数据库的用户信息\n        User dbUser = userMapper.selectByUsername(user.getUsername());\n        if (dbUser == null) {\n            \u002F\u002F 抛出一个自定义的异常\n            throw new ServiceException(\"用户名或密码错误\");\n        }\n        if (!user.getPassword().equals(dbUser.getPassword())) {\n            throw new ServiceException(\"用户名或密码错误\");\n        }\n        return dbUser;\n    }\n\n    public User register(User user) {\n        User dbUser = userMapper.selectByUsername(user.getUsername());\n        if (dbUser != null) {\n            \u002F\u002F 抛出一个自定义的异常\n            throw new ServiceException(\"用户名已存在\");\n        }\n        user.setName(user.getUsername());\n        userMapper.insert(user);\n        return user;\n    }\n```\n\n自定义异常 ServiceException\n\n```java\npublic class ServiceException extends RuntimeException {\n\n    public ServiceException(String msg) {\n        super(msg);\n    }\n}\n```\n\nGlobalException\n\n```java\nimport com.example.springboot.common.Result;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\n@ControllerAdvice\npublic class GlobalException {\n\n    @ExceptionHandler(ServiceException.class)\n    @ResponseBody\n    public Result serviceException(ServiceException e) {\n        return Result.error(\"500\", e.getMessage());\n    }\n\n}\n```\n","coding",1,4867,66,"2024-04-16 02:33:08","2026-05-03 22:49:02","【青哥带小白做毕设2024】完整教程资料汇总","qingge-graduation-project-2024",{"project":18,"items":19},{"id":6,"title":15,"slug":16},[20,28,35,42,49,56,63,69,76,83,90,97,98,105,112,119,126,133,140,147,154,161,168],{"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":27,"project_title":15,"project_slug":16},33,"R1oMCsCX","00. 从0开始带小白做SpringBoot+Vue+uniapp微信小程序实战项目",12130,55,"2025-04-08 11:28:17","2026-05-07 15:33:28.189425+00",{"id":29,"uuid":30,"project_id":6,"title":31,"type":9,"status":10,"public_enabled":10,"views":32,"sort":33,"created_at":34,"updated_at":14,"project_title":15,"project_slug":16},34,"s3u3u8W7","01. 网页布局技巧",3326,56,"2025-04-08 11:28:13",{"id":36,"uuid":37,"project_id":6,"title":38,"type":9,"status":10,"public_enabled":10,"views":39,"sort":40,"created_at":41,"updated_at":14,"project_title":15,"project_slug":16},35,"21zUHQYS","02. JavaScript入门",2017,57,"2025-04-08 11:27:55",{"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},36,"4XVgY9Ti","03. Vue脚手架搭建",3719,58,"2025-04-08 11:27:46",{"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},37,"S8vLLLvk","04. Git速成，推送代码到云端",1585,59,"2025-04-08 11:27: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},38,"9EbwnGDp","05. 网页布局神器ElementUI速成",2670,60,"2025-04-08 11:27:37",{"id":6,"uuid":64,"project_id":6,"title":65,"type":9,"status":10,"public_enabled":10,"views":66,"sort":67,"created_at":68,"updated_at":14,"project_title":15,"project_slug":16},"tmzahWer","06. Vue管理系统速成",3744,61,"2025-04-08 11:27:32",{"id":70,"uuid":71,"project_id":6,"title":72,"type":9,"status":10,"public_enabled":10,"views":73,"sort":74,"created_at":75,"updated_at":14,"project_title":15,"project_slug":16},40,"2agqAUQK","07. SpringBoot速成",3654,62,"2025-04-08 11:27:27",{"id":77,"uuid":78,"project_id":6,"title":79,"type":9,"status":10,"public_enabled":10,"views":80,"sort":81,"created_at":82,"updated_at":14,"project_title":15,"project_slug":16},41,"SXPAzgy7","08. Http扫盲，让小白也能听懂",2337,63,"2025-04-08 11:27:20",{"id":84,"uuid":85,"project_id":6,"title":86,"type":9,"status":10,"public_enabled":10,"views":87,"sort":88,"created_at":89,"updated_at":14,"project_title":15,"project_slug":16},42,"ostBIxAV","09. SpringBoot集成Mybatis实现增删改查",4190,64,"2025-04-08 11:27:13",{"id":91,"uuid":92,"project_id":6,"title":93,"type":9,"status":10,"public_enabled":10,"views":94,"sort":95,"created_at":96,"updated_at":14,"project_title":15,"project_slug":16},43,"6Sv7afpa","10. Vue封装前后端数据交互工具",3716,65,"2024-04-16 02:33:13",{"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":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},45,"m033ng06","12. SpringBoot集成JWT token实现权限验证",3243,67,"2024-04-16 02:33:00",{"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},46,"7xzyVD06","13. SpringBoot+Vue实现单文件、多文件上传和下载",2784,68,"2024-04-16 02:32:52",{"id":113,"uuid":114,"project_id":6,"title":115,"type":9,"status":10,"public_enabled":10,"views":116,"sort":117,"created_at":118,"updated_at":14,"project_title":15,"project_slug":16},47,"BdOLUenp","14. 多角色登录（Vue-Router路由守卫）",2318,69,"2024-04-16 02:32:39",{"id":120,"uuid":121,"project_id":6,"title":122,"type":9,"status":10,"public_enabled":10,"views":123,"sort":124,"created_at":125,"updated_at":14,"project_title":15,"project_slug":16},48,"2Wkx3igg","15. Vue个人信息修改、修改密码、重置密码",2092,70,"2024-04-16 02:32:33",{"id":127,"uuid":128,"project_id":6,"title":129,"type":9,"status":10,"public_enabled":10,"views":130,"sort":131,"created_at":132,"updated_at":14,"project_title":15,"project_slug":16},49,"BDvVa4By","16. SpringBoot+Vue管理系统实现增删改查",2598,71,"2024-04-16 02:32:29",{"id":134,"uuid":135,"project_id":6,"title":136,"type":9,"status":10,"public_enabled":10,"views":137,"sort":138,"created_at":139,"updated_at":14,"project_title":15,"project_slug":16},50,"FJVl0rCu","17. SpringBoot+Vue实现数据的批量导入和导出",1684,72,"2024-04-16 02:32:26",{"id":141,"uuid":142,"project_id":6,"title":143,"type":9,"status":10,"public_enabled":10,"views":144,"sort":145,"created_at":146,"updated_at":14,"project_title":15,"project_slug":16},51,"FvW9oHgj","18. SpringBoot+Vue项目部署上线",2845,73,"2024-04-16 02:32:22",{"id":148,"uuid":149,"project_id":6,"title":150,"type":9,"status":10,"public_enabled":10,"views":151,"sort":152,"created_at":153,"updated_at":14,"project_title":15,"project_slug":16},52,"xyqrxxiR","19. SpringBoot+Vue集成富文本编辑器",1499,74,"2024-04-16 02:32:18",{"id":155,"uuid":156,"project_id":6,"title":157,"type":9,"status":10,"public_enabled":10,"views":158,"sort":159,"created_at":160,"updated_at":14,"project_title":15,"project_slug":16},53,"XAaCXz8W","20. SpringBoot+Vue集成系统公告",1043,75,"2024-04-16 02:32:14",{"id":162,"uuid":163,"project_id":6,"title":164,"type":9,"status":10,"public_enabled":10,"views":165,"sort":166,"created_at":167,"updated_at":14,"project_title":15,"project_slug":16},54,"2havlmaC","21. SpringBoot+Vue集成AOP系统日志",1159,76,"2024-04-16 02:32:11",{"id":25,"uuid":169,"project_id":6,"title":170,"type":9,"status":10,"public_enabled":10,"views":171,"sort":172,"created_at":173,"updated_at":14,"project_title":15,"project_slug":16},"ObvLqJdX","22. SpringBoot+Vue实现Echarts数据报表（柱状图、饼图、折线图）",1688,99,"2024-04-16 02:30:25"]