개발 일지/Project

Spring : NewsFeed

쁘띠뀨띠 2024. 2. 7. 18:03
주제 : 동물 질병, 병원, 약국 등에 관한 뉴스피드
팀장 : 박정섭
팀원 : 손영효, 장원녕, 진유림, 이건희
결과 : https://github.com/katchSpring/animallia.git
기본 요구사항
  • 사용자 인증 기능
    • 회원가입 기능
      • 새로운 사용자가 ID와 비밀번호의 형태로 서비스에 가입할 수 있어야 합니다.
        • 이 때, 비밀번호는 안전하게 암호화되어 저장되어야 합니다!
    • 로그인 및 로그아웃 기능
      • 사용자는 자신의 계정으로 서비스에 로그인하고 로그아웃할 수 있어야 합니다.
  • 프로필 관리
    • 프로필 수정 기능
      • 이름, 한 줄 소개와 같은 기본적인 정보를 볼 수 있어야 하며 수정할 수 있어야 합니다.
      • 비밀번호 수정 시에는 비밀번호를 한 번 더 입력받는 과정이 필요합니다.
  • 게시물 CRUD 기능
    • 게시물 작성, 조회, 수정, 삭제 기능
      • 게시물 조회를 제외한 나머지 기능들은 전부 인가(Authorization) 개념이 적용되어야 하며 이는 JWT와 같은 토큰으로 검증이 되어야 할 것입니다.
      • 예컨대, 내가 작성한 글을 남이 삭제할 수는 없어야 하고 오로지 본인만 삭제할 수 있어야겠죠?
    • 게시물 작성, 수정, 삭제 시 새로고침 기능
      • 프론트엔드에서 게시물 작성, 수정 및 삭제를 할 때마다 조회 API를 다시 호출하여 자연스럽게 최신의 게시물 내용을 화면에 보여줄 수 있도록 해야 합니다!
  • 뉴스 피드 기능
    • 뉴스 피드 페이지
      • 사용자가 다른 사용자의 게시물을 한 눈에 볼 수 있는 뉴스 피드 페이지가 있어야 합니다.
추가요구사항
  • 댓글 CRUD 기능
    • 댓글 작성, 조회, 수정, 삭제 기능
    • 댓글 작성, 수정, 삭제 시 새로고침 기능
  • 이메일 가입 및 인증 기능
    • 이메일 가입 시 이메일 인증 기능을 포함하는 것이 좋습니다.
  • 좋아요 기능
    • 게시물 및 댓글 좋아요/좋아요 취소 기능
  • 프론트엔드 만들어보기
와이어프레임

ERD 설계

API 명세서


내가 맡은 부분 : 회워가입 및 로그인 / 패스워드 암호화

controller

@RequiredArgsConstructor
@RestController
@RequestMapping("/api")
public class UserController {

    private final UserService userService;

    @PostMapping("/user/signup")
    public ResponseEntity<String> signup(@RequestBody SignupRequestDto requestDto) {
        userService.signup(requestDto);
        return new ResponseEntity<>("signup-sucess",HttpStatus.OK);
    }

    @GetMapping("/user/login")
    public ResponseEntity<String> login(@RequestBody LoginRequestDto requestDto, HttpServletResponse res) {
        try {
            userService.login(requestDto, res);
        } catch (Exception e) {
           e.getMessage();
        }
        return new ResponseEntity<>("login-sucess",HttpStatus.OK);
    }

}

DTO

@Getter
public class LoginRequestDto {
    private String username;
    private String password;
}
@Getter
public class SignupRequestDto {
    private String username;
    private String password;
//    private String email;  -> 추가요구사항
}

SERVICE

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    @Transactional
    public void signup(SignupRequestDto requestDto) {
        String username = requestDto.getUsername();
        String password = passwordEncoder().encode(requestDto.getPassword());

        userRepository.save(new User(username, password));
    }

    @Transactional
    public void login(LoginRequestDto requestDto, HttpServletResponse res) {
        String username = requestDto.getUsername();
        String password = requestDto.getPassword();

        User user = userRepository.findByUsername(username).orElseThrow(() ->
            new IllegalArgumentException("존재하지 않는 username 입니다."));

        if (!passwordEncoder().matches(password,user.getPassword())) {
            throw new IllegalArgumentException("잘못된 비밀번호입니다.");
        }

    }
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
@Transactional
public void login(LoginRequestDto requestDto, HttpServletResponse res) {
    String username = requestDto.getUsername();
    String password = requestDto.getPassword();

    User user = userRepository.findByUsername(username).orElseThrow(() ->
            new IllegalArgumentException("존재하지 않는 username 입니다."));

    if (!passwordEncoder.matches(password,user.getPassword())) {
        throw new IllegalArgumentException("잘못된 비밀번호입니다.");
    }
    String token = jwtUtil.createToken(user.getUsername(), user.getRole());
    jwtUtil.addJwtToHeader(token, res);

}

REPOSITORY

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String user);
}

ENTITY

@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Post> postList = new ArrayList<>();

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

}

jwt 토큰생성까지 하고 1차 머지 후 로그인 후 토큰을 가진 유저의 게시물 등록하기가 안돼서 시간을 많이 잡아먹었다.

 

- controller 기존코드

@PostMapping("/post")
public ResponseEntity<CommonResponse<PostResponseDto>> createPost(@RequestBody PostRequestDto requestDto) {
    Post post = postService.createPost(requestDto);
    PostResponseDto response = new PostResponseDto(post);

    return ResponseEntity.ok()
            .body(CommonResponse.<PostResponseDto>builder()
                    .statusCode(HttpStatus.OK.value())
                    .msg("생성이 완료 되었습니다.")
                    .data(response)
                    .build());
}

 

-변경된 코드

@PostMapping("/post")
public ResponseEntity<CommonResponse<PostResponseDto>> createPost(@RequestBody PostRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
    Post post = postService.createPost(requestDto, userDetails);
    PostResponseDto response = new PostResponseDto(post);

    return ResponseEntity.ok()
            .body(CommonResponse.<PostResponseDto>builder()
                    .statusCode(HttpStatus.OK.value())
                    .msg("생성이 완료 되었습니다.")
                    .data(response)
                    .build());
}

 

- service 기존 코드

public Post createPost(PostRequestDto dto) {
    Post newPost = dto.toEntity();
    return postRepository.save(newPost);
}

 

- 변경된 코드

public Post createPost(PostRequestDto requestDto, UserDetailsImpl userDetails) {
    Post newPost = requestDto.toEntity();
    newPost.setUser(userDetails.getUser());
    System.out.println("user = " + newPost.getUser());
    return postRepository.save(newPost);
}

 

* userDerails 로 현재 user를 가져와 post의 User에 set 시켜 포스트를 함께 저장한다 !!!!!!!!!!!!!!!!!!!!

 

 

1_postman에서 로그인하면 생성된 토큰 등록하기

*headers 에 넣을때는 bearer 추가하기

 

등록 성공!