필요한 목록

  • src -> main -> java -> com.mycompany.myapp -> domain -> [DB 테이블과 연결할 class 파일]
  • src -> main -> java -> com.mycompany.myapp -> repository -> [repository interface 파일]
  • src -> main -> java -> com.mycompany.myapp -> web.rest -> [resource 파일(http request를 받아오는 곳)]
  • src -> main -> resources -> config -> liquibase -> changelog -> [.xml파일(테이블 구조)]
  • src -> main -> resources -> config -> liquibase -> master.xml(만들어준 .xml 파일 include)
  • src -> main -> webapp -> app -> layouts -> navbar -> navbar.component.html(메뉴 추가)
  • src -> main -> webapp -> app -> shared -> model -> [.model.ts 파일]
  • module 파일(만들어 준 후, 상위 모듈에서 import)
  • route 파일
  • service 파일
  • component.ts 파일(CRUD 각각)
  • component.html 파일(CRUD 각각)

front end 구현하기

Database와 front end를 연결하기 위한 파일들을 구현하였으면, 이제 프론트엔드를 구현해보겠다.

*코드는 entity 명령어를 사용해서 생성된 게시판을 참고하였다.

먼저, NavBar에서 Board를 눌렀을 때, DB에 저장된 Board 정보들을 가져와 출력하는 화면을 만들어보겠다.

현재, NavBar에서 Board를 누르면, app-routing.module을 통해 BoardModule을 호출한다.

BoardModule에서 BoardRoute를 호출한다. 아무 path도 주지 않을 경우, BoardComponent가 호출된다. BoardComponent에서 기본 화면(DB에 저장된 모든 Board정보들을 출력)이 보여져야한다.

BoardComponent의 화면은 board.component.html이기 때문에, 먼저 html 파일을 구현해주겠다.

//board.component.html

<div>
    <h2 id="page-heading">
        <span>Boards</span>
        <button id="jh-create-entity" class="btn btn-primary float-right jh-create-entity create-book" [routerLink]="['/board/new']">
            <fa-icon [icon]="'plus'"></fa-icon>
            <span >
            Create a new Board
            </span>
        </button>
    </h2>
    <jhi-alert-error></jhi-alert-error>
    <jhi-alert></jhi-alert>
    <br/>
    <div class="alert alert-warning" *ngIf="boards?.length === 0">
        <span>No books found</span>
    </div>
    <div class="table-responsive" *ngIf="books?.length > 0">
        <table class="table table-striped" aria-describedby="page-heading">
            <thead>
            <tr>
                <th scope="col" ><span>ID</span></th>
                <th scope="col" ><span>Title</span></th>
                <th scope="col" ><span>Contents</span></th>
                <th scope="col" ><span>Created Date</span></th>
                <th scope="col"></th>
            </tr>
            </thead>
            <tbody>
            <tr *ngFor="let board of boards ;trackBy: trackId">
                <td><a [routerLink]="['/board', board.id, 'view' ]">{{board.id}}</a></td>
                <td>{{board.title}}</td>
                <td>{{board.contents}}</td>
                <td>{{board.publicationDate | date:'mediumDate'}}</td>
                <td class="text-right">
                    <div class="btn-group">
                        <button type="submit"
                                [routerLink]="['/board', board.id, 'view' ]"
                                class="btn btn-info btn-sm">
                            <fa-icon [icon]="'eye'"></fa-icon>
                            <span class="d-none d-md-inline">View</span>
                        </button>
                        <button type="submit"
                                [routerLink]="['/board', board.id, 'edit']"
                                class="btn btn-primary btn-sm">
                            <fa-icon [icon]="'pencil-alt'"></fa-icon>
                            <span class="d-none d-md-inline">Edit</span>
                        </button>
                        <button type="submit"
                                [routerLink]="['/board', { outlets: { popup: board.id + '/delete'} }]"
                                replaceUrl="true"
                                queryParamsHandling="merge"
                                class="btn btn-danger btn-sm">
                            <fa-icon [icon]="'times'"></fa-icon>
                            <span class="d-none d-md-inline">Delete</span>
                        </button>
                    </div>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</div>

이 상태로는 코드의 'boards'와 'trackId'를 인식하지 못한다. board.component.ts 파일에 선언해 주어야한다.

//board.component.ts

import { Component, OnInit} from '@angular/core';

import { IBoard } from "app/shared/model/board.model";

@Component({
  selector: 'jhi-board',
  templateUrl: './board.component.html',
  styleUrls: ['./board.component.scss']
})
export class BoardComponent implements OnInit {
  boards: IBoard[];

  constructor() {}

  ngOnInit() {
  }

  trackId(index: number, item: IBoard) {
    return item.id;
  }

}

IBoard는 ... app -> shared -> model 안에 만들어준다.

//board.model.ts

import {Moment} from "moment";

export interface IBoard {
  id?: number;
  title?: string;
  contents?: string;
  createdDate?: Moment;
}

export class Board implements IBoard {
  constructor(
    public id?: number,
    public title?: string,
    public contents?: string,
    public createdDate?: Moment
  ) {}
}

crud기능을 위한 service를 BoardComponent의 생성자에 선언해 준다.

//board.component.ts

import { Component, OnInit} from '@angular/core';

import { IBoard } from "app/shared/model/board.model";
import {BoardService} from "app/board/board.service";

@Component({
  selector: 'jhi-board',
  templateUrl: './board.component.html',
  styleUrls: ['./board.component.scss']
})
export class BoardComponent implements OnInit {
  boards: IBoard[];

  constructor(
    protected boardService: BoardService
  ) {}

  ngOnInit() {
  }
}

BoardComponent에서 사용하기 위해, board.service.ts를 구현해준다. 여기서 http 통신으로 BoardResource 파일로 연결시켜준다.

//board.service.ts

import { Injectable } from '@angular/core';
import {HttpClient, HttpResponse} from "@angular/common/http";
import {IBoard} from "app/shared/model/board.model";
import {SERVER_API_URL} from "app/app.constants";
import {Observable} from "rxjs";
import {createRequestOption} from "app/shared/util/request-util";

type EntityResponseType = HttpResponse<IBoard>;
type EntityArrayResponseType = HttpResponse<IBoard[]>;

@Injectable({
  providedIn: 'root'
})
export class BoardService {
  public resourceUrl = SERVER_API_URL + 'api/boards';

  constructor(protected http: HttpClient) { }

  query(req?: any): Observable<EntityArrayResponseType>{
    const options = createRequestOption(req);
    return this.http.get<IBoard[]>(this.resourceUrl, {params: options, observe: 'response'});
  }

}

컴포넌트에 처음 시작 시 loadAll을 통해 모든정보를 불러온다.

//board.component.ts

import { Component, OnInit} from '@angular/core';

import { IBoard } from "app/shared/model/board.model";
import { filter, map } from 'rxjs/operators';
import {BoardService} from "app/board/board.service";
import {HttpResponse} from "@angular/common/http";

@Component({
  selector: 'jhi-board',
  templateUrl: './board.component.html',
  styleUrls: ['./board.component.scss']
})
export class BoardComponent implements OnInit {
  boards: IBoard[];

  constructor(
    protected boardService: BoardService
  ) {}

  loadAll(){
    this.boardService
      .query()
      .pipe(
        filter((res:HttpResponse<IBoard[]>)=>res.ok),
        map((res:HttpResponse<IBoard[]>)=>res.body)
      )
      .subscribe((res: IBoard[])=>{
        this.boards = res;
      });
  }

  ngOnInit() {
    this.loadAll(); //처음 실행시 시작되는 것
  }
}

만약 db에 변경이 생기면 새로 로드해주어야하는데 그 기능을 registerChangeInBoards 메소드로 구현해보겠다. 'boardListModification' 이라는 값을 받게되면, 목록을 새로 로드해준다.

//board.component.ts

//...
@Component({
  selector: 'jhi-board',
  templateUrl: './board.component.html',
  styleUrls: ['./board.component.scss']
})
export class BoardComponent implements OnInit, OnDestroy  {
  boards: IBoard[];
  eventSubscriber: Subscription;

  constructor(protected boardService: BoardService, protected eventManager: JhiEventManager) {}

  loadAll() {
    this.boardService
      .query()
      .pipe(
        filter((res: HttpResponse<IBoard[]>) => res.ok),
        map((res: HttpResponse<IBoard[]>) => res.body)
      )
      .subscribe((res: IBoard[]) => {
        this.boards = res;
      });
  }

  ngOnInit() {
    this.loadAll(); 
    this.registerChangeInBoards();
  }

  trackId(index: number, item: IBoard) {
    return item.id;
  }

  ngOnDestroy() {
    this.eventManager.destroy(this.eventSubscriber);
  }

  registerChangeInBoards() {
    this.eventSubscriber = this.eventManager.subscribe('boardListModification', response => this.loadAll());
  }
}

로그인 후 접속해보면, 아래와 같이 출력된다. 현재 정보가 없기 때문에 No books found가 출력된다.

스크린샷 2019-10-23 오후 11.01.18.png

workbench를 통해, 테스트 값을 넣어주면, 아래와 같이 잘 출력됨을 볼 수 있다.

스크린샷 2019-10-23 오후 11.05.24.png