diff --git a/build.gradle b/build.gradle index db3ebcf1..69e0dc59 100644 --- a/build.gradle +++ b/build.gradle @@ -1,29 +1,31 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.4.5' - id 'io.spring.dependency-management' version '1.1.7' + id 'org.springframework.boot' version '3.2.0' + id 'io.spring.dependency-management' version '1.1.4' + id 'java' } group = 'com.example' version = '0.0.1-SNAPSHOT' java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' - implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'mysql:mysql-connector-java:8.0.33' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } diff --git a/src/main/java/com/example/bcsd/BcsdApplication.java b/src/main/java/com/example/bcsd/BcsdApplication.java index 6e3ecb1b..c1d8f85e 100644 --- a/src/main/java/com/example/bcsd/BcsdApplication.java +++ b/src/main/java/com/example/bcsd/BcsdApplication.java @@ -6,8 +6,8 @@ @SpringBootApplication public class BcsdApplication { - public static void main(String[] args) { - SpringApplication.run(BcsdApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(BcsdApplication.class, args); + } } diff --git a/src/main/java/com/example/bcsd/Controller/ArticleController.java b/src/main/java/com/example/bcsd/Controller/ArticleController.java new file mode 100644 index 00000000..6aaa071a --- /dev/null +++ b/src/main/java/com/example/bcsd/Controller/ArticleController.java @@ -0,0 +1,61 @@ +package com.example.bcsd.Controller; + +import com.example.bcsd.Service.ArticleService; +import com.example.bcsd.dto.ArticleCreateRequest; +import com.example.bcsd.dto.ArticleUpdateRequest; +import com.example.bcsd.model.Article; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/articles") +public class ArticleController { + + private final ArticleService articleService; + + public ArticleController(ArticleService articleService) { + this.articleService = articleService; + } + + @GetMapping + public ResponseEntity> getAllArticles() { + return ResponseEntity.ok(articleService.findAllArticles()); + } + + @GetMapping("/{id}") + public ResponseEntity
getArticleById(@PathVariable Long id) { + return ResponseEntity.ok(articleService.findArticle(id)); + } + + @PostMapping + public ResponseEntity
createArticle(@RequestBody ArticleCreateRequest request) { + Article article = articleService.createArticle( + request.getAuthorId(), + request.getBoardId(), + request.getTitle(), + request.getContent() + ); + return ResponseEntity.ok(article); + } + + @PutMapping("/{id}") + public ResponseEntity
updateArticle( + @PathVariable Long id, + @RequestBody ArticleUpdateRequest request + ) { + Article updated = articleService.updateArticle( + id, + request.getTitle(), + request.getContent() + ); + return ResponseEntity.ok(updated); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteArticle(@PathVariable Long id) { + articleService.deleteArticle(id); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/example/bcsd/Controller/BoardController.java b/src/main/java/com/example/bcsd/Controller/BoardController.java new file mode 100644 index 00000000..47d9def5 --- /dev/null +++ b/src/main/java/com/example/bcsd/Controller/BoardController.java @@ -0,0 +1,52 @@ +package com.example.bcsd.Controller; + +import com.example.bcsd.Service.BoardService; +import com.example.bcsd.model.Board; +import com.example.bcsd.dto.BoardCreateRequest; +import com.example.bcsd.dto.BoardUpdateRequest; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/boards") +public class BoardController { + + private final BoardService boardService; + + public BoardController(BoardService boardService) { + this.boardService = boardService; + } + + @GetMapping + public ResponseEntity> getAllBoards() { + return ResponseEntity.ok(boardService.findAllBoards()); + } + + @GetMapping("/{id}") + public ResponseEntity getBoard(@PathVariable Long id) { + return ResponseEntity.ok(boardService.findBoard(id)); + } + + @PostMapping + public ResponseEntity createBoard(@RequestBody BoardCreateRequest request) { + Board saved = boardService.createBoard(request.getName()); + return ResponseEntity.ok(saved); + } + + @PutMapping("/{id}") + public ResponseEntity updateBoard( + @PathVariable Long id, + @RequestBody BoardUpdateRequest request + ) { + Board updated = boardService.updateBoard(id, request.getName()); + return ResponseEntity.ok(updated); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteBoard(@PathVariable Long id) { + boardService.deleteBoard(id); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/example/bcsd/Controller/LoginController.java b/src/main/java/com/example/bcsd/Controller/LoginController.java new file mode 100644 index 00000000..53e00a0b --- /dev/null +++ b/src/main/java/com/example/bcsd/Controller/LoginController.java @@ -0,0 +1,31 @@ +package com.example.bcsd.Controller; + +import com.example.bcsd.Service.MemberService; +import com.example.bcsd.dto.MemberLoginRequest; +import com.example.bcsd.model.Member; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/login") +public class LoginController { + + private final MemberService memberService; + + public LoginController(MemberService memberService) { + this.memberService = memberService; + } + + @PostMapping + public ResponseEntity login( + @RequestBody MemberLoginRequest request, + HttpSession session + ) { + Member member = memberService.login(request); + + session.setAttribute("LOGIN_MEMBER_ID", member.getId()); + + return ResponseEntity.ok(member); + } +} diff --git a/src/main/java/com/example/bcsd/Controller/MemberController.java b/src/main/java/com/example/bcsd/Controller/MemberController.java new file mode 100644 index 00000000..c1e51520 --- /dev/null +++ b/src/main/java/com/example/bcsd/Controller/MemberController.java @@ -0,0 +1,69 @@ +package com.example.bcsd.Controller; + +import com.example.bcsd.Service.MemberService; +import com.example.bcsd.dto.MemberCreateRequest; +import com.example.bcsd.dto.MemberLoginRequest; +import com.example.bcsd.dto.MemberUpdateRequest; +import com.example.bcsd.model.Member; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/members") +public class MemberController { + + private final MemberService memberService; + private static final String LOGIN_MEMBER_ID = "LOGIN_MEMBER_ID"; + + public MemberController(MemberService memberService) { + this.memberService = memberService; + } + + @GetMapping + public ResponseEntity> findAll() { + return ResponseEntity.ok(memberService.findAllMembers()); + } + + @GetMapping("/{id}") + public ResponseEntity findOne(@PathVariable Long id) { + return ResponseEntity.ok(memberService.findMember(id)); + } + + @PostMapping + public ResponseEntity create(@RequestBody MemberCreateRequest request) { + return ResponseEntity.ok(memberService.createMember(request)); + } + + @PutMapping("/{id}") + public ResponseEntity update( + @PathVariable Long id, + @RequestBody MemberUpdateRequest request + ) { + return ResponseEntity.ok(memberService.updateMember(id, request)); + } + + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + memberService.deleteMember(id); + return ResponseEntity.noContent().build(); + } + + @PostMapping("/login") + public ResponseEntity login( + @RequestBody MemberLoginRequest request, + HttpSession session + ) { + Member member = memberService.login(request); + session.setAttribute(LOGIN_MEMBER_ID, member.getId()); + return ResponseEntity.ok(member); + } + + @PostMapping("/logout") + public ResponseEntity logout(HttpSession session) { + session.invalidate(); + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/example/bcsd/Controller/PostViewController.java b/src/main/java/com/example/bcsd/Controller/PostViewController.java new file mode 100644 index 00000000..b9eadbb9 --- /dev/null +++ b/src/main/java/com/example/bcsd/Controller/PostViewController.java @@ -0,0 +1,31 @@ +package com.example.bcsd.Controller; + +import com.example.bcsd.Service.ArticleService; +import com.example.bcsd.Service.MemberService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +public class PostViewController { + + private final ArticleService articleService; + private final MemberService memberService; + + public PostViewController(ArticleService articleService, MemberService memberService) { + this.articleService = articleService; + this.memberService = memberService; + } + + @GetMapping("/posts") + public String posts(@RequestParam(required = false) Long boardId, Model model) { + model.addAttribute("articles", articleService.findAllArticles()); + model.addAttribute("members", memberService.findAllMembers()); + if (boardId != null) { + model.addAttribute("articlesByBoard", articleService.getArticlesByBoardId(boardId)); + } + return "posts"; + } + +} diff --git a/src/main/java/com/example/bcsd/Exception/ArticleCreateException.java b/src/main/java/com/example/bcsd/Exception/ArticleCreateException.java new file mode 100644 index 00000000..0125b1db --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/ArticleCreateException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class ArticleCreateException extends RuntimeException { + public ArticleCreateException(Long authorId, Long boardId) { + super("게시물 생성 중 잘못된 참조입니다."); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/ArticleNotFoundException.java b/src/main/java/com/example/bcsd/Exception/ArticleNotFoundException.java new file mode 100644 index 00000000..7cbc65ae --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/ArticleNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class ArticleNotFoundException extends RuntimeException { + public ArticleNotFoundException(Long id) { + super("해당 게시글을 찾을 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/ArticleUpdateException.java b/src/main/java/com/example/bcsd/Exception/ArticleUpdateException.java new file mode 100644 index 00000000..0ca13452 --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/ArticleUpdateException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class ArticleUpdateException extends RuntimeException { + public ArticleUpdateException(Long authorId, Long boardId) { + super("참조가 불가능합니다"); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/BoardDeleteException.java b/src/main/java/com/example/bcsd/Exception/BoardDeleteException.java new file mode 100644 index 00000000..acac4453 --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/BoardDeleteException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class BoardDeleteException extends RuntimeException { + public BoardDeleteException(Long boardId) { + super("게시판에 게시물이 존재하여 삭제할 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/BoardNotFoundException.java b/src/main/java/com/example/bcsd/Exception/BoardNotFoundException.java new file mode 100644 index 00000000..56d585bd --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/BoardNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class BoardNotFoundException extends RuntimeException { + public BoardNotFoundException(Long id) { + super("해당 게시판을 찾을 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/EmailConflictException.java b/src/main/java/com/example/bcsd/Exception/EmailConflictException.java new file mode 100644 index 00000000..ceb80db3 --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/EmailConflictException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class EmailConflictException extends RuntimeException { + public EmailConflictException(String email) { + super("이미 존재하는 이메일입니다: " + email); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/Exception/GlobalExceptionHandler.java new file mode 100644 index 00000000..7a9c5af7 --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/GlobalExceptionHandler.java @@ -0,0 +1,93 @@ +package com.example.bcsd.Exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(ArticleNotFoundException.class) + public ResponseEntity> handleArticleNotFound(ArticleNotFoundException ex) { + Map body = new HashMap<>(); + body.put("status", 404); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body); + } + + @ExceptionHandler(BoardNotFoundException.class) + public ResponseEntity> handleBoardNotFound(BoardNotFoundException ex) { + Map body = new HashMap<>(); + body.put("status", 404); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body); + } + + @ExceptionHandler(MemberNotFoundException.class) + public ResponseEntity> handleMemberNotFound(MemberNotFoundException ex) { + Map body = new HashMap<>(); + body.put("status", 404); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(body); + } + + @ExceptionHandler(EmailConflictException.class) + public ResponseEntity> handleEmailConflict(EmailConflictException ex) { + Map body = new HashMap<>(); + body.put("status", 409); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.CONFLICT).body(body); + } + + @ExceptionHandler(ArticleUpdateException.class) + public ResponseEntity> handleArticleUpdate(ArticleUpdateException ex) { + Map body = new HashMap<>(); + body.put("status", 400); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); + } + + @ExceptionHandler(InvalidInputException.class) + public ResponseEntity> handleInvalidInput(InvalidInputException ex) { + Map body = new HashMap<>(); + body.put("status", 400); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); + } + + @ExceptionHandler(ArticleCreateException.class) + public ResponseEntity> handleArticleCreate(ArticleCreateException ex) { + Map body = new HashMap<>(); + body.put("status", 400); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); + } + + @ExceptionHandler(MemberDeleteException.class) + public ResponseEntity> handleMemberDelete(MemberDeleteException ex) { + Map body = new HashMap<>(); + body.put("status", 400); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); + } + + @ExceptionHandler(BoardDeleteException.class) + public ResponseEntity> handleBoardDelete(BoardDeleteException ex) { + Map body = new HashMap<>(); + body.put("status", 400); + body.put("message", ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(body); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleGeneral(Exception ex) { + Map body = new HashMap<>(); + body.put("status", 500); + body.put("message", "서버 오류가 발생했습니다."); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(body); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/InvalidInputException.java b/src/main/java/com/example/bcsd/Exception/InvalidInputException.java new file mode 100644 index 00000000..4d19909b --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/InvalidInputException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class InvalidInputException extends RuntimeException { + public InvalidInputException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/MemberDeleteException.java b/src/main/java/com/example/bcsd/Exception/MemberDeleteException.java new file mode 100644 index 00000000..78a3d4bb --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/MemberDeleteException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class MemberDeleteException extends RuntimeException { + public MemberDeleteException(Long memberId) { + super("사용자가 작성한 게시물이 존재하여 삭제할 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/Exception/MemberNotFoundException.java b/src/main/java/com/example/bcsd/Exception/MemberNotFoundException.java new file mode 100644 index 00000000..0467a805 --- /dev/null +++ b/src/main/java/com/example/bcsd/Exception/MemberNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Exception; + +public class MemberNotFoundException extends RuntimeException { + public MemberNotFoundException(Long id) { + super("해당 사용자를 찾을 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/HelloController.java b/src/main/java/com/example/bcsd/HelloController.java index 9559e2f1..98b6432c 100644 --- a/src/main/java/com/example/bcsd/HelloController.java +++ b/src/main/java/com/example/bcsd/HelloController.java @@ -1,20 +1,67 @@ package com.example.bcsd; -import org.springframework.stereotype.Controller; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody; -@Controller +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/article") public class HelloController { @ResponseBody - @GetMapping("/hello") - public String hello() { - return "Hello World!!!!!"; + @GetMapping("/{id}") + public ResponseEntity
getArticle(@PathVariable int id) { + Article article = articleMap.get(id); + + if(article == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(article, HttpStatus.OK); } @GetMapping("/hello2") public String hello2() { return "hello"; } + + private Map articleMap = new HashMap<>(); + private int newId = 1; + + @PostMapping + public ResponseEntity
postArticle(@RequestBody Article article) { + article.setId(newId++); + articleMap.put(article.getId(), article); + + return new ResponseEntity<>(article,HttpStatus.CREATED); + } + @PutMapping("/{id}") + public ResponseEntity
putArticle( + @PathVariable int id, + @RequestBody Article updated + ) { + Article existing = articleMap.get(id); + + if (existing == null) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + + existing.setDescription(updated.getDescription()); + return new ResponseEntity<>(existing, HttpStatus.OK); + } + @DeleteMapping("/{id}") + public ResponseEntity deleteArticle(@PathVariable int id) { + Article removed = articleMap.remove(id); + + if(removed == null){ + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + } diff --git a/src/main/java/com/example/bcsd/Info.java b/src/main/java/com/example/bcsd/Info.java new file mode 100644 index 00000000..092fbb25 --- /dev/null +++ b/src/main/java/com/example/bcsd/Info.java @@ -0,0 +1,23 @@ +package com.example.bcsd; + +public class Info { + private int age; + private String name; + + public Info(int age, String name) { + this.age = age; + this.name = name; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} diff --git a/src/main/java/com/example/bcsd/Repository/ArticleRepository.java b/src/main/java/com/example/bcsd/Repository/ArticleRepository.java new file mode 100644 index 00000000..b481fd30 --- /dev/null +++ b/src/main/java/com/example/bcsd/Repository/ArticleRepository.java @@ -0,0 +1,12 @@ +package com.example.bcsd.Repository; + +import com.example.bcsd.model.Article; +import com.example.bcsd.model.Board; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ArticleRepository extends JpaRepository { + + List
findByBoard(Board board); +} diff --git a/src/main/java/com/example/bcsd/Repository/BoardRepository.java b/src/main/java/com/example/bcsd/Repository/BoardRepository.java new file mode 100644 index 00000000..8d665fa0 --- /dev/null +++ b/src/main/java/com/example/bcsd/Repository/BoardRepository.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Repository; + +import com.example.bcsd.model.Board; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface BoardRepository extends JpaRepository { +} diff --git a/src/main/java/com/example/bcsd/Repository/MemberRepository.java b/src/main/java/com/example/bcsd/Repository/MemberRepository.java new file mode 100644 index 00000000..c9a89102 --- /dev/null +++ b/src/main/java/com/example/bcsd/Repository/MemberRepository.java @@ -0,0 +1,11 @@ +package com.example.bcsd.Repository; + +import com.example.bcsd.model.Member; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface MemberRepository extends JpaRepository { + + Optional findByEmail(String email); +} diff --git a/src/main/java/com/example/bcsd/Service/ArticleService.java b/src/main/java/com/example/bcsd/Service/ArticleService.java new file mode 100644 index 00000000..535251cc --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/ArticleService.java @@ -0,0 +1,66 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Repository.ArticleRepository; +import com.example.bcsd.Repository.BoardRepository; +import com.example.bcsd.model.Article; +import com.example.bcsd.model.Board; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +public class ArticleService { + + private final ArticleRepository articleRepository; + private final BoardRepository boardRepository; + + public ArticleService(ArticleRepository articleRepository, BoardRepository boardRepository) { + this.articleRepository = articleRepository; + this.boardRepository = boardRepository; + } + + public Article createArticle(Long authorId, Long boardId, String title, String content) { + Board board = boardRepository.findById(boardId) + .orElseThrow(() -> new IllegalArgumentException("게시판을 찾을 수 없습니다. id=" + boardId)); + + Article article = new Article(authorId, title, content); + board.addArticle(article); + + return article; + } + + @Transactional(readOnly = true) + public Article findArticle(Long id) { + return articleRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("게시물을 찾을 수 없습니다. id=" + id)); + } + + @Transactional(readOnly = true) + public List
findAllArticles() { + return articleRepository.findAll(); + } + + public Article updateArticle(Long id, String title, String content) { + Article article = articleRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("게시물을 찾을 수 없습니다. id=" + id)); + + article.changeTitle(title); + article.changeContent(content); + + return article; + } + + public void deleteArticle(Long id) { + articleRepository.deleteById(id); + } + + @Transactional(readOnly = true) + public List
getArticlesByBoardId(Long boardId) { + Board board = boardRepository.findById(boardId) + .orElseThrow(() -> new IllegalArgumentException("게시판을 찾을 수 없습니다. id=" + boardId)); + + return board.getArticles(); + } +} diff --git a/src/main/java/com/example/bcsd/Service/BoardService.java b/src/main/java/com/example/bcsd/Service/BoardService.java new file mode 100644 index 00000000..0e9545cb --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/BoardService.java @@ -0,0 +1,45 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Repository.BoardRepository; +import com.example.bcsd.model.Board; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +public class BoardService { + + private final BoardRepository boardRepository; + + public BoardService(BoardRepository boardRepository) { + this.boardRepository = boardRepository; + } + + public Board createBoard(String name) { + Board board = new Board(name); + return boardRepository.save(board); + } + + @Transactional(readOnly = true) + public Board findBoard(Long id) { + return boardRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("게시판을 찾을 수 없습니다. id=" + id)); + } + + @Transactional(readOnly = true) + public List findAllBoards() { + return boardRepository.findAll(); + } + + public Board updateBoard(Long id, String name) { + Board board = findBoard(id); + board.changeName(name); + return board; + } + + public void deleteBoard(Long id) { + boardRepository.deleteById(id); + } +} diff --git a/src/main/java/com/example/bcsd/Service/MemberService.java b/src/main/java/com/example/bcsd/Service/MemberService.java new file mode 100644 index 00000000..ced9f6ba --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/MemberService.java @@ -0,0 +1,71 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Repository.MemberRepository; +import com.example.bcsd.dto.MemberCreateRequest; +import com.example.bcsd.dto.MemberLoginRequest; +import com.example.bcsd.dto.MemberUpdateRequest; +import com.example.bcsd.model.Member; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class MemberService { + + private final MemberRepository memberRepository; + + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + public List findAllMembers() { + return memberRepository.findAll(); + } + + public Member findMember(Long id) { + return memberRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Member not found")); + } + + public Member createMember(MemberCreateRequest request) { + Member member = new Member( + request.getName(), + request.getEmail(), + request.getPassword() + ); + return memberRepository.save(member); + } + + public Member updateMember(Long id, MemberUpdateRequest request) { + Member member = findMember(id); + member.changeName(request.getName()); + member.changePassword(request.getPassword()); + return member; + } + + public void deleteMember(Long id) { + memberRepository.deleteById(id); + } + + public Member login(MemberLoginRequest request) { + Member member = memberRepository.findByEmail(request.getEmail()) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 이메일입니다.")); + + if (!member.getPassword().equals(request.getPassword())) { + throw new IllegalArgumentException("비밀번호가 일치하지 않습니다."); + } + + return member; + } + + public Member login(String email, String password) { + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 이메일입니다.")); + + if (!member.getPassword().equals(password)) { + throw new IllegalArgumentException("비밀번호가 일치하지 않습니다."); + } + + return member; + } +} diff --git a/src/main/java/com/example/bcsd/dto/ArticleCreateRequest.java b/src/main/java/com/example/bcsd/dto/ArticleCreateRequest.java new file mode 100644 index 00000000..839a7987 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/ArticleCreateRequest.java @@ -0,0 +1,25 @@ +package com.example.bcsd.dto; + +public class ArticleCreateRequest { + + private Long authorId; + private Long boardId; + private String title; + private String content; + + public Long getAuthorId() { + return authorId; + } + + public Long getBoardId() { + return boardId; + } + + public String getTitle() { + return title; + } + + public String getContent() { + return content; + } +} diff --git a/src/main/java/com/example/bcsd/dto/ArticleUpdateRequest.java b/src/main/java/com/example/bcsd/dto/ArticleUpdateRequest.java new file mode 100644 index 00000000..e2f76e3d --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/ArticleUpdateRequest.java @@ -0,0 +1,15 @@ +package com.example.bcsd.dto; + +public class ArticleUpdateRequest { + + private String title; + private String content; + + public String getTitle() { + return title; + } + + public String getContent() { + return content; + } +} diff --git a/src/main/java/com/example/bcsd/dto/BoardCreateRequest.java b/src/main/java/com/example/bcsd/dto/BoardCreateRequest.java new file mode 100644 index 00000000..50b2ed41 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/BoardCreateRequest.java @@ -0,0 +1,10 @@ +package com.example.bcsd.dto; + +public class BoardCreateRequest { + + private String name; + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/example/bcsd/dto/BoardUpdateRequest.java b/src/main/java/com/example/bcsd/dto/BoardUpdateRequest.java new file mode 100644 index 00000000..c7cd108e --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/BoardUpdateRequest.java @@ -0,0 +1,10 @@ +package com.example.bcsd.dto; + +public class BoardUpdateRequest { + + private String name; + + public String getName() { + return name; + } +} diff --git a/src/main/java/com/example/bcsd/dto/LoginRequest.java b/src/main/java/com/example/bcsd/dto/LoginRequest.java new file mode 100644 index 00000000..501bfdc9 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/LoginRequest.java @@ -0,0 +1,23 @@ +package com.example.bcsd.dto; + +public class LoginRequest { + + private String email; + private String password; + + public LoginRequest() { + } + + public LoginRequest(String email, String password) { + this.email = email; + this.password = password; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } +} diff --git a/src/main/java/com/example/bcsd/dto/MemberCreateRequest.java b/src/main/java/com/example/bcsd/dto/MemberCreateRequest.java new file mode 100644 index 00000000..90c7b66c --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/MemberCreateRequest.java @@ -0,0 +1,34 @@ +package com.example.bcsd.dto; + +import com.example.bcsd.model.Member; + +public class MemberCreateRequest { + + private String name; + private String email; + private String password; + + public MemberCreateRequest() {} + + public MemberCreateRequest(String name, String email, String password) { + this.name = name; + this.email = email; + this.password = password; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } + + public Member toEntity() { + return new Member(name, email, password); + } +} diff --git a/src/main/java/com/example/bcsd/dto/MemberLoginRequest.java b/src/main/java/com/example/bcsd/dto/MemberLoginRequest.java new file mode 100644 index 00000000..2ecd4e56 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/MemberLoginRequest.java @@ -0,0 +1,22 @@ +package com.example.bcsd.dto; + +public class MemberLoginRequest { + + private String email; + private String password; + + public MemberLoginRequest() {} + + public MemberLoginRequest(String email, String password) { + this.email = email; + this.password = password; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } +} diff --git a/src/main/java/com/example/bcsd/dto/MemberUpdateRequest.java b/src/main/java/com/example/bcsd/dto/MemberUpdateRequest.java new file mode 100644 index 00000000..787c0c6f --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/MemberUpdateRequest.java @@ -0,0 +1,15 @@ +package com.example.bcsd.dto; + +public class MemberUpdateRequest { + + private String name; + private String password; + + public String getName() { + return name; + } + + public String getPassword() { + return password; + } +} diff --git a/src/main/java/com/example/bcsd/model/Article.java b/src/main/java/com/example/bcsd/model/Article.java new file mode 100644 index 00000000..c403848b --- /dev/null +++ b/src/main/java/com/example/bcsd/model/Article.java @@ -0,0 +1,92 @@ +package com.example.bcsd.model; + +import jakarta.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "article") +public class Article { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "author_id", nullable = false) + private Long authorId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "board_id", nullable = false) + private Board board; + + @Column(nullable = false, length = 255) + private String title; + + @Column(nullable = false, length = 2000) + private String content; + + @Column(name = "created_date", updatable = false) + private LocalDateTime createdDate; + + @Column(name = "modified_date") + private LocalDateTime modifiedDate; + + protected Article() { + } + + public Article(Long authorId, String title, String content) { + this.authorId = authorId; + this.title = title; + this.content = content; + } + + @PrePersist + protected void onCreate() { + this.createdDate = LocalDateTime.now(); + this.modifiedDate = LocalDateTime.now(); + } + + @PreUpdate + protected void onUpdate() { + this.modifiedDate = LocalDateTime.now(); + } + + public Long getId() { + return id; + } + + public Long getAuthorId() { + return authorId; + } + + public Board getBoard() { + return board; + } + + public String getTitle() { + return title; + } + + public String getContent() { + return content; + } + + public LocalDateTime getCreatedDate() { + return createdDate; + } + + public LocalDateTime getModifiedDate() { + return modifiedDate; + } + + void setBoard(Board board) { + this.board = board; + } + + public void changeTitle(String title) { + this.title = title; + } + + public void changeContent(String content) { + this.content = content; + } +} diff --git a/src/main/java/com/example/bcsd/model/Board.java b/src/main/java/com/example/bcsd/model/Board.java new file mode 100644 index 00000000..00c85dc3 --- /dev/null +++ b/src/main/java/com/example/bcsd/model/Board.java @@ -0,0 +1,56 @@ +package com.example.bcsd.model; + +import jakarta.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Table(name = "board") +public class Board { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 100) + private String name; + + @OneToMany( + mappedBy = "board", + cascade = CascadeType.ALL, + orphanRemoval = true + ) + private List
articles = new ArrayList<>(); + + protected Board() {} + + public Board(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public List
getArticles() { + return articles; + } + + public void changeName(String name) { + this.name = name; + } + + public void addArticle(Article article) { + articles.add(article); + article.setBoard(this); + } + + public void removeArticle(Article article) { + articles.remove(article); + article.setBoard(null); + } +} diff --git a/src/main/java/com/example/bcsd/model/Member.java b/src/main/java/com/example/bcsd/model/Member.java new file mode 100644 index 00000000..b513fdc5 --- /dev/null +++ b/src/main/java/com/example/bcsd/model/Member.java @@ -0,0 +1,64 @@ +package com.example.bcsd.model; + +import jakarta.persistence.*; + +@Entity +@Table(name = "member") +public class Member { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String name; + + @Column(nullable = false, unique = true, length = 100) + private String email; + + @Column(nullable = false, length = 255) + private String password; + + protected Member() { + } + + public Member(String name, String email, String password) { + this.name = name; + this.email = email; + this.password = password; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } + + public void changeName(String name) { + this.name = name; + } + + public void changeEmail(String email) { + this.email = email; + } + + public void changePassword(String encodedPassword) { + this.password = encodedPassword; + } + + public void update(String name, String password) { + this.name = name; + this.password = password; + } + +} diff --git a/src/main/resources/templates/introduce.html b/src/main/resources/templates/introduce.html new file mode 100644 index 00000000..c8cf9f7d --- /dev/null +++ b/src/main/resources/templates/introduce.html @@ -0,0 +1,10 @@ + + + + Getting Started: Serving Web Content + + + +

+ + diff --git a/src/main/resources/templates/posts.html b/src/main/resources/templates/posts.html new file mode 100644 index 00000000..3a9a496e --- /dev/null +++ b/src/main/resources/templates/posts.html @@ -0,0 +1,33 @@ + + + + + 자유게시판 + + + + +

자유게시판

+ +
+ +
제목
+ +
+ + | + 날짜 +
+ +
+
+ + +