diff --git a/README.md b/README.md index 0a0d3b4..6c9f94a 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,5 @@ ## API Documentation -### Base URL - -``` -http://localhost:8080 -``` - ### Endpoints | Method | Endpoint | Description | Parameters | Headers | Body | diff --git a/build.gradle b/build.gradle index 728ec9c..af5fc58 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0' + implementation 'org.springframework.boot:spring-boot-starter-security' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testCompileOnly 'org.projectlombok:lombok' + testAnnotationProcessor 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' testImplementation 'org.springframework.boot:spring-boot-starter-test' } diff --git a/src/main/java/com/example/demo/AOPexception/ExceptHandler.java b/src/main/java/com/example/demo/AOPexception/ExceptHandler.java new file mode 100644 index 0000000..0e50deb --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/ExceptHandler.java @@ -0,0 +1,70 @@ +package com.example.demo.AOPexception; + +import com.example.demo.AOPexception.Exception.*; +import org.apache.coyote.BadRequestException; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +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 ExceptHandler { + @ExceptionHandler + public ResponseEntity handleException(GetNotFoundException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.NOT_FOUND); + } + @ExceptionHandler + public ResponseEntity handleException(PutDuplicatedException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.CONFLICT); + } + @ExceptionHandler + public ResponseEntity handleException(PutNotFoundException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.BAD_REQUEST); + } + @ExceptionHandler + public ResponseEntity handleException(PostIllegalArgumemtException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.BAD_REQUEST); + } + @ExceptionHandler + public ResponseEntity handleException(PostNotFoundException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.BAD_REQUEST); + } + @ExceptionHandler + public ResponseEntity handleException(DeleteExistedExcepton e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler + public ResponseEntity handleException(RuntimeException e) { + return new ResponseEntity<>(new ErrorResponse(e.getMessage()),HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationExceptions(MethodArgumentNotValidException ex) { + Map errors = new HashMap<>(); + ex.getBindingResult().getAllErrors().forEach(error -> { + String fieldName = ((FieldError) error).getField(); + String errorMessage = error.getDefaultMessage(); + errors.put(fieldName, errorMessage); + }); + return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); + } + + static class ErrorResponse { + String message; + + ErrorResponse(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/DeleteExistedExcepton.java b/src/main/java/com/example/demo/AOPexception/Exception/DeleteExistedExcepton.java new file mode 100644 index 0000000..5061984 --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/DeleteExistedExcepton.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class DeleteExistedExcepton extends RuntimeException{ + public DeleteExistedExcepton(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/GetNotFoundException.java b/src/main/java/com/example/demo/AOPexception/Exception/GetNotFoundException.java new file mode 100644 index 0000000..10c1e90 --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/GetNotFoundException.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class GetNotFoundException extends RuntimeException{ + public GetNotFoundException(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/PostIllegalArgumemtException.java b/src/main/java/com/example/demo/AOPexception/Exception/PostIllegalArgumemtException.java new file mode 100644 index 0000000..a930bb0 --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/PostIllegalArgumemtException.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class PostIllegalArgumemtException extends RuntimeException{ + public PostIllegalArgumemtException(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/PostNotFoundException.java b/src/main/java/com/example/demo/AOPexception/Exception/PostNotFoundException.java new file mode 100644 index 0000000..57f33bb --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/PostNotFoundException.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class PostNotFoundException extends RuntimeException{ + public PostNotFoundException(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/PutDuplicatedException.java b/src/main/java/com/example/demo/AOPexception/Exception/PutDuplicatedException.java new file mode 100644 index 0000000..8844268 --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/PutDuplicatedException.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class PutDuplicatedException extends RuntimeException{ + public PutDuplicatedException(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/AOPexception/Exception/PutNotFoundException.java b/src/main/java/com/example/demo/AOPexception/Exception/PutNotFoundException.java new file mode 100644 index 0000000..06f910a --- /dev/null +++ b/src/main/java/com/example/demo/AOPexception/Exception/PutNotFoundException.java @@ -0,0 +1,8 @@ +package com.example.demo.AOPexception.Exception; + +public class PutNotFoundException extends RuntimeException{ + public PutNotFoundException(String msg) + { + super(msg); + } +} diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index 094d95b..23607a4 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +@EnableAspectJAutoProxy @SpringBootApplication public class DemoApplication { diff --git a/src/main/java/com/example/demo/config/AppConfig.java b/src/main/java/com/example/demo/config/AppConfig.java new file mode 100644 index 0000000..3f88905 --- /dev/null +++ b/src/main/java/com/example/demo/config/AppConfig.java @@ -0,0 +1,14 @@ +package com.example.demo.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class AppConfig { + @Bean + public PasswordEncoder passwordEncoder() { + return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/config/SecurityConfig.java b/src/main/java/com/example/demo/config/SecurityConfig.java new file mode 100644 index 0000000..683c785 --- /dev/null +++ b/src/main/java/com/example/demo/config/SecurityConfig.java @@ -0,0 +1,33 @@ +package com.example.demo.config; + +import org.springframework.context.annotation.Bean; +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.web.SecurityFilterChain; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { + httpSecurity + .csrf(AbstractHttpConfigurer::disable) + .formLogin(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(authorize -> authorize + .requestMatchers("/members/**").permitAll() + .anyRequest().authenticated()) + .exceptionHandling(configurer -> { + configurer.authenticationEntryPoint(((request, response, authException) -> { + + })); + configurer.accessDeniedHandler(((request, response, accessDeniedException) -> { + + })); + }); + return httpSecurity.build(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/controller/BoardController.java b/src/main/java/com/example/demo/controller/BoardController.java index ada81dc..baf6946 100644 --- a/src/main/java/com/example/demo/controller/BoardController.java +++ b/src/main/java/com/example/demo/controller/BoardController.java @@ -18,7 +18,7 @@ @RestController public class BoardController { - + // 과제 수행함 private final BoardService boardService; public BoardController(BoardService boardService) { diff --git a/src/main/java/com/example/demo/controller/MemberController.java b/src/main/java/com/example/demo/controller/MemberController.java index ddb18ec..68d04fa 100644 --- a/src/main/java/com/example/demo/controller/MemberController.java +++ b/src/main/java/com/example/demo/controller/MemberController.java @@ -2,7 +2,17 @@ import java.util.List; +import com.example.demo.controller.dto.request.MemberLoginRequest; +import com.example.demo.domain.Member; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -31,9 +41,46 @@ public ResponseEntity> getMembers() { return ResponseEntity.ok(response); } + @PostMapping("/members/login") + public ResponseEntity login( + @RequestBody MemberLoginRequest request, + HttpSession session + ) { + Member existingUser = (Member) session.getAttribute("loginUser"); + if (existingUser != null) { + return ResponseEntity.status(HttpStatus.FOUND) + .header(HttpHeaders.LOCATION, "/members/info") + .build(); + } + + Member user = memberService.login(request); + if (user == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("로그인 아이디 또는 비밀번호가 틀렸습니다."); + } + + session.setAttribute("loginUser", user); + return ResponseEntity.ok(String.format("loginId : %s login success!", user.getEmail())); + } + + @GetMapping("/members/info") + public String userInfo(HttpSession session) { + Member loginUser = (Member) session.getAttribute("loginUser"); + if (loginUser == null) { + return "로그인 상태가 아닙니다."; + } + return String.format("loginId : %s\nnickname : %s", loginUser.getEmail(), loginUser.getName()); + } + + @PostMapping("/members/logout") + public String logout(HttpSession session) { + session.invalidate(); + return "로그아웃 되었습니다."; + } + @GetMapping("/members/{id}") public ResponseEntity getMember( - @PathVariable Long id + @PathVariable Long id ) { MemberResponse response = memberService.getById(id); return ResponseEntity.ok(response); @@ -41,7 +88,7 @@ public ResponseEntity getMember( @PostMapping("/members") public ResponseEntity create( - @RequestBody MemberCreateRequest request + @Validated @RequestBody MemberCreateRequest request ) { MemberResponse response = memberService.create(request); return ResponseEntity.ok(response); @@ -49,8 +96,8 @@ public ResponseEntity create( @PutMapping("/members/{id}") public ResponseEntity updateMember( - @PathVariable Long id, - @RequestBody MemberUpdateRequest request + @PathVariable Long id, + @RequestBody MemberUpdateRequest request ) { MemberResponse response = memberService.update(id, request); return ResponseEntity.ok(response); @@ -58,7 +105,7 @@ public ResponseEntity updateMember( @DeleteMapping("/members/{id}") public ResponseEntity deleteMember( - @PathVariable Long id + @PathVariable Long id ) { memberService.delete(id); return ResponseEntity.noContent().build(); diff --git a/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java b/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java index 44f74a5..8be1268 100644 --- a/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java +++ b/src/main/java/com/example/demo/controller/dto/request/MemberCreateRequest.java @@ -1,9 +1,17 @@ package com.example.demo.controller.dto.request; + +import jakarta.validation.constraints.NotBlank; + public record MemberCreateRequest( - String name, - String email, - String password + @NotBlank(message = "이름을 입력해주세요.") + String name, + + @NotBlank(message = "이메일을 입력해주세요.") + String email, + + @NotBlank(message = "비밀번호를 입력해주세요.") + String password ) { } diff --git a/src/main/java/com/example/demo/controller/dto/request/MemberLoginRequest.java b/src/main/java/com/example/demo/controller/dto/request/MemberLoginRequest.java new file mode 100644 index 0000000..8b15039 --- /dev/null +++ b/src/main/java/com/example/demo/controller/dto/request/MemberLoginRequest.java @@ -0,0 +1,8 @@ +package com.example.demo.controller.dto.request; + +public record MemberLoginRequest( + String email, + String password +) +{ +} diff --git a/src/main/java/com/example/demo/domain/Article.java b/src/main/java/com/example/demo/domain/Article.java index e0183db..5e42d5c 100644 --- a/src/main/java/com/example/demo/domain/Article.java +++ b/src/main/java/com/example/demo/domain/Article.java @@ -1,21 +1,35 @@ package com.example.demo.domain; -import java.time.LocalDateTime; +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") private Long authorId; - private Long boardId; + + @ManyToOne + @JoinColumn(name="board_id") + private Board board; + private String title; + private String content; + + @Column(name = "created_date") private LocalDateTime createdAt; + + @Column(name = "modified_date") private LocalDateTime modifiedAt; public Article( Long id, Long authorId, - Long boardId, + Board board, String title, String content, LocalDateTime createdAt, @@ -23,25 +37,30 @@ public Article( ) { this.id = id; this.authorId = authorId; - this.boardId = boardId; + this.board = board; this.title = title; this.content = content; this.createdAt = createdAt; this.modifiedAt = modifiedAt; } - public Article(Long authorId, Long boardId, String title, String content) { + public Article(Long authorId, Board board, String title, String content) { this.id = null; this.authorId = authorId; - this.boardId = boardId; + this.board = board; this.title = title; this.content = content; this.createdAt = LocalDateTime.now(); this.modifiedAt = LocalDateTime.now(); } - public void update(Long boardId, String title, String description) { - this.boardId = boardId; + public Article() { + + } + + + public void update(Board board, String title, String description) { + this.board = board; this.title = title; this.content = description; this.modifiedAt = LocalDateTime.now(); @@ -64,7 +83,7 @@ public Long getAuthorId() { } public Long getBoardId() { - return boardId; + return board.getId(); } public String getTitle() { diff --git a/src/main/java/com/example/demo/domain/Board.java b/src/main/java/com/example/demo/domain/Board.java index 992e2c6..6f8be8f 100644 --- a/src/main/java/com/example/demo/domain/Board.java +++ b/src/main/java/com/example/demo/domain/Board.java @@ -1,10 +1,21 @@ package com.example.demo.domain; -public class Board { +import jakarta.persistence.*; + +import java.util.List; +@Entity +@Table(name = "board") +public class Board { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + private String name; + @OneToMany(mappedBy = "board",cascade = CascadeType.ALL, orphanRemoval = true) + private List
articles; + public Board(Long id, String name) { this.id = id; this.name = name; @@ -14,6 +25,10 @@ public Board(String name) { this.name = name; } + public Board() { + + } + public Long getId() { return id; } @@ -29,4 +44,5 @@ public String getName() { public void update(String name) { this.name = name; } + } diff --git a/src/main/java/com/example/demo/domain/Member.java b/src/main/java/com/example/demo/domain/Member.java index fe80d6b..079c8a2 100644 --- a/src/main/java/com/example/demo/domain/Member.java +++ b/src/main/java/com/example/demo/domain/Member.java @@ -1,10 +1,19 @@ package com.example.demo.domain; -public class Member { +import jakarta.persistence.*; +import org.springframework.security.crypto.password.PasswordEncoder; +@Entity +@Table(name = "member") +public class Member { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + private String name; + private String email; + private String password; public Member(Long id, String name, String email, String password) { @@ -20,6 +29,13 @@ public Member(String name, String email, String password) { this.password = password; } + public Member() { + + } + + public void encodePassword(PasswordEncoder passwordEncoder){ + this.password = passwordEncoder.encode(password); + } public void update(String name, String email) { this.name = name; this.email = email; diff --git a/src/main/java/com/example/demo/repository/ArticleRepository.java b/src/main/java/com/example/demo/repository/ArticleRepository.java index 3ef9445..daff8ee 100644 --- a/src/main/java/com/example/demo/repository/ArticleRepository.java +++ b/src/main/java/com/example/demo/repository/ArticleRepository.java @@ -3,18 +3,10 @@ import java.util.List; import com.example.demo.domain.Article; +import org.springframework.data.jpa.repository.JpaRepository; -public interface ArticleRepository { +public interface ArticleRepository extends JpaRepository { + List
findAllByBoard_Id(Long boardId); - List
findAll(); - - List
findAllByBoardId(Long boardId); - - Article findById(Long id); - - Article insert(Article article); - - Article update(Article article); - - void deleteById(Long id); + List
findAllByAuthorId(Long memberId); } diff --git a/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java b/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java deleted file mode 100644 index 349daf4..0000000 --- a/src/main/java/com/example/demo/repository/ArticleRepositoryJdbc.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.example.demo.repository; - -import java.sql.PreparedStatement; -import java.util.List; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import com.example.demo.domain.Article; - -@Repository -public class ArticleRepositoryJdbc implements ArticleRepository { - - private final JdbcTemplate jdbcTemplate; - - public ArticleRepositoryJdbc(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - private static final RowMapper
articleRowMapper = (rs, rowNum) -> new Article( - rs.getLong("id"), - rs.getLong("author_id"), - rs.getLong("board_id"), - rs.getString("title"), - rs.getString("content"), - rs.getTimestamp("created_date").toLocalDateTime(), - rs.getTimestamp("modified_date").toLocalDateTime() - ); - - @Override - public List
findAll() { - return jdbcTemplate.query(""" - SELECT id, board_id, author_id, title, content, created_date, modified_date - FROM article - """, articleRowMapper); - } - - @Override - public List
findAllByBoardId(Long boardId) { - return jdbcTemplate.query(""" - SELECT id, board_id, author_id, title, content, created_date, modified_date - FROM article - WHERE board_id = ? - """, articleRowMapper, boardId); - } - - @Override - public Article findById(Long id) { - return jdbcTemplate.queryForObject(""" - SELECT id, board_id, author_id, title, content, created_date, modified_date - FROM article - WHERE id = ? - """, articleRowMapper, id); - } - - @Override - public Article insert(Article article) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(con -> { - PreparedStatement ps = con.prepareStatement(""" - INSERT INTO article (board_id, author_id, title, content) - VALUES (?, ?, ?, ?) - """, - new String[]{"id"}); - ps.setLong(1, article.getBoardId()); - ps.setLong(2, article.getAuthorId()); - ps.setString(3, article.getTitle()); - ps.setString(4, article.getContent()); - return ps; - }, keyHolder); - return findById(keyHolder.getKey().longValue()); - } - - @Override - public Article update(Article article) { - jdbcTemplate.update(""" - UPDATE article - SET board_id = ?, title = ?, content = ? - WHERE id = ? - """, - article.getBoardId(), - article.getTitle(), - article.getContent(), - article.getId() - ); - return findById(article.getId()); - } - - @Override - public void deleteById(Long id) { - jdbcTemplate.update(""" - DELETE FROM article - WHERE id = ? - """, id); - } -} diff --git a/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java b/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java deleted file mode 100644 index 00d97ca..0000000 --- a/src/main/java/com/example/demo/repository/ArticleRepositoryMemory.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.example.demo.repository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -import com.example.demo.domain.Article; - -public class ArticleRepositoryMemory implements ArticleRepository { - - private static final Map articles = new HashMap<>(); - private static final AtomicLong autoincrement = new AtomicLong(1); - - @Override - public List
findAll() { - return articles.entrySet().stream() - .map(it -> { - Article article = it.getValue(); - article.setId(it.getKey()); - return article; - }).toList(); - } - - @Override - public List
findAllByBoardId(Long boardId) { - return articles.entrySet().stream() - .filter(it -> it.getValue().getBoardId().equals(boardId)) - .map(it -> { - Article article = it.getValue(); - article.setId(it.getKey()); - return article; - }).toList(); - } - - @Override - public Article findById(Long id) { - return articles.getOrDefault(id, null); - } - - @Override - public Article insert(Article article) { - long id = autoincrement.getAndIncrement(); - articles.put(id, article); - article.setId(id); - return article; - } - - @Override - public Article update(Article article) { - articles.put(article.getId(), article); - return article; - } - - @Override - public void deleteById(Long id) { - articles.remove(id); - } -} diff --git a/src/main/java/com/example/demo/repository/BoardRepository.java b/src/main/java/com/example/demo/repository/BoardRepository.java index cc2dfd0..5124fba 100644 --- a/src/main/java/com/example/demo/repository/BoardRepository.java +++ b/src/main/java/com/example/demo/repository/BoardRepository.java @@ -2,17 +2,10 @@ import java.util.List; +import com.example.demo.domain.Article; import com.example.demo.domain.Board; +import org.springframework.data.jpa.repository.JpaRepository; -public interface BoardRepository { +public interface BoardRepository extends JpaRepository { - List findAll(); - - Board findById(Long id); - - Board insert(Board board); - - void deleteById(Long id); - - Board update(Board board); } diff --git a/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java b/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java deleted file mode 100644 index c4fd6f6..0000000 --- a/src/main/java/com/example/demo/repository/BoardRepositoryJdbc.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.example.demo.repository; - -import java.sql.PreparedStatement; -import java.util.List; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import com.example.demo.domain.Board; - -@Repository -public class BoardRepositoryJdbc implements BoardRepository { - - private final JdbcTemplate jdbcTemplate; - - public BoardRepositoryJdbc(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - private static final RowMapper boardRowMapper = (rs, rowNum) -> new Board( - rs.getLong("id"), - rs.getString("name") - ); - - @Override - public List findAll() { - return jdbcTemplate.query(""" - SELECT id, name - FROM board - """, boardRowMapper); - } - - @Override - public Board findById(Long id) { - return jdbcTemplate.queryForObject(""" - SELECT id, name - FROM board - WHERE id = ? - """, boardRowMapper, id); - } - - @Override - public Board insert(Board board) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(con -> { - PreparedStatement ps = con.prepareStatement(""" - INSERT INTO board (name) VALUES (?) - """, new String[]{"id"}); - ps.setString(1, board.getName()); - return ps; - }, keyHolder); - return findById(keyHolder.getKey().longValue()); - } - - @Override - public void deleteById(Long id) { - jdbcTemplate.update(""" - DELETE FROM board WHERE id = ? - """, id); - } - - @Override - public Board update(Board board) { - return jdbcTemplate.queryForObject(""" - UPDATE board SET name = ? WHERE id = ? - """, boardRowMapper, board.getName(), board.getId() - ); - } -} diff --git a/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java b/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java deleted file mode 100644 index 8cf5ecf..0000000 --- a/src/main/java/com/example/demo/repository/BoardRepositoryMemory.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.example.demo.repository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -import com.example.demo.domain.Board; - -public class BoardRepositoryMemory implements BoardRepository { - - private static final Map boards = new HashMap<>(); - private static final AtomicLong autoincrement = new AtomicLong(1); - - static { - // 1번 게시판을 미리 만들어둔다. - boards.put(autoincrement.getAndIncrement(), new Board("자유게시판")); - } - - @Override - public List findAll() { - return boards.entrySet().stream() - .map(it -> { - Board board = it.getValue(); - board.setId(it.getKey()); - return board; - }).toList(); - } - - @Override - public Board findById(Long id) { - return boards.getOrDefault(id, null); - } - - @Override - public Board insert(Board board) { - boards.put(autoincrement.getAndIncrement(), board); - return board; - } - - @Override - public void deleteById(Long id) { - boards.remove(id); - } - - @Override - public Board update(Board board) { - return boards.put(board.getId(), board); - } -} diff --git a/src/main/java/com/example/demo/repository/MemberRepository.java b/src/main/java/com/example/demo/repository/MemberRepository.java index 8e2ad14..2dab276 100644 --- a/src/main/java/com/example/demo/repository/MemberRepository.java +++ b/src/main/java/com/example/demo/repository/MemberRepository.java @@ -1,18 +1,11 @@ package com.example.demo.repository; import java.util.List; +import java.util.Optional; import com.example.demo.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; -public interface MemberRepository { - - List findAll(); - - Member findById(Long id); - - Member insert(Member member); - - Member update(Member member); - - void deleteById(Long id); +public interface MemberRepository extends JpaRepository { + Optional findByEmail(String email); } diff --git a/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java b/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java deleted file mode 100644 index 30d2262..0000000 --- a/src/main/java/com/example/demo/repository/MemberRepositoryJdbc.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.example.demo.repository; - -import java.sql.PreparedStatement; -import java.util.List; - -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import com.example.demo.domain.Member; - -@Repository -public class MemberRepositoryJdbc implements MemberRepository { - - private final JdbcTemplate jdbcTemplate; - - public MemberRepositoryJdbc(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - private static final RowMapper memberRowMapper = (rs, rowNum) -> new Member( - rs.getLong("id"), - rs.getString("name"), - rs.getString("email"), - rs.getString("password") - ); - - @Override - public List findAll() { - return jdbcTemplate.query(""" - SELECT id, name, email, password - FROM member - """, memberRowMapper); - } - - @Override - public Member findById(Long id) { - return jdbcTemplate.queryForObject(""" - SELECT id, name, email, password - FROM member - WHERE id = ? - """, memberRowMapper, id); - } - - @Override - public Member insert(Member member) { - KeyHolder keyHolder = new GeneratedKeyHolder(); - jdbcTemplate.update(con -> { - PreparedStatement ps = con.prepareStatement(""" - INSERT INTO member (name, email, password) VALUES (?, ?, ?) - """, new String[]{"id"}); - ps.setString(1, member.getName()); - ps.setString(2, member.getEmail()); - ps.setString(3, member.getPassword()); - return ps; - }, keyHolder); - return findById(keyHolder.getKey().longValue()); - } - - @Override - public Member update(Member member) { - jdbcTemplate.update(""" - UPDATE member - SET name = ?, email = ? - WHERE id = ? - """, member.getName(), member.getEmail(), member.getId()); - return findById(member.getId()); - } - - @Override - public void deleteById(Long id) { - jdbcTemplate.update(""" - DELETE FROM member - WHERE id = ? - """, id); - } -} diff --git a/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java b/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java deleted file mode 100644 index b4cf722..0000000 --- a/src/main/java/com/example/demo/repository/MemberRepositoryMemory.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.example.demo.repository; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; - -import com.example.demo.domain.Member; - -public class MemberRepositoryMemory implements MemberRepository { - - private static final Map members = new HashMap<>(); - private static final AtomicLong autoincrement = new AtomicLong(1); - - static { - // 1번 유저를 미리 만들어둔다. - members.put(autoincrement.getAndIncrement(), new Member("최준호", "temp@gmail.com", "password")); - } - - @Override - public List findAll() { - return members.entrySet().stream() - .map(it -> { - Member member = it.getValue(); - member.setId(it.getKey()); - return member; - }).toList(); - } - - @Override - public Member findById(Long id) { - return members.getOrDefault(id, null); - } - - @Override - public Member insert(Member member) { - long id = autoincrement.getAndIncrement(); - members.put(id, member); - member.setId(id); - return member; - } - - @Override - public Member update(Member member) { - return members.put(member.getId(), member); - } - - @Override - public void deleteById(Long id) { - members.remove(id); - } -} diff --git a/src/main/java/com/example/demo/service/ArticleService.java b/src/main/java/com/example/demo/service/ArticleService.java index 7f8610b..cd3736f 100644 --- a/src/main/java/com/example/demo/service/ArticleService.java +++ b/src/main/java/com/example/demo/service/ArticleService.java @@ -2,6 +2,10 @@ import java.util.List; +import com.example.demo.AOPexception.Exception.GetNotFoundException; +import com.example.demo.AOPexception.Exception.PostIllegalArgumemtException; +import com.example.demo.AOPexception.Exception.PostNotFoundException; +import com.example.demo.AOPexception.Exception.PutNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,9 +28,9 @@ public class ArticleService { private final BoardRepository boardRepository; public ArticleService( - ArticleRepository articleRepository, - MemberRepository memberRepository, - BoardRepository boardRepository + ArticleRepository articleRepository, + MemberRepository memberRepository, + BoardRepository boardRepository ) { this.articleRepository = articleRepository; this.memberRepository = memberRepository; @@ -34,45 +38,85 @@ public ArticleService( } public ArticleResponse getById(Long id) { - Article article = articleRepository.findById(id); - Member member = memberRepository.findById(article.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); + try { + Article article = articleRepository.findById(id) + .orElseThrow(IllegalArgumentException::new); + ; + Member member = memberRepository.findById(article.getAuthorId()) + .orElseThrow(IllegalArgumentException::new); + ; + Board board = boardRepository.findById(article.getBoardId()) + .orElseThrow(IllegalArgumentException::new); + ; + return ArticleResponse.of(article, member, board); + } catch (RuntimeException e) { + throw new GetNotFoundException(e.getMessage()); + } } public List getByBoardId(Long boardId) { - List
articles = articleRepository.findAllByBoardId(boardId); - return articles.stream() - .map(article -> { - Member member = memberRepository.findById(article.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); - }) - .toList(); + try { + List
articles = articleRepository.findAllByBoard_Id(boardId); + return articles.stream() + .map(article -> { + Member member = memberRepository.findById(article.getAuthorId()) + .orElseThrow(IllegalArgumentException::new); + ; + Board board = boardRepository.findById(article.getBoardId()) + .orElseThrow(IllegalArgumentException::new); + ; + return ArticleResponse.of(article, member, board); + }) + .toList(); + } catch (RuntimeException e) { + throw new GetNotFoundException(e.getMessage()); + } } @Transactional public ArticleResponse create(ArticleCreateRequest request) { Article article = new Article( - request.authorId(), - request.boardId(), - request.title(), - request.description() + request.authorId(), + boardRepository.getReferenceById(request.boardId()), + request.title(), + request.description() ); - Article saved = articleRepository.insert(article); - Member member = memberRepository.findById(saved.getAuthorId()); - Board board = boardRepository.findById(saved.getBoardId()); - return ArticleResponse.of(saved, member, board); + if (article.getAuthorId() == null || article.getBoardId() == null || + article.getTitle() == null || article.getContent() == null) { + throw new PostIllegalArgumemtException("NULL field existed"); + } + try { + Member member = memberRepository.findById(article.getAuthorId()) + .orElseThrow(IllegalArgumentException::new); + ; + Board board = boardRepository.findById(article.getBoardId()) + .orElseThrow(IllegalArgumentException::new); + ; + Article saved = articleRepository.save(article); + return ArticleResponse.of(saved, member, board); + } catch (RuntimeException e) { + throw new PostNotFoundException(e.getMessage()); + } } @Transactional public ArticleResponse update(Long id, ArticleUpdateRequest request) { - Article article = articleRepository.findById(id); - article.update(request.boardId(), request.title(), request.description()); - Article updated = articleRepository.update(article); - Member member = memberRepository.findById(updated.getAuthorId()); - Board board = boardRepository.findById(article.getBoardId()); - return ArticleResponse.of(article, member, board); + try { + Article article = articleRepository.findById(id) + .orElseThrow(IllegalArgumentException::new); + ; + Board board = boardRepository.findById(request.boardId()) + .orElseThrow(IllegalArgumentException::new); + ; + article.update(boardRepository.getReferenceById(request.boardId()), request.title(), request.description()); + Article updated = articleRepository.save(article); + Member member = memberRepository.findById(updated.getAuthorId()) + .orElseThrow(IllegalArgumentException::new); + ; + return ArticleResponse.of(article, member, board); + } catch (RuntimeException e) { + throw new PutNotFoundException(e.getMessage()); + } } @Transactional diff --git a/src/main/java/com/example/demo/service/BoardService.java b/src/main/java/com/example/demo/service/BoardService.java index ffff891..c6c0cda 100644 --- a/src/main/java/com/example/demo/service/BoardService.java +++ b/src/main/java/com/example/demo/service/BoardService.java @@ -2,6 +2,10 @@ import java.util.List; +import com.example.demo.AOPexception.Exception.DeleteExistedExcepton; +import com.example.demo.AOPexception.Exception.GetNotFoundException; +import com.example.demo.AOPexception.Exception.PostIllegalArgumemtException; +import com.example.demo.repository.ArticleRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,9 +20,11 @@ public class BoardService { private final BoardRepository boardRepository; + private final ArticleRepository articleRepository; - public BoardService(BoardRepository boardRepository) { + public BoardService(BoardRepository boardRepository,ArticleRepository articleRepository) { this.boardRepository = boardRepository; + this.articleRepository=articleRepository; } public List getBoards() { @@ -28,27 +34,36 @@ public List getBoards() { } public BoardResponse getBoardById(Long id) { - Board board = boardRepository.findById(id); - return BoardResponse.from(board); + try { + Board board = boardRepository.findById(id).orElseThrow(IllegalArgumentException::new);; + return BoardResponse.from(board); + }catch (RuntimeException e) { + throw new GetNotFoundException(e.getMessage()); + } } - @Transactional public BoardResponse createBoard(BoardCreateRequest request) { + if (request.name() == null ) { + throw new PostIllegalArgumemtException("NULL field existed"); + } Board board = new Board(request.name()); - Board saved = boardRepository.insert(board); + Board saved = boardRepository.save(board); return BoardResponse.from(saved); } + @Transactional public void deleteBoard(Long id) { + //if(!articleRepository.findAllByBoard_Id(id).isEmpty()) + //throw new DeleteExistedExcepton("Articles exist in board!"); boardRepository.deleteById(id); } @Transactional public BoardResponse update(Long id, BoardUpdateRequest request) { - Board board = boardRepository.findById(id); + Board board = boardRepository.findById(id).orElseThrow(IllegalArgumentException::new);; board.update(request.name()); - Board updated = boardRepository.update(board); + Board updated = boardRepository.save(board); return BoardResponse.from(updated); } } diff --git a/src/main/java/com/example/demo/service/MemberService.java b/src/main/java/com/example/demo/service/MemberService.java index 04c1bc8..6f3472c 100644 --- a/src/main/java/com/example/demo/service/MemberService.java +++ b/src/main/java/com/example/demo/service/MemberService.java @@ -1,7 +1,15 @@ package com.example.demo.service; import java.util.List; +import java.util.Optional; +import com.example.demo.AOPexception.Exception.DeleteExistedExcepton; +import com.example.demo.AOPexception.Exception.GetNotFoundException; +import com.example.demo.AOPexception.Exception.PutDuplicatedException; +import com.example.demo.controller.dto.request.MemberLoginRequest; +import com.example.demo.repository.ArticleRepository; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,41 +24,86 @@ public class MemberService { private final MemberRepository memberRepository; + public final ArticleRepository articleRepository; + private final PasswordEncoder passwordEncoder; - public MemberService(MemberRepository memberRepository) { + + public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository, + PasswordEncoder passwordEncoder) { this.memberRepository = memberRepository; + this.articleRepository = articleRepository; + this.passwordEncoder = passwordEncoder; } public MemberResponse getById(Long id) { - Member member = memberRepository.findById(id); - return MemberResponse.from(member); + try { + Member member = memberRepository.findById(id).orElseThrow(IllegalArgumentException::new); + ; + return MemberResponse.from(member); + } catch (RuntimeException e) { + throw new GetNotFoundException(e.getMessage()); + } } public List getAll() { List members = memberRepository.findAll(); return members.stream() - .map(MemberResponse::from) - .toList(); + .map(MemberResponse::from) + .toList(); } @Transactional - public MemberResponse create(MemberCreateRequest request) { - Member member = memberRepository.insert( - new Member(request.name(), request.email(), request.password()) + public MemberResponse create(MemberCreateRequest request) throws RuntimeException { + if (memberRepository.findByEmail(request.email()).isPresent()) { + throw new RuntimeException("이미 존재하는 이메일입니다."); + } + Member member = memberRepository.save( + new Member(request.name(), request.email(), request.password()) ); + member.encodePassword(passwordEncoder); return MemberResponse.from(member); } + @Transactional + public Member login(MemberLoginRequest request) throws RuntimeException { + Optional optionalUser = memberRepository.findByEmail(request.email()); + if (optionalUser.isEmpty()) { + return null; + } + Member user = optionalUser.get(); + if (!passwordEncoder.matches(request.password(),user.getPassword())) { + return null; + } + return user; + } + + @Transactional + public Member getLoginUserByLoginId(String loginId) { + if (loginId == null) return null; + + Optional optionalUser = memberRepository.findByEmail(loginId); + return optionalUser.orElse(null); + + } + @Transactional public void delete(Long id) { + if (!articleRepository.findAllByAuthorId(id).isEmpty()) + throw new DeleteExistedExcepton("one above articles existed written by this member"); memberRepository.deleteById(id); } @Transactional public MemberResponse update(Long id, MemberUpdateRequest request) { - Member member = memberRepository.findById(id); - member.update(request.name(), request.email()); - memberRepository.update(member); - return MemberResponse.from(member); + Member member = memberRepository.findById(id).orElseThrow(IllegalArgumentException::new); + ; + try { + memberRepository.findByEmail(request.email()); + } catch (RuntimeException e) { + member.update(request.name(), request.email()); + memberRepository.save(member); + return MemberResponse.from(member); + } + throw new PutDuplicatedException("already used email"); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ff69a9e..105f0ba 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,8 @@ spring: - datasource: - url: jdbc:mysql://localhost:3306/bcsd # 본인의 환경에 맞게 수정한다. - username: root # 본인의 환경에 맞게 수정한다. - password: qwer1234 # 본인의 환경에 맞게 수정한다. - driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + show-sql: true + datasource: + url: jdbc:mysql://localhost:3306/bcsd # 본인의 환경에 맞게 수정한다. + driver-class-name: com.mysql.cj.jdbc.Driver + username: root # 본인의 환경에 맞게 수정한다. + password: gkrdlsdlelql!! # 본인의 환경에 맞게 수정한다. \ No newline at end of file