


package com.example.community.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
// WebSecurityConfigurerAdapter
// HTTP 시큐리티 객체를 사용할 수 있게 해준다
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 모든 경로에 대해서 매칭 허용
        http.authorizeRequests()
                .anyRequest().permitAll();
    }
}

package com.example.community.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller // Web Template(View) Return
public class FirstController {
    @RequestMapping(value = "/first-url", method = RequestMethod.GET)
    public void first() {
    }
}

package com.example.community.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller // Web Template(View) Return
public class FirstController {
    @RequestMapping(value = "/first-url", method = RequestMethod.GET)
    public void first() {
    }
    @ResponseBody
    @RequestMapping(value = "/helloworld", method = RequestMethod.GET)
    public String helloWorld() {
        return "hello world";
    }
} }
}

package com.example.community.controller;
import org.springframework.web.bind.annotation.*;
@RestController // REST JSON Return
public class SecondController {
    @RequestMapping(value = "/hello-spring", method = RequestMethod.GET)
    public String helloSpring() {
        return "hello spring";
    }
}

package com.example.community.controller;
import org.springframework.web.bind.annotation.*;
@RestController // REST JSON Return
public class SecondController {
    @RequestMapping(value = "/hello-spring", method = RequestMethod.GET)
    public String helloSpring() {
        return "hello spring";
    }
    @GetMapping("/hello-rest")
    public String helloRest() {
        return "hello rest";
    }
}

package com.example.community.controller;
import org.springframework.web.bind.annotation.*;
@RestController // REST JSON Return
public class SecondController {
    @RequestMapping(value = "/hello-spring", method = RequestMethod.GET)
    public String helloSpring() {
        return "hello spring";
    }
    @GetMapping("/hello-rest")
    public String helloRest() {
        return "hello rest";
    }
    @GetMapping("/api/helloworld")
    public String helloRestApi() {
        return "hello rest api";
    }
}

package com.example.community.notice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public String noticeString() {
        return "공지사항입니다.";
    }
}

package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class NoticeModel {
    private int id;
    private String title;
    private String content;
    private LocalDateTime regDate;
}
package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
public class ApiNoticeController {
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }

package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
// Builder 패턴, static한 클래스를 이용해서 편리하게 사용할 수 있게 도와줌
// 빌더 패턴(Builder pattern) 이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴
// 빌더패턴을 활용하면 어떤 필드에 어떤 인자를 넣어줬는지 명확히 알 수 있고, 넣어줄 필요 없는 필드(null)는 굳이 선언할 필요 없으니 좋다고 생각했다.
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class NoticeModel {
    private int id;
    private String title;
    private String content;
    private LocalDateTime regDate;
}
package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        NoticeModel notice1 = new NoticeModel();
        notice1.setId(1);
        notice1.setTitle("공지사항 입니다");
        notice1.setContent("공지사항 내용 입니다");
        notice1.setRegDate(LocalDateTime.of(2021, 07, 03, 11, 11));
        noticeList.add(notice1);
        NoticeModel notice2 = new NoticeModel();
        notice2.setId(2);
        notice2.setTitle("두번째 공지사항 입니다");
        notice2.setContent("두번째 공지사항 내용 입니다");
        notice2.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        noticeList.add(notice2);
        return noticeList;
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
}

package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
}

package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
}


package com.example.community.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
// WebSecurityConfigurerAdapter
// HTTP 시큐리티 객체를 사용할 수 있게 해준다
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 외부 호출에 대한 접근 허용
        http.csrf().disable();
        http.headers().frameOptions().sameOrigin();
        // 모든 경로에 대해서 매칭 허용
        http.authorizeRequests()
                .anyRequest().permitAll();
    }
}


package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
}


package com.example.community.notice.controller;
import com.example.community.notice.model.NoticeModel;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
public class ApiNoticeController {
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
}


server :
  port : 8090
# 데이터 베이스 세팅
spring:
  h2:
    console:
      enabled: true
      path: /h2-console
  datasource:
    url: jdbc:h2:mem:backofficeDb #Memory DB
    driver-class-name: org.h2.Driver
    username: root
    password: '1111'
  jpa:
    hibernate:
      ddl-auto: create-drop #배포 시 none
    generate-ddl: true #배포 시 false
    properties:
      format_sql: true
      hibernate:
        show-sql: true
  mvc:
    hiddenmethod:
      filter:
        enabled: true
  mustache:
    suffix: .html
logging:
  level:
    org.hibernate.SQL: trace
    org.hibernate.type: trace
package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
// 입력 받는 객체에는 입력 받지 않는 id와 regdate 필드는 필요 없다
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class NoticeInput {
    private String title;
    private String content;
}
package com.example.community.notice.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity // pk 지정이 필요
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Notice {
    @Id // pk 설정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // GeneratedValue, 값이 어떻게 만들어지는지 설정, GenerationType.IDENTITY, 자동으로 값 만들어지게 한다
    private long id;
    @Column
    private String title;
    @Column
    private String content;
    @Column
    private LocalDateTime regDate;
}
package com.example.community.notice.repository;
import com.example.community.notice.entity.Notice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
// @Repository는 Interface로 충분하다
@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
}






package com.example.community.notice.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity // pk 지정이 필요
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Notice {
    @Id // pk 설정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // GeneratedValue, 값이 어떻게 만들어지는지 설정, GenerationType.IDENTITY, 자동으로 값 만들어지게 한다
    private long id;
    @Column
    private String title;
    @Column
    private String content;
    @Column
    private LocalDateTime regDate;
    // 조회수
    @Column
    private int hits;
    // 좋아요
    @Column
    private int likes;
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
}




DROP TABLE IF EXISTS NOTICE;
-- auto-generated definition
create table NOTICE
(
    ID BIGINT auto_increment primary key,
    TITLE VARCHAR(255),
    CONTENT VARCHAR(255),
    HITS INTEGER,
    LIKES INTEGER,
    REG_DATE TIMESTAMP
);
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE) VALUES(1, '내용1', 0, 0, '2021-02-01 01:12:20', '제목1');
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE) VALUES(2, '내용2', 0, 0, '2021-02-01 01:12:20', '제목2');
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE) VALUES(3, '내용3', 0, 0, '2021-02-01 01:12:20', '제목3');
server :
  port : 8090
# 데이터 베이스 세팅
spring:
  h2:
    console:
      enabled: true
      path: /h2-console
  datasource:
    url: jdbc:h2:mem:backofficeDb #Memory DB
    driver-class-name: org.h2.Driver
    username: root
    password: '1111'
  jpa:
    hibernate:
      ddl-auto:  none #배포 시 none 반대 create-drop, 데이터 베이스를 내가 직접 생성
    generate-ddl: false #배포 시 false 반대 true, true로하면 데이터가 날라가고 flase로 하면 데이터가 남는다
    properties:
      format_sql: true
      hibernate:
        show-sql: true
  mvc:
    hiddenmethod:
      filter:
        enabled: true
  mustache:
    suffix: .html
logging:
  level:
    org.hibernate.SQL: trace
    org.hibernate.type: trace

package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        
        return null;
    }
}


package com.example.community.notice.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity // pk 지정이 필요
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Notice {
    @Id // pk 설정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // GeneratedValue, 값이 어떻게 만들어지는지 설정, GenerationType.IDENTITY, 자동으로 값 만들어지게 한다
    private long id;
    @Column
    private String title;
    @Column
    private String content;
    @Column
    private LocalDateTime regDate;
    @Column
    private LocalDateTime updateDate;
    // 조회수
    @Column
    private int hits;
    // 좋아요
    @Column
    private int likes;
}
DROP TABLE IF EXISTS NOTICE;
-- auto-generated definition
create table NOTICE
(
    ID BIGINT auto_increment primary key,
    TITLE VARCHAR(255),
    CONTENT VARCHAR(255),
    HITS         INTEGER,
    LIKES        INTEGER,
    REG_DATE     TIMESTAMP,
    UPDATE_DATE  TIMESTAMP,
);
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
}



package com.example.community.notice.exception;
public class NoticeNotFoundException extends RuntimeException {
    public NoticeNotFoundException(String message) {
        super(message);
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        // 정상로직 수행
        notice.get().setTitle(noticeInput.getTitle());
        notice.get().setContent(noticeInput.getContent());
        notice.get().setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice.get());
    }
   
}




package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    
}




package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    
}




[조건]
notice.controller / ApiNoticeController.java
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
}




package com.example.community.notice.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity // pk 지정이 필요
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Notice {
    @Id // pk 설정
    @GeneratedValue(strategy = GenerationType.IDENTITY) // GeneratedValue, 값이 어떻게 만들어지는지 설정, GenerationType.IDENTITY, 자동으로 값 만들어지게 한다
    private long id;
    @Column
    private String title;
    @Column
    private String content;
    @Column
    private LocalDateTime regDate;
    @Column
    private LocalDateTime updateDate;
    // 조회수
    @Column
    private int hits;
    // 좋아요
    @Column
    private int likes;
    // 삭제 여부
    @Column
    private boolean deleted;
    // 삭제 날짜짜
    @Column
    private LocalDateTime deletedDate;
}
DROP TABLE IF EXISTS NOTICE;
-- auto-generated definition
create table NOTICE
(
    ID BIGINT auto_increment primary key,
    TITLE VARCHAR(255),
    CONTENT VARCHAR(255),
    HITS         INTEGER,
    LIKES        INTEGER,
    REG_DATE     TIMESTAMP,
    UPDATE_DATE  TIMESTAMP,
    DELETED_DATE TIMESTAMP,
    DELETED      BOOLEAN
);
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE, DELETED) VALUES(1, '내용1', 0, 0, '2021-02-01 01:12:20', '제목1', 0);
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE, DELETED) VALUES(2, '내용2', 0, 0, '2021-02-01 01:12:20', '제목2', 0);
INSERT INTO NOTICE(ID, CONTENT, HITS, LIKES, REG_DATE, TITLE, DELETED) VALUES(3, '내용3', 0, 0, '2021-02-01 01:12:20', '제목3', 0);
package com.example.community.notice.exception;
public class AlreadyDeletedException extends RuntimeException {
    public AlreadyDeletedException(String message) {
        super(message);
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
}





package com.example.community.notice.repository;
import com.example.community.notice.entity.Notice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
// @Repository는 Interface로 충분하다
@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
    Optional<List<Notice>> findByIdIn(List<Long> idList);
}
package com.example.community.notice.model;
import lombok.Data;
import java.util.List;
@Data
public class NoticeDeleteInput {
    private List<Long> idList;
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
}



[조건]
notice.controller / ApiNoticeController.java
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
}



package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody NoticeInput noticeInput) {
        if(noticeInput.getTitle() == null ||
            noticeInput.getTitle().length() < 1 ||
            noticeInput.getContent() == null ||
            noticeInput.getContent().length() < 1) {
            return new ResponseEntity<>("입력값이 정확하지 않습니다", HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
        .title(noticeInput.getTitle())
        .content(noticeInput.getContent())
        .hits(0)
        .likes(0)
        .regDate(LocalDateTime.now())
        .build());
        return ResponseEntity.ok().build();
    }
}




Validation Library 추가
notice.model / NoticeInput.java
package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
// 입력 받는 객체에는 입력 받지 않는 id와 regdate 필드는 필요 없다
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class NoticeInput {
    @NotBlank(message = "제목은 필수 항목 입니다.")
    private String title;
    @NotBlank(message = "내용은 필수 항목 입니다.")
    private String content;
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.model.ResponseError;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
                                        , Errors errors) {
        if(errors.hasErrors()) {
            return new ResponseEntity<>(errors.getAllErrors(), HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
        .title(noticeInput.getTitle())
        .content(noticeInput.getContent())
        .hits(0)
        .likes(0)
        .regDate(LocalDateTime.now())
        .build());
        return ResponseEntity.ok().build();
    }
}




package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseError {
    private String field;
    private String message;
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.model.ResponseError;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
                                        , Errors errors) {
        if(errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();
            errors.getAllErrors().stream().forEach(e -> {
                ResponseError responseError = new ResponseError();
                responseError.setField(((FieldError)e).getField());
                responseError.setMessage(e.getDefaultMessage());
                responseErrors.add(responseError);
            });
            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
        .title(noticeInput.getTitle())
        .content(noticeInput.getContent())
        .hits(0)
        .likes(0)
        .regDate(LocalDateTime.now())
        .build());
        return ResponseEntity.ok().build();
    }
}






package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.validation.FieldError;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseError {
    private String field;
    private String message;
    public static ResponseError of(FieldError e) {
        return ResponseError.builder()
                .field((e).getField())
                .message(e.getDefaultMessage())
                .build();
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.model.ResponseError;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
                                        , Errors errors) {
        if(errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();
            errors.getAllErrors().stream().forEach(e -> {
                responseErrors.add(ResponseError.of((FieldError)e));
            });
            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
        .title(noticeInput.getTitle())
        .content(noticeInput.getContent())
        .hits(0)
        .likes(0)
        .regDate(LocalDateTime.now())
        .build());
        return ResponseEntity.ok().build();
    }
}
package com.example.community.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
// 입력 받는 객체에는 입력 받지 않는 id와 regdate 필드는 필요 없다
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class NoticeInput {
    @NotBlank(message = "제목은 필수 항목 입니다.")
    @Size(min = 10, max = 100, message = "제목은 10자 이상 100자 이하로 입력해주세요.")
    private String title;
    @NotBlank(message = "내용은 필수 항목 입니다.")
    @Size(min = 50, max = 1000, message = "내용은 50자 이상 1000자 이하로 입력해주세요.")
    private String content;
}


package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.model.ResponseError;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
            , Errors errors) {
        if(errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();
            errors.getAllErrors().stream().forEach(e -> {
                responseErrors.add(ResponseError.of((FieldError)e));
            });
            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .hits(0)
                .likes(0)
                .regDate(LocalDateTime.now())
                .build());
        return ResponseEntity.ok().build();
    }
    @GetMapping("/api/notice/latest/{size}")
    public Page<Notice> noticeLatest(@PathVariable int size) {
        Page<Notice> noticeList
                = noticeRepository.findAll(
                        PageRequest.of(0, size, Sort.Direction.DESC, "regDate"));
        return noticeList;
    }
}


package com.example.community.notice.repository;
import com.example.community.notice.entity.Notice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
// @Repository는 Interface로 충분하다
@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
    Optional<List<Notice>> findByIdIn(List<Long> idList);
    int countByTitleAndContentAndRegDateIsGreaterThanEqual(String title, String content, LocalDateTime regDate);
}
package com.example.community.notice.exception;
public class DuplicateNoticeException extends RuntimeException {
    public DuplicateNoticeException(String message) {
        super(message);
    }
}
package com.example.community.notice.controller;
import com.example.community.notice.entity.Notice;
import com.example.community.notice.exception.AlreadyDeletedException;
import com.example.community.notice.exception.DuplicateNoticeException;
import com.example.community.notice.exception.NoticeNotFoundException;
import com.example.community.notice.model.NoticeDeleteInput;
import com.example.community.notice.model.NoticeInput;
import com.example.community.notice.model.ResponseError;
import com.example.community.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiNoticeController {
    // Repository를 주입받는다. @RequiredArgsConstructor를 활용 해 생성자에서 주입을 받는다
    private final NoticeRepository noticeRepository;
    /*
    @GetMapping("/api/notice")
    public NoticeModel notice() {
        NoticeModel noticeModel = new NoticeModel();
        noticeModel.setId(1);
        noticeModel.setTitle("공지사항 입니다");
        noticeModel.setContent("공지사항 내용입니다");
        noticeModel.setRegDate(LocalDateTime.of(2021, 07, 04, 11, 11));
        return noticeModel;
    }
     */
    /*
    @GetMapping("/api/notice")
    public List<NoticeModel> notice() {
        List<NoticeModel> noticeList = new ArrayList<>();
        noticeList.add(NoticeModel.builder()
                .id(1)
                .title("공지사항 입니다")
                .content("공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 03, 11, 11))
                .build());
        noticeList.add(NoticeModel.builder()
                .id(2)
                .title("두번째 공지사항 입니다")
                .content("두번째 공지사항 내용 입니다")
                .regDate(LocalDateTime.of(2021, 07, 04, 11, 11))
                .build());
        return noticeList;
    }
     */
    @GetMapping("/api/notice")
    public List<NoticeInput> notice() {
        List<NoticeInput> noticeList = new ArrayList<>();
        return noticeList;
    }
    @GetMapping("/api/notice/count")
    public int noticeCount() {
        return 10;
    }
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestParam String title, @RequestParam String content) {
        return NoticeModel.builder()
                .id(1)
                .title(title)
                .content(content)
                .regDate(LocalDateTime.of(2021, 07,04,11,43))
                .build();
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(NoticeModel noticeModel) {
        noticeModel.setId(2);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public NoticeModel addNotice(@RequestBody NoticeModel noticeModel) {
        noticeModel.setId(3);
        noticeModel.setRegDate(LocalDateTime.now());
        return noticeModel;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .build();
        noticeRepository.save(notice);
        return notice;
    }
     */
    /*
    @PostMapping("/api/notice")
    public Notice addNotice(@RequestBody NoticeInput noticeInput) {
        Notice notice = Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .regDate(LocalDateTime.now())
                .hits(0)
                .likes(0)
                .build();
        Notice resultNotice = noticeRepository.save(notice);
        return resultNotice;
    }
    */
    @GetMapping("/api/notice/{id}")
    public Notice notice(@PathVariable Long id) {
        // .findById()는 반환타입이 Optional이다, 즉 null을 반환할 수도 있다
        // 그렇기에 Notice를 Optional로 감싸준다
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            return notice.get();
        }
        return null;
    }
    /*
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id,@RequestBody NoticeInput noticeInput) {
        Optional<Notice> notice = noticeRepository.findById(id);
        if(notice.isPresent()) {
            notice.get().setTitle(noticeInput.getTitle());
            notice.get().setContent(noticeInput.getContent());
            notice.get().setUpdateDate(LocalDateTime.now());
            noticeRepository.save(notice.get());
        }
    }
     */
    @ExceptionHandler(NoticeNotFoundException.class)
    public ResponseEntity<String> handlerNoticeNotFoundException(NoticeNotFoundException exception) {
            return new ResponseEntity<>(exception.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PutMapping("/api/notice/{id}")
    public void updateNotice(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
        /*
        Optional<Notice> notice = noticeRepository.findById(id);
        if(!notice.isPresent()) {
            // 예외 발생
            throw new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다.");
        }
        */
        // 이 경우 Optional이 아니기에 객체를 바로 받아 사용가능하다
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        // 정상로직 수행
        notice.setTitle(noticeInput.getTitle());
        notice.setContent(noticeInput.getContent());
        notice.setUpdateDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @PatchMapping("/api/notice/{id}/hits")
    public void noticeHits(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        notice.setHits(notice.getHits() + 1);
        noticeRepository.save(notice);
    }
    /*
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeRepository.delete(notice);
    }
     */
    @ExceptionHandler(AlreadyDeletedException.class)
    public ResponseEntity<String> handlerAlreadyDeletedException(AlreadyDeletedException exception) {
        return new ResponseEntity<>(exception.getMessage(), HttpStatus.OK);
    }
    @DeleteMapping("/api/notice/{id}")
    public void deleteNotice(@PathVariable Long id) {
        Notice notice = noticeRepository.findById(id)
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        if(notice.isDeleted()) {
            throw new AlreadyDeletedException("이미 삭제된 공지사항의 글입니다.");
        }
        notice.setDeleted(true);
        notice.setDeletedDate(LocalDateTime.now());
        noticeRepository.save(notice);
    }
    @DeleteMapping("/api/notice")
    public void deleteNoticeList(@RequestBody NoticeDeleteInput noticeDeleteInput) {
        List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
                .orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
        noticeList.stream().forEach(e -> {
            e.setDeleted(true);
            e.setDeletedDate(LocalDateTime.now());
        });
        noticeRepository.saveAll(noticeList);
    }
    @DeleteMapping("/api/notice/all")
    public void deleteNoticeAll() {
        List<Notice> noticeList = noticeRepository.findAll();
        if(!noticeList.isEmpty()) {
            noticeList.stream().forEach(e -> {
                if(!e.isDeleted()) {
                    e.setDeleted(true);
                    e.setDeletedDate(LocalDateTime.now());
                }
            });
        }
        noticeRepository.saveAll(noticeList);
    }
    /*
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
            , Errors errors) {
        if(errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();
            errors.getAllErrors().stream().forEach(e -> {
                responseErrors.add(ResponseError.of((FieldError)e));
            });
            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }
        // 정상 로직
        noticeRepository.save(Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .hits(0)
                .likes(0)
                .regDate(LocalDateTime.now())
                .build());
        return ResponseEntity.ok().build();
    }
     */
    @GetMapping("/api/notice/latest/{size}")
    public Page<Notice> noticeLatest(@PathVariable int size) {
        Page<Notice> noticeList
                = noticeRepository.findAll(
                        PageRequest.of(0, size, Sort.Direction.DESC, "regDate"));
        return noticeList;
    }
    @ExceptionHandler(DuplicateNoticeException.class)
    public ResponseEntity<?> handlerDuplicateNoticeException(DuplicateNoticeException duplicateNoticeException) {
        return new ResponseEntity(duplicateNoticeException.getMessage(), HttpStatus.BAD_REQUEST);
    }
    @PostMapping("/api/notice")
    public ResponseEntity<Object> addNotice(@RequestBody @Valid NoticeInput noticeInput
            , Errors errors) {
        // validation 로직
        if(errors.hasErrors()) {
            List<ResponseError> responseErrors = new ArrayList<>();
            errors.getAllErrors().stream().forEach(e -> {
                responseErrors.add(ResponseError.of((FieldError)e));
            });
            return new ResponseEntity<>(responseErrors, HttpStatus.BAD_REQUEST);
        }
        // Duplication 로직(중복체크)
        LocalDateTime checkDate = LocalDateTime.now().minusMinutes(1);
        int noticeCount = noticeRepository.countByTitleAndContentAndRegDateIsGreaterThanEqual(
                noticeInput.getTitle(),
                noticeInput.getContent(),
                checkDate
        );
        if (noticeCount > 0) {
            throw new DuplicateNoticeException("1분 이내에 동일한 내용의 공지사항이 등록되었습니다.");
        }
        // add 로직
        noticeRepository.save(Notice.builder()
                .title(noticeInput.getTitle())
                .content(noticeInput.getContent())
                .hits(0)
                .likes(0)
                .regDate(LocalDateTime.now())
                .build());
        return ResponseEntity.ok().build();
    }
}


차근차근 진행하는게 많은 도움이 되었습니다. 주석처리한 코드는 뒤로 갈 수록 너무 길어져서
코드읽기 좀 힘들었습니다. 코드가 전부 흰색 글씨라 보기 힘들었습니다. 코드 작성 태그에 ```java 추가하시면 훨씬 보기 좋을것 같습니다.