개발 일지/Project
Spring : NewsFeed
쁘띠뀨띠
2024. 2. 7. 18:03
주제 : 동물 질병, 병원, 약국 등에 관한 뉴스피드
팀장 : 박정섭
팀원 : 손영효, 장원녕, 진유림, 이건희
결과 : https://github.com/katchSpring/animallia.git
기본 요구사항
- 사용자 인증 기능
- 회원가입 기능
- 새로운 사용자가 ID와 비밀번호의 형태로 서비스에 가입할 수 있어야 합니다.
- 이 때, 비밀번호는 안전하게 암호화되어 저장되어야 합니다!
- 새로운 사용자가 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 추가하기
등록 성공!