阿里云七天云开发校园合伙人创造营 Day 7

云开发7天训练营学习计划

阿里云七天云开发校园合伙人创造营 Day 7_第1张图片

阿里云云开发平台校园合伙人招募 主要提供了 云开发平台 进行 Web 开发的体验,包括以下内容:

  • 认识 Serverless 云开发 (8.3) :学习云开发平台的基本概念和操作、团队协同、应用的开发、部署

  • 云函数 (8.4) :函数的基础概念,架构,调用方式、静态文件的托管方式

  • 开发Web接口 (8.5):学习使用函数开发 Web 接口、多个函数的同时开发,资源复用

  • 服务端渲染 (8.6):学习使用函数接入传统 koa 中间件,构建 Web 应用

  • 数据库调用 (8.7):学习接入数据库,调用数据存储

  • 多媒体托管和支付 (8.10):学习函数的文件多媒体托管和支持能力

  • 一体化方案开发实战 (8.11):学习和前端 ( react / vue ) 代码一起开发的一体化方案

完结撒花 ,点击上面的链接可以回顾这七天的内容哦~

Day 7: 在 Midway Serverless 数据库示例模板中实现一个注册和登陆系统

关于 Midway Serverless

关于 Midway Serverless 的相关介绍,请参考 Day2 的文章

每日任务

今日任务为使用 Midway Serverless 数据库示例模板实现一个注册和登录系统,展示注册和登录功能。

本次任务原理跟 Day5 相似,请先阅读 Day5 文章 的 每日任务 部分

1. 准备开发环境

登入云开发平台,进入到应用列表,点击 创建新应用,新建一个 WEB 实验室解决方案的 Midway Serverless OTS数据库示例

创建好后,进入 开发部署

阿里云七天云开发校园合伙人创造营 Day 7_第2张图片

进入 IDE 后,先在终端执行:

npm i --registry=https://registry.npm.taobao.org

安装 npm 依赖,因为依赖包很多,这里用了淘宝的镜像源,安装会更快。

2. 开发调试

本次任务是直接在 ToDo List 示例的基础上修改,先附上需要改动的地方:

.
├── f.yml                          # 修改函数定义文件
├── public
|   └── index.html                 # 修改前端 HTML 主页
└── src
	├── index.tsx                  # 修改 React 前端代码
   	└── apis
		├── user.ts                # 增加函数文件
		└── config
			└── config.default.ts  # 部署环境变量配置

同时,我将全部代码上传到 GitHub,可以用于覆盖原来的代码,具体上传代码到远程仓库的方法在 Day1 文章 的 每日任务 第三部分有提及。

2.1 修改代码

按照开发逻辑,首先修改后端代码,在 src/apis 下新增文件 user.ts,主要定义了注册、登录这两个函数,实现一些数据库操作,完整代码如下:

import { Func, Inject, Provide } from '@midwayjs/decorator';
import TableStore from 'tablestore';
import format from 'otswhere/format';

@Provide()
export class UserService {

  @Inject()
  ctx;

  @Inject()
  tb;

  @Func('user.login')
  async login() {
    const { name, password } = this.ctx.query;

    const params = {
      tableName: 'user',
      direction: TableStore.Direction.BACKWARD,
      inclusiveStartPrimaryKey: [{ id: TableStore.INF_MAX }],
      exclusiveEndPrimaryKey: [{ id: TableStore.INF_MIN }]
    };

    return new Promise(resolve => {
      this.tb.getRange(params, (_, data) => {
        const rows = format.rows(data, { email: true });
        const userExists = rows.list.findIndex(user => user.name === name) !== -1

        if (!userExists) {
          resolve({
            success: false,
            message: '用户不存在'
          })
          return
        }

        const user = rows.list.find(user => user.name === name);
        if (user.password !== password) {
          resolve({
            success: false,
            message: '密码不正确'
          })
          return
        }

        resolve({
          success: true,
          user
        });
      });
    })
  }

  @Func('user.register')
  async register() {
    const { name, password } = this.ctx.query;
    const params = {
      tableName: "user",
      condition: new TableStore.Condition(TableStore.RowExistenceExpectation.IGNORE, null),
      primaryKey: [
        { id: `${Date.now()}-${Math.random()}` }
      ],
      attributeColumns: [
        { name },
        { password }
      ]
    };
    return new Promise(resolve => {
      this.tb.putRow(params, async function (err, data) {
        if (err) {
          resolve({
            success: false,
            errmsg: err.message
          });
        } else {
          resolve({
            success: true,
            data
          });
        }
      });
    });
  }
}

下一步,在函数定义文件 f.ymlfunctions 下声明定义注册、登录这两个函数,增加代码:

register:
  handler: user.register
  events:
    - apigw:
        path: /api/register
login:
  handler: user.login
  events:
    - apigw:
        path: /api/login

接下来修改前端代码,重写 src/index.tsx 文件构造前端页面:

import React, { useEffect, useState } from 'react'
import ReactDOM from 'react-dom';

export default function App() {
  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8">
      <div className="max-w-md w-full">
        <div>
          <img className="mx-auto h-12 w-auto" src="https://tailwindui.com/img/logos/workflow-mark-on-white.svg" alt="Workflow" />
          <h2 className="mt-6 text-center text-3xl leading-9 font-extrabold text-gray-900">
            注册或者登录
            </h2>
        </div>
        <form className="mt-8" action="#" method="POST">
          <input type="hidden" name="remember" defaultValue="true" />
          <div className="rounded-md shadow-sm">
            <div>
              <input
                aria-label="Email address" name="email" type="email" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm sm:leading-5" placeholder="Email address" />
            </div>
            <div className="-mt-px">
              <input
                aria-label="Password" name="password" type="password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:shadow-outline-blue focus:border-blue-300 focus:z-10 sm:text-sm sm:leading-5" placeholder="Password" />
            </div>
          </div>
          <div className="mt-6">
            <button type="button" className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
              <span className="absolute left-0 inset-y-0 flex items-center pl-3">
              </span>
                注册
              </button>
          </div>
          <div className="mt-6">
            <button type="button" className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
              <span className="absolute left-0 inset-y-0 flex items-center pl-3">
              </span>
                登录
              </button>
          </div>
        </form>
      </div>
    </div>
  )
}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

修改 public/index.html 文件,在 head 标签结束前引入 CSS :

<head>
  
  <link href="https://cdn.bootcdn.net/ajax/libs/tailwindcss/1.6.2/tailwind.min.css" rel="stylesheet">
head>
2.2 连接数据库

要实现功能,需要开通阿里云 OTS 数据库,创建数据表,以及申请一个 AccessKey。具体请回顾 Day5 文章 每日任务 的第二部分。

与 Day5 文章中不同的是,这里只需要创建一个名为 user 的数据表,表主键为 id

阿里云七天云开发校园合伙人创造营 Day 7_第3张图片

2.3 调试

修改好环境变量后,可以执行 npm run dev 运行项目,点击生成的链接查看页面。

阿里云七天云开发校园合伙人创造营 Day 7_第4张图片

尝试注册一个新账号,注册成功时会弹窗提示:

阿里云七天云开发校园合伙人创造营 Day 7_第5张图片

尝试使用此账号登录,登录成功时会弹窗提示:

阿里云七天云开发校园合伙人创造营 Day 7_第6张图片

登录异常情况示例:

  1. 用户不存在

阿里云七天云开发校园合伙人创造营 Day 7_第7张图片

  1. 密码错误

阿里云七天云开发校园合伙人创造营 Day 7_第8张图片

3. 部署上线

正式部署上线前记得将 src/apis/config/config.default.ts 文件改回默认状态。

任务拓展

本次任务同样可以使用 MySQL 数据库,只需在 Midway Serverless MySQL数据库示例 中增加并修改函数文件 user.ts ,并在自己的数据库中新建如下一张数据表即可。

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

总结

这个简单的注册、登录只能作学习、演示使用,重点是如何在 Midway Serverless 中使用阿里云 BaaS 服务进行数据的操作和调用。

这个 demo 可改进的地方很多,比如注册时用户名是要求 Email 的,可以增加判断语句限定用户名必须为 Email 地址;又如密码错误次数过多,可以增加尝试次数限制、填写验证码、账号暂时锁定等;也可以限定密码的规范,进行密码加密或者增强验证,将注册和登录分为两个页面,增加跳转路由等等。

由于时间关系需要准备项目实战的内容,以上的改进成为了遗憾,后续 [视情况]^(看心情) 更新完善,也欢迎大家上 GitHub 提 issue 和 PR。

七天创造营就到此结束了,对后续 项目实战 内容感兴趣的朋友们记得 关注我 哦~

你可能感兴趣的:(阿里云七天云开发全记录,nosql,mysql,reactjs,typescript,经验分享)