๐Ÿ’ป Programming (356)

An exception occurred applying plugin request [id: 'org.springframework.boot', version: '2.4.0']
> Failed to apply plugin [id 'org.springframework.boot']
   > Spring Boot plugin requires Gradle 5 (5.6.x only) or Gradle 6 (6.3 or later). The current version is Gradle 6.1.1

 

์ธํ…”๋ฆฌJ์—์„œ ์‹ ๊ทœ ๊ทธ๋ž˜๋“ค ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์Šคํ”„๋ง๋ถ€ํŠธ ์ตœ์‹ ๋ฒ„์ „์ธ 2.4๋ฅผ ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ์ถ”๊ฐ€ํ–ˆ๋”๋‹ˆ ์œ„์™€๊ฐ™์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

ํ˜„์žฌ gradle 6.1.1 ๋ฒ„์ „์„ ์‚ฌ์šฉ์ค‘์ด๊ณ  ์Šคํ”„๋ง๋ถ€ํŠธ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด 6.3 ์ด์ƒ์˜ ๋ฒ„์ „์ด ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฑฐ์˜€๋‹ค.

 

๊ทธ๋ž˜๋“ค์€ ์ตœ์‹ ๋ฒ„์ „์ด ํ˜„์žฌ 6.7.1 (๊ทธ๋ž˜๋“ค ๊ณต์‹์‚ฌ์ดํŠธ)์ด๋ฉฐ ์—…๊ทธ๋ ˆ์ด๋“œ๋Š” ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค.

(์ฃผ์˜: ์šฐ์„  ๋นŒ๋“œ์‹œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋‹ˆ ์ถ”๊ฐ€ํ–ˆ๋˜ ๋‚ด์šฉ์„ ์ฃผ์„์ฒ˜๋ฆฌ ํ•œ๋’ค ์‹คํ–‰ํ•œ๋‹ค. ๋˜ํ•œ ์‹ ๊ทœ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋‹Œ ๊ธฐ์กด ํ”„๋กœ์ ํŠธ์—์„œ ๊ทธ๋ž˜๋“ค ๋ฒ„์ „์„ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•  ์‹œ์—๋Š” ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ถฉ๋ถ„ํžˆ ์ฝ์–ด๋ณด๊ณ  ์ง„ํ–‰ํ•  ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.)

> gradle wrapper --gradle-version 6.7.1

 

07:40:20: Executing tasks 'wrapper --gradle-version 6.7.1'...

> Task :wrapper

BUILD SUCCESSFUL in 344ms
1 actionable task: 1 executed
07:40:20: Tasks execution finished 'wrapper --gradle-version 6.7.1'.

์ด์ œ ๋‹ค์‹œ build.gradle ํŒŒ์ผ์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ฃผ์„์„ ํ•ด์ œํ•˜๊ณ  ๊ทธ๋ž˜๋“ค SYNC๋ฅผ ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ 6.7.1 ๋ฒ„์ „์„ ๋‹ค์šด๋กœ๋“œํ•˜์—ฌ ๋นŒ๋“œ์— ์„ฑ๊ณตํ•œ๋‹ค.

Download https://services.gradle.org/distributions/gradle-6.7.1-bin.zip (102.84 MB)
Download https://services.gradle.org/distributions/gradle-6.7.1-bin.zip finished succeeded, took 12 s 837 ms
Starting Gradle Daemon...
Gradle Daemon started in 1 s 447 ms
> Task :prepareKotlinBuildScriptModel UP-TO-DATE

BUILD SUCCESSFUL in 1m 14s

 

 

 

 

 

์ฐธ๊ณ ๋ฌธ์„œ: docs.gradle.org/current/userguide/upgrading_version_6.html

 

Upgrading your build from Gradle 6.x to the latest

This chapter provides the information you need to migrate your Gradle 6.x builds to the latest Gradle release. For migrating from Gradle 4.x or 5.x, see the older migration guide first. We recommend the following steps for all users: Try running gradle hel

docs.gradle.org

 

์šฐ์„  ํ™”๋ฉด ๊ธฐํš๋ถ€ํ„ฐ ์‹œ์ž‘ํ–ˆ๋‹ค.

ํ‡ด๊ทผ ๊ธธ ์ง€ํ•˜์ฒ ์—์„œ ํ•œ์‹œ๊ฐ„ ๋™์•ˆ ๊ฐค๋…ธํŠธ์—๋‹ค๊ฐ€ ๋„์ ์—ฌ๋ดค๋‹ค.

์›Œ๋‚™ ๊ผผ๊ผผํ•œ ์Šคํƒ€์ผ์ด๋ผ ์ด๊ฒƒ์ €๊ฒƒ ๋””ํ…Œ์ผํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๋‹ค ์ ์–ด๋„ฃ๊ณ  ์‹ถ์—ˆ์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ ์‹œ์ž‘ํ•˜๋ฉด ํž˜๋“ค์–ด์„œ ์ค‘๋„ํฌ๊ธฐํ•˜๊ฒŒ ๋  ๊ฒƒ ๊ฐ™์•„ ๊ณ„์† ๋“œ๋Š” ์ƒ๊ฐ๋“ค์„ ๋ฟŒ๋ฆฌ์น˜๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ๋งŒ ๋„์ ์˜€๋‹ค.

๊ฐค๋Ÿญ์‹œ๋…ธํŠธ์˜ SํŽœ์„ ์ด์šฉํ•œ ๋ฉ”๋ชจ๊ฐ€ ์ฒ˜์Œ์ธ์ง€๋ผ ์„œํˆฌ๋ฅด๊ฒŒ ์ž‘์„ฑํ–ˆ๋‹ค ใ…Ž

๋ฉ”์ธํ™”๋ฉด์€ ํฌ๊ฒŒ ์ƒ๋‹จ๋ถ€(ํ—ค๋”๋ถ€๋ถ„๊ณผ ์ตœ์ƒ์œ„๋ฉ”๋‰ด)์™€ ํ•˜๋‹จ๋ถ€(์‚ฌ์ด๋“œ๋ฉ”๋‰ด + ์ปจํ…ํŠธ)๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

์ปจํ…ํŠธ ์˜์—ญ์€ ์ขŒ์ธก์— ์‚ฌ์ด๋“œ๋ฉ”๋‰ด๊ฐ€ ์žˆ์„์ˆ˜๋„ ์žˆ๊ณ  ์—†์„์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์นด๋“œํ˜• ๋ชฉ๋ก๋ณด๊ฐ€์™€ ๋ฆฌ์ŠคํŠธํ˜•์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ๊ณ„ํš์ด๋‹ค.

์ตœ์ƒ์œ„ ๋ฉ”๋‰ด๋Š” ์ฃผ์ธ์žฅ ๋˜๋Š” ๋ธ”๋กœ๊ทธ์˜ ์†Œ๊ฐœ(Intro), ๋ธ”๋กœ๊ทธ(Blog), ๊ทธ๋ฆฌ๊ณ  ๋ถ„์„/ํ†ต๊ณ„(Stats) ๋กœ ๊ตฌ์„ฑํ–ˆ๋‹ค.
๋ธ”๋กœ๊ทธ๋ฉ”๋‰ด์˜ ํ•˜์œ„์—๋Š” ๊ฐœ๋ฐœ์ผ์ง€, ๋‹ค์ด์–ด๋ฆฌ, ์ œํ’ˆ๋ฆฌ๋ทฐ, ์—ฌํ–‰์ •๋ณด ๋ฉ”๋‰ด๊ฐ€์žˆ๊ณ , ๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ถ„์„ํ†ต๊ณ„ ๋ฉ”๋‰ด์—๋Š” ๊ฐ์ข… ํ†ต๊ณ„์ž๋ฃŒ๋ฅผ ๊ณต์œ ํ•  ์ƒ๊ฐ์ด๋‹ค.

๊ทธ๋ ‡๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ ํ™”๋ฉด์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

์ด์ œ ๊ฐ ๋ฉ”๋‰ด๋ณ„ ํ™”๋ฉด ๊ธฐํš ๋ฐ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์„ ์‹œ์ž‘ํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

์šฐ์„  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” AWS document DB์—์„œ ์ง€์›ํ•˜๋Š” mongo DB๋ฅผ ์จ๋ณผ ์˜ˆ์ •์ด๋‹ค.

ํ•œ row์— ๋Œ€ํ•ด์„œ ์ด 16MB ๊นŒ์ง€ ๋ฐ์ดํ„ฐ ์ €์žฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ˆ ์ด๋ฏธ์ง€๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๊ฒŒ์‹œ๊ธ€์— ๋Œ€ํ•ด์„œ๋„ ํ•˜๋‚˜์˜ row์— ์ €์žฅ์„ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. 

๋ฌด๋ฃŒ๋กœ mongoDB ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ด๋Ÿฐ์ €๋Ÿฐ ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ์ œ์•ฝ์‚ฌํ•ญ์ด ์ƒ๊ธธ ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฒ„์ „์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•  ์˜ˆ์ •์ด๋‹ค.

๋ฐฑ์—”๋“œ๋Š”.....์—ญ์‹œ ์ œ์ผ ๋นจ๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํ”„๋ง๋ถ€ํŠธ๊ธฐ๋ฐ˜์˜ ์ž๋ฐ”๋กœ ๊ฐ€์•ผ๊ฒ ๋‹ค.. ์‹œ๊ฐ„๋‹จ์ถ•์„ ์œ„ํ•ด์„œ...

 

์›น ์ƒ์—์„œ ์„ค๋ฌธ์ง€ ํŽ˜์ด์ง€์— ์ด์šฉํ•˜๊ธฐ ์ข‹์€ fieldset ํƒœ๊ทธ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

fieldset ํƒœ๊ทธ๋Š” form๋‚ด์—์„œ ์—ฐ๊ด€๋œ ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ๊ทธ๋ฃนํ™”ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ทธ๋ ‡๊ฒŒ ๊ทธ๋ฃนํ™”๋œ ์—˜๋ฆฌ๋จผํŠธ๋“ค์„ ๋‘˜๋Ÿฌ์‹ผ ์„ ์„ ๊ทธ๋ ค์ค๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ ๋ง์ด์ฃ 

<fieldset> ํƒœ๊ทธ๋ฅผ ํ™œ์šฉํ•œ ์„ค๋ฌธ์ง€ ์˜ˆ์ œ

์œ„ ์ฒ˜๋Ÿผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•˜๋ ค๋ฉด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

<form action="#">
  <fieldset>
      <legend>1. ์ข‹์•„ํ•˜๋Š” ์ƒ‰๊น”์€?</legend>
      <input type="radio" id="blue" name="favorite-color"><label for="blue">ํŒŒ๋ž€์ƒ‰</label>
      <input type="radio" id="green" name="favorite-color"><label for="green">์ดˆ๋ก์ƒ‰</label>
      <input type="radio" id="red" name="favorite-color"><label for="red">๋นจ๊ฐ„์ƒ‰</label>
    </fieldset>
    
    <p></p>
    
    <fieldset>
      <legend>2. ์ข‹์•„ํ•˜๋Š” ์Œ์‹ ์ข…๋ฅ˜๋Š”?</legend>
      <input type="radio" id="korean" name="food-type"><label for="korean">ํ•œ์‹</label>
      <input type="radio" id="american" name="food-type"><label for="american">์–‘์‹</label>
      <input type="radio" id="japanese" name="food-type"><label for="japanese">์ผ์‹</label>
      <input type="radio" id="chinese" name="food-type"><label for="chinese">์ค‘์‹</label>
    </fieldset>
</form>

 

์ฆ‰, legend ํƒœ๊ทธ๋ฅผ ์ด์šฉํ•˜์—ฌ ํƒ€์ดํ‹€์„ ๋„ฃ์–ด์ฃผ๊ณ  input ์ด๋‚˜ textarea์™€ ๊ฐ™์€ ํƒœ๊ทธ๋“ค์„ ์ด์šฉํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ์— ํ•˜๋‚˜์˜ ํ•„๋“œ์…‹์„ ๋” ์ถ”๊ฐ€ํ•˜์—ฌ ์ฃผ๊ด€์‹ ๋ฌธํ•ญ์„ ๋„ฃ์–ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

<fieldset> ํƒœ๊ทธ๋ฅผ ํ™œ์šฉํ•œ ์„ค๋ฌธ์ง€ ์˜ˆ์ œ

<form action="#">
    <fieldset>
      <legend>1. ์ข‹์•„ํ•˜๋Š” ์ƒ‰๊น”์€?</legend>
      <input type="radio" id="blue" name="favorite-color"><label for="blue">ํŒŒ๋ž€์ƒ‰</label>
      <input type="radio" id="green" name="favorite-color"><label for="green">์ดˆ๋ก์ƒ‰</label>
      <input type="radio" id="red" name="favorite-color"><label for="red">๋นจ๊ฐ„์ƒ‰</label>
    </fieldset>
    <p></p>
    <fieldset>
      <legend>2. ์ข‹์•„ํ•˜๋Š” ์Œ์‹ ์ข…๋ฅ˜๋Š”?</legend>
      <input type="radio" id="korean" name="food-type"><label for="korean">ํ•œ์‹</label>
      <input type="radio" id="american" name="food-type"><label for="american">์–‘์‹</label>
      <input type="radio" id="japanese" name="food-type"><label for="japanese">์ผ์‹</label>
      <input type="radio" id="chinese" name="food-type"><label for="chinese">์ค‘์‹</label>
    </fieldset>
    <p></p>
    <fieldset>
      <legend>3. ํƒ•์ˆ˜์œก์€ ์–ด๋–ป๊ฒŒ ๋จน์–ด์•ผ ๋ง›์žˆ๋‚˜์š”?</legend>
      <textarea placeholder="์ƒ๊ฐ์„ ์ ์–ด์ฃผ์„ธ์š”."></textarea>
    </fieldset>
  </form>

 

fieldset ํƒœ๊ทธ๋Š” ํฌ๋กฌ, ํŒŒํญ, ์—ฃ์ง€, ์˜คํŽ˜๋ผ ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์›ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ fieldset์˜ ์†์„ฑ์œผ๋กœ disabled๋ฅผ ๋ช…์‹œํ•ด์ฃผ๋ฉด ํ•ด๋‹น ํ•„๋“œ์…‹ ๋‚ด์˜ ์—˜๋ฆฌ๋จผํŠธ๋“ค์ด ๋ชจ๋‘ ๋น„ํ™œ์„ฑํ™” ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

 

๊ฐœ์ธ๋ธ”๋กœ๊ทธ ๋งŒ๋“ค๊ธฐ ํ”„๋กœ์ ํŠธํ•˜๋‹ค๊ฐ€ ์•Œ๊ฒŒ๋œ ์ƒˆ๋กœ์šด ํƒœ๊ทธ๋ผ ๊ธฐ๋ก์šฉ์œผ๋กœ ํฌ์ŠคํŒ…ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

 

์ฐธ๊ณ ๋ฌธ์„œ: https://developer.mozilla.org/ko/docs/Web/HTML/Element/fieldset

๋ธ”๋กœ๊ทธ ์›น์•ฑ ๋งŒ๋“ค๊ธฐ ๊ฐœ์ธํ”„๋กœ์ ํŠธ

ํ‹ฐ์Šคํ† ๋ฆฌ ๋ธ”๋กœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•œ์ง€๋„ ๋ช‡ ๋…„์ด ๋œ ๊ฒƒ ๊ฐ™๋‹ค.

์ฒ˜์Œ ์‹œ์ž‘์€ ๊ตฌ๊ธ€ ๊ด‘๊ณ ๋ฅผ ๋ถ™์—ฌ์„œ ๊ด‘๊ณ ์ˆ˜์ต์„ ์–ป์„ ์ƒ๊ฐ์œผ๋กœ ์‹œ์ž‘ํ–ˆ์—ˆ๋Š”๋ฐ

์ด์ง์„ ํ•˜๊ณ  ๋Œ€๊ทœ๋ชจ ์•ฑ์„ ๊ฑฐ์˜ ํ˜ผ์ž์„œ ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ์‹ ๊ทœ๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ ๋„ˆ๋ฌด ๋ฐ”๋น ์„œ ๊ธ€์„ ์“ธ ์‹œ๊ฐ„์ด ์—†์—ˆ๋‹ค.

๊ทธ๋ ‡๊ฒŒ 2๋…„์ด ๋„˜๋Š” ์‹œ๊ฐ„์ด ํ›Œ์ฉ ํ˜๋ €๋‹ค.

์ด์งํ•œ ํšŒ์‚ฌ์—์„œ ๊ด€๋ฆฌ์ž ์›น์•ฑ์„ ํ˜ผ์ž ๊ด€๋ฆฌํ•˜๊ฒŒ ๋˜๋ฉด์„œ ํ‰์†Œ ํ’€์Šคํƒ์ด ๋˜๊ณ ์‹ถ์—ˆ๋˜ ๊ฟˆ์ด ๋‹ค์‹œ ์‚ด์•„๋‚˜๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ 

๋ช‡ ์ผ ์ „๋ถ€ํ„ฐ ๋ฆฌ์•กํŠธ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค.

์ƒํ™œ์ฝ”๋”ฉ์˜ ๋ฆฌ์•กํŠธ ๋™์˜์ƒ๋„ ๋ณด๊ณ , ๋ฆฌ๋•์Šค ๊ฐ•์ขŒ๋„ ๋ณด๊ณ ...

ํ•˜์ง€๋งŒ ์—ญ์‹œ ๋ณด๊ธฐ๋งŒ ํ•˜๋Š”๊ฑด ํฐ ๋„์›€์ด ๋˜์ง€ ์•Š๊ธฐ์— ์ง์ ‘ ์ฝ”๋”ฉ์„ ํ•ด๊ฐ€๋ฉด์„œ ๊ณต๋ถ€ํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๊ณ 

์–ด๋–ค ํ”„๋กœ์ ํŠธ๋ฅผ ํ•ด๋ณผ๊นŒ ํ•˜๋‹ค๊ฐ€ ๊ฐœ์ธ ๋ธ”๋กœ๊ทธ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

ํ‹ฐ์Šคํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ๋“ค๋ณด๋‹ค ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์ด ๋งŽ์•„ ์ข‹๊ธดํ•˜์ง€๋งŒ ๊ทธ๋ž˜๋„ ์ œ์•ฝ์‚ฌํ•ญ์ด ์žˆ์„ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ‹ฐ์Šคํ† ๋ฆฌ๊ฐ€ ์„œ๋น„์Šค ์ค‘์ง€ ์„ ์–ธ์„ ํ•ด๋ฒ„๋ฆฌ๋ฉด? ใ… ใ… 

๊ทธ๋Ÿผ ์ž‘์„ฑํ•œ ๊ธ€๋“ค๋„ ๋ชจ๋‘ ์‚ฌ๋ผ์ง€๊ฒŒ ๋ ํ…Œ๋‹ˆ ๋ง์ด๋‹ค. 

์„ค๋ น ์ž‘์„ฑํ•œ ๊ธ€๋“ค์„ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค๊ณ  ํ•ด๋„ ํฌ๋งท์„ ์–ด๋–ป๊ฒŒ ์ œ๊ณตํ•˜๋Š๋ƒ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ์— ์˜ฎ๊ฒจ์‹ฌ๊ธฐ๋„ ๋ถˆํŽธํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ๊ธฐํšŒ์— ๊ฐœ์ธ ๋ธ”๋กœ๊ทธ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด์„œ ๋„๋ฉ”์ธ ์—ฐ๋™๋„ ํ•˜๊ณ  ๊พธ์ค€ํžˆ ์ž˜ ๊ฐ€๊พธ์–ด ๋‚˜๊ฐ€์•ผ ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ธ”๋กœ๊ทธ๋ฅผ ์™„์„ฑํ•˜๊ธฐ ๊นŒ์ง€์˜ ๊ณผ์ •์„ ์ด๊ณณ์— ๋‚จ๊ฒจ๋‘๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

๊ทธ๋ ‡๊ฒŒ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์˜ ๋ฆฌ์•กํŠธ๋กœ ๊ฐœ์ธ๋ธ”๋กœ๊ทธ ๋งŒ๋“ค๊ธฐ๋Š” ์‹œ์ž‘์ด ๋˜์—ˆ๋‹ค...

 

ํ•ด์•ผํ•  ์ผ์€ ๋งŽ๋‹ค. ์„œ๋ฒ„๋Š” ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•  ๊ฒƒ์ด๋ฉฐ ์–ด๋–ค ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ธ์ง€ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์€ ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ์ง€ ๋“ฑ๋“ฑ...

ํ•˜์ง€๋งŒ ์ด๋Ÿฐ๊ฒƒ๋“ค์„ ์ƒ์„ธํ•˜๊ฒŒ ๋‹ค ๋”ฐ์ ธ๊ฐ€๋ฉด์„œ ํ•˜๊ธฐ์—๋Š” ์‹œ๊ฐ„์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๋‹ˆ ๋ฆฌ์•กํŠธ๋กœ ํ™”๋ฉด๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์— ์ผ๋‹จ ์ง‘์ค‘ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ์—ฌ๋Ÿฌ ์‚ฌ์ดํŠธ๋ฅผ ๋Œ์•„๋‹ค๋‹ˆ๋ฉด์„œ ๋ฒค์น˜๋งˆํ‚นํ•˜๋ฉด์„œ ํ•ด์•ผ๊ฒ ๋‹ค

๋ฐฑ์—”๋“œ๋Š” ๋Š˜ ํ•ด์˜ค๋˜ ์ž๋ฐ”์™€ ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์ด์šฉํ• ์ง€...์˜ˆ์ „์— ํ•ด๋ดค๋˜ ๋…ธ๋“œ๋ฅผ ๋‹ค์‹œ ์จ๋ณผ์ง€...ํŒŒ์ด์ฌ์„ ์จ๋ณผ์ง€ ๊ณ ๋ฏผ์ด ์ข€ ๋˜๋Š”๋ฐ...

์ž๋ฐ”+์Šคํ”„๋ง๋ถ€ํŠธ๋Š” ์—…์œผ๋กœ ํ•˜๊ณ ์žˆ๋Š” ์ŠคํŽ™์ด๋‹ค๋ณด๋‹ˆ ๋น ๋ฅธ ์‹œ๊ฐ„๋‚ด์— ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด ๋ฆฌ์•กํŠธ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํ”„๋กœ์ ํŠธ๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๊ด€๋ฆฌํ•ด์•ผํ•  ๊ฒƒ ๊ฐ™๊ณ  ๋…ธ๋“œ์„œ๋ฒ„์™€ ์ž๋ฐ”์„œ๋ฒ„๋ฅผ ๋„์›Œ์•ผ ์™„์ „์ฒด๊ฐ€ ๋œ๋‹ค. 

๋…ธ๋“œ๋ฅผ ์“ฐ๋ฉด ํ”„๋ก ํŠธ์™€ ๋ฐฑ์—”๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ตณ์ด ๋ถ„๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†๊ณ  ์„œ๋ฒ„๋„ ๋…ธ๋“œ์„œ๋ฒ„๋งŒ ๋„์šฐ๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ์ธ์šฉ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ์—๋Š” ๋” ํŽธํ•˜๊ธด ํ•˜์ง€๋งŒ, ์ต์ˆ™ํ•˜์ง€ ์•Š์€ ๋…ธ๋“œ๋ฅผ ์“ฐ์ž๋‹ˆ ์ข€ ๋ถ€๋‹ด์ด ๋˜๊ธดํ•œ๋‹ค.

 

์ผ๋‹จ์€ ๋ฆฌ์•กํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ๊ป๋ฐ๊ธฐ(ํ”„๋ก ํŠธ)๋ถ€ํ„ฐ ๋งŒ๋“ค์–ด๋†“๊ณ  ๊ณ ๋ฏผํ•ด์•ผ๊ฒ ๋‹ค.

 

 

 

ํŠน๋ณ„ํžˆ ๋‚ด๊ฐ€ ๋ญ ์ž˜๋ชปํ•œ๊ฑฐ ์—†๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ ์›น์‚ฌ์ดํŠธ๋ฅผ ์„œํ•‘ํ•˜๋‹ค๋ณด๋ฉด ๊ผญ ๋‚˜๋งŒ ์ด์ƒํ•œ ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚˜๊ธฐ๋„ ํ•œ๋‹ค.

์ด๋ฒˆ์—๋„ ์ฒ˜์Œ๋ณด๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด์„œ ์งง๊ฒŒ ๊ธฐ๋ก์œผ๋กœ ๋‚จ๊ฒจ๋ณธ๋‹ค.

ํฌ๋กฌ์„ ๋ฉ”์ธ ๋ธŒ๋ผ์šฐ์ €๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋Š”๋ฐ ์–ผ๋งˆ ์ „๋ถ€ํ„ฐ ํŠน์ • ์‚ฌ์ดํŠธ์—๋งŒ ์ ‘์†ํ•˜๋ ค๊ณ  ํ• ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋–ด๋‹ค.

HTTP Bad Request - Header Field Too Long

์™€~ ์ด๊ฑด ๋ญ์ง€? ํ—ค๋” ํ•„๋“œ ๊ธธ์ด๊ฐ€ ใ„ด ~~~~ใ…“ ๋ฌด ๊ธธ๋‹ค๊ณ  ?? ๋‚œ ๋ญ ํ•œ๊ฒŒ ์—†๋Š”๋ฐ? ๋‚œ ๊ทธ๋ƒฅ ์‚ฌ์ดํŠธ์— ์ ‘์†์„ ์‹œ๋„ํ•œ๊ฒƒ ๋ฟ์ธ๋ฐ?

์‚ฌํŒŒ๋ฆฌ๋ฅผ ์ด์šฉํ•ด์„œ ์ ‘์†์„ ์‹œ๋„ํ•˜๋‹ˆ ์ •์ƒ์ ์œผ๋กœ ์ ‘์†์ด ๋œ๋‹ค.

๋ญ์ง€?

์—ญ์‹œ ๋ธŒ๋ผ์šฐ์ € ๋ฌธ์ œ์˜€์–ด.

ํฌ๋กฌ์—์„œ ์ฟ ํ‚ค์™€ ์ž„์‹œ์ธํ„ฐ๋„ท ํŒŒ์ผ๋“ค์„ ์‚ญ์ œํ•˜๊ณ  ์žฌ์ ‘์†์„ ์‹œ๋„ํ–ˆ๋‹ค.

์ •.์ƒ.์ ‘.์†.

๋ธŒ๋ผ์šฐ์ €์— ์บ์‹ฑ๋œ ๋ญ”๊ฐ€๊ฐ€ header field์™€ ์—ฐ๊ด€๋˜์–ด์žˆ๋Š”๊ฑด์ง€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ์ผ€์ด์Šค์˜€๋‹ค.

mysql(AWS aurora aurora_version,2.07.1, innodb_version,5.7.12)์—์„œ json ํƒ€์ž… ์ปฌ๋Ÿผ์„ ์ง€์›ํ•˜๊ณ  ์žˆ๊ณ  json string์„ ์ €์žฅํ•ด์•ผํ•  ์ผ์ด ์ƒ๊ฒจ ์˜ค๋žœ๋งŒ์— ํ•ด๋‹น ํƒ€์ž…์œผ๋กœ ์ปฌ๋Ÿผ์„ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ์ปฌ๋Ÿผ์˜ ๋‚ด์šฉ์ด ์—…๋ฐ์ดํŠธ๊ฐ€ ์•ˆ๋˜๋Š” ํ˜„์ƒ์„ ํ™•์ธํ–ˆ๋‹ค. ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ๋ฐ์ดํ„ฐ๋Š” double ๊ฐ’์„ ํฌํ•จํ•˜๋Š” ์ขŒํ‘œ๋ฐ์ดํ„ฐ์˜€๋‹ค.

 

{"latitude": 24.4436779, "longitude": 116.35241670000043}

 

์ด๋Ÿฐ ๋ฐ์ดํ„ฐ์˜€๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ๋ถ€๋ถ„์€ longitude ์˜€๋‹ค.

 

์œ ๋‹›ํ…Œ์ŠคํŠธ(java correto 11)์—์„œ ํ™•์ธ ์‹œ์— ์—…๋ฐ์ดํŠธ๋œ ๊ฐ’์ด ์ œ์ผ ๋์— ํ•œ์ž๋ฆฌ๊ฐ€ ๋ฐ”๋€Œ์–ด์„œ 116.35241670000045 ๋กœ ์ฝ˜์†”์— ์ถœ๋ ฅ๋˜์—ˆ๋Š”๋ฐ jpa ์—…๋ฐ์ดํŠธ ์‹œ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋‹ค.

 

update์ผ์‹œ ์ปฌ๋Ÿผ(timestamp)์— on update current_timestamp ์„ค์ •์ด ๋˜์–ด์žˆ์Œ์—๋„ ์—…๋ฐ์ดํŠธ ์ผ์‹œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค.

 

์ฟผ๋ฆฌ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ง์ ‘ ๋‚ ๋ ค๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€๋‹ค -_-; ์—ฌ๊ธฐ์„œ ์ข€ ๋ฉ˜๋ถ•;;

update location set coordinate = '{"latitude": 24.4436779, "longitude": 116.35241670000045}' where id=1;

jpa๊ฐ€ ์–ด๋–ป๊ฒŒ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ธ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๋‹ˆ ์ง์ ‘ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ ๊ฒƒ๊ณผ ๋™์ผํ–ˆ๋‹ค.

 

์• ์ดˆ์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ œ๋Œ€๋กœ ์•ˆ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์„ ๋•Œ ์–ด์ฐจํ”ผ string์œผ๋กœ ์ „๋‹ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— double precision์ด ๋ฌธ์ œ๊ฐ€ ๋ ๊ฑฐ๋ผ๋Š” ์ƒ๊ฐ์€ ์—†์—ˆ์œผ๋‚˜, ๊ตฌ๊ธ€๋ง์„ ํ•˜๋ฉด ํ•  ์ˆ˜๋ก ๋ฌธ์ œ๊ฐ€ ๋ ๋งŒํ•œ๊ฑด double precision ๋ฐ–์— ์—†์–ด๋ณด์˜€๋‹ค.

 

๊ฒ€์ƒ‰์–ด๋ฅผ ์ข€ ๋ฐ”๊ฟ”์„œ double precision ๊ด€๋ จํ•ด์„œ ์ฐพ์•„๋ณด๋‹ˆ double precision์˜ ๊ฒฝ์šฐ 16์ž๋ฆฌ๊นŒ์ง€ ( . ์ œ์™ธํ•˜๊ณ  ์ˆซ์ž๋งŒ ์…‹์„ ๋•Œ) ์ •ํ™•ํžˆ ํ‘œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค. ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ ์ผ€์ด์Šค๋Š” ์ด 17์ž๋ฆฌ์˜ ์†Œ์ˆ˜์ ์ด์—ˆ๊ณ  ๋”ฐ๋ผ์„œ ๋งˆ์ง€๋ง‰ ์ž๋ฆฌ์ˆ˜์— ๋Œ€ํ•œ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง€๊ฒŒ ๋œ ๊ฒƒ์ด๋‹ค.

 

ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด value์˜ ํƒ€์ž…์„ double์ด ์•„๋‹Œ string์œผ๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์žˆ์–ด๋ณด์˜€์œผ๋‚˜, ์ขŒํ‘œ์— ๋Œ€ํ•œ ์ž๋ฆฌ์ˆ˜๊ฐ€ ์ €๋ ‡๊ฒŒ ๊ธด๊ฒŒ ๋งž๋Š” ๊ฒƒ์ธ์ง€ ํ™•์ธํ•ด๋ณด๋‹ˆ ์ขŒํ‘œ ๋ฐ์ดํ„ฐ ์ €์žฅ์‹œ 8์ž๋ฆฌ ์ด์ƒ์€ ๋…ธ์ด์ฆˆ๊ฐ’์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†์„๊ฒƒ ๊ฐ™์•˜๋‹ค. -> ์œ„ํ‚ค ์ฐธ๊ณ 

 

๋”ฐ๋ผ์„œ ํ•ด๋‹น ์ด์Šˆ๋Š” ์ €์žฅํ•˜๋Š” ์ชฝ์€ ์ด์Šˆ๊ฐ€ ์—†๊ณ  ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ์ชฝ์—์„œ ์ž˜ ๊ฐ€์ ธ๋‹ค ์“ฐ๋ฉด ๋  ๋ฌธ์ œ์˜€๋‹ค.

 

์˜ค๋žœ๋งŒ์— ์•ผ๊ทผํ–ˆ์œผ๋‚˜ ๋˜ํ•˜๋‚˜ ์•Œ๊ฒŒ๋œ ๊ฒƒ์ด ์žˆ์–ด ๊ธฐ์œ ํ•˜๋ฃจ์˜€๋‹ค~

 

 

[์ฐธ๊ณ ๋‚ด์šฉ]

stackoverflow.com/questions/49119871/mysql-json-stores-different-floating-point-value

 

 

๐Ÿ’ป Programming

Apache Kafka ์šด์˜ ํŒ

Kafka ์šด์˜์‹œ ์œ ์šฉํ•œ ๋ช…๋ น์–ด

ํ† ํ”ฝ ๋ชฉ๋ก ์กฐํšŒ

bin/kafka-topics.sh --zookeeper localhost:2181 --list

 

ํ† ํ”ฝ ์ƒ์„ธ ์กฐํšŒ

bin/kafka-topics.sh --zookeeper localhost:2181 --describe --topic mytopic

 

ํ† ํ”ฝ ์‚ญ์ œ

bin/kafka-topics.sh --zookeeper localhost:2181 --delete --topic mytopic  (JRE 7 ์‚ฌ์šฉ์‹œ confluent-3.0.0 ์‚ฌ์šฉ)

 

ํ† ํ”ฝ ๋‚ด ๋ฉ”์‹œ์ง€ ๊ฐœ์ˆ˜ ์กฐํšŒ ???

bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic mytopic --time -1 --offsets 1 | awk -F ":" '{sum += $3} END {print sum}'

 

ํ† ํ”ฝ ๋‚ด earliest ์˜คํ”„์…‹ ์กฐํšŒ

bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic mytopic --time -2

 

ํ† ํ”ฝ ๋‚ด ์ตœ์‹  ์˜คํ”„์…‹ ์กฐํšŒ

bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:9092 --topic mytopic --time -1

 

์ฝ˜์†” ๋ช…๋ น์–ด๋กœ ๋ฉ”์‹œ์ง€ ์ปจ์ˆจํ•˜๊ธฐ

bin/kafka-console-consumer.sh --new-consumer --bootstrap-server localhost:9092 --topic mytopic --from-beginning

 

 

์•„ํŒŒ์น˜ ์นดํ”„์นด ์ปจ์ˆ˜๋จธ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ๋กœ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•œ ํŒ

 

 

 

์ฐธ๊ณ ๋ฌธ์„œ : gist.github.com/ursuad/e5b8542024a15e4db601f34906b30bb5

1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ์•„์ง ์•ˆ๋ณด์…จ๋‹ค๋ฉด ๋ณด๊ณ  ์˜ค์„ธ์š”~ >> 1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ(์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”)

1์ฐจ์› ๋ฐฐ์—ด์ด 1์—ด๋กœ ๋œ ์ €์žฅ๊ณต๊ฐ„์ด์—ˆ๋‹ค๋ฉด 2์ฐจ์› ๋ฐฐ์—ด์€ matrix(ํ–‰๋ ฌ)์„ ์ƒ๊ฐํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

2์ฐจ์› ๋ฐฐ์—ด ์„ ์–ธ

์ž๋ฐ”์—์„œ 2์ฐจ์› ๋ฐฐ์—ด์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        int[][] array;  // O
        int [][]array;  // X
        int array[][];  // X
    }

์ง€๋‚œ 1์ฐจ์› ๋ฐฐ์—ด ์ƒ์„ฑ ์‹œ์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ œ์ผ ์œ„์˜ ๋ฐฉ๋ฒ•์œผ๋กœ๋งŒ ๋ฌธ๋ฒ•์  ์˜ค๋ฅ˜ ์—†์ด ์ •์ƒ์ ์œผ๋กœ 2์ฐจ์› ๋ฐฐ์—ด์„ ์„ ์–ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

2์ฐจ์› ๋ฐฐ์—ด์˜ ์ดˆ๊ธฐํ™”

2์ฐจ์› ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™” ํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ฉ๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array;  // 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ

        array = new int[1][5];	// 2์ฐจ์› ๋ฐฐ์—ด์˜ ์ดˆ๊ธฐํ™”
    }

 

2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•˜๋Š” ๋ฐฉ๋ฒ•

2์ฐจ์› ๋ฐฐ์—ด๋„ 1์ฐจ์› ๋ฐฐ์—ด์ฒ˜๋Ÿผ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {
        
        int[][] array = new int[1][5];  // 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ ๋ฒˆ์—

    }

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐฐ์—ด ๋‚ด์—๋Š” 0์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

1์ฐจ์› ๋ฐฐ์—ด๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์•„๋ž˜์ฒ˜๋Ÿผ ์ดˆ๊ธฐํ™”๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array = {{1,2,3}, {4,5,6}};

    }

์ด๋ ‡๊ฒŒ ์ดˆ๊ธฐํ™”๋ฅผ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๊ธฐ๋ณธ๊ฐ’์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์—ฌ ์ •ํ•ด์ฃผ๊ฒ ๋‹ค๋Š” ๊ฒƒ์ด๊ฒ ์ฃ .

 

์ž, ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๊ณ  ๊ณต๊ฐ„์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ์ž‘์—…์„ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๋ฐฐ์—ด์— ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ํ•œ ๋ฒˆ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

2์ฐจ์› ๋ฐฐ์—ด ์ถœ๋ ฅํ•˜๊ธฐ

1์ฐจ์› ๋ฐฐ์—ด์„ ์ถœ๋ ฅํ•  ๋•Œ๋Š” Arrays.toString() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ 2์ฐจ์› ๋ฐฐ์—ด์„ ์ถœ๋ ฅํ•  ๋•Œ๋Š” ๊ทธ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์™œ๋ƒ๋ฉด 2์ฐจ์› ๋ฐฐ์—ด์€ ๋ฐฐ์—ด ์•ˆ์— ๋ฐฐ์—ด์ด ์žˆ๋Š” ํ˜•ํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋ฐฐ์—ด์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Object ์ด๊ณ  Object์˜ toString์ด ํ˜ธ์ถœ๋˜์–ด ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•ด์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋ณ„๋„๋กœ ์ถœ๋ ฅ๋ฌธ์„ ๊ตฌํ˜„ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

์‰ฝ๊ฒŒํ•˜๋ ค๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ loop๋ฅผ ํ•œ๋ฒˆ ๋Œ๋ฆฌ๋ฉด์„œ ์ถœ๋ ฅ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // ๊ตฌ๊ตฌ๋‹จ ๊ฒฐ๊ณผ๊ฐ’ ์ €์žฅ์„ ์œ„ํ•œ 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”

        for (int i = 0; i < array.length; i++) {
            System.out.println(Arrays.toString(array[i]));
        }
    }

 

๊ทธ๋Ÿผ ์—ฐ์Šต์‚ผ์•„ 2์ฐจ์› ๋ฐฐ์—ด์•ˆ์— ๊ตฌ๊ตฌ๋‹จ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด๋ณด๋„๋ก ํ•ด๋ณผ๊ฒŒ์š”.

 

    public static void main(String[] args) {

        int[][] array = new int[8][9];  // ๊ตฌ๊ตฌ๋‹จ ๊ฒฐ๊ณผ๊ฐ’ ์ €์žฅ์„ ์œ„ํ•œ 2์ฐจ์› ๋ฐฐ์—ด์˜ ์„ ์–ธ ๋ฐ ์ดˆ๊ธฐํ™”

	// ๋ฐฐ์—ด์— ๊ตฌ๊ตฌ๋‹จ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ์ €์žฅ
        for (int i = 2; i < 10; i++) {
            for (int j = 1; j < 10; j++) {
                array[i-2][j-1] = i * j;
            }
        }

	// ๋ฐฐ์—ด์— ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅ
        for (int i = 0; i < array.length; i++) {
            System.out.print((i + 2) + "๋‹จ: ");
            System.out.print(Arrays.toString(array[i]));
            System.out.println();
        }
    }
    
    
    // ์ถœ๋ ฅ ๊ฒฐ๊ณผ
    2๋‹จ: [2, 4, 6, 8, 10, 12, 14, 16, 18]
    3๋‹จ: [3, 6, 9, 12, 15, 18, 21, 24, 27]
    4๋‹จ: [4, 8, 12, 16, 20, 24, 28, 32, 36]
    5๋‹จ: [5, 10, 15, 20, 25, 30, 35, 40, 45]
    6๋‹จ: [6, 12, 18, 24, 30, 36, 42, 48, 54]
    7๋‹จ: [7, 14, 21, 28, 35, 42, 49, 56, 63]
    8๋‹จ: [8, 16, 24, 32, 40, 48, 56, 64, 72]
    9๋‹จ: [9, 18, 27, 36, 45, 54, 63, 72, 81]

 

๋กœ์ง์„ ํ•œ๋ฒˆ ๋ณด๋ฉด ํฌ๊ฒŒ ๊ตฌ๊ตฌ๋‹จ์„ ์ €์žฅํ•  ๋•Œ์™€ ์ €์žฅ๋œ ๋‚ด์šฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ๋ถ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  for-loop๋ฌธ์˜ ์กฐ๊ฑด๊ฑธ์— ํ•˜๋“œ์ฝ”๋”ฉํ•œ ์ˆซ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•˜๊ณ  array.length ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๊ธ‰์  array.length ์˜ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜๋ฉฐ 2์ฐจ์› ๋ฐฐ์—ด์—์„œ array.length๋Š” ํ–‰์ด ๋ช‡ ๊ฐœ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , array[x].length๋Š” ์—ด์˜ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ๊ตฌ๋‹จ์€ ๋ณดํ†ต 2๋‹จ๋ถ€ํ„ฐ 9๋‹จ๊นŒ์ง€์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ ์‚ฌ์ด์ฆˆ๋ฅผ 8ํ–‰, 9์—ด๋กœ ์ •์˜๋ฅผ ํ•˜์˜€๊ณ , array.length ๋Š” 8, array[x].length ๋Š” 9 ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

 

 

์ด์ƒ์œผ๋กœ ์ž๋ฐ”์—์„œ 2์ฐจ์› ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๊ณ  ์ดˆ๊ธฐํ™”ํ•˜๊ณ  ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•œ ๋’ค ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ ๊นŒ์ง€ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์งˆ๋ฌธ์žˆ์œผ์‹œ๋ฉด ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์„ธ์š”~

 

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด ๊ณต๊ฐ~ ๊พธ~~~์šฑ ๋ˆŒ๋Ÿฌ์ฃผ์„ธ์š” ^-^

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~

์•ˆ๋…•ํ•˜์„ธ์š”, ์ผ€์ด์น˜์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์ •๊ทœํ‘œํ˜„์‹์ด ๋ฌด์—‡์ธ์ง€ ๊ทธ๋ฆฌ๊ณ  ๋ฌธ๋ฒ•์€ ์–ด๋–ป๊ฒŒ ๋˜๋ฉฐ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ •๊ทœํ‘œํ˜„์‹์ด๋ž€?

- ์ •๊ทœํ‘œํ˜„์‹(regular expression)์ด๋ž€ ๊ฒ€์ƒ‰ ํŒจํ„ด์„ ์ •์˜ํ•œ ๋ฌธ์ž์—ด์ด๋ผ๊ณ  ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. regex ๋˜๋Š” regexp๋กœ ์ค„์—ฌ์„œ ๋งํ•˜๊ธฐ๋„ ํ•˜๋ฉฐ pattern์ด๋ผ๊ณ  ํ•˜๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ •๊ทœํ‘œํ˜„์‹์€ ๋ณดํ†ต ์ž„์˜์˜ string ๋‚ด์—์„œ ํŠน์ • ํŒจํ„ด์— ์ผ์น˜ํ•˜๋Š” ๋ฌธ์ž๋‚˜ ๋ฌธ์ž์—ด์„ ์ฐพ์•„๋‚ด๊ฑฐ๋‚˜(find) ์ฐพ์•„์„œ ๋ณ€๊ฒฝ(find and replace)ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ ๋กœ ์ •๊ทœํ‘œํ˜„์‹์˜ ๊ฐœ๋…์€ 1950๋…„๋Œ€์— ๋ฏธ๊ตญ์˜ ์ˆ˜ํ•™์ž Stephen Cole Kleene์— ์˜ํ•ด์„œ ์‹œ์ž‘๋˜์—ˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. 

 

์ •๊ทœํ‘œํ˜„์‹์˜ ๊ธฐ๋ณธ๋ฌธ๋ฒ•

 

Boolean "or"

 | swim|swam ๋Š” "swim" ๋˜๋Š” "swam" ๊ธ€์ž์™€ ๋งค์นญ๋ฉ๋‹ˆ๋‹ค

 

Grouping

์†Œ๊ด„ํ˜ธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ทธ๋ฃน์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ๋“ค์–ด sw(i|a)m ํŒจํ„ด์€ ๋ฐ”๋กœ ์œ„ ์˜ˆ์ œ์™€ ๋™์ผํ•˜๊ฒŒ "swim"๊ณผ "swam" ๋‹จ์–ด์™€ ๋งค์นญ๋ฉ๋‹ˆ๋‹ค.

 

์ˆ˜๋Ÿ‰(๊ฐœ์ˆ˜) ํŒจํ„ด

 ?  : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด 0~1๊ฐœ ์กด์žฌ

 *  : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด 0๊ฐœ ์ด์ƒ ์กด์žฌ

 +  : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด 1๊ฐœ ์ด์ƒ ์กด์žฌ

{n} : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด ์ •ํ™•ํžˆ n๋ฒˆ ์กด์žฌ

{min,} : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด ์ตœ์†Œ min ๊ฐœ ์กด์žฌ

{min,max} : ๋ฐ”๋กœ ์•ž์— ์žˆ๋Š” ๊ธ€์ž ๋˜๋Š” ๊ทธ๋ฃน์ด ์ตœ์†Œ min ์ด์ƒ ์ตœ๋Œ€ max ์ดํ•˜ ์กด์žฌ

 

์™€์ผ๋“œ์นด๋“œ (Wildcard)

 .  : ์™€์ผ๋“œ์นด๋“œ ๋ฌธ์ž๋Š” ์•„๋ฌด ์บ๋ฆญํ„ฐ(any character)๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ์–ด๋–ค ๊ธ€์ž์ด๋˜ ํŠน์ˆ˜๊ธฐํ˜ธ์ธ์ง€ ์•ŒํŒŒ๋ฒณ์ธ์ง€ ์ˆซ์ž์ธ์ง€์— ๊ด€๊ณ„์—†์ด 1๊ฐœ์˜ character๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, a.b ํŒจํ„ด์€ a์™€b ์‚ฌ์ด์— ์–ด๋–ค ๋ฌธ์ž๊ฐ€ ์™€๋„ ๋งค์นญ๋ฉ๋‹ˆ๋‹ค. "acb", "a3b", "aAb" ๋“ฑ๋“ฑ์ด ๋ชจ๋‘ ๋งค์นญ๋˜์ฃ . ์ด ์™€์ผ๋“œ์นด๋“œ ๋ฌธ์ž์™€ ์ˆ˜๋Ÿ‰์„ ๋‚˜ํƒ€๋‚ด๋Š” *๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ a.*b ํŒจํ„ด์œผ๋กœ ๋งค์นญ์„ ์‹œ๋„ํ•˜๋ฉด "a123b", "ab", "aTTb" ๋“ฑ์˜ ๋ฌธ์ž์—ด์ด ๋ชจ๋‘ ๋งค์นญ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, a์™€ b ์‚ฌ์ด์— 0๊ฐœ ์ด์ƒ์˜ ๋ฌธ์ž๊ฐ€ ๋“ค์–ด์žˆ๋Š” ๋ฌธ์ž์—ด์ด ๋งค์นญ์ด ๋ฉ๋‹ˆ๋‹ค.

 

์ด์™ธ ๊ธฐ๋ณธ ํŒจํ„ด

 ^  : ๋ฌธ์ž์—ด์˜ ์‹œ์ž‘

 $  : ๋ฌธ์ž์—ด์˜ ๋

[ ] : ๋Œ€๊ด„ํ˜ธ ๋‚ด์˜ ๋ฌธ์ž๋“ค ์ค‘ ํ•˜๋‚˜์˜ ๋ฌธ์ž์™€ ๋งค์นญ

[^ ] : ๋Œ€๊ด„ํ˜ธ ๋‚ด์˜ ๋ฌธ์ž๋“ค์„ ํฌํ•จํ•˜์ง€ ์•Š๋Š” ๋ฌธ์ž์™€ ๋งค์นญ

 

Expression Flags

g : global

i : case insensitive

m : multiline

s : single line

u : unicode

y : sticky

 

์ •๊ทœํ‘œํ˜„์‹ ํŒจํ„ด ์˜ˆ์ œ

์ •๊ทœํ‘œํ˜„์‹ ํŒจํ„ด์„ค๋ช…์ผ์น˜ ๋ฌธ์ž์—ด
^x- ์†Œ๋ฌธ์ž x๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฌธ์ž์—ด"xyz song"
a$
- ๋ฌธ์ž์—ด ๋์— ๊ณต๋ฐฑ์ด๋‚˜ ์ค„๋ฐ”๊ฟˆ ๋ฌธ์ž๊ฐ€ ์žˆ์„๊ฒฝ์šฐ ๋งค์นญ X
"blah bla"
a.c- ์†Œ๋ฌธ์ž a์™€ c ์‚ฌ์ด์— ํ•˜๋‚˜์˜ ๋ฌธ์ž๊ฐ€ ์žˆ๋Š” ๋ฌธ์ž์—ด
"Javascript is easy"
a+- ์†Œ๋ฌธ์ž a๊ฐ€ 1๋ฒˆ ์ด์ƒ ๋ฐ˜๋ณต๋จ

"I am a boy"
a*- ์†Œ๋ฌธ์ž a๊ฐ€ 0๋ฒˆ ์ด์ƒ ๋ฐ˜๋ณต๋จba* -> "b", "ba", "baa"
a?- ์†Œ๋ฌธ์ž a๊ฐ€ 1๋ฒˆ ์กด์žฌํ•˜๊ฑฐ๋‚˜ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์ผ€์ด์Šค 
a|b- ์†Œ๋ฌธ์ž a ๋˜๋Š” ์†Œ๋ฌธ์ž b 
(a)- ์†Œ๋ฌธ์ž a๋ฅผ ๊ทธ๋ฃนํ™” 
(a)(b)- ๊ทธ๋ฃน1์— ์†Œ๋ฌธ์ž a, ๊ทธ๋ฃน 2์— ์†Œ๋ฌธ์ž b ๋งค์นญ 
a{n}- ์†Œ๋ฌธ์ž a๊ฐ€ n๋ฒˆ ๋ฐ˜๋ณต๋˜๋Š” ๋ฌธ์ž์—ด 
a{min,}- ์†Œ๋ฌธ์ž a๊ฐ€ ์ตœ์†Œ min๋ฒˆ ๋ฐ˜๋ณต๋˜๋Š” ๋ฌธ์ž์—ด 
a{min,max}- ์†Œ๋ฌธ์ž a๊ฐ€ ์ตœ์†Œ min๋ฒˆ, ์ตœ๋Œ€ max๋ฒˆ ๋ฐ˜๋ณต๋˜๋Š” ๋ฌธ์ž์—ด 
[ab]- ์†Œ๋ฌธ์ž a ๋˜๋Š” b"I am a boy"
[^ab]- ์†Œ๋ฌธ์ž a์™€ b๋ฅผ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ๋ฌธ์ž"cab"
[a-z]- ์†Œ๋ฌธ์ž a๋ถ€ํ„ฐ z์‚ฌ์ด์˜ ๋ฌธ์ž์ค‘ ํ•˜๋‚˜ 
[^a-y]- ์†Œ๋ฌธ์ž a๋ถ€ํ„ฐ y๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๋ฌธ์ž"abcz"
\^ํŠน์ˆ˜๋ฌธ์ž ^๋ฅผ ํŒจํ„ด๋‚ด์— ํฌํ•จ์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉ 
\ddigit (์ˆซ์ž) 
\D์ˆซ์ž๊ฐ€ ์•„๋‹Œ ๋ฌธ์ž 
\s๊ณต๋ฐฑ๋ฌธ์ž 
\S๊ณต๋ฐฑ๋ฌธ์ž๊ฐ€ ์•„๋‹Œ ๋ฌธ์ž 
\ttab ๋ฌธ์ž 
\vvertical tab ๋ฌธ์ž 
\w์•ŒํŒŒ๋ฒณ, ์ˆซ์ž, _ ๋ฌธ์ž 
\W(์•ŒํŒŒ๋ฒณ, ์ˆซ์ž, _ ๋ฌธ์ž)๊ฐ€ ์•„๋‹Œ ๋ฌธ์ž 

 

 

์‹ค์ œ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ์˜จ๋ผ์ธ ์‚ฌ์ดํŠธ๋“ค์ด ์กด์žฌํ•˜๋Š”๋ฐ์š”, ์ €๋Š” ์•„๋ž˜ ์‚ฌ์ดํŠธ๋ฅผ ์• ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ๋ฌธ์ž์—ด๋„ ๋งˆ์Œ๋Œ€๋กœ ์ž…๋ ฅํ•ด๋ณผ ์ˆ˜ ์žˆ๊ณ  ํŒจํ„ด์„ ์ž…๋ ฅํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋งค์นญ๋˜๋Š” ๋ฌธ์ž๋“ค์„ ์ปฌ๋Ÿฌ๋งํ•ด์ค๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์ธ ํ…์ŠคํŠธ๊ฐ€ ์ž…๋ ฅ๋˜์–ด์žˆ์–ด์„œ ์›ํ•˜๋Š”๋Œ€๋กœ ํŒจํ„ด์„ ์ž…๋ ฅํ•ด๋ณด๊ณ  ๊ธฐ๋Œ€ํ•˜๋˜ ๋งค์นญ์ด ์ด๋ฃจ์–ด ์ง€๋Š”์ง€ ๋ฐ”๋กœ๋ฐ”๋กœ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค

https://regexr.com/

RegExr: Learn, Build, & Test RegEx

RegExr is an online tool to learn, build, & test Regular Expressions (RegEx / RegExp).

regexr.com

 

๋˜ํ•œ, ์ •๊ทœ์‹์ด ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”์ง€ ๋„์‹ํ™” ํ•ด์ฃผ๋Š” ์‚ฌ์ดํŠธ๋„ ์žˆ๋Š”๋ฐ์š”, ์—ฌ๊ธฐ๋„ ์ด์šฉํ•ด๋ณผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค.

์ž‘์„ฑํ•œ ์ •๊ทœ์‹์ด ์ •ํ™•ํžˆ ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”์ง€ ์‹ค์ œ ํŒจํ„ด ๋งค์นญ ํ…Œ์ŠคํŠธ ๋งŒ์œผ๋กœ๋Š” ์• ๋งคํ•  ๋•Œ ์ด์šฉํ•˜๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.

https://regexper.com/

 

Regexper

 

regexper.com

 

์ด์ƒ์œผ๋กœ ์ •๊ทœํ‘œํ˜„์‹์— ๋Œ€ํ•ด์„œ ๊ฐ„๋žตํžˆ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๐Ÿ’ป Programming

Eclipse์— lombok ์„ค์น˜ํ•˜๊ธฐ

How to install lombok plugin on Eclipse IDE

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์ผ€์ด์น˜์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์ดํด๋ฆฝ์Šค์— ๋กฌ๋ณต(lombok)์„ ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค๋“œ๋ฆฌ๋Ÿฌ ์™”์Šต๋‹ˆ๋‹ค.

lombok์€ ์ž๋ฐ”๊ฐœ๋ฐœ์ž๋“ค์˜ ๋ถˆํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ ์ƒ์„ฑ์„ ๋Œ€ํญ ์ค„์—ฌ์ฃผ๋Š” ๋งค์šฐ ์œ ์šฉํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

getter์™€ setter๋ฅผ ์ง€์ €๋ถ„ํ•˜๊ฒŒ ์ˆ˜์‹ญ ๊ฐœ ํ•„๋“œ๋ฅผ ์œ„ํ•ด์„œ ๋งŒ๋“ค์–ด์ค„ ํ•„์š”๊ฐ€ ์—†๊ฒŒ ํ•ด์ฃผ๊ธฐ๋„ ํ•˜๊ณ 

logger ์„ธํŒ…๋„ ์•Œ์•„์„œ ์ฒ™์ฒ™ ํ•ด์ฃผ๋Š” ์นœ์ ˆํ•œ ๋กฌ๋ณต์”จ์ฃ . ใ…Žใ…Ž

 

๊ทธ๋Ÿผ ์ดํด๋ฆฝ์Šค์—์„œ lombok์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋Š”์ง€ ํ•œ๋ฒˆ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

โš ๏ธNote: ์ดํด๋ฆฝ์Šค๋Š” ์ตœ์‹ ๋ฒ„์ „์ธ 2020-06 R ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…ํ•˜๋ฏ€๋กœ

๊ตฌ๋ฒ„์ „์˜ ์ดํด๋ฆฝ์Šค์—์„œ๋Š” ์•„๋ž˜ ์„ค๋ช…์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

  1. Download lombok
  2. ๋‹ค์šด๋กœ๋“œ๋ฐ›์€ lombok.jar ํŒŒ์ผ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. ์•„๋ž˜์ฒ˜๋Ÿผ ์ฐฝ์ด ๋œจ๋ฉด ์šฐ์ธก ํ•˜๋‹จ์˜ Install / Update ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.
  4. ์ดํด๋ฆฝ์Šค๋ฅผ ์žฌ๊ธฐ๋™ํ•ฉ๋‹ˆ๋‹ค.

์ดํด๋ฆฝ์Šค lombok ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜ ํ™”๋ฉด

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ ์™„๋ฃŒํ•˜์…จ์œผ๋ฉด ์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ดํด๋ฆฝ์Šค์—์„œ lombok ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์ด์ œ ์‹ค์ œ๋กœ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•˜์‹œ๋ ค๋ฉด dependency์— lombok์„ ์ถ”๊ฐ€ํ•œ ๋‹ค์Œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ’ฏ

 

์‹ค์ œ๋กœ lombok ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๋ณด๊ณ ์‹ถ์œผ์‹œ๋ฉด [Java] 30๋ถ„์™„์„ฑ ์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ ๋งŒ๋“ค๊ธฐ ๊ธ€์„ ์ฐธ๊ณ ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿผ ์˜ค๋Š˜๋„ ์ฆํ”„ํ•˜์„ธ์š”~

์•ˆ๋…•ํ•˜์„ธ์š”, ์ผ€์ด์น˜์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“œ๋Š” ์›น์•ฑ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉํ•  ๋„๊ตฌ๋Š” Eclipse 2020-06 R ์ด๊ณ ์š”, ์Šคํ”„๋ง๋ถ€ํŠธ์™€ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ, ๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™์€ mamp์™€ mybatis๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„  ๊ธฐ๋ณธ์ ์ธ ๋„๊ตฌ๋“ค๊ณผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค ๊ทธ๋ฆฌ๊ณ  ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์„ ์„ค์น˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœํ™˜๊ฒฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

  1. MacOS Catalina (10.15.6)
  2. Eclipse 2020-06 R (Download)
  3. Eclipse Spring Tool Suite 4 (์„ค์น˜ํ•˜๊ธฐ ๊ฐ€์ด๋“œ)
  4. MAMP (Download) -> community ๋ฒ„์ „ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์œผ์„ธ์š”, Window์‚ฌ์šฉ์ž์˜ ๊ฒฝ์šฐ WAMP๋ฅผ ์„ค์น˜ํ•˜์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  5. DBeaver (๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฌด๋ฃŒ ํˆด Download) -> community ๋ฒ„์ „ ๋‹ค์šด๋กœ๋“œ ๋ฐ›์œผ์„ธ์š”

 

์ž, ์œ„ ๋„๊ตฌ๋“ค์„ ๋ชจ๋‘ ์„ค์น˜์™„๋ฃŒํ–ˆ๋‹ค๋ฉด ์ด์ œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  ๊ฒฐ๊ณผ๋ฌผ์€ ์•„๋ž˜ ๋™์˜์ƒ์ฒ˜๋Ÿผ ๋‚˜์˜ฌ๊ฒ๋‹ˆ๋‹ค.

 

์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ์›น์•ฑ

์ž, ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ง„ํ–‰์€ ์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ํ•ฉ๋‹ˆ๋‹ค.

  1. ํ…Œ์ด๋ธ” ์„ค๊ณ„
  2. ๋ฐฑ์—”๋“œ ๊ตฌํ˜„
  3. ํ”„๋ก ํŠธ ๊ตฌํ˜„

 

ํ…Œ์ด๋ธ” ์„ค๊ณ„

์šฐ์„  ํ…Œ์ด๋ธ” ์„ค๊ณ„๋ถ€ํ„ฐ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. (MAMP์„ค์น˜ ๋ฐ ํ…Œ์ด๋ธ” ์†Œ์œ ์ž ๊ถŒํ•œ ๋“ฑ์˜ ์„ค์ •์€ ์—ฌ๊ธฐ์„œ ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

ํ…Œ์ด๋ธ”์€ contact ๋ผ๊ณ  ๋ช…๋ช…์ง€์–ด์ฃผ๊ณ  ์ปฌ๋Ÿผ์€ ์•„๋ž˜์ฒ˜๋Ÿผ ๋‘ ๊ฐœ๋งŒ ์ถ”๊ฐ€๋ฅผ ํ•ด์ค„ ๊ฒ๋‹ˆ๋‹ค.

CREATE TABLE `contact` (
  `name` varchar(100) NOT NULL,
  `phone` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

 

 

DBeaver์—์„œ ์กฐํšŒํ•œ contact ํ…Œ์ด๋ธ” ๋ช…์„ธ

์ •๋ง ๊ฐ„๋‹จํ•œ ์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ํ”„๋กœ๊ทธ๋žจ์ด๋ฏ€๋กœ ์ด๋ฆ„๊ณผ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด๋งŒ ๋‹ด์„ ์˜ˆ์ •์ด๊ณ  ๊ฐœ์ธ์ •๋ณด ์•”ํ˜ธํ™” ๊ฐ™์€๊ฑด ๋‹ค๋ฃจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ž…๋ ฅ๋ฐ›์€ ์ •๋ณด ๊ทธ๋Œ€๋กœ string์œผ๋กœ ์ €์žฅ์„ ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ…Œ์ด๋ธ” ์„ค๊ณ„๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ด์ œ ๋ฐฑ์—”๋“œ์—์„œ ์ฟผ๋ฆฌํ•ด์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„์„ ๋“ค์–ด๊ฐ€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ

์šฐ์„  ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ๊ฒ ์ฃ .

์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

Project Explorer > New > Project ์„ ํƒ

 

Wizards์—์„œ spring์œผ๋กœ ๊ฒ€์ƒ‰ํ•œ ๋’ค Spring Starter Prject ์„ ํƒ (์ด๊ฒŒ ์•ˆ๋‚˜์˜จ๋‹ค๋ฉด STS์„ค์น˜ํ•˜๊ธฐ๋ถ€ํ„ฐ ํ•˜๊ณ  ์˜ค์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.)

 

 

Name ํ•ญ๋ชฉ์€ ํ”„๋กœ์ ํŠธ๋ช…์„ ์ž…๋ ฅํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— contact-manager ๋ผ๊ณ  ๋„ฃ์–ด์ฃผ์‹œ๊ณ  Java Version์€ 8 ์ด์ƒ์œผ๋กœ ์•„๋ฌด๊ฑฐ๋‚˜ ์“ฐ์…”๋„ ๋ฌด๋ฐฉํ• ๊ฒ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ๋Š” Java 11 ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

Next๋ฅผ ๋ˆŒ๋Ÿฌ ๋‹ค์Œ์œผ๋กœ ๋„˜์–ด๊ฐ„ ๋’ค Available ๊ฒ€์ƒ‰์ฐฝ์—์„œ spring web, lombok, mybatis, mysql๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ์šฐ์ธก์˜ selected ํ•ญ๋ชฉ์— ์„ธ ๊ฐœ ํ•ญ๋ชฉ์ด ๋“ค์–ด๊ฐ€๋„๋ก ์ฒดํฌํ•˜๊ณ  Finish ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ์ด๋ฏธ ์‚ฌ์šฉํ•œ ์ ์ด ์žˆ์–ด์„œ Frequently Used์— ํ•ญ๋ชฉ์ด ๋‚˜ํƒ€๋‚˜์„œ ์ฒดํฌ๋งŒ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ ํ•˜์‹œ๋Š” ๋ถ„๋“ค์€ Available์—์„œ ๊ฒ€์ƒ‰ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์šฐ์ธก ํ•˜๋‹จ์— progress bar๊ฐ€ ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋˜๋Š” Progress View์—์„œ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์ฃ . Progress View๊ฐ€ ์•ˆ๋ณด์ธ๋‹ค๋ฉด ์ดํด๋ฆฝ์Šค ์ƒ๋‹จ ๋ฉ”๋‰ด์—์„œ Window > Show View > Other > Progress๋กœ ๊ฒ€์ƒ‰ํ•˜๋ฉด ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ง„ํ–‰์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉด Project Explorer์—์„œ ์•„๋ž˜์ฒ˜๋Ÿผ ํŒŒ์ผํŠธ๋ฆฌ๊ฐ€ ๋ณด์ผ๊ฒ๋‹ˆ๋‹ค.

pom.xml ํŒŒ์ผ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์ด ๋“ค์–ด์žˆ์ฃ .

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>contact-manager</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>contact-manager</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>11</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.3</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

 

 

์ด์ œ ์ž๋ฐ”๋กœ ์ฝ”๋”ฉํ•  ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  ์œ„์—์„œ ๋งŒ๋“  contact ํ…Œ์ด๋ธ”์˜ ๋‚ด์šฉ์„ ์กฐํšŒํ•ด์˜ค๋Š” API๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

com.example.demo ํŒจํ‚ค์ง€ ํ•˜์œ„์— domain ๋ผ๋Š” ์ด๋ฆ„์˜ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํŒจํ‚ค์ง€์— ContactInfo.java ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์„ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ContactInfo {
    private String name;
    private String phone;
}

 

ContactInfo ํด๋ž˜์Šค๋Š” contact ํ…Œ์ด๋ธ”๊ณผ ์—ฐ๋™ํ•  dto์ž…๋‹ˆ๋‹ค.

 

com.example.demo ํŒจํ‚ค์ง€ ํ•˜์œ„์— mapper ๋ผ๋Š” ์ด๋ฆ„์˜ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํŒจํ‚ค์ง€์— ContactInfoMapper.java ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค. ContactInfoMapper๋Š” ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ƒ์„ฑํ•ด์ฃผ๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

import com.example.demo.domain.ContactInfo;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface ContactInfoMapper {

    @Select("select * from contact")
    List<ContactInfo> selectAll();

    @Insert("insert into contact (name, phone) values (#{name}, #{phone})")
    int insert(ContactInfo contactInfo);

    @Delete("delete from contact where name = #{name}")
    int delete(String name);

    @Select("<script>" +
            "select * from contact " +
            "<where>" +
            "<if test=\"name != null and name.length > 0\">and name = #{name}</if>" +
            "<if test=\"phone != null and phone.length > 0\">and phone = #{phone}</if>" +
            "</where>" +
            "</script>")
    List<ContactInfo> selectBy(@Param("name") String name, @Param("phone") String phone);

    @Update("update contact " +
            "set phone = #{phone} " +
            "where name = #{name}")
    int update(String name, String phone);
}

 

์ด ContactInfoMapper ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์™€ ์—ฐ๋™์ด ๋˜์–ด ์ฟผ๋ฆฌ๋ฅผ database๋กœ ์ „๋‹ฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

 

com.example.demo ํŒจํ‚ค์ง€ ํ•˜์œ„์— service ๋ผ๋Š” ์ด๋ฆ„์˜ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํŒจํ‚ค์ง€์— ContactInfoService.java ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

์ด ํŒŒ์ผ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚ด์šฉ์„ ๋„ฃ์–ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.demo.domain.ContactInfo;
import com.example.demo.mapper.ContactInfoMapper;

@Service
public class ContactInfoService {

	@Autowired
	private ContactInfoMapper contactInfoMapper;

	public List<ContactInfo> getEveryContactInfo() {
		return contactInfoMapper.selectAll();
	}

	public int addContactInfo(ContactInfo contactInfo) {
		return contactInfoMapper.insert(contactInfo);
	}

	public int delContactInfo(String name) {
		return contactInfoMapper.delete(name);
	}

	public List<ContactInfo> getContactInfos(String name, String phone) {
		return contactInfoMapper.selectBy(name, phone);
	}

	public int updateContactInfo(String name, String phone) {
		return contactInfoMapper.update(name, phone);
	}
}

 

ContactInfoMapper์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์—ญํ• ๋งŒ ํ•˜๊ณ  ์žˆ์ง€๋งŒ ํ”„๋กœ์ ํŠธ๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด ๊ฐ์ข… ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋“ค์–ด๊ฐ€์•ผํ•  ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

์กฐํšŒํ•œ ๋’ค์— ์ •๋ ฌ์„ ํ•œ๋‹ค๋“ ์ง€, ํ•„ํ„ฐ๋ง์„ ํ•œ๋‹ค๋“ ์ง€ ํ•˜๋Š” ๋กœ์ง์€ ์ด ์„œ๋น„์Šค ํด๋ž˜์Šค์— ๋„ฃ์–ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ œ controller์ชฝ์—์„œ ์‚ฌ์šฉํ•  ์‘๋‹ต ๋„๋ฉ”์ธ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

com.example.demo.domain ํŒจํ‚ค์ง€์— Response.java ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@JsonInclude(Include.NON_NULL)
public class Response<T> {

    private int code;
    private String message;
    private T data;

    public Response(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public Response(int code, String message, T data) {
        this(code, message);
        this.data = data;
    }
}

 

๋งˆ์ง€๋ง‰์œผ๋กœ com.example.demo ํŒจํ‚ค์ง€ ํ•˜์œ„์— controller ๋ผ๋Š” ์ด๋ฆ„์˜ ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํŒจํ‚ค์ง€์— ContactInfoController.java ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์„œ ์•„๋ž˜ ๋‚ด์šฉ์„ ๋„ฃ์–ด์ฃผ์„ธ์š”.

import com.example.demo.domain.ContactInfo;
import com.example.demo.domain.Response;
import com.example.demo.service.ContactInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@RestController
@RequestMapping("/contact-info")
public class ContactInfoController {

	@Autowired
	private ContactInfoService contactInfoService;

	@GetMapping("/list") // --> localhost:8080/contact-info/list
	public List<ContactInfo> getAllContactInfo() {
		return contactInfoService.getEveryContactInfo();
	}

	@GetMapping("/get")
	public ResponseEntity<Response> getContactInfos(
			@RequestParam(required = false) String name,
			@RequestParam(required = false) String phone) {
		List<ContactInfo> result = contactInfoService.getContactInfos(name, phone);
		if (result.size() == 0) {
			return ResponseEntity.status(HttpStatus.OK).body(new Response(204, "๋ฐ์ดํ„ฐ ์—†์Œ"));
		}
		return ResponseEntity.ok(new Response(200, "์กฐํšŒ ์„ฑ๊ณต", result));
	}

	@PostMapping("/add")
	public ResponseEntity<Response> addNewContactInfo(@RequestBody ContactInfo contactInfo) {
		contactInfoService.addContactInfo(contactInfo);
		return ResponseEntity.ok(new Response(200, "๋“ฑ๋ก ์„ฑ๊ณต"));
	}

	@DeleteMapping("/del")
	public ResponseEntity<Response> delContactInfo(@RequestParam String name) {
		int result = contactInfoService.delContactInfo(name);
		if (result == 0) {
			return ResponseEntity.status(HttpStatus.OK).body(new Response(204, "๋ฐ์ดํ„ฐ ์—†์Œ"));
		}
		return ResponseEntity.ok(new Response(200, "์‚ญ์ œ ์„ฑ๊ณต"));
	}

	@PutMapping("/update")
	public ResponseEntity<Response> updateContactInfo(@RequestParam String name, @RequestParam String phone) {
		int result = contactInfoService.updateContactInfo(name, phone);
		if (result == 0) {
			return ResponseEntity.status(HttpStatus.OK).body(new Response(204, "๋ฐ์ดํ„ฐ ์—†์Œ"));
		}
		return ResponseEntity.ok(new Response(200, "์ˆ˜์ • ์„ฑ๊ณต"));
	}

	@ExceptionHandler
	public ResponseEntity<Response> contactInfoErrorHandler(Exception e) {

		log.error("error!!, {}", e.getClass().getName(), e);

		if (e instanceof DuplicateKeyException) {
			return ResponseEntity.status(HttpStatus.CONFLICT).body(new Response(409, "์ด๋ฏธ ์ค‘๋ณต๋œ ์ด๋ฆ„์ด ๋“ฑ๋ก๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค."));
		} else {
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new Response(500, "์„œ๋ฒ„์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์˜€์Šต๋‹ˆ๋‹ค."));
		}
	}
}

์ด ํด๋ž˜์Šค๊ฐ€ ํ”„๋ก ํŠธ์™€ ๋ฐฑ์—”๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ๋ถ€๋ถ„์œผ๋กœ API url์„ ์ •์˜ํ•˜๊ณ  ์–ด๋–ค ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์„ ์ „๋‹ฌ๋ฐ›์•„์•ผ ํ•˜๋Š”์ง€, ์‘๋‹ต์€ ์–ด๋–ป๊ฒŒ ์ฃผ๊ณ  ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋‚ด์šฉ์ด ๋‹ด๊ฒจ์žˆ์ฃ . 

 

์ด์ œ ๋ฐฑ์—”๋“œ ๊ตฌํ˜„์€ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์•„ ์ฐธ!! ํ•˜๋‚˜ ๋นผ๋จน์€๊ฒŒ ์žˆ๋„ค์š”. database ์ ‘์† ์ •๋ณด๋ฅผ ๋นผ๋จน์—ˆ์Šต๋‹ˆ๋‹ค. ์ž, src/main/resources ํ•˜์œ„์˜ application.properties ํŒŒ์ผ์„ ์—ด์–ด์„œ ์ง์ ‘ ์ƒ์„ฑํ•˜์…จ๋˜ database ์ ‘์† ์ •๋ณด๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋„ฃ์–ด์ฃผ์„ธ์š”.

spring.datasource.url=jdbc:mysql://localhost:8889/javastudy?useSSL=false&serverTimezone=UTC
spring.datasource.username=javastudy
spring.datasource.password=javastudy
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

์ ‘์† ํฌํŠธ(8889)์™€ database๋ช…(javastudy) ๊ทธ๋ฆฌ๊ณ  username, password ์ •๋ณด๋ฅผ ์ƒ์„ฑํ•˜์‹  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋งž๊ฒŒ ๋ณ€๊ฒฝํ•ด์ฃผ์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด Project Explorer์— ์•„๋ž˜์™€ ๊ฐ™์ด ํŒŒ์ผ๋“ค์ด ์กด์žฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด์ œ ContactManagerApplication์„ Sppring Boot App์œผ๋กœ ๊ธฐ๋™ํ•ด์„œ API๊ฐ€ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธ์„ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•ฑ ๊ธฐ๋™์— ์„ฑ๊ณตํ•˜๋ฉด Console View์—์„œ ์•„๋ž˜ ๋กœ๊ทธ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

INFO 69998 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
INFO 69998 --- [main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
INFO 69998 --- [main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.37]
INFO 69998 --- [main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
INFO 69998 --- [main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1185 ms
INFO 69998 --- [main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
INFO 69998 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
INFO 69998 --- [main] c.e.demo.ContactManagerApplication       : Started ContactManagerApplication in 2.457 seconds (JVM running for 3.521)

 

์ด์ œ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์„ ์—ด๊ณ  http://localhost:8080/contact-info/get ์„ ์ฃผ์†Œ์ฐฝ์— ์ž…๋ ฅํ•˜๊ณ  ํ˜ธ์ถœํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜์ฒ˜๋Ÿผ ์ถœ๋ ฅ์ด ๋˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ์ž˜ ๋™์ž‘ํ•œ ๊ฒ๋‹ˆ๋‹ค.

{"code":204,"message":"๋ฐ์ดํ„ฐ ์—†์Œ"}

 

์—ฌ๊ธฐ์„œ ํ˜น์‹œ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค๋ฉด ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€์„œ ๋‹ค์‹œ ์ˆœ์„œ๋Œ€๋กœ ๋”ฐ๋ผํ•ด๋ณด์„ธ์š”.

๊ทธ๋ž˜๋„ ์•ˆ๋˜์‹ ๋‹ค๋ฉด....๋Œ“๊ธ€๋กœ ์—๋Ÿฌ๋ฉ”์‹œ์ง€๋ฅผ ๋‚จ๊ฒจ์ฃผ์‹œ๋ฉด ํ•จ๊ป˜ ๊ณ ๋ฏผํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์ž, ์ด์ œ ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.

 

ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ

ํ”„๋ก ํŠธ ์˜์—ญ ๊ฐœ๋ฐœ์„ ์œ„ํ•ด์„œ pom.xml์— ๋‘ ๊ฐœ์˜ dependency๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>bootstrap</artifactId>
	<version>4.5.0</version>
</dependency>
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

thymeleaf์™€ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  controller ํŒจํ‚ค์ง€ ๋‚ด์— ViewController.java ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์งง์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ViewController {

    @GetMapping("/contact-info")
    public String contactInfo() {
        return "contact-info";	// contact-info.html์„ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ• 
    }

}

 

๊ทธ๋ฆฌ๊ณ  src/main/resources ํ•˜์œ„์˜ templates ๋””๋ ‰ํ† ๋ฆฌ์— contact-info.html ํŒŒ์ผ์„ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜ ๋‚ด์šฉ์„ ๋„ฃ์–ด์ฃผ์„ธ์š”.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">

    <!-- JS link -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="/webjars/bootstrap/4.5.0/js/bootstrap.min.js"></script>
    <script src="script/contact-info.js"></script>

    <!-- CSS link -->
    <link rel="stylesheet"
          href="/webjars/bootstrap/4.5.0/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="style/contact-info.css"/>

</head>
<body>

<div id="content">
    <h1>์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ</h1>
    <p>
        <label>์ด๋ฆ„:</label>
        <input id="name" type="text" placeholder="์ด๋ฆ„" pattern=""/>
        
        <label>์—ฐ๋ฝ์ฒ˜:</label>
        <input id="phone" type="text" placeholder="010-1234-5678"/>
        <button type="button" class="btn btn-primary btn-lg" onclick="addContact()">๋“ฑ๋ก</button>
        <button type="button" class="btn btn-danger btn-lg" onclick="delContact()">์‚ญ์ œ</button>
    </p>

    <div>
        <button type="button" class="btn btn-info btn-lg" onclick="getContacts()">์—ฐ๋ฝ์ฒ˜ ๋ชฉ๋ก ์กฐํšŒ</button>
        <table>
            <thead>
	            <tr>
	                <th class="name">Name</th>
	                <th class="phone">Phone</th>
	            </tr>
            </thead>
            <tbody id="contact-info-table"></tbody>
        </table>
    </div>
</div>


<!-- Update Modal -->
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-labelledby="updateModalLabel"
     aria-hidden="true">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="updateModalLabel">์—ฐ๋ฝ์ฒ˜ ์ˆ˜์ •</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">

            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary" onclick="updateContactInfo()">Save changes</button>
            </div>
        </div>
    </div>
</div>

</body>
</html>

 

๊ทธ๋ฆฌ๊ณ  src/main/resources ํ•˜์œ„์˜ static ๋””๋ ‰ํ† ๋ฆฌ ํ•˜์œ„์— style, script ๋‘ ๊ฐœ์˜ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

style ๋””๋ ‰ํ† ๋ฆฌ์—๋Š” contact-info.css ํŒŒ์ผ์„ ๋„ฃ์„๊ฑฐ๊ณ , script ๋””๋ ‰ํ† ๋ฆฌ์—๋Š” contact-info.js ํŒŒ์ผ์„ ๋„ฃ์„ ๊ฒ๋‹ˆ๋‹ค.

๊ฐ ํŒŒ์ผ์˜ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

src/main/resources/static/style/contact-info.css

body {background-color: beige;}
th {text-align:center}
.name {width:100px;}
.phone {width:200px;}
#content {margin:100px;}
#contact-info-table tr:hover {background-color: cornflowerblue;}

 

src/main/resources/static/script/contact-info.js

$( document ).ready(function() {
    getContacts();
});

function addContact() {
    let name = $('#name').val();
    if (!name) {
        alert('"name" is required!');
        return;
    }
    if (!validateName(name)) {
        alert('"name" is invalid! ํ•œ๊ธ€๋งŒ ์ž…๋ ฅ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.');
        return;
    }
    let phone = $('#phone').val();
    if (!validatePhone(phone)) {
        alert('"phone number" is invalid!\nvalid format: 000-0000-0000');
        return;
    }

    let contactInfo = new Object();
    contactInfo.name = name;
    contactInfo.phone = phone;

    $.ajax({
        url: 'contact-info/add',
        dataType: 'json',
        type: 'post',
        contentType: 'application/json',
        data: JSON.stringify(contactInfo)
    }).done(function(response) {
        alert(response.message);
        console.log(response);
        $('#name').val('');
        $('#phone').val('');
        getContacts();
    }).fail(function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.responseText);
        console.log(jqXHR.responseText);
    });
}

function validateName(name) {
    return /^[๊ฐ€-ํžฃ]+$/.test(name);
// /^[A-Za-z]+$/
}
function validatePhone(phone){
    return /^\d{2,3}-\d{3,4}-\d{4}$/.test(phone);
}

function delContact() {

    let name = $('#name').val();
    if (!name) {
        alert('"name" is required!');
        return;
    }
    $.ajax({
        url: 'contact-info/del?name=' + name,
        dataType: 'json',
        type: 'delete',
        contentType: 'application/json'
    }).done(function(response) {
        alert(response.message);
        console.log(response);
        $('#name').val('');
        $('#phone').val('');
        getContacts();
    }).fail(function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.responseText);
        console.log(jqXHR.responseText);
    });
}

function getContacts() {
    let name = $('#name').val();
    let phone = $('#phone').val();

    $.ajax({
        url: 'contact-info/get' + generateQueryParams(name,phone),
        dataType: 'json',
        type: 'get',
        contentType: 'application/json'
    }).done(function(response) {
        printContactInfos(response.data);
    }).fail(function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.responseText);
        console.log(jqXHR.responseText);
    });
}

function generateQueryParams(name, phone) {
    let params = '';
    if (name || phone) {
        params = '?';
        if (name) {
            params += 'name=' + name;
        }
        if (phone) {
           if (params.length > 1) { params += '&';}
            params += 'phone=' + phone;
        }
    }
    return params;
}

function printContactInfos(contactInfos) {
    let rows = '';
    if (contactInfos) {
        contactInfos.forEach(function (item, index) {
            rows += '<tr onclick="popsUpUpdateModal(this)" ><td class="name">' + item.name
            + '</td><td class="phone">' + item.phone + '</td></tr>';
        });
    } else {
        alert('์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.');
    }
    $('#contact-info-table').html(rows);
}
function popsUpUpdateModal(row) {
    let name = $(row).find('.name').text();
    let phone = $(row).find('.phone').text();
    let modalBody = '<input type="text" class="name" value="' + name + '" disabled>'
        + '<input type="text" class="phone" value="' + phone + '">';
    $('#updateModal .modal-body').html(modalBody);
    $('#updateModal').modal('show');
}
function updateContactInfo() {
    let name = $('#updateModal .modal-body .name').val();
    let phone = $('#updateModal .modal-body .phone').val();

    if (!validateName(name)) {
        alert('"name" is invalid! ํ•œ๊ธ€๋งŒ ์ž…๋ ฅ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.');
        return;
    }
    if (!validatePhone(phone)) {
        alert('"phone number" is invalid!\nvalid format: 000-0000-0000');
        return;
    }

    $.ajax({
        url: 'contact-info/update' + generateQueryParams(name,phone),
        dataType: 'json',
        type: 'put',
        contentType: 'application/json'
    }).done(function(response) {
        alert(response.message);
        console.log(response);
        getContacts();
        $('#updateModal').modal('hide');
    }).fail(function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.responseText);
        console.log(jqXHR.responseText);
    });
}

 

๊ฐ ํŒŒ์ผ๋“ค ๋‚ด์—์„œ ํ•˜๋Š” ์—ญํ• ์ด ๋ญ”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋‹ค๋Š” ๋ถ„๋“ค์€ ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ์•„๋Š” ํ•œ๋„ ๋‚ด์—์„œ ๋‹ต๋ณ€ ๋‹ฌ์•„๋“œ๋ฆด๊ฒŒ์š”. 

ํฌ์ŠคํŒ…์ด ๋„ˆ๋ฌด ๊ธธ์–ด์ ธ์„œ ์ผ์ผ์ด ์„ค๋ช…์„ ๋‹ค ์ถ”๊ฐ€ํ•  ์ˆ˜๊ฐ€ ์—†์Œ์„ ์–‘ํ•ด๋ฐ”๋ž๋‹ˆ๋‹ค.

 

์ž, ์ด๋ ‡๊ฒŒ ์ด 4 ๊ฐœ์˜ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๋‹ค์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์žฌ๊ธฐ๋™ํ•œ ๋’ค ํ™”๋ฉด์œผ๋กœ ์ ‘์†ํ•ด์„œ ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” localhost:8080/contact-info ์ฃผ์†Œ๋กœ ์ ‘์†์„ ํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์•ž์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ /get ์ฃผ์†Œ๋Š” API๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ˆ ๋นผ๊ณ  ์ ‘์†ํ•ด์ฃผ์‹œ๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ํ™”๋ฉด์ด ๋œฐ๊ฒ๋‹ˆ๋‹ค.

์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ์›น์•ฑ ์™„์„ฑ

์ด ์›น์•ฑ์—์„œ๋Š” ๋“ฑ๋ก์‹œ์— ์ด๋ฆ„์„ ์ •์ƒ์ ์ธ ํ•œ๊ธ€์„ ์ž…๋ ฅํ•ด์ค˜์•ผ ํ•˜๊ณ  ์—ฐ๋ฝ์ฒ˜์˜ ๊ฒฝ์šฐ -๋ฅผ ํฌํ•จํ•˜์—ฌ ์ž๋ฆฌ์ˆ˜๋ฅผ ๊ฒ€์ฆํ•˜๋„๋ก ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒ€์ฆ์€ contact-info.js์—์„œ validateName(), validatePhone() ํ•จ์ˆ˜์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์œผ๋‹ˆ ํ™•์ธํ•ด๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

์˜ค๋ฅ˜๋ฐœ์ƒ์‹œ์—๋Š” ํ™”๋ฉด์— ์˜ค๋ฅ˜๋ฐœ์ƒํ–ˆ๋‹ค๊ณ  ๊ฒฝ๊ณ ํŒ์—…์ฐฝ์ด ๋œจ๋„๋ก ๋˜์–ด์žˆ์œผ๋ฉฐ, ์„œ๋ฒ„๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์—ฐ๋ฝ์ฒ˜ ์ˆ˜์ •์€ ์ œ์ผ ์ฒ˜์Œ์— ๊ณต์œ ํ•ด๋“œ๋ฆฐ ๋™์˜์ƒ์„ ๋”ฐ๋ผํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์—ฌ๊ธฐ๊นŒ์ง€ 30๋ถ„๋งŒ์— ์—ฐ๋ฝ์ฒ˜ ๊ด€๋ฆฌ ์›น์•ฑ ๋งŒ๋“ค๊ธฐ ํฌ์ŠคํŒ…์„ ๋งˆ์น˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

๊ถ๊ธˆํ•˜์‹  ์‚ฌํ•ญ์ด๋‚˜ ์ž˜ ์•ˆ๋˜์‹œ๋Š” ๋ถ„๋“ค์€ ๋Œ“๊ธ€ ๋‹ฌ์•„์ฃผ์‹œ๋ฉด ํ™•์ธํ•ด์„œ ๋‹ต๋ณ€๋“œ๋ฆฌ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์˜ค๋Š˜๋„ ์ฆํ”„ํ•˜์„ธ์š”~ 

 

 

๐Ÿ’ป Programming

Eclipse Version M1 M2 M3 R RC SR Difference

์•ˆ๋…•ํ•˜์„ธ์š”, ์ผ€์ด์น˜์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์ดํด๋ฆฝ์Šค์˜ ๋ฒ„์ „์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๋“ค๊ณ ์™”์Šต๋‹ˆ๋‹ค.

์ดํด๋ฆฌ์Šค๋Š” ์ž๋ฐ” ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฌด๋ฃŒํˆด๋กœ ๊ฐ€์žฅ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํˆด์ธ๋ฐ์š”

์ง€์†์ ์ธ ์—…๋ฐ์ดํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉด์„œ

ํŒจํ‚ค์ง€ ๋ฒ„์ „๋„ ์—ฌ๋Ÿฌ๊ฐœ๋กœ ๊ตฌ๋ถ„์„ ํ•ด์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๋ฐ”๋€Œ์—ˆ์Šต๋‹ˆ๋‹ค.

 

์ €๋„ ๋„ˆ๋ฌด ์˜ค๋žœ๋งŒ์— ์ดํด๋ฆฝ์Šค๋ฅผ ์ตœ์‹ ๋ฒ„์ „์œผ๋กœ ์„ค์น˜ํ•˜๋ ค๊ณ  ๋‹ค์šด๋กœ๋“œํ•˜๋Ÿฌ ๋“ค์–ด๊ฐ”๋‹ค๊ฐ€

๋‹ค์–‘ํ•œ ๋ฒ„์ „๋“ค์„ ๋ณด๊ณ  ์ด๊ฒŒ ๋ญ์ง€?? ์ด๋žฌ๊ฑฐ๋“ ์š”.

๊ทธ๋ž˜์„œ ๊ฐ ํŒจํ‚ค์ง€ ๋ฒ„์ „์ด ์–ด๋–ค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๊ฑด์ง€ ํ™•์ธ์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  ์ดํด๋ฆฝ์Šค ๋‹ค์šด๋กœ๋“œ ์‚ฌ์ดํŠธ๋กœ ๊ฐ€๋ณด์‹œ๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ํŒจํ‚ค์ง€ ์ข…๋ฅ˜๊ฐ€ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Eclipse Release Versions for Packaging Project Releases

Eclipse์˜ ํŒจํ‚ค์ง• ํ”„๋กœ์ ํŠธ ๋ฐฐํฌ๋ฒ„์ „์˜ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฑด๋ฐ์š”

๋ชฉ๋ก์˜ ์•„๋ž˜์ชฝ์„ ๋ณด์‹œ๋ฉด ์•„์‹œ๊ฒ ์ง€๋งŒ ์˜ˆ์ „์—๋Š” ์ดํด๋ฆฝ์Šค์˜ ๋ฒ„์ „์„ ์ด๋ฆ„์œผ๋กœ ๊ตฌ๋ถ„์„ ํ•ด์„œ ์‚ฌ์šฉํ•ด์™”์—ˆ์Šต๋‹ˆ๋‹ค. 

๊ทธ๋Ÿฌ๋‹ค๊ฐ€ ๋…„๋„์™€ ์›”์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๋ฒ„์ „์˜ ํŒจํ‚ค์ง€๋ฅผ ๋‹ค์šด๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ œ๊ณต์„ ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋…„๋„์™€ ์›”๋กœ ๋˜์–ด์žˆ๋Š” ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋˜ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฒ„์ „์ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Eclipse 2020-06 package versions

2020-06 ๋งํฌ๋ฅผ ๋”ฐ๋ผ ๋“ค์–ด๊ฐ€๋ณด๋ฉด ํŒจํ‚ค์ง€ ์ข…๋ฅ˜๊ฐ€ ๋‹ค์„ฏ ๊ฐ€์ง€๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ์š”

๊ฐ๊ฐ ์ด ํŒจํ‚ค์ง€๋“ค์ด ์–ด๋–ค ํŒจํ‚ค์ง€์ธ์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์ด๋‹ˆ์…œ์ด ๋ถ™์–ด์žˆ์Šต๋‹ˆ๋‹ค.

R, RC1, M3, M2, M1 ์ด๋ผ๋Š” ์ด๋‹ˆ์…œ์€ ๊ฐ๊ฐ ๋‹ค์Œ์˜ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

R : release ๋ฒ„์ „ (์•ˆ์ •ํ™” ๋ฒ„์ „)

RC1 : release candidate 1 (์•ˆ์ •ํ™” ๋ฒ„์ „ ํ›„๋ณด 1) -> ๊ณต์‹์ ์ธ ์•ˆ์ •ํ™”๊ฐ€ ๋˜๊ธฐ ์ „ ๋ฒ„์ „

M1, M2, M3 : milestone 1, 2, 3 -> ๊ฐœ๋ฐœ์ด ์ง„ํ–‰์ค‘์ธ ๋งˆ์ผ์Šคํ†ค ๋ฒ„์ „์œผ๋กœ ์•„์ง ํ…Œ์ŠคํŠธ ์ค‘์ธ ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

 

์ด์™ธ์—๋„ ์˜ค๋ž˜๋œ ์ดํด๋ฆฝ์Šค ๋ฒ„์ „์˜ ๊ฒฝ์šฐ SR ๋ฒ„์ „๋„ ์กด์žฌํ•˜๋Š”๋ฐ์š”

์ด๊ฑด service release ๋ฒ„์ „์ด๋ผ๊ณ  ํ•ด์„œ ์ผ์ข…์˜ ์„œ๋น„์ŠคํŒฉ๊ฐ™์€ ๊ฐœ๋…์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

 

Eclipse + SpringBoot + JSP ๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ 2ํƒ„์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ backend ๋ณด๋‹ค๋Š” frontend ์ž‘์—…์„ ์œ„ํ•œ Bootstrap ์ถ”๊ฐ€๋ฅผ webjar๋ฅผ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด๋ณด๋„๋ก ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

์ €๋Š” backend ๊ฐœ๋ฐœ์ž๋‹ค๋ณด๋‹ˆ front์ชฝ์€ ์ž์„ธํžˆ ์•Œ๋ ค๋“œ๋ฆฌ๊ธฐ๋Š” ํž˜๋“ค์ง€๋งŒ ๋น ๋ฅด๊ฒŒ ์„œ์น˜ํ•ด์„œ ์‚ฌ์šฉํ•ด๋ณธ ๊ฒฝํ—˜์ƒ webjar๋Š” maven ์˜์กด์„ฑ ๊ด€๋ฆฌ๋ฅผ ํ†ตํ•ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋‹ค์šด๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋งค์šฐ ์‰ฝ๊ฒŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. org.webjars์—๋Š” bootstrap, jquery, font-awesome, swagger-ui ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ angularJS, momentJS, d3js ๋“ฑ ๋งค์šฐ ๋งŽ์€ ํ”„๋ก ํŠธ ๊ฐœ๋ฐœ์„ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋งค๋ฒˆ ๋‹ค์šด๋กœ๋“œ๋ฐ›์•„์„œ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•  ํ•„์š” ์—†์ด ๋ฐฑ์—”๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ๊ด€๋ฆฌํ•˜๋“ฏ์ด ๋ฉ”์ด๋ธ ์˜์กด์„ฑ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์šฐ์„  ์ง€๋‚œ์‹œ๊ฐ„์— ํ–ˆ๋˜ Eclipse + SpringBoot + JSP ๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ 1ํƒ„ ์„ ์™„์„ฑํ•˜์…จ๋˜ ๋ถ„๋“ค์„ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…์„ ํ•  ์˜ˆ์ •์ด๋‹ˆ ํ•ด๋‹น ํฌ์ŠคํŒ…์„ ์•ˆ๋ณด์‹  ๋ถ„๋“ค์€ ํ•œ๋ฒˆ ์ญˆ์šฑ~ ํ›‘์–ด๋ณด์‹œ๊ณ  ๋‹ค์‹œ ์˜ค์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

webjar ์„ค์ •์„ ์œ„ํ•ด์„œ ์ถ”๊ฐ€ํ•  ํŒŒ์ผ์€ ๋”ฑ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. org.springframework.web.servlet.config.annotation.WebMvcConfigurer๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” WebMVCConfig ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด addResourceHandlers ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์—ฌ ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
	    if (!registry.hasMappingForPattern("/webjars/**")) {
	        registry.addResourceHandler("/webjars/**").addResourceLocations(
	                "classpath:/META-INF/resources/webjars/");
	    }
	    if (!registry.hasMappingForPattern("/**")) {
	        registry.addResourceHandler("/**").addResourceLocations(
	        		new String[] {"classpath:/static/script", "classpath:/static/style"});
	    }
    }

 

์šฐ์„  webjars ๊ฒฝ๋กœ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๊ฒƒ ๋•Œ๋ฌธ์— ์ด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•˜๋Š”๋ฐ ์ด๋•Œ @EnableWebMvc ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์ด ์ด ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๊ฒŒ๋˜๋ฉด WebMvcAutoConfiguration ์ด disable๋˜๋ฉด์„œ ๊ธฐ์กด ์„ค์ •๋“ค์ด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ธฐ์กด์— ์ž˜ ์ฝ์–ด์˜ค๋˜ staticํ•˜์œ„์˜ javascriptํŒŒ์ผ๋“ค๊ณผ cssํŒŒ์ผ๋“ค์„ ๋ชป์ฐพ์•„ 404 ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜์ฃ . ๊ทธ๋ž˜์„œ addResourceHandlers์— ์ด ๋‘ ํŒŒ์ผ๋“ค์ด ์กด์žฌํ•˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ classpath๊ฒฝ๋กœ๋กœ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ, application.properties ํŒŒ์ผ์— ์ž‘์„ฑํ•˜์˜€๋˜ ์•„๋ž˜ ๋‘ ๋ผ์ธ์€ ๋”์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋ฐฉ๊ธˆ ์ถ”๊ฐ€ํ•œ WebMVCConfig ํด๋ž˜์Šค์— ๋ณ„๋„๋กœ ViewResolver๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

	@Bean
	public ViewResolver getViewResolver(){
	    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
	    resolver.setPrefix("/WEB-INF/views/");
	    resolver.setSuffix(".jsp");
	    resolver.setViewClass(JstlView.class);
	    return resolver;
	}

 

์•„๋ž˜๋Š” ์™„์„ฑ๋œ WebMVCConfig ํด๋ž˜์Šค์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

@Configuration
@EnableWebMvc
public class WebMVCConfig implements WebMvcConfigurer {

	@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
		if (!registry.hasMappingForPattern("/webjars/**")) {
	        registry.addResourceHandler("/webjars/**").addResourceLocations(
	                "classpath:/META-INF/resources/webjars/");
	    }
	    if (!registry.hasMappingForPattern("/**")) {
	        registry.addResourceHandler("/**").addResourceLocations(
	        		new String[] {"classpath:/static/script", "classpath:/static/style"});
	    }
    }
	
	@Bean
	public ViewResolver getViewResolver(){
	    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
	    resolver.setPrefix("/WEB-INF/views/");
	    resolver.setSuffix(".jsp");
	    resolver.setViewClass(JstlView.class);
	    return resolver;
	}
}

 

์ž, ๋ชจ๋“  ์ค€๋น„๋Š” ์™„๋ฃŒ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ pom.xml์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

		<!-- Bootstrap CSS -->
		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>bootstrap</artifactId>
			<version>4.5.0</version>
		</dependency>

 

๊ทธ๋ฆฌ๊ณ  test.jsp ํŒŒ์ผ์„ ์—ด์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์„ ๋งํฌ๊ฑธ์–ด์ค๋‹ˆ๋‹ค.

<link rel="stylesheet" href="/webjars/bootstrap/4.5.0/css/bootstrap.min.css" />

 

๋งŒ์•ฝ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์ด ์•„๋‹Œ jQuery์™€ ๊ฐ™์€ javascript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•  ๊ฒฝ์šฐ ์˜์กด์„ฑ ์ถ”๊ฐ€๋Š” ๋™์ผํ•˜๊ฒŒ, jspํŒŒ์ผ์— ๋งํฌ๋ฅผ ๊ฑธ์–ด์ค„ ๋•Œ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

<script src="/webjars/jqeury/3.5.1/js/jqeury.min.js"></script>

 

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ ์™„๋ฃŒ๋˜๋ฉด ๋ชจ๋“  ์ค€๋น„๋Š” ๋๋‚œ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋งˆ์Œ๊ป ์‚ฌ์šฉํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ €๋Š” ์ง€๋‚œ ์‹œ๊ฐ„์— ์ตœ์ข…๊ฒฐ๊ณผ๋ฌผ์—์„œ ๋ฒ„ํŠผ์„ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•ด๋ณด๋Š” ์ •๋„๋กœ ์ด๋ฒˆ ํฌ์ŠคํŒ…์„ ๋งˆ์น˜๊ฒ ์Šต๋‹ˆ๋‹ค.

test.jsp์˜ body์— ๋‹ค์Œ ํ•œ ์ค„์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

<button type="button" class="btn btn-danger btn-lg">๋ฒ„ํŠผ</button>

 

๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋นจ๊ฐ„์ƒ‰ ๋ฒ„ํŠผ์ด ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด์ƒ์œผ๋กœ Eclipse + SpringBoot + JSP ๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ธํŒ…ํ•˜๊ธฐ 2ํƒ„ ํฌ์ŠคํŒ…์„ ๋งˆ์นฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜๋„ ์ฆ๊ฒ๊ณ  ํ–‰๋ณตํ•œ ์ฝ”๋”ฉ์„ ํ•˜๋Š” ์ผ€์ด์น˜์˜€์Šต๋‹ˆ๋‹ค~

MacOS Catalina ์—…๋ฐ์ดํŠธ ํ›„ ๋ฐœ์ƒํ•œ Invalid active developer path ์˜ค๋ฅ˜ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

 

MacOS๋ฅผ Catalina๋กœ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ ๋‚˜๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

 

xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), 
missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

 

๊ทธ๋ฆฌ๊ณ  IntelliJ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฒฝ๊ณ ํŒ์—…์„ ๋„์›Œ์ฃผ์—ˆ๋‹ค.

 

 

๋ญ์ง€? ์ด๋Ÿฐ ์˜ค๋ฅ˜๋Š” ์ฒจ์ธ๋ฐ?? ์ผ๋‹จ ๊ธฐ์กด์— ์ž˜ ๋˜๋˜๊ฒƒ์ด๋ผ ์„ค์ •๋งŒ ๋ฐ”๊พธ๋ฉด ๋˜๊ฒ ์ง€ ํ•˜๊ณ  Configure์— ๋“ค์–ด๊ฐ€๋ณด๋‹ˆ 

 

 

path ๊ด€๋ จํ•ด์„œ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ์ œ์ผ ์ƒ๋‹จ์— ์žˆ๋Š” Git ์‹คํ–‰ํŒŒ์ผ ์œ„์น˜๋ฅผ ์„ ํƒํ•ด์ฃผ๋Š” ๊ณณ์ธ๋ฐ..์ด๋ฏธ ์ž๋™์œผ๋กœ ์ฐพ์•„์„œ ์„ค์ •์ด ๋˜์–ด์žˆ๋‹ค. ํ•˜์ง€๋งŒ Test๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋Š” ์ˆœ๊ฐ„ 

 

์ด๋ ‡๊ฒŒ ๋˜‘๊ฐ™์€ ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•ด์ค€๋‹ค.

์ฝ˜์†”์ฐฝ์—์„œ ์ง์ ‘ git ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด๋ณด๋‹ˆ ๋™์ผํ•œ ์˜ค๋ฅ˜๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.

์ด๋Ÿด๋• ๊ตฌ๊ธ€์‹ ์—๊ฒŒ ๋ฌผ์–ด๋ณด๋ฉด ๋ชจ๋“  ํ•ด๊ฒฐ์ฑ…์ด ๋‹ค ์žˆ๋‹ค.

๊ฒ€์ƒ‰ํ•ด๋ณธ ๊ฒฐ๊ณผ xcode-select --install ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด cli ํˆด์„ ์„ค์น˜ํ•ด์ฃผ๋‹ˆ ๋”์ด์ƒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜๋‹ค.

 

์ดํด๋ฆฝ์Šค ์Šคํ”„๋งํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•

์ด๋ฒˆ์—๋Š” ์ดํด๋ฆฝ์Šค์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์œ„ํ•œ ์Šคํ”„๋งํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณผ๊ฒŒ์š”.

์ดํด๋ฆฝ์Šค๊ฐ€ ์„ค์น˜์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ์•„๋ž˜ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰ํ•˜์‹œ๋ฉด๋ฉ๋‹ˆ๋‹ค.

 

1. ์ดํด๋ฆฝ์Šค ์ƒ๋‹จ ๋ฉ”๋‰ด์—์„œ Help > Eclipse Marketplace... ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

 

 

2. ๊ฒ€์ƒ‰์ฐฝ์— spring ์œผ๋กœ ๊ฒ€์ƒ‰ํ•œ ๋’ค ์ œ์ผ ์ƒ๋‹จ์— Spring Tools (aka Spring Tools Suite) ๊ฐ€ ๋ณด์ด๋ฉด install ๋ฒ„ํŠผ ํด๋ฆญ (2020๋…„ 7์›” ํ˜„์žฌ ์ตœ์‹  ๋ฒ„์ „์€ 4.7.0.RELEASE)

๋งŒ์•ฝ 4.7.0 ๋ฒ„์ „์ด ๋ณด์ด์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ดํด๋ฆฝ์Šค ๋ฒ„์ „์ด ์˜ค๋ž˜๋œ ๊ฑด ์•„๋‹Œ์ง€ ํ™•์ธํ•ด๋ณด์‹œ๊ณ  ์ตœ์‹  ๋ฒ„์ „์œผ๋กœ ์ดํด๋ฆฝ์Šค๋ฅผ ๋‹ค์‹œ ๋‹ค์šด๋ฐ›์•„ ์„ค์น˜ํ•˜์‹  ๋’ค ์ง„ํ–‰ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

 

3. required ํ•ญ๋ชฉ๋งŒ ๋‚จ๊ธฐ๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ฒดํฌ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.

 

4. ๋ผ์ด์„ผ์Šค ๋™์˜๋ฅผ ์„ ํƒํ•˜๊ณ  Finish ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

์ด์ƒ์œผ๋กœ ์ดํด๋ฆฝ์Šค์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์œ ์šฉํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šคํ”„๋ง ํˆด์ฆˆ ์„ค์น˜๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์„ ๋งˆ์นฉ๋‹ˆ๋‹ค.

์ดํด๋ฆฝ์Šค์—์„œ ์Šคํ”„๋ง๋ถ€ํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ JSP๊ฐœ๋ฐœํ•˜๊ธฐ

์•ˆ๋…•ํ•˜์„ธ์š”, ์˜ค๋Š˜์€ ์Šคํ”„๋ง๋ถ€ํŠธ ๊ธฐ๋ฐ˜์œผ๋กœ JSP๊ฐœ๋ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ์„ธํŒ…ํ•˜๋Š” ๊ณผ์ •์„ ์•Œ๋ ค๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ์— ๋Œ€๊ทœ๋ชจ์˜ ์›น ๊ฐœ๋ฐœ์€ ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋กœ ๊ตฌ์„ฑํ•˜๊ฑฐ๋‚˜ ๋ชจ๋“ˆ๋กœ ๋‚˜๋ˆ„์–ด ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๊ฐœ๋ฐœ์„ ํ•˜๋˜์ง€ ๊ฒฐ๊ตญ ๋ฐฑ์—”๋“œ์™€ ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์™„์ „ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐœ๋ฐœํ•˜๊ฒŒ๋˜์ฃ . ํ•˜์ง€๋งŒ ๊ทธ๋ ‡๊ฒŒ๊นŒ์ง€ ํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ์ž‘์€ ํ”„๋กœ์ ํŠธ๋“ค์€ ๊ตณ์ด ๊ทธ๋ ‡๊ฒŒ ๋‚˜๋ˆ„์–ด ๊ฐœ๋ฐœ์„ ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ๊ตฌ๋ถ„์„ ํ•˜๋Š” ๊ฒƒ์ด ์˜คํžˆ๋ ค ์œ ์ง€๋ณด์ˆ˜๋ฅผ ํž˜๋“ค๊ฒŒ ํ•˜๋Š” ์›์ธ์ด ๋˜๊ธฐ๋„ ํ•˜์ฃ .

์˜ค๋Š˜์€ ํ•˜๋‚˜์˜ ์Šคํ”„๋ง๋ถ€ํŠธ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  JSP๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ธํŒ…ํ•˜๋Š” ๋ถ€๋ถ„๊นŒ์ง€ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ์ค€๋น„๋ฌผ์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

1. Eclipse (2020๋…„ 7์›” ๊ธฐ์ค€ ์ตœ์‹ ๋ฒ„์ „ ๋‹ค์šด๋กœ๋“œ)

Version: 2020-09 M1 (4.17.0 M1)

 

2. Spring Tools plugin (์„ค์น˜๋ฐฉ๋ฒ•)

 

์ด๋ ‡๊ฒŒ๋งŒ ์žˆ์œผ๋ฉด ์ผ๋‹จ ์ค€๋น„๋Š” ์™„๋ฃŒ์ž…๋‹ˆ๋‹ค.

 

์ด์ œ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์ดํด๋ฆฝ์Šค๋ฅผ ์ฒ˜์Œ ์„ค์น˜ํ•˜์‹  ๋ถ„์ด๋ผ๋ฉด ํŒจํ‚ค์ง€ ํƒ์ƒ‰๊ธฐ(Project Explorer)์— ์•„๋ž˜์™€ ๊ฐ™์ด ๋‚˜์˜ค๋Š”๋ฐ ์—ฌ๊ธฐ์„œ ๋ฐ‘์—์„œ ๋‘ ๋ฒˆ์งธ์— ์žˆ๋Š” Create a project...๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ด๋ฏธ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด ๋†“์€๊ฒŒ ์žˆ๋Š” ๋ถ„๋“ค์ด๋ผ๋ฉด ๊ทธ๋ƒฅ ํƒ์ƒ‰๊ธฐ ์ฐฝ์—์„œ ์šฐํด๋ฆญํ•ด์„œ New > Project ๋ฅผ ์„ ํƒํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์ด ์ƒˆ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋งˆ๋ฒ•์‚ฌ๊ฐ€ ๋œจ๋ฉด spring ์œผ๋กœ ๊ฒ€์ƒ‰์„ ํ•ด์„œ Spring Starter Project๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ๋งŒ๋“ค ํ”„๋กœ์ ํŠธ์˜ ์ด๋ฆ„์„ Name ํ•ญ๋ชฉ์— ์ ์–ด์ค๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Java Version ์€ 11๋กœ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค. (8๋กœ ํ•ด๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค)

 

Spring Boot์˜ ๋ฒ„์ „์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด ๋ถ€๋ถ„์€ ๊ทธ๋Œ€๋กœ ๋†”๋‘๊ณ  Available ๊ฒ€์ƒ‰์ฐฝ์—์„œ web์ด๋ผ๊ณ  ๊ฒ€์ƒ‰ํ•˜์—ฌ Spring Web์„ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค. (์ด์™ธ์—๋„ lombok์ด๋‚˜ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ๋“œ๋ผ์ด๋ฒ„, MyBatis ๋“ฑ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์„ ํƒํ•˜์—ฌ ์‚ฌ์ „์„ค์น˜๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค๋งŒ ์—ฌ๊ธฐ์„œ๋Š” ์„ ํƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

 

Finish ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์ค๋‹ˆ๋‹ค.

์ด์ œ MyDemoApplication.java ํŒŒ์ผ์„ ์—ด์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค๋‹ˆ๋‹ค.

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class MyDemoApplication extends SpringBootServletInitializer {

	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(MyDemoApplication.class);
	}

	public static void main(String[] args) {
		SpringApplication.run(MyDemoApplication.class, args);
	}

}

SpringBootServletInitializer๋ฅผ ์ƒ์†ํ•˜๊ณ  configure ๋ฉ”์„œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  pom.xml ํŒŒ์ผ์— ์•„๋ž˜ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค. jasper๋Š” JSP ํŒŒ์ผ์„ ์ปดํŒŒ์ผ ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํ•ฉ๋‹ˆ๋‹ค.

<!-- Need this to compile JSP -->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

 

์ด์ œ ํ”„๋กœ์ ํŠธ๋ช…์—์„œ ์šฐํด๋ฆญํ•˜๊ณ  "src/main/webapp" ์ƒˆ ํด๋”๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํด๋”๋ฅผ ๋งŒ๋“ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ œ ๋‹ค์‹œ ์šฐํด๋ฆญํ•˜์—ฌ build path ์„ค์ •(Configure Buildpath...)ํ™”๋ฉด์œผ๋กœ ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.

 

Add Folder... ๋ฅผ ํด๋ฆญํ•˜๊ณ  webapp ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐพ์•„ ์ฒดํฌํ•ด์ค๋‹ˆ๋‹ค.

OK ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  Applyํ•˜๋ฉด ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ฐ”๋€๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ webapp ์•„๋ž˜์— WEB-INF๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•˜์œ„์— ๋˜ views ๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  test.jsp ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ด์ค๋‹ˆ๋‹ค.

<%@ page import="java.util.*" %>

<!DOCTYPE html>
<html>
<body>
	<h1>Test Page</h1>
	Today's date: <%= new Date() %>
</body>
</html>

 

application.properties ํŒŒ์ผ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‘ ๋ผ์ธ์„ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

spring.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp

 

์ž, ์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด๋‹น ํŽ˜์ด์ง€์™€ ์—ฐ๊ฒฐํ•  API๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. root package์—์„œ controller ๋ผ๋Š” ํŒจํ‚ค์ง€๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  ๊ทธ ์•„๋ž˜์— DemoController.java๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

package com.example.demo.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;


@Controller
public class DemoController {
	
	@GetMapping("/test")
	public String login() {
		return "/test";
	}
}

 

์—ฌ๊ธฐ๊นŒ์ง€ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉด ์ด์ œ Run As > Java Application ๋˜๋Š” Run As > Spring Boot App ์œผ๋กœ ๊ธฐ๋™์‹œ์ผœ์ค๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  localhost:8080/test ์— ์ ‘์†ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด jsp ํŽ˜์ด์ง€๊ฐ€ ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

JSP ํŽ˜์ด์ง€์— javascript ๋ฐ css ํŒŒ์ผ ์—ฐ๋™

์ด์ œ JSP ํŽ˜์ด์ง€์— javascript ํŒŒ์ผ ๋ฐ css ํŒŒ์ผ์„ ์—ฐ๊ฒฐ์‹œ์ผœ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

javascript์™€ css ํŒŒ์ผ์€ src/main/resources ํ•˜์œ„์˜ static ํด๋” ์•ˆ์ชฝ์— ๋ชฐ์•„๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์šฐ์„  static ํด๋” ํ•˜์œ„์— script ํด๋”๋ฅผ ๋งŒ๋“ค์–ด test.jsํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

$(document).ready(function() { printCurrentDatetime(); });

function printCurrentDatetime() {
	let date = new Date();
	$('#currentTime').html(date);
	setTimeout(printCurrentDatetime, 1000);
}

 

๊ทธ๋ฆฌ๊ณ  static ํด๋” ํ•˜์œ„์— style ํด๋”๋ฅผ ๋งŒ๋“ค์–ด test.css ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

@charset "UTF-8";

body {background-color:cornflowerblue;}

 

์ž, ๋”์ด์ƒ ํŒŒ์ผ์„ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ JSP ํŒŒ์ผ์— ์œ„์—์„œ ์ž‘์„ฑํ•œ ๋‘ ํŒŒ์ผ์„ ์—ฐ๊ฒฐ์‹œ์ผœ์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

test.jsp ํŒŒ์ผ์„ ์—ด์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด์ค๋‹ˆ๋‹ค.

<%@ page import="java.util.*"%>

<!DOCTYPE html>
<html>
<head>

<!-- JS link -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="script/test.js"></script>

<!-- CSS link -->
<link href="style/test.css" rel="stylesheet">

</head>
<body>
	<h1>Test Page</h1>
	Today's date: <span id='currentTime'></span>
</body>
</html>

 

๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

1. html์˜ body ์•ˆ์— ์žˆ๋˜ ์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๋ฅผ test.js๋กœ ์˜ฎ๊ธฐ๋ฉด์„œ refresh ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€

2. test.jsํŒŒ์ผ์—์„œ jquery๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— htmlํŽ˜์ด์ง€(jspํŒŒ์ผ)์— jQuery ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋งํฌ ์ถ”๊ฐ€

3. css ๋งํฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  body์˜ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒ‰์ƒ์„ cornflowerblue ๋กœ ์„ค์ •

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ตœ์ข…์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ํŒจํ‚ค์ง€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ๋ฉ๋‹ˆ๋‹ค.

SpringBoot + JSP ์—ฐ๋™ ์ตœ์ข… ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

 

์—ฌ๊ธฐ๊นŒ์ง€ ์ž˜ ๋”ฐ๋ผ์˜ค์…จ๋‹ค๋ฉด ์‹คํ–‰์‹œ์ผฐ์„ ๋•Œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ˜„์žฌ์‹œ๊ฐ„์ด ๊ณ„์† ์—…๋ฐ์ดํŠธ๋˜๋Š” ํŒŒ๋ž€ ํ™”๋ฉด์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ˜Š

 

์ตœ์ข… ์™„๋ฃŒ ํ™”๋ฉด

 

์ด์ƒ์œผ๋กœ Eclipse์—์„œ SpringBoot์™€ JSP๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ์›นํ”„๋กœ์ ํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

์ž๋™์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” mysql ๋ฐ๋ชฌํ”„๋กœ์„ธ์Šค ๊ฐ•์ œ์ข…๋ฃŒ

MySQL 8 ๋ฒ„์ „(mysql-8.0.20-macos10.15)์„ MacOS 10.14 (Mojave) ์— ์„ค์น˜ํ–ˆ๋‹ค. ์„ค์น˜๋Š” CE๋ฒ„์ „ dmg ํŒŒ์ผ์„ ๋‹ค์šด๋ฐ›์•„์„œ ํ–ˆ๋Š”๋ฐ, ์„ค์น˜ํ•  ๋•Œ ๋งˆ์ง€๋ง‰์— ์ธ์Šคํ†จ ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ํ›„ ์ž๋™์œผ๋กœ MySQL์„ ์‹œ์ž‘ํ• ๊ฑด์ง€์— ๋Œ€ํ•œ ์ฒดํฌ๋ฅผ ํ•ด์ œํ•˜์ง€ ์•Š๊ณ  finishํ–ˆ๊ณ , MAMP๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๊ธธ๋ž˜(ํŒ์—…์ฐฝ์ด ๋œจ์ง€ ์•Š๊ธธ๋ž˜) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰์„ ์‹œ์ผฐ๋Š”๋ฐ nginx ์„œ๋ฒ„๋งŒ ๋œจ๊ณ  mysql ์„œ๋ฒ„๊ฐ€ ๋œจ์ง€ ์•Š์•˜๋‹ค.

์˜ค๋žœ๋งŒ์— MAMP๋ฅผ ์“ฐ๋ ค๋‹ค๋ณด๋‹ˆ ์™œ ์•ˆ๋œจ๋Š”์ง€ ์›์ธ์„ ์ฐพ๊ธฐ๊ฐ€ ํž˜๋“ค์–ด์„œ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.

์ผ๋‹จ mysql ์„œ๋ฒ„์˜ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•ด๋ณด๋ ค ํ–ˆ๋‹ค. ๋กœ๊ทธ ์œ„์น˜๊ฐ€ ์–ด๋””์ธ์ง€๋ฅผ ๋ชฐ๋ผ์„œ ๊ทธ๋ƒฅ find ๋ช…๋ น์–ด๋กœ mysql*.log ํŒŒ์ผ์„ ์ฐพ์œผ๋ คํ–ˆ๋Š”๋ฐ ์•ˆ๋‚˜์˜จ๋‹ค -_-; ๊ทธ๋ž˜์„œ ๊ตฌ๊ธ€๋ง์„ ํ•ด๋ดค๋”๋‹ˆ .err ํ™•์žฅ์ž๋กœ ๋๋‚˜๋Š” ํŒŒ์ผ์ด MAMP ์•ˆ์— log ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— ์žˆ์—ˆ๊ณ (ํŒŒ์ผ๋ช…์€ mysql_error_log.err ์ด๋‹ค) ํ•ด๋‹น ํŒŒ์ผ์„ ์—ด์–ด์„œ ์—๋Ÿฌ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ–ˆ๋”๋‹ˆ ํ•ด๋‹น ํฌํŠธ๊ฐ€ ์ด๋ฏธ ์‚ฌ์šฉ์ค‘์ด๋ž€๋‹ค. ์˜ค์ž‰? ๊ทธ๋Ÿผ ์„ค์น˜ํ›„์— ์‹คํ–‰์ด ๋๋‹ค๋Š” ์–˜๊ธด๊ฐ€??? ๊ทธ๋ž˜์„œ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ™•์ธํ•ด๋ณด์•˜๋‹ค.

ps -ef|grep mysql

๊ทธ๋žฌ๋”๋‹ˆ mysql ๋ฐ๋ชฌ์ด ์ด๋ฏธ ๋– ์žˆ๋‹ค. ์‹คํ–‰์‹œํ‚จ ์œ ์ €๋Š” _mysql ์ด๋ผ๊ณ  ๋˜์–ด์žˆ์—ˆ๊ณ  ์ด ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„๊ณ  ๋‹ค์‹œ MAMP๋ฅผ ์‹คํ–‰์‹œ์ผœ์„œ mysql ์„œ๋ฒ„๋ฅผ ๋„์šฐ๋ ค๊ณ  kill -9 PID๋ฅผ ์‹คํ–‰์‹œ์ผฐ๋Š”๋ฐ ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋Š” ๊บผ์กŒ์œผ๋‚˜ ๋‹ค๋ฅธ PID๋ฅผ ๊ฐ–๋Š” mysql๋ฐ๋ชฌ์ด ์ž๋™์œผ๋กœ ์‹คํ–‰์ด ๋˜์–ด์žˆ์—ˆ๋‹ค. ใ…กใ…ก;

๋ญ์ง€?? ์–˜ ์ข€๋น„๋„ค? ๋‹ค์‹œ ์—ด์‹ฌํžˆ ๊ตฌ๊ธ€๋ง์„ ํ•ด์„œ ๋™์ผํ•œ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์„ค๋ช…์„ ์ž˜ ํ•ด๋†“์€ ๋ฏธ๋””์—„ ํฌ์ŠคํŒ…์„ ํ•˜๋‚˜ ์ฐพ์•˜๋‹ค. ๋ฐ”๋กœ ์—ฌ๊ธฐ์ด๋‹ค. ํ•ด๋‹น ์‚ฌ์ดํŠธ์—์„œ๋Š” mysql-8.0.12-macos10.13 ๋ฒ„์ „์— ๋Œ€ํ•œ ์„ค๋ช…์ด ์žˆ์—ˆ๊ณ  ๋‚ด๊ฐ€ ์„ค์น˜ํ•œ ๋ฒ„์ „์€ mysql-8.0.20-macos10.15 ๋ฒ„์ „์ด์—ˆ๋‹ค. ์•„๋งˆ macOS ๋ฒ„์ „๋„ ๋‹ค๋ฅด์ง€ ์•Š์„๊นŒ ์‹ถ์€๋ฐ ์•„๋ฌดํŠผ ์ € ์‚ฌ์ดํŠธ์˜ ์„ค๋ช…๋Œ€๋กœ ํ•ด๋„ ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๋Š” ์ฃฝ์—ˆ๋‹ค ์‚ด์•„๋‚˜๊ณ  ์ฃฝ์—ˆ๋‹ค ์‚ด์•„๋‚˜๊ณ ๋ฅผ ๋ฐ˜๋ณตํ–ˆ๋‹ค.


๊ทธ๋ž˜์„œ ์ข€ ๋” ๊ตฌ๊ธ€๋ง์„ ํ•˜์—ฌ MySQL ๊ณต์‹ ๋ฌธ์„œ ์ค‘ MySQL launch daemon์— ๊ด€ํ•œ ๋ฌธ์„œ๋ฅผ ๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค. ํ•ด๋‹น ๋ฌธ์„œ์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๋‚ด์šฉ์ด ์žˆ์—ˆ๋‹ค.

2.4.3 Installing and Using the MySQL Launch Daemon
macOS uses launch daemons to automatically start, stop, and manage processes 
and applications such as MySQL.

By default, the installation package (DMG) on macOS installs a launchd file named 
/Library/LaunchDaemons/com.oracle.oss.mysql.mysqld.plist that contains a plist 
definition similar to:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>             <string>com.oracle.oss.mysql.mysqld</string>
    <key>ProcessType</key>       <string>Interactive</string>
    <key>Disabled</key>          <false/>
    <key>RunAtLoad</key>         <true/>
    <key>KeepAlive</key>         <true/>
    <key>SessionCreate</key>     <true/>
    <key>LaunchOnlyOnce</key>    <false/>
    <key>UserName</key>          <string>_mysql</string>
    <key>GroupName</key>         <string>_mysql</string>
    <key>ExitTimeOut</key>       <integer>600</integer>
    <key>Program</key>           <string>/usr/local/mysql/bin/mysqld</string>
    <key>ProgramArguments</key>
        <array>
            <string>/usr/local/mysql/bin/mysqld</string>
            <string>--user=_mysql</string>
            <string>--basedir=/usr/local/mysql</string>
            <string>--datadir=/usr/local/mysql/data</string>
            <string>--plugin-dir=/usr/local/mysql/lib/plugin</string>
            <string>--log-error=/usr/local/mysql/data/mysqld.local.err</string>
            <string>--pid-file=/usr/local/mysql/data/mysqld.local.pid</string>
            <string>--keyring-file-data=/usr/local/mysql/keyring/keyring</string>
            <string>--early-plugin-load=keyring_file=keyring_file.so</string>
        </array>
    <key>WorkingDirectory</key>  <string>/usr/local/mysql</string>
</dict>
</plist>

์ฆ‰, mysql์„ ์„ค์น˜ํ•˜๋ฉด /Library/LaunchDaemons/com.oracle.oss.mysql.mysqld.plist ํŒŒ์ผ์— ์œ„์™€ ๊ฐ™์€ ์„ค์ • ๋‚ด์šฉ์ด ๋“ค์–ด์žˆ๋‹ค๋Š” ๋‚ด์šฉ์ด์—ˆ๊ณ  ์„ค์ • ํ•ญ๋ชฉ๋“ค ์ค‘์— ์ž๋™์‹คํ–‰๊ณผ ๊ด€๋ จ๋œ ํ•ญ๋ชฉ์ด ์žˆ์„๊นŒ ์‹ถ์–ด ์ญˆ์šฑ ํ›‘์–ด๋ณด๋‹ˆ RunAtLoad ์™€ LaunchOnlyOnce ํ•ญ๋ชฉ์ด ๋ˆˆ์— ๋„์—ˆ๋‹ค.
์ผ๋‹จ ๋‘˜๋‹ค ๊ธฐ๋ณธ๊ฐ’๊ณผ ๋ฐ˜๋Œ€๋กœ ์„ค์ •ํ•˜์—ฌ RunAtLoad ๊ฐ’์€ false๋กœ, LaunchOnlyOnce์˜ ๊ฐ’์€ true๋กœ ์ˆ˜์ •ํ•ด์„œ ์ €์žฅํ•˜๊ณ  ๋‹ค์‹œ kill์„ ํ•ด๋ณด์•˜๋‹ค. (์ด ๊ณผ์ •์—์„œ ์žฌ๋ถ€ํŒ…์„ ํ–ˆ์—ˆ๋Š”์ง€ ์ •ํ™•ํžˆ ๊ธฐ์–ต์ด ๋‚˜์ง€๋Š” ์•Š๋Š”๋‹ค;; ์•ˆํ–ˆ๋˜๊ฒƒ ๊ฐ™์€๋ฐ..^^; ) ๊ทธ๋žฌ๋”๋‹ˆ ๋”์ด์ƒ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š์•˜๊ณ , MAMP๋ฅผ ์‹คํ–‰์‹œ์ผœ์„œ mysql ์„œ๋ฒ„๋ฅผ startํ•˜๋‹ˆ ์ด์ œ ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
 

๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๊พธ~~์šฑ~~ 

MySQL์˜ auto_increment ๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๋Š” ์‹œ์ 

์‚ฌ๋‚ด์—์„œ ํ…Œ์ด๋ธ” ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘์„ ์œ„ํ•ด์„œ ํ…Œ์ด๋ธ” ๋งŒ๋“ค ๋•Œ auto increment ์ปฌ๋Ÿผ์„ pk๋กœ ์ถ”๊ฐ€ํ•ด๋‹ฌ๋ผ๋Š” ์š”์ฒญ์ด ์žˆ์–ด์„œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ์‹œ ๊ผญ ์ถ”๊ฐ€ํ•˜๊ณ  ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ auto increment ์ปฌ๋Ÿผ์˜ ๊ฐ’์€ ์‹ค์ œ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ(insert)๋  ๋•Œ๋งŒ ์˜ฌ๋ผ๊ฐˆ ๊ฑฐ๋ผ๊ณ  ์ง€๋ ˆ์ง์ž‘๋งŒ ํ•˜๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ์ด๋ฒˆ์— ์–ด๋–ค ์„œ๋น„์Šค๋ฅผ ๋นจ๋ฆฌ ๊ฐœ๋ฐœํ•ด์ค˜์•ผํ•ด์„œ ์ƒˆ๋กœ์šด ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค์–ด ํ…Œ์ŠคํŠธํ•˜๋‹ค๊ฐ€ auto increment๊ฐ’์ด ์ˆœ์„œ๋Œ€๋กœ ์˜ฌ๋ผ๊ฐ€์ง€ ์•Š๋Š” ํ˜„์ƒ์„ ๋ณด๊ฒŒ๋˜์—ˆ๋‹ค.

ํ…Œ์ŠคํŠธ์ฝ”๋“œ๋Š” insert -> select -> update -> select ์ˆœ์œผ๋กœ ๋™์ž‘ํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๊ณ  ๋™์ผํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์ตœ์†Œ ๋‘ ๋ฒˆ ์ด์ƒ ๋Œ๋ ธ๋‹ค. ์ด๋ ‡๊ฒŒ ๋Œ๋ฆฌ๋‹ˆ๊นŒ ์ฒ˜์Œ์—๋Š” ๋‹น์—ฐํžˆ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์–ด์„œ no๊ฐ’์€ default๋กœ 1๋กœ ์ƒ์„ฑ์ด ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋˜‘๊ฐ™์€ ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ๋‹ค์‹œ ๋Œ๋ฆฌ๋ฉด duplicate key exception์ด ๋ฐœ์ƒํ•˜๋ฉด์„œ ๋‚ด๋ถ€์ ์œผ๋กœ auto increment๊ฐ’์ด ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์„ ์ค„ ์•Œ์•˜์œผ๋‚˜, ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์ง€ ๋ชปํ•œ๋‹คํ•ด๋„ insert๊ฐ€ ์‹œ๋„๋  ๋•Œ๋งˆ๋‹ค no๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. auto increment๊ฐ’์ด ์ฆ๊ฐ€ํ•˜๋Š” ์ผ€์ด์Šค๋ฅผ ์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

1. insert๊ฐ€ ์‹œ๋„๋˜๋ฉด no๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค.

2. duplication key ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹คํ•ด๋„ ์ฆ๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค.

3. update์‹œ์—๋Š” ์ฆ๊ฐ€ํ•˜์ง€ ์•Š์•˜๋‹ค.

์ผ๋ถ€ ํ…Œ์ด๋ธ”์€ ๋งŽ์€ ์–‘์˜ insert on duplicate key update ๋ฌธ์„ ์‹คํ–‰ํ•˜๊ณ ์žˆ๋Š”๋ฐ auto increment๊ฐ’์ด overflow ๋˜์ง€ ์•Š์„๊นŒ ์—ผ๋ ค๋˜์–ด ํ˜„์žฌ max no๊ฐ’์„ ์กฐํšŒํ•ด๋ณด๋‹ˆ ์•„์ง ์ˆ˜ ๋…„์€ ๋ฒ„ํ‹ธ ์ˆ˜๋Š” ์žˆ์„ ์ •๋„์˜€๋‹ค.

๋งŒ์•ฝ overflow ๋ ์ •๋„๋กœ ๋งŽ์ด ์˜ฌ๋ผ๊ฐ„๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ ??? no ๊ฐ’์„ ๋‹ค์‹œ 1๋กœ ์„ธํŒ…ํ•˜์—ฌ ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๊ธฐ๋Š” ํ•˜๋‹ค. ์•„๋ž˜ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด ๋‹ค์‹œ 1๋ถ€ํ„ฐ ์„ธํŒ…์„ ํ•ด์ค€๋‹ค.

ALTER TABLE YOUR_TABLE_NAME AUTO_INCREMENT=1;
SET @COUNT = 0;
UPDATE YOUR_TABLE_NAME SET AUTO_INCREMENT_COLUMN_NAME = @COUNT:=@COUNT+1;

ํ•˜์ง€๋งŒ ํ•ด๋‹น ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ lock์ด ์žกํž ๊ฒƒ์ด๋ผ์„œ ์ ๊ฒ€๋•Œ์—๋‚˜ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์ด ๋ฐฉ๋ฒ• ๋ง๊ณ  ์ง์ ‘ no๋ฅผ ์„ธํŒ…ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ๋ฐ์ดํ„ฐ ์ €์žฅ ์‹œ์— no๊ฐ’์„ ์ง์ ‘ ํ• ๋‹นํ•ด์ค„ ์ˆ˜ ์žˆ์œผ๋‹ˆ ๋ง์ด๋‹ค.

MyBatis TypeHandler๋ฅผ ์ด์šฉํ•œ ๊ฐ์ฒด๋ฆฌ์ŠคํŠธ ํ•ธ๋“ค๋ง

์ด๋ฒˆ์— ํŠน์ • ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๋‹ค๊ฐ€ JSON ํ˜•ํƒœ์˜ ์ŠคํŠธ๋ง์„ ๊ทธ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ๊บผ๋‚ด์จ์•ผํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ฒผ๋‹ค.

๊ทธ๊ฒƒ๋„ RBD์ธ mysql ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ง์ด๋‹ค. mysql์ด json ์ปฌ๋Ÿผ์„ ์ง€์›ํ•˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ json ํ•จ์ˆ˜๋ฅผ ์ฟผ๋ฆฌ์— ์“ธ ํ•„์š”๊นŒ์ง€๋Š” ์—†๋Š” ์ƒํ™ฉ์ด๋‹ค๋ณด๋‹ˆ ๊ทธ๋ƒฅ varcharํƒ€์ž…์œผ๋กœ ์ปฌ๋Ÿผ์„ ์ •์˜ํ–ˆ๊ณ  ์—ฌ๊ธฐ์— jsonํฌ๋งท์˜ ์ŠคํŠธ๋ง์„ ๊ทธ๋Œ€๋กœ ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ๊บผ๋‚ด์“ธ ์ˆ˜ ์žˆ๋„๋ก ํ•ด์•ผํ–ˆ๋‹ค.

์ผ๋‹จ ํƒ€์ž…ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋กœ ํ–ˆ๊ณ  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฑด์ง€ ๊ฒ€์ƒ‰์„ ์ข€ ํ•ด๋ดค๋‹ค. ๊ตฌ๊ธ€์—์„œ "Type handler for ArrayList in myBatis" ๋ผ๊ณ  ๊ฒ€์ƒ‰์„ ํ•˜๋‹ˆ ๋งŽ์€ ํฌ์ŠคํŒ…์ด ๊ฒ€์ƒ‰์ด ๋˜์—ˆ๊ณ  ๋‚ด ํ”„๋กœ์ ํŠธ์— ๋งž๊ฒŒ ๊ฐ€์ ธ๋‹ค๊ฐ€ ์“ธ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ž‘์—… ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. 

 

์šฐ์„  dto์˜ ๊ตฌ์กฐ๋ฅผ ๋ณด๋ฉด MyJsonDataWrapperClass ๊ฐ€ myJsonData ๋ฆฌ์ŠคํŠธ๋ฅผ ๋“ค๊ณ  ์žˆ๋Š”๋ฐ ์ด๋•Œ MyJsonData ํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋กœ json ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋  ์ •๋ณด์ด๋‹ค.

@Getter
@Setter
@JsonInclude(Include.NON_NULL)
public class MyJsonDataWrapperClass {

    private Integer someIntData;
    private List<MyJsonData> myJsonData = new ArrayList<>();
    
    @Override
    public String toString() {
        return new Gson().toJson(this);
    }
}
@Getter
@Setter
@EqualsAndHashCode
public class MyJsonData {
    private String name;
    private int age;

    @Override
    public String toString() {
        return new Gson().toJson(this);
    }
}

 

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” myJsonData ๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ textํƒ€์ž…์˜ ์ปฌ๋Ÿผ์„ ๋งŒ๋“ค์—ˆ๊ณ  mybatis์˜ insert๋ฌธ์— ์‚ฌ์šฉํ•  ํƒ€์ž…ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค.

, myJsonData = #{myJsonData, typeHandler=MyJsonDataTypeHandler}

 

๊ทธ๋ฆฌ๊ณ  ํƒ€์ž…ํ•ธ๋“ค๋Ÿฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ•˜์˜€๋‹ค.

@Slf4j
public class MyJsonDataTypeHandler extends BaseTypeHandler<List<MyJsonData>> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, List<MyJsonData> parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, new Gson().toJson(parameter));
    }

    @Override
    public List<MyJsonData> getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return convertToList(rs.getString(columnName));
    }

    @Override
    public List<MyJsonData> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return convertToList(rs.getString(columnIndex));
    }

    @Override
    public List<MyJsonData> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return convertToList(cs.getString(columnIndex));
    }

    private List<MyJsonData> convertToList(String myJsonDataListAsString) {
        try {
            return new ObjectMapper().readValue(myJsonDataListAsString, new TypeReference<List<MyJsonData>>() {
            });
        } catch (IOException e) {
            log.error("MyJsonDataTypeHandler failed to convert text to list, myJsonDataListAsString:{}", myJsonDataListAsString, e);
        }
        return Collections.emptyList();
    }
}

 

BaseTypeHandler๋ฅผ ์ƒ์†ํ•˜๋ฉด์„œ List<MyJsonData> ํƒ€์ž…์— ๋Œ€ํ•œ ํ•ธ๋“ค๋Ÿฌ์ž„์„ ๋ช…์‹œํ•ด์ฃผ์—ˆ๊ณ  setter์—๋Š” ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋ฅผ json ์ŠคํŠธ๋ง์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋„๋ก Gson.toJson() ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•˜์˜€๊ณ , getter์—๋Š” ์กฐํšŒํ•œ json ์ŠคํŠธ๋ง์„ ๋‹ค์‹œ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋„๋ก ํ•˜์˜€๋Š”๋ฐ ์ด๋•Œ๋Š” ObjectMapper.readValue()๋ฅผ ์ด์šฉํ•˜์˜€๋‹ค.

 

์กฐํšŒ์‹œ์—๋Š” mybatis ๋งคํ•‘ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด resultMap์„ ์ •์˜ํ•˜์—ฌ MyJsonDataTypeHandler๋ฅผ ์ด์šฉํ•ด์„œ myJsonDataํ•„๋“œ์˜ ๊ฐ’์„ ArrayList๋กœ ๋ณ€ํ™˜ํ•˜๋„๋ก ํ•˜์˜€์œผ๋ฉฐ, ์ด๋ ‡๊ฒŒ ์ •์˜ํ•œ resultMap์„ select ๋ฌธ์˜ resultMap์œผ๋กœ ์„ ์–ธํ•ด์ฃผ์—ˆ๋‹ค.

<resultMap id="myJsonDataClassMap" type="MyJsonDataWrapperClass">
<result property="myJsonData" column="myJsonData" javaType="java.util.ArrayList"
jdbcType="VARCHAR" typeHandler="MyJsonDataTypeHandler" />
</resultMap>

....์ค‘๋žต....

<select id="findMyJsonDataType"
resultMap="myJsonDataClassMap">
SELECT * FROM findMyJsonDataWrapperClass
</select>

 

์ด๋ ‡๊ฒŒ ํ•ด์ฃผ๋ฉด ์†Œ์Šค๋ ˆ๋ฒจ์—์„œ๋Š” ํŠน์ • ๊ฐ์ฒด์˜ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ํ•ธ๋“ค๋ง์„ ํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—๋Š” json ์ŠคํŠธ๋ง์œผ๋กœ ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ปฌ๋Ÿผ๋‹จ์œ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ชผ๊ฐœ์„œ ์ €์žฅํ•˜๊ธฐ ์• ๋งคํ•œ ์ƒํ™ฉ์—์„œ json ์ŠคํŠธ๋ง์„ varchar(text) ํƒ€์ž…์œผ๋กœ ํ†ต์œผ๋กœ ์ €์žฅํ•˜๊ณ  ์†Œ์Šค๋ ˆ๋ฒจ์—์„œ๋Š” ๊ฐ์ฒดํƒ€์ž…์œผ๋กœ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ฑด ์ •๋ง ๋ฉ‹์ง„ ๊ธฐ๋Šฅ์ธ๊ฒƒ ๊ฐ™๋‹ค.

 

 

์—˜๋ผ์Šคํ‹ฑ์„œ์น˜ shards failed ๋กœ์ธํ•œ ์กฐํšŒ์˜ค๋ฅ˜ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

์ตœ๊ทผ์— ์—˜๋ผ์Šคํ‹ฑ์„œ์น˜ ๋กœ๊ทธ๋ฐฑ ์–ดํŽœ๋”๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ์žˆ์–ด ์›๋ณต์„ ํ–ˆ๋‹ค.

 

๊ทผ๋ฐ ๊ทธ๋•Œ๋ถ€ํ„ฐ ํ‚ค๋ฐ”๋‚˜์—์„œ ๋กœ๊ทธ ์กฐํšŒ ์‹œ 5 of 240 shards failed ์™€ ๊ฐ™์€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋œจ๋ฉด์„œ ์กฐํšŒ์— ์‹คํŒจํ•˜์˜€๋‹ค.

 

์ฒ˜์Œ์—๋Š” type์ด ๋ฐ”๋€Œ๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๊ฑด๊ฐ€ ์‹ถ์—ˆ๊ณ , ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ์ง€ ๋ชฐ๋ผ ํŠน์ • ์ธ๋ฑ์Šค๋ฅผ ์‚ญ์ œํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

๊ฐœ๋ฐœํ™˜๊ฒฝ์—์„œ๋Š” ๊ทธ๋ ‡๊ฒŒ ํ–ˆ๋”๋‹ˆ ์กฐํšŒ๊ฐ€ ์ž˜ ๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ์œผ๋‚˜ ์ƒ์šฉํ™˜๊ฒฝ์—์„œ๋Š” ์—ฌ์ „ํžˆ ๋งˆ์ฐฌ๊ฐ€์ง€์˜€๋‹ค.

 

๋˜ํ•œ ์›๋ณตํ•œ ์ผ์ž์˜ ์ธ๋ฑ์Šค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด์ „ ๋‚ ์งœ์— ๋Œ€ํ•œ ์ธ๋ฑ์Šค๋“ค๋„ ์กฐํšŒ์— ์‹คํŒจํ•˜์˜€๋‹ค. ๊ทธ๊ฒƒ๋„ ํŠน์ • ์ธ๋ฑ์Šค ํŒจํ„ด์—์„œ๋งŒ ๋ง์ด๋‹ค.

 

ElasticSearch Head ํ”Œ๋Ÿฌ๊ทธ์ธ์œผ๋กœ ๊ฐœ๋ฐœํ™˜๊ฒฝ๊ณผ ์ƒ์šฉํ™˜๊ฒฝ์˜ ์ธ๋ฑ์Šค ์ƒํƒœ์— ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ์„ ํ•ด๋ณด์•˜๋Š”๋ฐ, 

๊ฐœ๋ฐœํ™˜๊ฒฝ์—๋Š” ํ‚ค๋ฐ”๋‚˜ ๊ด€๋ จ ์ธ๋ฑ์Šค ํŒŒ์ผ์ด 1๊ฐœ ์žˆ์—ˆ๊ณ  (.kibana_1) ์ƒํƒœ๊ฐ€ ํ‘ธ๋ฅธ์ƒ‰์ด์—ˆ๋‹ค. 

์ƒ์šฉํ™˜๊ฒฝ์—๋Š” ํ‚ค๋ฐ”๋‚˜ ๊ด€๋ จ ํŒŒ์ผ์ด 2๊ฐœ๊ฐ€ ์žˆ์—ˆ๊ณ  (.kibana_2, .kibana_1) .kibana_2 ํŒŒ์ผ์ด ์ฃผํ™ฉ์ƒ‰์œผ๋กœ ํ‘œ์‹œ๊ฐ€ ๋˜์—ˆ๋‹ค.

 

๊ตฌ๊ธ€๋ง์„ ์ข€ ํ•ด๋ณด๋‹ˆ ์ธ๋ฑ์Šค ํŒจํ„ด์„ ์‚ญ์ œํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑํ•ด๋ณด๋ผ๋Š” ์–˜๊ธฐ๊ฐ€ ์žˆ์–ด์„œ ๊ทธ๋ ‡๊ฒŒ ์ง„ํ–‰ํ–ˆ๋”๋‹ˆ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜ ์กฐํšŒ๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค ^-^