<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Thinker</title>
    <link>https://thinkerodeng.tistory.com/</link>
    <description>Programming</description>
    <language>ko</language>
    <pubDate>Mon, 25 May 2026 22:15:02 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>생각하는로뎅</managingEditor>
    <image>
      <title>Thinker</title>
      <url>https://tistory1.daumcdn.net/tistory/1171935/attach/4e350720cbfb4ef9a09fea79d6235ed8</url>
      <link>https://thinkerodeng.tistory.com</link>
    </image>
    <item>
      <title>[NestJS] create excel download by exceljs</title>
      <link>https://thinkerodeng.tistory.com/350</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. exceljs 를 받는다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733492882487&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install exceljs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. controller 에 작성한다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733493017155&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;this is controller.ts

import { Res, Req, Get } from '@nestjs/common';
import * as ExcelJS from 'exceljs';

...

// 엑셀 다운로드
@Get('downloadExcel')
async downloadExcel(
  @Req() req : Request
, @Res() res : Response ) {

    const workbook = new ExcelJS.Workbook();
    const worksheet = workbook.addWorksheet('TestExportXLS');

    worksheet.columns = [
        { header: 'name', key: 'name' },
        { header: 'age', key: 'age' }
    ];

    worksheet.addRow({
        name: 'test Row',
        age: 37
    });

    const buffer = await workbook.xlsx.writeBuffer();
    res.header('Content-Disposition', 'attachment; filename=data.xlsx');
    res.type('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    res.send(buffer);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. html&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733493225572&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    
    .....

    &amp;lt;script src=&quot;https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;

    .....
    
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
...

	&amp;lt;button type=&quot;button&quot; id=&quot;download_excel&quot;&amp;gt;엑셀다운로드&amp;lt;/button&amp;gt;
...
&amp;lt;/body&amp;gt;

&amp;lt;script&amp;gt;

// 엑셀 다운로드 버튼 클릭
$(&quot;#download_excel&quot;).click(function () {

    axios({
        method: &quot;get&quot;,
        url: &quot;/downloadExcel&quot;,
        responseType: &quot;blob&quot;, 
    })
    .then((response) =&amp;gt; {
        const url = window.URL.createObjectURL(
        new Blob([response.data])
        );
        const link = document.createElement(&quot;a&quot;);
        link.href = url;
        link.setAttribute(&quot;download&quot;, &quot;data.xlsx&quot;); 
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        window.URL.revokeObjectURL(url);
    })
    .catch((error) =&amp;gt; {
    });

});
            
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;figure id=&quot;og_1733493350615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Nestjs export Excel file&quot; data-og-description=&quot;The full stack explains export excel so easy, using nestjs, exceljs, axios&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@ggluopeihai/nestjs-export-excel-file-697e3891ea8f&quot; data-og-url=&quot;https://medium.com/@ggluopeihai/nestjs-export-excel-file-697e3891ea8f&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cYoe5b/hyXKwy0u5d/Z9xKCfkuN6q7kDKMzBdEsK/img.gif?width=762&amp;amp;height=742&amp;amp;face=0_0_762_742,https://scrap.kakaocdn.net/dn/68sIp/hyXGNbmhZX/jUiqq3XdvLERgbhmSDWksk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://medium.com/@ggluopeihai/nestjs-export-excel-file-697e3891ea8f&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@ggluopeihai/nestjs-export-excel-file-697e3891ea8f&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cYoe5b/hyXKwy0u5d/Z9xKCfkuN6q7kDKMzBdEsK/img.gif?width=762&amp;amp;height=742&amp;amp;face=0_0_762_742,https://scrap.kakaocdn.net/dn/68sIp/hyXGNbmhZX/jUiqq3XdvLERgbhmSDWksk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Nestjs export Excel file&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The full stack explains export excel so easy, using nestjs, exceljs, axios&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>Excel</category>
      <category>exceljs</category>
      <category>nestjs</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/350</guid>
      <comments>https://thinkerodeng.tistory.com/350#entry350comment</comments>
      <pubDate>Fri, 6 Dec 2024 23:00:38 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] read excel file With exceljs (DiskStorage)</title>
      <link>https://thinkerodeng.tistory.com/349</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 에서는 파일 업로드시 메모리에서 읽는 방식(MemoryStorage)&lt;br /&gt;과 디스크에서 읽는 방식(DiskStorage) 으로 구성되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 방법은 &lt;b&gt;DiskStorage&lt;/b&gt; 를 사용했을때, &lt;b&gt;해당 경로에 있는 Excel 파일을 읽어서 출력해주는 방법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. npm 설치&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733422227384&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install exceljs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 많은 예제를 참고하여&amp;nbsp;&amp;nbsp; &lt;b&gt;DiskStorage&lt;/b&gt; 으로 구성되어 있을 경우&amp;nbsp; file.path 를 이용하여 파일 경로를 읽어서 엑셀 파일 내용을 읽어 온다.&lt;/p&gt;
&lt;pre id=&quot;code_1733422283744&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Cell, Row, Workbook } from 'exceljs';

...

  // 엑셀 업로드
  @Post('uploadExcel')
  @UseInterceptors(FileInterceptor('file'))
  async uploadExcel(
      @UploadedFile() file : Multer.file) {
    
    ...
    
      var workbook = new Workbook();
      await workbook.xlsx.readFile(file.path);
      var sheet = workbook.worksheets[0];

      // 1 ~ N ROW
      var rows : Row[] = sheet.getRows(1, sheet.rowCount);
      var cell : Cell;

      rows.forEach(row =&amp;gt; {

        // 1 ~ N Cell
        row.eachCell((cell: Cell, colNumber: number)=&amp;gt;{

          Logger.debug(&quot;colNumber, cell value &quot;, cell.value, colNumber);

        })

      });
  
  ....
 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>diskstorage</category>
      <category>Excel</category>
      <category>exceljs</category>
      <category>memorystorage</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/349</guid>
      <comments>https://thinkerodeng.tistory.com/349#entry349comment</comments>
      <pubDate>Fri, 6 Dec 2024 03:17:43 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] Image file download with Url</title>
      <link>https://thinkerodeng.tistory.com/348</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. npn install&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733421811335&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i --save @nestjs/axios axios&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2.Model 에 HttpModule 추가&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733421831150&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  import { HttpModule } from '@nestjs/axios';
  
  @Module({
 
  imports: [
    HttpModule
  ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 다운로드를 구현할 Service 에서 아래 코드를 추가하여 다운로드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1733421985617&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { HttpService } from '@nestjs/axios';

@Injectable()
export class ApiService {
  constructor(
    , private readonly httpService : HttpService

...
..
async downLoadImage() {

    const writer = fs.createWriteStream('저장할 파일 경로');

    const response = await this.httpService.axiosRef({
        url: 'https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png',
        method: 'GET',
        responseType: 'stream',
    });

    response.data.pipe(writer);

    return new Promise((resolve, reject) =&amp;gt; {
        writer.on('finish', resolve);
        writer.on('error', reject);
    });
    
    }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/Node.js</category>
      <category>File</category>
      <category>image</category>
      <category>JS</category>
      <category>Nest</category>
      <category>nestjs</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/348</guid>
      <comments>https://thinkerodeng.tistory.com/348#entry348comment</comments>
      <pubDate>Fri, 6 Dec 2024 03:08:46 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client</title>
      <link>https://thinkerodeng.tistory.com/347</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;101&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpJ0Tb/btsK4MhZUG3/L6EnZTOsmkgMNZ86AT13qK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpJ0Tb/btsK4MhZUG3/L6EnZTOsmkgMNZ86AT13qK/img.png&quot; data-alt=&quot;Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpJ0Tb/btsK4MhZUG3/L6EnZTOsmkgMNZ86AT13qK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpJ0Tb%2FbtsK4MhZUG3%2FL6EnZTOsmkgMNZ86AT13qK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;672&quot; height=&quot;101&quot; data-origin-width=&quot;672&quot; data-origin-height=&quot;101&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 여러 원인이 있었지만, 공통적인 원인은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서버에서 같은 클라이언트에게 2번 이상 연속으로 응답&lt;/b&gt;&lt;/span&gt;을 전송하면 발생했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 필자 같은 경우는 아래와 같이 코딩 되어 있었다.&lt;/p&gt;
&lt;pre id=&quot;code_1733140614303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @Get('/index')
  @Render('index')
  getAddminIndex(@Req() req : Request, @Res() res: Response) {

   	return res.redirect(&quot;/admin/login&quot;);

  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 처음 위 코드만 봤을때 return 한번만 수행하므로 이상이 없어보였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 자세히 살펴보니 &lt;b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;@Render&lt;/span&gt;('index')&lt;/b&gt; 부분에 한번 더 호출한다는 것을 알아냈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 그래서 아래처럼, &lt;b&gt;&lt;span style=&quot;color: #f3c000;&quot;&gt;@Render&lt;/span&gt;&lt;/b&gt;&amp;nbsp; 을 쓰지 않고, 직접 호출하는 방식으로 작성하여 해결 되었다.&lt;/p&gt;
&lt;pre id=&quot;code_1733140798987&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @Get('/index')
  getAddminIndex(@Req() req : Request, @Res() res: Response) {

    if (해당 조건이면) {
       // 리다이렉트
       return res.redirect(&quot;/login&quot;);
    } else {
      // index 페이지 Render
      res.render('index');
    }
    
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>err_http_headers_sent</category>
      <category>nestjs</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/347</guid>
      <comments>https://thinkerodeng.tistory.com/347#entry347comment</comments>
      <pubDate>Mon, 2 Dec 2024 21:00:32 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] Handlebars template in hbs(Handlebars)</title>
      <link>https://thinkerodeng.tistory.com/346</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yWk97/btsKVbcbhUP/kHyok4aHn7hyQmCQO5oxWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yWk97/btsKVbcbhUP/kHyok4aHn7hyQmCQO5oxWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yWk97/btsKVbcbhUP/kHyok4aHn7hyQmCQO5oxWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyWk97%2FbtsKVbcbhUP%2FkHyok4aHn7hyQmCQO5oxWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;405&quot; height=&quot;233&quot; data-origin-width=&quot;405&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nest.js 에서 화면 그려주는 부분을 hbs(handlebars) 을 사용하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동적으로 화면을 그려주기 위해서, template 를 찾다가, Handlebars.js 를 이용하면 Handlebars template 을 사용할 수 있다는 것을 알게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 내 폴더 구조는 아래와 같았다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1732553810361&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  views
    ㄴindex.hbs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 서버에서 데이터를 받아서 hbs 의 문법을 사용하여 화면을 그렸다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1732553943194&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  	{{#each list}}
 		&amp;lt;span&amp;gt;{{this.comment}}&amp;lt;/span&amp;gt;
	{{/each}}
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 이제 동적으로 그려주기 위해서&amp;nbsp; Handlebars template 을 사용하기로 한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;script 부분에 handlers.min.js 도 추가하고, jquery도 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;template 구분은 제일 아래에 위치해서 ajax 결과 반환 후 사용하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732554215106&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
..
    &amp;lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.8/handlebars.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  	{{#each list}}
 		&amp;lt;span&amp;gt;{{this.comment}}&amp;lt;/span&amp;gt;
	{{/each}}
    
    &amp;lt;ul class=&quot;ul_list&quot;&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;

...

      $(&quot;.classname&quot;).click(function () {
      
          $.ajax({
            type: 'POST',
            dataType: 'json',
            data: {
              &quot;key&quot;: value
            },
            url: '/api/url',
            success: function (result) {
              var source   = $(&quot;#list-template&quot;).html();
              var template = Handlebars.compile(source);
              var html = template(result);
              $(&quot;.ul_list&quot;).html(html);
            }
          });
        
      });

...

&amp;lt;!-- hbs tamplate --&amp;gt;
&amp;lt;script id=&quot;list-template&quot; type=&quot;text/x-handlebars-template&quot;&amp;gt;
	{{#each list}}
          &amp;lt;span&amp;gt;{{this.comment}}&amp;lt;/span&amp;gt;
	{{/each}}
&amp;lt;/script&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. 음.. 여기까지 아주 좋았다. hbs 문법도 익숙해져서 template 작성하는 부분에 대해서는 막힘이 없었다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 그런데 왠 걸..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 에러가 빵빵 터진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 나는 분명 list 데이터를 넘겼지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732554293704&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;              var source   = $(&quot;#list-template&quot;).html();
              var template = Handlebars.compile(source);
              var html = template(result);
              $(&quot;.ul_list&quot;).html(html);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; template 에서는 아무런 데이터도 노출하지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732554344584&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- hbs tamplate --&amp;gt;
&amp;lt;script id=&quot;list-template&quot; type=&quot;text/x-handlebars-template&quot;&amp;gt;
	{{#each list}}
          &amp;lt;span&amp;gt;{{this.comment}}&amp;lt;/span&amp;gt;
	{{/each}}
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 위치도 바꿔보고, id 도 틀렸는지 확인도 하고, 삽질을 하고 나서야 답을 찾을 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;!--&amp;nbsp;hbs&amp;nbsp;tamplate&amp;nbsp;--&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;script&amp;nbsp;id=&quot;list-template&quot;&amp;nbsp;type=&quot;text/x-handlebars-template&quot;&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;\&lt;/b&gt;&lt;/span&gt;{{#each list}} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;span&amp;gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;\&lt;/b&gt;&lt;/span&gt;{{this.comment}}&amp;lt;/span&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;\&lt;/b&gt;&lt;/span&gt;{{/each}} &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&amp;nbsp; 문법 앞에 역슬러쉬(\) 를 붙여 줘야 했던 것이었다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>handlebars</category>
      <category>HBS</category>
      <category>nestjs</category>
      <category>template</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/346</guid>
      <comments>https://thinkerodeng.tistory.com/346#entry346comment</comments>
      <pubDate>Tue, 26 Nov 2024 02:11:54 +0900</pubDate>
    </item>
    <item>
      <title>[AWS/Linux] pm2: command not found (ec2)</title>
      <link>https://thinkerodeng.tistory.com/345</link>
      <description>&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;35&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boAmHs/btsKVTtVWWm/kCU8TAeFHUsMVr0da5R3P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boAmHs/btsKVTtVWWm/kCU8TAeFHUsMVr0da5R3P1/img.png&quot; data-alt=&quot;에러&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boAmHs/btsKVTtVWWm/kCU8TAeFHUsMVr0da5R3P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboAmHs%2FbtsKVTtVWWm%2FkCU8TAeFHUsMVr0da5R3P1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;383&quot; height=&quot;35&quot; data-origin-width=&quot;383&quot; data-origin-height=&quot;35&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;에러&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;sudo ln -s &quot;$(which pm2)&quot; /usr/bin/pm2&lt;/code&gt;&lt;/pre&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5iM7C/btsKVUl4XqQ/l0SFqaBjWMb7VBUqhS2K7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5iM7C/btsKVUl4XqQ/l0SFqaBjWMb7VBUqhS2K7k/img.png&quot; data-alt=&quot;정상&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5iM7C/btsKVUl4XqQ/l0SFqaBjWMb7VBUqhS2K7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5iM7C%2FbtsKVUl4XqQ%2Fl0SFqaBjWMb7VBUqhS2K7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;402&quot; height=&quot;44&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;정상&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Linux/AWS</category>
      <category>aws</category>
      <category>Linux</category>
      <category>pm2</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/345</guid>
      <comments>https://thinkerodeng.tistory.com/345#entry345comment</comments>
      <pubDate>Mon, 25 Nov 2024 07:18:15 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] Table leftJoin with Mysql2</title>
      <link>https://thinkerodeng.tistory.com/344</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clFW02/btsKT4XFKch/I2d9c38q6LgPxpDOwg75i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clFW02/btsKT4XFKch/I2d9c38q6LgPxpDOwg75i0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clFW02/btsKT4XFKch/I2d9c38q6LgPxpDOwg75i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclFW02%2FbtsKT4XFKch%2FI2d9c38q6LgPxpDOwg75i0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;964&quot; height=&quot;902&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nest.js + mysql2&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조합으로 테이블 join 을 하려고 했다가.. 시간을 너무 많이 허비해서 글로 작성해두기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 테이블 관계는 아래와 같다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4LSL5/btsKUzQMJ8l/7FTmsfE8g3eMhfqqvuHRLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4LSL5/btsKUzQMJ8l/7FTmsfE8g3eMhfqqvuHRLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4LSL5/btsKUzQMJ8l/7FTmsfE8g3eMhfqqvuHRLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4LSL5%2FbtsKUzQMJ8l%2F7FTmsfE8g3eMhfqqvuHRLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;375&quot; height=&quot;406&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 각 파일 내용과 중요 내용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 여기서 중요한 것은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; class_list(class_cd) : class_item_list(class_cd) 의 관계는 1:N 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;때문에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;class_list.entity.ts 파일의 class_cd는&amp;nbsp; 반드시 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;OneToMany&lt;/b&gt;&lt;/span&gt; 를 주입 시켜 주어야하며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;class_item_list.entity.ts 의 class_cd 에는&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ManyToOne&lt;/b&gt;&lt;/span&gt; 을 주입 시켜줘야하고, 추가적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;JoinColumn&lt;/b&gt;&lt;/span&gt; 도 주입 시켜 줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-1) class_list.entity.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426151897&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;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(()=&amp;gt;ClassItemList, classItemList =&amp;gt; classItemList.classCd)
  classItemList: ClassItemList[];

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-2) class_item_list.entity.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426287860&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;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(()=&amp;gt;ClassList, classList =&amp;gt; classList.classCd)
  @JoinColumn({ name: 'class_cd'})
  @Column({ name: 'class_cd'})
  classCd: string;

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

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

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-3) class_list.module.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426175130&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 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 {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-4) class_list.service.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426340040&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class ClassListService {
  constructor(
    @InjectRepository(ClassList)
    private classListRepository: Repository&amp;lt;ClassList&amp;gt;, // UserRepository 주입
  ) {}

  findClassInfo(classCd : String): Promise&amp;lt;ClassList&amp;gt; {

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

  }

  async remove(id: number): Promise&amp;lt;void&amp;gt; {
    await this.classListRepository.delete(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2-5) app.module.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426404532&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Module({
  imports: [
    ..., ClassListModule
  ],
  controllers: [AppController],
  providers: [
    AppService, ClassListService
  ],
})
export class AppModule {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;2-6) app.controller.ts&lt;/p&gt;
&lt;pre id=&quot;code_1732426441020&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller()
export class AppController {
  
  ...

  @Get('url')
  @Render('file name')
  async getRegisterStepOne() {
    const result = await this.classListService.findClassInfo('param');
    return { key: result };
  }
  ...
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Programming/Node.js</category>
      <category>Join</category>
      <category>MySQL</category>
      <category>nestjs</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/344</guid>
      <comments>https://thinkerodeng.tistory.com/344#entry344comment</comments>
      <pubDate>Sun, 24 Nov 2024 14:44:39 +0900</pubDate>
    </item>
    <item>
      <title>[NestJS] AWS DB Tunneling With Mysql Setting (터널링 및 Mysql 설정)</title>
      <link>https://thinkerodeng.tistory.com/343</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;902&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AmJwj/btsKTjVJhFY/Wwz3QfGk6q4eOEZVqM3hl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AmJwj/btsKTjVJhFY/Wwz3QfGk6q4eOEZVqM3hl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AmJwj/btsKTjVJhFY/Wwz3QfGk6q4eOEZVqM3hl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAmJwj%2FbtsKTjVJhFY%2FWwz3QfGk6q4eOEZVqM3hl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;964&quot; height=&quot;902&quot; data-origin-width=&quot;964&quot; data-origin-height=&quot;902&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; Nest.js 에서 터널링 하는 방법을 아무리 찾아봐도 안되어서, 테스트를 위해 꼼수를 쓰기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 어차피 로컬에서 접속할때만 필요하고, 서버에 소스 올라가면 터널링이 불필요하므로, 이 방법으로 쓰기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;내가 터널링 해보려고 별짓을 다 했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;내 PC -&amp;gt; 베스천 서버 -&amp;gt; 비공개 서버(Mysql 설치 서버)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(키페어 상태, 모두 3306 방화벽 오픈 상태)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Nest.js 에 mysql을 사용하도록 npm으로 다운로드 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 설정 파일을 셋팅하기 위해서 dotenv 를 설치한다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot; style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;code&gt;npm install dotenv&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. mysql을 사용하기 위해서 mysql2를 설치한다.&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1732246740264&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install --save @nestjs/typeorm typeorm mysql2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Root 디렉토리에 [ &lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;.env&lt;/span&gt; ] 파일 생성&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;4. &lt;span style=&quot;color: #ee2323;&quot;&gt;.env&lt;/span&gt;&amp;nbsp; 파일에 아래 정보 삽입&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1732244435265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 운영 디비 접속 정보
# 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 스키마명&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5..database.module.ts 파일을 생성한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;config(); 를 수행해줘야지, .env 설정 파일을 불러 올 수 있다.&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732423937865&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { config } from 'dotenv';

config();

@Module({
  imports: [
    TypeOrmModule.forRootAsync({
        useFactory: () =&amp;gt; ({
        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 {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. app.module.ts&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;위에서 생성한&amp;nbsp; imports에 DatabaseModule 을 추가해준다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732424052986&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;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 {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. 이제 프로젝트 경로에 가서&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;nbsp; &amp;nbsp;npm run start:dev&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행하면, 아래와 같이 당연히 연결이 안된다고 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1075&quot; data-origin-height=&quot;106&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4TTJn/btsKTIURaJ1/RLtqOwRu3rq9duUbKuCukk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4TTJn/btsKTIURaJ1/RLtqOwRu3rq9duUbKuCukk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4TTJn/btsKTIURaJ1/RLtqOwRu3rq9duUbKuCukk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4TTJn%2FbtsKTIURaJ1%2FRLtqOwRu3rq9duUbKuCukk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1075&quot; height=&quot;106&quot; data-origin-width=&quot;1075&quot; data-origin-height=&quot;106&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 AWS DB 서버로 접속하기 위해서 터널링을 할 차례다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(꼼수)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;8. MobaXterm 을 설치한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mobaxterm.mobatek.net/download.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mobaxterm.mobatek.net/download.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732424280820&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MobaXterm free Xserver and tabbed SSH client for Windows&quot; data-og-description=&quot;The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!&quot; data-og-host=&quot;mobaxterm.mobatek.net&quot; data-og-source-url=&quot;https://mobaxterm.mobatek.net/download.html&quot; data-og-url=&quot;https://mobaxterm.mobatek.net/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bqEgd6/hyXzLZncCi/sKUk9FhmXnuH6ZdNGPu4w0/img.png?width=764&amp;amp;height=489&amp;amp;face=0_0_764_489,https://scrap.kakaocdn.net/dn/esxkAb/hyXDjz7GSH/SXO9qk8kyF6JYYSr5Tex1K/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443,https://scrap.kakaocdn.net/dn/brTdS7/hyXDgi5bPd/eOkiiaFM3bWmL6xMx6nr9k/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443&quot;&gt;&lt;a href=&quot;https://mobaxterm.mobatek.net/download.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mobaxterm.mobatek.net/download.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bqEgd6/hyXzLZncCi/sKUk9FhmXnuH6ZdNGPu4w0/img.png?width=764&amp;amp;height=489&amp;amp;face=0_0_764_489,https://scrap.kakaocdn.net/dn/esxkAb/hyXDjz7GSH/SXO9qk8kyF6JYYSr5Tex1K/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443,https://scrap.kakaocdn.net/dn/brTdS7/hyXDgi5bPd/eOkiiaFM3bWmL6xMx6nr9k/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MobaXterm free Xserver and tabbed SSH client for Windows&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mobaxterm.mobatek.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;9. 상단 메뉴에 Turnneling 버튼을 누른다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEo9m3/btsKTItPD2O/hej0K2FKPtIGtwIGWkFLO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEo9m3/btsKTItPD2O/hej0K2FKPtIGtwIGWkFLO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEo9m3/btsKTItPD2O/hej0K2FKPtIGtwIGWkFLO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEo9m3%2FbtsKTItPD2O%2Fhej0K2FKPtIGtwIGWkFLO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;588&quot; height=&quot;166&quot; data-origin-width=&quot;588&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;10. 하단에 New SSH tunnel 버튼을 누른다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tOP2s/btsKUG9V3Iu/5sxWDcb0LTyXz84ILYfMs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tOP2s/btsKUG9V3Iu/5sxWDcb0LTyXz84ILYfMs1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tOP2s/btsKUG9V3Iu/5sxWDcb0LTyXz84ILYfMs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtOP2s%2FbtsKUG9V3Iu%2F5sxWDcb0LTyXz84ILYfMs1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1022&quot; height=&quot;408&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;11.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;11-1) Forwarded port : 5003&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 내 PC에서 접속할 접속 Port 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;11-2) SSH server : AWS 베스천 서버 ip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SSH login : 베스천 서버 ID&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SSH port :&amp;nbsp; 22&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 11-3) Remote server : db가 설치된 서버 ip (비공개 서버)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Remote port : &lt;u&gt;&lt;i&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;3306 (mysql 서버 port)&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;설정 후 하단 Save&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ISfgO/btsKUydb2mG/VrwKvnTDqmROuKxCJdVCCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ISfgO/btsKUydb2mG/VrwKvnTDqmROuKxCJdVCCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ISfgO/btsKUydb2mG/VrwKvnTDqmROuKxCJdVCCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FISfgO%2FbtsKUydb2mG%2FVrwKvnTDqmROuKxCJdVCCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;861&quot; height=&quot;579&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;579&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;12. 추가된 항목에 열쇠 모양을 눌러서&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;u&gt;&lt;i&gt; pem 파일&lt;/i&gt;&lt;/u&gt;&lt;/span&gt;을 선택해서 등록한다.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tNGDq/btsKTwHk0a7/OubmdPAWVgqFf75AtEVbq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tNGDq/btsKTwHk0a7/OubmdPAWVgqFf75AtEVbq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tNGDq/btsKTwHk0a7/OubmdPAWVgqFf75AtEVbq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtNGDq%2FbtsKTwHk0a7%2FOubmdPAWVgqFf75AtEVbq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1018&quot; height=&quot;411&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;13. 이제 시작 버튼을 누른 후, 정지 버튼이 계속 활성화 되어 있으면 성공.&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oPT94/btsKT680AY2/kiDaHHUFZDreea7jXcAV3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oPT94/btsKT680AY2/kiDaHHUFZDreea7jXcAV3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oPT94/btsKT680AY2/kiDaHHUFZDreea7jXcAV3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoPT94%2FbtsKT680AY2%2FkiDaHHUFZDreea7jXcAV3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1018&quot; height=&quot;411&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OuMwc/btsKUjNNr1B/dlE1yDQMEPNVPhpYkMV1UK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OuMwc/btsKUjNNr1B/dlE1yDQMEPNVPhpYkMV1UK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OuMwc/btsKUjNNr1B/dlE1yDQMEPNVPhpYkMV1UK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOuMwc%2FbtsKUjNNr1B%2FdlE1yDQMEPNVPhpYkMV1UK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1022&quot; height=&quot;412&quot; data-origin-width=&quot;1022&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &lt;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;내 PC에서 5003 Port 를 경유하여, 디비 서버에 있는 Mysql 3306 Port로 접속이 가능&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;14. 이제 서버를 다시 시작하면 접속이 될 것이다.&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;npm&amp;nbsp;run&amp;nbsp;start:dev&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOQfAR/btsKU4Jm8L1/9y3p8geIftCfKrdf8tEJp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOQfAR/btsKU4Jm8L1/9y3p8geIftCfKrdf8tEJp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOQfAR/btsKU4Jm8L1/9y3p8geIftCfKrdf8tEJp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOQfAR%2FbtsKU4Jm8L1%2F9y3p8geIftCfKrdf8tEJp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1080&quot; height=&quot;274&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Programming/Node.js</category>
      <category>aws</category>
      <category>MySQL</category>
      <category>nestjs</category>
      <category>Tunnel</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/343</guid>
      <comments>https://thinkerodeng.tistory.com/343#entry343comment</comments>
      <pubDate>Sun, 24 Nov 2024 14:13:02 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter/Window] 사운드 재생(Sound Play)</title>
      <link>https://thinkerodeng.tistory.com/342</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter Window 용 사운드 재생을 위해서는 아래 라이브러리를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;window 용 라이브러리 사용 방법이 없어서, 정리하기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(라이브러리 소스 뒤적뒤적... )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;[ Window 용 Flutter 라이브러리 Url ]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pub.dev/packages/audioplayers_windows/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pub.dev/packages/audioplayers_windows/install&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1717070033652&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;audioplayers_windows install | Flutter package&quot; data-og-description=&quot;Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously&quot; data-og-host=&quot;pub.dev&quot; data-og-source-url=&quot;https://pub.dev/packages/audioplayers_windows/install&quot; data-og-url=&quot;https://pub.dev/packages/audioplayers_windows/install&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gxgnJ/hyWdmMd74h/k55cctKjNAFntUwi6xOfsK/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/tkyr5/hyWdhc32m7/I2NvUjP1ukFz09GaZ7FbMk/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640&quot;&gt;&lt;a href=&quot;https://pub.dev/packages/audioplayers_windows/install&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pub.dev/packages/audioplayers_windows/install&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gxgnJ/hyWdmMd74h/k55cctKjNAFntUwi6xOfsK/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640,https://scrap.kakaocdn.net/dn/tkyr5/hyWdhc32m7/I2NvUjP1ukFz09GaZ7FbMk/img.png?width=1280&amp;amp;height=640&amp;amp;face=0_0_1280_640');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;audioplayers_windows install | Flutter package&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Windows implementation of audioplayers, a Flutter plugin to play multiple audio files simultaneously&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pub.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. pubspec.yaml&lt;/p&gt;
&lt;pre id=&quot;code_1717070102197&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies:
  ....
  audioplayers_windows: ^4.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 라이브러리 Get 후, 아래 패키지를 사용이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1717070161074&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. &lt;b&gt;static 으로 구성된 instace 으로 객체를 가져 올 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717070229164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';

class ... {

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

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4. &lt;b&gt;사운드 파일 경로는 assets 폴더 아래에 위치&lt;/b&gt;(SOUND_WARRING_PATH)하였으며, &lt;b&gt;사운드 ID(SOUND_WARRING_ID) 로 여러 사운드를 구분&lt;/b&gt; 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;create 메소드를 호출시, stream 객체가 만들어 지는데, Future 비동기 방식이므로, then 메소드를 이용하여, 추후 stream 객체가 만들어지면, 상태 값을 받을 수 있도록 getEventStream 을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717070365124&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import 'package:audioplayers_platform_interface/audioplayers_platform_interface.dart';

class ... {

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

  @override
  void initState() {
  
    // 경고 사운드 설정
    Future&amp;lt;void&amp;gt; soundWarringFuture = soundWarringPlayer.create(SOUND_WARRING_ID);  // 생성
    
    soundWarringFuture.then((value) {
      // 상태 값
      Stream&amp;lt;AudioEvent&amp;gt; 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);
    
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;5. &lt;b&gt;아래 소스를 주석하면, 1번만 재생이 가능&lt;/b&gt;하고, 종료시 상태값 AudioEventType.complete (complete) 값을 받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ReleseMode.loop 는 stop 시, complete&amp;nbsp; 값은 들어오지 않고, seekComplete(AudioEventType.seekComplete) 값만 들어온다.&lt;/p&gt;
&lt;pre id=&quot;code_1717070624919&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;soundWarringPlayer.setReleaseMode(SOUND_WARRING_ID, ReleaseMode.loop);  // 반복 설정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;6. &lt;b&gt;사운드 플레이&lt;/b&gt;가 가능하다. &amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1717070554385&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;soundWarringPlayer.resume(SOUND_WARRING_ID);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;7. &lt;b&gt;사운드 중지&lt;/b&gt;가 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1717070819562&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;soundWarringPlayer.stop(SOUND_WARRING_ID);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;8. 사운드 중지 후, &lt;b&gt;relese 와 dispose 후에는 resume 을 수행하여도 사운드는 재생되지 않는다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1717070837979&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;soundWarringPlayer.stop(SOUND_WARRING_ID);
soundWarringPlayer.release(SOUND_WARRING_ID);
soundWarringPlayer.dispose(SOUND_WARRING_ID);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Flutter</category>
      <category>Flutter</category>
      <category>flutter sound</category>
      <category>Sound</category>
      <category>window</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/342</guid>
      <comments>https://thinkerodeng.tistory.com/342#entry342comment</comments>
      <pubDate>Thu, 30 May 2024 21:11:57 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin/Android] MongoDB 날짜, 한국 시간(Korea) 변환</title>
      <link>https://thinkerodeng.tistory.com/341</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MongoDB 에서 보내오는 Date Format 형식은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1712385477103&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

2024-04-06T07:27:00.000Z&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 날짜는 한국 시간과 일치하지 않아, 변환이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변환 도중 실패한 사례는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1712385913729&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.text.SimpleDateFormat
import java.util.Date

var dateFormat = SimpleDateFormat(&quot;yyyy.MM.dd HH:mm&quot;, Locale.KOREAN)
val sdf = SimpleDateFormat(&quot;yyyy-MM-dd'T'HH:mm:ss.SSS'Z'&quot;, Locale.US)
dateFormat.timeZone = TimeZone.getTimeZone(&quot;Asia/Seoul&quot;)

val date : Date? = sdf.parse(&quot;2024-04-06T07:27:00.000Z&quot;)

date?.let {
    Log.d(&quot;test_date&quot;, dateFormat.format(it))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 에뮬레이터에서는 정상 동작하였으나, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;실제 디바이스에서는 변환이 되지 않는 현상&lt;/span&gt;&lt;/b&gt;이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서, 아래 코드로 적용 후에는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;실제 디바이스에서도 변환이 정상적으로 가능&lt;/span&gt;&lt;/b&gt;하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1712386085779&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.time.OffsetDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter

val zone = ZoneId.of(&quot;Asia/Seoul&quot;)
val fmt = DateTimeFormatter.ofPattern(&quot;yyyy.MM.dd HH:mm&quot;, Locale.getDefault())

val dateTime = OffsetDateTime.parse(&quot;2024-04-06T07:27:00.000Z&quot;).atZoneSameInstant(zone)

dateTime?.let {
    Log.d(&quot;test_date&quot;, fmt.format(it))
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Android</category>
      <category>date</category>
      <category>kotlin</category>
      <category>mongoDB</category>
      <category>날짜변환</category>
      <author>생각하는로뎅</author>
      <guid isPermaLink="true">https://thinkerodeng.tistory.com/341</guid>
      <comments>https://thinkerodeng.tistory.com/341#entry341comment</comments>
      <pubDate>Sat, 6 Apr 2024 15:48:57 +0900</pubDate>
    </item>
  </channel>
</rss>