TID


Project(SEMOGONG) ๊ฐœ๋ฐœ ์ผ์ง€

  • Issue ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐœ๋ฐœ ์ง„ํ–‰.
  • Issue Labels
    • Bug : ๊ตฌํ˜„ํ•œ ๊ธฐ๋Šฅ๋“ค ์ค‘์—์„œ ์„œ๋ฒ„์— ์˜ฌ๋ ธ๋Š”๋ฐ ์ž‘๋™ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊น€
    • Back : Back-End Engineer ๋งŒ์„ ์œ„ํ•œ ์ด์Šˆ
    • Front : Front-End Engineer ๋งŒ์„ ์œ„ํ•œ ์ด์Šˆ
    • Enhancement : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, front back ๋ชจ๋‘๊ฐ€ ์†๋ด์•ผํ•  ์ด์Šˆ

<220818>

#99 Bug : 0-4 ์‹œ ์‹œ์ž‘ ์‹œ ์‹œ์ž‘์‹œ๊ฐ„ ์˜ค๋ฅ˜

  • #99
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • 0-4์‹œ ๊ณต๋ถ€ ์‹œ์ž‘ ์‹œ, ๋กœ์ง์— ๋”ฐ๋ผ ๋‚ ์งœ๋Š” ์ „๋‚ ๋กœ ์„ค์ •๋˜๋Š”๋ฐ, ๊ทธ๋•Œ ๊ณต๋ถ€ ์‹œ์ž‘ ์‹œ๊ฐ„ ๋งˆ์ € createTime์œผ๋กœ ์„ค์ •๋˜๋Š” ์˜ค๋ฅ˜
      • Post Entity ์ƒ์„ฑ ๋ฉ”์„œ๋“œ createPost ์˜ ์‹œ๊ฐ„ List์— ์‹œ๊ฐ„์„ ์ถ”๊ฐ€ํ•˜๋Š” times.add ๊ฐ€ createTime ์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์–ด ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜
    • ํ•ด๊ฒฐ
      • createPost์˜ times.add ๋ฅผ ํ˜„์žฌ ์‹œ๊ฐ„(LocalDateTime.now())์œผ๋กœ ์„ค์ •

          public static Post createPost(Member member, LocalDateTime createTime){
              Post post = new Post();
              post.setMember(member);
              post.createTime = createTime;
              DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm");
              post.times.add(LocalDateTime.now().format(timeFormatter));
              post.state = StudyState.STUDYING;
              return post;
          }
        

<220815>

#96 Back : ๊ณต๋ถ€ ์‹œ์ž‘ ์‹œ๊ฐ„์ด 0~4์‹œ ์‚ฌ์ด์ผ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ [์‹œ๊ฐ„ ์ฒ˜๋ฆฌ]

  • #96
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ 0~4์‹œ ์‚ฌ์ด์— ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น post๋Š” ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ํŠน์„ฑ ์ƒ ํ•ด๋‹น ๋‚ ์งœ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋จ. (LocalDateTime.now() ์ด์šฉ)
      • ํ•˜์ง€๋งŒ, ์„œ๋น„์Šค ํŠน์„ฑ ์ƒ 0~4์‹œ ์‚ฌ์ด์˜ ์‹œ๊ฐ„์€ ์ด์ „ ๋‚ ์งœ๋กœ ์ธ์‹๋˜๊ฒŒ ํ•ด์•ผ๋จ. (๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ํ•ด๋‹น ๋‚ ์งœ์˜ Post๊ฐ€ 2๊ฐœ๊ฐ€ ๋˜๋Š” ์˜ˆ์™ธ ๋ฐœ์ƒ)
      • ex) 13์ผ์ด ๋„˜์–ด๊ฐ€๋Š” 1์‹œ์— ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ–ˆ๋‹ค๋ฉด 14์ผ๋กœ ์ธ์‹ โ†’ 13์ผ๋กœ ์ธ์‹๋˜๊ฒŒ ์„ค์ • ํ•„์š”
    • ๊ตฌํ˜„
      • 0 - 4 ์‹œ ์‚ฌ์ด์— ๊ธ€์„ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ, ์ „ ๋‚ ์˜ 23:59 ์— ๊ธ€์„ ์ž‘์„ฑํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•˜๊ฒŒ ์ทจ๊ธ‰ํ•˜์—ฌ ๊ตฌํ˜„ โ†’ ๊ธฐ์กด์˜ ๋กœ์ง์— ๋ฐฉํ•ด๋˜์ง€ ์•Š์œผ๋ฉด์„œ ํ˜„์žฌ ํ•„์š”ํ•œ ์š”๊ตฌ์‚ฌํ•ญ ์ถฉ์กฑ ๊ฐ€๋Šฅ
      • ์ฆ‰, post์˜ times์—๋Š” ํ˜„์žฌ์‹œ๊ฐ„์„ ๋„ฃ์–ด์ฃผ๊ณ , post์˜ createTime์€ ๊ทธ์ „๋‚ ์˜ 23:59 ๋กœ ์„ค์ •

          if (createDate.getHour() < 4) { // 0 - 4 ์‹œ ์‚ฌ์ด์— ๊ธ€์„ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ, ์ „ ๋‚ ์˜ 23:59 ์— ๊ธ€์„ ์ž‘์„ฑํ•œ ๊ฒƒ๊ณผ ๋™์ผํ•˜๊ฒŒ ์ทจ๊ธ‰.
              LocalDateTime toChange = createDate.minusDays(1); // ์ „๋‚ ๋กœ ์„ค์ •
              createDate = LocalDateTime.of(toChange.getYear(), toChange.getMonthValue(), toChange.getDayOfMonth(), 23, 59, 59); // ์ „๋‚  23์‹œ59๋ถ„์œผ๋กœ ์„ค์ •
          }
          Long postId = postService.save(loginMember.getId(), createDate); // ์ €์žฅํ•  ๋•Œ๋Š” ํ•ด๋‹น ๊ธ€์˜ ์ž‘์„ฑ์ž Member ์—ฐ๊ฒฐ, creatTime๋งŒ ์„ค์ •ํ•ด์คŒ
        

<220814>

#95 Back : ๋žญํฌ ์ธก์ • ๊ธฐ๋ฒ• ๋ณ€๊ฒฝ

  • #95
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ํ˜„์žฌ ๋žญํฌ ์ธก์ • ๊ธฐ์ค€์€ [์–ด์ œ ๊ณต๋ถ€ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋Ÿ‰ + ์ผ์ฃผ์ผ ์ด ๊ณต๋ถ€์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ์ผ์ฃผ์ผ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋Ÿ‰ + ํ•œ๋‹ฌ ์ถœ์„๋ฅ ]
      • ํ•˜์ง€๋งŒ, โ€˜์–ด์ œ ๊ณต๋ถ€ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋Ÿ‰โ€™ ์€ ๋ณ€๋™๋Ÿ‰์ด ๋„ˆ๋ฌด ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์–ด์ œ ํ•˜๋ฃจ์˜ ๊ณต๋ถ€๋Ÿ‰์ด ๋žญํฌ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นจ. โ†’ ๋žญํฌ ๋ณ€๋™๋ฅ ์ด ์ปค์ง
      • ๊ณ ๋กœ ๋ณ€๋™๋ฅ ์„ ์ค„์ผ ํ•„์š”๊ฐ€ ์กด์žฌ
    • ๊ตฌํ˜„
      • โ€˜์–ด์ œ ๊ณต๋ถ€ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋Ÿ‰โ€™ โ†’ โ€˜์ผ์ฃผ์ผ ๊ธฐ์ค€ ํ•˜๋ฃจ ํ‰๊ท  ๊ณต๋ถ€์‹œ๊ฐ„์œผ๋กœ ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋Ÿ‰โ€™ ์œผ๋กœ ๋ณ€๊ฒฝ (ํ•ด๋‹น ์‚ฌํ•ญ์€ ์ถ”ํ›„ ๋ณ€๋™ ๊ฐ€๋Šฅ)

          Times weekAvgTimes = new Times();
          int weekAvgTime = weekAllTimes / 7;
          int dayGoalTimes = member.getGoal().getDayGoalTimes();
          allStatic.setGoalAttainmentToday(Math.round(((float) weekAvgTime / (float) dayGoalTimes) * 100));
        

<220812>

#93 Bug : ๋žญํ‚น ํŽ˜์ด์ง€ ๋ฐ My Page Times ๊ณ„์‚ฐ ์˜ค๋ฅ˜

  • #93
    • ๋ฐœ์ƒ ์˜ค๋ฅ˜
      • Ranking Page ์ด๋“  My Page ์ด๋“  ๊ณต๋ถ€ ์‹œ๊ฐ„ ๊ณ„์‚ฐ ์‹œ ์‹œ๊ฐ„์ด ๋งˆ๋ฌด๋ฆฌ๋˜์ง€ ์•Š์€ Post์— ๋Œ€ํ•ด์„  Times๊ฐ€ Null ๋ฐ˜ํ™˜ โ†’ NullPointerException ๋ฐœ์ƒ
      • Post์˜ times size ๊ฐ€ ํ™€์ˆ˜ ์ผ๊ฒฝ์šฐ ๊ทธ๋ƒฅ null์ด ๋ฐ˜ํ™˜๋˜๋„๋ก ์„ค์ •๋˜์–ด ์žˆ์—ˆ์Œ โ†’ ์ฒ˜๋ฆฌ ํ•„์š”
    • ํ•ด๊ฒฐ
      • times size ๊ฐ€ ์ง์ˆ˜๋ผ๋ฉด ๊ณ„์‚ฐ์„ ๋Œ๋ฆฌ๊ณ 
      • ํ™€์ˆ˜ (๋งˆ๋ฌด๋ฆฌ๋˜์ง€ ์•Š์€ ์‹œ๊ฐ„) ์— ๋Œ€ํ•ด์„œ๋Š” null ์ด ์•„๋‹Œ 0์„ ๋ฐ˜ํ™˜ํ•˜์—ฌ NullPointerException ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

          private Times getTimes(List<String> times) {
              Times resultTime;
              if (times.size() % 2 == 0) { // ์ง์ˆ˜
          					int total1 = 0;
          					...
                  }
                  resultTime = new Times(total1);
              } else { // ํ™€์ˆ˜ -> ๋งˆ๋ฌด๋ฆฌ๋˜์ง€ ์•Š์€ post
                  resultTime = new Times(0);
              }
              return resultTime;
          }
        

<220811>

#88 Bug : My Page ์—์„œ์˜ post edit ์˜ค๋ฅ˜
#89 Bug : My Page, Member Detail ์—์„œ์˜ ์ถœ์„๋ฅ  ๊ณ„์‚ฐ ์˜ค๋ฅ˜

  • #88
    • ๋ฐœ์ƒ ์˜ค๋ฅ˜
      • My Page ์—์„œ ๊ธ€ ์ˆ˜์ • submit์ด ์•ˆ๋˜๋Š” ์˜ค๋ฅ˜
      • focusedPostId ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์–ด์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜
      • ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด์ „์— home์—์„œ์˜ post edit ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์™€ ๋™์ผํ•œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
      • ์›์ธ : focusedPostId ๋ณ€์ˆ˜์ด๋ฆ„ ๋ณ€๊ฒฝ์œผ๋กœ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜ + ์ค‘๋ณต๋˜๋Š” id๋กœ ์ธํ•œ ์˜ค๋ฅ˜ โ†’ ์ „์ฒด์ ์ธ post edit์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜์ง€ ์•Š์Œ
    • ํ•ด๊ฒฐ
      • Home์—์„œ์˜ ์˜ค๋ฅ˜ํ•ด๊ฒฐ๊ณผ ๋™์ผํ•˜๊ฒŒ My Page์˜ ๋ Œ๋”๋ง๋˜๋Š” html์— ๊ฐ ๋ชจ๋“  post์— ์—ฐ๊ฒฐ๋˜๋Š” simplemde + {post.id} ๋ณ€์ˆ˜ ์ƒ์„ฑ ํ›„ ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋Š” Simple MDE ํ• ๋‹น
      • focusedPostId ๋ณ€์ˆ˜ ์ด๋ฆ„ ์ˆ˜์ •
    • ์ถ”ํ›„ ํ•„์š” ์ˆ˜์ • ์‚ฌํ•ญ
      • [์ค‘์š”] focusedPostId๋Š” ํ•ด๋‹น ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์—์„œ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Œ โ†’ main.js ๊ฐ€ ์•„๋‹Œ ์ƒˆ๋กœ์šด javascript๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ถ„๋ฆฌํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ.
  • #89
    • ๋ฐœ์ƒ ์˜ค๋ฅ˜
      • ํ•œ๋‹ฌ ๊ณต๋ถ€ ํ†ต๊ณ„์—์„œ ์ถœ์„๋ฅ , ์ „์ฒด ๊ณต๋ถ€์‹œ๊ฐ„, ํ‰๊ท  ๊ณต๋ถ€์‹œ๊ฐ„ ๋“ฑ์ด ์ˆ˜์ •ํ•œ ๋ถ€๋ถ„๊ณผ ๋‹ค๋ฅด๊ฒŒ โ€˜์˜ค๋Š˜โ€™๊นŒ์ง€ ๊ณ ๋ ค๊ฐ€ ๋จ. ( โ†’ ์›๋ž˜๋Š” โ€˜์–ด์ œโ€™ ๊นŒ์ง€๋งŒ ๊ณ ๋ ค๊ฐ€ ๋˜์–ด ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•จ)
      • ๊ณ„์‚ฐ ๋ถ€๋ถ„์— ์žˆ์–ด์„œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ โ†’ ๊ณ„์‚ฐ ํ•ด๋†“๊ณ  ๋‹ค๋ฅธ ๋ณ€์ˆ˜๋กœ ์ ์šฉํ•˜๊ณ  ์žˆ์—ˆ์Œ
    • ํ•ด๊ฒฐ
      • ๊ณต๋ถ€ ๋žญํ‚น์„ ์œ„ํ•ด์„œ ํ˜„์žฌ ๋‹ฌ์˜ ์ถœ์„๋ฅ ์„ ๊ตฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ focusedDay, nowMonthDayLen ์„ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ํ˜„์žฌ ๋ณด๊ณ  ์žˆ๋Š” ๋‹ฌ๋ ฅ์˜ ํ†ต๊ณ„๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด monthDate, mothPosts ๋ฅผ ์‚ฌ์šฉํ–ˆ์Œ. ์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ ํ˜„์žฌ ๋ณด๋Š” ๋‹ฌ๋ ฅ์ด ์˜ค๋Š˜ ๋‚ ์งœ์˜ ๋‹ฌ๊ณผ ๋™์ผํ•˜๋‹ค๋ฉด monthDate์— focusedDay ๋ฅผ ๋Œ€์ž… ํ•˜๊ณ  monthPosts์— ์–ด์ œ๋‚ ์งœ๊นŒ์ง€์˜ post๋ฅผ ๋„ฃ์–ด์ฃผ์–ด ํ•ด๊ฒฐ
      • ์ฆ‰, ๋ณด๊ณ  ์žˆ๋Š” ๋‹ฌ๋ ฅ์˜ ํ†ต๊ณ„๋ฅผ ์ƒํ™ฉ์— ๋”ฐ๋ผ ํ˜„์žฌ ๋‹ฌ์— ๋งž๊ฒŒ ์„ค์ •ํ•ด์ฃผ๋ฉฐ ํ•ด๊ฒฐ
        List<Post> nowMonthPosts = postService.getMonthPosts(memberId, LocalDateTime.now().getMonthValue());
        int focusedDay;
        if (LocalDateTime.now().getHour() < 4) {
            focusedDay = LocalDateTime.now().getDayOfMonth() - 2;
        } else {
            focusedDay = LocalDateTime.now().getDayOfMonth() - 1;
        }
        List<Post> calculatedNowMonthPosts = new ArrayList<>();
        for (Post post : nowMonthPosts) {
            if (post.getCreateTime().getDayOfMonth() > focusedDay) {
                break;
            }
            calculatedNowMonthPosts.add(post);
        }
              
        ForCalender CalenderInfo = getCalenderInfo(weekDay, focusedDate);
        int monthDate = dayData[month - 1];
        if (month == LocalDateTime.now().getMonthValue()) {
            monthDate = focusedDay;
            monthPosts = new ArrayList<>(calculatedNowMonthPosts);
        }
        AllStatic allStatic = getAllStatus(oriMember, staticsData, days.get(days.size() - 1), monthPosts, monthDate, focusedDay, calculatedNowMonthPosts.size());
      
      • ๋จผ์ € focosedDay๋ฅผ ๊ตฌํ•ด๊ณ  ํ•ด๋‹น ๋ณ€์ˆ˜์— ๋งž๋Š” ํ˜„์žฌ ๋‹ฌ์˜ posts๋ฅผ ๊ฐ€์ ธ์˜ด
      • ๊ทธ ํ›„ ๋งŒ์•ฝ ์‚ฌ์šฉ์ž๊ฐ€ ํ™•์ธํ•˜๊ณ  ์žˆ๋Š” ๋‹ฌ๋ ฅ์ด ํ˜„์žฌ ๋‹ฌ๊ณผ ๋™์ผํ•˜๋‹ค๋ฉด ํ•ด๋‹น ๋ณ€์ˆ˜๋“ค์„ ํ˜„์žฌ ๋‹ฌ์— ์‚ฌ์šฉ๋˜๋Š” ๋ณ€์ˆ˜๋กœ ๋ณ€๊ฒฝ. (์•„๋‹ˆ๋ผ๋ฉด ๊ธฐ์กด์˜ ๋ณ€์ˆ˜ ์‚ฌ์šฉ)

<220809>

#90 Bug : ์ƒˆ ๊ธ€ ์ž‘์„ฑ ์˜ค๋ฅ˜

  • #90
    • ๋ฐœ์ƒ ์˜ค๋ฅ˜
      • ์ƒˆ ๊ธ€ ์ž‘์„ฑ ์‹œ simpleMDE ๊ฐ€ content์— ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ
      • submit ์‹œ ์ œ์ถœ๋˜์ง€ ์•Š์Œ
      • ์›์ธ : post edit ๊ณผ fragment๋ฅผ ๊ณต์œ ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด์ „์— post edit ์˜ค๋ฅ˜ ์ˆ˜์ • ์‹œ id ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ถ€๋ถ„์ด ์žˆ์—ˆ๋Š”๋ฐ, ๊ทธ ๋ถ€๋ถ„์„ post new(์ƒˆ ๊ธ€ ์ž‘์„ฑ)์˜ javascript ์ฝ”๋“œ์— ๋ฐ˜์˜ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒ
    • ํ•ด๊ฒฐ
      • ๊ธฐ์กด์˜ content ๋ผ๋Š” id๋ฅผ ๊ฐ€์กŒ๋˜ ์š”์†Œ์— content + ${post.id} ์˜ id๋ฅผ ์ƒˆ๋กœ ๋ถ€์—ฌ โ†’ ์ด์ œ ํ•ด๋‹น id๋กœ Simple MDE ๋ฅผ ์‹ฌ์–ด์ค„ ์ˆ˜ ์žˆ์Œ
      • simplemde + ${post.id} ์˜ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด์ฃผ๊ณ  ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ƒˆ๋กœ ์ƒ์„ฑ๋œ Simple MDE ๋ฅผ ํ• ๋‹น โ†’ ํ•ด๋‹น MDE์˜ value(content) ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋จ

<220808>

#87 Bug : ๋‹ค์ค‘ post edit ์‹œ ์—ฌ๋Ÿฌ ์˜ค๋ฅ˜ ๋ฐœ์ƒ

  • #87
    • ๊ธฐ์กด ๋ฌธ์ œ์ 
      1. ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— edit๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ post์˜ content๋กœ ๋ชจ๋“  post์˜ ๋‚ด์šฉ์ด ๋ณ€๊ฒฝ๋จ (simpleMDE๋ฅผ ์ „์—ญ๋ณ€์ˆ˜๋กœ ๊ณต์œ ํ•˜๋ฉฐ ์‚ฌ์šฉํ•ด์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ)
      2. simpleMDE๊ฐ€ ๋‹ค๋ฅธ post์˜ content์— ์ƒ์„ฑ๋จ (postEditForm์˜ content๊ฐ€ unique id๊ฐ€ ์•„๋‹ˆ๋ฉด์„œ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ. โ†’ editํ•˜๋ฉด ์—ฌ๋Ÿฌ๊ฐœ์˜ content๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ์ค‘๋ณต๋œ ID๋กœ ์ธํ•ด์„œ ๊ฐ€์žฅ ์ฒ˜์Œ ์ƒ์„ฑ๋œ content์— simpleMDE๊ฐ€ ๋ฐœ์ƒ)
      3. submit ํ•˜๋ฉด ์ด์ „์— ์—ด์—ˆ๋˜ post์— fragment๊ฐ€ replacement๋˜๊ณ  ํ˜„์žฌ post๋Š” replacement๋˜์ง€ ์•Š์Œ (postEditForm์˜ postEdit_container์˜ id๊ฐ€ uniqueํ•˜์ง€ ์•Š์•„ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ, 2๋ฒˆ๊ณผ ๋™์ผํ•œ ์ด์œ ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ)
    • ํ•ด๊ฒฐ
      1. simpleMDE ๋ณ€์ˆ˜ ํ•˜๋‚˜๋ฅผ ์ „์—ญ๋ณ€์ˆ˜๋กœ ๊ณต์œ ํ•˜๋ฉฐ ์‚ฌ์šฉํ•ด์„œ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ
        • simpleMDE๋ฅผ ๊ฐ post์˜ ID๋กœ ์ƒ์„ฑํ•œ ํ›„ (์ „์—ญ๋ณ€์ˆ˜๋กœ ์„ ์–ธ โ†’ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ๋„ ์‚ฌ์šฉํ•ด์•ผ ๋˜๊ธฐ ๋•Œ๋ฌธ)
        • edit ์‹œ ํ•ด๋‹น post์˜ ID ๊ฐ’์„ ๊ฐ€์ง€๋Š” simpleMDE๋ฅผ ๊ฐ€์ ธ์™€ ํ•ด๋‹น ๋ณ€์ˆ˜์— ์ƒˆ๋กœ์šด simpleMDE๋ฅผ ์ƒ์„ฑํ•ด์คŒ. โ†’ unique ID๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ post์˜ simpleMDE์˜ ๊ฐ’์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ์ €์žฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ
        • ๊ตฌํ˜„ ์ฝ”๋“œ

            // home.html์˜ script ๋ถ€๋ถ„ (๋ณ€๊ฒฝ ์ „: var simplemde;)
            [# th:each="post, stat : ${postDtos}"]
            var simplemde[[${post.id}]];
            [/]
          
          • home.html์˜ simplemde๋ฅผ ๊ฐ post์— mapping ๋  ์ˆ˜ ์žˆ๋„๋ก id์— ๋งž๊ฒŒ simplemde๋ฅผ ์ƒ์„ฑ
          • thymeleaf์˜ javascirpt์—์„œ์˜ ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ ๋™์  ๋ณ€์ˆ˜ ์ƒ์„ฑ
            function edit_post(id) {
                $.ajax({
                    url: '/posts/edit/' + id,
                    type: "GET",
                })
                    .done(function (fragment) {
                        $('#postModal_content' + id).replaceWith(fragment);
            						/* (๋ณ€๊ฒฝ ์ „) => simplemde = new SimpleMDE({element: document.getElementById("content"+id.toString()),spellChecker: false});*/
                        eval("simplemde" + id + "= new SimpleMDE({element: document.getElementById("content"+id.toString()),spellChecker: false})");
                        ...
                    });
            }
          
          • edit ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋™์ ์œผ๋กœ ํ•ด๋‹น post์— mapping ๋˜๋Š” simplemde๋ฅผ ์žฌ์ •์˜ โ†’ ํ•ด๋‹น post์— simpleMDE๋ฅผ content์— ์‹ฌ์–ด์ฃผ๋Š” ๊ฒƒ
          • ์ด๋•Œ id์— ๋งž๋Š” ๋™์  ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด ์ „์—ญ ๋ณ€์ˆ˜์ธ simpleMDE๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•˜๊ธฐ ๋–„๋ฌธ์— eval() ํ•จ์ˆ˜ ์‚ฌ์šฉ
      2. postEditForm์˜ content๊ฐ€ unique id๊ฐ€ ์•„๋‹ˆ๋ฉด์„œ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ. โ†’ editํ•˜๋ฉด ์—ฌ๋Ÿฌ๊ฐœ์˜ content๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ์ค‘๋ณต๋œ ID๋กœ ์ธํ•ด์„œ ๊ฐ€์žฅ ์ฒ˜์Œ ์ƒ์„ฑ๋œ content์— simpleMDE๊ฐ€ ๋ฐœ์ƒ
        • postEditForm์— content id์†์„ฑ์„ post์˜ ID๋ฅผ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด uniqueํ•œ id๊ฐ€ ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •.

            <textarea type="text" rows="4" 
            					th:field="*{content}" th:id="'content'+${postForm.id}" 
            					placeholder="Content" class="form-control"
                      autocomplete="off"></textarea>
          
        • ์ถ”๊ฐ€๋กœ ๊ทธ์— ๋งž๊ฒŒ simpleMDE๋ฅผ ์‹ฌ์–ด์ค„ ๋•Œ๋„ content+post.id ๋กœ ์ฐพ์•„์˜ค๊ณ  ์‹ฌ์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • โ†’ unique id์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฒน์น ์ผ๋„ ์—†์œผ๋ฉฐ, ์ œ๋Œ€๋กœ๋œ ์œ„์น˜์— ์ƒ์„ฑ ๊ฐ€๋Šฅ

          new SimpleMDE({element: document.getElementById(\"content\"+id.toString()),spellChecker: false})

      3. submit ํ•˜๋ฉด ์ด์ „์— ์—ด์—ˆ๋˜ post์— fragment๊ฐ€ replacement๋˜๊ณ  ํ˜„์žฌ post๋Š” replacement๋˜์ง€ ์•Š์Œ (postEditForm์˜ postEdit_container์˜ id๊ฐ€ uniqueํ•˜์ง€ ์•Š์•„ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ, 2๋ฒˆ๊ณผ ๋™์ผํ•œ ์ด์œ ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ)
        • eidt ์š”์ฒญ ์‹œ postEditForm์˜ postEdit_container๋ฅผ ์ฐพ์•„์™€ ๊ต์ฒดํ•ด ์ค€ ํ›„
        • ํ•ด๋‹น postEdit_container id๊ฐ’์„ postEdit_container + post.id ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • โ†’ ๋ฏธ๋ฆฌ id๊ฐ’์œผ๋กœ ๋ Œ๋”๋ง ํ›„ ์ฐพ์œผ๋ฉด ์ฐพ์•„์™€์ง€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ€์ ธ์˜จ ํ›„ id ๊ฐ’์„ ๋ณ€๊ฒฝ
        • ์ฝ”๋“œ

            function edit_post(id) {
                $.ajax({
                    url: '/posts/edit/' + id,
                    type: "GET",
                })
                    .done(function (fragment) {
                        $('#postModal_content' + id).replaceWith(fragment);
                        ...
                        document.getElementById("postEdit_container").setAttribute("id", "postEdit_container" + id.toString());
                        document.getElementById("postEdit_container"+id.toString()).scrollIntoView();
                    });
            }
          
        • ๋งˆ์ง€๋ง‰์œผ๋กœ post ์‹œ postEdit_container + post.id ๋กœ ๊ฒฐ๊ณผ fragment๋กœ replace. โ†’ unique ID๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ œ๋Œ€๋กœ๋œ ์œ„์น˜๋กœ replace ๋จ

<220807>

#83 Bug : ์‹œ๊ฐ„ ๋ณ€๊ฒฝ ์˜ค๋ฅ˜

  • #83
    • ๊ธฐ์กด ๋ฌธ์ œ์ 
      • ์˜ค๋Š˜์ด ์•„๋‹Œ ์ด์ „ post์—์„œ ์‹œ๊ฐ„ ์ˆ˜์ • ์‹œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
      • ์˜ค๋Š˜ ์ž‘์„ฑ ์ค‘์ธ Post๊ฐ€ ์•„๋‹Œ๋ฐ, โ€˜ํ˜„์žฌ์‹œ๊ฐ„์„ ๋„˜๋Š” ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ–ˆ๋‹คโ€™ ๋Š” validation ์ž‘๋™
      • ๋˜ํ•œ 00์‹œ, 01์‹œ ๋“ฑ 0~4์‹œ์— ๋Œ€ํ•œ ์‹œ๊ฐ„๊ณ„์‚ฐ ์˜ค๋ฅ˜ โ†’ 23์‹œ๋ณด๋‹ค 00์‹œ, 01์‹œ๊ฐ€ ๋” ํฐ ๊ฐ’์ธ๋ฐ, ๋‹จ์ˆœํ•˜๊ฒŒ 23>0 ์ด๋ฏ€๋กœ 0~4์‹œ๊ฐ€ ๋” ์ž‘์€ ์‹œ๊ฐ„์œผ๋กœ ํŒ๋ณ„๋˜๋Š” ์˜ค๋ฅ˜
    • ํ•ด๊ฒฐ
      • 0~4 ์‹œ์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ ์ธ ์ฒ˜๋ฆฌ
        • ํ•˜๋ฃจ ์‹œ๊ฐ„์˜ ๊ธฐ์ค€์„ 4์‹œ๋กœ ์žก์žˆ๊ธฐ ๋•Œ๋ฌธ์— 0~4์‹œ์— ๋Œ€ํ•ด์„  24๋ฅผ ๋” ์ถ”๊ฐ€ํ•ด์ฃผ์–ด์•ผ ํ•จ
        • if (hour < 4) {hour+=24} ์ถ”๊ฐ€ํ•˜์—ฌ ์ „์ฒด์ ์ธ ์‹œ๊ฐ„ ๊ณ„์‚ฐ์ด ์ •์ƒ์ ์œผ๋กœ ์ด๋ฃจ์–ด์งˆ ์ˆ˜ ์žˆ๋„๋ก ์ˆ˜์ •
      • ์˜ค๋Š˜ post์— ๋Œ€ํ•ด์„œ๋งŒ ์‹œ๊ฐ„ํ™•์ธ(1) ๊ฒ€์ฆ ์‹คํ–‰
        • ์ด์ „ post๋“ค์— ๋Œ€ํ•ด์„  ์‹œ๊ฐ„ํ™•์ธ(1-ํ˜„์žฌ์‹œ๊ฐ„๊ณผ ๋น„๊ต)์„ ์ง„ํ–‰ํ•ด์„  ์•ˆ๋จ
        • if (id == focusedPostId) {...} ๋ฅผ ํ†ตํ•ด ์˜ค๋Š˜ post์— ๋Œ€ํ•ด์„œ๋งŒ ํ•ด๋‹น ๊ฒ€์ฆ ์ง„ํ–‰

<220806>

#82 Enhancement : ์‹œ๊ฐ„์–‘์‹ check

  • #82
    • ๊ธฐ๋Šฅ์˜ ํ•„์š”์„ฑ
      • ํ˜„์žฌ ์‹œ๊ฐ„์„ ์ œ์ถœํ•  ๋•Œ, ์‹œ๊ฐ„์˜ ๊ฐœ์ˆ˜, ๋นˆ ์‹œ๊ฐ„์ธ์ง€ ์•„๋‹Œ์ง€ ๋“ฑ์˜ Validation๋งŒ ๊ฑฐ์น˜๊ณ  ์žˆ์Œ
      • ํ•˜์ง€๋งŒ, ์‹œ๊ฐ„ ๊ณ„์‚ฐ์„ ์œ„ํ•œ ์‹œ๊ฐ„์–‘์‹์—์„œ ๋ฒ—์–ด๋‚œ ์ž…๋ ฅ๊ฐ’์— ๋Œ€ํ•ด์„  ์ฒ˜๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š๊ณ  ์žˆ์Œ
      • ์‹œ๊ฐ„ ๊ณ„์‚ฐ์„ ์œ„ํ•ด์„  ์˜ฌ๋ฐ”๋ฅธ ์‹œ๊ฐ„์–‘์‹์œผ๋กœ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ ๋„ ํ•„์š”
    • ๊ตฌํ˜„
      1. ํ˜•์‹ ์ฒดํฌ
        • ์ง€์ • ํ˜•์‹ : (์‹œ๊ฐ„ํ˜•์‹: ex_ โ€˜17:20โ€™) var reg = /^\d{1,2}:\d{1,2}$/;
        • ์ •๊ทœํ‘œํ˜„์‹์„ ์ด์šฉํ•˜์—ฌ ํ˜•์‹ ํ™•์ธ, ํ˜•์‹์—์„œ ๋ฒ—์–ด๋‚  ๊ฒฝ์šฐ alert ๋ฐ class ๋ณ€๊ฒฝ
         if (!reg.test(times[idx].value)) {
             alert('์ž˜๋ชป๋œ ํ˜•์‹์˜ ์‹œ๊ฐ„์ด ์ž…๋ ฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.\n์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹: "์‹œ๊ฐ„:๋ถ„" ex) 17:20');
             var temp_times_id = "times" + idx;
             var timeHtml = document.getElementById(temp_times_id);
             timeHtml.setAttribute('class', 'form-control is-invalid');
             timeHtml.setAttribute('style', 'background-image: none; padding: 6px;');
             document.getElementById("postEdit_container").scrollIntoView();
             return;
         }
        
      2. ์‹œ๊ฐ„ ํ™•์ธ - 1
        • ์ž…๋ ฅ๋œ ์‹œ๊ฐ„ ๊ฐ’์ด ํ˜„์žฌ ์‹œ๊ฐ„๋ณด๋‹ค ํฐ์ง€ ํ™•์ธ
        • ํฌ๋ฉด ์˜ค๋ฅ˜, alert์„ ํ†ตํ•ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
         var curr = times[idx].value.split(':')
         var currTime = parseInt(curr[0])*60 + parseInt(curr[1])
         if (currTime > totalTimeToday) {
             alert("ํ˜„์žฌ์‹œ๊ฐ„์„ ์ดˆ๊ณผํ•œ ์‹œ๊ฐ„๊ฐ’์ด ์žˆ์Šต๋‹ˆ๋‹ค.");
             var curr_times_id = "times" + idx;
             var timeHtmlCurr = document.getElementById(curr_times_id);
             timeHtmlCurr.setAttribute('class', 'form-control is-invalid');
             timeHtmlCurr.setAttribute('style', 'background-image: none; padding: 6px;');
             document.getElementById("postEdit_container").scrollIntoView();
             return;
         }
        
      3. ์‹œ๊ฐ„ ํ™•์ธ -2
        • ์ด์ „ ์‹œ๊ฐ„๊ฐ’์ด ์ดํ›„ ์‹œ๊ฐ„๊ฐ’๋ณด๋‹ค ํฐ์ง€ ํ™•์ธ
        • ํฌ๋ฉด ์˜ค๋ฅ˜, alert์„ ํ†ตํ•ด ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
         if (idx !== 0){
             var before = times[idx-1].value.split(':');
             var beforeTime = parseInt(before[0])*60 + parseInt(before[1]);
             if (beforeTime > currTime) {
                 alert("์ดํ›„ ์‹œ๊ฐ„์ด ์ด์ „์‹œ๊ฐ„๋ณด๋‹ค ์ž‘์Šต๋‹ˆ๋‹ค. ์ˆ˜์ •ํ•ด์ฃผ์„ธ์š”!");
                 var timeAfter = "times" + idx;
                 var timeBefore = "times" + (idx-1);
                 var timeHtmlAfter = document.getElementById(timeAfter);
                 var timeHtmlBefore = document.getElementById(timeBefore);
                 timeHtmlAfter.setAttribute('class', 'form-control is-invalid');
                 timeHtmlAfter.setAttribute('style', 'background-image: none; padding: 6px;');
                 timeHtmlBefore.setAttribute('class', 'form-control is-invalid');
                 timeHtmlBefore.setAttribute('style', 'background-image: none; padding: 6px;');
                 document.getElementById("postEdit_container").scrollIntoView();
                 return;
             }
         }
        

<220804>

#80 Back : ๋žญํฌ ์ธก์ • ๊ธฐ์ค€ ๋ณ€๊ฒฝ
#81 Bug : post edit ์˜ค๋ฅ˜
#79 Bug : paging ์˜ค๋ฅ˜

  • #80
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ๋žญํฌ ์ธก์ • ๊ธฐ์ค€ ํ•ญ๋ชฉ๋“ค์˜ ๊ธฐ์ค€์ด ์ผ์น˜ํ•˜์ง€ ์•Š์•˜์Œ โ†’ ์ด๋ฒˆ๋‹ฌ ์ถœ์„๋ฅ (์˜ค๋Š˜๊นŒ์ง€ ํฌํ•จ), ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋ฅ (์–ด์ œ), ์ฃผ๊ฐ„ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋ฅ (์–ด์ œ๊นŒ์ง€)
      • ๋ณ€๊ฒฝ ํ•„์š” : ๋ชจ๋‘ ์–ด์ œ๊นŒ์ง€๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ธก์ •. -> ์ด๋ฒˆ๋‹ฌ ์ถœ์„๋ฅ ์„ ์˜ค๋Š˜์ด ์•„๋‹Œ ์–ด์ œ๊นŒ์ง€๋งŒ ํฌํ•จํ•˜๋„๋ก
    • ํ•ด๊ฒฐ
      • ์ด๋ฒˆ๋‹ฌ ์ถœ์„๋ฅ ์— ํฌํ•จ๋˜๋Š” ๋ฒ”์œ„๋ฅผ ์˜ค๋Š˜์—์„œ ์–ด์ œ๊นŒ์ง€๋งŒ ํฌํ•จ
      • DB ์ž์ฒด์˜ ์กฐํšŒ๋ฅผ ํ†ตํ•ด์„œ๋„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๋ฏธ ์˜ค๋Š˜๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ์—, ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„ ์ž์ฒด์—์„œ ํŒ๋‹จํ•˜๋„๋ก ์‹คํ–‰

          int focusedDay;
          int nowMonthPostsLen = 0;
          if (LocalDateTime.now().getHour() < 4) {
              focusedDay = LocalDateTime.now().getDayOfMonth() - 2;
          } else {
              focusedDay = LocalDateTime.now().getDayOfMonth() - 1;
          }
          for (Post post : nowMonthPosts) {
              if (post.getCreateTime().getDayOfMonth() > focusedDay) {
                  break;
              }
              nowMonthPostsLen = nowMonthPostsLen + 1;
          }
        
        • ์š”์ฒญ์‹œ๊ฐ„์— ๋”ฐ๋ผ ๋ฒ”์œ„๋ฅผ 1์—์„œ2๋กœ ์ค„์ž„ (์–ด์ œ๊นŒ์ง€์˜ ๋‚ ์งœ)
        • ๋˜ํ•œ ๋ฒ”์œ„์˜ ๋์ด ๋˜๋Š” focusedDay ์ดํ›„์˜ post๋Š” ํฌํ•จํ•˜์ง€ ์•Š์Œ
        • ์ด๋ ‡๊ฒŒ ํ•ด์„œ ๋ฒ”์œ„๋ฅผ ํ•ด๋‹น ๋‚ ์งœ(์–ด์ œ)๊นŒ์ง€๋กœ ์„ค์ •
  • #81
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • edit ์‹œ javascript(ajax)์—์„œ post ํ›„ ๋ฐ›์•„์˜ค๋Š” fragment๋กœ replace๋ฅผ ํ•˜์ง€ ๋ชปํ•˜๋Š” ์˜ค๋ฅ˜ ๋ฐœ์ƒ
      • fragment ์ค‘ postModal id part๋ฅผ ์ฐพ์•„์˜ค์ง€ ๋ชปํ•จ (id๋ฅผ th:id=โ€โ€™postModalโ€™+${post.id}โ€ ๋กœ ์„ค์ •ํ•˜์—ฌ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜)
    • ํ•ด๊ฒฐ
      • th:id=โ€โ€™postModalโ€™+${post.id}โ€ โ†’ id=โ€postModalโ€ ๋กœ๋ณ€๊ฒฝ
      • [์ค‘์š”] ๊ทธ ํ›„ replace๋ฅผ ํ†ตํ•ด ์š”์†Œ๋ฅผ ๋ฐ”๊ฟ”์ฃผ๊ณ  ํ•ด๋‹น ๋ถ€๋ถ„์˜ id๋ฅผ ์ƒˆ๋กœ โ€œpostModal+post.id" ๋กœ ๋ถ€์—ฌํ•จ
  • #79
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • page ๋ฒ„ํŠผ์ด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ (๋ˆ„๋ฅด๋ฉด ์•„๋ฌด post๋„ ๋œจ์ง€ ์•Š๋Š” ์˜ค๋ฅ˜ ๋ฐœ์ƒ)
      • page ๋ฒ„ํŠผ์ด ๊ฐ€์ง€๋Š” a ์š”์†Œ์˜ href์˜ requestParam ์ด๋ฆ„์ด ์ž˜๋ชป ์„ค์ •๋จ (content๊ฐ’)
    • ํ•ด๊ฒฐ
      • page์˜ queryParameter ์ˆ˜์ • (queryParam : content -> inputContent)
      • th:href="@{/ (page=${i}, focus=${nav2}, selected=${searchForm.selected}, **content**=${searchForm.inputContent})}" โ†’ th:href="@{/ (page=${i}, focus=${nav2}, selected=${searchForm.selected}, **inputContent**=${searchForm.inputContent})}"

<220803>

#29 Back : comment ์ˆ˜์ • ๊ธฐ๋Šฅ

  • #29
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • member ์ •๋ณด๋ฅผ ์ˆ˜์ •, post๋ฅผ ์ˆ˜์ • ํ•˜๋Š” ๋“ฑ ๊ธฐ์กด์˜ ๋ชจ๋“  Entity๋Š” ์ˆ˜์ •๊ธฐ๋Šฅ์ด ์žˆ์—ˆ์ง€๋งŒ, comment๋Š” ์ž‘์„ฑ ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ๋ฐ–์— ์—†์—ˆ์Œ
      • comment๋„ ์ž˜๋ชป์ž‘์„ฑํ•  ๊ฒฝ์šฐ ์ˆ˜์ • ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•ด์•ผ ๋จ. (์ด์ „์—๋Š” ์ˆ˜์ •์„ ์›ํ•œ๋‹ค๋ฉด ์‚ญ์ œ ํ›„ ๋‹ค์‹œ ์ž‘์„ฑ)
    • ๊ตฌํ˜„
      • Controller
        • ๋Œ“๊ธ€ ์ˆ˜์ • Form ์š”์ฒญ

            // ๋Œ“๊ธ€ ์ˆ˜์ • get
            @GetMapping("/comment/api/edit/{id}/{commentId}")
            public String editForm(@PathVariable("id") Long postId, @PathVariable("commentId") Long commentId, @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Long loginMemberId,Model model) {
                Post post = postService.findOne(postId);
                PostViewDto postViewDto = new PostViewDto(post);
                Comment comment = commentService.findOne(commentId);
                CommentViewDto commentDto = new CommentViewDto(comment);
                model.addAttribute("post", postViewDto);
                model.addAttribute("check", true);
                model.addAttribute("comment", commentDto);
                return "components/commentList :: #comment";
            }
          
          • ๊ธฐ์กด์˜ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ํ•ด๋‹น id๋ฅผ ๊ฐ€์ง„ comment๋ฅผ ๊ฐ€์ ธ์™€ model์— ๋„ฃ์–ด์คŒ
          • post์•ˆ์˜ comment๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น comment๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” post๋„ model์— ๋‹ด์•„์คŒ
        • ๋Œ“๊ธ€ ์ˆ˜์ •

            @PostMapping("/comment/api/edit/{id}/{commentId}")
            public String edit(@PathVariable("id") Long postId, @PathVariable("commentId") Long commentId, @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Long loginMemberId, Model model, @RequestParam Map<String, Object> paramMap) {
                Member member = memberService.findOne(loginMemberId);
                Post post = postService.findOne(postId);
                commentService.edit(commentId, paramMap.get("comment").toString());
                PostViewDto postViewDto = new PostViewDto(post);
                MemberDto memberDto = new MemberDto(member);
                          
                model.addAttribute("post", postViewDto);
                model.addAttribute("check", true);
                model.addAttribute("member", memberDto);
                return "components/commentList :: #commentPart";
            }
          
          • ๊ธฐ์กด์˜ ์ƒˆ๋กœ์šด ๋Œ“๊ธ€ ์ž‘์„ฑ๊ณผ ๋น„์Šทํ•œ ์›๋ฆฌ๋กœ ์ง„ํ–‰ (ํ•ด๋‹น post์˜ comment๋“ค์„ ์ƒˆ๋กœ ๋ถˆ๋Ÿฌ์™€ redering ํ›„ ํ•ด๋‹น commentPart๋ฅผ replaceํ•˜๋Š” ๊ฒƒ)
          • ํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์ ์€ save๊ฐ€ ์•„๋‹Œ edit
          • commentService.edit()

              public void edit(Long id, String content) {
                  Comment comment = em.find(Comment.class, id);
                  comment.editContent(content);
              }
            
            • ํ•ด๋‹น comment๋ฅผ ๊ฐ€์ ธ์™€ content์˜ ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•ด์คŒ (์ƒˆ๋กœ ์ €์žฅ) โ†’ editContent : this.content = content;
            • ์ค‘์š”ํ•œ ์ ์€ ์ด๋ ‡๊ฒŒ ์ˆ˜์ • ํ›„ ์ƒˆ๋กœ post์— ์—ฐ๊ฒฐํ•  ํ•„์š”๊ฐ€ ์—†์Œ. ์ด๋ฏธ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ธฐ์—.

<220802>

#3 Back : post ๊ฒ€์ƒ‰ (ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด -> ์กฐ๊ฑด[์ œ๋ชฉ,์ด๋ฆ„,ํฌ๋ง์ง๋ฌด,๋‚ด์šฉ])
#76 Back : member ๊ฒ€์ƒ‰ (ํ•„ํ„ฐ๋ฅผ ํ†ตํ•ด -> ์กฐ๊ฑด[์ด๋ฆ„, ํฌ๋ง์ง๋ฌด])
#8 Enhancement : error page ์ƒ์„ฑ (error.html, error/4xx.html, error/5xx.html)
#77 Bug : edit ์‹œ search bar์— simpleMDE๊ฐ€ ์ƒ๊ธฐ๋Š” ์˜ค๋ฅ˜

  • #3, #76
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ํ˜„์žฌ๊นŒ์ง€๋Š” ๊ทธ๋ƒฅ ํ•ด๋‹น ๋ฉ”๋‰ด(์ „์ฒด๊ธ€, ๋‚˜์˜๊ธ€, ์˜ค๋Š˜์˜๊ธ€ ๋“ฑ)์— ๋งž๋Š” ๋ชจ๋“  ๊ธ€๋“ค์„ ๋ณด์—ฌ์คŒ
      • ํ•˜์ง€๋งŒ, ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ์›ํ•˜๋Š” ๊ธ€์„ ํ•„ํ„ฐ๋งํ•˜์—ฌ ๋ณด๋Š” ๊ธฐ๋Šฅ์€ ๋‹น์—ฐํžˆ ํ•„์š”
      • ์—ฌ๊ธฐ์„œ ๊ฒ€์ƒ‰ ์‹œ, ์กฐ๊ฑด์„ ๋‹ฌ์•„ ์„ธ๋ถ€์ ์œผ๋กœ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ํ•„์š”
      • ์ถ”๊ฐ€๋กœ ๋ฉค๋ฒ„ ๊ฒ€์ƒ‰๋„ ํ•„์š”
    • ํ•ด๊ฒฐ ๋ฐ ๊ตฌํ˜„
      • search bar๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น search bar ์ขŒ์ธก์— ์กฐ๊ฑด[์ œ๋ชฉ,์ด๋ฆ„,ํฌ๋ง์ง๋ฌด,๋‚ด์šฉ]์„ ์„ ํƒํ•˜์—ฌ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • ํ•ด๋‹น form์—์„œ ์‚ฌ์šฉ๋  Object(SearchForm)๋ฅผ HomeController์—์„œ ๋ณด๋‚ด์ค€ ํ›„ ํ•ด๋‹น SearchForm์˜ selected(์กฐ๊ฑด), inputContent(๊ฒ€์ƒ‰๋‚ด์šฉ) ์„ ๋ฐ›์•„์™€ ๊ฒ€์ƒ‰ ์ง„ํ–‰
      • @ModelAttribute(name = "searchForm") SearchForm searchForm
      • ReqeustMapping์œผ๋กœ ์ง„ํ–‰, GetMapping์—์„œ๋Š” ModelAttribute์˜ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด serachForm์„ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด model์— ํฌํ•จ์‹œ์ผœ์ฃผ์–ด ๋„˜๊ธฐ๋ฉฐ, PostMapping ๋•Œ๋Š” ModelAttribute๋ฅผ ํ†ตํ•ด selected์™€ inputContent์˜ ์ž…๋ ฅ๋œ ๊ฐ’์„ ๋ฐ›์•„์˜ด โ†’ GET๊ณผ POST๋ฅผ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š์•˜๊ธฐ์— ์ถ”๊ฐ€์ ์ธ ์ฝ”๋”ฉ์ด ํ•„์š”ํ–ˆ์Œ (searchForm์ด ์ดˆ๊ธฐํ™”๊ฐ€ ๋˜์ง€ ์•Š์€ ์ƒํƒœ ํŒ๋‹จ (if (searchForm.getSelected() == null)) โ†’ GET, searchForm์ด ์ดˆ๊ธฐํ™” โ†’ POST)
      • ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ form html ์ž‘์„ฑ

          <form id="search-form" class="d-flex px-1" th:object="${searchForm}">
              <input hidden id="focus" name="focus" th:value="${nav2}"/>
              <select th:field="*{selected}" class="form-select form-select-sm" aria-label=".form-select-lg example" style="width: 35%">
                  <option th:if="${nav2 != 'all-members'}" selected value="title">์ œ๋ชฉ</option>
                  <option th:if="${nav2 != 'my-posts'}" value="writer">์ด๋ฆ„</option>
                  <option th:if="${nav2 != 'my-posts'}" value="desiredJob">ํฌ๋ง์ง๋ฌด</option>
                  <option th:if="${nav2 != 'all-members'}" value="content">๋‚ด์šฉ</option>
              </select>
              <input type="search" th:field="*{inputContent}" class="form-control" th:placeholder="'['+ ${nav2} + ']' + ' ์—์„œ ๊ฒ€์ƒ‰'"/>
              <button type="submit" class="btn btn-secondary">
                  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
                      <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
                  </svg>
              </button>
          </form>
        
        • selected ์™€ inputContent๋ฅผ th:field๋ฅผ ํ†ตํ•ด ์—ฐ๊ฒฐ
        • [์ค‘์š”] ์ถ”๊ฐ€๋กœ Mapping๋œ Controller๋Š” focus request param๊ฐ’์„ ์š”๊ตฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ focus๋ฅผ ๋‹ด์•„ ๊ฐ™์ด form์œผ๋กœ ์ „ํ•ด์คŒ
      • ์ค‘์š”ํ•œ ์ ์€ ๊ฐ ๋ฉ”๋‰ด์— ๋งž๊ฒŒ ๊ฒ€์ƒ‰์ด ์ง„ํ–‰๋˜๋ฉฐ, ํŽ˜์ด์ง•๊นŒ์ง€ ์ ์šฉ์ด ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์ 
        • all, today, my-posts, members ์˜ ๋ฉ”๋‰ด์— ๋งž๊ฒŒ ๊ฒ€์ƒ‰์ด ์ง„ํ–‰๋˜์–ด์•ผ ํ•จ
        • all,today ์—์„œ๋Š” ๋ชจ๋“  ์กฐ๊ฑด(ํ•„ํ„ฐ) ์‚ฌ์šฉ ๊ฐ€๋Šฅ
        • my-posts ์—์„œ๋Š” ์ด๋ฏธ ์ด๋ฆ„๊ณผ ํฌ๋ง์ง๋ฌด๋Š” ์ •ํ•ด์ ธ์žˆ๊ธฐ ๋•Œ๋ฌธ์— [์ œ๋ชฉ, ๋‚ด์šฉ] ํ•„ํ„ฐ๋งŒ ์ ์šฉ ๊ฐ€๋Šฅ
        • members ์—์„œ๋Š” ๊ธ€์ด ์•„๋‹ˆ๋ฏ€๋กœ [์ด๋ฆ„, ํฌ๋ง์ง๋ฌด]๋กœ๋งŒ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅ. (ํŽ˜์ด์ง•๋„ ์ ์šฉX)
        • ์ด์— Controller, Service์—์„œ๋„ ํ˜„์žฌ ๋ฉ”๋‰ด์™€ ๋“ค์–ด์˜ค๋Š” ํ•„ํ„ฐ ์กฐ๊ฑด, ๊ฒ€์ƒ‰๋‚ด์šฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์ฟผ๋ฆฌ ์ ์šฉ [๋ถ„๊ธฐ ์ˆœ์„œ : menu โ†’ selectedโ†’ searchContent]
          • ๋˜ํ•œ query ์ ์šฉ ์‹œ like์„ ์‚ฌ์šฉํ•˜๊ณ  ํ•ด๋‹น ๊ฒ€์ƒ‰๋‚ด์šฉ์„ ํฌํ•จํ•˜๋Š” ๋ชจ๋“  post๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— โ€˜%โ€™+๊ฒ€์ƒ‰๋‚ด์šฉ+โ€™%โ€™ ํ˜•์‹ ์ ์šฉ โ†’ String searchKeyword = '%' + content + '%';
          • today : posts = postService.findByTodaySearch(...)
            • selected[title,writer,desriedJob,content] โ†’ searchContent

                if (selected.equals("title")) {
                    return postNativeRepository.findByTitleToday(searchKeyword, date, offset);
                } else if (selected.equals("writer")) {
                    return postNativeRepository.findByWriterToday(searchKeyword, date, offset);
                } else if (selected.equals("desiredJob")) {
                    return postNativeRepository.findByJobToday(searchKeyword, date, offset);
                } else {
                    return postNativeRepository.findByContentToday(searchKeyword, date, offset);
                }
              
            • today๊ฐ™์€ ๊ฒฝ์šฐ ๋‚ ์งœ๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ์— native query๋กœ DB ์กฐํšŒ

          • my-posts : posts = postService.findBySearchMy(...)
            • selected[title,content] โ†’ searchContent

                if (selected.equals("title")) {
                    return postRepository.findByTitleMy(memberId, searchKeyword, offset);
                } else {
                    return postRepository.findByContentMy(memberId, searchKeyword, offset);
                }
              
            • my-posts๋Š” ๋‚ ์งœ๊ฐ€ ๋“ค์–ด๊ฐ€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์ธ JPQL ์‚ฌ์šฉ

          • all : posts = postService.findBySearch(...)
            • selected[title,writer,desriedJob,content] โ†’ searchContent

                if (selected.equals("title")) {
                    return postRepository.findByTitle(searchKeyword, offset);
                } else if (selected.equals("writer")) {
                    return postRepository.findSearchByMember(searchKeyword, offset);
                } else if (selected.equals("desiredJob")) {
                    return postRepository.findByJob(searchKeyword, offset);
                } else {
                    return postRepository.findByContent(searchKeyword, offset);
                }
              
          • members: bySearchMembers = memberService.findBySearch(...)
            • selected[writer,desriedJob] โ†’ searchContent

                if (selected.equals("writer")) {
                    return memberRepository.findSearchByName(searchKeyword);
                } else {
                    return memberRepository.findSearchByJob(searchKeyword);
                }
              
        • [์ค‘์š”] ๋˜ํ•œ ์ด๋Ÿฐ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์—์„œ ํŽ˜์ด์ง€ ๋„˜๊ธฐ๋Š” ๊ธฐ๋Šฅ์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด page index ๋ฒ„ํŠผ์— request param([ํ˜„์žฌ๋ฉ”๋‰ด, ์„ ํƒ๋œ ํ•„ํ„ฐ, ๊ฒ€์ƒ‰ ๋‚ด์šฉ])์„ ํฌํ•จ โ†’ th:href="@{/ (page=${i}, focus=${nav2}, selected=${searchForm.selected}, inputContent=${searchForm.inputContent})}"
  • #8
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • error๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, Spring ๊ธฐ๋ณธ error page๊ฐ€ ๋‚˜์™€์„œ ์ด์งˆ๊ฐ์„ ์คฌ์Œ
      • ์ง์ ‘ ๊ฐœ๋ฐœํ•œ error page๋ฅผ ๋ณด์—ฌ์คŒ์œผ๋กœ์จ ์–ด๋–ค ์˜ค๋ฅ˜์ธ์ง€ ์•ˆ๋‚ดํ•˜๊ณ  ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์‰ฝ๊ฒŒ ์ด๋™ ๊ฐ€๋Šฅ ํ•„์š”
    • ํ•ด๊ฒฐ
      • Spring์—์„œ๋Š” ์ž๋™์œผ๋กœ ์—๋ŸฌํŽ˜์ด์ง€๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฉฐ, ๊ทธ ๊ธฐ๋Šฅ์„ ์ด์šฉ
      • templates/error/4xx.html โ†’ 400, 404 ๋“ฑ Error Code๊ฐ€ 4๋กœ ์‹œ์ž‘ํ•˜๋Š” ์—๋Ÿฌ๋“ค์— ๋Œ€ํ•ด ํ•ด๋‹น html๋กœ ์—ฐ๊ฒฐ
      • templates/error/5xx.html โ†’ 500, 505 ๋“ฑ Error Code๊ฐ€ 5๋กœ ์‹œ์ž‘ํ•˜๋Š” ์—๋Ÿฌ๋“ค์— ๋Œ€ํ•ด ํ•ด๋‹น html๋กœ ์—ฐ๊ฒฐ
      • templates/error.html โ†’ ๊ธฐ๋ณธ ์—๋ŸฌํŽ˜์ด์ง€. ์œ„์˜ ํ•ด๋‹น๋˜์ง€ ์•Š๋Š” Error Code๋“ค์— ๋Œ€ํ•ด ์—ฐ๊ฒฐ
      • ๊ณ ๋กœ ํ•ด๋‹น html ํŒŒ์ผ์„ ์‚ฌ์šฉ์ž์นœํ™”์ ์œผ๋กœ ๋งŒ๋“ค์–ด ํ•ด๋‹น ๊ทœ์น™์— ๋งž๊ฒŒ ์„ค์ •.
  • #77
    • ์˜ค๋ฅ˜ ํ•ญ๋ชฉ
      • post edit์„ ๋ˆ„๋ฅผ ์‹œ ๋™์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋ฐ, ์ด๋•Œ post modal์—์„œ ์ง„ํ–‰๋˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ search bar์˜ input ์— editor๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋จ.
      • ๋ฌธ์ œ ์›์ธ : input ํƒœ๊ทธ์˜ searchForm์˜ field์˜ ์ด๋ฆ„์„ content๋กœ ์„ค์ •ํ•˜๊ณ  ์ด๋ฅผ th:field๋กœ ๋ฐ›์•„์˜ค๋ฉด์„œ ํ•ด๋‹น ํƒœ๊ทธ๊ฐ€ content์˜ id๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋˜๊ณ , MDE๊ฐ€ content์— mapping๋˜์–ด ์žˆ์—ˆ๊ธฐ์— ํ•ด๋‹น inputํƒœ๊ทธ์— mde๊ฐ€ ๋‹ฌ๋ฆฌ๊ฒŒ ๋จ
    • ํ•ด๊ฒฐ
      • searchForm์˜ field๋ฅผ inputContent๋กœ ๋ณ€๊ฒฝ (searchForm.content โ†’ searchForm.inputContent)

<220801>

#46 Enhancement : post edit์—์„œ ์‹œ๊ฐ„ ์ˆ˜์ •(์‹œ๊ฐ„ ์ถ”๊ฐ€ ๋ฐ ์‚ญ์ œ)
#52 Enhancement : older page ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • #46
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ์‹œ๊ฐ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜๋Š” ์žˆ์—ˆ์ง€๋งŒ, ์‹œ๊ฐ„์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†์—ˆ์Œ
      • Breaking์„ ์ž˜๋ชป๋ˆŒ๋Ÿฌ, ์“ธ๋ฐ์—†์ด ์‹œ๊ฐ„์ด ๊ธฐ๋ก๋˜๊ฑฐ๋‚˜ ์‹œ๊ฐ„์„ ์ž˜๋ชป ์ถ”๊ฐ€ํ•œ ๊ฒฝ์šฐ๋“ค์ด ์žˆ์Œ
      • ๋˜ํ•œ ์‰ฐ ๊ฒƒ์„ ๊ธฐ๋กํ•˜์ง€ ์•Š์„ ๋•Œ๋Š” ์‹œ๊ฐ„๋ณ€๊ฒฝ์„ ์œ„ํ•ด breaking์„ ๋ˆŒ๋ €๋‹ค๊ฐ€ ์‹œ๊ฐ„์„ ์ˆ˜์ •ํ•ด์•ผ ๋˜๋Š” ๋ถˆํŽธํ•จ ์กด์žฌ
    • ํ•ด๊ฒฐ
      • edit์„ ํ†ตํ•ด ์‹œ๊ฐ„์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • ์ด๋•Œ, ํ˜„์žฌ ์ƒํƒœ์— ๋งž์ง€ ์•Š๋Š” ์‹œ๊ฐ„์˜ ๊ฐœ์ˆ˜๋กœ ์„ค์ • ๋  ๋•Œ ์•Œ๋ฆผ์„ ํ†ตํ•ด ์ œ๋Œ€๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ ๋„ (ex_ STUDYING ์ƒํƒœ์ธ๋ฐ [12:00] ~ [13:00] ์ฒ˜๋Ÿผ ๊ณต๋ถ€๊ฐ€ ๋งˆ๋ฌด๋ฆฌ๋˜์–ด ์žˆ๊ฒŒ ์‹œ๊ฐ„์ด ์„ค์ •๋˜์–ด ์žˆ๋‹ค๋ฉด, ๋‹ค์‹œ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก alert ์•Œ๋ฆผ)

          if (state == 'STUDYING' & times_len % 2 == 0) {
              alert("[STUDYING] ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„ ๊ฐœ์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”!");
              var times_id = "times" + (times_len-1);
              var timeInput = document.getElementById(times_id);
              timeInput.setAttribute('class','form-control is-invalid');
              document.getElementById("postEdit_container").scrollIntoView();
          } else if ((state == 'BREAKING' || state == 'END') & times_len % 2 != 0) {
              alert("[BREAKING] ํ˜น์€ [END] ์ƒํƒœ์ž…๋‹ˆ๋‹ค. ์‹œ๊ฐ„ ๊ฐœ์ˆ˜๋ฅผ ํ™•์ธํ•ด์ฃผ์„ธ์š”!");
              var times_id = "times" + (times_len-1);
              var titleHtml = document.getElementById(times_id);
              titleHtml.setAttribute('class', 'form-control is-invalid');
              document.getElementById("postEdit_container").scrollIntoView();
          } else {
              $.ajax({
                  url: '/posts/edit/' + id,
                  type: "POST",
                  data: formData
              }).done(...)
          }
        
      • ์ถ”๊ฐ€๋กœ ๋น„์–ด์žˆ๋Š” ์ƒํƒœ๋กœ ์‹œ๊ฐ„์„ ์ˆ˜์ •ํ•˜๋ฉด ๋นˆ ์‹œ๊ฐ„์€ ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜๋„๋ก ์„ค์ •

          List<String> times = postEditForm.getTimes();
          while (times.remove("")) {}
        
  • #52
    • ์ถ”๊ฐ€ ์ˆ˜์ • ํ•„์š” ๋ถ€๋ถ„
      • ํ˜„์žฌ๊นŒ์ง€๋Š” ๊ทธ๋ƒฅ older page๋กœ ๋‹ค์Œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๋Š” ๊ฒƒ๋งŒ ์ ์šฉ.
      • ์ฆ‰, 1~5page ๊นŒ์ง€๋Š” ์„ ํƒํ•˜์—ฌ ๋ณผ ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ, 6page ๋ถ€ํ„ฐ๋Š” older page๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ํ•˜๋‚˜ํ•˜๋‚˜์”ฉ ๋‹ค์ŒํŽ˜์ด์ง€๋กœ ๋„˜๊ฒจ์•ผ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Œ
    • ํ•ด๊ฒฐ (์ˆ˜์ •)
      • 1~5p ์—์„œ 6p ๋กœ ๋„˜์–ด๊ฐ€๋ฉด page index ๊ฐ€ 6~10๋กœ ์„ค์ •๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • ๋˜ํ•œ 7p๋„ 6~11 ๋ฒ”์œ„์— ์žˆ๊ธฐ์— 7p์—์„œ๋„ 6~11p ์˜ ์ธ๋ฑ์Šค๋กœ ๋ณด์—ฌ์งˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • page ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์ธ๋ฑ์Šค ๊ณ„์‚ฐ ์‹คํ–‰
        • th:each="i: ${#numbers.sequence(5*((page -1)/5)+1, 5*((page -1)/5)+5)}"
        • 1~5, 6~10, 12~16 ๋“ฑ ๋ฒ”์œ„๋ณ„๋กœ 5๋กœ ๋‚˜๋ˆŒ๋•Œ์˜ ๋ชซ์ด ๊ฐ™๋‹ค๋Š” ์ ์„ ์ด์šฉํ•˜์—ฌ ์ˆ˜์‹ ์„ค์ • โ‡’ page ๊ฐ’์—์„œ 1์„ ๋บ€ ๊ฐ’์„ 5๋กœ ๋‚˜๋ˆˆ ๋ชซ์„ 5๋ฅผ ๊ณฑํ•˜๊ณ  1~5์„ ๋”ํ•ด ์„ค์ •.

<220728>

#69 Bug : post_times DB ์ €์žฅ ์˜ค๋ฅ˜
#71 Bug : ์ธ์ฆ์— ๋”ฐ๋ฅธ html ์˜ค๋ฅ˜ ๋ณ€๊ฒฝ
#59 Enhancement : ํ•˜๋ฃจ ๋ชฉํ‘œ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ์•Œ๋ฆผ

  • #69
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • 4์›”,5์›”์— ๋Œ€ํ•œ post๋“ค์˜ ์ €์žฅ๋œ post_times๊ฐ€ ์ค‘๋ณต๋˜์–ด ์ €์žฅ๋˜์–ด ์žˆ์–ด์„œ ์‹œ๊ฐ„๊ณ„์‚ฐ๋“ฑ์—์„œ ๊ธฐ์กด์˜ 2๋ฐฐ์˜ ์‹œ๊ฐ„์œผ๋กœ ๊ธฐ๋ก๋จ โ†’ ex) [12:00~15:00] [16:00~17:30] [12:00~15:00][16:00~17:30] ๊ณผ ๊ฐ™์ด ์ค‘๋ณต๋˜์–ด ์ €์žฅ.
      • ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์ „์ฒด ๊ณต๋ถ€ ์‹œ๊ฐ„, ์›”๋ณ„ ๊ณต๋ถ€์‹œ๊ฐ„ ๋“ฑ ํ†ต๊ณ„์ž๋ฃŒ์— ์˜ํ–ฅ์„ ๋ฏธ์นจ
    • ํ•ด๊ฒฐ
      • DBM ์—์„œ ์ˆ˜์ •ํ•˜๋ ค ํ–ˆ์ง€๋งŒ, post_times๊ฐ€ Embedded Type์œผ๋กœ ์ €์žฅ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, unique key๊ฐ€ ์—†์–ด์„œ ์‚ญ์ œ ์‹œ ๋ชจ๋“  post_times๊ฐ€ ์‚ญ์ œ๋˜๋Š” ํ˜„์ƒ ๋ฐœ์ƒ
      • Spring ๋‚ด์—์„œ ์ฝ”๋“œ๋กœ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ์‹ ์„ ํƒ

          @Component
          @RequiredArgsConstructor
          public class DbChange {
                    
              private final InitService initService;
                    
              @PostConstruct
              public void dbInit() {
                  initService.dbInit1();
              }
                    
              @Component
              @Transactional
              @RequiredArgsConstructor
              static class InitService {
                    
                  private final MemberService memberService;
                  private final PostNativeRepository postNativeRepository;
                  private final PostService postService;
                    
                  public void dbInit1() {
                      // 4/1 ~ 5/31
                      List<Member> all = memberService.findAll();
                      for (Member member : all) {
                          List<Post> posts = postNativeRepository.getBetween(member.getId(), "2022-04-17", "2022-06-01");
                          for (Post post : posts) {
                              Post one = postService.findOne(post.getId());
                              List<String> times = one.getTimes();
                              List<String> newTimes = new ArrayList<>();
                              for (String time : times) {
                                  if (newTimes.contains(time)) {
                                      break;
                                  }
                                  newTimes.add(time);
                              }
                              one.setTimes(newTimes);
                          }
                      }
                    
                  }
              }
          }
        
        • ํ•ด๋‹น ๋กœ์ง์ด ์ด๋ฃจ์–ด์ง„ Class๋ฅผ Component๋กœ ๋“ฑ๋กํ•˜๊ณ  PostCostruct๋ฅผ ํ†ตํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ์‹œ์ž‘๋˜์ž ๋งˆ์ž ํ•ด๋‹น ๋กœ์ง์ด ์ง„ํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
        • ๋กœ์ง
          • ๋ชจ๋“  ๋ฉค๋ฒ„๋“ค์— ๋Œ€ํ•ด ์ง„ํ–‰
          • ํ•ด๋‹น ๋ฉค๋ฒ„์˜ 4/1 ~ 5/31 ์˜ post๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„
          • ํ•ด๋‹น post๋“ค ์ค‘ ์ค‘๋ณต๋˜๋Š” ๊ฐ’์ด ๋‚˜์˜ฌ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณต์„ ์ง„ํ–‰ํ•˜๋ฉฐ ์‹œ๊ฐ„์„ renew ํ•œ ํ›„ ์ €์žฅ
  • #71
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • my post์™€ ๋™์ผํ•œ html์„ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋‹ˆ member detail ํ™”๋ฉด ์—์„œ๋„ ์ธ์ฆ์—†์ด post edit, ๋Œ“๊ธ€ ์ธ์ฆ ๋“ฑ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ๋จ
    • ํ•ด๊ฒฐ
      • ๊ฐ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์ธ์ฆ์„ ์ง„ํ–‰ํ•œ ํ›„ post, comment ์ˆ˜์ • ๋ฐ ์‚ญ์ œ ๋“ฑ์„ ์ ์šฉ
  • #59
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ๋ชฉํ‘œ์‹œ๊ฐ„์„ ๋„˜๊ธฐ์ง€ ๋ชปํ–ˆ์„ ๋•Œ ๋™๊ธฐ๋ถ€์—ฌ๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•จ
    • ๊ตฌํ˜„

        function check_end(memberId) {
            $.ajax({
                url: '/members/times/' + memberId,
                type: "GET"
            })
                .done(function (response) {
                    var currTotal = response.hour * 60 + response.min;
                    if (currTotal < memberTodayGoalTotal) {
                        var timeDiff = memberTodayGoalTotal - currTotal;
                        var check = confirm("์•„์ง ๋ชฉํ‘œ ์‹œ๊ฐ„์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ•˜์…จ์Šต๋‹ˆ๋‹ค. (" + Math.floor(timeDiff / 60) + "์‹œ๊ฐ„ " + timeDiff % 60 + "๋ถ„ ๋ถ€์กฑ)\n์‚ฌ์šฉ์„ ์ข…๋ฃŒํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?");
                        if (check) {
                            window.location.href = "/end";
                        }
                    } else {
                        window.location.href = "/end";
                    }
                })
        }
      
      • javascript, ajax ํ†ต์‹ ์„ ์ด์šฉํ•˜์—ฌ ๋ชฉํ‘œ์‹œ๊ฐ„๋ณด๋‹ค ์ž‘์€ ๊ฒฝ์šฐ alert์„ ํ†ตํ•ด ์•Œ๋ฆผ์„ ์คŒ
      • ๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด ๊ทธ๋ƒฅ ๋ฐ”๋กœ โ€œ/endโ€ ๋ฅผ ํ†ตํ•ด ๊ณต๋ถ€ ์ข…๋ฃŒ ์ง„ํ–‰

<220727>

#58 Enhancement: ์ƒ๋‹จ๋ฐ” ๋ฉ”๋‰ด(all-members) ๋ฐ ๋ฉค๋ฒ„ ์ƒ์„ธํ™”๋ฉด ์„ค์ •

  • #58
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ๋ฉค๋ฒ„๋“ค์— ๋Œ€ํ•œ ํ”„๋กœํ•„์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ™”๋ฉด์ด ์—†์—ˆ์Œ
      • all-members ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๊ธฐ๋ณธ์ ์ธ ๊ฐ„๋‹จํ•œ ๋ชจ๋“  ๋ฉค๋ฒ„์˜ ํ”„๋กœํ•„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • ๋˜ ํ•ด๋‹น ํ”„๋กœํ•„์„ ํด๋ฆญํ•˜๋ฉด ํšŒ์›์˜ ์ƒ์„ธ ์ •๋ณด (ํ†ต๊ณ„์ž๋ฃŒ, ๋ชฉํ‘œ, ๊ณต๋ถ€ ์บ˜๋ฆฐ๋”) ๋“ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •
    • ๊ตฌํ˜„
      • ๊ธฐ๋ณธ โ€œ/โ€ ์— mapping ๋œ controller์—์„œ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ์ด๋ฏธ ๋„˜๊ธฐ๊ณ  ์žˆ์—ˆ๊ธฐ์— ํ•ด๋‹น ์ •๋ณด๋ฅผ ์ด์šฉํ•ด์„œ view Template์—์„œ ์ผ๋ถ€๋งŒ์„ ์ˆ˜์ •ํ•˜์—ฌ ์ง„ํ–‰
      • focus request parameter๊ฐ€ all-members๋ฉด post๋ฅผ renderingํ•˜์ง€์•Š๊ณ  ํ•ด๋‹น ์œ„์น˜์— ๋ชจ๋“  ๋ฉค๋ฒ„์˜ ํ”„๋กœํ•„์„ ๋ณด์ผ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •. (all-members๊ฐ€ ์•„๋‹ˆ๋ฉด post(all, today, my-posts) rendering)

          <div class="col-lg-5 mb-4" th:if="${nav2 == 'all-members'}" th:each="mem:${allMembers}">
              <!-- All Members -->
              <div id="profile" class="card shadow">
                  <div class="card-header d-sm-flex justify-content-between">
                      <div style="margin-top: 5px" class="input-group">
                          <h6 class="m-0 font-weight-bold"> <span
                                  class="ml-1 h5 fw-bold">ํ”„๋กœํ•„</span></h6>
          								...
                  </div>
              </div>
          </div>
        

<220726>

Article Nav๋ฐ”(All Members) ์„œ๋น„์Šค
#58 Enhancement: ์ƒ๋‹จ๋ฐ” ๋ฉ”๋‰ด (my-posts ์ธํ„ฐ์…‰ํ„ฐ, all-members)
#70 Bug : Interceptor ์˜ค๋ฅ˜

  • #58
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ์ƒ๋‹จ๋ฐ” ๋ฉ”๋‰ด์—์„œ my-posts ๊ฐ™์€ ๊ฒฝ์šฐ, ๋กœ๊ทธ์ธ๋œ ํšŒ์›์˜ ์ „์ฒด posts๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, my-posts์— ๋“ค์–ด๊ฐˆ ๊ฒฝ์šฐ ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ์ ์šฉํ•ด์ค˜์•ผ ๋จ
      • ๋˜ํ•œ, redirect๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ ํ›„ ๋‹ค์‹œ my-posts๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก redirectURL ํฌํ•จ ํ•„์ˆ˜
    • ํ•ด๊ฒฐ
      • WebConfig ์— ์ธํ„ฐ์…‰ํ„ฐ ์ ์šฉ URL์— โ€œ/โ€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  focus @RequestParam ์ด โ€œmy-postsโ€์ธ ๊ฒฝ์šฐ๋งŒ ๋กœ๊ทธ์ธ์ธ์ฆ์ด ์ง„ํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • โ†’ .addPathPatterns("/members/my-page", "/members/edit/**", "/");
      • Spring Interceptor ์ ์šฉ ์‹œ ํฌํ•จ Url๊ณผ ์ œ์™ธ Url์€ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, request param๊ณผ ๊ฐ™์€ parameter ํ•„ํ„ฐ๋ง์€ ์ง€์›ํ•˜์ง€ ์•Š์•„ Interceptor ๋‚ด์˜ request๋ฅผ ํ†ตํ•ด parameter๋ฅผ ์ง์ ‘ ๋ฐ›์•„์™€ ๋กœ์ง์„ ๊ตฌ์„ฑํ•ด์ค˜์•ผ๋จ

          String requestURI = request.getRequestURI();
          String focus = request.getParameter("focus");
                    
          if (requestURI.equals("/")) {
              if (focus == null || !focus.equals("my-posts")) { // basic home -> / or parameters -> focus=all, today, all-members
                  return true;
              }
          } // my-posts ๋งŒ ๋กœ๊ทธ์ธ ์ธ์ฆ ์ง„ํ–‰
        
        • โ€œ/โ€ url์— ๋Œ€ํ•ด์„œ focus paramter๊ฐ€ my-posts๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  url์€ true๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธ์ธ์ฆ์„ ์ง„ํ–‰ํ•˜์ง€ ์•Š์Œ
  • #70
    • Bug : ์ถ”๊ฐ€์ ์ธ ๋กœ์ง์— ๋”ฐ๋ผ My Page๊ฐ€ ๋“ค์–ด๊ฐ€์ง€์ง€ ์•Š์•„์ง
    • ํ•ด๋‹น ๋กœ์ง์„ ์งœ๋Š” ๊ณผ์ •์—์„œ ๊ธฐ์กด์˜ My Page์— ๋Œ€ํ•œ Interceptor ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ โ†’ url๊ณผ request param ํŒ์ • ๊ณผ์ •์—์„œ์˜ ์‹ค์ˆ˜ ํ•ด๊ฒฐ (์กฐ๊ฑด๋ฌธ ์‹ค์ˆ˜)

<220725>

Article Nav๋ฐ”(All, Today, My Posts) ์„œ๋น„์Šค
#58 Enhancement: ์ƒ๋‹จ๋ฐ” ๋ฉ”๋‰ด ๊ฐœ๋ฐœ
#44 Enhancement: Today ํ™œ์„ฑํ™”

  • #58, #44
    • ๊ฐœ๋ฐœ ํ•„์š”์„ฑ
      • ํ˜„์žฌ ๋ชจ๋“  Post๋“ค์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์˜ค๋Š˜ ์ž‘์„ฑ๋œ Post, ๋‚˜์˜ Post๋“ฑ ์กฐ๊ฑด์— ๋”ฐ๋ฅธ post๋ฅผ ๋ณด์—ฌ์ค„ ํ•„์š”๊ฐ€ ์žˆ์Œ
      • ์ฆ‰, ํ•„ํ„ฐ๋ง๋œ Post๋“ค์— ๋Œ€ํ•ด์„œ ๋ณด์—ฌ์ค„ ํ•„์š” ์กด์žฌ
    • ๊ตฌํ˜„
      • ์ด๋“ค์„ Nav๋ฐ”๋ฅผ ํ†ตํ•ด All(๋ชจ๋“  Posts), Today(์˜ค๋Š˜์˜ Posts), My Posts(๋‚˜์˜ ๋ชจ๋“  Posts) ๋ฅผ ์„ ํƒํ•˜์—ฌ Post๋“ค์„ ๋ณผ ์ˆ˜ ์žˆ์Œ
      • ์ด๋“ค์„ @RequestParam์œผ๋กœ ๊ตฌ๋ถ„ โ†’ @RequestParam(name = "focus", defaultValue = "all") String focus (all, today, my-posts)

          if (focus.equals("today")) {
              DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
              LocalDateTime now = LocalDateTime.now();
              String date = now.format(dateTimeFormatter);
              if (now.getHour() < 4) {
                  date = now.minusDays(1).format(dateTimeFormatter);
              }
              posts = postService.getTodayPosts(date, (page - 1) * 12);
          } else if (focus.equals("my-posts")) {
              posts = postService.getMemberPosts(loginMemberId, (page - 1) * 12);
          } else {
              posts = postService.findByPage((page - 1) * 12);
          }
        
        • ์—ฌ๊ธฐ์„œ all,today,my-posts ์— ๋”ฐ๋ผ repository์—์„œ ๊ฐ€์ ธ์˜ค๋Š” post๊ฐ€ ๋‹ค๋ฆ„
        • ๋˜ํ•œ ์—ฌ๊ธฐ์„œ paging๊ธฐ๋Šฅ๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ ์กฐ๊ฑด์— ๋”ฐ๋ฅธ post์— ๋”๋ถˆ์–ด paging๊ธฐ๋Šฅ๊นŒ์ง€ ์ ์šฉํ•˜์—ฌ repository์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
        • ๊ฐ€์ ธ์˜จ ํ›„ ๋˜‘๊ฐ™์ด home.html์— rendering โ†’ ๋ชจ๋‘ posts๋กœ viewTemplate์— ๋ณด๋‚ด์ง
        • ์ถ”๊ฐ€๋กœ today๋Š” ์š”์ฒญ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์„ค์ •๋˜๋Š” ๋‚ ์งœ๋ฅผ ์ง€์ •
          • 0~4 ์š”์ฒญ : ์ „๋‚  ๊ธ€
          • 4~24 ์š”์ฒญ : ๋‹น์ผ ๊ธ€

<220723>

#55 Back : ๋ชฉํ‘œ ์„ค์ •
#52 Back : older page

  • #55
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ๋ชฉํ‘œ๋ฅผ ์„ค์ •ํ•ด์„œ ํ•ด๋‹น ๋ชฉํ‘œ์— ๋‹ค๋ฅธ ๋‹ฌ์„ฑ๋ฅ  ๋“ฑ์„ ์•Œ๋ ค์ฃผ๋ฉฐ ๊ณต๋ถ€ ๋™๊ธฐ ๋ถ€์—ฌ๋ฅผ ์ค„ ํ•„์š”๊ฐ€ ์žˆ์Œ
    • ๊ตฌํ˜„
      • ๋ชฉํ‘œ๋Š” Member์— ๋”ฐ๋ผ ์„ค์ •๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ Member ๊ฐ์ฒด์— ๋ชฉํ‘œ๊ฐ’์„ ์ •ํ•  ์ˆ˜ ์žˆ๋Š” Goal ๊ฐ์ฒด field ์ถ”๊ฐ€ (Embedded Type)
        • Goal

            @Embeddable
            @Getter
            public class Goal {
                          
                private int dayGoalTimes;
                private int weekGoalTimes;
                          
                public Goal(int day, int week) {
                    this.dayGoalTimes = day;
                    this.weekGoalTimes = week;
                }
                          
                public Goal() { }
            }
          
          • int dayGoalTimes : ํ•˜๋ฃจ ๋ชฉํ‘œ ๊ณต๋ถ€์‹œ๊ฐ„
          • int weekGoalTimes : ์ผ์ฃผ์ผ ๋ชฉํ‘œ ๊ณต๋ถ€์‹œ๊ฐ„
          • Entity์— Embedded Type์œผ๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— Custom ๊ฐ์ฒด์ธ Times๋กœ ์ €์žฅ์ด ์•ˆ๋จ โ†’ ํ•ด๋‹น ๊ฐ’์„ ๋ถ„(int)์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์ €์žฅ
      • ์ƒˆ๋กœ์šด Member๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ, ๊ธฐ๋ณธ์ ์ธ ๋ชฉํ‘œ์‹œ๊ฐ„์ด ์ •ํ•ด์ง„ ์ƒํƒœ๋กœ ์ €์žฅ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • โ†’ member.setGoal(new Goal(300, 1500));
      • ์ถ”๊ฐ€๋กœ ๋ชฉํ‘œ ์„ค์ •์€ My Page์—์„œ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •
        • goal ์„ค์ • ์‹œ ํŽธ์˜์ƒ ์‹œ๊ฐ„๊ณผ ๋ถ„์„ ๋”ฐ๋กœ ์ž…๋ ฅ ๋ฐ›์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด์˜ Goal ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ์ž…๋ ฅ Form์„ ์œ„ํ•œ GoalDto ์ƒ์„ฑ

            @Data
            static class GoalDto {
                          
                private int dayHour;
                private int dayMin;
                private int weekHour;
                private int weekMin;
                          
                public GoalDto(Goal goal) {
                    int day = goal.getDayGoalTimes();
                    this.dayHour = Math.floorDiv(day, 60);
                    this.dayMin = day % 60;
                    int week = goal.getWeekGoalTimes();
                    this.weekHour = Math.floorDiv(week, 60);
                    this.weekMin = week % 60;
                }
                          
                public GoalDto() {
                }
            }
          
          • Times๋กœ ํ•˜๋ฉด ๋‘๋‹จ๊ณ„๋กœ modelAttribute๊ฐ€ ๋™์ž‘ํ•ด์•ผ๋จ โ†’ ์ด ๋ถ€๋ถ„์ด ๋˜์ง€ ์•Š์•„ ๋ชจ๋‘ ํ•œ๋‹จ๊ณ„์˜ modelAttribute๊ฐ€ ๋™์ž‘ํ•˜๋„๋ก ๋ชจ๋“  field๋ฅผ int๋กœ ์„ค์ •
      • ๋˜ํ•œ, ์ด ๋ชฉํ‘œ์— ๋”ฐ๋ฅธ ๋‹ฌ์„ฑ๋ฅ (ํ•˜๋ฃจ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋ฅ , ์ผ์ฃผ์ผ ๋ชฉํ‘œ ๋‹ฌ์„ฑ๋ฅ ) ๋ณด์—ฌ์คŒ
      • ์ด์— ๋”ฐ๋ฅธ ๋žญํฌ๋„ ์ถ”๊ฐ€ (๋ธŒ๋ก ์ฆˆ, ์‹ค๋ฒ„, ๊ณจ๋“œ, โ€ฆ)
  • #52
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • paging์— ๋”ฐ๋ฅธ post๋“ค์„ ๋ณด์—ฌ์ฃผ๊ธดํ–ˆ์ง€๋งŒ, 5ํŽ˜์ด์ง€ ๋„˜๊ฒจ์„œ์˜ post๋“ค์„ ๋ณด์—ฌ์ฃผ์ง€ ๋ชปํ–ˆ์Œ
      • older ๋ฒ„ํŠผ์ด ์žˆ์—ˆ์ง€๋งŒ ํ™œ์„ฑํ™”๋˜๊ณ  ์žˆ์ง€ ์•Š์•˜์Œ
    • ํ•ด๊ฒฐ
      • older ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ด์ „ page๋กœ ๊ณ„์†ํ•ด์„œ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

          <ul class="pagination justify-content-center my-4">
              <li class="page-item">
                  <a class="page-link" href="/" tabindex="-1" aria-disabled="true">Newer</a>
              </li>
              <li th:each="i: ${#numbers.sequence(5*((page -1)/5)+1, 5*((page -1)/5)+5)}" aria-current="page"
                  th:class="${page == i}? 'page-item active' : 'page-item'">
                  <a class="page-link" th:href="@{/ (page=${i}, focus=${nav2})}" th:text="${i}">#</a>
              </li>
              <li class="page-item">
                  <a class="page-link" th:href="@{/ (page=${page+1}, focus=${nav2})}">Older</a>
              </li>
          </ul>
        
        • ํ˜„์žฌ focus ๋˜์–ด ์žˆ๋Š” page์— 1์„ ๋”ํ•˜์—ฌ ๋‹ค์Œ page๋กœ ๋„˜์–ด๊ฐ€๋„๋ก ์„ค์ •
        • th:each="i: ${#numbers.sequence(5*((page -1)/5)+1, 5*((page -1)/5)+5)}" ๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ํŽ˜์ด์ง€์— ๋”ฐ๋ผ 1~5, 6~10, 11~15 ๋“ฑ์œผ๋กœ page index๊ฐ€ ๋ณด์ผ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

<220722>

My Page (๋‚ด ํ”„๋กœํ•„) ์„œ๋น„์Šค
#54 Enhancement : ๊ณต๋ถ€ ๋‹ฌ๋ ฅ ๋ฐ ํ•ด๋‹น ์›”๋ณ„ ํ†ต๊ณ„

  • #54
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ์ง€๊ธˆ๊นŒ์ง€๋Š” ์ž์‹ ์ด ์ผ๋˜ ๊ธ€์„ ํ™•์ธํ•  ์ˆ˜ ์—†์œผ๋ฉฐ
      • ๊ทธ์— ๋”ฐ๋ผ ์–ผ๋งˆ๋‚˜ ๊ณต๋ถ€๋ฅผ ํ–ˆ๋Š”์ง€๋„ ์•Œ ์ˆ˜ ์—†๊ณ , ์–ด๋–ค ๊ณต๋ถ€๋ฅผ ํ–ˆ๋Š”์ง€๋„ ์•Œ ์ˆ˜ ์—†์—ˆ์Œ
      • ์ด๋ฅผ ์›”๋ณ„๋กœ ์–ด๋–ค ๊ณต๋ถ€๋ฅผ ํ–ˆ๊ณ  ๊ณต๋ถ€๋ฅผ ์–ผ๋งˆ๋‚˜ ํ–ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์ด ํ•„์š”
    • ๊ตฌํ˜„
      • ์›”๋ณ„๋กœ ์–ด๋–ค ๊ณต๋ถ€๋ฅผ ํ–ˆ๊ณ , ํ•ด๋‹น ์ผ์ž์˜ ๊ธ€์„ ํ™•์ธํ•˜๊ณ  ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ฒŒ๋” ๊ณต๋ถ€ ๋‹ฌ๋ ฅ ๋ฐ ํ•ด๋‹น ์›”๋ณ„ ํ†ต๊ณ„ ์„œ๋น„์Šค ์ œ๊ณต
      • ๊ณต๋ถ€ ๋‹ฌ๋ ฅ
        • ๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ์˜ ๋‹ฌ์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ฌ๋ ฅ์„ ๋ณด์—ฌ์ฃผ๊ณ , < > ๋ฒ„ํŠผ์„ ํ†ตํ•ด ๋‹ค๋ฅธ ๋‹ฌ๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ๊ฒŒ ์„ค์ •
        • ๊ฐ ๋‚ ์งœ์— ํ•ด๋‹นํ•˜๋Š” post๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ ํ›„ ์žˆ์œผ๋ฉด ํ•ด๋‹น post์˜ ์ œ๋ชฉ์„ ๋‹ฌ๋ ฅ์— ๋ณด์—ฌ์คŒ
        • ๋˜ํ•œ, ๊ทธ ์ œ๋ชฉ์„ ํด๋ฆญํ•˜๋ฉด ๋ชจ๋‹ฌํ˜•์‹์œผ๋กœ ํ•ด๋‹น post๊ฐ€ ๋œฐ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
          if (month == null) {
              month = LocalDateTime.now().getMonthValue();
          }
          focusedDate = LocalDateTime.of(year, month, 1, 0, 0);
          List<Post> monthPosts = postService.getMonthPosts(member.getId(), month);
          List<PostViewDto> monthPostDtos = monthPosts.stream().map(PostViewDto::new).collect(Collectors.toList());
          int[] dayData = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
          List<String> weekDay = Arrays.asList("sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday");
          List<Integer> calenderDays = new ArrayList<>();
          Map<Integer, PostViewDto> calenderData = new HashMap<>();
          for (int i = 1; i <= dayData[month - 1]; i++) {
              calenderDays.add(i);
              calenderData.put(i, null);
          }
          for (PostViewDto monthPostDto : monthPostDtos) {
              int dayOfMonth = monthPostDto.getCreateTime().getDayOfMonth();
              calenderData.put(dayOfMonth, monthPostDto);
          }
          ForCalender CalenderInfo = getCalenderInfo(weekDay, focusedDate);
        
        • @RequestParam ์œผ๋กœ month๋ฅผ ๋ฐ›์•„ ์˜ค๋Š”๋ฐ, ์ด๋•Œ month๊ฐ€ ์—†๋‹ค๋ฉด ํ˜„์žฌ ์›”์„ focus
        • ํ•ด๋‹น month์˜ 1์ผ์„ ์‹œ์ž‘ ๋‚ ์งœ๋กœ ์„ค์ •
        • ํ•ด๋‹น member์˜ ํ•ด๋‹น month์˜ post๋ฅผ ๊ฐ€์ ธ์˜ด (navtive query ์‚ฌ์šฉ) โ†’ postService.getMonthPosts(member.getId(), month);

            @Query(value = "SELECT * " +
                    "FROM post p " +
                    "where p.member_id = :m_id " +
                    "and MONTH(p.create_time) = :request_month ;", nativeQuery = true)
            List<Post> getMonthPost(@Param(value = "m_id") Long id, @Param(value="request_month") int month);
          
        • ํ•ด๋‹น ์›”์— ๋งž๋Š” calender ์ƒ์„ฑ (List๋กœ ๋‹ฌ๋ ฅ์„ ๋งŒ๋“ค๊ณ , Map์œผ๋กœ ํ•ด๋‹น ๋‚ ์งœ์— ๋งž๋Š” post๋ฅผ ๋„ฃ์–ด์คŒ)
        • ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด๋‹น calender์˜ ์ •๋ณด(๋…„๋„, ์›”, ์‹œ์ž‘์š”์ผ ๋“ฑ)๋ฅผ ๋‹ด์•„ View Template์— ๋„˜๊ฒจ์คŒ
      • ๊ณต๋ถ€ ํ†ต๊ณ„
        • ํ˜„์žฌ focus ๋˜์–ด ์žˆ๋Š” ๋‹ฌ์˜ ๋ชจ๋“  post๋ฅผ ๊ฐ€์ ธ์™€์„œ โ€œ์ถœ์„๋ฅ , ์ด ๊ณต๋ถ€์‹œ๊ฐ„, ํ‰๊ท  ๊ณต๋ถ€์‹œ๊ฐ„โ€ ์— ๋Œ€ํ•œ ํ†ต๊ณ„ ์ž๋ฃŒ๋ฅผ ์ œ๊ณต
          int monthDate = dayData[month - 1];
          int nowMonthPostsLen = 0;
          if (month == LocalDateTime.now().getMonthValue()) {
              monthDate = LocalDateTime.now().getDayOfMonth();
              nowMonthPostsLen = monthPosts.size();
          } else {
              nowMonthPostsLen = postService.getMonthPosts(loginMemberId, LocalDateTime.now().getMonthValue()).size();
          }
          AllStatic allStatic = getAllStatus(oriMember, staticsData, days.get(days.size() - 1), monthPosts, monthDate, nowMonthPostsLen);
        
        • ์ถœ์„๋ฅ  : ํ•ด๋‹น ๋‹ฌ์˜ ๋ชจ๋“  post์˜ ๊ฐœ์ˆ˜ / ํ•ด๋‹น ๋‹ฌ์˜ ๋ชจ๋“  ๋‚ ์งœ (ํ•ด๋‹น ๋‹ฌ์ด ํ˜„์žฌ ๋‹ฌ์ด๋ฉด ํ˜„์žฌ๊นŒ์ง€์˜ ์ถœ์„๋ฅ ๋กœ ๊ณ„์‚ฐ)
        • ์ด ๊ณต๋ถ€์‹œ๊ฐ„ : ํ•ด๋‹น ๋‹ฌ์˜ ๋ชจ๋“  post๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‹œ๊ฐ„๊ณ„์‚ฐ
        • ํ‰๊ท  ๊ณต๋ถ€์‹œ๊ฐ„ : ์ด ๊ณต๋ถ€์‹œ๊ฐ„ / ํ•ด๋‹น ๋‹ฌ์˜ ๋ชจ๋“  ๋‚ ์งœ (ํ•ด๋‹น ๋‹ฌ์ด ํ˜„์žฌ ๋‹ฌ์ด๋ฉด ํ˜„์žฌ๊นŒ์ง€์˜ ์ถœ์„๋ฅ ๋กœ ๊ณ„์‚ฐ)

<220721>

My Page (๋‚ด ํ”„๋กœํ•„) ์„œ๋น„์Šค
#65 Enhancement: ์ฃผ๊ฐ„ ๊ณต๋ถ€ ๊ทธ๋ž˜ํ”„ (๋ˆ„์  ๊ทธ๋ž˜ํ”„ X โ†’ ์ผ๋ฐ˜ ๊ทธ๋ž˜ํ”„ O)

  • #65
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • Ranking ํ™”๋ฉด์„ ํ†ตํ•ด์„œ ์ผ์ฃผ์ผ๊ฐ„์˜ ๊ณต๋ถ€์‹œ๊ฐ„ ๋ˆ„์  ๊ทธ๋ž˜ํ”„๋Š” ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ผ๋ฐ˜ ๊ทธ๋ž˜ํ”„, ์ฆ‰ ์ผ์ฃผ์ผ๊ฐ„์˜ ๋‚ด๊ฐ€ ํ•˜๋ฃจํ•˜๋ฃจ ์–ผ๋งˆ๋‚˜ ๊ณต๋ถ€ํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ๊ทธ๋ž˜ํ”„๊ฐ€ ์—†์–ด ๋ถˆํŽธ
      • ๋˜ํ•œ Profile์—์„œ์˜ ๊ทธ๋ž˜ํ”„๋Š” ๋ˆ„์  ๊ทธ๋ž˜ํ”„๋ณด๋‹ค๋Š” ์ผ๋ฐ˜ ๊ทธ๋ž˜ํ”„๊ฐ€ ๋”์šฑ ํ•„์š” (Bar Chart)
    • ๊ตฌํ˜„
      • ๋จผ์ € ๋ชจ๋“  ๋ฉค๋ฒ„๋“ค์˜ ์ผ์ฃผ์ผ ๊ฐ„์˜ post๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ์‹œ๊ฐ„ ๊ณ„์‚ฐ (getStaticsData)

          private Map<Integer, Times> getStaticsData(MemberDto member) {
                    
              List<Post> posts;
              Map<Integer, Times> dayTimes = new HashMap<>();
              DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
              // 0-4 ์‚ฌ์ด ์š”์ฒญ (์ดํ‹€์ „๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ)
              if (LocalDateTime.now().getHour() < 4) {
                  String end = LocalDateTime.now().minusDays(1).format(dateTimeFormatter);
                  String start = LocalDateTime.now().minusDays(8).format(dateTimeFormatter);
                  posts = postService.getLast7(member.getId(), start, end);
                  for (int i = 8; i > 1; i--) {
                      dayTimes.put(LocalDateTime.now().minusDays(i).getDayOfMonth(), new Times(0));
                  }
              } else {...} // ์ด์™ธ์˜ ์š”์ฒญ (4~24 ์‚ฌ์ด ์š”์ฒญ, ํ•˜๋ฃจ์ „๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ)
              }
              for (Post post : posts) {
                  Times time = getTimes(post.getTimes());
                  int today = (time.getHour() * 60 + time.getMin());
          				...
              }
              return dayTimes;
          }
        
        • ๋จผ์ € ๋‚ ์งœ๋ณ„์˜ ์‹œ๊ฐ„๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด Map ์‚ฌ์šฉ (๋‚ ์งœ์™€ ์ธ๋ฑ์Šค๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— List ๋ง๊ณ  Map ์‚ฌ์šฉ)
        • nativequery์—์„œ Between์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ post list๋ฅผ ๊ฐ€์ ธ์˜ด (0-4 ์‚ฌ์ด ์š”์ฒญ โ†’ ์ดํ‹€์ „๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ, ์ด์™ธ์˜ ์š”์ฒญ(4~24 ์‚ฌ์ด ์š”์ฒญ) โ†’ ํ•˜๋ฃจ์ „๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ) [getLast7(Long memberId, String start, String end)]
        • ๋งˆ์ง€๋ง‰์œผ๋กœ Times ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ ์‹œ๊ฐ„ ๊ณ„์‚ฐ ํ›„ ํ•ด๋‹น ์ •๋ณด๊ฐ€ ๋“ค์–ด์žˆ๋Š” dayTimes Map ๋ฐ˜ํ™˜
      • ๊ทธ ํ›„ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ view Template์œผ๋กœ ๋ณด๋‚ธ ํ›„ ์ด ๊ฐ’์„ Javascript๋กœ ๋ฐ›์•„์™€ BarChart์˜ ๋ฐ์ดํ„ฐ ๊ฐ’์— ๋„ฃ์–ด์คŒ (staticDays ๋Š” staticData์˜ key๋ฅผ ์ •๋ ฌํ•œ ๊ฐ’. โ†’ ์ •๋ ฌ๋œ ๋‚ ์งœ)

          var staticDays = [[ ${staticDays}]];
          var data = [[ ${staticData}]]
                    
          // Bar Chart
          var ctx = document.getElementById("myBarChart");
          var myBarChart = new Chart(ctx, { datatsets: ...})
        

<220720>

My Page (๋‚ด ํ”„๋กœํ•„) ์„œ๋น„์Šค ์ถ”๊ฐ€
#13 Enhancement : ์‚ฌ์šฉ์ž ์ •๋ณด ๋ณด๊ธฐ
#53 Back : ๋ชจ๋“  ๊ณต๋ถ€ ์‹œ๊ฐ„
#67 Back : Spring Interceptor ์ ์šฉ

  • #13
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • ์ง€๊ธˆ๊นŒ์ง€๋Š” ์ƒ๋Œ€๋ฐฉ์˜ ์ƒ์„ธ ํ”„๋กœํ•„์„ ํ™•์ธํ•  ์ˆ˜ ์—†์„ ๋ฟ๋”๋Ÿฌ ์ž์‹ ์˜ ์ƒ์„ธ ํ”„๋กœํ•„๋„ ํ™•์ธํ•  ์ˆ˜ ์—†์—ˆ์Œ
      • ๋งํฌ, ๋ณ„๋ช… ๋“ฑ ์ž์‹ ์˜ ์ •๋ณด, ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋“ค์˜ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค„ ํ•„์š”๊ฐ€ ์žˆ์Œ
    • ํ•ด๊ฒฐ
      • My Page๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€ ์ถ”๊ฐ€ (์‚ฌ์šฉ์ž๋Š” Session์— ์ €์žฅ๋œ member โ†’ ๋กœ๊ทธ์ธ๋œ ๋ฉค๋ฒ„)
      • Session์— ์ €์žฅ๋œ member์˜ Id๋ฅผ ๋ฐ›์•„์™€ ํ•ด๋‹น member์˜ ์ •๋ณด๋ฅผ DB์—์„œ ๊ฐ€์ ธ์™€ ๋ณด์—ฌ์คŒ. (login id, name, nickname, introduce, links)
        • @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Long loginMemberId โ†’ Member oriMember = memberService.findOne(loginMemberId);
        • DTO๋กœ ๋ณ€๊ฒฝ ํ›„ ๋ณด์—ฌ์ค„ ์ •๋ณด๋งŒ์„ veiw Template์— ๋„˜๊ฒจ์คŒ โ†’ MemberDto member = new MemberDto(oriMember);
      • link๋Š” ํด๋ฆญ ์‹œ ํ•ด๋‹น link๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
  • #53
    • ๊ธฐ๋Šฅ ์„ค๋ช…
      • ํ•ด๋‹น ๋ฉค๋ฒ„๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ์–ผ๋งˆ๋‚˜ ๊ณต๋ถ€๋ฅผ ํ•ด์™”๋Š”์ง€ ์•Œ๋ ค์ฃผ๋Š” ๊ธฐ๋Šฅ (์‹œ๊ฐ„)
    • ๊ตฌํ˜„
      • ํ”„๋กœํ•„์— ์ถ”๊ฐ€ ํ•ด๋‹น ๊ธฐ๋Šฅ ์ถ”๊ฐ€
      • ํ•ด๋‹น ๋ฉค๋ฒ„์˜ ๋ชจ๋“  post๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„ ๊ฐ post์˜ times๋“ค์˜ ์‹œ๊ฐ„ ๊ฐ’์„ ๊ณ„์‚ฐ, ๊ทธ ํ›„ member์— ์ €์žฅ โ†’ member.setTotalTime(getAllTimes(oriMember));

          private Times getAllTimes(Member member) {
              List<Post> posts = member.getPosts();
              int total = 0;
              for (Post post : posts) {
                  if (post.getTimes().size() % 2 != 0) continue;
                  Times times = getTimes(post.getTimes());
                  total += times.getHour() * 60 + times.getMin();
              }
                    
              return new Times(total);
          }
        
  • #67
    • ๊ธฐ๋Šฅ ํ•„์š”์„ฑ
      • My Page ๊ฐ™์€ ๊ฒฝ์šฐ, ์ž์‹ ์˜ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ  ์ˆ˜์ •ํ•˜๋Š” ๊ณต๊ฐ„์ด๋ฏ€๋กœ ๋กœ๊ทธ์ธ ์ธ์ฆ ๋ฐ ํšŒ์› ์ผ์น˜ ์ธ์ฆ์ด ํ•„์š”
    • ํ•ด๊ฒฐ
      • Login Interceptor์— ํ•ด๋‹น url ์ถ”๊ฐ€
      • .addPathPatterns("/members/my-page", โ€ฆ )
      • ๋งŒ์•ฝ ๋กœ๊ทธ์ธ์ด ๋˜์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋กœ๊ทธ์ธ ํ›„ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

<220719>

#65 Bug : static ๊ทธ๋ž˜ํ”„ ์˜ค๋ฅ˜

  • #65
    • ๋ฐœ์ƒ๋œ Bug
      • 0~4์‹œ์˜ ์š”์ฒญ์— ๋Œ€ํ•ด์„  ์ดํ‹€์ „๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ณด์—ฌ์ ธ์•ผ๋˜๋Š”๋ฐ, 0์‹œ20๋ถ„ ์ฏค์— ์š”์ฒญํ–ˆ์„ ๋•Œ, ํ•˜๋ฃจ์ „์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณด์—ฌ์ง
      • ๋ˆ„์  ๋ฐ์ดํ„ฐ์ธ๋ฐ, ์ค‘๊ฐ„์— ๋ˆ„์ ๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ ๋ฐœ์ƒ
    • ํ•ด๊ฒฐ
      • 0~4์‹œ์˜ ์š”์ฒญ์— ๋Œ€ํ•œ ๋ถ„๊ธฐ๋ฅผ if (0<nowTimeโ€ฆ) ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฒ”์œ„ ์„ค์ •์„ ์ž˜๋ชปํ•จ. โ†’ if (now.getHour() < 4) ๋กœ ๋ฒ”์œ„ ์ˆ˜์ •
      • ๋ˆ„์  ๋ฐ์ดํ„ฐ ๋ฌธ์ œ
        • ๋‚ ์งœ์— ๋Œ€ํ•œ HashMap์˜ key๋ฅผ ๊ฐ€์ ธ์˜ฌ๋•Œ, ๋”ฐ๋กœ ์ •๋ ฌํ•˜์ง€ ์•Š์•„ ๋ฐœ์ƒ โ†’ keySet์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋ฉด ๋‹น์—ฐํžˆ ์ •๋ ฌ์—†์ด ๊ฐ€์ ธ์™€์ง.
        • ์ด๋Š” keySet์„ ๊ฐ€์ ธ์˜ค๊ณ , ๋‚ ์งœ๋ฅผ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ํ•ด๊ฒฐ

            List<Integer> list = new ArrayList<>(dayTimes.keySet());
            list.sort(Comparator.naturalOrder());
          
          • keySet์„ list๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  sort๋ฅผ ํ†ตํ•ด ์ •๋ ฌ
        • ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๋‚ ์งœ๊ฐ€ ๋’ค์ฃฝ๋ฐ•์ฃฝ๋˜์ง€ ์•Š๊ณ  ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ง„ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์ฝ”๋“œ ์ƒ ๋ˆ„์ ์ด ์ œ๋Œ€๋กœ ์ง„ํ–‰๋จ

<220718>

#63 Bug : ์ฒซ ๋กœ๊ทธ์ธ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜ (session Id ์ด๋™์œผ๋กœ ์ธํ•œ ๋ฌธ์ œ)
#64 Enhancement : static ์„œ๋น„์Šค ๊ธฐ๋Šฅ ์ถ”๊ฐ€ (์ผ์ฃผ์ผ ๊ฐ„์˜ ๊ณต๋ถ€ ํšŸ์ˆ˜, ๊ณต๋ถ€์™•, ์ถœ์„์™• ๊ธฐ๋Šฅ ์ถ”๊ฐ€)

  • #63
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ์ฒซ ๋กœ๊ทธ์ธ ์‹œ (์„ธ์…˜ ์ €์žฅ ์‹œ) ์˜ค๋ฅ˜ ๋ฐœ์ƒ
      • ์„ธ์…˜ ์ €์žฅ ํ›„ ํ•ด๋‹น ๊ฐ’์„ url๋กœ ๋ณด๋‚ด์ง€๋ฉด์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜๋กœ ํŒ๋‹จ (์ฟ ํ‚ค๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ์ƒํ™ฉ์„ ๋Œ€๋น„ํ•œ servlet ์ž๋™ ๊ธฐ๋Šฅ โ†’ traking-modes)
    • ํ•ด๊ฒฐ
      • servlet ์„ค์ •์„ ํ†ตํ•ด ํ•ด๋‹น ์ž๋™ ๊ธฐ๋Šฅ์„ ๋ง‰์Œ (cookie๋กœ ์„ค์ •ํ•จ์œผ๋กœ์จ ์ฟ ํ‚ค๋กœ๋งŒ session์„ ์ธ์‹ํ•˜๊ฒ ๋‹ค๋Š” ์„ค์ •)
        server.servlet.session.tracking-modes: 'cookie'
      
  • #64
    • ์ผ์ฃผ์ผ ๊ฐ„์˜ ๊ณต๋ถ€ ํšŸ์ˆ˜
      • ์ผ์ž๋กœ count ํ•˜๋ฉฐ ๊ณต๋ถ€์‹œ๊ฐ„์ด 0์ธ post๋“ค์— ๋Œ€ํ•ด์„œ counting
      • ๊ทธ ํ›„ 7-cnt ๋กœ ๊ณต๋ถ€ ํšŸ์ˆ˜ ๊ธฐ๋ก
      • ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด๋‹น ๊ฐ’์„ memberDto์— ์ €์žฅ, veiw Template์œผ๋กœ ๋„˜๊ฒจ์คŒ
    • ๊ณต๋ถ€์™•, ์ถœ์„์™• ๊ธฐ๋Šฅ
      • ๊ณต๋ถ€์™• : ์ผ์ฃผ์ผ๊ฐ„์˜ ๋ˆ„์  ๊ณต๋ถ€์‹œ๊ฐ„์ด ๊ฐ€์žฅ ๋งŽ์€ ์‚ฌ๋žŒ
      • ์ถœ์„์™• : ์ผ์ฃผ์ผ๊ฐ„์˜ ๊ณต๋ถ€ ํšŸ์ˆ˜๊ฐ€ ๊ฐ€์žฅ ๋งŽ์€ ์‚ฌ๋žŒ

<220717>

#62 Back : ๋ฐฐ์šด๋‚ด์šฉ์ ์šฉ โ†’ ์ตœ์ ํ™”

  1. Spring Security ์—†์ด ๋กœ๊ทธ์ธ ๊ฐœ๋ฐœ (authentication โ†’ session)
  2. session timeout ์—ฐ์žฅ

#61 Front : ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์ƒ์„ฑ

  • #62-1
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ์ œ๋Œ€๋กœ ๋ฐฐ์šฐ์ง€ ์•Š์€ Spring Security๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๋•Œ ์ œ๋Œ€๋กœ ์ด์šฉํ•˜์ง€ ๋ชปํ•จ (session ์„ค์ • ๋“ฑ) โ†’ ์ถ”ํ›„ ํ•™์Šต ํ›„ ์ ์šฉ ์˜ˆ์ •
    • ํ•ด๊ฒฐ
      • session์„ ์ด์šฉํ•œ login(์ธ์ฆ)์œผ๋กœ ๊ตฌํ˜„ โ†’ ๋กœ๊ทธ์ธ ๊ฒ€์ฆ ๋ฐ ๋กœ๊ทธ์ธ์„ ๋ชจ๋‘ ์ง์ ‘ ๊ตฌํ˜„
      • Spring Security์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  session๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋กœ ๋Œ€์ฒด (๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฝ”๋”ฉ ์ œ์™ธ)
      • ๋กœ๊ทธ์ธ

          @PostMapping("/members/login")
              public String login(@Validated @ModelAttribute("loginForm") LoginForm loginForm, BindingResult bindingResult,
                                  @RequestParam(defaultValue = "/") String redirectURL,
                                  HttpServletRequest request) {...}
        
        • ๋กœ๊ทธ์ธ ์‹œ ์ค‘๊ฐ„์— ๋กœ๊ทธ์ธ ์š”๊ตฌ์— ์˜ํ•ด์„œ ๋กœ๊ทธ์ธ์„ ํ•˜๋Š” ์ƒํ™ฉ์„ ๋Œ€๋น„ํ•ด์„œ redirectURL์„ ๋ฐ›์•„์˜ด (์—†์„ ๊ฒฝ์šฐ ๊ทธ๋ƒฅ home์œผ๋กœ)
        • session์„ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด HttpServletRequest ์ด์šฉ
        • ๋กœ๊ทธ์ธ ๊ฒ€์ฆ

            // form ํ˜•์‹์— ๋งž์ง€ ์•Š์€ ์ œ์ถœ
            if (bindingResult.hasErrors()) {
                return "login";
            }
                          
            // ๋กœ๊ทธ์ธ ๊ฒ€์ฆ         // Global Error -> Object ๋‹จ ์˜ค๋ฅ˜! (์ง์ ‘ ์ฒ˜๋ฆฌํ•ด์•ผ ๋˜๋Š” ๋ถ€๋ถ„)
            Optional<Member> loginMember = memberService.findByLoginId(loginForm.getLoginId());
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            if (loginMember.isEmpty() || !passwordEncoder.matches(loginForm.getPassword(), loginMember.get().getPassword())) {
                bindingResult.reject("loginFail", "์•„์ด๋”” ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ๋งž์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
                return "login";
            }
          
          • Form ํ˜•์‹์— ๋งž์ง€ ์•Š์€ ์ œ์ถœ์—์„œ์˜ ๊ฒ€์ฆ์€ Bean Validation ์‚ฌ์šฉ (FieldError)
          • ์•„์ด๋”” ๋ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ์˜ค๋ฅ˜ ์‹œ ObjectError ๋ฐœ์ƒ ํ›„ veiw Template์œผ๋กœ ๋„˜๊ฒจ ์คŒ
          • Optional์„ ํ†ตํ•ด ์˜ค๋ฅ˜ ๊ฒ€์ฆ
        • ๋กœ๊ทธ์ธ ์„ฑ๊ณต

            // ๋กœ๊ทธ์ธ ์„ฑ๊ณต
            HttpSession session = request.getSession();
            // ์„ธ์…˜์— ๋กœ๊ทธ์ธ ํšŒ์› ์ •๋ณด ๋ณด๊ด€
            session.setAttribute("loginMember", loginMember.get().getId());
            return "redirect:"+ redirectURL;
          
          • ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ session์— ํšŒ์›์ •๋ณด(member id) ์ €์žฅ
          • member ๊ฐ์ฒด ์ž์ฒด๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ , member id๋งŒ์„ ์ €์žฅํ•˜์—ฌ, ์ถ”ํ›„ ์ด๋ฅผ ํ†ตํ•ด repo์—์„œ member๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰
  • #62-2
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • session timeout์„ ์„ค์ •ํ•˜์ง€ ์•Š์•„, ๋„ˆ๋ฌด ์ž์ฃผ ๋กœ๊ทธ์•„์›ƒ๋˜์–ด ์‚ฌ์šฉ ์‹œ ๋ถˆํŽธํ•จ
    • ํ•ด๊ฒฐ
      • spring securrity๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์ง์ ‘ session์„ ์ด์šฉํ•˜๊ณ , session timeout์„ applications.yml ์— ์„ค์ •ํ•˜์—ฌ ๊ด€๋ฆฌ (timeout์„ 10์‹œ๊ฐ„์œผ๋กœ ์„ค์ •)

          server.servlet.session.timeout: 36000
        
  • #61
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ์—†์ด home์—์„œ ๋กœ๊ทธ์ธ์„ ์ง„ํ–‰ํ•˜๋‹ค ๋ณด๋‹ˆ ์“ธ๋ฐ์—†์ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ฃผ๊ณ ๋ฐ›์•„์ง€๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Œ. (home์—์„œ ๋กœ๊ทธ์ธ ์ด์ „์—๋„ ๋‹ค๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ๋กœ๊ทธ์ธ ํ›„์—๋„ ๋‹ค๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Œ. โ†’ ๋น„ ํšจ์œจ์ )
      • redirect๋ฅผ ํ†ตํ•œ ๋กœ๊ทธ์ธ ํ›„ ํŽ˜์ด์ง€ ์ด๋™์ด ๋ถˆ๊ฐ€๋Šฅ.
    • ํ•ด๊ฒฐ
      • ์ผ๋ฐ˜์ ์ธ ์›น์‚ฌ์ดํŠธ์ฒ˜๋Ÿผ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด ์ œ๊ณต
      • ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑ
  • #30
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ์„ธ์…˜ ๋งŒ๋ฃŒ ์‹œ ์—๋ŸฌํŽ˜์ด์ง€ ๋ฐœ์ƒ
      • ์„ธ์…˜ ๋งŒ๋ฃŒ์—๋„ ์„œ๋น„์Šค๋ฅผ ์œ ๋™์ ์œผ๋กœ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ›„ redirect๋ฅผ ํ†ตํ•ด ๋˜๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์ด ํ•„์š”
    • ํ•ด๊ฒฐ
      • Interceptor์—์„œ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๋Š” request์— redirectURL query parameter๋ฅผ ์ถ”๊ฐ€.
      • ๋กœ๊ทธ์ธ ํ›„ ํ•ด๋‹น redirectURL query parameter ๋ฅผ ํ†ตํ•ด ์ด์ „ ํŽ˜์ด์ง€๋กœ ๋˜๋Œ์•„๊ฐ.
      • response.sendRedirect( "/members/login?redirectURL=" + request.getRequestURI())
      • @RequestParam(name = "redirectURL", defaultValue = "/") String redirectURL โ†’ return "redirect:" + redirectURL

<220714>

#48 Enhancement : ์ƒˆ๋กœ์šด ๋Œ€์‹œ๋ณด๋“œ (Static ์„œ๋น„์Šค ๊ฐœ์„ )

  • #48
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

      ํŒŒ์ด์ฌ์œผ๋กœ ํ†ต๊ณ„๋‚ด์–ด ํ•ด๋‹น ๊ทธ๋ž˜ํ”„๋ฅผ ์‚ฌ์ง„์œผ๋กœ ์ €์žฅํ•˜๊ณ , ๊ทธ ์‚ฌ์ง„์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ํ˜•์‹์œผ๋กœ ์ง„ํ–‰, ํ•˜์ง€๋งŒ ์ด๋Š” ํ†ตํ•ฉ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉฐ, ์‚ฌ์ง„์œผ๋กœ ๋ณด์ž„์œผ๋กœ์จ ๋ถ€๊ฐ€์ ์ธ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜์ง€ ๋ชปํ•จ

    • ํ•ด๊ฒฐ

      • javascript๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ˜•์‹์œผ๋กœ ์ง„ํ–‰.
      • Model๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์•„์™€ thymeleaf in javascript ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ด์šฉ
      • ๋ฉค๋ฒ„๋‹น ์ตœ๊ทผ 1์ฃผ์ผ post๋ฅผ ๊ฐ€์ ธ์™€ ํ•ด๋‹น post์˜ ๋ชจ๋“  ์‹œ๊ฐ„์„ ๋”ํ•œ ์‹œ๊ฐ„์„ ์ ์šฉ
        • ์ค‘์š”ํ•œ ์ ์€ ์ƒˆ๋ฒฝ4์‹œ๋ฅผ ํ•˜๋ฃจ์˜ ๋๊ณผ ์‹œ์ž‘์œผ๋กœ ์ •ํ–ˆ๊ธฐ๋•Œ๋ฌธ์—, ์š”์ฒญ ์‹œ๊ฐ„์ด 0~4์‹œ ์‚ฌ์ด์ผ ๊ฒฝ์šฐ์™€ ๋‚˜๋จธ์ง€ ์‹œ๊ฐ„์ผ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ๊ตฌ๋ถ„ ํ•„์š”
      • ๊ทธ๋ž˜ํ”„๋กœ๋Š” ๋ˆ„์  ์‹œ๊ฐ„์„ ๋ณด์—ฌ์คŒ
      • ์ถ”๊ฐ€๋กœ ํ•ด๋‹น ์ผ์ฃผ์ผ๊ฐ„์˜ ๋ˆ„์  ์‹œ๊ฐ„์— ๋Œ€ํ•œ ๋žญํ‚น ํ‘œ์‹œ
      • StaticController ์ฃผ์š” ์ฝ”๋“œ

          @GetMapping("/data")
          public String data(Model model, Authentication authentication) throws IOException {
              if (authentication == null) {
                  return "redirect:/";
              }
              List<MemberDto> members = memberService.findAll().stream().map(MemberDto::new).collect(Collectors.toList());
              Map<MemberDto, Map<Integer, Times>> memberStatic = new HashMap<>();
              List<Integer> days = getDays(LocalDateTime.now());
              for (MemberDto member : members) {
                  Map<Integer, Times> staticsData = getStaticsData(member);
                  memberStatic.put(member, staticsData);
                  member.setTime(staticsData.get(days.get(days.size()-1)));
                  if (member.getTime().getHour() != 0) {
                      Random rand = new Random();
                      int r = rand.nextInt(255);
                      int g = rand.nextInt(255);
                      int b = rand.nextInt(255);
                      member.setColor("rgba(" + String.valueOf(r) + "," + String.valueOf(g) + "," + String.valueOf(b) + "," + "1)");
                  } else {
                      member.setColor("rgba(236,236,236,1)");
                  }
              }
                    
              members.sort(new TimeSorter()); 
          	  ...
          }
        
        • getDays : ๊ทธ๋ž˜ํ”„์— ํ‘œ์‹œํ•  ๋‚ ์งœ๋ชจ์Œ(์ผ)
        • getStaticData : ๊ทธ๋ž˜ํ”„์— ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
          • 0~4์‹œ์˜ ์š”์ฒญ : 8์ผ์ „ ~ ์ดํ‹€์ „ ๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
          • ์ด์™ธ์˜ ์š”์ฒญ : 7์ผ์ „ ~ ํ•˜๋ฃจ ์ „ ๊นŒ์ง€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด
          • ์ถ”๊ฐ€๋กœ ๋‚ ์งœ๋งˆ๋‹ค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๊ธฐ ์œ„ํ•ด HashMap ์‚ฌ์šฉ (key: ๋‚ ์งœ, value: ์‹œ๊ฐ„) ์ด๋•Œ, ํ•ด๋‹น ๋‚ ์งœ์˜ post๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ๋ฐ›์•„ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ • (๋ˆ„์  ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ)
        • ๋˜ํ•œ ๊ฐ ๋ฉค๋ฒ„๋ณ„๋กœ ๋žœ๋คํ•œ ์ƒ‰๊น”์„ ์„ค์ •ํ•˜์—ฌ ๊ฐ ๋ฉค๋ฒ„๋ณ„์˜ ๊ทธ๋ž˜ํ”„๊ฐ€ ๊ตฌ๋ถ„ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •
        • ๊ทธ ํ›„ ๋žญํ‚นํ‘œ์‹œ๋ฅผ ์œ„ํ•ด TimeSorter๋กœ ์ •๋ ฌ
      • Javascript ์ฃผ์š” ์ฝ”๋“œ

          var datasets = [];
          [# th:each="user, stat : ${staticsDataMap}"]
          var user[[${stat.count}]] = [[${user.value}]];
          if (user[[${stat.count}]][staticDays[6]].hour !== 0) {
              datasets.push({
                  label: [[${user.key.name}]],
                  lineTension: 0.3,
                  backgroundColor: "rgba(33,37,41,0)",
                  borderColor: [[${user.key.color}]],
                  pointRadius: 3,
                  pointBackgroundColor: [[${user.key.color}]],
                  pointBorderColor: [[${user.key.color}]],
                  pointHoverRadius: 3,
                  pointHoverBackgroundColor: [[${user.key.color}]],
                  pointHoverBorderColor: [[${user.key.color}]],
                  pointHitRadius: 10,
                  pointBorderWidth: 2,
                  data: [user[[${stat.count}]][staticDays[0]].hour + Math.round(user[[${stat.count}]][staticDays[0]].min/60),
                      user[[${stat.count}]][staticDays[1]].hour+ Math.round(user[[${stat.count}]][staticDays[1]].min/60),
                      user[[${stat.count}]][staticDays[2]].hour+ Math.round(user[[${stat.count}]][staticDays[2]].min/60),
                      user[[${stat.count}]][staticDays[3]].hour+ Math.round(user[[${stat.count}]][staticDays[3]].min/60),
                      user[[${stat.count}]][staticDays[4]].hour+ Math.round(user[[${stat.count}]][staticDays[4]].min/60),
                      user[[${stat.count}]][staticDays[5]].hour+ Math.round(user[[${stat.count}]][staticDays[5]].min/60),
                      user[[${stat.count}]][staticDays[6]].hour+ Math.round(user[[${stat.count}]][staticDays[6]].min/60)],
              });
          }
                    
          [/]
                    
          var myLineChart = new Chart(ctx, {
                  type: 'line',
                  data: {
                      labels: [staticDays[0]+'์ผ',staticDays[1]+'์ผ',staticDays[2]+'์ผ',staticDays[3]+'์ผ',staticDays[4]+'์ผ',staticDays[5]+'์ผ',staticDays[6]+'์ผ'],
                      datasets: datasets,
                  },
          ...})
        
        • thymeleaf in javascript ๊ธฐ์ˆ ์˜ for each ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ user๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น user์˜ ๋ฐ์ดํ„ฐ๋ฅผ dataset์— ๋„ฃ์–ด ๊ทธ๋ž˜ํ”„์— ๋Œ€์ž….

<220713>

#42 Enhancement: ํ•˜๋ฃจ ๊ณต๋ถ€์‹œ๊ฐ„ ๋žญํ‚น
#62 Back : MVC ์ตœ์ ํ™”

  • #42
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

      ์šฐ์ธก ์•„ํ‹ฐํด์—์„œ ๋ˆ„์  ๊ณต๋ถ€์‹œ๊ฐ„ ๊ทธ๋ž˜ํ”„๋ฅผ ์‚ฌ์ง„์œผ๋กœ ๋Œ€๋žต์ ์œผ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋ถ€๋ถ„์ด ์žˆ์—ˆ์œผ๋‚˜ ์‚ฌ์‹ค์ƒ ์˜๋ฏธ๊ฐ€ ์—†๋Š” ๊ธฐ๋Šฅ์ด์˜€์œผ๋ฉฐ, ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ์‚ฌ์ง„์ด ์•„๋‹Œ js๋กœ ๊ตฌ์„ฑํ•˜๊ธฐ๋กœ ๊ฒฐ์ •. ์ถ”๊ฐ€๋กœ ๊ณต๋ถ€ ๋™๊ธฐ๋ถ€์—ฌ๋ฅผ ๋†’์—ฌ์ฃผ๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์ด ํ•„์š”ํ–ˆ์Œ

    • ํ•ด๊ฒฐ (ํ•˜๋ฃจ ๊ณต๋ถ€์‹œ๊ฐ„ ๋žญํ‚น์œผ๋กœ ๋Œ€์ฒด)

      • ๊ธฐ์กด์˜ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋ฃจ ๊ณต๋ถ€์‹œ๊ฐ„ ๊ณ„์‚ฐ ๋กœ์ง(getTotalStudyTimes())์„ ์ด์šฉ
      • ์ด ๋กœ์ง์„ ๋ชจ๋“  Member๋“ค์—๊ฒŒ ์ ์šฉํ•˜์—ฌ ๊ฐ Member์˜ ํ•˜๋ฃจ ๊ณต๋ถ€์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•˜๋„๋ก ์ง„ํ–‰

          for (MemberDto m : memberDtos) {
              Optional<Post> eachOptionalPost = postService.getRecentPost(m.getId());
              PostViewDto memberRecentPostDto = eachOptionalPost.map(PostViewDto::new).orElse(null);
              if (memberRecentPostDto != null) {
                  m.setTime(getTotalStudyTimes(memberRecentPostDto));
              } else {
                  m.setTime(null);
              }
          }
        
      • ์ด ์‹œ๊ฐ„์„ ๊ฐ๊ฐ์˜ MemberDto์˜ time property์— ์ €์žฅ ํ›„ ์ด๋ฅผ View Template์—์„œ ๋ฐ›์•„, ์ด์šฉ.
      • ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€, ํ•˜๋ฃจ ๊ณต๋ถ€์‹œ๊ฐ„ ๋žญํ‚น์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋“ค์„ ์‹œ๊ฐ„(Times)์— ๋”ฐ๋ผ ์ •๋ ฌ์ด ํ•„์š” โ†’ custom Comparator(TimeSorter) ์ƒ์„ฑ ํ›„ sort ์ ์šฉ

          public class TimeSorter implements Comparator {
            @Override
            public int compare(Object o1, Object o2) {
                //o1 - o2 = ASC , o2 - o1 = DESC
                MemberDto m1 = (MemberDto) o1;
                MemberDto m2 = (MemberDto) o2;
                int totalTime1 = 0;
                int totalTime2 = 0;
                if (m1.getTime() != null) totalTime1 = m1.getTime().getHour() * 60 + m1.getTime().getMin();
                if (m2.getTime() != null) totalTime2 = m2.getTime().getHour() * 60 + m2.getTime().getMin();
                return totalTime2 - totalTime1;
            }
          }
        
        • Times๊ฐ€ hour์™€ min์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ด๋ฅผ ๋ชจ๋‘ minute์œผ๋กœ ๋ณ€๊ฒฝ ํ›„ ์ด๋“ค์— ๋Œ€ํ•œ ์ •๋ ฌ์„ ์‹คํ–‰.
          List<MemberDto> memberRanking = new ArrayList<>(memberDtos);
          memberRanking.sort(new TimeSorter());
        
  • #62
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 
      • ํŽ˜์ด์ง•์— ๋”ฐ๋ฅธ Controller๊ฐ€ ์กด์žฌ โ†’ ๋ฒˆ์žกํ•œ ๊ตฌ์„ฑ
      • Static ํ™”๋ฉด๋„ HomeController์— ์กด์žฌ โ†’ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ ํ•„์š”
    • ํ•ด๊ฒฐ
      • ํŽ˜์ด์ง• Controller ํ†ตํ•ฉ โ†’ @RequestMapping({"/", "/{page}"}) , @PathVariable(name = "page", required = false) Integer page , if (page == null) page = 1;
        • url๋กœ ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ ์—†๋‹ค๋ฉด 1๋กœ ์„ค์ •ํ•˜์—ฌ main์€ page 1๋กœ ๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • StaticController ์ƒ์„ฑ โ†’ (HomeController์™€ ๋ถ„๋ฆฌ)

<220618> ~ <220630>

  • Spring MVC ์ง‘์ค‘ ๊ณต๋ถ€! (๊ฐ•์˜ ๋ฐ ๊ฐœ์ธ ํ•™์Šต์œผ๋กœ ์ธํ•ด ๊ฐ•์˜์—์„œ ์ง„ํ–‰ํ•œ ๊ฐœ๋ฐœ ์˜์™ธ์˜ ๊ฐœ๋ฐœ์€ ์ง„ํ–‰ํ•˜์ง€ ์•Š์Œ)
  • ์ถ”ํ›„ ํ•ด๋‹น ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ Semogong Project๋ฅผ Upgrade ์‹œํ‚ฌ ์˜ˆ์ •

<220615>

Front : ์‚ฌ์šฉ์ž ํŽธ์˜๋ฅผ ์œ„ํ•œ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€

  • ํ˜„์žฌ ๋ฌธ์ œ์ 
    • Home ํ™”๋ฉด์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  ์žˆ๋Š” Point๊ฐ€ ์–ด๋”˜์ง€ ํ™•์ธ ๋ถˆ๊ฐ€
    • Static ํ™”๋ฉด์—์„œ ํ˜„์žฌ ์ธ์›์ด ๋ณ€๊ฒฝ๋˜๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ ๋ถˆ๊ฐ€
  • ํ•ด๊ฒฐ
    • Home ํ™”๋ฉด์€ ํ•ด๋‹น Point์— ๋ฌผ๊ฒฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ˜„์žฌ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•˜๊ณ  ์žˆ๋Š” ์ง€์ ์— ๋Œ€ํ•ด Focusํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
    • Static ํ™”๋ฉด์€ Live ๋ฒ„ํŠผ์— ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์žˆ์œผ๋ฉด ์ดˆ๋ก์ƒ‰ ๊นœ๋นก์ž„์„ ์ฃผ์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜์˜๋˜๊ณ  ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

<220614>

Back : ์ธํ„ฐ์…‰ํ„ฐ๋ฅผ ํ†ตํ•œ ์ตœ์ ํ™”

  • ํ˜„์žฌ ๋ฌธ์ œ์ 
    • ํ˜„์žฌ Temp โ†’ Info๋กœ ๋ฐ”๊พธ๋Š” ๋กœ์ง์€ ํ•œ ์„œ๋น„์Šค๊ฐ€ ์‹œ์ž‘๋  ๋•Œ ๋ชจ๋“  Temp๋ฅผ Info๋กœ ๋ฐ”๊พธ๋Š” ์‹์˜ ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ ์ค‘
    • ํ•˜์ง€๋งŒ ํ˜„์žฌ ๋ฐฉ์‹์€ ์‚ฌ์‹ค์ƒ ๋น„ํšจ์œจ์ ์ž„. ๋ชจ๋“  DB๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๋ณด๋‹ค, ์ตœ๊ทผ ์š”์ฒญ์‹œ์ ์„ ๊ธฐ์–ตํ•˜๊ณ  ๊ทธ ์ดํ›„๋กœ ์ƒˆ๋กœ ๋“ค์–ด์˜จ Temp๋“ค๋งŒ์„ Info๋กœ ๋ฐ”๊พธ๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”
  • ํ•ด๊ฒฐ
    • Point์— ์ตœ๊ทผ Info์˜ ๋ณ€๊ฒฝ์‹œ์ ์„ ๊ธฐ๋กํ•˜์—ฌ
    • ํ•ด๋‹น ๋ณ€๊ฒฝ์‹œ์  ์ดํ›„์— ์ƒˆ๋กœ์šด Temp๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ํ•ด๋‹น Temp๋ฅผ Info๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰
    • ๋˜ํ•œ ์ด๋Š” ์–ด๋–ค ์„œ๋น„์Šค๋“  ์‹œ์ž‘๋ ๋•Œ ์ ์šฉ์ด ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ์ธํ„ฐ์…‰ํ„ฐ ๊ฐœ๋… ๋„์ž…
  • UpdateInterceptor

      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
          List<Point> pointList = pointService.findAll(); // find all Point
          for (Point point : pointList) { // each point
              infoService.createInfo(point.getId()); // make ์—ฐ๊ด€๊ด€๊ณ„ with Point (์ƒˆ๋กœ ์ƒ์„ฑ๋œ Temp๋“ค์— ๋Œ€ํ•ด์„œ ์ƒˆ๋กœ์šด Info ์ƒ์„ฑ)
              pointService.updatePoint(point.getId()); // point์˜ lastCommittedTime update (์ตœ๊ทผ Info update ์‹œ๊ฐ„ update)
          }
          return true;
      }
    
    • CheckPoint ์ดํ›„ ์ƒˆ๋กœ ์ƒ์„ฑ๋œ Temp๋“ค์— ๋Œ€ํ•ด์„œ ์ƒˆ๋กœ์šด Info ์ƒ์„ฑ
    • CheckPoint Update
    • ๋งˆ์ง€๋ง‰์œผ๋กœ WebConfig๋ฅผ ํ†ตํ•ด Interceptor ๋“ฑ๋ก

<220612>

Enhancement : ๋ˆ„์  ํ†ต๊ณ„ ์ •๋ณด ์กฐํšŒ ๊ฐœ๋ฐœ

  • Static์—์„œ ๋ณด์—ฌ์ค„ ๋ˆ„์  ํ†ต๊ณ„ ์ •๋ณด์— ๋Œ€ํ•œ ๊ฐœ๋ฐœ ์ง„ํ–‰
  • ํ†ต๊ณ„ ๋กœ์ง
    • ํ•ด๋‹น Point์— ๋Œ€ํ•œ ๋ชจ๋“  Info๋ฅผ ์กฐํšŒ
    • ์กฐํšŒํ•œ ํ›„ ๋‚ ์งœ๋ณ„๋กœ Info๋ฅผ ๋‚˜๋ˆ„๊ณ  ํ•ด๋‹น ๋‚ ์งœ์— ๋Œ€ํ•œ Info ๊ฐœ์ˆ˜์˜ ํ‰๊ท ์น˜๋ฅผ model์— ๋‹ด์•„ rendering
    • ์ผ์ฃผ์ผ๊ฐ„์˜ ๋ฐ์ดํ„ฐ, ์‹œ๊ฐ„๋ณ„ ๋ฐ์ดํ„ฐ ๋ชจ๋‘ ํ•œ๊ณณ์— ์ €์žฅ
    • ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ Pie,Arial Chart ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” js ์— ํ• ๋‹น (ํƒฌํ”Œ๋ฆฟ ์ด์šฉ)

<220610>

Back : Temp, Info Repository, Service ์žฌ์ •์˜

  • Temp, Info Repository, Service ์žฌ์ •์˜
    • ๊ธฐ์กด์— ์‚ฌ์šฉํ–ˆ๋˜ Info์˜ Domain, Service, Repository๋ฅผ ๋ชจ๋‘ Temp๋กœ ์ด์ „, ๊ทธ ํ›„ Info Repository, Service ์ƒˆ๋กœ ์ •์˜
    • ํ•ต์‹ฌ์€ Temp๋กœ ๋ฐ›์•„์˜จ ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ๋ฅผ Info๋กœ ๋ฐ”๊พธ์–ด ์ €์žฅํ•˜๋Š” ๊ฒƒ. ์ฆ‰, Temp์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฐ›์•„์™€ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๊ณ  Entity๋กœ์จ ๊ด€๋ฆฌ๋˜๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ
  • Info Repository
    • ์ €์žฅ๋งŒ ํ•˜๋ฉด ๋จ (์กฐํšŒ๋Š” ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๋งบ์€ Point๋กœ ์ง„ํ–‰) โ†’ em.persist(info)
  • Info Service
    • Info ์ƒ์„ฑ ๋ฉ”์„œ๋“œ๋งŒ ์กด์žฌ โ†’ (๋งคํ•‘ ๋กœ์ง: ) ํ•ด๋‹น ๊ตฌ์—ญ์— ๋”ฐ๋ผ Point์™€ ๋งคํ•‘์‹œ์ผœ์ค€ ํ›„ ์ €์žฅ. ๊ทธ ๊ฒฐ๊ณผ๋กœ ์ธก์ •๋œ ์ˆ˜์น˜๋“ค์„ ๋ฐ”ํƒ•์œผ๋กœ Point๋ฅผ ์ˆ˜์ •

<220609>

Back : ์ด์ „ Info ๋ฐ์ดํ„ฐ์™€ Point์˜ ์—ฐ๊ด€๊ด€๊ณ„ ์ƒ์„ฑ ํ•„์š” Back : Temp, Info Domain ์žฌ์ •์˜

  • ๋ฐœ๊ฒฌ๋œ ๋ฌธ์ œ์ 
    • ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ›์•„์˜ค๋Š” Info๋ฅผ ๊ทธ ์ฆ‰์‹œ Floating ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ์€ ๊ฐ€๋Šฅํ•˜๋‚˜, Info์˜ ๊ณผ๊ฑฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์ด๋ฏธ ํ•œ๋ฒˆ ๋งคํ•‘๋˜์—ˆ๋˜ Point์™€ ๋‹ค์‹œ ํŒ๋‹จ ๋กœ์ง์„ ํ†ตํ•ด ๋งคํ•‘์ด ํ•„์š”ํ•จ
    • ๋˜ํ•œ Info๊ฐ€ Entity๋กœ์จ ์ €์žฅ๋˜์ง€ ์•Š์•˜๊ธฐ์— ๋ฐœ์ƒํ•˜๋Š” ๋ถˆํŽธํ•จ ํ•ด๊ฒฐ ํ•„์š”
  • ํ•ด๊ฒฐ๋ฒ•
    • ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ƒˆ๋กœ Entity๋กœ ๊ด€๋ฆฌ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑ โ†’ Temp๋ผ๋Š” Object๋กœ ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ ๋ฐ›์•„์˜ด
    • ์ถ”๊ฐ€๋กœ Info๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ point์™€ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๋งบ์–ด ์„œ๋กœ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

        //==์—ฐ๊ด€๊ด€๊ณ„ ๋ฉ”์„œ๋“œ==//
        private void setPoint(Point point) {
            this.point = point;
            point.getInfos().add(this);
        }
      
    • ๊ธฐ์กด์— ์‚ฌ์šฉํ–ˆ๋˜ Info์˜ Domain, Service, Repository๋ฅผ ๋ชจ๋‘ Temp๋กœ ์ด์ „, ๊ทธ ํ›„ Info ์ƒˆ๋กœ ์ •์˜

<220608>

Front : Home, Static ํ™”๋ฉด ์ˆ˜์ • Back : HomeRestController ๊ฐœ๋ฐœ

  • Home, Static ํ™”๋ฉด ์ˆ˜์ •
    • Home
      • Kakao Map API๋ฅผ ์ด์šฉํ•œ ์ง€๋„์— Point์˜ ์ขŒํ‘œ๋ฅผ ๋งคํ•‘์‹œ์ผœ floating
      • ๊ฐ Point๋“ค์— ๋Œ€ํ•œ ์‹ค์‹œ๊ฐ„ ๋ณ€๋™๋Ÿ‰ ํ‘œ์‹œ๋ฅผ ์œ„ํ•œ ๊ฐœ๋ฐœ โ†’ ajax ๋น„๋™๊ธฐ ํ†ต์‹ , REST API ์ด์šฉ โ†’ REST API ๋ฅผ ์œ„ํ•œ Controller ๊ฐœ๋ฐœ ํ•„์š”
        $( document ).ready(function detection_change() {
            interval = setInterval(function () {
                $.ajax({
                    url: '/infos',
                    type: "GET"
                })
                    .done(function (response) { ... //๋กœ์ง }
        })
      
    • Static
      • ์‹ค์‹œ๊ฐ„ ์ธ์› ์ธก์ •๋Ÿ‰ ํ‘œ์‹œ (๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋ณผ ์ˆ˜ ์žˆ๊ณ , ์•„๋‹ˆ๋ฉด ์•ˆ๋ณด์—ฌ์ฃผ๋Š” ๋А๋‚Œ์œผ๋กœ ์ง„ํ–‰ โ†’ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด interval ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ 3์ดˆ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญ, JSON์œผ๋กœ ๊ฐ’์„ ๋ฐ›์•„์˜ด)
      • ์ด ๋˜ํ•œ ajax ๋น„๋™๊ธฐ ํ†ต์‹ , REST API ์ด์šฉ โ†’ REST API ๋ฅผ ์œ„ํ•œ Controller ๊ฐœ๋ฐœ ํ•„์š”
  • HomeRestController ๊ฐœ๋ฐœ
    • REST API ๋ฅผ ์œ„ํ•œ Controller ๊ฐœ๋ฐœ (@RestController)
    • Homeํ™”๋ฉด๊ณผ Static ํ™”๋ฉด์— ๋ฟŒ๋ ค์ค„ JSON ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ๋ฐ ๋ฐ˜ํ™˜
    • JSON ๋ฐ์ดํ„ฐ๋Š” ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ธก์ •๋œ ์ธ์›์˜ ์ˆ˜๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” count์™€ ์ด ๋ฐ์ดํ„ฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฐ˜ํ™˜ (Result<T> ์‚ฌ์šฉ)

<220606>

Back : HomeController ๊ฐœ๋ฐœ

  • ๊ณตํ†ต
    • Home ํ™”๋ฉด์ด๋“  Static ํ™”๋ฉด์ด๋“  ๋ชจ๋“  Point๋“ค์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— point list๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ Model์— ์ถ”๊ฐ€ํ•ด์คŒ. (@ModelAttribute ์‚ฌ์šฉ)
  • Home
    • API๋ฅผ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ Model์— ์ถ”๊ฐ€ํ•ด์ค„ ๊ฒƒ๋“ค์ด ์—†์Œ.
    • Point List๋Š” ๋ฏธ๋ฆฌ ์ถ”๊ฐ€๋œ ์ƒํƒœ์˜ model ์‚ฌ์šฉ
  • Statics
    • ๊ฒ€์ƒ‰ํ•ด์„œ ๋“ค์–ด์˜ค๋Š” ์ƒํ™ฉ๊ณผ, ๊ธฐ๋ณธ static ํ™”๋ฉด ๋ถ„๋ฆฌ (๋ฐ์ดํ„ฐ ๋ถ„๋ฆฌ)
    • ๊ทธ์— ๋Œ€ํ•œ ์ถ”๊ฐ€์ ์ธ ์ •๋ณด(Live Count) ๋“ฑ ์ถ”๊ฐ€
    • ์ถ”๊ฐ€์ ์œผ๋กœ ํ•„์š”ํ•œ ๋ถ€๋ถ„ : ๋ฐ์ดํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋ˆ„์ ํ†ต๊ณ„ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ํ•„์š”.

<220605>

Back : Info Service, Repository ๊ฐœ๋ฐœ

  • Info ๋„๋ฉ”์ธ์˜ ์ฃผ์˜์ 
    • ์ด๋ฏธ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ floatingํ•˜๋Š” ์—ญํ• 
    • ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋”ฐ๋กœ ์ €์žฅํ•  ํ•„์š”๋Š” ์—†๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์—ญํ• ๋งŒ ํ•˜๋ฉด ๋จ
    • ์—ฌ๊ธฐ์„œ ๊ธฐ์กด์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„  JpaRepository, NativeQuery ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๋จ
  • ๊ฐœ๋ฐœ
    • 10์ดˆ~ํ˜„์žฌ ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” method โ†’ static ํ™”๋ฉด์—์„œ ์‚ฌ์šฉ

        @Query(value = "SELECT * " +
                    "FROM temp t " +
                    "where t.date >= DATE_SUB(CONVERT_TZ(NOW(),'SYSTEM','Asia/Seoul'), INTERVAL 10 SECOND);", nativeQuery = true)
            List<Temp> getLiveData();
      
      • ํ•ด๋‹น Entity๋กœ ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ธฐ์กด์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ JpaRepository, NativeQuery ์‚ฌ์šฉ
      • 10์ดˆ ์ „~ํ˜„์žฌ์˜ ๋ˆ„์  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ด โ†’ DATE_SUB() sql๋ฌธ ์‚ฌ์šฉ
    • ์ €์žฅ์€ ๋”ฐ๋กœ ํ•„์š”์—†์Œ

<220604>

Back : Basic Point Service, Repository ๊ฐœ๋ฐœ

  • Repository ๋‹จ
    • ์ •ํ•ด์ง„ ์ง€์ ์— ๋Œ€ํ•ด์„œ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— @PostConstruct๋ฅผ ํ†ตํ•ด ๋ฏธ๋ฆฌ DB ์ €์žฅ. (1ํšŒ์„ฑ initDB)
    • ๋‹ค๊ฑด์กฐํšŒ, ๋‹จ๊ฑด์กฐํšŒ, ์ด๋ฆ„์œผ๋กœ ์กฐํšŒ. 3๊ฐ€์ง€ method ์ƒ์„ฑ
  • Service ๋‹จ
    • ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์˜ ์—ญํ• ์„ ๋‹จ์ˆœ ์œ„์ž„
  • ์ถ”๊ฐ€ํ•  ์ 
    • ํ˜„์žฌ๋Š” ๋ˆ„์ ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๊ธฐ์— ๋ˆ„์ ํ†ต๊ณ„๋Ÿ‰์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ Repository๋‚˜ Service๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์ง€์•Š์Œ โ†’ ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋А์ •๋„ ๋ˆ„์ ๋œ ์ดํ›„ ๊ฐœ๋ฐœ ํ•„์š”

<220602>

Back : Domain ๊ฐœ๋ฐœ

  • ํ•„์š”์„ฑ
    • ํ˜„์žฌ ํ•„์š”ํ•œ ๋ถ€๋ถ„์€ ์žฅ์†Œ(๊ฒ€์ถœ ์ง€์ )๋ฅผ ์—ฐ๊ฒฐํ•  Point์™€ ์‹ค์‹œ๊ฐ„์œผ๋กœ DB์— ์ ์žฌ๋˜๋Š” ๊ฒ€์ถœ๊ฐ์ฒด์ •๋ณด๋ฅผ ์—ฐ๊ฒฐํ•  Info๊ฐ€ ํ•„์š”
  • ๊ฐœ๋ฐœ ๊ณผ์ •
    • Point ๋„๋ฉ”์ธ ๊ฐœ๋ฐœ
      • field ์„ค์ •, ์ƒ์„ฑ ๋ฐ ์ˆ˜์ • ๋ฉ”์„œ๋“œ ์ƒ์„ฑ
    • Info ๋„๋ฉ”์ธ ๊ฐœ๋ฐœ
      • ๊ธฐ์กด์˜ DB์™€ ์—ฐ๊ฒฐ
      • field ์„ค์ •, ์ƒ์„ฑ ๋ฐ ์ˆ˜์ • ๋ฉ”์„œ๋“œ ์ƒ์„ฑ

<220601>

Front : ํƒฌํ”Œ๋ฆฟ ์ปค์Šคํ…€ (home, static)

  • ํ”„๋ก ํŠธ๋ฅผ ์ „๋ฌธ์ ์œผ๋กœ ํ•˜๋Š” ์ธ์›์ด ์—†์–ด, ๋ฌด๋ฃŒ๋กœ ์ œ๊ณต๋˜๋Š” ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •. ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ ์ž ํ•˜๋Š” ์„œ๋น„์Šค์— ๋งž๋Š” ๋Œ€์‹œ๋ณด๋“œ ํƒฌํ”Œ๋ฆฟ์„ ๋ฐ›์•„์™€ ์ปค์Šคํ…€.
  • ์—ฌ๋Ÿฌ html ํŒŒ์ผ ์ค‘ home ํ™”๋ฉด๊ณผ static ํ™”๋ฉด๋งŒ ์‚ด๋ฆฌ๊ณ  ์ด๋“ค์— ๋Œ€ํ•ด ์ปค์Šคํ…€ ์ง„ํ–‰.

<2205010> ~ <220530>

  • Spring MVC ์ง‘์ค‘ ๊ณต๋ถ€! (๊ฐ•์˜ ๋ฐ ๊ฐœ์ธ ํ•™์Šต์œผ๋กœ ์ธํ•ด ๊ฐ•์˜์—์„œ ์ง„ํ–‰ํ•œ ๊ฐœ๋ฐœ ์˜์™ธ์˜ ๊ฐœ๋ฐœ์€ ์ง„ํ–‰ํ•˜์ง€ ์•Š์Œ)
  • ์ถ”ํ›„ ํ•ด๋‹น ๊ณต๋ถ€ํ•œ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ Semogong Project๋ฅผ Upgrade ์‹œํ‚ฌ ์˜ˆ์ •

<220508>

Tag : version 1.0.11
#39 Enhancement : ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„ reload ๋ฒ„ํŠผ ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ถ”๊ฐ€

  • #39
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ : ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„ reload ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋„ ์ž˜ ๋ˆŒ๋ ค์กŒ๋Š”์ง€๋ฅผ ํ™•์ธํ•  ๋ฐฉ๋ฒ•์ด ์—†์—ˆ์Œ โ†’ alert์„ ํ•˜๋ คํ–ˆ์ง€๋งŒ, alert์€ ๋œจ๋ฉด ๊บผ์•ผ๋œ๋‹ค๋Š” ๊ท€์ฐฎ์Œ ํ™•์ธ
    • ํ•ด๊ฒฐ : reload ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ๊ฒฝ์šฐ, reload img ๊ฐ€ 360๋„ rotate ๋˜๋ฉด์„œ ์‹œ๊ฐ์ ์œผ๋กœ ์žฌ๋ถ€ํŒ… ๋˜๋Š” ํšจ๊ณผ ์ œ๊ณต โ†’ <img id="reload" src="/images/reload.png" height="20px" width="20px">

        .reload {
            transform:             rotate( 360deg );
            -moz-transform:    rotate( 360deg );
            -ms-transform:     rotate( 360deg );
            -o-transform:      rotate( 360deg );
            -webkit-transform: rotate( 360deg );
            transition:             transform 1000ms ease;
            -moz-transition:    -moz-transform 1000ms ease;
            -ms-transition:     -ms-transform 1000ms ease;
            -o-transition:      -o-transform 1000ms ease;
            -webkit-transition: -webkit-transform 1000ms ease;
        }
      
        var rotate = document.getElementById('reload')
              
        if (rotate) {
            rotate.addEventListener('click', function() {
                this.className = 'reload';
                window.setTimeout(function() {
                    rotate.className = ''
                }, 1000);
            }, false);
        }
      

<220507>

#39 Front : ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„ reload ๊ธฐ๋Šฅ ์ถ”๊ฐ€
#39 Bug : 23์‹œ, 00์‹œ์˜ ์ฐจ์ด ์˜ค๋ฅ˜ ํ•ด๊ฒฐ

  • #39

    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : ํ˜„์žฌ ๊ณต๋ถ€์‹œ๊ฐ„์„ ํ™•์ธํ•˜๋ ค๋ฉด ๋ฌด์กฐ๊ฑด home์„ reloadํ•ด์•ผ ๋˜๋Š” ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์„ ์„ ํƒํ•ด์•ผ ํ–ˆ์Œ. โ†’ ๋„คํŠธ์›Œํฌ, ๋ Œ๋”๋ง ๊ณผ๋ถ€ํ™” ๊ฐ€๋Šฅ
    • ํ•ด๊ฒฐ : ํ•™์Šต ์‹œ๊ฐ„ ์ž์ฒด์— reload ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ ajax api ํ†ต์‹ ์„ ํ†ตํ•ด ํ•ด๋‹น ๊ณ„์‚ฐ๋œ ํ•™์Šต ์‹œ๊ฐ„๋งŒ ๋ฐ›์•„์™€ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

        function reload_times(memberId) {
            $.ajax({
                url: 'members/times/' + memberId,
                type: "GET"
            })
                .done(function (response) {
                    $('#member_time').replaceWith(
                        '<div id="member_time"> ์˜ค๋Š˜์˜ ํ•™์Šต ์‹œ๊ฐ„ : ' + response.hour + '์‹œ๊ฐ„ '+ response.min +'๋ถ„ </div>'
                    )
                })
        }
      

<220506>

Tag : version 1.0.10
#2 Bug : ๋Œ“๊ธ€ submit enter ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •, apple์—์„œ์˜ ์˜ค๋ฅ˜ ์ˆ˜์ •
#39 Enhancement : post edit ์‹œ์—๋„ ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„์ด ๋ณ€๊ฒฝ๋˜๋„๋ก

  • #2
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ : input์— onkeyup์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ apple๊ธฐ๊ธฐ์—์„œ ํ•œ๊ธ€๋กœ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ ํ•ด๋‹น ์—ฐ๊ฒฐ๋œ javascript ํ•จ์ˆ˜๊ฐ€ ์—ฐ์†ํ•ด์„œ 2๋ฒˆ ์ž‘๋™ํ•˜๋Š” ์˜ค๋ฅ˜ ๋ฐœ์ƒ
    • ํ•ด๊ฒฐ: onkeyup์„ ๋ชจ๋‘ onkeypress๋กœ ๋ณ€๊ฒฝ
  • #39
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : post eidt ์‹œ ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Œ
    • ํ•ด๊ฒฐ :
      • post edit ์‹œ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ„์„ ๋ฐ›์•„์™€ ๊ทธ ์ˆœ๊ฐ„ javascript ์•ˆ์—์„œ ํ˜„์žฌ ํ•™์Šต ์‹œ๊ฐ„ ๊ณ„์‚ฐ ๋กœ์ง(์œ„์—์„œ ์ž‘์„ฑํ•œ ๋กœ์ง)์„ ํ†ตํ•ด ํ˜„์žฌ๊นŒ์ง€์˜ ํ•™์Šต์‹œ๊ฐ„์„ ๋ฐ˜์˜ํ•˜์—ฌ ๋ณ€๊ฒฝ.
      • ์ด ๋˜ํ•œ replace๋ฅผ ํ†ตํ•ด ์š”์†Œ๋ฅผ ํ˜„์žฌ ๋ณ€๊ฒฝ๋œ ์š”์†Œ๋กœ ๊ต์ฒด.

<220505>

Tag : version 1.0.9
#39 Enhancement : ์‹ค์‹œ๊ฐ„ ํ•™์Šต ์‹œ๊ฐ„ ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  • #39
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : ํ•™์Šต ์‹œ๊ฐ„์ด ๊ธฐ๋ก์€ ๋˜์—ˆ์ง€๋งŒ, ์ด๋ฅผ ๊ทธ์ € ์‹œ๊ฐ„์œผ๋กœ๋งŒ ๋ณด์—ฌ์ฃผ์–ด์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์˜ค๋Š˜ ํ•˜๋ฃจ ์–ผ๋งˆ๋‚˜ ๊ณต๋ถ€๋ฅผ ํ–ˆ๋Š”์ง€ ์ง์ ‘ ๊ณ„์‚ฐํ•˜๊ฑฐ๋‚˜ ๋†“์น˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒ
    • ํ•ด๊ฒฐ: ํ”„๋กœ๊ทธ๋žจ์ƒ์œผ๋กœ ์ž๋™ ๊ณ„์‚ฐํ•˜์—ฌ ์ง€์†์ ์œผ๋กœ ์ง€๊ธˆ๊นŒ์ง€ ์ž์‹ ์ด ํ•˜๋ฃจ ์–ผ๋งˆ๋‚˜ ๊ณต๋ถ€๋ฅผ ์ง„ํ–‰ํ–ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
      • getTotalStudyTimes, getTimes๋ฅผ ํ†ตํ•ด ํ˜„์žฌ ์ƒํ™ฉ์— ๋งž๋Š” ์‹œ๊ฐ„ ๊ณ„์‚ฐ ์ง„ํ–‰
      • ๋กœ์ง :

        ์กฐํšŒ ์‹œ๊ฐ„ ๊ธฐ์ค€ (home์œผ๋กœ ์ด๋™)

        1. 04:00 - 24:00
          • ๊ทธ member์˜ ๊ฐ€์žฅ ์ตœ์‹  ๊ธ€ search
            1. ํ•ด๋‹น member์˜ ์ตœ์‹ ๊ธ€์ด ๋‹น์ผ 4์‹œ ์ดํ›„ create ๋˜์—ˆ๋‹ค
            • ๊ฐ€์ ธ์™€์„œ times ๊ณ„์‚ฐ 2. ๋‹น์ผ 4์‹œ ์ด์ „ โ†’ ์–ด์ œ ๊ธ€์ด๋ผ ํŒ๋‹จ
            • โ€œ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹คโ€ ์ถœ๋ ฅ
        2. 00:00 - 04:00
          • ๊ทธ member์˜ ๊ฐ€์žฅ ์ตœ์‹  ๊ธ€ search
            1. ํ•ด๋‹น member์˜ ์ตœ์‹ ๊ธ€์ด ๋‹น์ผ create
            • ๊ฐ€์ ธ์™€์„œ times ๊ณ„์‚ฐ 2. ์ „๋‚  create
              1. 04์‹œ์ดํ›„ create
              • ๊ฐ€์ ธ์™€์„œ times ๊ณ„์‚ฐ 2. 04์‹œ ์ด์ „ create
              • โ€œ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹คโ€ ์ถœ๋ ฅ

<220504>

Tag : version 1.0.8
#2 Bug : post edit์—์„œ ์‹œ๊ฐ„ ๋ณ€๊ฒฝ ์‹œ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” bug ์ˆ˜์ •, comment ์‚ญ์ œ, post ์‚ญ์ œ ์‹œ ๋ชจ๋‹ฌ ์œ ์ง€

  • #2
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ : post๋ฅผ editํ•  ๋•Œ, main(home) ํ™”๋ฉด์˜ title, introduce๋Š” ์ˆ˜์ •๋˜์ง€๋งŒ, ๋ณ€๊ฒฝ๋œ time์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์Œ. โ†’ ๋˜ times๋“ค์— ๋Œ€ํ•ด replace ํ•ด์ค„ ํ•„์š” ์žˆ์Œ ๋˜ํ•œ, comment ์‚ญ์ œ, post ์‚ญ์ œ๋„ RestAPI๋กœ ๊ต์ฒด ํ•„์š”
    • ํ•ด๊ฒฐ: ๊ธฐ์กด main ํ™”๋ฉด์˜ ํ•ด๋‹น post์˜ times์— ์ •๋ณด๋ฅผ ๋‚˜ํƒ€๋‚ด๊ณ  ์žˆ๋Š” ์š”์†Œ๋ฅผ ๋นˆ ์š”์†Œ๋กœ replaceํ•˜๊ณ  ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ์š”์†Œ๋“ค์„ appendํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰
      • ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ์ง์€ ๊ธฐ์กด์˜ ๋กœ์ง๊ณผ ๋™์ผ

          $('#post_times' + id).replaceWith(
                                  '<div id="post_times'+ id +'" class="card-text overflow-hidden d-sm-flex" style="margin: 2px 0px 0px 0px; max-width: 100%;"></div>'
                              )
          var cnt = 0;
          for (var i = 1; i < times.length; i+=2, cnt++) {
              if (cnt % 2 != 0) {
                  $('#post_times' + id).append(
                      '<p class="badge" style="margin: 3px; background-color:#8AA6A3;">' +
                      times[i-1].value + '&nbsp;~&nbsp;' + times[i].value
                      + '</p>'
                  );
              } else {
                  $('#post_times' + id).append(
                      '<p class="badge" style="margin: 3px; background-color:#A1A185;">' +
                      times[i-1].value + '&nbsp;~&nbsp;' + times[i].value
                      + '</p>'
                  );
              }
          }
          if (times.length % 2 == 1) {
              if ((times.length - 1) % 4 == 0) {
                  $('#post_times' + id).append(
                      '<p class="badge" style="margin: 3px; background-color:#A1A185;">' +
                      times[times.length-1].value + '&nbsp;~'
                      + '</p>'
                  );
              } else {
                  $('#post_times' + id).append(
                      '<p class="badge" style="margin: 3px; background-color:#8AA6A3;">' +
                      times[times.length-1].value + '&nbsp;~'
                      + '</p>'
                  );
              }
          }
        
      • comment, post ์‚ญ์ œ ์š”์ฒญ์„ RestAPI๋กœ ๊ต์ฒด

          function post_delete_check(id) {
              var check = confirm("์ •๋ง ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?");
              if (check){    //ํ™•์ธ
                  alert("์‚ญ์ œ๊ฐ€ ์™„๋ฃŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.")
                  $.ajax({
                      url: 'posts/delete/' + id,
                      type: "DELETE"
                  })
                      .done(function () {
                          location.reload();
                      })
              }else{   //์ทจ์†Œ
                  return false;
              }
          }
        
          function delete_check(postId, commentId) {
                    
              var deleteForm = {
                  postId : postId,
                  commentId : commentId
              };
                    
              var check = confirm("์ •๋ง ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?");
                    
              if (check){ //ํ™•์ธ
                  $.ajax({
                      url: 'comment/delete/' + commentId,
                      type: "DELETE",
                      data: deleteForm
                  })
                      .done(function (fragment) {...}
          }
        
        • post๋ฅผ ์‚ญ์ œํ•  ๋•Œ๋Š” ์‚ญ์ œ ํ›„ ๋ฐ”๋กœ home์œผ๋กœ ๊ฐ€๋ฉด ๋˜์ง€๋งŒ, comment๋Š” ์‚ญ์ œํ•ด๋„ ๋ชจ๋‹ฌ์„ ์œ ์ง€ํ•˜๋ฉฐ ํ•ด๋‹น ์‚ญ์ œ๋ฅผ ๋ฐ˜์˜ํ•œ ์ƒํƒœ์˜ comment list๋ฅผ ์ƒˆ๋กœ ๋ณด์—ฌ์ค„ ํ•„์š”๊ฐ€ ์žˆ๊ธฐ์— ์‚ญ์ œ ํ›„ comment list(์‚ญ์ œ๋œ ํ›„์˜ comment list)๋ฅผ fragment๋กœ ๋ฐ›์•„์™€ replace ์ง„ํ–‰

<220503>

#2 Enhancement : Post ์ˆ˜์ • ์‹œ ๋ชจ๋‹ฌ ์œ ์ง€
#28 Enhancement : ์ด๋ฏธ์ง€ Upload ์‹œ API๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

  • #2
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ : comment ์ž‘์„ฑ ์‹œ ์— ๋ชจ๋‹ฌ์„ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์ ์šฉ, ํ•˜์ง€๋งŒ post ๋˜ํ•œ ์ˆ˜์ • ํ›„ submit์„ ๋ˆ„๋ฅด๋ฉด ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” home์œผ๋กœ ๋Œ์•„๊ฐ€์•ผ ๋˜๊ณ , modal์ด ๋‚ด๋ ค๊ฐ€๋Š” ํ˜„์ƒ ๋ฐœ์ƒ โ†’ edit ํ›„ ๋ฐ”๋กœ ๊ทธ ๋ชจ๋‹ฌ ์ž์ฒด์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ํ•„์š” (comment์—์„œ์˜ ๋ฌธ์ œ์™€ ์œ ์‚ฌ)
    • ํ•ด๊ฒฐ: ์ด ๋˜ํ•œ comment ์ž‘์„ฑ ์‹œ ๋™์ž‘ํ•˜๋Š” ๋กœ์ง๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ง„ํ–‰ โ†’ Ajax Web API ์š”์ฒญ์„ ํ†ตํ•ด post eidt์„ Postํ•˜๊ณ  ํ•ด๋‹น ๊ฒฐ๊ณผ ๊ฐ’์„ fragment๋œ html๋กœ ๋ฐ›์•„์™€ ๊ธฐ์กด fragment๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰ (์ƒˆ ๊ธ€ ์ž‘์„ฑ์€ ๋ชจ๋‹ฌ์ด ์•„๋‹Œ, ๊ธฐ์กด ํผ์œผ๋กœ ๋ณด์—ฌ์ฃผ๋„๋ก ์„ค์ •)
      • post๋Š” get, post ๋ชจ๋‘ Ajax api๋กœ ์š”์ฒญ (edit ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๊ฒฝ์šฐ ๋˜ํ•œ ๋ชจ๋‹ฌ์•ˆ์—์„œ ์ˆ˜์ • ๋ฐ ์ˆ˜์ • ์™„๋ฃŒ ํ›„ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ํ™•์ธ์„ ์œ„ํ•จ)
      • @GetMapping("/posts/edit/{id}") ์„ Ajax api๋กœ ์š”์ฒญํ•˜๋„๋ก ์„ค์ • (๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ • ํผ)

          function edit_post(id) {
              $.ajax({
                  url: 'posts/edit/' + id,
                  type: "GET",
              })
                  .done(function (fragment) {
                      $('#postModal_content' + id).replaceWith(fragment);
                      simplemde = new SimpleMDE({element: document.getElementById("content"),spellChecker: false});
                      document.getElementById("postEdit_container").scrollIntoView();
                  });
          }
        
        • ๋˜‘๊ฐ™์ด ๊ธฐ์กด ๋‚ด์šฉ์„ fragment๋กœ ๋ฐ›์•„ ์˜จ editForm html(return "post/editPostForm :: #postEdit_container";)๋กœ ๊ต์ฒด
        • ๊ต์ฒด ํ›„ markdown editor ์ถ”๊ฐ€.
        • ์ƒ๋‹จ์œผ๋กœ ์Šคํฌ๋กค ์ž๋™ ์ด๋™
      • @PostMapping("/posts/edit/{id}") ์„ Ajax api๋กœ ์š”์ฒญํ•˜๋„๋ก ์„ค์ • (๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •)

          function post_edit(id) {
              var formData = $("#formPost").serializeArray();
              formData[formData.length - 1].value = simplemde.value(); // content
                  $.ajax({
                              url: '/posts/edit/' + id,
                              type: "POST",
                              data: formData
                          })
                              .done(function (fragment) {...}
          }
        
        • form์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋“ค์„ ๋ฐ˜์˜ํ•˜๊ธฐ ์œ„ํ•ด form์˜ ์ž…๋ ฅ๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ serializeArray๋ฅผ ํ†ตํ•ด ๋ฐ›์•„์˜ด
        • ์—ฌ๊ธฐ์„œ simplemde๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ content์˜ ๋‚ด์šฉ์ด serializeArray์— ๋‹ด๊ฒจ์˜ค์ง€ ์•Š์•„ ์ง์ ‘ simplemde์— ์ž…๋ ฅ๋œ ๊ฐ’์„ form์•ˆ์˜ content์— ๋„ฃ์–ด์คŒ
        • ์ดํ›„๋Š” ์œ„์˜ comment ๋ณ€๊ฒฝ ๋กœ์ง๊ณผ ๋™์ผํ•˜๊ฒŒ ์ง„ํ–‰ (ajax api, fragment replace, setAttribute(id), recentpost, โ€ฆ)
  • #28
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : ์ด๋ฏธ์ง€๋ฅผ iframe์˜ form์œผ๋กœ upload ์ง„ํ–‰. โ†’ ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•, Rest API๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐ ๊ฐ€๋Šฅ
    • ํ•ด๊ฒฐ : Ajax Web API ์š”์ฒญ์˜ Post๋ฅผ ์ด์šฉํ•˜์—ฌ ์—…๋กœ๋“œ๋ฅผ ํ•˜๊ณ  ๋ฐ˜ํ™˜ ๊ฐ’์œผ๋กœ ํ•ด๋‹น Image ๊ฐ์ฒด (value: imgSrc, imgName)๋ฅผ Json ํ˜•์‹์œผ๋กœ ๋ฐ›์•„ ์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์‚ฌ์ง„ ์ •๋ณด๋ฅผ ์ถœ๋ ฅ

        @ResponseBody
        @PostMapping("/posts/edit/{id}/img")
        public Image postImgEdit(@PathVariable("id") Long id, @RequestParam("file") MultipartFile[] files) throws IOException {
            MultipartFile file = files[0];
            Image image = s3Service.upload(file);
            postService.editPostImg(id, image);
            return image; // image ๊ฐ์ฒด๋ฅผ Json์œผ๋กœ ๋ฐ˜ํ™˜
        }
      
        function image_upload(id){
              
            var formData = new FormData();
            var image = $("#file")[0].files[0];
              
            formData.append( "file", image);
              
            if(image == null){
                alert("ํŒŒ์ผ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”");
                return;
            }
              
            $.ajax({
                url : "/posts/edit/"+id+"/img"
                , type : "POST"
                , processData : false
                , contentType : false
                , data : formData
                })
        }
      
      • ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ํ›„ ๊ฐ์ฒด๋ฅผ Json์œผ๋กœ ๋ฐ˜ํ™˜ํ•ด ์คŒ
      • ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ file ๋ฐ์ดํ„ฐ๋Š” formdata๋กœ ํ•œ๋ฒˆ ๋ฌถ์–ด์ค˜์„œ ๋ณด๋‚ด์ฃผ๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•จ
      • ๋˜ํ•œ file ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ผ ๋•Œ๋Š” ํ•ญ์ƒ processData : false, contentType : false ์ฃผ์˜

<220502>

#25 Enhancement : ๋ˆ„์ ๊ณต๋ถ€์‹œ๊ฐ„ ํ†ต๊ณ„ ๋Œ€์‹œ๋ณด๋“œ

  • #25
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : ๋‚ด๊ฐ€ ์ผ์ฃผ์ผ๋™์•ˆ ์–ผ๋งŒํผ ๊ณต๋ถ€๋ฅผ ํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์—†์–ด, ๋™๊ธฐ๋ถ€์—ฌ๊ฐ€ ๋ถ€์กฑ. ์ผ์ฃผ์ผ ๋™์•ˆ์˜ ๋ˆ„์  ๊ณต๋ถ€์‹œ๊ฐ„ ํ†ต๊ณ„๋Ÿ‰์„ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋“ค๋ผ๋ฆฌ ๋น„๊ตํ•˜์—ฌ ๋ณด์—ฌ์ฃผ๋ฉด ๋™๊ธฐ๋ถ€์—ฌํ•˜๋Š” ๋ฐ์— ์ข‹์€ ํšจ๊ณผ๊ฐ€ ์žˆ์„ ๊ฒƒ์ด๋ผ๊ณ  ํŒ๋‹จ
    • ํ•ด๊ฒฐ : ๋ถ„์„ ํˆด์€ ํŒŒ์ด์ฌ์ด ๋” ์ต์ˆ™ํ•˜๊ธฐ์— ํŒŒ์ด์ฌ์˜ matplot์„ ํ†ตํ•ด ์‹œ๊ฐ„์„ ๊ณ„์‚ฐํ•˜๊ณ  ploting. ๊ทธ ํ›„ ํ•ด๋‹น ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฏธ์ง€๋กœ ์ €์žฅํ•˜์—ฌ S3์— ์ €์žฅํ•˜๊ณ , ์›น์—์„œ๋Š” ํ•ด๋‹น ์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์™€ ๋ณด์—ฌ์ฃผ๋Š” ํ˜•์‹์œผ๋กœ ์ง„ํ–‰. (Side Widget์˜ Statics, Nav bar์˜ Data ๋ถ€๋ถ„)
    • ์ถ”ํ›„ ํ•ด๊ฒฐ : D3.js ์™€ ๊ฐ™์€ ํˆด์„ ์‚ฌ์šฉํ•˜์—ฌ ์ข€ ๋” ์‹œ๊ฐ์  ํšจ์œจ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์˜ˆ์ •

<220501>

#2 Enhancement : Comment ์ž‘์„ฑ ์‹œ ๋ชจ๋‹ฌ ์œ ์ง€

  • #2
    • ๊ธฐ์กด ๋ฌธ์ œ์  : Post ํด๋ฆญ ์‹œ ์ƒ์„ฑ๋˜๋Š” ๋ชจ๋‹ฌ์—์„œ ๋Œ“๊ธ€์„ ์ž‘์„ฑํ•  ์‹œ ์ž‘์„ฑ ํ›„ submit ์„ ํด๋ฆญํ•  ๊ฒฝ์šฐ modal ์ด๊ธฐ์— ์ž‘์„ฑ๋œ ๋Œ“๊ธ€์„ ํ™•์ธํ•˜๋ ค๋ฉด home์œผ๋กœ reload๋จ. โ†’ ์ž‘์„ฑ ํ›„ ํ˜„์žฌ ๋ชจ๋‹ฌ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ž‘์„ฑ๋œ ๋Œ“๊ธ€๋ชฉ๋ก๋งŒ์„ reloadํ•  ํ•„์š”๊ฐ€ ์žˆ์Œ
    • ํ•ด๊ฒฐ : Ajax Web API ์š”์ฒญ์„ ํ†ตํ•ด comment๋ฅผ postํ•˜๊ณ  ํ•ด๋‹น ๊ฒฐ๊ณผ ๊ฐ’์„ fragment๋œ html๋กœ ๋ฐ›์•„์™€ ๊ธฐ์กด fragment๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ง„ํ–‰
      • @PostMapping("/comment/api/new/{id}") ๋ฅผ ajax์˜ post ์š”์ฒญ์œผ๋กœ mapping

          function submit_comment(id) {
                    
              var commentForm = {
                  postId : id,
                  comment : $("#comment_content"+id).val()
              };
                    
              $.ajax({
                  url: 'comment/api/new/' + id,
                  type: "POST",
                  data: commentForm,
              })
                  .done(function (fragment) {...}
        
        • fragment๋Š” ๋ชจ๋‹ฌ์˜ ์ผ๋ถ€๋ถ„์ธ commentList ๋ฅผ replaceํ•˜๊ธฐ ์œ„ํ•œ ๋ Œ๋”๋ง๋œ html ํŒŒ์ผ
        • ์ฆ‰, post๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์ƒˆ๋กœ ๊ฐฑ์‹ ๋œ ํ•ด๋‹น Post์˜ comment list (๋ฐฉ๊ธˆ ์ž‘์„ฑ๋œ ๋Œ“๊ธ€์„ ์ถ”๊ฐ€ํ•œ ๋Œ“๊ธ€ ๋ฆฌ์ŠคํŠธ)๋ฅผ ๋ Œ๋”๋งํ•œ html ํŒŒ์ผ์„ ๋ฐ›์•„์™€ ์ด๋ฅผ ๊ธฐ์กด์˜ comment list์™€ ๊ต์ฒด. โ†’ ์ž‘์„ฑ๋œ ๋Œ“๊ธ€์„ url reload ํ•„์š” ์—†์ด ๋ฐ”๋กœ ํ™•์ธ ๊ฐ€๋Šฅ
      • fragment๋Š” thymeleaf์—์„œ ์ œ๊ณตํ•˜๋Š” html ์ผ๋ถ€๋งŒ์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ ์‚ฌ์šฉ : return "components/commentList :: #commentPart"; โ†’ ํ•ด๋‹น id๋ฅผ ๊ฐ€์ง„ ์š”์†Œ๋งŒ ๋ฐ˜ํ™˜ํ•ด์คŒ.
      • ๋ฐ˜ํ™˜๋œ fragment๋กœ ๊ธฐ์กด ์š”์†Œ๋ฅผ ๊ต์ฒดํ•œ ํ›„, id๋ฅผ ์ƒˆ๋กœ ํ• ๋‹น โ†’ ๋ชจ๋‹ฌ์ด๊ธฐ์—, ๋‹ค๋ฅธ post๋“ค์˜ commentPart์™€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•จ.

          var commentPart =document.getElementById("commentPart");
          commentPart.setAttribute("id", "commentPart"+id.toString());
        
      • ๋˜ํ•œ, ๋ณ€๊ฒฝ๋œ ์‚ฌํ•ญ์„ modal ๋ฟ๋งŒ์•„๋‹Œ, home์˜ ํ•ด๋‹น post์˜ comment ๊ฐœ์ˆ˜์—๋„ ๋ฐ˜์˜ํ•ด์ค„ ํ•„์š”๊ฐ€ ์žˆ์Œ โ†’ ํ•ด๋‹น post id๋ฅผ ๊ฐ€์ง„ post์˜ comment ๊ฐœ์ˆ˜๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์š”์†Œ๋ฅผ replace ํ•ด์คŒ
      • ๋˜ํ•œ, recent post๋ผ๊ณ  ํ˜„์žฌ ์ž์‹ ์ด ์ž‘์„ฑ ์ค‘(๊ณต๋ถ€๋ฅผ endํ•˜์ง€ ์•Š์€ ์ƒํƒœ์˜ post)์ธ post๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋Œ“๊ธ€ ์ž‘์„ฑ์ด ์ด๋ฃจ์–ด์ง„ post๊ฐ€ ๊ทธ recent post์™€ ๋™์ผํ•  ๊ฒฝ์šฐ recent post ๋˜ํ•œ ์œ„์˜ ๊ณผ์ •์„ ์ ์šฉ (comment ๊ฐœ์ˆ˜ ๋ณ€๊ฒฝ)

<220427>

Tag : version 1.0.7
#28 Enhancement : Post Image ๋ณ€๊ฒฝ ์‹œ ๋ณ€๊ฒฝ๋œ ์ด๋ฏธ์ง€ ๋„์›Œ์ฃผ๊ธฐ
#31 Back : ํฌ๋ง์ง๋ฌด ์„ ํƒ์ง€ ๋ถ€์—ฌ (์„ ํƒ์ง€์— ์›ํ•˜๋Š” ์ง๋ฌด๊ฐ€ ์—†์„ ์‹œ ์ง์ ‘ ์ถ”๊ฐ€)
#15 Front : OG ํƒœ๊ทธ ๋ถ€์—ฌ

  • #28
    • ๊ธฐ์กด ๋ฌธ์ œ์  : ํ˜„์žฌ ์ด๋ฏธ์ง€์˜ ์ด๋ฆ„๋งŒ์„ ์•Œ๋ ค์ฃผ๊ณ , ํ˜„์žฌ ์ด๋ฏธ์ง€ ์ž์ฒด๋ฅผ ๋ณด์—ฌ ์ฃผ์ง„ ์•Š์•˜์Œ. ๋˜ํ•œ, Upload ์‹œ ๋ฐ”๋กœ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š์€ ์ฑ„๋กœ edit์„ ์ง„ํ–‰ํ•˜๊ฒŒ ์„ค์ •ํ•จ
    • ํ•ด๊ฒฐ : ์ด๋ฏธ์ง€๋ฅผ ๋„์›Œ์ฃผ๊ณ  Upload ์‹œ ๋ฐ”๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ์ด๋ฏธ์ง€๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ํ•„์š”
      • Upload ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ์‹œ a ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ๋ฐ”๋กœ img upload ๋กœ์ง์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ, onclick=โ€™upload_check()โ€™์„ ํ†ตํ•ด javascript ์ฝ”๋“œ๋ฅผ ๊ฑฐ์ณ ์ง„ํ–‰๋˜๋„๋ก ์„ค์ •

          function upload_check() {
              setTimeout(function(){alert("Upload์™„๋ฃŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!");location.reload();},500);
          } // 0.5์ดˆ ํ›„์— ์ž๋™์œผ๋กœ ํŽ˜์ด์ง€๊ฐ€ reload ๋˜๋„๋ก ์„ค์ •. -> reload ๋˜๋ฉด ๋ณ€๊ฒฝ๋œ ์ •๋ณด๋ฅผ ๋„์šธ ์ˆ˜ ์žˆ์Œ.
        
  • #31
    • ๊ธฐ์กด ๋ฌธ์ œ์  : ํฌ๋ง ์ง๋ฌด์˜ ์„ ํƒ์ง€๋ฅผ ์ฃผ์ง€ ์•Š์•„, ์ •ํ•ด์ง„ ํ˜•์‹ ์—†์ด ํฌ๋ง ์ง๋ฌด๋ฅผ ์ ๊ฒŒ ๋จ โ†’ ๋˜‘๊ฐ™์€ ์ง๋ฌด๋ผ๋„ ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋‹ค๋ฅธ ์ด๋ฆ„์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒ
    • ํ•ด๊ฒฐ : ViewTemplate ์— jobs ๋ผ๋Š” ์„ค์ •๋œ ์ง๋ฌด List๋ฅผ ๋„˜๊ฒจ์ค˜ datalist๋กœ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • + ์›ํ•˜๋Š” ์ง๋ฌด๊ฐ€ ์—†์œผ๋ฉด ์ง์ ‘ ์ ์„ ์ˆ˜ ์žˆ๋„๋ก Input์„ text๋กœ ์„ค์ •

        public class DesiredJob {
            static final List<String> jobList =  Arrays.asList("๋ฐฑ์—”๋“œ ์—”์ง€๋‹ˆ์–ด", "๋ฐ์ดํ„ฐ ์—”์ง€๋‹ˆ์–ด", "ML ์—”์ง€๋‹ˆ์–ด", "ํ”„๋ก ํŠธ์—”๋“œ ์—”์ง€๋‹ˆ์–ด");
            public static List<String> getJobList() {
                return jobList;
            }
        }
      
        <div class="input-group mb-3">
            <input **type="text"** autocomplete="off" class="form-control" list="datalistOptions" th:field="*{desiredJob}" placeholder="ํฌ๋ง ์ง๋ฌด๋ฅผ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์ž…๋ ฅํ•˜์„ธ์š”!">
            <**datalist** id="datalistOptions" >
                <th:block **th:each="job : ${jobs}"**>
                    <option **th:value="${job}"**>
                </th:block>
            </**datalist**>
        </div>
      
  • #15
    • ๊ธฐ์กด ๋ฌธ์ œ์  : ๋งํฌ๋ฅผ ๊ณต์œ ํ•ด๋„ ์ •ํ•ด์ง„ ํ˜•์‹ ์—†์ด ์ด์ƒํ•œ ํ˜•ํƒœ๋กœ ๊ณต์œ  ํ™”๋ฉด์ด ๋„์›Œ์ง
    • ํ•ด๊ฒฐ : Og ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด์„œ ์ •ํ•ด์ง„ ๊น”๋”ํ•œ ํ˜•์‹์œผ๋กœ ๊ณต์œ ๋  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

        <meta property="og:title" content="์„ธ๋ชจ๊ณต - ์„ธ์ƒ์˜ ๋ชจ๋“  ๊ณต๋ถ€" />
        <meta property="og:url" content="http://semogong.site/" />
        <meta property="og:type" content="website" />
        <meta property="og:image" content="https://semogong-bucket.s3.ap-northeast-2.amazonaws.com/SEMOGONG.jpg" />
        <meta property="og:description" content="TIL ๊ณต์œ  ์‚ฌ์ดํŠธ, ์˜ค๋Š˜ ํ•œ ๊ณต๋ถ€๋ฅผ ๊ณต์œ ํ•ด๋ณด์„ธ์š”!" />
      

<220425>

Tag : version 1.0.6
#32 Enhancement : Comment ์ž‘์„ฑ ์‹œ๊ฐ„ ํ‘œ์‹œ
#35 Bug Back : State ๋ณ€๊ฒฝ ์‹œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
#36 Front : ๊ธ€ ๋ฐ ๋Œ“๊ธ€ ์‚ญ์ œ ์‹œ Confirm

  • #32
    • ๊ธฐ์กด ๋ฌธ์ œ์  : ๋Œ“๊ธ€์„ ์ž‘์„ฑํ–ˆ์„ ๋•Œ, ํ•ด๋‹น ๋Œ“๊ธ€์ด ์–ธ์ œ ๋‹ฌ๋ฆฐ ๊ฑด์ง€ ๊ตฌ๋ถ„์ด ์•ˆ๋  ๋•Œ๊ฐ€ ์žˆ์—ˆ์Œ. โ†’ ๋Œ“๊ธ€์ด ์–ธ์ œ ๋‹ฌ๋ฆฐ ๊ฒƒ์ธ์ง€ ํ‘œ๊ธฐ ํ•„์š”
    • ํ•ด๊ฒฐ : ๋Œ“๊ธ€์ด ๋‹ฌ๋ฆฐ ์‹œ๊ฐ„ ํ‘œ๊ธฐ
      • ๋กœ์ง : CommetViewDto์—์„œ ๋Œ“๊ธ€์ด ๋‹ฌ๋ฆฐ ์‹œ๊ฐ„์ธ CreateDateTime๊ณผ ํ˜„์žฌ ์‹œ๊ฐ„์ธ LocalDateTime.now()์˜ ์ดˆ์ฐจ์ด ๋ฅผ Duration.between์„ ํ†ตํ•ด ๊ณ„์‚ฐํ•˜์—ฌ ํ•ด๋‹น DTO์— ์ €์žฅํ•˜๊ณ  veiwTemplate์— ๋ณด๋‚ด์ค€ ํ›„, ViewTemplate(Thymeleaf) ์•ˆ์—์„œ

        1. 60๋ถ„์ด ์ง€๋‚˜์ง€ ์•Š์•˜์œผ๋ฉด โ€˜x๋ถ„ ์ „โ€™์œผ๋กœ
        2. 60๋ถ„์ด ์ง€๋‚ฌ๊ณ  24์‹œ๊ฐ„์ด์ „์ด๋ฉด โ€˜x์‹œ๊ฐ„ ์ „โ€™์œผ๋กœ
        3. 24์‹œ๊ฐ„์ด ์ง€๋‚ฌ์œผ๋ฉด โ€˜x์ผ ์ „โ€™์œผ๋กœ ํ‘œ๊ธฐ
      • ์ด๋•Œ, Thmeleaf์—์„œ Math.round๋ฅผ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด ThymeMath Component๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์Šคํ”„๋ง ๋นˆ์œผ๋กœ ๋“ฑ๋ก โ†’ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ Object๋Š” Thymeleaf ์—์„œ @thymeMath ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

  • #35
    • ๊ธฐ์กด ๋ฌธ์ œ์  : State ๋ณ€๊ฒฝ ์˜ค๋ฅ˜ ์‹œ ๋ณ„ ๋‹ค๋ฅธ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ ์—†์ด ๊ทธ๋ƒฅ ํ™ˆ์œผ๋กœ ๋Œ์•„๊ฐ€๊ฒŒ ์„ค์ • โ†’ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€, ์˜ค๋ฅ˜๊ฐ€ ๋‚œ์ง€ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ง€ํ•˜๊ธฐ ์–ด๋ ค์›€
    • ํ•ด๊ฒฐ : State ๋ณ€๊ฒฝ ์˜ค๋ฅ˜ ์‹œ alert์„ ํ†ตํ•ด ์ž˜๋ชป๋œ state ๋ณ€๊ฒฝ์ด๋ผ๊ณ  ์•Œ๋ ค์คŒ
      • ๋กœ์ง : ViewTemplate(Thymeleaf) ์—์„œ ํ˜„์žฌ state ๊ฐ’์„ ๋ฐ›์•„์˜จ ํ›„
        ( Studying -> Studying / Breaking, End -> Breaking / End -> End ) ์™€ ๊ฐ™์€ ๋ณ€๊ฒฝ ์˜ค๋ฅ˜์— ๋Œ€ํ•ด์„œ if ์ ˆ์„ ํ†ตํ•ด alert์„ ๋„์šธ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
  • #36
    • ๊ธฐ์กด ๋ฌธ์ œ์  : ๊ธ€ ๋ฐ ๋Œ“๊ธ€ ์‚ญ์ œ ์‹œ โ€œ์‚ญ์ œโ€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ทธ๋ƒฅ ๋ฐ”๋กœ ์‚ญ์ œ ๋จ โ†’ ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ˆ˜๋กœ ์‚ญ์ œ๋ฅผ ๋ˆ„๋ฅด๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”.
    • ํ•ด๊ฒฐ :
      • ๋กœ์ง : ๋ฐ”๋กœ a ํƒœ๊ทธ๋กœ ์‚ญ์ œ URL๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹Œ, button์œผ๋กœ ๋ฐ”๊พผ ํ›„ onclick์œผ๋กœ javascript delete_check ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด confirmํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •

        detele_check : ์ธ์ž๋กœ ์‚ญ์ œํ•˜๊ณ ์ž ํ•˜๋Š” Entity์˜ id๋ฅผ ๋ฐ›์•„์˜ค๊ณ  confrim ์ง„ํ–‰. confirm์—์„œ ํ™•์ธ์„ ๋ˆ„๋ฅผ ์‹œ location.href ๋ฅผ ํ†ตํ•ด delete ์š”์ฒญ์„ ์ง„ํ–‰. ์ทจ์†Œ๋ฅผ ๋ˆ„๋ฅผ ์‹œ ์•„๋ฌด๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •

<220420>

Tag : version 1.0.5
#10 Back Front: State๋งˆ๋‹ค ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ์œ  ์ƒ‰ ๋ถ€์—ฌ ํ•„์š”
#11 Back : ๊ฐ Post ๋‹น comment ๊ฐœ์ˆ˜๋ฅผ ์ธ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • ํ•„์š”
#16 Back : Side Widget์˜ All Members๋ฅผ Studyingโ†’Breakingโ†’End ์ˆœ์œผ๋กœ ์ •๋ ฌ ํ•„์š”
#18 Front : ํ…Œ๋งˆ ๊ธ€๊ผด ์„ค์ • ํ•„์š”
#20 Front : ํ†ต์ผ๋œ Header ์ƒ์„ฑ ํ•„์š”
#24 Back Front : ๊ฐ Post์— CreateDate ํ‘œ๊ธฐ ํ•„์š”

  • #10
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์  : State๋งˆ๋‹ค ๊ตฌ๋ถ„์ด ์•ˆ๋˜์–ด ์žˆ์–ด, ์‹œ๊ฐ์ ์œผ๋กœ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•จ. ์ฆ‰๊ฐ ์ธ์ง€ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ค์›€.
    • ํ•ด๊ฒฐ : ๊ฐ State์— ๋งž๋Š” ์ƒ‰์„ ๋ถ€์—ฌ (thymeleaf์˜ if ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉ)
  • #11
    • ๋ฌธ์ œ์  : comment๋ฅผ ๋‹ฌ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ๊ฐ post์— comment๊ฐ€ ๋‹ฌ๋ฆฐ์ง€ ์•ˆ๋‹ฌ๋ฆฐ์ง€ ์™ธ๋ถ€์—์„œ๋Š” ํ™•์ธ ๋ถˆ๊ฐ€
    • ํ•ด๊ฒฐ : ViewTemplate์—๊ฒŒ DTO๋ฅผ ๋ณด๋‚ด์ค„ ๋•Œ, DTO์•ˆ์— Comment Count๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ post ๋‹น ๋‹ฌ๋ฆฐ comment์˜ ๊ฐœ์ˆ˜๋ฅผ ํ‘œ์ถœํ•ด์คŒ. (๊ฐ post ์šฐ์ƒ๋‹จ์— ํ‘œํ˜„)
  • #16
    • ๊ธฐ์กด์—๋Š” ์ด๋ฆ„์ˆœ์œผ๋กœ ์ •๋ ฌํ–ˆ๋˜ All members๋ฅผ Studying โ†’ Breaking โ†’ End ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ํ‘œํ˜„
    • ํ•ด๊ฒฐ ๋กœ์ง :
      • ์ผ๋‹จ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ DB์—์„œ ๊ฐ€์ ธ์˜จ ํ›„ Memory ๋‹จ์—์„œ ์ง์ ‘ ์ •๋ ฌ ์‹คํ–‰. โ†’ O(N)
      • ๋นˆ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ
        1. ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ๋Œ๋ฉด์„œ Studying์ธ ๋ฉค๋ฒ„ ์ถ”๊ฐ€
        2. ๊ทธ ํ›„ ๋˜ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ๋Œ๋ฉด์„œ Breaking์ธ ๋ฉค๋ฒ„ ์ถ”๊ฐ€
        3. ๊ทธ ํ›„ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ชจ๋“  ๋ฉค๋ฒ„๋ฅผ ๋Œ๋ฉด์„œ End์ธ ๋ฉค๋ฒ„ ์ถ”๊ฐ€
  • #18
    • Body์— font-family๋ฅผ NanumSquareRound ์ ์šฉ โ†’ ๊ธฐ์กด๋ณด๋‹ค ํ›จ์”ฌ ๋ณด๊ธฐ ์ข‹์•„์ง
  • #20
    • ํ†ต์ผ๋œ header,footer๋ฅผ ๋งŒ๋“  ํ›„ ๋ชจ๋“  html์ด fragment๋กœ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
    • edit,create ํ™”๋ฉด ๊ฐ™์€ ๊ฒฝ์šฐ bootstarp ์ด์™ธ์˜ css๋ฅผ ๋ฐ›์œผ๋ฉด ์•ˆ๋˜๋ฏ€๋กœ addheader๋ฅผ ์ถ”๊ฐ€๋กœ ์ƒ์„ฑํ•˜์—ฌ home.html์ด fragment๋กœ ๋ฐ›๋„๋ก ์„ค์ •
  • #24
    • Post Entity์— FormatCreateDate๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ LocalDateTime class๊ฐ€ ์•„๋‹Œ String์œผ๋กœ DB์— ํ•ด๋‹น ๋‚ ์งœ๋ฅผ ์›ํ•˜๋Š” format ํ˜•์‹์œผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ • (โ€œApril 14, 2022โ€ ํ˜•์‹์œผ๋กœ ์ €์žฅ)
    • ๊ทธ ํ›„ DTO์—๋„ FormatCreateDate๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ViewTemplate์— ๊ฐ’์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
    • ๊ฐ post ์ขŒ์ƒ๋‹จ์— ํ‘œ๊ธฐ

<220418>

#14 Back : Member๊ฐ€ ์ด๋ฏธ ๊ทธ๋‚  ๊ณต๋ถ€๋ฅผ ์ข…๋ฃŒํ–ˆ์ง€๋งŒ, ๋‹ค์‹œ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•  ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์กฐ์น˜
#21 Front : ์ƒˆ๋กœ์šด Member ๊ฐ€์ž…๊ณผ ๊ธฐ์กด Member ์ •๋ณด ์ˆ˜์ • html์ด ๋ถ„๋ฆฌ๋˜์ง€ ์•Š์Œ
#7 Bug : ๋กœ๊ทธ์ธ์ด ์•ˆ๋œ ์ƒํƒœ์—์„œ post์— ๋Œ“๊ธ€์„ ๋‹ฌ ๊ฒฝ์šฐ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
#6 Back : Posting ์‚ญ์ œ ๊ธฐ๋Šฅ ๋ฐ ์‚ญ์ œ ๋ฒ„ํŠผ ์ƒ์„ฑ
#4 Front : ์—ฌ๋Ÿฌ ์ž…๋ ฅ placeholder ์ˆ˜์ •

  • #14
    • ๊ธฐ์กด์˜ ๋ฌธ์ œ์ 

      Member๊ฐ€ ๊ณต๋ถ€๋ฅผ ์ข…๋ฃŒํ•œ ํ›„ ๋‹ค์‹œ ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๊ณต๋ถ€ ๊ธฐ๋ก์„ ์ง„ํ–‰ํ•˜๋˜ ๊ธ€์ด ๋ถˆ๋Ÿฌ์™€์ง€๋Š” ๊ฒƒ์ด ์•„๋‹Œ, ์ƒˆ๋กœ์šด ๊ธ€์„ ์ž‘์„ฑ๊ฒŒ๋” ์„ค์ •๋˜์–ด ์žˆ์—ˆ์Œ. ์ฆ‰, ๊ณต๋ถ€์ข…๋ฃŒ๋ฅผ ํ–ˆ์ง€๋งŒ, ๋‹ค์‹œ ๊ณต๋ถ€๋ฅผ ํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ–ˆ์Œ

    • ํ•ด๊ฒฐ ๋กœ์ง

      ์ผ๋‹จ ๊ธฐ๋ณธ์ ์œผ๋กœ 04์‹œ๋ฅผ ํ•˜๋ฃจ์˜ ์‹œ์ž‘๊ณผ ๋์œผ๋กœ ์„ค์ • (์ƒˆ๋ฒฝ๋ฐ˜ ๊ณ ๋ ค)
      ์‚ฌ์šฉ์ž๊ฐ€ End -> Studying ์œผ๋กœ State๋ฅผ ๋ณ€๊ฒฝํ•  ์‹œ (๊ณต๋ถ€์™„๋ฃŒ -> ๊ณต๋ถ€์‹œ์ž‘)์˜ ์ƒํ™ฉ

      1. ์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฌ ์“ด ๊ธ€์ด ์กด์žฌํ•˜๋Š” ์ง€ ํŒ๋‹จ (์ฆ‰, ์‹ ๊ทœ ํšŒ์›์ธ์ง€ ์•„๋‹Œ์ง€ ํŒ๋‹จ)
        • true (์“ด ๊ธ€์ด ์กด์žฌ)
          1. ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ž‘์„ฑํ•œ ๊ธ€์ด ํ•ด๋‹น ๋‚ ์งœ์— ์ž‘์„ฑํ•œ ๊ธ€์ด๋ฉด์„œ ์ž‘์„ฑ ํ•œ ์‹œ๊ฐ„์ด 04์‹œ ์ดํ›„์ธ์ง€ ํŒ๋‹จ
            • true => ํ•ด๋‹น ๊ธ€์„ ๊ฐ€์ ธ์™€์„œ ์ด์–ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
            • false
              1. ํ˜„์žฌ State ๋ณ€๊ฒฝ ์‹œ์ ์ด 04์‹œ ์ด์ „์ธ์ง€ ํŒ๋‹จ
                • true
                  1. ๊ทธ ์ „๋‚  ์ž‘์„ฑํ•œ ๊ธ€์ด ์กด์žฌํ•˜๋Š” ์ง€, ํ•ด๋‹น ๊ธ€์ด 04์‹œ ์ดํ›„ ์ž‘์„ฑํ•œ ๊ธ€์ธ์ง€ ํŒ๋‹จ
                    • true => ํ•ด๋‹น ๊ธ€์„ ๊ฐ€์ ธ์™€์„œ ์ด์–ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •
                    • flase => ์ƒˆ๋กœ์šด ๊ธ€ ์ž‘์„ฑ
                • false => ์ƒˆ๋กœ์šด ๊ธ€ ์ž‘์„ฑ
        • false => ์ƒˆ๋กœ์šด ๊ธ€ ์ž‘์„ฑ
  • #21
    • ์ถ”ํ›„์˜ bug๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒƒ์„ ๋Œ€๋น„ํ•˜์—ฌ sign up ํ™”๋ฉด ๊ณผ eidt ํ™”๋ฉด์„ ๋ถ„๋ฆฌ
    • createMemberForm.html โ†’ createMemberForm.html + editMemberForm.html
  • #7
    • ๋กœ๊ทธ์ธ์ด ์•ˆ๋œ ์œ ์ €๊ฐ€ Post์— ๋Œ“๊ธ€์„ ๋‹ฌ ๊ฒฝ์šฐ, alert (โ€๋กœ๊ทธ์ธ ํ›„ ๋Œ“๊ธ€์„ ๋‹ค์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.โ€) ์ฐฝ์„ ๋„์šฐ๋„๋ก ์„ค์ •
  • #6
    • ์ž„์‹œ์ ์œผ๋กœ DeleteMapping์œผ๋กœ Controller ์— ์„ค์ •ํ•œ ๊ฒƒ์ด ์•„๋‹Œ GetMapping์œผ๋กœ ์„ค์ •ํ•ด๋‘ . โ†’ ์ถ”ํ›„ DeleteMapping๊ณผ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐ ์˜ˆ์ •
    • edit ํ™”๋ฉด์— post ์‚ญ์ œ ๋ฒ„ํŠผ ์ƒ์„ฑ
  • #4
    • placeholder ์ˆ˜์ • (๋„์‹œ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. ๋“ฑ ๊ด€๋ จ์—†๋Š” ๊ฐ’๋“ค์ด default๊ฐ’์œผ๋กœ ์ฃผ์–ด ์กŒ์—ˆ์Œ)