Skip to content

chujaeyeong/MAT_ZIP_board

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

8 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

[ํŒ€ํ”„๋กœ์ ํŠธ] ๋ง›.JAVA - ๋ง›.ZIP

๐Ÿ’ก ๋ง›.ZIP์€ โ€œ์ง„์งœ ๋ฏฟ๊ณ  ๋จน์„ ์ˆ˜ ์žˆ๋Š” ๋ง›์ง‘โ€ ์„ ๊ณต์œ ํ•˜๋Š” ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค.

  • ๋ง›.JAVA ํŒ€์€ ๋ง›์ง‘ ํƒ๋ฐฉ์— ๋ˆ„๊ตฌ๋ณด๋‹ค ์ง„์‹ฌ์ธ ์‚ฌ๋žŒ๋“ค์ด ๋ญ‰์นœ ํŒ€์ž…๋‹ˆ๋‹ค. ๐Ÿ”
  • ํ‰์†Œ์— ๋ชจ๋‘๊ฐ€ ๊ฒช๊ณ  ์žˆ๋˜ ๋ถ€์ •ํ•œ ๊ด‘๊ณ , ๋ฏฟ์„ ์ˆ˜ ์—†๋Š” ํ›„๊ธฐ ์†์—์„œ ์†Œ๋น„์ž๋“ค์ด ๋ฏฟ๊ณ  ๋ฐฉ๋ฌธํ•  ์ˆ˜ ์žˆ๋Š” ๋ง›์ง‘์„ ๋ชจ์•„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์ดํŠธ์˜ ํ•„์š”์„ฑ์„ ๋А๊ผˆ์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ, ์˜์ˆ˜์ฆ 2ํšŒ ์ด์ƒ ์ธ์ฆ๋œ ๋ง›์ง‘๋งŒ ๋“ฑ๋ก๋˜๋„๋ก ํ•ด์„œ ์‹ ๋ขฐ๋„ ๋ฐ ๋งŒ์กฑ๋„๊ฐ€ ๋†’์€ ๋ง›์ง‘๋งŒ ์„ ๋ณ„ํ•˜์—ฌ ์†Œ๋น„์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๊ตญ๋‚ด ์šด์˜ ์ค‘์ธ ๋ง›์ง‘ ์ถ”์ฒœ ์‚ฌ์ดํŠธ, ๋Œ€ํ˜• ํฌํ„ธ ์ง€๋„ ์‚ฌ์ดํŠธ์˜ ์‚ฌ๋ก€ ๋ถ„์„์„ ํ†ตํ•ด, ์›น์‚ฌ์ดํŠธ ๊ธฐ๋Šฅ์˜ ๋ฐฉํ–ฅ์„ฑ์„ "์ง„์ •์„ฑ ์žˆ๋Š” ๋ง›์ง‘ ๊ณต์œ "๋กœ ์ดˆ์ ์„ ๋งž์ท„์Šต๋‹ˆ๋‹ค.
  • ๋ง›์ง‘์„ ์ข‹์•„ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ๋ง›์ง‘์„ ์ข‹์•„ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์˜ ๋ฐฉ๋ฌธ์„ ์›ํ•˜๋Š” ์š”์‹์—…๊ณ„ ์‚ฌ์žฅ๋‹˜๋“ค๋„ ํƒ€์ผ“ํŒ…ํ•œ ์‚ฌ์žฅ๋‹˜ ์ „์šฉ ๊ตฌ๋… ์„œ๋น„์Šค ๋ฐ ๋…ธ์ถœ ๋ฐฐ๋„ˆ ๊ด‘๊ณ ๋ฅผ BM์œผ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

1. ์ œ์ž‘ ๊ธฐ๊ฐ„

2023๋…„ 4์›” 28์ผ ~ 6์›” 9์ผ (1๊ฐœ์›”)


2. ์‚ฌ์šฉ ๊ธฐ์ˆ 

Back-end

  • Java 8
  • Spring Framework 5.0.1, Spring MVC
  • Junit5
  • Maven
  • Mybatis
  • Eclipse, Visual Studio Code

Front-end

  • HTML
  • CSS
  • JavaScript
  • JQuery 3.6.4
  • BootStrap 4.1

DevOps

  • AWS EC2, S3, RDS, CloudFront, Route 53, ALB
  • Tomcat 8.5
  • MySQL 8.0.32

Collaboration

  • Git, Sourcetree
  • Slack
  • Notion

3. ๊ธฐ๋Šฅ ๊ตฌํ˜„

  • [์ถ”์žฌ์˜] ํšŒ์› ์ปค๋ฎค๋‹ˆํ‹ฐ

    • ๋ง›์ง‘์— ๊ด€์‹ฌ์ด ์žˆ๋Š” ์†Œ๋น„์ž๊ฐ€ ์ด์šฉํ•˜๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ๋กœ, ๋ฆฌ๋ทฐ / ์‚ฌ์ง„ / ์ง€์œ ๊ฒŒ์‹œํŒ์œผ๋กœ ๋‚˜๋ˆ„์–ด ์œ ์ € ์šฉ๋„์— ๋”ฐ๋ผ ์„ธ๋ถ€ ๋ฉ”๋‰ด ๋ถ„๋ฅ˜
    • ๊ฐ ๊ฒŒ์‹œํŒ๋ณ„ ๊ฒŒ์‹œ๋ฌผ CRUD ๊ธฐ๋Šฅ ๋ฐ ๋Œ“๊ธ€ insert ๊ธฐ๋Šฅ
    • ๋ฆฌ๋ทฐ๊ฒŒ์‹œํŒ์€ ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜์—ฌ ์˜์ˆ˜์ฆ ๋“ฑ๋ก์„ ํ•œ ์œ ์ €๋งŒ ๋ฆฌ๋ทฐ๋ฅผ ๋‚จ๊ธธ ์ˆ˜ ์žˆ๋„๋ก ์ œ์•ฝ์‚ฌํ•ญ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฆฌ๋ทฐ์˜ ์‹ ๋ขฐ๋„๋ฅผ ๊ฐ•ํ™”ํ•จ.


4. ERD ์„ค๊ณ„


5. ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์„ค๋ช… & ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

[์ถ”์žฌ์˜] ํšŒ์› ์ปค๋ฎค๋‹ˆํ‹ฐ

๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์„ค๋ช…
1. ์œ ์ €์˜ ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•œ ๋ฆฌ๋ทฐ ์ž‘์„ฑ ๊ธฐ๋Šฅ
  • ํšŒ์› ์ปค๋ฎค๋‹ˆํ‹ฐ ๋‚ด ๋ฆฌ๋ทฐ ๊ฒŒ์‹œํŒ์€ ์œ ์ €๊ฐ€ ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์˜ ๋ฆฌ๋ทฐ์— ๋Œ“๊ธ€์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ์˜ ๊ฒŒ์‹œํŒ ํŽ˜์ด์ง€๋กœ ๊ตฌํ˜„.
    • ๋ฆฌ๋ทฐ์— ์‹ ๋ขฐ๋„๋ฅผ ๋†’์ด๊ธฐ ์œ„ํ•ด, ์œ ์ €์˜ ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์—ฌ๋ถ€ ํŒ๋‹จ์ด ํ•„์š”ํ•จ.
    • ์˜์ˆ˜์ฆ์„ ๋‹ค์ˆ˜์˜ ์‹๋‹น์— ๋“ฑ๋กํ•˜๊ณ  ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ, ๋ฆฌ๋ทฐ๋ฅผ ๋‚จ๊ธฐ๊ณ  ์‹ถ์€ ์˜์ˆ˜์ฆ์„ ์„ ํƒํ•˜๋Š” form์œผ๋กœ ๋จผ์ € ์ด๋™์ด ํ•„์š”ํ•จ.
  • ๋ฆฌ๋ทฐ๊ฒŒ์‹œํŒ (Review...) ๊ฒŒ์‹œ๋ฌผ ๋“ฑ๋ก ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด registerAndSearch ํŒจํ‚ค์ง€ ์•ˆ์— ์žˆ๋Š” MZRegisterInfoVO ์™€ RestaurantVO์˜ ์‚ฌ์šฉ์ด ํ•„์š”ํ•จ. ๋‘ model ๋ชจ๋‘ ๋‹ค๋ฅธ ํŒจํ‚ค์ง€์— ์žˆ์ง€๋งŒ, public ๋ฉ”์†Œ๋“œ๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— board ํŒจํ‚ค์ง€์— ๋™์ผ model์„ ๋งŒ๋“ค์ง€ ์•Š๊ณ  MZRegisterReceiptDTO ๋งŒ ์ƒ์„ฑํ•˜์—ฌ mzRegisterInfoVO์™€ restaurantVO๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ.
  • ReviewMapper.xml์—์„œ mzregisterinfo ์™€ restaurant ํ…Œ์ด๋ธ”์„ join ํ•ด์„œ ์˜์ˆ˜์ฆ ์ •๋ณด์™€ ์‹๋‹น ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๋Š” getReceiptWithRestaurant ์ฟผ๋ฆฌ ์ž‘์„ฑ. (mzregisterinfo ํ…Œ์ด๋ธ”์˜ storePhoneNumber ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ์™€ restaurant ํ…Œ์ด๋ธ”์˜ tel ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๊ฐ€ ์ผ์น˜ํ•˜๋Š” restaurant ํ…Œ์ด๋ธ”์˜ name ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒํ˜ธ๋ช…์œผ๋กœ ์ถ”์ถœ)
  • ์˜์ˆ˜์ฆ 1์žฅ์œผ๋กœ ๋ฆฌ๋ทฐ๋ฅผ ๋‹คํšŒ ์ž‘์„ฑ์„ ๋ง‰๊ธฐ ์œ„ํ•ด cs_review ํ…Œ์ด๋ธ”์— receipt_id ์ปฌ๋Ÿผ (mzregisterinfo์˜ no ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ €์žฅ) ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์˜์ˆ˜์ฆ ์ •๋ณด์™€ ์‹๋‹น ์ •๋ณด๋ฅผ ์ถ”์ถœ.
  • โ€ผ๊ฒฐ๊ณผโ€ผ writeReview๋กœ ์ด๋™ํ•˜๋ฉด getReceiptWithRestaurant ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ์˜์ˆ˜์ฆ์˜ ์ƒํ˜ธ๋ช… + ์ฃผ์†Œ ๊ฐ€ radio form์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์ถœ๋ ฅ, ์œ ์ €๊ฐ€ ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•  ์˜์ˆ˜์ฆ์„ ์„ ํƒํ•˜๊ณ  ๋ฆฌ๋ทฐ ์ž‘์„ฑ form์œผ๋กœ ์ด๋™ํ•˜๋„๋ก ๊ตฌํ˜„. (์˜์ˆ˜์ฆ์„ ๋“ฑ๋กํ•˜์ง€ ์•Š์€ ์œ ์ €๊ฐ€ writeReview ์œผ๋กœ ์ด๋™ํ•˜๋ฉด alert ์ฐฝ์„ ๋ณด์—ฌ์ฃผ๊ณ  ๋ฆฌ๋ทฐ๊ฒŒ์‹œํŒ์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋จ.)
2. ๋ฆฌ๋ทฐ ๋ณธ๋ฌธ์—์„œ ํŠน์ • ํ‚ค์›Œ๋“œ ์ถ”์ถœํ•˜์—ฌ ์ด๋ชจํ‹ฐ์ฝ˜ ์กฐํšŒ ๊ธฐ๋Šฅ
  • ์œ ์ €๊ฐ€ ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑ ํ›„ ์ œ์ถœํ•˜๊ธฐ ์ „์—, ์ด๋ชจํ‹ฐ์ฝ˜ ์กฐํšŒ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์‹๋‹น ๋ฐฉ๋ฌธ ์‹œ ์ฐธ๊ณ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฃผ์š” ํ‚ค์›Œ๋“œ (ex. ์ฃผ์ฐจ, ๋ง›, ์ฒญ๊ฒฐ, ๊ฐ€์„ฑ๋น„ ๋“ฑ) ๋ฅผ ๊ฒ€์ƒ‰ํ•ด์„œ ์ด๋ชจํ‹ฐ์ฝ˜์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ๋ฆฌ๋ทฐ ์ž‘์„ฑ form ์— ์ถ”๊ฐ€.
  • ๊ธฐ์กด์—๋Š” ๋„ค์ด๋ฒ„ Sentiment API๋ฅผ ํ™œ์šฉํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜, ๊ธ์ •/๋ถ€์ • ํŒŒํŠธ๋ฅผ ํผ์„ผํŠธ๋กœ ํŒ๋‹จํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์ด๋ผ ๋‹ค์–‘ํ•œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ ํ›„ ์ถœ๋ ฅ์ด ํ•„์š”ํ•œ ์ง€๊ธˆ ์ƒํ™ฉ์—๋Š” API๊ฐ€ ์•ฝ๊ฐ„ ๋งž์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ MySQL์— ํ‚ค์›Œ๋“œ์™€ ์ด๋ชจํ‹ฐ์ฝ˜์„ ์ €์žฅํ•œ emojiMap ํ…Œ์ด๋ธ”์„ DB์— ์ƒ์„ฑํ•˜์—ฌ ํ‚ค์›Œ๋“œ๋ฅผ ์ €์žฅํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰. (ํ˜•ํƒœ์†Œ ๋ถ„๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€๋งŒ ์ผ๋‹จ ํ…Œ์ŠคํŠธ)
  • ReviewMapper.xml ์— ์ถ”๊ฐ€ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฌธ์—์„œ๋Š” emojiMap ๋ฐ์ดํ„ฐ ์ „์ฒด SELECT ์ฟผ๋ฆฌ , Service ๊ณ„์ธต์—์„œ ๋ฆฌ๋ทฐ ๋ณธ๋ฌธ๊ณผ emojiMap ํ…Œ์ด๋ธ”์˜ keyward ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ๋น„๊ตํ•ด์„œ ์ผ์น˜ํ•˜๋Š” emoji ์ปฌ๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœ ํ›„ ๋ชจ๋ธ์— ์ €์žฅํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰.
  • โ€ผ๊ฒฐ๊ณผโ€ผ ๋ฆฌ๋ทฐ ์ž‘์„ฑ form (insertReview) ์—์„œ ๋ฆฌ๋ทฐ ๋ณธ๋ฌธ์„ ๋ชจ๋‘ ์ž…๋ ฅ ํ•˜๊ณ , ์ด๋ชจํ‹ฐ์ฝ˜ ์กฐํšŒ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ajax๋กœ ๋ฆฌ๋ทฐ ํ•˜๋‹จ div์— ์ถ”์ถœ๋œ ์ด๋ชจํ‹ฐ์ฝ˜์ด ์ถœ๋ ฅ๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ ์ด๋ชจํ‹ฐ์ฝ˜ ์กฐํšŒ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„.
3. 3๊ฐœ์˜ ์„ธ๋ถ€ ๊ฒŒ์‹œํŒ๋ณ„ CRUD ๊ธฐ๋Šฅ
  • ์œ ์ €๊ฐ€ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฒŒ์‹œํŒ์˜ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋ถ„ํ• , ๊ฐ ๊ฒŒ์‹œํŒ๋ณ„ CRUD ๊ธฐ๋Šฅ ์ถ”๊ฐ€. ๊ฒŒ์‹œ๋ฌผ insert ๊ธฐ๋Šฅ์€ ํšŒ์›๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ž‘์„ฑ ๋ฒ„ํŠผ์„ user_id ์„ธ์…˜์ด ์žกํ˜€์žˆ๋Š” ๊ฒฝ์šฐ์—๋งŒ ๋ธŒ๋ผ์šฐ์ €์— ์ถœ๋ ฅ๋˜๋„๋ก ์ฝ”๋“œ ์ž‘์„ฑ, ๋„ค๋น„๊ฒŒ์ด์…˜๋ฐ”๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์•„์›ƒํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ € ๋’ค๋กœ๊ฐ€๊ธฐ๋กœ ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ–ˆ์„ ๋•Œ alert ์ฐฝ ์ถœ๋ ฅ ํ›„ ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋  ์ˆ˜ ์žˆ๋„๋ก ์˜ˆ์™ธ์ฒ˜๋ฆฌ ์ง„ํ–‰.
  • ์ƒ๋Œ€์ ์œผ๋กœ ๊ธฐ๋Šฅ์ด ๊ฐ„๋‹จํ•œ ์ž์œ ๊ฒŒ์‹œํŒ์€ Service ๊ณ„์ธต์„ ๋‚˜๋ˆ„์ง€ ์•Š์•˜๊ณ , ์ž์œ ๊ฒŒ์‹œํŒ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ์™„๋ฃŒ ํ›„ ๋ฆฌ๋ทฐ๊ฒŒ์‹œํŒ๊ณผ ์‚ฌ์ง„๊ฒŒ์‹œํŒ์€ Service ๊ณ„์ธต์„ ๋‚˜๋ˆ„์–ด ๊ธฐ๋Šฅ ์ถ”๊ฐ€.
  • ๊ฒŒ์‹œํŒ๋ณ„ ์ œ๋ชฉ search form ์ถ”๊ฐ€ํ•˜์—ฌ ํŠน์ • ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ์‹œ ์ œ๋ชฉ์— ํ•ด๋‹น ํ‚ค์›Œ๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒŒ์‹œ๋ฌผ list๋ฅผ ajax ๋น„๋™๊ธฐ์ฒ˜๋ฆฌ๋กœ ๋ธŒ๋ผ์šฐ์ €์— ์ถœ๋ ฅ.
  • ๊ฒŒ์‹œํŒ์— ํ•„์š”ํ•œ ์กฐํšŒ์ˆ˜ ์ฆ๊ฐ€ / ๋Œ“๊ธ€ ์ž‘์„ฑ ๊ธฐ๋Šฅ ๊ฐ ์„ธ๋ถ€ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฒŒ์‹œํŒ์— ์ถ”๊ฐ€.
  • ๊ฒŒ์‹œ๋ฌผ insert ๊ธฐ๋Šฅ์€ ํšŒ์›๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ธ์…˜
  • โ€ผ๊ฒฐ๊ณผโ€ผ ๊ฐ ์„ธ๋ถ€ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฒŒ์‹œํŒ์˜ ๊ธฐ๋ณธ CRUD, ๋Œ“๊ธ€ insert ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ ์™„๋ฃŒ.
โšฝ ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…
1. ์˜์ˆ˜์ฆ ๋“ฑ๋ก ํ›„ ๋ฆฌ๋ทฐ ์ž‘์„ฑ ์‹œ ์˜์ˆ˜์ฆ list๋ฅผ ์ถœ๋ ฅํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ
  • ๋ฆฌ๋ทฐ ๋“ฑ๋ก ์‹œ, ๋จผ์ € ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์ •๋ณด๋ฅผ writeReview.jsp ๋กœ ํŽ˜์ด์ง€ ์ด๋™ํ•˜์—ฌ ์ถœ๋ ฅํ•ด์•ผ๋˜๋Š”๋ฐ, receiptList (์˜์ˆ˜์ฆ์˜ ๋ฆฌ์ŠคํŠธ) ์˜ ๋ชจ๋“  ์š”์†Œ๊ฐ€ null๋กœ ์ถœ๋ ฅ๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•จ. ๋””๋ฒ„๊น… ํ–ˆ๋”๋‹ˆ receiptList์˜ size (๋ฆฌ๋ทฐํ•  ์˜์ˆ˜์ฆ์˜ ๊ฐฏ์ˆ˜) ๋Š” ์ •์ƒ์ ์œผ๋กœ ์ฝ˜์†”์ฐฝ์— ์ถœ๋ ฅ๋˜๊ณ  ์žˆ์Œ.
๐Ÿ‘‰ ๋ฌธ์ œ๊ฐ€ ์žˆ๋˜ ์ฟผ๋ฆฌ ํ™•์ธ
  <!-- ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ž -->
  <select id="getReceiptWithRestaurant" parameterType="String" resultType="MZRegisterReceiptDTO">
  	SELECT r.*, m.* 
  	FROM mzRegisterInfo m 
  	JOIN restaurant r ON m.storePhoneNumber = r.tel 
  	WHERE m.userID = #{user_id} 
  	AND m.no NOT IN 
  	(SELECT receipt_id FROM MAT_ZIP.cs_review)
  </select>
  • 1๏ธโƒฃ ์ฒซ ๋ฒˆ์งธ ์‹œ๋„ : ์ฟผ๋ฆฌ ์ž‘์„ฑ์—์„œ ์˜คํƒ€๋‚˜ ์ž˜๋ชป ์ž‘์„ฑ๋œ ๋ถ€๋ถ„์ด ์žˆ์„ ์ˆ˜๋„ ์žˆ์–ด์„œ, getReceiptWithRestaurant ์ฟผ๋ฆฌ๋ฅผ ๊ทธ๋Œ€๋กœ MySQL ์Šคํฌ๋ฆฝํŠธ์—์„œ ์‹คํ–‰ํ•จ. -> ์ฟผ๋ฆฌ์— ๋ฌธ์ œ ์—†์Œ. ์ •์ƒ์ ์œผ๋กœ mzregisterinfo ํ…Œ์ด๋ธ”๊ณผ restaurant ํ…Œ์ด๋ธ”์„ join ํ•˜๊ณ , ๋”๋ฏธ๋ฐ์ดํ„ฐ๋กœ ์ถ”๊ฐ€ํ•ด๋‘” cs_review ํ…Œ์ด๋ธ”์˜ receipt_id๋„ ์ •์ƒ์ ์œผ๋กœ ์ œ์™ธํ•˜์—ฌ ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•  ๋ฐ์ดํ„ฐ๋งŒ select ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ.
  • 2๏ธโƒฃ ๋‘ ๋ฒˆ์งธ ์‹œ๋„ : MZRegisterReceiptDTO ์— ์ถ”๊ฐ€ํ•œ MZRegisterInfoVO์™€ RestaurantVO์— ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๊ฐ€ ๋งคํ•‘๋˜์ง€ ๋ชปํ–ˆ์„ ์ˆ˜๋„ ์žˆ์Œ. -> ReviewMapper.xml ์— ์ถ”๊ฐ€ํ•œ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์˜ ๊ฐ ์—ด์ด MZRegisterInfoVO์™€ RestaurantVO์˜ ํ•„๋“œ์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•จ.
  • 3๏ธโƒฃ ์„ธ ๋ฒˆ์งธ ์‹œ๋„ : MZRegisterReceiptDTO ํด๋ž˜์Šค์˜ toString() ๋ฉ”์„œ๋“œ๊ฐ€ MZRegisterInfoVO์™€ RestaurantVO์˜ toString() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”์ง€ ํ™•์ธ -> MZRegisterReceiptDTO, MZRegisterInfoVO, RestaurantVO ํด๋ž˜์Šค์˜ toString() ๋ฉ”์„œ๋“œ๋Š” ๋”ฑํžˆ ๋ฌธ์ œ ์—†์ด ์ž˜ ์ž‘์„ฑ๋˜์—ˆ์Œ์„ ํ™•์ธํ•จ.
  • โ€ผ์›์ธโ€ผ SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ ๋งคํ•‘ ๋ฌธ์ œ์ž„์„ ํ™•์ธํ•จ.

  • 4๏ธโƒฃ ๋„ค ๋ฒˆ์งธ ์‹œ๋„ : ๋” ์ •ํ™•ํ•œ ๋งคํ•‘์„ ์œ„ํ•ด MyBatis์˜ resultMap์„ ์ด์šฉํ•ด์„œ SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ MZRegisterReceiptDTO ๊ฐ์ฒด์— ๋งคํ•‘ ์‹œ๋„

    • ์ด์ „ ์ฟผ๋ฆฌ๋ฌธ์—์„œ๋Š” resultType="MZRegisterReceiptDTO" ์„ ํ†ตํ•ด DTO์— ๋งคํ•‘์„ ํ–ˆ์ง€๋งŒ, MyBatis์˜ resultMap์€ SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋„๋ฉ”์ธ ๋ชจ๋ธ ๋˜๋Š” DTO ๊ฐ์ฒด์— ๋งคํ•‘ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ํ•จ.
    • MyBatis์˜ resultMap์€ ์ผ๋ฐ˜์ ์ธ resultType ๋งคํ•‘๋ณด๋‹ค ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ์ปจํŠธ๋กค ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋‚˜์ฒ˜๋Ÿผ ์ฟผ๋ฆฌ๊ฐ€ DB์—์„œ๋„ ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ์ž‘์„ฑํ–ˆ๋Š”๋ฐ๋„ ๋งคํ•‘์„ ํ•˜์ง€ ๋ชปํ•ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ๋Š” resultMap์œผ๋กœ ์„ธ๋ฐ€ํ•˜๊ฒŒ ๋งคํ•‘์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๊ณ  ํ•˜์—ฌ ์ ์šฉํ•ด๋ณด๊ธฐ๋กœ ํ•จ.
    <!-- resultMap ๋งคํ•‘ ์˜ˆ์‹œ ์ฟผ๋ฆฌ -->
    <resultMap id="yourResultMap" type="com.yourpackage.YourDTO">
        <result property="propertyOfYourDTO" column="columnOfYourSQLResult"/>
        <!-- more result mappings... -->
    </resultMap>
    • ๋‚˜๋Š” ํ•ญ์ƒ resultType์œผ๋กœ ๋„๋ฉ”์ธ ๋ชจ๋ธ (VO) ์— ๋งคํ•‘์„ ํ–ˆ๋Š”๋ฐ, ์ด๋ฒˆ์— resultMap์— ๋Œ€ํ•ด์„œ ์•Œ๊ฒŒ ๋จ. ๋ณดํ†ต resultMap์€ ์ด๋Ÿฐ ๊ตฌ์กฐ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Œ. ์—ฌ๊ธฐ์„œ id๋Š” resultMap์˜ ๊ณ ์œ  ์‹๋ณ„์ž, type์€ ๊ฒฐ๊ณผ๋ฅผ ๋งคํ•‘ํ•  DTO์˜ ํ’€ ํด๋ž˜์Šค ์ด๋ฆ„์ด๊ณ , result ์š”์†Œ๋Š” SQL ๊ฒฐ๊ณผ์˜ ์—ด(column)๊ณผ DTO์˜ ์†์„ฑ(property)์„ ๋งคํ•‘ํ•จ.
    • ๋‹จ์ˆœํžˆ DTO์˜ ์†์„ฑ ์ด๋ฆ„์ด SQL ๊ฒฐ๊ณผ์˜ ์—ด ์ด๋ฆ„๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋˜๋Š” ๋ณต์žกํ•œ ๊ฐ์ฒด ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„ DTO์— ๊ฒฐ๊ณผ๋ฅผ ๋งคํ•‘ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์— resultMap์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ ์šฉํ•˜๋‹ค๊ณ  ํ•จ. ๋‚œ ๋‹ค์†Œ ๋ณต์žกํ•œ DTO (๋ชจ๋ธ 2๊ฐœ๋ฅผ ํ•ฉ์ณ์„œ DTO๋ฅผ ๋งŒ๋“ค์—ˆ์Œ) ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋•Œ๋ฌธ์— ํ›„์ž์ธ ๊ฒƒ์œผ๋กœ ์ถ”์ •.

  • โ€ผ๊ฒฐ๊ณผโ€ผ MyBatis์˜ resultMap์œผ๋กœ ์ฟผ๋ฆฌ ๋งคํ•‘์— ์„ฑ๊ณตํ•จ! DTO์— ์ฃผ์ž…ํ–ˆ๋˜ mzRegisterInfoVO ์™€ restaurantVO ์˜ ํ•„๋“œ๋ฅผ mzregisterinfo ํ…Œ์ด๋ธ”๊ณผ restaurant ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ์— ํ•˜๋‚˜ํ•˜๋‚˜ ์ˆ˜๋™ ๋งคํ•‘ํ•ด์คŒ. ์ˆ˜๋™ ๋งคํ•‘ ํ›„ ์ฟผ๋ฆฌ๋ฅผ ์ข€ ๋” ์ƒ์„ธํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์—ฌ ๋ฆฌ๋ทฐ ์ž‘์„ฑ ์‹œ ์˜์ˆ˜์ฆ list๋ฅผ ์ถœ๋ ฅํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•œ ๊ฒฐ๊ณผ, ์›ํ•˜๋Š”๋Œ€๋กœ ์ƒํ˜ธ๋ช…๊ณผ ์ฃผ์†Œ ์ •๋ณด๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•จ.

๐Ÿ‘‰ ์ˆ˜์ •ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ ์ฟผ๋ฆฌ ํ™•์ธ
  <!-- ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ž -->
  <resultMap id="MZRegisterReceiptDTOMap" type="com.mat.zip.board.MZRegisterReceiptDTO">
      <association property="mzRegisterInfoVO" javaType="com.mat.zip.registerAndSearch.model.MZRegisterInfoVO">
  	<result property="no" column="m_no" />
  	<result property="userId" column="m_userId" />
  	<result property="storeAddress" column="m_storeAddress" />
  	<result property="storePhoneNumber" column="m_storePhoneNumber" />
  	<result property="buyTime" column="m_buyTime" />
      </association>
      <association property="restaurantVO" javaType="com.mat.zip.registerAndSearch.model.RestaurantVO">
  	<result property="no" column="r_no" />
  	<result property="landNumAddress" column="r_landNumAddress" />
  	<result property="roadNameAddress" column="r_roadNameAddress" />
  	<result property="name" column="r_name" />
  	<result property="status" column="r_status" />
  	<result property="tel" column="r_tel" />
  	<result property="food" column="r_food" />
      </association>
  </resultMap>

  <select id="getReceiptWithRestaurant" parameterType="String" resultMap="MZRegisterReceiptDTOMap">
  SELECT r.no as r_no, r.landNumAddress as r_landNumAddress, r.roadNameAddress as r_roadNameAddress,
             r.name as r_name, r.status as r_status, r.tel as r_tel, r.food as r_food,
             m.no as m_no, m.userId as m_userId, m.storeAddress as m_storeAddress,
             m.storePhoneNumber as m_storePhoneNumber, m.buyTime as m_buyTime
      FROM mzRegisterInfo m 
      JOIN restaurant r ON m.storePhoneNumber = r.tel 
      WHERE m.userID = #{user_id} 
      AND m.no NOT IN 
      (SELECT receipt_id FROM cs_review)
  </select>
  • โ€ผํ•ด์„โ€ผ MZRegisterInfoVO์™€ RestaurantVO์˜ ๊ฐ ํ•„๋“œ์™€ SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์˜ ์—ด์„ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด resultMap์„ ์‚ฌ์šฉํ•จ. resultMap ๋‚ด์—์„œ association ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณตํ•ฉ DTO ๋‚ด์˜ ๋‘ ๊ฐœ์˜ ๊ฐ์ฒด๋ฅผ ๋”ฐ๋กœ ๊ด€๋ฆฌ ์ง„ํ–‰ํ•˜๊ณ , ๋˜ํ•œ SQL ์ฟผ๋ฆฌ์—์„œ๋Š” ๊ฐ ํ•„๋“œ์— ๋ณ„์นญ(alias)์„ ์‚ฌ์šฉํ•˜์—ฌ resultMap์—์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ , ๋ณ„์นญ์„ ์‚ฌ์šฉํ•˜์—ฌ SQL ๊ฒฐ๊ณผ์˜ ์—ด๊ณผ DTO์˜ ์†์„ฑ์„ ์—ฐ๊ฒฐํ•จ

  • ๐Ÿ’ก ์ถ”๊ฐ€ โ–บ ์—…๋ฐ์ดํŠธํ•œ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋ฉด, cs_review (๋ฆฌ๋ทฐ๊ฒŒ์‹œ๊ธ€ ์ €์žฅ ํ…Œ์ด๋ธ”) ์„ IN ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, IN ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ถ”ํ›„์— ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ์— ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฌธ์ œ์ ์ด ์žˆ๋Š” ์ฟผ๋ฆฌ์ž„. ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์„๊ฑฐ๋ฉด ๋ญ ๊ณ ์น˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€์€ ์—†์ง€๋งŒ, ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด JOIN ์ ˆ์„ ํ•˜๋‚˜ ๋” ์‚ฌ์šฉํ•ด์„œ ์ฟผ๋ฆฌ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง„ํ–‰ํ•จ.
๐Ÿ‘‰ ์„ฑ๋Šฅ์„ ์—…๋ฐ์ดํŠธํ•œ ์ฟผ๋ฆฌ ํ™•์ธ
  <!-- ์˜์ˆ˜์ฆ ๋“ฑ๋ก ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค์ž -->
  <resultMap id="MZRegisterReceiptDTOMap" type="com.mat.zip.board.MZRegisterReceiptDTO">
      <association property="mzRegisterInfoVO" javaType="com.mat.zip.registerAndSearch.model.MZRegisterInfoVO">
  	<result property="no" column="m_no" />
  	<result property="userId" column="m_userId" />
  	<result property="storeAddress" column="m_storeAddress" />
  	<result property="storePhoneNumber" column="m_storePhoneNumber" />
  	<result property="buyTime" column="m_buyTime" />
      </association>
      <association property="restaurantVO" javaType="com.mat.zip.registerAndSearch.model.RestaurantVO">
  	<result property="no" column="r_no" />
  	<result property="landNumAddress" column="r_landNumAddress" />
  	<result property="roadNameAddress" column="r_roadNameAddress" />
  	<result property="name" column="r_name" />
  	<result property="status" column="r_status" />
  	<result property="tel" column="r_tel" />
  	<result property="food" column="r_food" />
      </association>
  </resultMap>

  <select id="getReceiptWithRestaurant" parameterType="String" resultMap="MZRegisterReceiptDTOMap">
      SELECT 
  	    r.no as r_no, r.landNumAddress as r_landNumAddress, 
  	    r.roadNameAddress as r_roadNameAddress, r.name as r_name, 
  	    r.status as r_status, r.tel as r_tel, r.food as r_food,
  	    m.no as m_no, m.userId as m_userId, m.storeAddress as m_storeAddress,
  	    m.storePhoneNumber as m_storePhoneNumber, m.buyTime as m_buyTime
  	FROM 
  	    mzRegisterInfo m 
  	JOIN 
  	    restaurant r ON m.storePhoneNumber = r.tel 
  	LEFT JOIN
  	    cs_review cr ON m.no = cr.receipt_id
  	WHERE 
  	    m.userID = #{user_id} 
  	    AND cr.receipt_id IS NULL;
  </select>
  • โ€ผํ•ด์„โ€ผ MZRegisterInfoVO์™€ RestaurantVO์˜ ๊ฐ ํ•„๋“œ์™€ SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์˜ ์—ด์„ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด resultMap์„ ์‚ฌ์šฉํ•œ ๊ฒƒ์€ ๋™์ผํ•จ. ์˜์ˆ˜์ฆ๋ณ„ 1๊ฐœ์˜ ๋ฆฌ๋ทฐ๋งŒ ์ž‘์„ฑ ํ•˜๊ธฐ ์œ„ํ•ด (์ค‘๋ณต๋ฆฌ๋ทฐ, ๋„๋ฐฐ๋ฆฌ๋ทฐ ๋ฐฉ์ง€) ์‚ฌ์šฉํ–ˆ๋˜ cs_review ํ…Œ์ด๋ธ”์„ IN ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜จ ๊ฒƒ์„ LEFT JOIN ํ•˜์—ฌ, m.no์™€ cr.receipt_id๊ฐ€ ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์„ ์ฐพ๋Š” ์ฟผ๋ฆฌ์ž„. ๊ทธ๋Ÿฐ ๋‹ค์Œ cr.receipt_id๊ฐ€ NULL์ธ ํ•ญ๋ชฉ, ์ฆ‰ cs_review ํ…Œ์ด๋ธ”์— ํ•ด๋‹น ์˜์ˆ˜์ฆ์ด ์—†๋Š” ํ•ญ๋ชฉ๋งŒ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๋ก ์€ ์ด์ „ ์ฟผ๋ฆฌ๋ž‘ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ธฐ๋Šฅ์€ ๋˜‘๊ฐ™๊ณ , ๋Œ€๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์ข€ ๋” ํšจ์œจ์ ์ธ ์„ฑ๋Šฅ์„ ๋ฐœํœ˜์‹œํ‚ค๊ธฐ ์œ„ํ•ด IN ์„œ๋ธŒ์ฟผ๋ฆฌ ์‚ฌ์šฉ ๋ถ€๋ถ„์„ JOIN์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณ€๊ฒฝํ•จ.

  • โ€ผ๊ฒฐ๋ก โ€ผ ๋ณดํ†ต์€ resultType ์„ ์ด์šฉํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋ชจ๋ธ๊ณผ ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‘๊ฐœ ์ด์ƒ ๋ชจ๋ธ์ด๋‚˜ ๋‹ค์†Œ ๋ณต์žกํ•œ DTO์™€ ๋งคํ•‘์„ ์ง„ํ–‰ํ•  ๋•Œ๋Š” resultMap์œผ๋กœ ์„ธ๋ฐ€ํ•œ ์ปจํŠธ๋กค์„ ํ•˜์ž! ๋ผ๋Š” ๊ฒƒ์„ ํ•™์Šต.

About

๐Ÿ”ฅ ๋ฉ€ํ‹ฐ์บ ํผ์Šค ๋ฐฑ์—”๋“œ ์ทจ์—…์บ ํ”„ ์ตœ์ข… ํ”„๋กœ์ ํŠธ (๊ฐœ์ธํŒŒํŠธ)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages