在线判题项目
快来分享你的内容吧~
- 05-06 11:14·Java后端
- 02-22 12:06·信息安全有大佬帮忙远程布局部署一下鱼皮的oj判题系统吗?有偿编程导航_小y:可以加一下 OJ 项目群:https://www.codefather.cn/course/1790980707917017089?tabKey=courseGroup&contentType=video110分享
- 01-29 16:31查看全文请问一下老师,在OJ 项目中,权限拦截那 使用的是: Spring Cloud Gateway 的 Filter 请求拦截器(内部接口拦截) + (可以进行扩展的 JWT token 实现)。 我想根据目前学到的知识,这样做是否可以: Spring Cloud Gateway 的 Fi...编程导航_小y:可以加一下 OJ 项目群,在群里和大家一起讨论交流:https://www.codefather.cn/course/1790980707917017089?tabKey=courseGroup&contentType=text151分享
- 01-29 13:39请问一下,OJ 项目的 rabbitMQ ,之前电脑装过 3.11.10版本,看到课程中使用的是 3.12.4 的版本,请问我如果不换还是使用之前的版本是否可行?leikooo:尽量保持版本一致,当然也可以试试看行不行,不行的再替换就好020分享
- 01-06 16:13各位同学好,在做 OJ 项目,做到了 java 操作 docker,遇到了这个问题卡住了。自己目前做过以下修改,添加netty 依赖,想使用 netty 代替 Jersey HTTP 失败。尝试linux上添加 配置文件也是失败。 卡了好久,谢谢各位老师。leikooo:sandbox 代码运行需要在虚拟机里面具体可以参考这个 https://mp.weixin.qq.com/s/zOvx89QBhIPj5Cicbo90sA321分享
- 2025-11-28·Java后端老鱼OJ的项目,被问到这样一个问题,有uu们知道怎么回答吗? 通过rabbitmq将判题请求异步地执行,代码沙箱是不是需要处理完一个题目,才继续处理下一个题目?如果有1000个题目,那前端等待判题结果的时间是否太长了?符合实际应用吗?牧濑红莉栖:扩充多个沙箱服务即可,不管是用轮询还是哈希,只要把这1000个请求平摊掉不就快了330分享
2025-10-24·@官方运营 学习、求职、生活问题欢迎交流- 2025-08-15想问一下,我做完了OJ项目,但是我的服务器是2核2G,实际内存好像都没到2G,就1.7G好像,启动了nacos这些之后,再启动后端,会直接把nacos强制退出导致启动不了,这样有什么解决办法吗?来杯碳酸饮料:最少2核4G270分享
- 2025-07-21·Java后端学习打卡 oj项目前后端联调 哪位老能给一些建议,,,前端几乎不懂,仅了解三件套和vue,仅仅是了解,前端该怎么学习呢,后端能看懂代码,但是实践上机很差。。。 目前做的项目有黑马点评还有AI智能体,几乎都是照着代码敲的,如何才能做到九月份前找到实习呢查看全文编程导航_小y:如果前端实在看不懂可以先不学,主要写后端部分就行,然后跟着敲后端代码,多敲几个项目后就熟悉了。可以看下编程导航的简历优化技巧:https://www.codefather.cn/course/cv,先调整一版简历投递起来,等 9 月投递实习。可以跟着面试鸭刷面试题:https://www.mianshiya.com/020分享
OJ在线判题系统(一)
# OJ在线判题系统(一) ## 项目设计 ### 实现核心 1. 权限校验:谁能提代码,谁不能提代码 2. 代码沙箱(安全沙箱) 1. 隔离藏毒的用户代码 2. 资源分配-防止用户恶意疯狂占用资源占满内存 3. 判题规则:判题用例的比对 4. 任务调度:在服务器资源有限用户要排队的情况下如何按照顺序依次判题,而不是直接拒绝 ### 核心业务流程  不编译不能运行代码 时序图: 按时间顺序、调用的顺序去画  判题服务:获取题目信息,预计的输入输出结果,返回给主业务后端:用户的答案是否正确 代码沙箱:只负责运行代码,给出结果,不管什么结果是正确的。 ### 功能 1. 题目模块 1. 创建题目(管理员) 2. 删除题目(管理员) 3. 搜索题目(用户) 4. 在线做题 5. 提交题目代码 2. 用户模块 1. 注册 2. 登录 3. 判题模块 1. 提交判题(结果是否正确) 2. 错误处理(内存溢出、安全性、超时) 3. **自主实现**代码沙箱 4. 开放接口 ### 技术选型 前端:Vue3、Arco Design 组件库、手撸项目模板、在线代码编辑器、在线文档浏览 Java进程控制、Java安全管理器、部分JVM 知识点 虚拟机(云服务器)、Docker(代码沙箱实现) Spring Cloud 微服务、消息队列、多种设计模式 ### 架构设计 一、你要知道分哪些层;二、你要知道每一层有哪些模块  ### 主流的OJ系统实现方案 开发原则:能用别人的轮子,就不要造轮子 这里鱼皮走的是自主开发,就不详写了,感兴趣自己看成熟项目Judge0的代码 代码:https://github.com/judge0/judge0 Judge0 APl 地址: https://rapidapi.com/judge0-official/api/judge0-ce 官方文档:https://cejudge0.com/#submissions-submission-post ## 前后端初始化 ### 前端: 准备工具:nodejs + npm + vue-cli脚手架  其中vue-cli脚手架安装: ```shell npm install -g @vue/cli ``` 其他工具的安装问AI,`nvm`在这里只起到换`nodejs`版本的作用,`nodejs`版本在16/18的可不下`nvm` #### 创建项目 ```shell vue create demo-frontend-name ```  选`Manually select features`  这里多选,用空格选上 其中TypeScript是语言,Router是路由,Vuex是状态管理  选`3.x` 剩余设置看图片  先运行试试 1. 打开`package.json`点击`serve`左边的绿色小箭头 2. 终端输入,我的是`yarn serve`,具体看你初始化时的提示:  >  > > 这里遇到了问题,vue-router找不到,刚初始化就报错也是难绷 > > 试了两次都出现报错,应该是版本问题 > > 这个是AI修复的回答: > > 你这个项目“其实已经启动了”,但被 TypeScript 类型检查错误拦住了热更新流程。 > > 核心原因是版本不兼容: > > - 你的项目是老模板(`vue@3.2.13` + `typescript~4.5.5` + vue-cli 5) > - 但现在装到的是新版本 `vue-router@4.6.4` > - `vue-router@4.6.4` 的类型声明是 `dist/vue-router.d.mts`,对你这套旧 TS/解析配置不友好,导致报: > - `TS7016: Could not find a declaration file for module 'vue-router'` > > 另外它还要求 `peerDependencies: vue ^3.5.0`,也和你当前 `vue 3.2.13` 不一致。 > > > > 解决办法: > > 把 `vue-router` 降到和当前项目年代一致的版本: > > ```yarn add vue-router@4.1.6``` > > 然后重新启动: > > ```yarn serve``` 运行成功后继续 #### 前端工程化配置 创建后在webStorm里开启代码美化插件 `setting`-`Languages & Frameworks(语言和框架)`-`Javascript`-`Prettier`  在vue文件中执行格式化快捷键`Ctrl+Alt+L`,不报错,表示配置工程化成功 #### 引入组件 组件库:arco.design/vue 快速上手:arco.design/vue/docs/start 注意:**vue版本≥3.2.0** `npm install --save-dev @arco-design/web-vue` 这里使用**全局引入** ```ts import { createApp } from "vue"; import App from "./App.vue"; import ArcoVue from "@arco-design/web-vue"; import "@arco-design/web-vue/dist/arco.css"; import router from "./router"; import store from "./store"; createApp(App).use(ArcoVue).use(store).use(router).mount("#app"); ``` > 注:如果出现报错而,有可能是不符合Pretter/ESLint代码规范导致的,按`ctrl`+`Alt`+`L`即可 引入一个组件,如果显示出来,就表示引入成功 用日历组件进行实验(放那个vue都行只是看能不能引入) ```vue <template> <a-calendar v-model="value" /> select: {{ value }} </template> <script> import { ref } from "vue"; export default { setup() { const value = ref(new Date("2023-01-01")); return { value, }; }, }; </script> ``` 运行显示日历即可  > 初始化的这些组件(HelloView等)先别删,后面还有用 #### 搞布局 创建文件夹`layouts`,里面创建vue文件`BasicLayout.vue` 将这个布局文件引入到`App.vue`中 ```vue <template> <div id="app"> <BasicLayout /> </div> </template> ``` 引入完成,接下来是敲`BasicLayout.vue`来实现布局了,先把上中下布局编排好,然后再填充内容。 这里使用arco.design给的布局组件库  这里鱼皮是不停调整css样式(比如修改颜色让布局更清晰)的,故只附上最终源码 BasicLayout.vue: ```vue <template> <div id="basicLayout"> <a-layout style="height: 400px"> <a-layout-header class="header"> <GlobalHeader></GlobalHeader> </a-layout-header> <a-layout-content class="content"> <router-view /> </a-layout-content> <a-layout-footer class="footer"> <a href="http://yupi.icu.com" target="_blank" >OJ判题系统 by 桃木</a ></a-layout-footer > </a-layout> </div> </template> <script setup lang="ts"> import GlobalHeader from "@/components/GlobalHeader.vue"; </script> <style scoped> #basicLayout { } #basicLayout .header { background: red; margin-bottom: 16px; } #basicLayout .content { background: linear-gradient(to right, #bbb, #fff); margin-bottom: 16px; } #basicLayout .footer { background: #efefef; padding: 14px; position: fixed; bottom: 0; right: 0; left: 0; text-align: center; } </style> ``` GlobalHeader.vue: ```vue <template> <div id="globalHeader"> <a-menu mode="horizontal" :selected-keys="selectedKeys" @menu-item-click="doMenuClick" > <a-menu-item key="0" :style="{ padding: 0, marginRight: '38px' }" disabled > <div class="title-bar"> <img src="@/assets/logo.png" alt="" class="logo" /> <div class="title">桃 OJ</div> </div> </a-menu-item> <a-menu-item v-for="item in routes" :key="item.path"> {{ item.name }} </a-menu-item> </a-menu> </div> </template> <script lang="ts" setup> import { routes } from "../router/routes"; import { useRouter } from "vue-router"; import { ref } from "vue"; const router = useRouter(); //默认主页 const selectedKeys = ref(["/"]); //路由跳转后,更新激活项 router.afterEach((to, from, next) => { selectedKeys.value = [to.path]; }); const doMenuClick = (key: string) => { router.push({ path: key, }); }; </script> <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped> .title-bar { display: flex; align-items: center; } .title { color: #444; margin-left: 16px; } .logo { height: 48px; } </style> ``` > 这时候你会发现报错,这是因为在`router`-`index.ts`文档下,鱼皮将里面具体的路由路径与配置做了分离 > > 即:在router文件夹下创建routes.ts,将`const routes`的内容搬进去 > > routes.ts: > > ```ts > import { RouteRecordRaw } from "vue-router"; > > export const routes: Array<RouteRecordRaw> = []; > ``` > > (因为我把初始化自带的组件都删了,所以我这很干净……) > > 然后在原先的`index.ts`文件中引入这个routes > > ``` > import { routes } from "@/router/routes"; > ``` 演示一下样式,如果你的routes不为空,组件还没删,能看到顶部的导航栏=。=  #### 全局状态管理 工具:vuex 状态管理:所有页面全局共享的变量,而不是仅存在于一个页面中 比如:同步已登录的用户信息 本质上:给你提供了一套增删改查全局变量的API,只不过可能多了一些功能(比如时间旅行) 存放vuex全局管理信息的位置:`store`-`index.ts` state:存储的状态信息,比如用户信息 mutation(尽量同步):定义了对变量进行增删改(更新)的方法 actions(支持异步):执行异步操作,并且触发mutation 的更改(actions调用mutation) modules(模块):把一个大的state(全局变量)划分为多个小模块,比如user专门存用户的状态信息 这里创建`user.ts`,并在`index.ts`的modules里定义了user ```ts import { createStore } from "vuex"; import user from "@/store/user"; export default createStore({ state: {}, getters: {}, mutations: {}, actions: {}, modules: { user }, }); ``` 如果把store比作一个数据库,那么user此刻就是里面的一张表 user.ts: ```ts import { StoreOptions } from "vuex"; export default { namespaced: true, state: { loginUser: { userName: "未登录" }, }, getters: {}, actions: { getLoginUser({ commit, state }, payload) { commit("updateUser", { userName: "鱼皮" }); }, }, mutations: { updateUser(state, payload) { state.loginUser = payload; }, }, } as StoreOptions<any>; ``` 然后修改GlobalHeader测试全局管理的效果 在已有的导航栏外添加栅格布局(template) ```vue <a-row align="center" style="margin-bottom: 16px" id="globalHeader"> <a-col flex="auto"> <a-menu mode="horizontal" :selected-keys="selectedKeys" @menu-item-click="doMenuClick" > <a-menu-item key="0" :style="{ padding: 0, marginRight: '38px' }" disabled > <div class="title-bar"> <img src="@/assets/logo.jpg" alt="" class="logo" /> <div class="title">派 OJ</div> </div> </a-menu-item> <a-menu-item v-for="item in routes" :key="item.path"> {{ item.name }} </a-menu-item> </a-menu> </a-col> <a-col flex="100px"> <div>{{ store.state.user?.loginUser?.userName ?? "未登录" }}</div> </a-col> </a-row> ``` 在script中使用vuex进行变量的全局管理 ```vue //使用vuex const store = useStore(); //添加一个3s后启动的方法 setTimeout(() => { store.dispatch("user/getLoginUser",{userName:"鱼皮"}); }, 3000); ``` 用store.dispatch调用action `store.dispatch(模块名.对应的方法,{传入的参数})` 运行  #### 全局权限管理 目标:能够直接以一套通用的机制,去定义哪个页面需要那些权限。而不用每个页面独立去判断权限,提高效率。 思路: 1. 在路由配置文件,定义某个路由的访问权限 2. 在全局页面组件 app.vue 中,绑定一个全局路由监听。每次访问页面时,根据用户要访问页面的路由信息先判断用户是否有对应的访问权限。 3. 如果有,跳转到原页面;如果没有,拦截或跳转到 401鉴权或登录页 在视图(view)下添加两个页面,分别为`AdminView.vue`和`NoAuthView.vue`,并配置好路由显示在导航栏上 在路由中用meta定义每个页面需要什么权限 ```ts import { RouteRecordRaw } from "vue-router"; export const routes: Array<RouteRecordRaw> = [ { path: "/noAuth", name: "无权限", component: () => import("../views/NoAuthView.vue"), }, { path: "/admin", name: "admin", component: () => import("../views/AdminView.vue"), meta: {//注意这个meta access: "canAdmin", }, }, ]; ``` 在App.vue中加入跳转逻辑 ```ts router.beforeEach((to, from, next) => { if (to.meta.access === "canAdmin") { if (store.state.loginUser?.role !== "admin") { next("/noAuth"); return; } } next(); }); ``` 效果:点击admin后会跳转无权限页 #### 修改页面布局 1. 为了修改footer不在最底部的问题 ```vue <template> <div id="basicLayout"> //该行修改 <a-layout style="min-height: 100vh"> <a-layout-header class="header"> <GlobalHeader></GlobalHeader> </a-layout-header> <a-layout-content class="content"> <router-view /> </a-layout-content> <a-layout-footer class="footer"> <a href="http://yupi.icu.com" target="_blank" >OJ判题系统 by 桃木</a ></a-layout-footer > </a-layout> </div> </template> #basicLayout .footer { background: #efefef; padding: 16px; //该行修改 position: sticky; bottom: 0; right: 0; left: 0; text-align: center; } ``` 2. 过窄时未登录被挤压到第二行 ```vue //GlobalHeader.vue //添加wrap //为了下一步的优化布局,删掉style <a-row align="center" id="globalHeader" :wrap="false"> ``` 3. 纯优化布局 ```css #basicLayout .content { background: linear-gradient(to right, #bbb, #fff); margin-bottom: 16px; //加这行 padding: 20px; } //红色背景早就可以删了,这里改成鱼皮调的阴影 #basicLayout .header { box-shadow: #eee 1px 1px 5px; margin-bottom: 16px; } ``` #### 通过meta控制页面可见 ##### 阶段一 用属性来实现vue页面的展示 逻辑:在meta中添加hideInMenu属性(boolean),然后在vue展示中只展示没有hideInMenu的页面 > 注意,不要用v-for+v-if去条件渲染元素,这样会先循环所有的元素,导致性能的浪费 方法:先过滤再展示 ```ts //也是不得已临时创建一个HelloView组件了,引入路径不用模仿我,你们看懂了就行 { path: "/hide", name: "隐藏页面", component: () => import("../views/HelloView.vue"), meta: { hideInMenu: true, }, }, ``` 这时候你看到导航栏有更新,这里的任务是只让隐藏页面消失(不要在意那个主页)  需要在GlobalHeader引入的路由中加入过滤条件 ```js const visibleRouter = routes.filter((item, index) => { if (item.meta?.hideInMenu) { return false; } return true; }); const router = useRouter(); ``` 在渲染中将渲染范围中routes改为visibleRoutes ```vue <a-menu-item v-for="item in visibleRoutes" :key="item.path"> {{ item.name }} </a-menu-item> ``` 完成  ##### 阶段二 让这个属性的值能按照使用逻辑动态改变 ###### 定义权限 创建access文件夹,添加accessEnum和checkAccess 在accessEnum.ts中定义不同权限(类似枚举类的形式) ```ts /** * 权限定义 */ const ACCESS_ENUM = { NOT_LOGIN: "notLogin", USER: "user", ADMIN: "admin", }; export default ACCESS_ENUM; ``` ###### 抽离权限检查功能 以后的很多功能需要验证当前用户的权限,故将检验权限功能从App.vue中抽离出来 checkAccess.ts ```ts import ACCESS_ENUM from "@/access/accessEnum"; /** * 检查权限(判断当前登录用户是否具有某个权限) * @param loginUser 当前登录用户 * @param needAccess 需要有的权限 * @return boolean 有无权限 */ const checkAccess = (loginUser: any, needAccess = ACCESS_ENUM.NOT_LOGIN) => { // 获取当前登录用户具有的权限(如果没有 loginUser,则表示未登录) //如果loginUser.userRole不存在,则loginUserAccess=ACCESS_ENUM.NOT_LOGIN const loginUserAccess = loginUser?.userRole ?? ACCESS_ENUM.NOT_LOGIN; if (needAccess === ACCESS_ENUM.NOT_LOGIN) { return true; } // 如果用户登录才能访问 if (needAccess === ACCESS_ENUM.USER) { // 如果用户没登录,那么表示无权限 if (loginUserAccess === ACCESS_ENUM.NOT_LOGIN) { return false; } } // 如果需要管理员权限 if (needAccess === ACCESS_ENUM.ADMIN) { // 如果不为管理员,表示无权限 if (loginUserAccess !== ACCESS_ENUM.ADMIN) { return false; } } return true; }; export default checkAccess; ``` ###### 调整路由携带的参数 将meta里的参数修改成ACCESS_ENUM中定义的常量 routes.ts ```ts { path: "/admin", name: "admin", component: () => import("../views/AdminView.vue"), meta: { access: AccessEnum.ADMIN, }, }, ``` ###### 修改store存储的参数名称 前面有的写成role了,这里统一一下,注意getLoginUser里payload部分不要写死 user.ts ```ts export default { namespaced: true, state: { loginUser: { userName: "未登录", userRole: AccessEnum.NOT_LOGIN }, }, getters: {}, actions: { getLoginUser({ commit, state }, payload) { commit("updateUser", payload); }, }, mutations: { updateUser(state, payload) { state.loginUser = payload; }, }, } as StoreOptions<any>; ``` ###### 修改导航栏组件动态更新 ```vue const visibleRoutes = computed(() => { return routes.filter((item, index) => { if (item.meta?.hideInMenu) { return false; } //根据权限过滤菜单 if (!checkAccess(store.state.user.loginUser, item.meta?.access as string)) { return false; } return true; }); }); ``` setTimeout这部分注意将role修改成userRole ```vue setTimeout(() => { store.dispatch("user/getLoginUser", { userName: "管理员", userRole: "admin", }); }, 3000); ``` 若3s后用户从未登录变成管理员,且出现admin导航栏,说明此功能实现 ## 后端项目初始化 在知识星球中下载后端源码 https://pan.baidu.com/s/1VkrwKe63VF7KLtM_Jd4kdQ?pwd=lcpu 1. **ctrl shift R** spring-init修改为yuoj-backend 2. **ctrl shift R** springinit 修改为 yuoj 3. 包名 springinit 修改为yuoj 4. 模块名 修改为yuoj-backend 5. 在sql文件夹中运行create_table文件,自己定义数据库 6. application.yml中配置MySQL 7. 将server底下的port从8101改为8121(也可以不改但你要记住你和鱼皮后端用的端口号不一样) > 运行如果显示找不到springinit就在编辑配置中将爆红的springinit修改为yuoj > >  ### 初始化模板讲解 1)先阅读README.md 2)sql/create_table.sql定义了数据库的初始化建库建表语句 3)sq/post_es_mappingjson 帖子表在 ES 中的建表语句 4)aop:用于全局权限校验、全局日志记录 5)common:万用的类,比如通用响应类 6)config:用于接收application.yml 中的参数,初始化一些客户端的配置类(比如对象存储客户端) 7)constant:定义常量 8)controller:接受请求 9)esdao:类似 mybatis 的mapper,用于操作ES 10)exception:异常处理相关 11)job:任务相关(定时任务、单次任务) 12)manager:服务层(一般是定义一些公用的服务、对接第三方APl等) 13)mapper:mybatis 的数据访问层,用于操作数据库 14)model:数据模型、实体类、包装类、枚举值 15)service:服务层,用于编写业务逻辑 16)utils:工具类,各种各样公用的方法 17)wxmp:公众号相关的包 18)test:单元测试 19)MainApplication:项目启动入口 20)Dockerfile:用于构建Docker镜像 ### 前后端联调 意思是将前端和后端的数据同步起来 1. 安装请求工具类axios(里面封装的是ajax)`npm install axios`(axios.get()...axios.post()...) 2. 编写调用后端的代码 1) 参考这个链接直接生成代码:https://github.com/ferdikoomen/openapi-typescript-codegen `npm install openapi-typescript-codegen --save-dev` 后执行 `openapi --input http://localhost:8121/api/v2/api-docs --output ./generated --client axios` > 我在这里访问不到http://localhost:8121/api/v2/api-docs,于是在本地创建json文件转存进去,让openapi依据这个json文件生成代码 这里先修改一下插件的全局配置,在generated-core-OpenAPI.ts中修改: ```ts export const OpenAPI: OpenAPIConfig = { //删掉api BASE: "http://localhost:8121", VERSION: "1.0", WITH_CREDENTIALS: false, CREDENTIALS: "include", TOKEN: undefined, USERNAME: undefined, PASSWORD: undefined, HEADERS: undefined, ENCODE_PATH: undefined, }; ``` 在user.ts中修改action: ```ts actions: { //async:声明这是一个异步函数,内部可以使用 await 等待接口返回。 async getLoginUser({ commit, state }, payload) { //这里调用了刚才通过工具生成的 API 服务(UserControllerService) //它会发起一个 HTTP GET 请求到后端的 /user/get/login(或其他对应路径)接口。 const res = await UserControllerService.getLoginUserUsingGet(); //如果后端返回 0(通常代表操作成功),则调用名为 updateUser 的 Mutation。 if (res.code === 0) { commit("updateUser", res.data); } else { //...state.loginUser:保留原有用户信息(如果有的话)。 //强制将 userRole 字段设置为 AccessEnum.NOT_LOGIN(未登录枚举)。 //配合之前的 checkAccess 权限校验函数,确保页面能正确识别出当前是“游客”身份,从而限制某些敏感操作。 commit("updateUser", { ...state.loginUser, userRole: AccessEnum.NOT_LOGIN, }); } }, }, ``` 效果:打开浏览器,在网络请求中看到对后端的请求   > 到这里前后端最基本的对接就已经完成了 > > 让我们理一理逻辑:后端提供API接口,我们用一个github插件将api接口快捷生成前端访问后端的业务代码(services文件夹下),然后我们在vuex的user.ts文件中将数据的更新从完全的前端业务转为依据后端返回的结果而更新 > > 因为你是访问的后端,所以考虑到网络波动的影响,它后端服务器未必立刻为你服务,所以你要加async异步访问要加await,毕竟你不太可能前端的访问刚发出,后端的服务器就立马为你返回结果 2) 直接定义axios请求库的全局参数,比如全局请求响应拦截器 创建plugins目录,添加axios.ts文件 ```ts // Add a request interceptor import axios from "axios"; axios.interceptors.request.use( function (config) { // Do something before request is sent return config; }, function (error) { // Do something with request error return Promise.reject(error); } ); // Add a response interceptor axios.interceptors.response.use( function (response) { console.log("响应", response); // Any status code that lie within the range of 2xx cause this function to trigger // Do something with response data return response; }, function (error) { // Any status codes that falls outside the range of 2xx cause this function to trigger // Do something with response error return Promise.reject(error); } ); ``` 在main.ts中引入,添加一行: ```ts import "@/plugins/axios"; ``` 打开浏览器发现打印:  > 为什么我看上去没有明写get/post请求,这里却自动对准了http://localhost:8121/api/user/get/login? > > 因为你写的是拦截器,它捕获到了应用启动时自动发起的“获取当前登录用户”请求 > > 无论是你手动写的`axios.get`还是插件生成的`UserControllerService.getLoginUserUsingGet()`,只要底层使用的是同一个Axios包,都会经过定义的拦截器 > > 而根据之前的代码逻辑,`getLoginUser`会在页面加载时自动执行 > > 于是触发了拦截器 ### 用户登录功能 #### 自动登录 业务逻辑:用户在登进你的网站后你要第一时间访问服务器获取数据并更新页面 1. 在store-user.ts中编写获取远程登录用户信息的代码(vuex专门管理前端的全局变量) 2. 在哪里去触发 getLoginUser 函数的执行?应当在一个全局的位置 1. 可以用路由拦截、全局页面入口app.vue、全局通用布局等多种方式实现 2. 此处选择第一种方案,可以直接在全局权限管理的路由拦截中判断用户是否已经登录 #### 全局权限管理优化 在access下新建index.ts 将App.vue里的关于用户验证的代码移到index.ts中 App.vue: ```ts <template> <div id="app"> <BasicLayout></BasicLayout> </div> </template> <style></style> <script setup lang="ts"> import BasicLayout from "@/layouts/BasicLayout.vue"; import { onMounted } from "vue"; /** * 全局初始化函数,有全局单次调用的代码。都可以写到这里 */ const doInit = () => { console.log("hello 欢迎来到我的项目"); }; onMounted(() => { doInit(); }); </script> ``` 在main.ts中引入access ```ts import "@/access"; ``` 创建access/index.ts(好吧看样子是重新写了逻辑) ```ts import router from "@/router"; import store from "@/store"; import ACCESS_ENUM from "@/access/accessEnum"; import checkAccess from "@/access/checkAccess"; router.beforeEach(async (to, from, next) => { console.log("登录用户信息" + store.state.user.loginUser); const loginUser = store.state.user.loginUser; //如果没登陆,自动登录 //守卫会检查内存中是否有用户信息。如果没有,它会阻塞(await)后续操作,先去调用你之前写的 getLoginUser 接口 //防止用户刷新浏览器时,vuex的状态会被清空 if (!loginUser || !loginUser.userRole) { await store.dispatch("user/getLoginUser"); } //如果没有配置 access,则默认该页面是公共的(NOT_LOGIN) const needAccess = (to.meta?.access as string) ?? ACCESS_ENUM.NOT_LOGIN; //要跳转的页面需要登录 if (needAccess !== ACCESS_ENUM.NOT_LOGIN) { //如果没登录,跳转登录页 if (!loginUser || !loginUser.userRole) { next(`/user/login?redirect=${to.fullPath}`); return; } //已登录但没有权限 if (!checkAccess(loginUser, needAccess as string)) { next("/noAuth"); return; } } // if (to.meta.access === "canAdmin") { // if (store.state.loginUser?.role !== "admin") { // next("/noAuth"); // return; // } // } //如果跳转的页面是公共页面,则直接放行 next(); }); ``` 访问http://localhost:8080/admin,重定位到http://localhost:8080/user/login?redirect=/admin即可  > 笔者遇到的问题是无法重定位,依然是/noAuth > > 这里排查了原因:路由守卫里 `await store.dispatch("user/getLoginUser")` 之后,代码仍然用的是dispatch 之前的旧 `loginUser` 常量,导致它被当成“已登录但无权限”(或拿到空用户去做权限判断),于是走了 `next("/noAuth")` > > 把 `src/access/index.ts` 改成:dispatch 之后重新从 `store.state.user.loginUser` 取一次最新值,再做登录/权限判断,这样访问 `http://localhost:8080/admin` 未登录时会正确跳转到:`/user/login?redirect=/admin` > > 也就是access/index.ts的代码修改成: > > ```ts > import router from "@/router"; > import store from "@/store"; > import ACCESS_ENUM from "@/access/accessEnum"; > import checkAccess from "@/access/checkAccess"; > > router.beforeEach(async (to, _from, next) => { > let loginUser = store.state.user.loginUser; > > // 如果没登陆,自动拉取登录态(避免刷新后 vuex 清空) > if (!loginUser || !loginUser.userRole) { > await store.dispatch("user/getLoginUser"); > loginUser = store.state.user.loginUser; > } > > // 如果没有配置 access,则默认该页面是公共的(NOT_LOGIN) > const needAccess = (to.meta?.access as string) ?? ACCESS_ENUM.NOT_LOGIN; > > // 要跳转的页面需要登录 > if (needAccess !== ACCESS_ENUM.NOT_LOGIN) { > // 如果没登录,跳转登录页 > if (!loginUser || !loginUser.userRole) { > next(`/user/login?redirect=${to.fullPath}`); > return; > } > > // 已登录但没有权限 > if (!checkAccess(loginUser, needAccess as string)) { > next("/noAuth"); > return; > } > } > > next(); > }); > > ``` > > 在vuex中user.ts文件中的state删去userRole这一项 #### 支持多套布局 1. 在routes路由文件中添加一套用户路由 ```ts { path: "/user", name: "用户", component: () => import("../layouts/UserLayout.vue"), children: [ { path: "/user/login", name: "登录", component: () => import("../views/user/UserLoginView.vue"), }, { path: "/user/register", name: "注册", component: () => import("../views/user/UserRegisterView.vue"), }, ], meta: { hideInMenu: true, }, ``` 2. 新建UserLayout、UserLoginView、UserRegisterView页面,并在routes中引入 3. 在app.vue根页面文件,根据路由区分多套布局 ```ts <template v-if="route.path.startsWith('/user')"> <router-view /> </template> <template v-else> <BasicLayout /> </template> ``` ### 登录页面开发 登陆页面的核心是表单,只需要从组件库中找到表单组件,修改表单字段名称和后端完全匹配就足够了。 看个人审美吧 ```html <template> <div id="userLoginView"> <h2 style="margin-bottom: 16px">用户登录</h2> <a-form style="max-width: 480px; margin: 0 auto" label-align="left" auto-label-width :model="form" @submit="handleSubmit" > <a-form-item field="userAccount" label="账号"> <a-input v-model="form.userAccount" placeholder="请输入账号" /> </a-form-item> <a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码"> <a-input-password v-model="form.userPassword" placeholder="请输入密码" /> </a-form-item> <a-form-item> <a-button type="primary" html-type="submit" style="width: 120px"> 登录 </a-button> </a-form-item> </a-form> </div> </template> <script setup lang="ts"> import { reactive } from "vue"; import { UserControllerService, UserLoginRequest } from "../../../generated"; import message from "@arco-design/web-vue/es/message"; import { useRouter } from "vue-router"; import { useStore } from "vuex"; /** * 表单信息 */ const form = reactive({ userAccount: "", userPassword: "", } as UserLoginRequest); const router = useRouter(); const store = useStore(); /** * 提交表单 * @param data */ const handleSubmit = async () => { const res = await UserControllerService.userLoginUsingPost(form); // 登录成功,跳转到主页 if (res.code === 0) { await store.dispatch("user/getLoginUser"); router.push({ path: "/", replace: true, }); } else { message.error("登陆失败," + res.message); } }; </script> ``` 在OpenApi.ts中修改配置 ```ts export const OpenAPI: OpenAPIConfig = { BASE: "http://localhost:8121", VERSION: "1.0", //改为true WITH_CREDENTIALS: true, CREDENTIALS: "include", TOKEN: undefined, USERNAME: undefined, PASSWORD: undefined, HEADERS: undefined, ENCODE_PATH: undefined, }; ``` 不然请求头不带cookie 修改库里的userName,再次登录,会发现用户名同步改变  ### 注册页面开发 UserRegisterView.vue ```vue <template> <div id="userRegisterView"> <h2 style="margin-bottom: 16px">用户注册</h2> <a-form style="max-width: 480px; margin: 0 auto" label-align="left" auto-label-width :model="form" @submit="handleSubmit" > <a-form-item field="userAccount" label="账号"> <a-input v-model="form.userAccount" placeholder="请输入账号" /> </a-form-item> <a-form-item field="userPassword" tooltip="密码不少于 8 位" label="密码"> <a-input-password v-model="form.userPassword" placeholder="请输入密码" /> </a-form-item> <a-form-item field="checkPassword" tooltip="密码不少于 8 位" label="确认密码" > <a-input-password v-model="form.checkPassword" placeholder="请与密码一致" /> </a-form-item> <a-form-item> <a-button type="primary" html-type="submit" style="width: 120px"> 登录 </a-button> </a-form-item> </a-form> </div> </template> <script setup lang="ts"> import { reactive } from "vue"; import { UserControllerService, UserRegisterRequest } from "../../../generated"; import message from "@arco-design/web-vue/es/message"; import { useRouter } from "vue-router"; /** * 表单信息 */ const form = reactive({ userAccount: "", userPassword: "", checkPassword: "", } as UserRegisterRequest); const router = useRouter(); /** * 提交表单 * @param data */ const handleSubmit = async () => { if (form.userPassword !== form.checkPassword) { message.error("两次输入的密码不一致"); return; } const res = await UserControllerService.userRegisterUsingPost(form); // 注册成功,跳转到主页 if (res.code === 0) { router.push({ path: "/user/login", replace: true, }); } else { message.error("注册失败," + res.message); } }; </script> ```
有大佬帮忙远程布局部署一下鱼皮的oj判题系统吗?有偿
请问一下老师,在OJ 项目中,权限拦截那 使用的是: Spring Cloud Gateway 的 Filter 请求拦截器(内部接口拦截) + (可以进行扩展的 JWT token 实现)。 我想根据目前学到的知识,这样做是否可以: Spring Cloud Gateway 的 Filter 请求拦截器 (内部接口拦截) + @AuthCheck 自定义注解 + AOP 切面 这种方法实现的,业务逻辑是否可行?
请问一下,OJ 项目的 rabbitMQ ,之前电脑装过 3.11.10版本,看到课程中使用的是 3.12.4 的版本,请问我如果不换还是使用之前的版本是否可行?
各位同学好,在做 OJ 项目,做到了 java 操作 docker,遇到了这个问题卡住了。自己目前做过以下修改,添加netty 依赖,想使用 netty 代替 Jersey HTTP 失败。尝试linux上添加 配置文件也是失败。 卡了好久,谢谢各位老师。
老鱼OJ的项目,被问到这样一个问题,有uu们知道怎么回答吗? 通过rabbitmq将判题请求异步地执行,代码沙箱是不是需要处理完一个题目,才继续处理下一个题目?如果有1000个题目,那前端等待判题结果的时间是否太长了?符合实际应用吗?
🚀 编程导航成品项目(上百个真实项目)
编程导航已累计发布数十套项目教程:[课程地址](https://www.codefather.cn/course)。 为方便大家集中学习参考,也帮助已完成项目的同学获得更多曝光与真实用户,我们整理汇总了过往提交的优质项目帖。 🔍 如果你的项目已提交,欢迎确认是否被收录; 🚀 如果你正在开发中,不妨参考已有项目的实现思路与笔记总结,相信对你有帮助。 > 收录说明:若你的项目文章尚未被收录,欢迎评论区留言:项目文章链接 + 线上地址(如有),管理员会定期更新到汇总帖里,助力每一个认真分享的项目被更多人看见~ ## AI 零代码应用生成平台 企业级项目教程:https://codefather.cn/course/1948291549923344386 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### CodeLoom(已上线) 👉 线上地址:http://1.15.243.228:9010/CodeLoom/ 📚 原帖链接:https://codefather.cn/post/1960256724123316226   #### AI Code Mother(已上线) 👉 线上地址:https://joinoai.cloud/user/register?inviteCode=INVNJZKYSJH 📚 原帖链接:https://codefather.cn/post/1974436661408411649   #### 代码灵构 📚 原帖链接:https://codefather.cn/note/1957033275842670593   #### XiangAI 📚 原帖链接:https://codefather.cn/essay/1957335221259333633   #### AI Code easen 📚 原帖链接:https://codefather.cn/post/1954389275447824386   ## AI 超级智能体 企业级项目教程:https://codefather.cn/course/1915010091721236482 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### Crispix Agent 📚 原帖链接:https://codefather.cn/post/1962528203403792386  #### ApocalyxAI(智能助手平台) 📚 原帖链接:https://codefather.cn/post/1937413626668843010   #### 神农医慧库 📚 原帖链接:https://codefather.cn/post/1936010788000563201  #### AI 智能应用中心 📚 原帖链接:https://codefather.cn/post/1928019148442537985  #### CodeManus AI 助手 📚 原帖链接:https://codefather.cn/post/1966800552892235778   ## 智能协同云图库项目项目 企业级项目教程:https://codefather.cn/course/1864210260732116994 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 悦木图库(已上线) 👉 线上地址:https://lumenglover.com/ 📚 原帖链接:https://codefather.cn/essay/1890067861869486081   #### 暴龙图库(已上线) 👉 线上地址:https://picture.baolong.icu/ 📚 原帖链接:https://codefather.cn/post/1905997569888280577   #### Crispix AI 图库(已上线) 👉 线上地址:https://crispix.fun 📚 原帖链接:https://codefather.cn/post/1915861894909386754   #### 云图智联(已上线) 👉 线上地址:https://imagecore.netlify.app/ 📚 原帖链接:https://codefather.cn/post/1970098502037934081   #### 荒梦图库(已上线) 👉 线上地址:https://pichm.cloud/ 📚 原帖链接:https://codefather.cn/post/1960673049771610113   #### Picazza 图库(已上线) 👉 线上地址:https://picazza.com/ 📚 原帖链接:https://www.codefather.cn/post/1945659153240215554   #### 悦突突(已上线) 👉 线上地址:https://coder-live.cn/ 📚 原帖链接:https://codefather.cn/post/1950740016980426754   #### 图潮(已上线) 👉 线上地址:https://picwave.top/ 📚 原帖链接:https://codefather.cn/essay/1911024578559188993   #### 云相册(已上线) 👉 线上地址:https://pic.lin03.cn/ 📚 原帖链接:https://codefather.cn/post/1929477619980566530   #### HY 映像(已上线) 👉 线上地址:https://zhydoc.com/picture/ 📚 原帖链接:https://codefather.cn/post/1967843032026775553  #### 智图云链(已上线) 👉 线上地址:http://117.72.69.235/  #### han_picture 📚 原帖链接:https://codefather.cn/post/1974327430218887170   ## 面试刷题平台 企业级项目教程:https://codefather.cn/course/1826803928691945473 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 面试秘境(已上线) 👉 线上地址:http://mianshimijing.icu/ 📚 原帖链接:https://codefather.cn/post/1869660024067571713   ## AI 答题应用平台 企业级项目教程:https://codefather.cn/course/1790274408835506178 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 腾蛇问渊(已上线) 👉 线上地址:https://aianswerproj.vercel.app/ 📚 原帖链接:https://codefather.cn/essay/1809498338799878146  #### 智慧答 📚 原帖链接:https://codefather.cn/post/1826490068167761921   ## OJ 在线判题系统 企业级项目教程:https://codefather.cn/course/1790980707917017089 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 雪 OJ(已上线) 👉 线上地址:http://snowyee.cn/snowyee-oj/#/ 📚 原帖链接:https://codefather.cn/note/1810751001442844674   #### 流火 OJ 📚 原帖链接:https://codefather.cn/post/1827575600860672001   #### SSPU-OJ 📚 原帖链接:https://codefather.cn/post/1964988539086487554   #### 新 OJ 📚 原帖链接:https://codefather.cn/note/1806522941518364673   #### HHOJ 📚 原帖链接:https://codefather.cn/post/1895681485945774082   #### AICoder OJ 📚 原帖链接:https://codefather.cn/note/1811051057198858241  📚 原帖链接:https://codefather.cn/note/1829734814391640065   #### CsCS OJ 📚 原帖链接:https://codefather.cn/post/1836003849697837057  #### 疯 OJ 📚 原帖链接:https://codefather.cn/post/1913879429893369857   ## 代码生成器共享平台 企业级项目教程:https://codefather.cn/course/1790980795074654209 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 飞云代码生成 📚 原帖链接:https://codefather.cn/note/1816913082742140930  ## 智能 BI 项目 企业级项目教程:https://codefather.cn/course/1790980531403927553 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 灵犀 BI(已上线) 👉 线上地址:http://bi.hejiajun.icu/ 📚 原帖链接:https://codefather.cn/post/1876163793297530881  #### Kim 智能 BI 📚 原帖链接:https://codefather.cn/post/1908147328172138498   #### Liy 智能 BI 分析系统 👉 线上地址:https://8.141.7.82/login 📚 原帖链接:https://codefather.cn/essay/1853271746140782593   #### Admin 智能 BI 分析系统 📚 原帖链接:https://codefather.cn/post/1812563734513770498   #### Flance 智能 BI 系统 📚 原帖链接:https://codefather.cn/note/1813731731964133378   #### AI 洞察 📚 原帖链接:https://codefather.cn/post/1816913159401435138    #### hx BI 📚 原帖链接:https://codefather.cn/post/1812563043074367490   #### Solar BI 📚 原帖链接:https://codefather.cn/note/1816551710832824322   #### 哥布林智能 BI 分析系统 📚 原帖链接:https://codefather.cn/note/1811050100016742402   #### PS 智能 BI 分析系统 📚 原帖链接:https://codefather.cn/note/1810278024374505474   #### ToolVerse:一体化智能管理与创新服务平台 📚 原帖链接:https://codefather.cn/post/1810389203533025282   #### Nero 智能 BI 分析系统 📚 原帖链接:https://codefather.cn/note/1811010648561090562   #### GBC 智能 BI 分析系统 📚 原帖链接:https://codefather.cn/note/1808941076960215041   ### 聚合搜索平台 企业级项目教程:https://codefather.cn/course/1790979621621641217 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 空空-聚合搜索平台 📚 原帖链接:https://codefather.cn/note/1924150587763404802   #### 崽崽聚合搜索平台 📚 原帖链接:https://codefather.cn/note/1817637092455018497   #### 青年聚合搜索平台 📚 原帖链接:https://codefather.cn/post/1825764402195537921  ### API 开放平台 企业级项目教程:https://codefather.cn/course/1790979723916521474 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### Qi-API 接口开放平台(已上线) 👉 线上地址:https://api.qimuu.icu/user/login 📚 原帖链接:https://codefather.cn/note/1805877794735435778   #### 羊腿 API 开放平台(已上线) 👉 线上地址:http://api.panyuwen.top/user/login 📚 原帖链接:https://codefather.cn/note/1855478010485653505    #### Cxm-API 接口开放平台 📚 原帖链接:https://codefather.cn/essay/1905452207706185730    #### LeAPI 接口开放平台 📚 原帖链接:https://codefather.cn/note/1816551310788497409   #### X API 开放调用平台 📚 原帖链接:https://codefather.cn/note/1816913304989921281   #### Adagio 接口开放平台 📚 原帖链接:https://codefather.cn/note/1816551835571425281   #### 聚合 API 开放平台 📚 原帖链接:https://codefather.cn/note/1811049203207438337   #### EasyAPI 开放平台 📚 原帖链接:https://codefather.cn/note/1832713500474793986   #### 洛言接口开放平台 📚 原帖链接:https://codefather.cn/post/1828449609845428226  #### k 接口开放平台 📚 原帖链接:https://codefather.cn/note/1808772929765376001  #### 为-接口开放平台 📚 原帖链接:https://codefather.cn/note/1811050695448526849   #### API 接口服务平台 📚 原帖链接:https://codefather.cn/post/1839933551062880258  #### 银竹接口开放平台 📚 原帖链接:https://codefather.cn/post/1810389203533025282   #### Insight平台 📚 原帖链接:https://codefather.cn/post/1812563734513770498  ### 伙伴匹配系统 企业级项目教程:https://codefather.cn/course/1790950013153095682 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### homie 伙伴匹配系统(已上线) 👉 线上地址:http://hm.hejiajun.icu/ 📚 原帖链接:https://codefather.cn/note/1823592419365535746   #### 花语-伙伴匹配系统(已上线) 👉 线上地址:http://huayu.hanades.online  #### 速配 SUPER - 伙伴匹配系统(已上线) 👉 线上地址:https://ochiamalu.fun/ 📚 原帖链接:https://codefather.cn/essay/1909073423851560961   #### yes - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/post/1811047157863481345   #### 等闲 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1812741780545921026   #### 鱼泡 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1806571986623836161   #### Louis - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1806569725122228226  #### 知秋 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1816551544797106177   #### 小虎 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1814012455103463426  #### 龙 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1818361301050142721   #### w - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1838446471885594625   #### 云交友 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/post/1825763690480869378   #### 大学生 - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/note/1820898093159849986   #### Yz - 伙伴匹配系统 📚 原帖链接:https://codefather.cn/essay/1870039737155010561   ### 用户中心项目 企业级项目教程:https://codefather.cn/course/1790943469757837313 > 视频教程 + 项目文档 + 源码 + 简历写法 + 面试题解 + 专属交流群 #### 可乐用户中心(已上线) 👉 线上地址:http://user.xykcola.site/user/login 📚 原帖链接:https://codefather.cn/note/1811475602152685570   #### (NextJS 版)用户中心管理 📚 原帖链接:https://codefather.cn/post/1912880102888280065  #### chen 用户中心 📚 原帖链接:https://codefather.cn/note/1811050198691938306   #### Find Me 用户中心 📚 原帖链接:https://codefather.cn/note/1811342501757911041   #### 小汉用户中心 📚 原帖链接:https://codefather.cn/note/1810181026137473026   #### 用户中心 📚 原帖链接:https://codefather.cn/post/1925206864866131970   #### 吃鱼用户中心 📚 原帖链接:https://codefather.cn/post/1896897093685288961  📚 原帖链接:https://codefather.cn/note/1811049194567172097  #### 崽崽用户中心 📚 原帖链接:https://codefather.cn/note/1817637102550708225   #### Jiaxiong 用户中心 📚 原帖链接:https://codefather.cn/note/1815828758460895233  
想问一下,我做完了OJ项目,但是我的服务器是2核2G,实际内存好像都没到2G,就1.7G好像,启动了nacos这些之后,再启动后端,会直接把nacos强制退出导致启动不了,这样有什么解决办法吗?
oj项目微服务版本 启动后打开接口文档 Knife4j文档请求异常 怎么解决 后台也没报错
学习打卡
学习打卡 oj项目前后端联调 哪位老能给一些建议,,,前端几乎不懂,仅了解三件套和vue,仅仅是了解,前端该怎么学习呢,后端能看懂代码,但是实践上机很差。。。 目前做的项目有黑马点评还有AI智能体,几乎都是照着代码敲的,如何才能做到九月份前找到实习呢
