본문 바로가기
Project/Newsfeed Project

[Project / Newsfeed] - 뉴스피드 프로젝트 6일차

by nam_ji 2024. 2. 18.

뉴스피드 프로젝트 6일차

최종 코드

  • config 패키지
    더보기
    PasswordConfig
    @Configuration
    public class PasswordConfig {
    
        @Bean
        public PasswordEncoder passwordEncoder () {
            return new BCryptPasswordEncoder();
        }
    }
    SecurityConfig
    @Configuration
    @EnableWebSecurity
    @RequiredArgsConstructor
    public class SecurityConfig {
    
        private final JwtUtil jwtUtil;
        private final UserDetailsServiceImpl userDetailsService;
        private final AuthenticationConfiguration authenticationConfiguration;
    
        @Bean
        public SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
            http.csrf((csrf) -> csrf.disable());
    
            http.sessionManagement((sessionManagement) ->
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
    
            http.authorizeHttpRequests((authorizeHttpRequests) ->
                    authorizeHttpRequests
                            .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                            .requestMatchers("/users/**").permitAll()
                            .anyRequest().authenticated()
            );
    
            http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
            http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    
            return http.build();
        }
    
        @Bean
        public AuthenticationManager authenticationManager (AuthenticationConfiguration configuration) throws Exception {
            return configuration.getAuthenticationManager();
        }
    
        @Bean
        public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
            JwtAuthenticationFilter filter = new JwtAuthenticationFilter(jwtUtil);
            filter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
            return filter;
        }
    
        @Bean
        public JwtAuthorizationFilter jwtAuthorizationFilter() {
            return new JwtAuthorizationFilter(jwtUtil, userDetailsService);
        }
    }
  • controller 패키지
    더보기
    BoardController
    @RequiredArgsConstructor
    @RestController
    @RequestMapping("/boards")
    public class BoardController {
    
        private final BoardService boardService;
    
        @PostMapping
        public ResponseEntity<BoardResponseDto> createBoard(
                @RequestBody BoardRequestDto requestDto,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            Board board = boardService.createBoard(requestDto, userDetails.getUser());
            BoardResponseDto boardResponseDto = new BoardResponseDto(board);
    
            return new ResponseEntity<>(boardResponseDto, HttpStatus.OK);
        }
    
        @GetMapping
        public ResponseEntity<List<Board>> getAllBoards() {
            List<Board> boards = boardService.getAllBoards();
            return new ResponseEntity<>(boards, HttpStatus.OK);
        }
    
        @GetMapping("/{boardnum}")
        public ResponseEntity<BoardResponseDto> getBoardById(
                @PathVariable Long boardnum
        ) {
            Board board = boardService.getBoardById(boardnum);
            BoardResponseDto boardResponseDto = new BoardResponseDto(board);
            return new ResponseEntity<>(boardResponseDto, HttpStatus.OK);
    
        }
    
        @GetMapping("/userboard")
        public List<BoardResponseDto> getUserAllBoards(
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ){
            return boardService.getUserAllBoards(userDetails);
        }
    
        @GetMapping("/userboard/{boardnum}")
        public BoardResponseDto getUserSelectedBoards(
                @PathVariable Long boardnum,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            return boardService.getUserSelectedBoards(boardnum, userDetails);
    
        }
    
        @PutMapping("/{boardNum}")
        public ResponseEntity<BoardResponseDto> updateBoard(
                @PathVariable Long boardNum,
                @RequestBody BoardUpdateDto requestDto,
                @AuthenticationPrincipal UserDetailsImpl userDetails) {
            Board board = boardService.updateBoard(boardNum, requestDto, userDetails.getUser());
            BoardResponseDto boardResponseDto = new BoardResponseDto(board);
    
            return new ResponseEntity<>(boardResponseDto, HttpStatus.OK);
        }
    
        @DeleteMapping("/{boardNum}")
        public ResponseEntity<String> deleteBoard(
                @PathVariable Long boardNum,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            boardService.deleteBoard(boardNum, userDetails.getUser());
            return ResponseEntity.ok("게시글 삭제 완료");
        }
    }​
    CommentController
    @RestController
    @RequiredArgsConstructor
    @RequestMapping("/boards")
    public class CommentController {
        private final CommentService commentService;
    
        @GetMapping("/{boardNum}/comment")
        public List<CommentResponseDto> getCommentsByBoard(@PathVariable("boardNum") Long boardNum){
            return commentService.getCommentsByBoard(boardNum);
        }
        
        @PostMapping("/{boardNum}/comment")
        public ResponseEntity<CommentResponseDto> addComment(
                @PathVariable("boardNum") Long boardNum,
                @RequestBody CommentRequestDto requestDto,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            Comment comment = commentService.addComment(boardNum, requestDto, userDetails.getUser());
            return new ResponseEntity<>(new CommentResponseDto(comment), HttpStatus.OK);
        }
    
        @PutMapping("/{boardNum}/comment/{commentNum}")
        public ResponseEntity<CommentResponseDto> updateComment(
                @PathVariable("boardNum") Long boardNum,
                @PathVariable("commentNum") Long commentNum,
                @RequestBody CommentRequestDto commentRequestDto,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            Comment comment = commentService.updateComment(boardNum, commentNum, commentRequestDto, userDetails.getUser());
            return new ResponseEntity<>(new CommentResponseDto(comment), HttpStatus.OK);
        }
    
        @DeleteMapping("/{boardNum}/comment/{commentNum}")
        public ResponseEntity<String> deleteComment(
                @PathVariable("boardNum") Long boardNum,
                @PathVariable("commentNum") Long commentNum,
                @AuthenticationPrincipal UserDetailsImpl userDetails
        ) {
            commentService.deleteComment(boardNum, commentNum, userDetails.getUser());
            return ResponseEntity.ok("댓글 삭제 완료");
        }
    
    }​
    UserController
    @Slf4j
    @RestController
    @RequiredArgsConstructor
    @RequestMapping("/users")
    public class UserController {
    
        private final UserService userService;
    
        @PostMapping("/signup")
        public String signup (@Valid @RequestBody SignupRequestDto requestDto, BindingResult bindingResult) {
            List<FieldError> fieldErrors = bindingResult.getFieldErrors();
            if (!fieldErrors.isEmpty()) {
                for (FieldError fieldError : bindingResult.getFieldErrors()) {
                    log.error(fieldError.getField() + " 필드 : " + fieldError.getDefaultMessage());
                }
                return "회원가입도중 에러가 발생했습니다.";
            }
    
            userService.signup(requestDto);
    
            return "회원가입 성공";
        }
    
        @PostMapping("/login")
        public LoginResponseDto login (@RequestBody LoginRequestDto requestDto) {
            LoginResponseDto responseDto = userService.login(requestDto);
    
            return responseDto;
        }
    
        @GetMapping("/info")
        @ResponseBody
        public UserDetailsImpl getUserInfo(@AuthenticationPrincipal UserDetailsImpl userDetails) {
    
            return userDetails;
        }
    
        // 회원탈퇴
        @DeleteMapping("/delete")
        public ResponseEntity<String> deleteUser(@AuthenticationPrincipal UserDetailsImpl userDetails) {
            userService.deleteUser(userDetails.getUser());
            return ResponseEntity.ok("회원 탈퇴 완료");
        }
    
        // 프로필 단건조회
        @GetMapping
        public ResponseEntity<ProfileResponseDto> getProfile(@AuthenticationPrincipal UserDetailsImpl userDetails) {
            ProfileResponseDto response = userService.getProfile(userDetails.getUser().getUserNum());
            return new ResponseEntity<>(response, HttpStatus.OK);
        }
    
        // 프로필 수정
        @PutMapping
        public ResponseEntity<ProfileResponseDto> updateProfile(@RequestBody UserUpdateDto request, @AuthenticationPrincipal UserDetailsImpl userDetails) {
            ProfileResponseDto response = userService.updateProfile(userDetails.getUser().getUserNum(), request);
    
            return new ResponseEntity<>(response, HttpStatus.OK);
        }
    
    
    }​
  • dto 패키지
    더보기
    RequestDto
    BoardRequestDto
    @Getter
    public class BoardRequestDto {
        String title;
        String contents;
    }​
    BoardUpdateDto
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    @Getter
    public class BoardUpdateDto {
        private String title;
        private String contents;
    }​

    CommentRequestDto

    @Getter
    public class CommentRequestDto {
        private String contents;
    }​
    LoginRequestDto
    @Getter
    public class LoginRequestDto {
        private String userId;
        private String password;
    }​
    SignupRequestDto
    @Getter
    public class SignupRequestDto {
        @NotBlank
        private String userId;
        @NotBlank
        private String password;
        @Pattern(regexp = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$")
        @NotBlank
        private String email;
        @NotBlank
        private String name;
    }​
    UserUpdateDto
    @Getter
    public class UserUpdateDto {
    
        @NotBlank
        private String name;
        @NotBlank
        private String userId;
        @NotBlank
        private String email;
        @Pattern(regexp = "^[a-zA-Z0-9]{8,15}$", message = "영대소문자와 숫자만, 8~15길이만 허용")
        @NotBlank
        private String password;
        @Pattern(regexp = "^[a-zA-Z0-9]{8,15}$", message = "영대소문자와 숫자만, 8~15길이만 허용")
        @NotBlank
        private String confirmPassword;
    }​

    ResponseDto
    BoardResponseDto

    @ToString
    @Setter
    @Getter
    public class BoardResponseDto {
        private Long boardNum;
        private String title;
        private String contents;
        private String userId;
        private LocalDateTime createAt;
        private LocalDateTime modifiedAt;
    
        public BoardResponseDto(Board board) {
            this.boardNum = board.getBoardNum();
            this.title = board.getTitle();
            this.contents = board.getContents();
            this.userId = board.getUser().getUserId();
            this.createAt = board.getCreatedAt();
            this.modifiedAt = board.getModifiedAt();
        }
    }

    CommentResponseDto

    @Getter
    public class CommentResponseDto {
        private String contents;
        private String userId;
        private LocalDateTime createAt;
        private LocalDateTime modifiedAt;
    
        public CommentResponseDto(Comment comment) {
            this.contents = comment.getContents();
            this.userId = comment.getUser().getUserId();
            this.createAt = comment.getCreatedAt();
            this.modifiedAt = comment.getModifiedAt();
        }
    }

    LoginResponseDto

    @Getter
    @Builder
    public class LoginResponseDto {
        private String userId;
        private String password;
        private String email;
        private String name;
        private String token;
    }

    ProfileResponseDto

    @Getter
    public class ProfileResponseDto {
    
        private String name;
        private String userId;
        private String email;
        private String password;
    
        public ProfileResponseDto(String name, String userId, String email, String password) {
            this.name = name;
            this.userId = userId;
            this.email = email;
            this.password = password;
        }
    }
  • entity 패키지
    더보기
     Board
    @Getter
    @NoArgsConstructor
    @Entity
    @Table(name = "boards")
    @AllArgsConstructor
    public class Board extends Timestamped {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long boardNum;
        @Column(nullable = false, length = 50)
        private String title;
        @Lob
        private String contents;
        @ManyToOne
        @JoinColumn(name = "userNum", nullable = false)
        private User user;
    
        public Board(String title, String content, User user) {
            this.title = title;
            this.contents = content;
            this.user = user;
        }
    
        public void updateBoard(BoardUpdateDto requestDto) {
            this.title = requestDto.getTitle();
            this.contents = requestDto.getContents();
        }
    }​
    Comment
    @Entity
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Table(name = "comments")
    public class Comment extends Timestamped {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long commentNum;
        @Lob
        private String contents;
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "userNum", nullable = false)
        private User user;
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "boardNum", nullable = false)
        private Board board;
    
        public Comment(CommentRequestDto requestDto, Board board, User user) {
            this.contents = requestDto.getContents();
            this.board = board;
            this.user = user;
        }
    
        public void updateComment (CommentRequestDto commentRequestDto) {
            this.contents = commentRequestDto.getContents();
        }
    }​
    Timestamped
    @Getter
    @MappedSuperclass
    @EntityListeners(AuditingEntityListener.class)
    public abstract class Timestamped {
        @CreatedDate
        @Column(updatable = false)
        @Temporal(TemporalType.TIMESTAMP)
        private LocalDateTime createdAt;
    
        @LastModifiedDate
        @Column
        @Temporal(TemporalType.TIMESTAMP)
        private LocalDateTime modifiedAt;
    
    }​
    User
    @Getter
    @Entity
    @Table(name = "users")
    @NoArgsConstructor
    public class User extends Timestamped {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long userNum;
        @Column(nullable = false, unique = true, length = 50)
        private String userId;
        @Column(nullable = false)
        private String password;
        @Column(nullable = false, unique = true, length = 50)
        private String email;
        @Column(nullable = false, length = 50)
        private String name;
        @Column(nullable = false)
        @Enumerated(value = EnumType.STRING)
        private UserRoleEnum role;
    
        public User(String userId, String password, String email, String name, UserRoleEnum role) {
            this.userId = userId;
            this.password = password;
            this.email = email;
            this.name = name;
            this.role = role;
        }
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof User user)) return false;
            return Objects.equals(getUserNum(), user.getUserNum()) && Objects.equals(getUserId(), user.getUserId());
        }
    
        public void updateProfile(String name, String userId, String email, String password) {
            this.name = name;
            this.userId = userId;
            this.email = email;
            this.password = password;
    
        }
    }​
    UserRoleEnum
    public enum UserRoleEnum {
        USER(Authority.USER);
    
        private final String authority;
    
        UserRoleEnum (String authority) {
            this.authority = authority;
        }
    
        public String getAuthority() {
            return this.authority;
        }
    
        public static class Authority {
            public static final String USER = "ROLE_USER";
        }
    }
  • jwt 패키지
    더보기
     JwtAuthenticationFilter
    @Slf4j(topic = "로그인 및 JWT 생성")
    public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    
        private final JwtUtil jwtUtil;
    
        public JwtAuthenticationFilter (JwtUtil jwtUtil) {
            this.jwtUtil = jwtUtil;
    //        setFilterProcessesUrl("/users/login");
        }
    
        @Override
        public Authentication attemptAuthentication (
                HttpServletRequest req,
                HttpServletResponse res
        ) throws AuthenticationException {
            log.info("로그인 시도");
    
            try {
                LoginRequestDto requestDto = new ObjectMapper()
                        .readValue(req.getInputStream(), LoginRequestDto.class);
    
                return getAuthenticationManager().authenticate(
                        new UsernamePasswordAuthenticationToken(
                                requestDto.getUserId(),
                                requestDto.getPassword(),
                                null
                        )
                );
            } catch (IOException e) {
                log.error(e.getMessage());
                throw new RuntimeException(e.getMessage());
            }
        }
    
        @Override
        protected void successfulAuthentication(
                HttpServletRequest req,
                HttpServletResponse res,
                FilterChain chain,
                Authentication authResult)
            throws IOException, ServletException {
            log.info("로그인 성공 및 JWT 토큰 생성");
            String userId = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
            UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();
    
            String token = jwtUtil.createToken(userId, role);
            res.addHeader(JwtUtil.AUTHORIZATION_HEADER, token);
        }
    
        @Override
        protected void unsuccessfulAuthentication(
                HttpServletRequest req,
                HttpServletResponse res,
                AuthenticationException failed
        ) throws IOException, ServletException {
            log.info("로그인 실패");
            res.setStatus(401);
        }
    }

    JwtAuthorizationFilter

    @Slf4j(topic = "JWT 검증 및 인가")
    @RequiredArgsConstructor
    public class JwtAuthorizationFilter extends OncePerRequestFilter {
    
        private final JwtUtil jwtUtil;
        private final UserDetailsServiceImpl userDetailsService;
    
        @Override
        protected void doFilterInternal (
                HttpServletRequest req,
                HttpServletResponse res,
                FilterChain filterChain
        ) throws ServletException, IOException {
            String tokenValue = jwtUtil.getJwtFromHeader(req);
    
            if (StringUtils.hasText(tokenValue)) {
                log.info(tokenValue);
                if (!jwtUtil.validateToken(tokenValue)) {
                    log.error("Token Error");
                    return;
                }
    
                Claims info = jwtUtil.getUserInfoFromToken(tokenValue);
    
                try {
                    setAuthentication(info.getSubject());
                } catch (Exception e) {
                    log.error(e.getMessage());
                    return;
                }
            }
    
            filterChain.doFilter(req, res);
        }
    
        public void setAuthentication (String userId) {
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            Authentication authentication = createAuthentication(userId);
            context.setAuthentication(authentication);
    
            SecurityContextHolder.setContext(context);
        }
    
        private Authentication createAuthentication (String userId) {
            UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
            return new UsernamePasswordAuthenticationToken(
                    userDetails,
                    null,
                    userDetails.getAuthorities());
        }
    }
  • repository 패키지
    더보기
     BoardRepository
    public interface BoardRepository extends JpaRepository<Board, Long> {
       List<Board> findAllByUser(User user);
       List<Board> findByUser(User user);// (마이페이지)
       List<Board> findAllByOrderByCreatedAtDesc();
    }​
    CommentRepository
    public interface CommentRepository extends JpaRepository<Comment, Long> {
        List<Comment> findByBoardBoardNum(Long boardNum);
    
        List<Comment> findByBoard(Board board);
    }​
    UserRepository
    public interface UserRepository extends JpaRepository<User, Long> {
        Optional<User> findByUserId(String userId);
        Optional<User   > findByEmail(String email);
    
    }​
  • security 패키지
    더보기
     UserDetailsImpl
    @RequiredArgsConstructor
    public class UserDetailsImpl implements UserDetails {
    
        private final User user;
        public User getUser() {
            return user;
        }
        
        @Override
        public String getUsername() {
            return user.getUserId();
        }
    
        @Override
        public String getPassword() {
            return user.getPassword();
        }
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            UserRoleEnum role = user.getRole();
            String authority = role.getAuthority();
    
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(simpleGrantedAuthority);
            return authorities;
        }
    
        @Override
        public boolean isAccountNonExpired() {
            return true;
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;
        }
    
        @Override
        public boolean isEnabled() {
            return false;
        }
    }​
    UserDetailsServiceImpl
    @Service
    @RequiredArgsConstructor
    public class UserDetailsServiceImpl implements UserDetailsService {
        private final UserRepository userRepository;
    
        @Override
        public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
            User user = userRepository.findByUserId(userId)
                    .orElseThrow(() -> new UsernameNotFoundException("NOT FOUND" + userId));
            return new UserDetailsImpl(user);
        }
    }​
  • service 패키지
    더보기
     BoardService
    @Service
    @RequiredArgsConstructor
    public class BoardService {
    
        private final BoardRepository boardRepository;
        private final UserRepository userRepository;
    
        public Board createBoard(BoardRequestDto requestDto, User user) {
            String title = requestDto.getTitle();
            String contents = requestDto.getContents();
            Board board = new Board(title, contents, user);
            boardRepository.save(board);
    
            return board;
        }
    
        public List<Board> getAllBoards() {
            return boardRepository.findAll();
        }
    
        public Board getBoardById(Long boardNum) {
            Board board = boardRepository.findById(boardNum)
                    .orElseThrow(() -> new IllegalArgumentException("ID에 해당하는 게시물을 찾을 수 없습니다: " + boardNum));
    
            return boardRepository.findById(boardNum).orElseThrow(() -> new IllegalArgumentException("없는 게시글 입니다."));
    
        }
    
        public List<BoardResponseDto> getUserAllBoards(UserDetailsImpl userDetails) {
            User user = userRepository.findByUserId(userDetails.getUsername())
                    .orElseThrow(() -> new IllegalArgumentException("존재하는 회원이 없습니다."));
            return boardRepository.findAllByUser(user)
                    .stream().map(BoardResponseDto::new).toList();
        }
    
        public BoardResponseDto getUserSelectedBoards(Long boardnum, UserDetailsImpl userDetails) {
            Board board = boardRepository.findById(boardnum)
                    .orElseThrow(() -> new IllegalArgumentException("존재하는 게시물이 없습니다."));
            if (!Objects.equals(userDetails.getUser().getUserNum(), board.getUser().getUserNum())) {
                throw new IllegalArgumentException("로그인 정보와 다른 게시물을 선택하였습니다.");
            }
            return new BoardResponseDto(board);
        }
    
        @Transactional
        public Board updateBoard(Long boardNum, BoardUpdateDto requestDto, User user) {
            Board board = findOne(boardNum);
            if (!board.getUser().equals(user)) {
                throw new IllegalArgumentException("작성자만 수정 할 수 있습니다.");
            }
            board.updateBoard(requestDto);
            return board;
        }
    
        public void deleteBoard(Long boardNum, User user) {
            Board board = findOne(boardNum);
    
            if (!board.getUser().equals(user)) {
                throw new IllegalArgumentException("작성자만 삭제 할 수 있습니다.");
            }
            boardRepository.delete(board);
        }
    
        private Board findOne(Long boardNum) {
            return boardRepository.findById(boardNum).orElseThrow(() -> new IllegalArgumentException("없는 게시글 입니다."));
        }
    }​
    CommentService
    @Service
    @RequiredArgsConstructor
    public class CommentService {
        private final CommentRepository commentRepository;
        private final BoardRepository boardRepository;
        private final UserRepository userRepository;
    
        public Comment addComment(Long boardNum, CommentRequestDto requestDto, User user) {
            Board board = findBoard(boardNum);
            User findUser = findUser(user);
    
            return commentRepository.save(new Comment(requestDto, board, findUser));
        }
    
        public Comment updateComment(Long boardNum, Long commentNum, CommentRequestDto commentRequestDto, User user) {
            findBoard(boardNum);
            User findUser = findUser(user);
            Comment comment = findComment(commentNum);
    
            if(!comment.getUser().equals(findUser)) {
                throw new IllegalArgumentException("작성자만 수정 할 수 있습니다.");
            }
            comment.updateComment(commentRequestDto);
            return comment;
        }
        
        public void deleteComment(Long boardNum, Long commentNum, User user) {
            findBoard(boardNum);
            User findUser = findUser(user);
            Comment comment = findComment(commentNum);
    
            if(!comment.getUser().equals(findUser)) {
                throw new IllegalArgumentException("작성자만 삭제 할 수 있습니다.");
            }
            commentRepository.delete(comment);
    
        }
    
        public List<CommentResponseDto> getCommentsByBoard(Long boardNum) {
            Board board = findBoard(boardNum);
            List<Comment> commentList = commentRepository.findByBoardBoardNum(boardNum);
            return convertToDtoList(commentList);
        }
        private Board findBoard(Long boardNum) {
            return boardRepository.findById(boardNum).orElseThrow(() -> new IllegalArgumentException("없는 게시글입니다."));
        }
    
        private User findUser(User user) {
            return userRepository.findById(user.getUserNum()).orElseThrow(() -> new IllegalArgumentException("없는 사용자입니다."));
        }
    
        private Comment findComment(Long commentNum) {
            return commentRepository.findById(commentNum).orElseThrow(() -> new IllegalArgumentException("없는 댓글입니다."));
        }
    
        private List<CommentResponseDto> convertToDtoList(List<Comment> commentList) {
            List<CommentResponseDto> commentResponseDtoList = new ArrayList<>();
            for (Comment comment : commentList) {
                commentResponseDtoList.add(new CommentResponseDto(comment));
            }
            return commentResponseDtoList;
        }
    }​
    UserService
    @Service
    @RequiredArgsConstructor
    public class UserService {
    
        private final UserRepository userRepository;
        private final PasswordEncoder passwordEncoder;
        private final BoardRepository boardRepository;
        private final CommentRepository commentRepository;
        private final JwtUtil jwtUtil;
    
        public void signup(SignupRequestDto requestDto) {
            String userId = requestDto.getUserId();
            Optional<User> checkUserId = userRepository.findByUserId(userId);
            if (checkUserId.isPresent()) {
                throw new IllegalArgumentException("중복된 아이디가 존재합니다.");
            }
    
            String password = passwordEncoder.encode(requestDto.getPassword());
    
            String email = requestDto.getEmail();
            Optional<User> checkEmail = userRepository.findByEmail(email);
            if (checkEmail.isPresent()) {
                throw new IllegalArgumentException("중복된 이메일이 존재합니다.");
            }
    
            String name = requestDto.getName();
    
            UserRoleEnum role = UserRoleEnum.USER;
    
            User user = new User(userId, password, email, name, role);
            userRepository.save(user);
        }
    
        public LoginResponseDto login(LoginRequestDto requestDto) {
            Optional<User> user = userRepository.findByUserId(requestDto.getUserId());
            if (user.isEmpty()) {
                throw new IllegalArgumentException("존재하지 않는 회원입니다.");
            }
            if (!passwordEncoder.matches(requestDto.getPassword(), user.get().getPassword())) {
                throw new IllegalArgumentException("비밀번호가 다릅니다.");
            }
    
            String token = jwtUtil.createToken(user.get().getUserId(), UserRoleEnum.USER);
    
            LoginResponseDto responseDto = LoginResponseDto.builder()
                    .userId(user.get().getUserId())
                    .password(user.get().getPassword())
                    .email(user.get().getEmail())
                    .name(user.get().getName())
                    .token(token)
                    .build();
    
            return responseDto;
        }
    
        public void deleteUser(User user) {
            User findUser = findUser(findUser(user));
            if(!user.getUserNum().equals(findUser.getUserNum())) {
                throw new IllegalArgumentException("유저 정보가 일치하지 않습니다.");
            }
            List<Board> userBoards = boardRepository.findByUser(user);
                    for(Board board : userBoards) {
                        List<Comment> boardComments = commentRepository.findByBoard(board);
                        commentRepository.deleteAll(boardComments);
                    }
                    boardRepository.deleteAll(userBoards);
                    userRepository.delete(user);
        }
    
        public ProfileResponseDto getProfile(Long userNum) {
                User user = userRepository.findById(userNum).orElseThrow(() -> new IllegalArgumentException("해당 아이디는 존재하지 않습니다."));
                return new ProfileResponseDto(user.getName(), user.getUserId(), user.getEmail(), user.getPassword());
        }
    
        @Transactional
        public ProfileResponseDto updateProfile(Long userNum, UserUpdateDto request) {
            User user = userRepository.findById(userNum).orElseThrow(() -> new IllegalArgumentException(" 계정 정보가 일치하지 않습니다."));
            if (!request.getPassword().equals(request.getConfirmPassword())) {
                throw new RuntimeException("패스워드가 일치하지 않습니다.");
            }
    
            String changedPassword = passwordEncoder.encode(request.getPassword());
    
            user.updateProfile(request.getName(), request.getUserId(), request.getEmail(), changedPassword);
            return new ProfileResponseDto(user.getName(), user.getUserId(), user.getEmail(), changedPassword);
        }
    
        private User findUser(User user) {
            return userRepository.findById(user.getUserNum()).orElseThrow(() -> new IllegalArgumentException("없는 사용자입니다."));
        }
    }​
  • util 패키지
    더보기
     JwtUtil
    @Component
    public class JwtUtil {
        public static  final String AUTHORIZATION_HEADER = "Authorization";
    
        public static final String AUTHORIZATION_KEY = "auth"; // 권한 사용할 때 필요
    
        public static final String BEARER_PREFIX = "Bearer";
    
        private final long TOKEN_TIME = 60 * 60 * 1000L; // 60분
    
        @Value(("${jwt.secret.key}"))
        private String secretKey;
        private Key key;
        private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    
        public static final Logger logger = LoggerFactory.getLogger("JWT 관련 로그");
    
        @PostConstruct
        public void init() {
            byte[] bytes = Base64.getDecoder().decode(secretKey);
            key = Keys.hmacShaKeyFor(bytes);
        }
    
        public String createToken (String userId, UserRoleEnum role) {
            Date date = new Date();
    
            return BEARER_PREFIX +
                    Jwts.builder()
                            .setSubject(userId)
                            .claim(AUTHORIZATION_KEY, role)
                            .setExpiration(new Date(date.getTime() + TOKEN_TIME))
                            .setIssuedAt(date)
                            .signWith(key, signatureAlgorithm)
                            .compact();
        }
    
        public String getJwtFromHeader (HttpServletRequest req) {
            String bearerToken = req.getHeader(AUTHORIZATION_HEADER);
            if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(BEARER_PREFIX)) {
                return bearerToken.substring(7);
            }
            return null;
        }
    
        public boolean validateToken (String token) {
            try {
                Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
                return true;
            } catch (SecurityException | MalformedJwtException | SignatureException e) {
                logger.error("Invalid JWT Signature, 유효하지 않는 JWT 서명입니다.");
            } catch (ExpiredJwtException e) {
                logger.error("Expired JWT Token, 만료된 JWT 토큰입니다.");
            } catch (UnsupportedJwtException e) {
                logger.error("Unsupported JWT Token, 지원되지 않는 JWT 토큰입니다.");
            } catch (IllegalArgumentException e) {
                logger.error("JWT Claims is Empty, 잘못된 JWT 토큰입니다.");
            }
            return false;
        }
    
        public Claims getUserInfoFromToken (String token) {
            return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
        }
    }​

회고

  • 이번 프로젝트로 인해 말로만 들었던 문제들을 직접 겪어보고 그 중요성을 더욱 크게 깨닫게 되는 시간이라 생각합니다.
  • 또한 프로젝트를 통해 얻게 된 지식들이 너무 많고 직접 코드를 작성하며 깨닫는 것이 더 많은 것을 얻어가는 것 같습니다.
  • 코드의 흐름을 알게 되고 문제를 해결하는 방법, 팀원과의 소통 등 너무 많은 것을 느끼고 얻어가는 시간이었습니다.