基于koa服务端脚手架搭建(文件加载器) --【elpis全栈项目笔记】

news2024/12/24 1:40:08

基于koa服务端脚手架(文件加载器) --【elpis-core】


前言: elpis-core 是一个项目文件加载器。基于一定的约定,将功能不同的代码分类放置到不同的目录下管理。适用于项目代码规范化、减少维护成本、沟通成本,易于扩展。(简易版的 egg-core )

请添加图片描述
其目的,就是将各类约定好的文件夹下的js方法,自动挂载到全局的app的实例上。(这只是其中一类实例,更多请看后文)

|-- app
	|-- controller
		|-- project.js
	|-- ...

// 在别的文件下 每次使用都需要手动引入 project.js 文件
const projController = require('app/controller/project.js');
projController.getList()

// ==> 接入 elpis-core 之后

// 只需将 project.js 放入 controller 文件夹下,会自动挂载到app实例上
const projController = app.controller.project
projController.getList()

一、 elpis-core 目录结构


在这里插入图片描述

|-- app
|-- ...
|-- elpis-core
	|-- loader
		|-- config.js 					解析环境配置
		|-- controller.js				解析公共业务逻辑
		|-- extend.js 					解析加载外部工具类
		|-- middleware.js 				解析中间件
		|-- router-schema.js 			解析路由校验规则
		|-- router.js 					解析注册路由
		|-- service.js					解析服务模块
	|-- env.js							判断环境
	|-- index.js 						引擎入口文件
|-- index.js 项目入口文件

项目入口文件,引入/启动 elpis-core:

const ElpisCore = require('./elpis-core');
// 启动项目
ElpisCore.start({name: 'Elpis',homePage: '/'});

引擎入口文件, 加载各个处理器:

const Koa = require('koa');
const env = require('./env')
const configLoader = require('./loader/config'); 
const middlewareLoader = require('./loader/middleware');
...
module.exports = {
  start(options = {}) {
    const app = new Koa(); // koa 实例
    app.baseDir = process.cwd() // 基本路径
    app.env = env();  // 初始化环境配置
    controllerLoader(app) // 加载contorller处理器
    configLoader(app) // 加载config处理器
    ... 
    
    // 启动服务
    try {
      const port = process.env.PORTB || 8080;
      const host = process.env.IP || '0.0.0.0';
      app.listen(port, host);
      console.log(`\n --- 🚀 Server running at http://localhost:${port} 🚀 --- \n`);
    } catch (e) {
      console.error(e);
    }
  }
}

二、解析环境配置 – config.js


要实现的功能:基于当前环境,读取当前环境对象的config配置,可通过app.config读取当前环境配置。

|-- app
|-- config
	|-- config.default.js
	|-- config.local.js
	|-- config.beta.js
	|-- config.prod.js

// config.prod.js
module.exports = {name:'生产', ...}

// 生产环境调用时:
const prodName = app.config.name

处理器实现:

const path = require('path');
const { sep } = path

/**
 * config loader
 * @param {object} app koa实例 
 * 
 * 配置区分 本地/测试/生产 环境, 通过 env 环境读取不同文件配置
 * 通过 env.config 覆盖 default.config 加载到 app.config 中
 * 
 * 目录下对应的 config 配置
 * 默认配置 config/config.default.js
 * 本地环境配置 config/config.local.js
 * 测试环境配置 config/config.beta.js
 * 生产环境配置 config/config.prod.js
 */

module.exports = (app) => {
  // 获取 config/ 目录
  const configPath = path.resolve(app.baseDir, `.${sep}config`);

  // 获取 default.config
  let defaultConfig = {};
  try {
    defaultConfig = require(path.resolve(configPath, `.${sep}config.default.js`));
  } catch (e) {
    console.log('[exceprion] there is no default.config file')
  }

  // 获取 env.config
  let envConfig = {};
  try {
    if (app.env.isLocal()) { // 本地环境
      envConfig = require(path.resolve(configPath, `.${sep}config.local.js`))
    } else if (app.env.isBeta()) {  // 测试环境
      envConfig = require(path.resolve(configPath, `.${sep}config.beta.js`))
    } else if (app.env.isProd()) {  // 生产环境
      envConfig = require(path.resolve(configPath, `.${sep}config.prod.js`))
    }
  } catch (e) {
    console.log('[exceprion] there is no default.envConfig file')
  }

  // 覆盖并加载 config 配置
  app.config = { ...defaultConfig, ...envConfig }
}

三、 解析业务逻辑-- controller.js


要实现的功能:读取controller文件夹,挂载到app实例上,使其中的函数可通过app.controller.xxx.getxxx()调用

|-- app
	|-- controller
		|-- base.js
		|-- project.js
		|-- view.js

// project.js
module.exports = (app) => {
  const BaseController = require('./base')(app)
  return class ProjectController extends BaseController {
    async getList(ctx) {}
  }
}

// 被router文件调用时:
module.exports = (app, router) => {
  const { project: projectController } = app.controller
  router.get('/api/project/list', projectController.getList.bind(projectController))
}

处理器实现:

const glob = require('glob');
const path = require('path')
const { sep } = path

/**
 *  controller loader
 * @param {object} app koa 实例
 * 
 * 加载所有 controller,,可通过`app.controller.${目录}.${文件}`访问 
 * 
 * 例子:
 * app/controller
 *   |
 *   | -- custom-module
 *           |
 *           | -- custom-controller.js
 * 
 * => app.controller.customname.customController
 */

module.exports = (app) => {
  // 读取app/controller/**/**.js 所有文件
  const controllerPath = path.resolve(app.businessPath, `.${sep}controller`);
  const fileList = glob.sync(path.resolve(controllerPath, `.${sep}**${sep}**.js`));

  // 遍历所有文件目录,把内容加载到 app.controller 下
  const controller = {}
  fileList?.forEach(file => {
    //提取文件名
    let name = path.resolve(file)

    // 截取路径 app/controller/custom-module/custom-controller.js => custom-module/custom-controller
    name = name.substring(name.lastIndexOf(`controller${sep}`) + `controller${sep}`.length, name.lastIndexOf('.'));

    // 把'-'统一改为驼峰式, custom-module/custom-controller.js => customModule/customController
    name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());

    //挂载 controller 到内存 app 对象中;  tempController === { customModule:{ customController:{ } } }
    let tempController = controller;
    const names = name.split(sep)
    for (let i = 0, len = names.length; i < len; ++i) {
      if (i === len - 1) {
        const ControllerModule = require(path.resolve(file))(app)
        tempController[names[i]] = new ControllerModule()
        return
      } else {
        if (!tempController[names[i]]) {
          tempController[names[i]] = {}
        }
        tempController = tempController[names[i]]
      }
    }
  })
  app.controller = controller
}

四、解析外部工具类 – extend.js


要实现的功能:读取extend文件夹,挂载到app实例上,使其中的函数可通过app.xxx.xxx()调用

|-- app
	|-- extend
		|-- logger.js

// logger.js
module.exports = (app) => {
   let logger
   ...
   logger = log4js.getLogger();
   ...
   return logger
}

// 被其他文件调用时:
module.exports = (app, router) => {
	...
   app.logger.info('info');
   app.logger.error('error');
}

处理器实现:

const glob = require('glob');
const path = require('path')
const { sep } = path

/**
 *  extend loader
 * @param {object} app koa 实例
 * 
 * 加载所有 extend,,可通过`app.extend.${文件}`访问 
 * 
 * 例子:
 * app/extend
 *   |
 *   | -- custom-extend.js
 * 
 * => app.extend.customExtend 访问
 */

module.exports = (app) => {
  // 读取app/extend/**/**.js 所有文件
  const extendPath = path.resolve(app.businessPath, `.${sep}extend`);
  const fileList = glob.sync(path.resolve(extendPath, `.${sep}**${sep}**.js`));

  // 遍历所有文件目录,把内容加载到 app.extend 下
  fileList?.forEach(file => {
    //提取文件名
    let name = path.resolve(file)

    // 截取路径 app/extend/custom-extend.js => custom-extend
    name = name.substring(name.lastIndexOf(`extend${sep}`) + `extend${sep}`.length, name.lastIndexOf('.'));

    // 把'-'统一改为驼峰式, custom-extend.js => customExtend
    name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());

    // 过滤 app 已经存在的key
    for (const key in app) {
      if (key === name) {
        console.warn(`[extend load error] ${name} is already in app`)
        return
      }
    }

    //挂载 extend 到内存 app 对象中;  
    app[name] = require(path.resolve(file))(app)
  })
}

五、解析中间件 – middleware.js


要实现的功能:读取middleware文件夹,挂载到app实例上,使其可通过app.middlewares.xxx调用

|-- app
	|-- middleware
		|-- error-handler.js

// error-handler.js
module.exports = (app) => {
 return async (ctx, next) => {
    try {
      await next()
    } catch (err) {   // 异常处理
    	...
      const resBody = { success: false, code: 5000, message: '网络异常,请稍后再试' }
      ctx.status = 200;
      ctx.body = resBody;
    }
  }
}

// 使用全局 middlewares.js 统一维护引入时:
module.exports = (app, router) => {
  app.use(app.middlewares.errorHandler);  // 引入异常捕获中间件
  app.use(xxx)
  ...
}

处理器实现:

const glob = require('glob');
const path = require('path')
const { sep } = path

/**
 *  middleware loader
 * @param {object} app koa 实例
 * 
 * 加载所有 middleware,,可通过`app.middleware.${目录}.${文件}`访问 
 * 
 * 例子:
 * app/middleware
 *   |
 *   | -- custom-module
 *           |
 *           | -- custom-middleware.js
 * 
 * => app.middlleware.customname.customMiddleware
 */

module.exports = (app) => {
  // 读取app/middleware/**/**.js 所有文件 
  const middlewarePath = path.resolve(app.businessPath, `.${sep}middleware`);
  const fileList = glob.sync(path.resolve(middlewarePath, `.${sep}**${sep}**.js`));

  // 遍历所有文件目录,把内容加载到 app.middlewares 下
  const middleware = {}
  fileList?.forEach(file => {
    //提取文件名
    let name = path.resolve(file)

    // 截取路径 app/middleware/custom-module/custom-middleware.js => custom-module/custom-middleware
    name = name.substring(name.lastIndexOf(`middleware${sep}`) + `middleware${sep}`.length, name.lastIndexOf('.'));

    // 把'-'统一改为驼峰式, custom-module/custom-middleware.js => customModule/customMiddleware
    name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());

    //挂载 middleware 到内存 app 对象中;  tempMiddleware === { customModule:{ customMiddleware:{ } } }
    let tempMiddleware = middleware;
    const names = name.split(sep)
    for (let i = 0, len = names.length; i < len; ++i) {
      if (i === len - 1) {
        tempMiddleware[names[i]] = require(path.resolve(file))(app)
        return
      } else {
        if (!tempMiddleware[names[i]]) {
          tempMiddleware[names[i]] = {}
        }
        tempMiddleware = tempMiddleware[names[i]]
      }
    }
  })

  app.middlewares = middleware
}

koa中间件有一个需要特别关注的地方:洋葱圈模型; 有时间需要单独写一篇;
网友的: 浅谈 Koa 和 Express 的中间件设计模式

六、解析路由校验规则 – router-schema.js


要实现的功能:读取router-schema文件夹,挂载到app实例上,使其可通过app.routerSchema.xxx调用

|-- app
	|-- router-schema
		|-- project.js


// project.js 是 '/api/project/list' 接口的参数校验规则
module.exports = {
  '/api/project/list': {
    get: {
      query: {
        type: 'object',
      	... 
        required: ['id']
      }
    }
  }
}

// 在API参数校验的中间件 api-params-verify.js 中使用时:
module.exports = (app, router) => {
  return async (ctx, next) => {
  	 const { query } = ctx.request;
	 const { path } = ctx;
	 const schema = app.routerSchema[path]?.[method.toLowerCase()];
	 ...
	 validate = ajv.compile(schema.query)
     valid = validate(query)
     ...
  }
}

处理器实现:

const glob = require('glob');
const path = require('path')
const { sep } = path

/**
 * router-schema loader
 * @param {object} app koa实例 
 * 
 * 通过 'json-schema' & 'ajv' 对 api规则进行约束,配合 api-params-verify 中间件使用
 * 
 * app/router-schema/api1.js  // { 'api1/data/getDetail' :{} } 
 * app/router-schema/api2.js  // { 'api2/data/getDetail' :{} } 
 * ...
 * 
 * 输出:
 *   app.routerSchema = {
 *      'api1/data/getDetail':{},
 *      'api2/data/getDetail':{},
 *     ...
 *   }
 */

module.exports = (app) => {
  // 读取app/router-schema/**/**.js 所有文件 
  const middlewarePath = path.resolve(app.businessPath, `.${sep}router-schema`);
  const fileList = glob.sync(path.resolve(middlewarePath, `.${sep}**${sep}**.js`));

  // 注册所有 routerSchema, 使得 app.routerSchema 可以访问
  let routerSchema = {}
  fileList.forEach(file => {
    routerSchema = {
      ...routerSchema,
      ...require(path.resolve(file))
    }
  });
  app.routerSchema = routerSchema
}

七、解析注册路由 – router.js


要实现的功能:读取router文件夹,引入每个文件的’/xxx/xxx/...‘接口,将其直接注册到koaRouter

|-- app
	|-- router
		|-- project.js

// project.js 
module.exports = (app, router) => {
  const { project: projectController } = app.controller
  router.get('/api/project/list', projectController.getList.bind(projectController))
}

// rouer.js 处理器会遍历所有路由,引入并注册
module.exports = (app) => {
	...
	fileList.forEach(file => {require(path.resolve(file))(app, router) }); // 将遍历到的所有路由引入
	...
	app.use(router.routes()); // 注册
  	app.use(router.allowedMethods()); // 自动响应不支持的 HTTP 方法
}

处理器实现:

const KoaRouter = require('koa-router');
const glob = require('glob');
const path = require('path');
const { sep } = path;

/**
 * router loader
 * @param {object} app koa实例
 * 
 * 解析所有 app/router/ 下所有 js 文件, 加载到 KoaRouter 下
 * 
 */

module.exports = (app) => {
  // 找到路由文件路径
  const routerPath = path.resolve(app.businessPath, `.${sep}router`);
  // 实例化所有路由
  const router = new KoaRouter();

  // 注册所有路由
  const fileList = glob.sync(path.resolve(routerPath, `.${sep}**${sep}**.js`));
  fileList.forEach(file => {
    require(path.resolve(file))(app, router);
  });

  // 路由兜底(健壮性)
  router.get('*', async (ctx, next) => {
    ctx.status = 302; // 临时重定向
    ctx.redirect(`${app?.options?.homePath ?? '/'}`);
  })

  // 路由注册到 app 上
  app.use(router.routes());
  app.use(router.allowedMethods()); 
}

八、解析服务模块-- service.js


要实现的功能:读取service文件夹,挂载到app实例上,使其可通过app.service.xxx调用

|-- app
	|-- service
		|-- base.js
		|-- project.js

// project.js 
module.exports = (app) => {
  const BaseService = require('./base')(app)
  return class ProjectService extends BaseService {
    async getList() {return '数据库拿到的数据'}
  }
}

// 在 controller 中处理接口请求的业务逻辑时: 直接调用app.service
module.exports = (app) => {
  ...
  return class ProjectController extends BaseController {
    async getList(ctx) {
      const { project: projectService } = app.service;
      const projectList = await projectService.getList();
      this.success(ctx, projectList);
    }
  }
}

处理器实现:

const glob = require('glob');
const path = require('path')
const { sep } = path

/**
 *  service loader
 * @param {object} app koa 实例
 * 
 * 加载所有 service,,可通过`app.service.${目录}.${文件}`访问 
 * 
 * 例子:
 * app/service
 *   |
 *   | -- custom-module
 *           |
 *           | -- custom-service.js
 * 
 * => app.service.customname.customService
 */

module.exports = (app) => {
  // 读取app/service/**/**.js 所有文件
  const servicePath = path.resolve(app.businessPath, `.${sep}service`);
  const fileList = glob.sync(path.resolve(servicePath, `.${sep}**${sep}**.js`));

  // 遍历所有文件目录,把内容加载到 app.service 下
  const service = {}
  fileList?.forEach(file => {
    //提取文件名
    let name = path.resolve(file)

    // 截取路径 app/service/custom-module/custom-service.js => custom-module/custom-service
    name = name.substring(name.lastIndexOf(`service${sep}`) + `service${sep}`.length, name.lastIndexOf('.'));

    // 把'-'统一改为驼峰式, custom-module/custom-service.js => customModule/customService
    name = name.replace(/[_-][a-z]/ig, (s) => s.substring(1).toUpperCase());

    //挂载 service 到内存 app 对象中;  tempService === { customModule:{ customService:{ } } }
    let tempService = service;
    const names = name.split(sep)
    for (let i = 0, len = names.length; i < len; ++i) {
      if (i === len - 1) {
        const SerivceModule = require(path.resolve(file))(app)
        tempService[names[i]] = new SerivceModule()
        return
      } else {
        if (!tempService[names[i]]) {
          tempService[names[i]] = {}
        }
        tempService = tempService[names[i]]
      }
    }
  })

  app.service = service
}

了解更多:
核心体系egg-core
阮一峰Koa 框架教程


至此elpis-core的核心功能已基本实现

全文特别鸣谢: 抖音“哲玄前端”,《全栈实践课》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2264485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AQS源码学习

一、park/unpark阻塞唤醒线程 LockSupport是JDK中用来实现线程阻塞和唤醒的工具。使用它可以在任何场合使线程阻塞&#xff0c;可以指定任何线程进行唤醒&#xff0c;并且不用担心阻塞和唤醒操作的顺序&#xff0c;但要注意连续多次唤醒的效果和一次唤醒是一样的。JDK并发包下…

【漏洞复现】CVE-2023-37461 Arbitrary File Writing

漏洞信息 NVD - cve-2023-37461 Metersphere is an opensource testing framework. Files uploaded to Metersphere may define a belongType value with a relative path like ../../../../ which may cause metersphere to attempt to overwrite an existing file in the d…

02-1:python入门基础Python变量与数据类型

一、Python 变量的定义 &#xff08;一&#xff09;定义方式 在 Python 中&#xff0c;变量的定义是通过赋值来实现的&#xff0c;其语法格式非常简洁直观&#xff0c;基本形式为 “变量名 值”。等号左边是你自定义的变量名&#xff0c;右边则是要赋给该变量的值。Python 是…

在Vue3中实现文件上传功能,结合后端API

随着现代Web应用程序的不断发展&#xff0c;文件上传成为了用户交互中不可或缺的一部分。在本篇博客中&#xff0c;我们将深入讨论如何在Vue3中实现一个文件上传功能&#xff0c;并与后端API进行交互。我们将使用Vue3的Composition API&#xff08;setup语法糖&#xff09;来构…

详细ECharts图例3添加鼠标单击事件的柱状图

<!DOCTYPE html><html><head><meta charset"UTF-8"><script src"js/echarts.js"></script> <!-- 确保路径正确 --><title>添加鼠标单击事件的柱状图</title></head><body><div id&q…

Redis Hash Tag 知识详解

一、Redis Hash Tag概述 Redis Hash Tag是Redis集群环境里用于控制数据分片的关键机制。在Redis集群中&#xff0c;数据依据键的哈希值来确定分片存储位置。Hash Tag能让用户指定键的特定部分作为哈希计算核心部分&#xff0c;进而使相关键存储于同一节点&#xff0c;这对处理…

Java 初学者的第一个 SpringBoot3.4.0 登录系统二

Java 初学者的第一个 SpringBoot3.4.0 登录系统二 SpringBoot 3.4.0 是 SpringBoot 的最新版本&#xff0c;是乐衷与新技术的 Java 初学者和程序员的选择。和 SpringBoot3.4.0 搭配的各种软件组件也是新的潮流。Java 通用代码生成器光&#xff0c;2.4.0 电音之王尝鲜版十支持新…

SSH客户端

SSH客户端 在VMware界面中操作虚拟机非常不友好&#xff0c;所以一般推荐使用专门的SSH客户端。市面上常见的有&#xff1a; Xshell&#xff1a;个人免费&#xff0c;商业收费&#xff0c;之前爆出过有隐藏后门。不推荐Finshell&#xff1a;基础功能免费&#xff0c;高级功能…

python小课堂(一)

基础语法 1 常量和表达式2 变量和类型2.1 变量是什么2.2 变量语法 3 变量的类型3.1 动态类型特性 4 注释4.1注释是什么 5 输入输出5.1 print的介绍5.2 input 6 运算符6.1 算术运算符在这里插入图片描述6.2 关系运算符6.3 逻辑运算符6.4赋值运算符 1 常量和表达式 在print()中可…

java中的方法的重载和重写、构造器

目录 方法的重载和重写、构造器1.java的修饰符&#xff1a;2.普通方法3.构造器&#xff08;也叫构造方法/构造函数&#xff09;4.方法的重载5.补充6.方法的重写7.类的执行顺序8.再看方法的重写 方法的重载和重写、构造器 1.java的修饰符&#xff1a; public修饰的代码&#xf…

Halcon例程代码解读:安全环检测(附源码|图像下载链接)

安全环检测核心思路与代码详解 项目目标 本项目的目标是检测图像中的安全环位置和方向。通过形状匹配技术&#xff0c;从一张模型图像中提取安全环的特征&#xff0c;并在后续图像中识别多个实例&#xff0c;完成检测和方向标定。 实现思路 安全环检测分为以下核心步骤&…

前端知识补充—HTML

1. HTML 1.1 什么是HTML HTML(Hyper Text Markup Language), 超⽂本标记语⾔ 超⽂本: ⽐⽂本要强⼤. 通过链接和交互式⽅式来组织和呈现信息的⽂本形式. 不仅仅有⽂本, 还可能包含图⽚, ⾳频, 或者⾃已经审阅过它的学者所加的评注、补充或脚注等等 标记语⾔: 由标签构成的语⾔…

springboot根据租户id动态指定数据源

代码地址 码云地址springboot根据租户id动态指定数据源: springboot根据租户id指定动态数据源,结合mybatismysql多数源下的事务管理 创建3个数据库和对应的表 sql脚本在下图位置 代码的执行顺序 先设置主数据库的数据源配置目标数据源和默认数据源有了主库的数据源&#xff…

powershell美化

powershell美化 写在前面 除了安装命令&#xff0c;其他都是测试命令&#xff0c;后续再写进配置文件 安装主题控件 安装主题oh-my-posh&#xff0c;powershell中执行 winget install JanDeDobbeleer.OhMyPosh -s winget oh-my-posh init pwsh | Invoke-Expression # 查看…

Docker监控新纪元:Prometheus引领高效容器监控革命

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 •座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言&…

arcgisPro将面要素转成CAD多段线

1、说明&#xff1a;正常使用【导出为CAD】工具&#xff0c;则导出的是CAD三维多线段&#xff0c;无法进行编辑操作、读取面积等。这是因为要素面中包含Z值&#xff0c;导出则为三维多线段数据。需要利用【复制要素】工具禁用M值和Z值&#xff0c;再导出为CAD&#xff0c;则得到…

R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)

1. 上下标 # 注意y轴标签文字 library(ggplot2) ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))2. 希腊字母&#xff0c;如alpha ggplot(mtcars, aes(mpg, cyl))geom_point()ylab(label bquote(O[3]~(ug / m^3)))ggtitle(expression(alpha))…

WebContainerapi 基础(Web IDE 技术探索 一)

前言 随着web技术的发展&#xff0c;在网页端直接运行node.js、实现微型操作系统已经不再是难事。今天介绍的 WebContainers就是一个基于浏览器的运行时&#xff0c;用于执行 Node.js 应用程序和操作系统命令&#xff0c;它完全运行在您的浏览器页面中&#xff0c;提供了文件系…

解决pytorch安装中的三个错误

查明已安装python版本为3.12.7后&#xff0c;创建虚拟环境。 报错内容&#xff1a;ArgumentError: one of the arguments -n/–name -p/–prefix is required 解决方式&#xff1a; 输入 conda create -n pytorch python3.8即可安装成功。 参考文章&#xff1a;https://blo…

LeetCode:104.二叉树的最大深度

跟着carl学算法&#xff0c;本系列博客仅做个人记录&#xff0c;建议大家都去看carl本人的博客&#xff0c;写的真的很好的&#xff01; 代码随想录 LeetCode&#xff1a;104.二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节…