從零開始實現一個簡單的 rest 風格服務器 (4) —— 連接 postgresql 數據庫

從零開始實現一個簡單的rest風格服務器 (1) —— typescript 開發環境配置
從零開始實現一個簡單的rest風格服務器 (2) —— 集成 koa
從零開始實現一個簡單的rest風格服務器 (3) —— 自動編譯

終於寫到要連接數據庫啦,有些讀者可能等得有點不耐煩了。以前的幾篇寫的都是些花架子,只有連上數據庫,纔是能算是一個完整的 rest 風格服務器嘛。

這裏選用 sequelize 這個 ORM 框架來連接 postgresql 數據庫,當然你也可以直接用 sql 來操作數據庫。爲什麼會選擇 ORM 框架呢,還是爲了獲得 IDE 的更多提示嘛。文章有點長,我爲每一個步驟標上序號,大家耐心點。

1、安裝 sequelize,數據庫驅動 pg 以及與 typescript 相關的包

yarn add sequelize sequelize-typescript pg reflect-metadata

2、新建數據庫配置文件夾 conf 及 配置文件 db.conf.ts

/**
 * @name: 數據庫配置
 * @param : undefined
 * @return : undefined
 */ 
export const dbConfig = {
  host: 'localhost',
  database: 'demo',
  dialect: 'postgres',
  username: 'postgres',
  password: '123456'
}

3、連接數據庫,新建文件夾 db 及 配置文件 db.ts

/*
 * @Description: 數據庫連接類
 */
import * as path from 'path'
import { Sequelize } from 'sequelize-typescript'
import { dbConfig } from '../conf/db.conf'

class DbContext {
  private sequelize: Sequelize
  constructor() {
    const { host, database, dialect, username, password } = dbConfig
    this.sequelize = new Sequelize({
      host: host,
      database: database,
      dialect: dialect,
      username: username,
      password: password,
      define: {
        timestamps: true,  //開啓時間戳 create_at delete_at update_at
        paranoid: true,    //開啓假刪除
        underscored: true, //下劃線
        charset: 'utf8',
        freezeTableName: true //固定表名爲單數  默認表名是xxxs
      },
      pool: {
        max: 10,
        min: 0,
        acquire: 30000,
        idle: 10000
      },
      timezone: '+08:00',
      modelPaths: [path.resolve(__dirname, `./models`)]
    })
    this.sequelize.sync()
  }
  init(): Boolean {
    return !!this.sequelize
  }
  getInstance(): Sequelize {
    return this.sequelize
  }
  isInit(): Boolean {
    return !!this.sequelize
  }
}
export const dbContext = new DbContext()

4、數據庫實體類,新建文件夾 models 及文件 user.ts

/*
 * @Description: 數據庫實體類
 */

import { Table, Column, Model } from 'sequelize-typescript'

@Table({
  tableName: 'user'
})
export default class User extends Model<User> {
  @Column({
    comment: '自增ID',
    primaryKey: true,
    autoIncrement: true,
  })
  id: number

  @Column
  username: string

  @Column
  password: string
}

5、編寫業務邏輯接口,在 src 目錄下新建文件夾 dao、service,在 dao 目錄下新建 UserDao.ts 及子目錄 impl,在 service 目錄下新建 UserService.ts 及子目錄 impl

/*
 * @Description: 數據庫表操作基礎接口 UserDao.ts 
 */
export interface UserDao {
  /**
   * @name: 查詢
   * @param : 
   * @return : Array<User>
   */
  findAll();
  /**
   * @name: 查詢
   * @param : 
   * @return : Array<User>
   */
  findByName(username:string);
  /**
   * @name: 新增
   * @param : undefined
   * @return : undefined
   */
  create(entity:UserInfo);

  /**
   * @name: 刪除
   * @param : undefined
   * @return : undefined
   */
  delete(id:number);
}
export interface UserInfo {
  username:string;
  password:string;
}

==================================================

/*
 * @Description: service接口  UserService.ts
 * @version: 
 */

export interface UserService{
  /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  findAll();
  
  /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  findByName(username:string);

  /**
   * @name: 新增
   * @param : undefined
   * @return : undefined
   */
  create(username:string,password:string);

  /**
   * @name: 刪除
   * @param : undefined
   * @return : undefined
   */
  delete(id:String);
}

6、編寫業務邏輯實現類 UserDaoImpl.ts、UserServiceImpl.ts

/*
 * @Description: 數據庫表操作基礎實現類 UserDaoImpl.ts
 */
 
import { dbContext } from '../../db/db'
import { UserDao, UserInfo } from '../UserDao';
import User from '../../db/models/user';

export class UserDaoImpl implements UserDao{
  constructor(){
    dbContext.init();
  }
  /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  public async findAll(){
    const results = await User.findAll({
      raw: true
    })
    return results;
  } 
  
   /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  public async findByName(username:string){
    const results = await User.findOne({
      where:{
        username:username
      }
    })
    return results;
  } 

  /**
   * @name: 新增
   * @param : entity
   * @return : undefined
   */
  public async create(entity:UserInfo) {
    const results = await User.create(entity)
    return results;
  }
  
   /**
   * @name: 刪除
   * @param : undefined
   * @return : undefined
   */
  public async delete(id: number) {
    const results = await User.destroy({
      where:{
          id:{
            $eq:id
          }
      }
    });
    return results;
  }
}

========================================================

/*
 * @Description: service實現類 UserServiceImpl.ts
 */
import { UserService } from "../UserService";
import { UserDao } from "../../dao/UserDao";
import { UserDaoImpl } from "../../dao/impl/UserDaoImpl";

export class UserServiceImpl implements UserService{
  private userDao:UserDao;

  constructor(){
    this.userDao = new UserDaoImpl();
  }

  /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  public findAll() {
    return this.userDao.findAll();
  } 
  /**
   * @name: 查詢
   * @param : undefined
   * @return : undefined
   */
  public findByName(username:string) {
    return this.userDao.findByName(username);
  } 
  /**
   * @name: 新增
   * @param : entity
   * @return : undefined
   */
  public create(username: string, password: string) {
    return this.userDao.create({username,password});
  }

  /**
   * @name: 刪除
   * @param : undefined
   * @return : undefined
   */
  public delete(id: String) {
    return this.userDao.delete(~~id);
  }  
}

7、查看成果,修改 router/index.ts

/*
 * @Description: 後臺路由組件
 * @version: 0.1.0
 */
import * as Router from 'koa-router';
import { UserInfo } from '../dao/UserDao';
import { UserService } from '../service/UserService';
import { UserServiceImpl } from '../service/impl/UserServiceImpl';

const router = new Router();
const userService:UserService =new UserServiceImpl();

router.get('/*', async (ctx) => {
  ctx.body = await userService.findAll();
})

export { router }

8、瀏覽器輸入 http://localhost:8080
在這裏插入圖片描述

數據庫連接成功!!!

目錄結構:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章