[NestJS] Table leftJoin with Mysql2

Programming/Node.js 2024. 11. 24. 14:44 Posted by 생각하는로뎅
반응형

nest.js + mysql2

 

조합으로 테이블 join 을 하려고 했다가.. 시간을 너무 많이 허비해서 글로 작성해두기로 했다.

 

1. 테이블 관계는 아래와 같다.

2. 각 파일 내용과 중요 내용

 

  여기서 중요한 것은

 

  class_list(class_cd) : class_item_list(class_cd) 의 관계는 1:N 이다.

 

 때문에 

 

 class_list.entity.ts 파일의 class_cd는  반드시 OneToMany 를 주입 시켜 주어야하며,

 

 class_item_list.entity.ts 의 class_cd 에는ManyToOne 을 주입 시켜줘야하고, 추가적으로 JoinColumn 도 주입 시켜 줘야한다.

 

  2-1) class_list.entity.ts

import { Entity, Column, OneToMany, JoinColumn, PrimaryColumn } from 'typeorm';
import { ClassItemList } from '../class_item_list/class_item_list.entity'

@Entity({ schema: 'dkdoctor_pet_exam', name: 'class_list' })
export class ClassList {

  @PrimaryColumn({ name: 'class_cd'})
  classCd: string;

  @Column({ name: 'value'})
  value: string;

  @OneToMany(()=>ClassItemList, classItemList => classItemList.classCd)
  classItemList: ClassItemList[];

}

 

 

  2-2) class_item_list.entity.ts

import { Entity, Column, PrimaryGeneratedColumn, JoinColumn, OneToMany, ManyToOne, PrimaryColumn } from 'typeorm';
import { ClassList } from '../class_list/class_list.entity';

@Entity({ schema: 'dkdoctor_pet_exam', name: 'class_item_list' })
export class ClassItemList {

  @PrimaryGeneratedColumn({ name: 'class_item_id' })
  classItemId: bigint;

  @ManyToOne(()=>ClassList, classList => classList.classCd)
  @JoinColumn({ name: 'class_cd'})
  @Column({ name: 'class_cd'})
  classCd: string;

  @Column({ name: 'value'})
  value: string;

  @Column({ name: 'comment'})
  comment: string;

}

 

 

  2-3) class_list.module.ts

// class_list.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ClassList } from './class_list.entity';
import { ClassListService } from './class_list.service';

@Module({
  imports: [TypeOrmModule.forFeature([ClassList])],
  exports: [TypeOrmModule],
  providers: [ClassListService]
})
export class ClassListModule {}

 

  2-4) class_list.service.ts

@Injectable()
export class ClassListService {
  constructor(
    @InjectRepository(ClassList)
    private classListRepository: Repository<ClassList>, // UserRepository 주입
  ) {}

  findClassInfo(classCd : String): Promise<ClassList> {

    return this.classListRepository.createQueryBuilder('m')
    .leftJoinAndSelect('m.classItemList', 't')
    .where('m.classCd = :classCd', {classCd: classCd})
    .getOne();

  }

  async remove(id: number): Promise<void> {
    await this.classListRepository.delete(id);
  }
}

 

  2-5) app.module.ts

@Module({
  imports: [
    ..., ClassListModule
  ],
  controllers: [AppController],
  providers: [
    AppService, ClassListService
  ],
})
export class AppModule {}

 

 2-6) app.controller.ts

@Controller()
export class AppController {
  
  ...

  @Get('url')
  @Render('file name')
  async getRegisterStepOne() {
    const result = await this.classListService.findClassInfo('param');
    return { key: result };
  }
  ...
}
반응형
반응형

 

  Nest.js 에서 터널링 하는 방법을 아무리 찾아봐도 안되어서, 테스트를 위해 꼼수를 쓰기로 했다.

  어차피 로컬에서 접속할때만 필요하고, 서버에 소스 올라가면 터널링이 불필요하므로, 이 방법으로 쓰기로 했다.

 내가 터널링 해보려고 별짓을 다 했다.

 

 

내 PC -> 베스천 서버 -> 비공개 서버(Mysql 설치 서버)

(키페어 상태, 모두 3306 방화벽 오픈 상태)

 

 

우선 Nest.js 에 mysql을 사용하도록 npm으로 다운로드 한다.

 

1. 설정 파일을 셋팅하기 위해서 dotenv 를 설치한다.

npm install dotenv

 

2. mysql을 사용하기 위해서 mysql2를 설치한다.

npm install --save @nestjs/typeorm typeorm mysql2

 

 

 

3. Root 디렉토리에 [ .env ] 파일 생성

 

4. .env  파일에 아래 정보 삽입

# 운영 디비 접속 정보
# DB_HOST=DB 서버 IP
# DB_PORT=3306
# DB_USERNAME=DB ID
# DB_PASSWORD=DB PASSWORD
# DB_DATABASE=DB 스키마명

# 로컬 개발 접속 정보
DB_HOST=127.0.0.1
DB_PORT=5003
DB_USERNAME=DB ID
DB_PASSWORD=DB PASSWORD
DB_DATABASE=DB 스키마명

 

5..database.module.ts 파일을 생성한다.

 

config(); 를 수행해줘야지, .env 설정 파일을 불러 올 수 있다.

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { config } from 'dotenv';

config();

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
        useFactory: () => ({
        type: 'mysql',
        host: process.env.DB_HOST,
        port: Number(process.env.DB_PORT),
        username: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_DATABASE,
        synchronize: false,
        logging: true,
        dropSchema: false,
        // entities: [ entities 추가 ],
      }),
    }),
  ],
})


export class DatabaseModule {}

 

6. app.module.ts

 

 위에서 생성한  imports에 DatabaseModule 을 추가해준다. 

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabaseModule } from './database/database.module';

@Module({
  imports: [
    DatabaseModule
  ],
  controllers: [AppController],
  providers: [
    AppService
  ],
})
export class AppModule {}

 

7. 이제 프로젝트 경로에 가서

 

   npm run start:dev

 

실행하면, 아래와 같이 당연히 연결이 안된다고 나온다.

 

이제 AWS DB 서버로 접속하기 위해서 터널링을 할 차례다. (꼼수)

 

8. MobaXterm 을 설치한다.

https://mobaxterm.mobatek.net/download.html

 

MobaXterm free Xserver and tabbed SSH client for Windows

The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!

mobaxterm.mobatek.net

 

9. 상단 메뉴에 Turnneling 버튼을 누른다.

 

 

10. 하단에 New SSH tunnel 버튼을 누른다.

 

11.

   11-1) Forwarded port : 5003

            내 PC에서 접속할 접속 Port 이다.

 

   11-2) SSH server : AWS 베스천 서버 ip

            SSH login : 베스천 서버 ID

            SSH port :  22

 

    11-3) Remote server : db가 설치된 서버 ip (비공개 서버)

             Remote port : 3306 (mysql 서버 port)

 

설정 후 하단 Save

 

 

12. 추가된 항목에 열쇠 모양을 눌러서 pem 파일을 선택해서 등록한다.

 

 

13. 이제 시작 버튼을 누른 후, 정지 버튼이 계속 활성화 되어 있으면 성공.

 

 

 

 

이제 내 PC에서 5003 Port 를 경유하여, 디비 서버에 있는 Mysql 3306 Port로 접속이 가능하게 되었다.

 

 

14. 이제 서버를 다시 시작하면 접속이 될 것이다.

 

npm run start:dev

 

반응형

[Flutter/Window] 사운드 재생(Sound Play)

Programming/Flutter 2024. 5. 30. 21:11 Posted by 생각하는로뎅
반응형

Flutter Window 용 사운드 재생을 위해서는 아래 라이브러리를 사용한다.

 

window 용 라이브러리 사용 방법이 없어서, 정리하기로 했다.

(라이브러리 소스 뒤적뒤적... )

 

 

[ Window 용 Flutter 라이브러리 Url ]

https://pub.dev/packages/audioplayers_windows/install

 

audioplayers_windows install | Flutter package

Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously

pub.dev

 

 

 

1. pubspec.yaml

dependencies:
  ....
  audioplayers_windows: ^4.0.0

 

 

2. 라이브러리 Get 후, 아래 패키지를 사용이 가능하다.

import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';

 

 

3. static 으로 구성된 instace 으로 객체를 가져 올 수 있다.

import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';

class ... {

  // 경고 사운드
  AudioplayersPlatformInterface soundWarringPlayer = AudioplayersPlatformInterface.instance;

}

 

 

4. 사운드 파일 경로는 assets 폴더 아래에 위치(SOUND_WARRING_PATH)하였으며, 사운드 ID(SOUND_WARRING_ID) 로 여러 사운드를 구분 할 수 있다.

 

create 메소드를 호출시, stream 객체가 만들어 지는데, Future 비동기 방식이므로, then 메소드를 이용하여, 추후 stream 객체가 만들어지면, 상태 값을 받을 수 있도록 getEventStream 을 한다.

 

import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';

class ... {

  // 경고 사운드
  final String SOUND_WARRING_ID = "SOUND_WARRING";
  final String SOUND_WARRING_PATH = "assets/sound_waring.wav";
  
  // 경고 사운드
  AudioplayersPlatformInterface soundWarringPlayer = AudioplayersPlatformInterface.instance;

  @override
  void initState() {
  
    // 경고 사운드 설정
    Future<void> soundWarringFuture = soundWarringPlayer.create(SOUND_WARRING_ID);  // 생성
    
    soundWarringFuture.then((value) {
      // 상태 값
      Stream<AudioEvent> soundWarringEvent = soundWarringPlayer.getEventStream(SOUND_WARRING_ID);
      soundWarringEvent.listen((event) {
        debugPrint(event.eventType.name);
      });

    });
    
    // 재생 url 설정
    soundWarringPlayer.setSourceUrl(SOUND_WARRING_ID, SOUND_WARRING_PATH); 
    
    // 반복 설정
    soundWarringPlayer.setReleaseMode(SOUND_WARRING_ID, ReleaseMode.loop);
    
  }
}

 

 

5. 아래 소스를 주석하면, 1번만 재생이 가능하고, 종료시 상태값 AudioEventType.complete (complete) 값을 받을 수 있다.

 

ReleseMode.loop 는 stop 시, complete  값은 들어오지 않고, seekComplete(AudioEventType.seekComplete) 값만 들어온다.

soundWarringPlayer.setReleaseMode(SOUND_WARRING_ID, ReleaseMode.loop);  // 반복 설정

 

 

6. 사운드 플레이가 가능하다.   

soundWarringPlayer.resume(SOUND_WARRING_ID);

 

 

7. 사운드 중지가 가능하다.

soundWarringPlayer.stop(SOUND_WARRING_ID);

 

 

8. 사운드 중지 후, relese 와 dispose 후에는 resume 을 수행하여도 사운드는 재생되지 않는다.

soundWarringPlayer.stop(SOUND_WARRING_ID);
soundWarringPlayer.release(SOUND_WARRING_ID);
soundWarringPlayer.dispose(SOUND_WARRING_ID);

 

반응형