diff --git a/build.gradle b/build.gradle index db3ebcf1..605a373d 100644 --- a/build.gradle +++ b/build.gradle @@ -18,10 +18,19 @@ repositories { } dependencies { + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-data-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-security' testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + runtimeOnly 'mysql:mysql-connector-java:8.0.33' + + implementation 'org.springframework.boot:spring-boot-starter' } tasks.named('test') { diff --git a/src/main/java/com/example/bcsd/BcsdApplication.java b/src/main/java/com/example/bcsd/BcsdApplication.java index 6e3ecb1b..36808987 100644 --- a/src/main/java/com/example/bcsd/BcsdApplication.java +++ b/src/main/java/com/example/bcsd/BcsdApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @SpringBootApplication +@EnableJpaAuditing public class BcsdApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/bcsd/Dao/ArticleDao.java b/src/main/java/com/example/bcsd/Dao/ArticleDao.java new file mode 100644 index 00000000..762849cd --- /dev/null +++ b/src/main/java/com/example/bcsd/Dao/ArticleDao.java @@ -0,0 +1,18 @@ +package com.example.bcsd.Dao; + +import com.example.bcsd.Model.Article; + +import java.util.List; +import java.util.Optional; + +public interface ArticleDao { + List
findByBoardId(long board_id); + List
findByAuthorId(long author_id); + Article findById(long id); + + Article insert(Article article); + + Article update(Article article); + + boolean delete(long id); +} diff --git a/src/main/java/com/example/bcsd/Dao/BoardDao.java b/src/main/java/com/example/bcsd/Dao/BoardDao.java new file mode 100644 index 00000000..c67268e4 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dao/BoardDao.java @@ -0,0 +1,20 @@ +package com.example.bcsd.Dao; + +import com.example.bcsd.Model.Board; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +public interface BoardDao { + + Board findById(long id); + + Board insert(Board board); + + Board update(Board board); + + boolean delete(long id); + + +} diff --git a/src/main/java/com/example/bcsd/Dao/MemberDao.java b/src/main/java/com/example/bcsd/Dao/MemberDao.java new file mode 100644 index 00000000..36bbaa56 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dao/MemberDao.java @@ -0,0 +1,17 @@ +package com.example.bcsd.Dao; + +import com.example.bcsd.Model.Member; + +public interface MemberDao { + + Member findById(long id); + Member findByEmail(String email); + + Member insert(Member member); + + Member update(Member member); + + boolean delete(long id); + + +} diff --git a/src/main/java/com/example/bcsd/Dto/ArticleCreate.java b/src/main/java/com/example/bcsd/Dto/ArticleCreate.java new file mode 100644 index 00000000..c1996539 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/ArticleCreate.java @@ -0,0 +1,29 @@ +package com.example.bcsd.Dto; + +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Article; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +public record ArticleCreate( + @NotNull(message = "board_id cannot be null") + Long board_id, + @NotNull (message = "author_id cannot be null") + Long author_id, + @NotBlank (message = "title cannot be null") + String title, + @NotBlank (message = "content cannot be null") + String content) { + + + public ArticleCreate of(Long board_id, + Long author_id, + String title, + String content){ + return new ArticleCreate(board_id, author_id, title, content); + } +} + + + + diff --git a/src/main/java/com/example/bcsd/Dto/ArticleResponse.java b/src/main/java/com/example/bcsd/Dto/ArticleResponse.java new file mode 100644 index 00000000..e5413ba7 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/ArticleResponse.java @@ -0,0 +1,31 @@ +package com.example.bcsd.Dto; + +import java.time.LocalDateTime; + +import com.example.bcsd.Model.Article; + +public record ArticleResponse( + Long id, + Long board_id, + Long author_id, + String title, + String content, + LocalDateTime createdDate, + LocalDateTime modifiedDate +) { + + + public static ArticleResponse of( + Long id, Long board_id, + Long author_id, + String title, + String content, + LocalDateTime createdDate, + LocalDateTime modifiedDate + ) { + return new ArticleResponse(id, board_id, author_id, title, content, createdDate, modifiedDate); + } + + +} + diff --git a/src/main/java/com/example/bcsd/Dto/ArticleUpdate.java b/src/main/java/com/example/bcsd/Dto/ArticleUpdate.java new file mode 100644 index 00000000..972ad735 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/ArticleUpdate.java @@ -0,0 +1,15 @@ +package com.example.bcsd.Dto; + +import jakarta.validation.constraints.NotNull; + +public record ArticleUpdate ( + @NotNull(message = "title cannot be null") + String title, + @NotNull(message = "content cannot be null") + String content){ + public static ArticleUpdate of(String title,String content){ + return new ArticleUpdate(title,content); + } + + +} diff --git a/src/main/java/com/example/bcsd/Dto/BoardCreate.java b/src/main/java/com/example/bcsd/Dto/BoardCreate.java new file mode 100644 index 00000000..f2f072ae --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/BoardCreate.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Dto; + +public record BoardCreate( String name) { + public static BoardCreate of( String name) { + return new BoardCreate( name); + } +} diff --git a/src/main/java/com/example/bcsd/Dto/BoardResponse.java b/src/main/java/com/example/bcsd/Dto/BoardResponse.java new file mode 100644 index 00000000..034ad098 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/BoardResponse.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Dto; + +public record BoardResponse( Long id,String name) { + public static BoardResponse of( Long id, String name) { + return new BoardResponse(id, name); + } +} diff --git a/src/main/java/com/example/bcsd/Dto/BoardUpdate.java b/src/main/java/com/example/bcsd/Dto/BoardUpdate.java new file mode 100644 index 00000000..dff0c43d --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/BoardUpdate.java @@ -0,0 +1,7 @@ +package com.example.bcsd.Dto; + +public record BoardUpdate (String name){ + public BoardUpdate of(String name){ + return new BoardUpdate(name); + } +} diff --git a/src/main/java/com/example/bcsd/Dto/LoginResponse.java b/src/main/java/com/example/bcsd/Dto/LoginResponse.java new file mode 100644 index 00000000..469bb1ab --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/LoginResponse.java @@ -0,0 +1,8 @@ +package com.example.bcsd.Dto; + +public record LoginResponse( String email) { + public static LoginResponse of(String email) { + return new LoginResponse( email); + } +} + diff --git a/src/main/java/com/example/bcsd/Dto/MemberCreate.java b/src/main/java/com/example/bcsd/Dto/MemberCreate.java new file mode 100644 index 00000000..da3c551c --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/MemberCreate.java @@ -0,0 +1,16 @@ +package com.example.bcsd.Dto; + +import jakarta.validation.constraints.NotNull; + +public record MemberCreate ( + + @NotNull(message="name cannot be null") + String name, + @NotNull(message="email cannot be null") + String email, + @NotNull(message="password cannot be null") + String password) { + public MemberCreate of(String name, String email, String password) { + return new MemberCreate(name, email, password); + } +} diff --git a/src/main/java/com/example/bcsd/Dto/MemberResponse.java b/src/main/java/com/example/bcsd/Dto/MemberResponse.java new file mode 100644 index 00000000..fadd7141 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/MemberResponse.java @@ -0,0 +1,20 @@ +package com.example.bcsd.Dto; + +import java.time.LocalDateTime; + +public record MemberResponse( + Long id, + String name, + String email, + String password +) { + + + public static MemberResponse of( + Long id, String name, String email, String password + ) { + return new MemberResponse(id, name, email, password); + } + + +} diff --git a/src/main/java/com/example/bcsd/Dto/MemberUpdate.java b/src/main/java/com/example/bcsd/Dto/MemberUpdate.java new file mode 100644 index 00000000..46c4bd59 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/MemberUpdate.java @@ -0,0 +1,19 @@ +package com.example.bcsd.Dto; + +import jakarta.validation.constraints.NotNull; + +public record MemberUpdate ( + @NotNull(message = "name cannot be null") + String name, + @NotNull(message = "email cannot be null") + String email, + @NotNull(message = "email cannot be null") + String password +) + { + public static MemberUpdate of(String name,String email, String password){ + return new MemberUpdate(name,email,password); + } + + +} 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..1c5a42e1 --- /dev/null +++ b/src/main/java/com/example/bcsd/Dto/loginRequest.java @@ -0,0 +1,15 @@ +package com.example.bcsd.Dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +public record loginRequest( + @NotNull(message="로그인 이메일이 비어있습니다.") + String email, + @NotNull(message="로그인 비밀번호이가 비어있습니다.") + String password) { + + public static loginRequest of(String email, String password) { + return new loginRequest(email, password); + } +} diff --git a/src/main/java/com/example/bcsd/HelloController.java b/src/main/java/com/example/bcsd/HelloController.java index 9559e2f1..72e95f9e 100644 --- a/src/main/java/com/example/bcsd/HelloController.java +++ b/src/main/java/com/example/bcsd/HelloController.java @@ -1,20 +1,36 @@ package com.example.bcsd; import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import java.util.HashMap; +import java.util.Map; + @Controller public class HelloController { - @ResponseBody - @GetMapping("/hello") - public String hello() { - return "Hello World!!!!!"; - } - @GetMapping("/hello2") - public String hello2() { + //@GetMapping("/introduce") + //public String introduce(@RequestParam(name="name" , required=false, defaultValue = "조원희") String name, Model model) { + // model.addAttribute("name", name); + //return "hello"; + + //} + @GetMapping("/introduce") + public String introduce() { + // Thymeleaf가 templates/introduce.html 을 렌더링 return "hello"; } + + @GetMapping("/json") + @ResponseBody + public Map json() { + Map result = new HashMap<>(); + result.put("age", 24); + result.put("name", "조원희"); + return result; + } } 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..c68eeb62 --- /dev/null +++ b/src/main/java/com/example/bcsd/Model/Article.java @@ -0,0 +1,120 @@ +package com.example.bcsd.Model; + + +import jakarta.persistence.*; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import java.time.LocalDateTime; + +@Entity +@Table(name = "article") +@EntityListeners(AuditingEntityListener.class) +public class Article { + @Column(name="title") + private String title; + @Lob + @Column(name="content") + private String content; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name="id") + private Long id; + @Column(name="author_id") + private Long author_id; + @Column(name="board_id",insertable = false, updatable = false) + private Long board_id; + @Column(name="created_date") + @CreatedDate + private LocalDateTime created_date; + @Column(name="modified_date") + @LastModifiedDate + private LocalDateTime modified_date; + @ManyToOne(fetch= FetchType.LAZY) + @JoinColumn(name="board_id") + private Board board; + public void Board(Board board){ + this.board = board; + } + public Article() { + } + + public Article(Long id, String title, String content, LocalDateTime created_date, LocalDateTime modified_date, Long author_id, Long board_id) { + this.id = id; + this.title = title; + this.content = content; + this.created_date = created_date; + this.modified_date = modified_date; + this.author_id = author_id; + this.board_id = board_id; + } + + public Long getAuthor_id() { + return author_id; + } + + public void setAuthor_id(Long author_id) { + this.author_id = author_id; + } + + public Long getBoard_id() { + return board_id; + } + + public void setBoard_id(Long board_id) { + this.board_id = board_id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public LocalDateTime getCreated_date() { + return created_date; + } + + public void update(String title, String content, LocalDateTime modified_date) { + this.title = title; + this.content = content; + this.modified_date = modified_date; + } + + public void setCreated_date(LocalDateTime created_date) { + this.created_date = created_date; + } + + public LocalDateTime getModified_date() { + return modified_date; + } + + public void setModified_date(LocalDateTime modified_date) { + this.modified_date = modified_date; + } + + public String toString() { + return "title: " + title + "\ncontent: " + content + "\ndate: " + created_date + "\nname: " + author_id + "\nboard_id: " + board_id + "\nmodified_date: " + modified_date; + } + + +} 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..658f25cd --- /dev/null +++ b/src/main/java/com/example/bcsd/Model/Board.java @@ -0,0 +1,44 @@ +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(name = "name") + private String name; + + @OneToMany(mappedBy = "board", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY + ) + private List
articles = new ArrayList<>(); + + public Board() { + } + + public Board(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} 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..f2dc32b4 --- /dev/null +++ b/src/main/java/com/example/bcsd/Model/Member.java @@ -0,0 +1,51 @@ +package com.example.bcsd.Model; + +import jakarta.persistence.*; + +@Entity +@Table(name="member") +public class Member { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name="name") + private String name; + @Column(name="email") + private String email; + @Column(name="password") + private String password; + + public Member() {} + public Member(Long id, String name, String email, String password) { + this.id = id; + this.name = name; + this.email = email; + this.password = password; + } + + public Long getId() { + return id; + } + public void setId(Long id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + public String getPassword() { + return password; + } + public void setPassword(String password) { + this.password = password; + } +} + 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..7ae7f173 --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/ArticleService.java @@ -0,0 +1,132 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Dao.ArticleDao; +import com.example.bcsd.Dao.BoardDao; +import com.example.bcsd.Dao.MemberDao; +import com.example.bcsd.Dto.ArticleCreate; +import com.example.bcsd.Dto.ArticleResponse; +import com.example.bcsd.Dto.ArticleUpdate; +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Board; +import com.example.bcsd.Model.Member; +import jakarta.persistence.EntityNotFoundException; +import org.apache.coyote.BadRequestException; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ArticleService { + private final ArticleDao articleDao; + private final MemberDao memberDao; + private final BoardDao boardDao; + public ArticleService(ArticleDao articleDao, MemberDao memberDao, BoardDao boardDao) { + this.articleDao = articleDao; + this.memberDao = memberDao; + this.boardDao = boardDao; + + } + + @Transactional + public List getArticlesByBoardId(Long board_id) { + if(articleDao.findByBoardId(board_id)==null){ + throw new EntityNotFoundException("Article Not Found"+"(board_id:"+board_id+")");} + return articleDao.findByBoardId(board_id).stream().map(a -> ArticleResponse.of( + a.getId(), + a.getBoard_id(), + a.getAuthor_id(), + a.getTitle(), + a.getContent(), + a.getCreated_date(), + a.getModified_date() + )) + .collect(Collectors.toList()); + } + @Transactional + public ArticleResponse getArticleById(Long id) { + if(articleDao.findById(id)==null){ + throw new EntityNotFoundException("Article Not Found"+"(id:"+id+")"); + } + Article article = articleDao.findById(id); + return ArticleResponse.of(article.getId(), + article.getBoard_id(), + article.getAuthor_id(), + article.getTitle(), + article.getContent(), + article.getCreated_date(), + article.getModified_date()); + + } + + @Transactional + public ArticleResponse createArticle(ArticleCreate request) throws IllegalAccessException { + if( memberDao.findById(request.author_id())==null){ + throw new IllegalAccessException("Member Not Found"+"(author_id:"+request.author_id()+")"); + } + if(boardDao.findById(request.board_id())==null){ + throw new IllegalAccessException("Board Not Found"+"(id:"+request.board_id()+")"); + } + + + + Article toSave = articleDao.findById(request.author_id()); + toSave.setBoard_id(request.board_id()); + toSave.setAuthor_id(request.author_id()); + toSave.setTitle(request.title()); + toSave.setContent(request.content()); + LocalDateTime now = LocalDateTime.now(); + toSave.setCreated_date(now); + toSave.setModified_date(now); + + Article saved = articleDao.insert(toSave); + + return ArticleResponse.of( + saved.getId(), + saved.getBoard_id(), + saved.getAuthor_id(), + saved.getTitle(), + saved.getContent(), + saved.getCreated_date(), + saved.getModified_date() + ); + + } + + @Transactional + public ArticleResponse updateArticle(ArticleUpdate update, Long id) throws IllegalAccessException { + if(articleDao.findById(id)==null){ + throw new IllegalAccessException("Article with id: " + id + " not found!"); + } + Article articles = articleDao.findById(id); + + if(update.title() != null && !update.title().isBlank()) { + articles.setTitle(update.title()); + } + if(update.content() != null && !update.content().isBlank()) { + articles.setContent(update.content()); + } + articles.setModified_date(LocalDateTime.now()); + articleDao.update(articles); + return ArticleResponse.of(articles.getId(), + articles.getBoard_id(), + articles.getAuthor_id(), + articles.getTitle(), + articles.getContent(), + articles.getCreated_date(), + articles.getModified_date()); + } + + @Transactional + public void deleteArticle(Long id) { + if (!articleDao.delete(id)) { + throw new NullPointerException("해당 id가 존재하지 않습니다."); + } + } + + + +} 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..2e5bef01 --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/BoardService.java @@ -0,0 +1,82 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Dao.ArticleDao; +import com.example.bcsd.Dao.BoardDao; +import com.example.bcsd.Dto.BoardCreate; +import com.example.bcsd.Dto.BoardResponse; +import com.example.bcsd.Dto.BoardUpdate; +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Board; +import com.example.bcsd.repository.BoardRepository; +import jakarta.persistence.EntityExistsException; +import jakarta.persistence.EntityNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class BoardService { + private final BoardDao boardDao; + private final ArticleDao articleDao; + + public BoardService(BoardDao boardDao, ArticleDao articleDao) { + this.articleDao = articleDao; + this.boardDao = boardDao; + } + + @Transactional + public BoardResponse findById(long id) { + if (boardDao.findById(id) == null) { + throw new EntityNotFoundException("Board with id: " + id + " not found!"); + + } + Board board = boardDao.findById(id); + return BoardResponse.of( + board.getId(), + board.getName() + + ); + } + + @Transactional + public BoardResponse insert(BoardCreate board) { + if (board.name().isEmpty()) { + throw new EntityNotFoundException("Board name empty!"); + } + Board board1 = new Board(); + board1.setName(board.name()); + Board board2 = boardDao.insert(board1); + return BoardResponse.of( + board2.getId(), + board2.getName() + ); + } + + @Transactional + public BoardResponse update(BoardUpdate board, long id) { + if (boardDao.findById(id) == null) { + throw new EntityNotFoundException("Board with id: " + id + " not found!"); + } + Board board1 = boardDao.findById(id); + board1.setName(board.name()); + Board board2 = boardDao.update(board1); + return BoardResponse.of( + board2.getId(), + board2.getName() + ); + } + + @Transactional + public void delete(Long id) throws IllegalAccessException { + if (!articleDao.findByBoardId(id).isEmpty()) { + throw new IllegalAccessException("연결된 article 존재"); + } + + + boolean deleted = boardDao.delete(id); + if (!deleted) { + throw new EntityNotFoundException("해당 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..276ca5d0 --- /dev/null +++ b/src/main/java/com/example/bcsd/Service/MemberService.java @@ -0,0 +1,105 @@ +package com.example.bcsd.Service; + +import com.example.bcsd.Dao.ArticleDao; +import com.example.bcsd.Dao.MemberDao; +import com.example.bcsd.Dto.*; +import com.example.bcsd.Model.Member; +import com.example.bcsd.exception.Emailexception; +import jakarta.persistence.EntityExistsException; +import jakarta.persistence.EntityNotFoundException; +import org.springframework.http.HttpStatus; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.server.ResponseStatusException; + +import java.util.Optional; + +@Service +public class MemberService { + private final ArticleDao articleDao; + private final MemberDao memberDao; + private final PasswordEncoder passwordEncoder; + public MemberService(MemberDao memberDao, ArticleDao articleDao, PasswordEncoder passwordEncoder) { + this.memberDao = memberDao; + this.articleDao = articleDao; + this.passwordEncoder = passwordEncoder; + } + public MemberResponse findmemberById(long id) { + if(memberDao.findById(id)==null){ + throw new EntityNotFoundException("Member with id: " + id + " not found!"); + } + Member member= memberDao.findById(id); + + return MemberResponse.of( + member.getId(), + member.getName(), + member.getEmail(), + member.getPassword() + ); + } + @Transactional + public MemberResponse insertMember(MemberCreate member) { + if(memberDao.findByEmail(member.email())!=null){ + throw new Emailexception(member.email()); + } + + Member insert=new Member(); + insert.setName(member.name()); + insert.setEmail(member.email()); + insert.setPassword(member.password()); + + Member save = memberDao.insert(insert); + return MemberResponse.of( + save.getId(), + save.getName(), + save.getEmail(), + save.getPassword() + ); + } + @Transactional + public MemberResponse updateMember(MemberUpdate update,Long id) { + if(memberDao.findById(id)==null){ + throw new EntityNotFoundException("Member with id: " + id + " not found!"); + } + + Member update1=memberDao.findById(id); + update1.setName(update.name()); + update1.setEmail(update.email()); + update1.setPassword(update.password()); + + memberDao.update(update1); + return MemberResponse.of( + update1.getId(), + update1.getName(), + update1.getEmail(), + update1.getPassword() + ); + } + @Transactional + public void deleteMember(Long id) { + if (!articleDao.findByAuthorId(id).isEmpty()) { + throw new EntityExistsException("사용자가 작성한 게시물이 존재합니다."); + } + + boolean deleted = memberDao.delete(id); + if (!deleted) { + throw new EntityNotFoundException("해당 id가 존재하지 않습니다."); + } + + } + @Transactional + public LoginResponse login(loginRequest loginRequest) { + Member member=memberDao.findByEmail(loginRequest.email()); + if(member==null){ + throw new Emailexception(loginRequest.email()); + } + if(!passwordEncoder.matches(loginRequest.password(), member.getPassword())){ + throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "비밀번호가 일치하지 않습니다."); } + return LoginResponse.of(member.getEmail()); + } + + + +} 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..6058a55d --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/ArticleController.java @@ -0,0 +1,57 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.Dto.ArticleCreate; +import com.example.bcsd.Dto.ArticleResponse; + +import com.example.bcsd.Dto.ArticleUpdate; +import com.example.bcsd.Service.ArticleService; +import org.springframework.http.ResponseEntity; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import jakarta.validation.Valid; +import java.net.URI; +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/articles") +public class ArticleController { + private ArticleService articleService; + + public ArticleController(ArticleService articleService ) { + this.articleService = articleService; + + } + + + @GetMapping + public List getArticlesByBoardId(@RequestParam("boardId") Long board_id) { + return articleService.getArticlesByBoardId(board_id); + } + + + @GetMapping("/{id}") + public ResponseEntity getArticle(@PathVariable Long id) { + ArticleResponse response = articleService.getArticleById(id); + return ResponseEntity.ok(response); + } + + @PostMapping + public ResponseEntity createArticle(@Valid @RequestBody ArticleCreate article) throws IllegalAccessException { + ArticleResponse response = articleService.createArticle(article); + return ResponseEntity.created(URI.create("/" + response.id())).body(response); + } + + @PutMapping("/{id}") + public ResponseEntity updateArticle(@PathVariable Long id, @Valid @RequestBody ArticleUpdate article) throws IllegalAccessException { + ArticleResponse re = articleService.updateArticle(article,id); + return ResponseEntity.ok(re); + } + + @DeleteMapping("/{id}") + public void deleteArticle(@PathVariable Long id) { + articleService.deleteArticle(id); + } + + +} \ No newline at end of file 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..30c55575 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/BoardController.java @@ -0,0 +1,39 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.Dto.BoardCreate; +import com.example.bcsd.Dto.BoardResponse; +import com.example.bcsd.Dto.BoardUpdate; +import com.example.bcsd.Service.BoardService; +import com.example.bcsd.Model.Board; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; +import java.util.Map; +@RestController +public class BoardController { + private final BoardService boardService; + public BoardController(BoardService boardService) { + this.boardService = boardService; + } + @PostMapping("/board") + public ResponseEntity addBoard(@RequestBody BoardCreate board) { + BoardResponse newBoard = boardService.insert(board); + return ResponseEntity.created(URI.create("/board")).body(newBoard); + } + @PutMapping("/board/{id}") + public ResponseEntity uqdateBoard(@PathVariable Long id, @RequestBody BoardUpdate board) { + + BoardResponse res=boardService.update(board,id); + return ResponseEntity.ok(res); + } + + @DeleteMapping("/board/{id}") + public ResponseEntity deleteBoard(@PathVariable Long id) throws IllegalAccessException { + boardService.delete(id); + + return ResponseEntity.noContent().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..73efba00 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/LoginController.java @@ -0,0 +1,55 @@ +package com.example.bcsd.controller; + + +import com.example.bcsd.Dto.LoginResponse; +import com.example.bcsd.Dto.loginRequest; +import com.example.bcsd.Service.MemberService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class LoginController { + private final MemberService memberService; + + public LoginController(MemberService memberService) { + this.memberService = memberService; + } + + @GetMapping("/login") + public String checkLogin() { + + return "OK"; + } + + @PostMapping("/login") + public LoginResponse login(@Valid @RequestBody loginRequest loginRequest, + HttpServletRequest request) { + + LoginResponse loginResponse = memberService.login(loginRequest); + HttpSession oldSession = request.getSession(false); + if (oldSession != null) { + oldSession.invalidate(); + } + HttpSession session = request.getSession(true); + session.setAttribute("LOGIN_MEMBER_EMAIL", loginResponse.email()); + session.setMaxInactiveInterval(30 * 60); + return LoginResponse.of( + loginResponse.email() + + ); + + } + + @PostMapping("/logout") + public void logout(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + } +} 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..6d762ab0 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -0,0 +1,46 @@ +package com.example.bcsd.controller; + + +import com.example.bcsd.Dao.MemberDao; +import com.example.bcsd.Dto.ArticleUpdate; +import com.example.bcsd.Dto.MemberCreate; +import com.example.bcsd.Dto.MemberResponse; +import com.example.bcsd.Dto.MemberUpdate; +import com.example.bcsd.Model.Member; + +import com.example.bcsd.Service.MemberService; +import jakarta.validation.Valid; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; +import java.util.Map; +import java.util.Optional; + +@RestController +public class MemberController { + private final MemberService memberService; + public MemberController(MemberService memberService) { + this.memberService = memberService; + } + + @PostMapping("/member") + public ResponseEntity addMember(@Valid @RequestBody MemberCreate member) { + MemberResponse newMember = memberService.insertMember(member); + return ResponseEntity.created(URI.create("/"+newMember.id())).body(newMember); + } + @PutMapping("/member/{id}") + public ResponseEntity updateMember(@PathVariable Long id, @RequestBody MemberUpdate update) { + MemberResponse reponse= memberService.updateMember(update,id); + + // 변경된 정보를 다시 조회해서 돌려줄 수도 있습니다. + return ResponseEntity.ok(reponse); + } + + @DeleteMapping("/member/{id}") + public ResponseEntity deleteMember(@PathVariable Long id) { + memberService.deleteMember(id); + + return ResponseEntity.noContent().build(); + } +} diff --git a/src/main/java/com/example/bcsd/controller/PostsController.java b/src/main/java/com/example/bcsd/controller/PostsController.java new file mode 100644 index 00000000..754574ca --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/PostsController.java @@ -0,0 +1,36 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.Dao.ArticleDao; +import com.example.bcsd.Dao.BoardDao; +import com.example.bcsd.Dto.ArticleResponse; +import com.example.bcsd.Dto.BoardResponse; +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Board; +import com.example.bcsd.Service.ArticleService; +import com.example.bcsd.Service.BoardService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; +@Controller +public class PostsController { + private final BoardService boardService; + private ArticleService articleService; + + public PostsController(ArticleService articleService,BoardService boardService) { + this.articleService = articleService; + this.boardService = boardService; + } + + @GetMapping("/posts") + public String viewPosts(@RequestParam("boardId") Long board_id, Model model) { + BoardResponse board = boardService.findById(board_id); + List list = articleService.getArticlesByBoardId(board_id); + + model.addAttribute("boardName", board.name()); + model.addAttribute("posts", list); + return "posts"; + } +} diff --git a/src/main/java/com/example/bcsd/exception/Emailexception.java b/src/main/java/com/example/bcsd/exception/Emailexception.java new file mode 100644 index 00000000..9f27b359 --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/Emailexception.java @@ -0,0 +1,15 @@ +package com.example.bcsd.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.CONFLICT) + +public class Emailexception extends RuntimeException { + + + public Emailexception(String email) { + super("이미 존재하는 이메일: " + email); + } + +} diff --git a/src/main/java/com/example/bcsd/exception/Globarexception.java b/src/main/java/com/example/bcsd/exception/Globarexception.java new file mode 100644 index 00000000..ca885c4d --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/Globarexception.java @@ -0,0 +1,62 @@ +package com.example.bcsd.exception; + +import jakarta.persistence.EntityExistsException; +import jakarta.persistence.EntityNotFoundException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@RestControllerAdvice +public class Globarexception { + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Map handleValidation(MethodArgumentNotValidException ex) { + return ex.getBindingResult().getFieldErrors().stream() + .collect(Collectors.toMap( + fe -> fe.getField(), + fe -> fe.getDefaultMessage() + )); + } + //400 + @ExceptionHandler(IllegalAccessException.class) + public ResponseEntity handleIllegalAccess(IllegalAccessException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } + @ExceptionHandler(EntityNotFoundException.class) + public ResponseEntity handleEntityNotFound(EntityNotFoundException ex) { + return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); + + } + @ExceptionHandler(EntityExistsException.class) + public ResponseEntity handleEntityExistsException(EntityExistsException ex) { + return ResponseEntity.status( HttpStatus.BAD_REQUEST).body(ex.getMessage()); + + } + @ExceptionHandler(Exception.class)// + public ResponseEntity handleInternalError(Exception ex) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); + } + + @ExceptionHandler(Emailexception.class) + public ResponseEntity handleMethodArgumentNotValid(Emailexception ex) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); + } + @ExceptionHandler(IncorrectResultSizeDataAccessException.class) + public ResponseEntity handleNoResult(IncorrectResultSizeDataAccessException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ex.getMessage()); + } + + +} diff --git a/src/main/java/com/example/bcsd/passwordEncoder/SecurityConfig.java b/src/main/java/com/example/bcsd/passwordEncoder/SecurityConfig.java new file mode 100644 index 00000000..ab53301d --- /dev/null +++ b/src/main/java/com/example/bcsd/passwordEncoder/SecurityConfig.java @@ -0,0 +1,16 @@ +package com.example.bcsd.passwordEncoder; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file 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..702ed7d7 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -0,0 +1,61 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.Dao.ArticleDao; +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Board; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.transaction.Transactional; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; + +import java.sql.PreparedStatement; +import java.util.*; + +@Repository +@Transactional +public class ArticleRepository implements ArticleDao { + @PersistenceContext + private EntityManager em; + + @Override + public Article insert(Article article){ + em.persist(article); + return article; + } + + @Override + public List
findByBoardId(long board_id) { + String jpql = "select a from Article a where a.board_id=:board_id"; + return em.createQuery(jpql,Article.class).setParameter("board_id",board_id).getResultList(); + } + public List
findByAuthorId(long author_id){ + String jpql = "select a from Article a where a.author_id=:author_id"; + return em.createQuery(jpql,Article.class).setParameter("author_id",author_id).getResultList(); + }; + + @Override + public Article findById(long id) { + return em.find(Article.class, id); + + } + + + public Article update(Article article) { + return em.merge(article); + } + + public boolean delete(long id) { + Article article = em.find(Article.class, id); + if (article != null) { + em.remove(article); + return true; + } + return false; + } + + + + +} 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..7f2756f2 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -0,0 +1,42 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.Dao.BoardDao; +import com.example.bcsd.Model.Article; +import com.example.bcsd.Model.Board; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.stereotype.Repository; + +@Repository +public class BoardRepository implements BoardDao { + @PersistenceContext + private EntityManager em; + + @Override + public Board findById(long id) { + return em.find(Board.class, id); + } + + + @Override + public Board insert(Board board) { + + + em.persist(board); + return board; + } + + public Board update(Board board) { + return em.merge(board); + } + + public boolean delete(long id) { + Board b = em.find(Board.class, id); + if (b != null) { + em.remove(b); + return true; + } + return false; + } + +} 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..a3756fb1 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -0,0 +1,55 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.Dao.MemberDao; +import com.example.bcsd.Model.Board; +import com.example.bcsd.Model.Member; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import org.springframework.stereotype.Repository; + +@Repository +public class MemberRepository implements MemberDao { + @PersistenceContext + private EntityManager em; + + + @Override + public Member findById(long id) { + + return em.find(Member.class, id); + + } + + + @Override + public Member findByEmail(String email) { + + String jpql = "select m from Member m where m.email=:email"; + try{ return em.createQuery(jpql, Member.class).setParameter("email",email).getSingleResult();} + catch (NoResultException e){ + return null; + } + + } + + @Override + public Member insert(Member member) { + + em.persist(member); + return member; + } + + public Member update(Member member) { + return em.merge(member); + } + + public boolean delete(long id) { + Board b = em.find(Board.class, id); + if (b != null) { + em.remove(b); + return true; + } + return false; + } +} diff --git a/src/main/resources/templates/hello.html b/src/main/resources/templates/hello.html index 09349e2d..ddc857d7 100644 --- a/src/main/resources/templates/hello.html +++ b/src/main/resources/templates/hello.html @@ -1,9 +1,11 @@ - + - 안녕하세요 + introduce + -

안녕!!!

+

안녕하세요 제 이름은 + 입니다.

- \ No newline at end of file + diff --git a/src/main/resources/templates/posts.html b/src/main/resources/templates/posts.html new file mode 100644 index 00000000..3742bfc5 --- /dev/null +++ b/src/main/resources/templates/posts.html @@ -0,0 +1,21 @@ + + + + + Board Posts + + +

게시판 이름

+
+

제목

+

+ 작성자 | + 게시물 | + 게시된 날짜 + 수정된 날짜 +

+
내용
+
+ + +