2023年开发小总结3:node的接触&midway使用

206 阅读4分钟

前言

文档

midway官网

使用

  • 函数调用注意要做异常捕获处理

目录介绍

clam脚手架是阿里商旅内部的,在创建项目的时候可以选择仅client还是client与service都支持的。 如果选择后者的话,创建后的项目,service目录如下

image.png

view目录中配置cdn链接,同时在client配置中设置 externals: {react: 'React','react-dom': 'ReactDOM'} 这样在打包的时候就不会把react打包到项目中,通过cdn的方式拉取。

view/index.ejs.ts 中配置

//注意 src为cdn的链接,需要注意版本号,版本号要小于package.json中的版本号
 <script src="https://xxx/code/lib/react/18.2.0/umd/react.production.min.js"></script>

config配置文件

function文件夹下面,写一些入口处理,当发送过来一个http请求的时候,首先会在function中处理,

相当于MVC中的controller

service会做一些逻辑处理一般在function中的函数调用这里面的函数进行进一步处理。

model对数据进行增删改查操作, 一般是service中调用model中的操作。

简单的使用

1. 客户端发送一个http请求

使用js自带的fetch发送一个post请求

请求的url: http:/这里是域名/api/moduleName/getList?name=Jonh&age=30

const host = 'xxx'
const params = {
  name: 'John',
  age: 30
}
fetch(`${host}/api/moduleName/getList`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body:JSON.stringify(params)
}).then(response => response.json()).then(data => {
  console.log('data',data)
}).catch(err => {
  console.log(err)
})

以上的moduleName我使用具体的名字代替

我以用户模块为例 user

http:/这里是域名/api/user/getList?name=Jonh&age=30

2.控制器解析用户的输入,并返回数据

方法一:通过官网给出的@Controller注解方式处理

image.png

方法二: 根据请求方法名称,做统一的调用处理

import { Context as FaasContext } from "@midwayjs/faas";
import {
  Inject,
  Provide,
  ServerlessTrigger,
  ServerlessTriggerType,
  Config,
} from "@midwayjs/decorator";
import { IUserService } from "@/interface/user";

@Provide()
export class UserHandler {
  @Inject()
  ctx!: FaasContext; //这里获取上下文 主要有url,params等信息 返回信息处理

  @Inject()
  userService!: IUserService;//service的实例,通过该对象调用service里面定义的函数处理

  @Config("user")
  userConfig;
//该 装饰器用于定义不同的触发器,它的参数为每个触发器信息,以及通用触发器参数
  @ServerlessTrigger(ServerlessTriggerType.HTTP, {
    path: "/api/user/*",
    method: "post",
  })
  async userHandle() {
    const data = this.ctx.request.body;
    let res = {};
    try {
    //path='/api/user/getList' funcType的值为getList
      const funcType = this.ctx.path?.split("/").reverse()[0] || "";
      //如果我的service里面有定义getList这个函数 继续执行
      if (typeof this.userService[funcType] === "function") {
        //bind用来创建一个新的函数,并绑定指定的对象
        //function.bind(thisArg, arg1, arg2, ...);
        const _handler = this.userService[funcType].bind(this, data);
        //这里其实是调用service层的方法
        res = await _handler();
      } else {
        res = {
          data: null,
          success: false,
          msg: "",
          code: "fail",
        };
      }
    } catch (err) {
      this.ctx.logger.error(`user api ${this.ctx.path} error`, err);
      res = {
        data: null,
        success: false,
        msg: err,
        code: "fail",
      };
    }
    this.ctx.body = {
      status: 200,
      success: true,
      data: res,
    };
  }
}




config/config.daily.ts

通过 @Config("user")注解就可以获取到配置

export default{
  user:{
    appName:"app's name",
    accessKey:'这里随便写各种属性和属性值'
  }
}

说明

@Provide 装饰器的作用:

  • 1、这个 Class,被依赖注入容器托管,会自动被实例化(new)
  • 2、这个 Class,可以被其他在容器中的 Class 注入

而对应的 @Inject 装饰器,作用为:

  • 1、在依赖注入容器中,找到对应的属性名,并赋值为对应的实例化对象 @Inject 的类中,必须有对应的 @Provide 才会生效。成对出现的。

3.service服务层 业务逻辑处理层

interface/user.ts

export interface IUserService{
  getList():Promise<any>
}

service/user.ts

方式一:这一层调用后端服务获取到返回值后做一些简单处理,返回给客户端的页面使用

import { Context as FaasContext } from "@midwayjs/faas";
import { Inject, Provide, Config } from "@midwayjs/decorator";
import { IUserService } from "@/interface/acl";

@Provide()
export class UserService implements IUserService{
  @Inject()
  ctx!: FaasContext & { user?: any; hsfClient?: any };

  @Config("user")
  userConfig;
  
    /**
   * 通过name获取该应用下所有用户
   * @param {number} userId
   * @param {Array<string>} roleNames
   * @return {*}  {Promise<UserResult[]>}
   * @memberof UserService
   */
  async getList(data): Promise<any[]> {
    const { name } = data;
    const res: any = await this.ctx.hsfClient.invoke({
      id: "com.xxx.UserService:2.0.0",
      method: "findUserByName",
      group: "HSF",
      args: [
        {
          searchName: name,
          class: "com.xxx.FindListByNameParam",
        },
      ],
      parameterTypes: [
        "com.xxx.FindListByNameParam",
      ],
    });
    if (res.success) {
      const { result = [] } = res;
      return result;
    }
    throw new Error(res.msg);
  }
 
 
  //另外的service方法,假设在这里调用这个类的其他函数,可以controller中的实力化的 userService对象调用
  async getAllAppUser(data): Promise<any[]>{
   try{
     //这里就是调用上面的函数
     //@ts-ignore
     const res = await this.userService.getList()
   }catch(err){
     this.ctx.body = {
        success: false,
        data: "xxx",
      };
      return;
   }
  }

}

方法二:这一层调用dao层定义的增删改查操作 不调用后端的服务

sequelize 是基于nodejs的ORM

ORM(Object-Relational Mapping,对象关系映射)是一种技术,用于将面向对象的程序中的对象与关系型数据库中的表进行映射。它提供了一种将对象模型与数据库模型进行交互的方式,使开发人员可以使用面向对象的编程语言来操作数据库,而无需直接编写SQL语句。

ORM框架通常提供以下功能:

  1. 对象映射:ORM框架将数据库表映射为对象,表的列映射为对象的属性。这样,开发人员可以使用面向对象的方式来操作数据库,而无需关注底层的SQL语句。
  2. 数据库操作:ORM框架提供了一组API和方法,用于执行数据库操作,如插入、更新、删除和查询数据。开发人员可以使用这些方法来操作对象,ORM框架会自动将操作转换为对应的SQL语句。
  3. 关系管理:ORM框架能够处理对象之间的关系,如一对一、一对多、多对多等关系。它可以自动处理关系的建立、更新和删除,简化了数据库关系的管理。
  4. 数据库迁移:ORM框架通常提供数据库迁移工具,可以根据定义的对象模型自动生成数据库表结构,以及在模型变更时对数据库进行更新。

常见的ORM框架包括Java的Hibernate、Python的Django ORM、Ruby的Active Record、Node.js的Sequelize等。它们提供了强大的功能和易于使用的API,简化了开发人员与数据库之间的交互。

使用ORM框架可以提高开发效率,减少编写SQL的工作量,并使代码更具可维护性和可扩展性。然而,ORM框架也有一些限制,例如性能问题、复杂查询的处理等。在选择和使用ORM框架时,需要根据具体应用的需求和性能要求进行评估和选择。

在sevice层中调用还是使用this.model对象.findAndCountAll 等等其他的操作