1 Project Info

1๏ธโƒฃ ์„œ๋น„์Šค ์š”๊ตฌ์‚ฌํ•ญ

API ๊ตฌ๋ถ„๊ธฐ๋Šฅ
ํšŒ์›๊ฐ€์ž…- ํšŒ์›๋ช…, ๋น„๋ฐ€๋ฒˆํ˜ธ Client์—์„œ ์ „๋‹ฌ๋ฐ›๊ธฐ
- username : 4 ~ 10์ž, ์•ŒํŒŒ๋ฒณ์†Œ๋ฌธ์ž(a ~ z), ์ˆซ์ž(0 ~ 9) ๊ตฌ์„ฑ
- password : 8 ~ 15์ž, ์•ŒํŒŒ๋ฒณ๋Œ€์†Œ๋ฌธ์ž(a ~ z, A ~ Z), ์ˆซ์ž(0 ~ 9) ๊ตฌ์„ฑ
- ํšŒ์› DB ์ค‘๋ณตํ™•์ธ ํ›„, ์ €์žฅ
- ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต ์‹œ, Client๋กœ ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ ๋ฐ˜ํ™˜
๋กœ๊ทธ์ธ- ํšŒ์›๋ช…, ๋น„๋ฐ€๋ฒˆํ˜ธ Client์—์„œ ์ „๋‹ฌ๋ฐ›๊ธฐ
- ํšŒ์› DB์—์„œ username์„ ์‚ฌ์šฉํ•ด ์กฐํšŒ โ†’ password ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
- ๋กœ๊ทธ์ธ์„ฑ๊ณต โ†’ username๊ณผ JWT ํ†ตํ•ด Token ๋ฐœ๊ธ‰
- Token โ†’ Response Header์— ์ถ”๊ฐ€, ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ Client ๋ฐ˜ํ™˜
๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ- Client Token ์œ ํšจ์„ฑ๊ฒ€์‚ฌ โ†’ ๊ฒŒ์‹œ๊ธ€์ž‘์„ฑ ๊ฐ€๋Šฅ
- ์ œ๋ชฉ, ํšŒ์›๋ช…, ์ž‘์„ฑ๋‚ด์šฉ ์ €์žฅ
- ์ €์žฅ๋œ๊ฒŒ์‹œ๊ธ€ Client ๋ฐ˜ํ™˜
์ „์ฒด๊ฒŒ์‹œ๊ธ€ ๋ชฉ๋ก์กฐํšŒ- ์ œ๋ชฉ, ํšŒ์›๋ช…, ์ž‘์„ฑ๋‚ด์šฉ, ์ž‘์„ฑ๋‚ ์งœ ์กฐํšŒ
- ์ž‘์„ฑ๋‚ ์งœ ๊ธฐ์ค€ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ- ์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€ ์ œ๋ชฉ, ํšŒ์›๋ช…, ์ž‘์„ฑ๋‚ ์งœ, ์ž‘์„ฑ๋‚ด์šฉ ์กฐํšŒ
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •- ์ˆ˜์ •์š”์ฒญ ์‹œ, Client Token ์œ ํšจ์„ฑ๊ฒ€์‚ฌ + ๋™์ผ ํšŒ์›์ผ ๊ฒฝ์šฐ์—๋งŒ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •๊ฐ€๋Šฅ
- ์ œ๋ชฉ, ์ž‘์„ฑ๋‚ด์šฉ ์ˆ˜์ •
- ์ˆ˜์ •๋œ๊ฒŒ์‹œ๊ธ€ Client ๋ฐ˜ํ™˜
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ- ์‚ญ์ œ์š”์ฒญ ์‹œ, Client Token ์œ ํšจ์„ฑ๊ฒ€์‚ฌ + ๋™์ผ ํšŒ์›์ผ ๊ฒฝ์šฐ์—๋งŒ ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ๊ฐ€๋Šฅ
- ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ Client ๋ฐ˜ํ™˜

2๏ธโƒฃ ERD

3๏ธโƒฃ API ๋ช…์„ธ์„œ

๊ธฐ๋ŠฅURLMethodRequestHeaderRequestResponseHeaderResponse
ํšŒ์›๊ฐ€์ž…/auth/signupPOST-{
ย ย "username" : String,
ย ย "password" : String
}
-{
ย ย "status" : 200,
ย ย "message" : "You have successfully signed up"
}
๋กœ๊ทธ์ธ/auth/loginPOST-{
ย ย "username" : String,
ย ย "password" : String
}
Authorization: Bearer <JWT>{
ย ย "status" : 200,
ย ย "message" : "You have successfully logged in"
}
๊ฒŒ์‹œ๊ธ€์ž‘์„ฑ/postPOSTAuthorization: Bearer <JWT>{
ย ย "title" : String,
ย ย "content" : String
}
-{
ย ย "id" : Long,
ย ย "username" : String,
ย ย "title" : String,
ย ย "content" : String,
ย ย "createAt" : String,
ย ย "modifiedAt" : String
}
์ „์ฒด๊ฒŒ์‹œ๊ธ€๋ชฉ๋ก์กฐํšŒ/postsGET---[
{
ย ย "id" : Long,
ย ย "username" : String,
ย ย "title" : String,
ย ย  "content" : String,
ย ย "createdAt" : String,
ย ย "modifiedAt" : String
},
{
ย ย "id" : Long,
ย ย "username" : String,
ย ย "title" : String,
ย ย  "content" : String,
ย ย "createdAt" : String,
ย ย "modifiedAt" : String
}, โ€ขโ€ขโ€ข
]
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€์กฐํšŒ/post/{post-id}GET---{
ย ย "id" : Long,
ย ย "username" : String,
ย ย "title" : String,
ย ย  "content" : String,
ย ย "createdAt" : String,
ย ย "modifiedAt" : String
}
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€์ˆ˜์ •/post/{post-id}PUTAuthorization: Bearer <JWT>{
ย ย "title" : String,
ย ย "content" : String
}
-{
ย ย "id" : Long,
ย ย "username" : String,
ย ย "title" : String,
ย ย  "content" : String,
ย ย "createdAt" : String,
ย ย "modifiedAt" : String
}
์„ ํƒํ•œ๊ฒŒ์‹œ๊ธ€์‚ญ์ œ/post/{post-id}DELETEAuthorization: Bearer <JWT>--{
ย ย "status" : 200,
ย ย "message" : "Your post has been deleted successfully"
}

2 User ์„ค๊ณ„

1๏ธโƒฃ entity > User.java

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

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

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

    @Column(nullable = false)
    private String password;

    // ์ƒ์„ฑ์ž
    @Builder
    private User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static User of(String username, String password) {
        return User.builder()
                .username(username)
                .password(password)
                .build();
    }

}

2๏ธโƒฃ repository > UserRepository.java

public interface UserRepository extends JpaRepository<User, Long> {
}

3๏ธโƒฃ dto > SignupRequestDto.java

@Getter
public class SignupRequestDto {
    
    // build.gradle -> validation ์˜์กด์„ฑ์ถ”๊ฐ€
    @Size(min = 4, max = 10, message = "์ตœ์†Œ 4์ž, ์ตœ๋Œ€ 10์ž๊นŒ์ง€ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค")
    @Pattern(regexp = "[a-z0-9]*$", message = "์•ŒํŒŒ๋ฒณ์†Œ๋ฌธ์ž ๋ฐ ์ˆซ์ž๋กœ๋งŒ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค")
    private String username;

    @Size(min = 8, max = 15, message = "์ตœ์†Œ 8์ž, ์ตœ๋Œ€ 15์ž๊นŒ์ง€ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค")
    @Pattern(regexp = "[a-zA-Z0-9]*$", message = "์•ŒํŒŒ๋ฒณ๋Œ€์†Œ๋ฌธ์ž ๋ฐ ์ˆซ์ž๋กœ๋งŒ ์„ค์ • ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค")
    private String password;

}
/*build.gradle -> validation ์˜์กด์„ฑ์ถ”๊ฐ€*/

// ์ •๊ทœํ‘œํ˜„์‹ @Size, @Pattern
    implementation 'org.springframework.boot:spring-boot-starter-validation'

4๏ธโƒฃ dto > LoginRequestDto.java

@Getter
public class LoginRequestDto {

    private String username;

    private String password;

}

3 EntityMapping (User&Post)

1๏ธโƒฃ entity > Post.java

@Entity
@Getter
@NoArgsConstructor // ํŒŒ๋ผ๋ฏธํ„ฐ์—†๋Š” ๊ธฐ๋ณธ์ƒ์„ฑ์ž
public class Post extends Timestamped {

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

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    // User Entity -> Post Entity ; ๋‹จ๋ฐฉํ–ฅ์—ฐ๊ด€๊ด€๊ณ„
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_Id")
    private User user;

    // Client Request ๊ฐ’ -> Dto์—์„œ ๋ฐ›์•„์™€์„œ -> ๋ฎ์–ด์”Œ์›€
    @Builder // ๋นŒ๋”ํŒจํ„ด : ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ›์Œ (-> ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ)
    private Post(String title, String content, User user) {
        this.title = title;
        this.content = content;
        this.user = user;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static Post of(PostRequestDto postRequestDto, User user) {
        return Post.builder()
                .title(postRequestDto.getTitle())
                .content(postRequestDto.getContent())
                .user(user)
                .build();
    }

    // Post ์ˆ˜์ • (Service -> RequestDto -> update ๋ฉ”์„œ๋“œ)
    public void update(PostRequestDto postRequestDto) {
        this.title = postRequestDto.getTitle();
        this.content = postRequestDto.getContent();
    }

}
  • username, password โ†’ ์ปฌ๋Ÿผ ์‚ญ์ œ

  • ์ƒ์„ฑ์ž ๋ฐ ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ User ๋ถ€๋ถ„ ์ถ”๊ฐ€

  • ๋‹จ๋ฐฉํ–ฅ์—ฐ๊ด€๊ด€๊ณ„ ์„ค์ •

    • 1(User) : N(Post)
    • N์ธ Post Entity์— @ManyToOne ์„ค์ •

2๏ธโƒฃ dto > PostRequestDto.java

@Getter
public class PostRequestDto {

    private String title;

    private String content;

}
  • username, password โ†’ ์‚ญ์ œ

3๏ธโƒฃ dto > PostResponseDto.java

@Getter
public class PostResponseDto {

    private Long id;

    private String title;

    private String username;

    private String content;

    private LocalDateTime createdAt;

    private LocalDateTime modifiedAt;

    // ์ƒ์„ฑ์ž
    @Builder
    private PostResponseDto(Long id,
                            String title, String username, String content,
                            LocalDateTime createdAt, LocalDateTime modifiedAt) {
        this.id = id;
        this.title = title;
        this.username = username;
        this.content = content;
        this.createdAt = createdAt;
        this.modifiedAt = modifiedAt;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static PostResponseDto of(Post post) {
        return PostResponseDto.builder()
                .id(post.getId())
                .title(post.getTitle())
                .username(post.getUser().getUsername())
                .content(post.getContent())
                .createdAt(post.getCreatedAt())
                .modifiedAt(post.getModifiedAt())
                .build();
    }

}
  • ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ โ†’ username ๊ฐ€์ ธ์˜ค๋Š”๋ถ€๋ถ„ ์ˆ˜์ •

4 JWT ์„ค๊ณ„

1๏ธโƒฃ build.gradle > jwt dependency ์ถ”๊ฐ€

// JWT
compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2'

2๏ธโƒฃ application.properties > SecretKey ์ถ”๊ฐ€

# JWT SecretKey
jwt.secret.key=<์•”ํ˜ธํ™”์ฝ”๋“œ>

3๏ธโƒฃ jwt > JwtUtil.java

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtUtil {

    /* JWT Token ์ƒ์„ฑ ํ•„์š”๊ฐ’ */
    // Header key
    public static final String AUTHORIZATION_HEADER = "Authorization";

    // ์‚ฌ์šฉ์ž ๊ถŒํ•œ๊ฐ’ key
    public static final String AUTHORIZATION_KEY = "auth";

    // JWT Token ์ธ์ฆ๋ฐฉ์‹ (Bearer + JWT Token ๊ฐ™์ด ์ „์†ก)
    private static final String BEARER_PREFIX = "Bearer ";

    // JWT Token ๋งŒ๋ฃŒ์‹œ๊ฐ„ (1h)
    private static final long TOKEN_TIME = 60 * 60 * 1000L;

    // WT SecretKey ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
    @Value("${jwt.secret.key}")
    private String secretKey;

    // JWT Token ์„œ๋ช… ๋ฐ ๊ฒ€์ฆ์šฉ๋„
    private Key key;

    // JWT Token ์ƒ์„ฑ(์„œ๋ช…) ์•Œ๊ณ ๋ฆฌ์ฆ˜
    private final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

    // SecretKey ๋””์ฝ”๋”ฉ ํ›„, ์„œ๋ช… ๋ฐ ๊ฒ€์ฆ์— ํ•„์š”ํ•œ key ์ƒ์„ฑ
    @PostConstruct
    public void init() {
        // secretKey -> ๋””์ฝ”๋”ฉ -> byte๋ฐฐ์—ด์— ๋‹ด์Œ
        byte[] bytes = Base64.getDecoder().decode(secretKey);

        // ๋””์ฝ”๋”ฉ ํ•œ byte๋ฐฐ์—ด -> JWT Token ์„œ๋ช… ๋ฐ ๊ฒ€์ฆ์— ํ•„์š”ํ•œ key ์ƒ์„ฑ
        key = Keys.hmacShaKeyFor(bytes);
    }


    /* 1. Client Request Header -> JWT Token ๊ฐ€์ ธ์˜ค๊ธฐ */
    public String getToken(HttpServletRequest httpServletRequest) {

        // Header์— ์žˆ๋Š” JWT Token -> clientToken์— ๋‹ด์Œ
        String clientToken = httpServletRequest.getHeader(AUTHORIZATION_HEADER);

        // clientToken ์กด์žฌ + Bearer๋กœ ์‹œ์ž‘ -> JWT Token ๊ฐ’๋งŒ ์ถ”์ถœ
        if (StringUtils.hasText(clientToken) && clientToken.startsWith(BEARER_PREFIX)) {
            return clientToken.substring(7);
        }

        return null;

    }


    /* 2. JWT Token ์ƒ์„ฑ */
    public String createToken(String username) {

        Date date = new Date();

        return BEARER_PREFIX +
                Jwts.builder()
                        .setSubject(username)
                        .setExpiration(new Date(date.getTime() + TOKEN_TIME))
                        .setIssuedAt(date)
                        .signWith(key, signatureAlgorithm)
                        .compact();

    }


    /* 3. JWT Token ๊ฒ€์ฆ */
    public boolean validateToken(String token) {

        try {

            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;

        } catch  (SecurityException | MalformedJwtException exception) {
            log.info("Invalid JWT signature, ์œ ํšจํ•˜์ง€ ์•Š๋Š” JWT ์„œ๋ช… ์ž…๋‹ˆ๋‹ค");
        } catch (ExpiredJwtException exception) {
            log.info("Expired JWT Token, ๋งŒ๋ฃŒ๋œ JWT Token ์ž…๋‹ˆ๋‹ค");
        } catch (UnsupportedJwtException exception) {
            log.info("Unsupported JWT Token, ์ง€์›๋˜์ง€ ์•Š๋Š” JWT Token ์ž…๋‹ˆ๋‹ค");
        } catch (IllegalArgumentException exception) {
            log.info("JWT claims is empty, ์ž˜๋ชป๋œ JWT Token ์ž…๋‹ˆ๋‹ค");
        }

        return false;

    }


    /* 4. JWT Token -> ํšŒ์›์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ */
    public Claims getUserInfoFromToken(String token) {

        return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();

    }

}

5 ํšŒ์›๊ฐ€์ž… ์„ค๊ณ„

1๏ธโƒฃ StatusMessageResponseDto.java

@Getter
public class StatusMessageResponseDto {

    private Integer status;

    private String message;

    // ์ƒ์„ฑ์ž
    @Builder
    private StatusMessageResponseDto(Integer status, String message) {
        this.status = status;
        this.message = message;
    }

    // ์ •์ ํŒฉํ† ๋ฆฌ๋ฉ”์„œ๋“œ
    public static StatusMessageResponseDto of(Integer status, String message) {
        return StatusMessageResponseDto.builder()
                .status(status)
                .message(message)
                .build();
    }

}

2๏ธโƒฃ UserController.java

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

    private final UserService userService;

    // ํšŒ์›๊ฐ€์ž…
    @PostMapping("/signup")
    public ResponseEntity<StatusMessageResponseDto> signup(@Valid @RequestBody SignupRequestDto signupRequestDto) {

        return userService.signup(signupRequestDto);

    }

}

3๏ธโƒฃ UserService.java

@Service
@RequiredArgsConstructor
public class UserService {

    private final UserRepository userRepository;

    private final JwtUtil jwtUtil;

    // ํšŒ์›๊ฐ€์ž…
    @Transactional
    public ResponseEntity<StatusMessageResponseDto> signup(SignupRequestDto signupRequestDto) {

        // id/pw ๊ฐ€์ ธ์˜ค๊ธฐ
        String username = signupRequestDto.getUsername();
        String password = signupRequestDto.getPassword();

        // ํšŒ์›์ค‘๋ณตํ™•์ธ (Optional -> ๊ฒฐ๊ณผ๊ฐ’ Null ํ—ˆ์šฉ)
        Optional<User> duplicationTest = userRepository.findByUsername(username);

        if (duplicationTest.isPresent()) {
            throw new IllegalArgumentException("A Duplicate user already exists");
        }

        // ํšŒ์›์ •๋ณด -> Entity ์ดˆ๊ธฐํ™”
        User user = User.of(username, password);

        // Entity -> DB ์ €์žฅ
        userRepository.save(user);

        // ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต ์‹œ, Client๋กœ ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ ๋ฐ˜ํ™˜
        return ResponseEntity.ok(StatusMessageResponseDto.of(200, "You have successfully signed up"));

    }

}

4๏ธโƒฃ UserRepository.java

public interface UserRepository extends JpaRepository<User, Long> {

    // ํšŒ์›๊ฐ€์ž… -> ์ค‘๋ณต๊ฒ€์‚ฌ
    Optional<User> findByUsername(String username);

}

6 ๋กœ๊ทธ์ธ ์„ค๊ณ„

1๏ธโƒฃ UserController.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// ๋กœ๊ทธ์ธ
@PostMapping("/login")
public ResponseEntity<StatusMessageResponseDto> login(@RequestBody LoginRequestDto loginRequestDto,
                                                      HttpServletResponse httpServletResponse) {

        return userService.login(loginRequestDto, httpServletResponse);

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

2๏ธโƒฃ UserService.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// ๋กœ๊ทธ์ธ
@Transactional(readOnly = true)
public ResponseEntity<StatusMessageResponseDto> login(LoginRequestDto loginRequestDto,
                                                      HttpServletResponse httpServletResponse) {

    // id/pw ๊ฐ€์ ธ์˜ค๊ธฐ
    String username = loginRequestDto.getUsername();
    String password = loginRequestDto.getPassword();

    // ํšŒ์›์œ ํšจ์„ฑ๊ฒ€์‚ฌ
    User user = userRepository.findByUsername(username).orElseThrow(
            () -> new IllegalArgumentException("This account does not exist")
    );

    // ๋น„๋ฐ€๋ฒˆํ˜ธ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
    if (! user.getPassword().equals(password)) {
        throw new IllegalArgumentException("This password is invalid");
    }

    // ๋กœ๊ทธ์ธ์„ฑ๊ณต -> ResponseHeader์— JWT Token ๋ณด๋ƒ„
    httpServletResponse.addHeader(JwtUtil.AUTHORIZATION_HEADER, jwtUtil.createToken(user.getUsername()));

    // ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ, Client๋กœ ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ ๋ฐ˜ํ™˜
    return ResponseEntity.ok(StatusMessageResponseDto.of(200, "You have successfully logged in"));

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

7 ๊ฒŒ์‹œ๊ธ€์ž‘์„ฑ JWT์ธ๊ฐ€์„ค๊ณ„

1๏ธโƒฃ PostController.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// Post ์ƒ์„ฑ
@PostMapping("/post")
public PostResponseDto createPost(@RequestBody PostRequestDto postRequestDto,
                                  HttpServletRequest httpServletRequest) {

    return postService.createPost(postRequestDto, httpServletRequest);

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

2๏ธโƒฃ PostService.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

private final PostRepository postRepository;

private final UserRepository userRepository;

private final JwtUtil jwtUtil;

// Post ์ƒ์„ฑ
@Transactional // DB์ฒ˜๋ฆฌ ์ž‘์—… ์ค‘ ์˜ค๋ฅ˜ -> ๋ชจ๋“ ์ž‘์—… ์›์ƒํƒœ๋กœ ๋ณต๊ตฌ
public PostResponseDto createPost(PostRequestDto postRequestDto,
                                  HttpServletRequest httpServletRequest) {

    // 1. HTTP Request Header -> JWT Token ๊ฐ€์ ธ์˜ค๊ธฐ
    String token = jwtUtil.getToken(httpServletRequest);
    Claims claims;

    // 2. JWT Token ์œ ํšจ -> Post ์ƒ์„ฑ ๊ฐ€๋Šฅ
    if (token != null) {

        // 2-1. JWT Token ๊ฒ€์ฆ
        if (jwtUtil.validateToken(token)) {

            // JWT Token ์—์„œ ์‚ฌ์šฉ์ž์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
            claims = jwtUtil.getUserInfoFromToken(token);

        } else {
            throw new IllegalArgumentException("Token Error");
        }

        // 2-2. Token์—์„œ ๊ฐ€์ ธ์˜จ ์‚ฌ์šฉ์ž ์ •๋ณด -> DB ์กฐํšŒ
        User user = userRepository.findByUsername(claims.getSubject()).orElseThrow(
                () -> new IllegalArgumentException("This account does not exist")
        );

        // 2-3. ์š”์ฒญ๋ฐ›์€ DTO -> DB์— ์ €์žฅํ•  ๊ฐ์ฒด์ƒ์„ฑ
        Post post = postRepository.saveAndFlush(Post.of(postRequestDto, user));

        // 2-4. ResponseDto์— ๊ฐ์ฒด๋‹ด์•„ ๋ฐ˜ํ™˜
        return PostResponseDto.of(post);

    } else {

        return null;

    }

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

8 ๊ฒŒ์‹œ๊ธ€์ˆ˜์ • JWT์ธ๊ฐ€์„ค๊ณ„

1๏ธโƒฃ PostController.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// Post ์ˆ˜์ •
@PutMapping("/post/{post-id}")
public PostResponseDto updatePost(@PathVariable(name="post-id") Long postId,
                                  @RequestBody PostRequestDto postRequestDto,
                                  HttpServletRequest httpServletRequest) {

    return postService.updatePost(postId, postRequestDto, httpServletRequest);

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

2๏ธโƒฃ PostService.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// Post ์ˆ˜์ •
@Transactional
public PostResponseDto updatePost(Long postId, PostRequestDto postRequestDto,
                                  HttpServletRequest httpServletRequest) {

    // 1. HTTP Request Header -> JWT Token ๊ฐ€์ ธ์˜ค๊ธฐ
    String token = jwtUtil.getToken(httpServletRequest);
    Claims claims;

    // 2. JWT Token ์œ ํšจ -> Post ์ˆ˜์ • ๊ฐ€๋Šฅ
    if (token != null) {

        // 2-1. JWT Token ๊ฒ€์ฆ
        if (jwtUtil.validateToken(token)) {

            // JWT Token ์—์„œ ์‚ฌ์šฉ์ž์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
            claims = jwtUtil.getUserInfoFromToken(token);

        } else {
            throw new IllegalArgumentException("Token Error");
        }

        // 2-2. User ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        User user = userRepository.findByUsername(claims.getSubject()).orElseThrow(
                () -> new IllegalArgumentException("This account does not exist")
        );

        // 2-3. Post ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        Post updatePost = postRepository.findById(postId).orElseThrow(
                () -> new IllegalArgumentException("The Post does not exist")
        );

        // 2-4. ํšŒ์›์†Œ์œ  ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        if (! updatePost.getUser().getUsername().equals(user.getUsername())) {
            throw new IllegalArgumentException("You are not authorized to update this post");
        }

        // 2-5. Post ์ˆ˜์ •
        updatePost.update(postRequestDto);

       // 2-6. update ๋œ Post ๋ฐ˜ํ™˜
       return PostResponseDto.of(updatePost);

    } else {

        return null;

    }

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

9 ๊ฒŒ์‹œ๊ธ€์‚ญ์ œ JWT์ธ๊ฐ€์„ค๊ณ„

1๏ธโƒฃ PostController.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// Post ์‚ญ์ œ
@DeleteMapping("/post/{post-id}")
public ResponseEntity<StatusMessageResponseDto> deletePost(@PathVariable(name="post-id") Long postId,
                                                           HttpServletRequest httpServletRequest) {

    return postService.deletePost(postId, httpServletRequest);

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

2๏ธโƒฃ PostService.java

/* ์•ž๋ถ€๋ถ„ ์ƒ๋žต */

// Post ์‚ญ์ œ
@Transactional
public ResponseEntity<StatusMessageResponseDto> deletePost(Long postId,
                                                           HttpServletRequest httpServletRequest) {

    // 1. HTTP Request Header -> JWT Token ๊ฐ€์ ธ์˜ค๊ธฐ
    String token = jwtUtil.getToken(httpServletRequest);
    Claims claims;

    // 2. JWT Token ์œ ํšจ -> Post ์ˆ˜์ • ๊ฐ€๋Šฅ
    if (token != null) {

        // 2-1. JWT Token ๊ฒ€์ฆ
        if (jwtUtil.validateToken(token)) {

            // JWT Token ์—์„œ ์‚ฌ์šฉ์ž์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ
            claims = jwtUtil.getUserInfoFromToken(token);

        } else {
            throw new IllegalArgumentException("Token Error");
        }

        // 2-2. User ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        User user = userRepository.findByUsername(claims.getSubject()).orElseThrow(
                () -> new IllegalArgumentException("This account does not exist")
        );

        // 2-3. Post ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        Post deletePost = postRepository.findById(postId).orElseThrow(
                () -> new IllegalArgumentException("The Post does not exist")
        );

        // 2-4. ํšŒ์›์†Œ์œ  ์œ ํšจ์„ฑ๊ฒ€์‚ฌ
        if (!deletePost.getUser().getUsername().equals(user.getUsername())) {
            throw new IllegalArgumentException("You are not authorized to delete this post");
        }

        // 2-5. Post ์‚ญ์ œ
        postRepository.delete(deletePost);

        // 2-6. Post์‚ญ์ œ ์„ฑ๊ณต ์‹œ, Client๋กœ ์„ฑ๊ณต๋ฉ”์‹œ์ง€ + ์ƒํƒœ์ฝ”๋“œ ๋ฐ˜ํ™˜
        return ResponseEntity.ok(StatusMessageResponseDto.of(200, "Your Post has been deleted successfully"));

    } else {

        return null;

    }

}

/* ๋’ท๋ถ€๋ถ„ ์ƒ๋žต */

10 Postman ํ™•์ธ

1๏ธโƒฃ signup(ํšŒ์›๊ฐ€์ž…)

2๏ธโƒฃ login(๋กœ๊ทธ์ธ)

3๏ธโƒฃ createPost(๊ฒŒ์‹œ๊ธ€์ž‘์„ฑ)

4๏ธโƒฃ getPosts(์ „์ฒด๊ฒŒ์‹œ๊ธ€๋ชฉ๋ก์กฐํšŒ)

5๏ธโƒฃ getSelectedPost(์„ ํƒ๊ฒŒ์‹œ๊ธ€์กฐํšŒ)

6๏ธโƒฃ updatePost(์„ ํƒ๊ฒŒ์‹œ๊ธ€์ˆ˜์ •)

7๏ธโƒฃ deletePost(์„ ํƒ๊ฒŒ์‹œ๊ธ€์‚ญ์ œ)

profile
๐ŸฑSunyeon-Jeong, mallang developer๐Ÿฐ

0๊ฐœ์˜ ๋Œ“๊ธ€