Egg:用装饰器来进行参数校验

7 篇文章 1 订阅
5 篇文章 0 订阅

一. 构建项目

1.创建一个React项目,在本地有npm命令的情况下,通过umi脚手架来搭建项目(注意,这里用了umi,也可以用React自带的脚手架,只不过后续修改跨域的配置文件不一样):

npm create @umijs/umi-app

2.初始化下项目:

npm install

3.创建Egg项目,执行命令:

npm init egg --type=simple

4.初始化egg项目:

npm install

二. 先解决本地的跨域问题

React项目中,修改.umirc.ts文件,增加以下内容:(若是React脚手架搭建的,则修改package.json文件)

proxy: {
  // 以api为前缀的都会走这个代理
  "/api": {
    // 将请求代理到egg服务商
    target: "http://localhost:7001",
    changeOrigin: true,
    // 重写路径,最终请求到egg的路由是不带api前缀的
    pathRewrite: {
      "^/api": ""
    }
  }
}

修改pages目录下的index.tsx文件:(记得npm install axios

import styles from './index.less';
import { Input, Button } from 'antd';
import axios from 'axios'
import { useState } from 'react'
export default function IndexPage() {
  const [state, setState] = useState('')

  const click = async () => {
    console.log(state)
    await axios({
      url: '/api/test',
      method: 'post',
      withCredentials: true,
      data: {
        message: state,
      },
    })
  }
  return (
    <div>
      <h1 className={styles.title}>Page index</h1>
      <Input onChange={(event) => { setState(event.target.value) }}></Input>
      <Button onClick={click}>传递参数</Button>
    </div>
  );
}

然后启动项目,npm start,页面效果如下:
在这里插入图片描述


修改Egg项目,增加一条路由配置:
在这里插入图片描述
内容如下:

router.post('/test', controller.home.index);

home.js中添加一条提示语:
在这里插入图片描述

启动egg项目:npm run dev

然后最终效果如下:

在这里插入图片描述

到这里,准备工作都已经做好了,那么来讲一讲本文的重点内容。在进行前后开发的过程中,往往我们需要注意前台传给后台的参数是否合法、是否有效。

在Java里面,我们可以通过@NotBlank、@NotEmpty等注解来控制一个变量的值,那么在Node里面,我们可以怎样去实现这样的效果呢?

三. 用装饰器实现参数校验

首先配置下Egg项目中的一些配置,在根目录下创建一个tsconfig.json文件,添加以下内容:

{
    "compilerOptions": {
        "target": "es2017",
        "experimentalDecorators": true,
    }
}

其次来编写下装饰器,创建一个decorator文件夹,创建myValid.ts文件:

import { Controller } from 'egg';

// 校验方法中参数的类型
export type CheckFunc<T> = (paramVal: T) => boolean;

/**
 * x:就是参数的名称
 * value则是一个函数,该函数的参数则是这个参数对应的值(返回true/false)
 * 参考:
 * @ParamValid({
    message: valid<string>([notBlank()]),
  })
 */
interface ParamEntity {
    [x: string]: (paramVal: any) => boolean;
}

export function preAction(preFn: any): any {
    /**
     * _target:目标对象
     * _name:目标属性名称
     * descriptor描述符,包含目标的全部属性
     */
    return function (_target: any, _name: any, descriptor: PropertyDescriptor): any {
        // 获取旧属性值
        const oldValue = descriptor.value;
        descriptor.value = function (...args: any) {
            // 执行preFn函数,查看这个参数是否校验通过,若某个参数不通过,则后续的就因短路运算就不走了
            const isContinueFlag= preFn?.apply(this, args);
            return isContinueFlag && oldValue.apply(this, args);
        };

        return descriptor;
    };
}

/**
 * T:校验的参数的类型
 * paramVal:我们传入的需要校验的前端参数
 */
export function valid<T>(rules: CheckFunc<T>[]): (paramVal: T) => boolean {
    return (paramVal: T) => rules.reduce<boolean>((prev: boolean, curr) => { return prev ? curr(paramVal) : prev; }, true);
}

export function ParamValid(paramEntity: ParamEntity) {
    return preAction(function (this: Controller) {
        // 前端请求参数体
        const requestBodyFromFront = this.ctx.request.body;
        // 校验注解中传入的参数数组
        const paramNames: string[] = Object.keys(paramEntity);
        const result: boolean = paramNames.reduce<boolean>((prev: boolean, paramName) => {
            // 根据参数名称去获得对应 前端请求体中 对应参数的值
            const paramVal = requestBodyFromFront[paramName];
            // 获得对应的校验API(对应上述的valid方法)
            const checkFunc = paramEntity[paramName];
            // 若不通过校验,则后续的方法就不执行了
            return prev ? checkFunc(paramVal) : prev;
        }, true);
        if (result === false) {
            this.ctx.body = {
                content: '参数不合法',
                success: false,
            };
        } else {
            this.ctx.body = {
                success: true,
            };
        }
        return result;
    });
}

export const notBlank = (): CheckFunc<string> => (str: string) => str?.trim().length > 0;

Controller层的方法上调用:

import { Controller } from 'egg';
import { ParamValid, valid, notBlank } from '../decorator/myValid'

class HomeController extends Controller {
  @ParamValid({
    message: valid<string>([notBlank()]),
  })
  async index() {
    const { ctx } = this;
    const { message } = this.ctx.request.body;
    console.log('获得请求了:' + message)
    ctx.body = '校验通过';
  }
}
export default HomeController;

最终的实现效果如下:
在这里插入图片描述

到这里一个简单的校验参数功能就做好啦。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值