새롭게 들어가는 ‘빌릴게’ 프로젝트에서 혼자 백엔드를 맡게 되어 ‘이참에 Kotlin으로 플젝을 진행해보자!’라는 생각으로 Kotlin + Spring 조합으로 스택을 구성했다.
Kotlin은 자바처럼 JVM 위에서 동작하는 언어지만, 자바보다 간결하고 쓸데없이 적어야하는 코드가 적다!
그리고, 언어 자체에 안정성이 높아서 null 가능성 체크를 통해 NullPointerException을 미리미리 방지할 수 있다고 한다..!
실제로 작성한 자바 코드와 코틀린 코드를 아래처럼 비교했을 때 더 읽기 편한 코드는 누가 봐도 코틀린이다.
(아닌가..?)
package cokothon.backend.global.jwt;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Arrays;
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {
private final TokenProvider tokenProvider;
private final static String HEADER_AUTHORIZATION = "Authorization";
private final static String BEARER_AUTH = "Bearer ";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authorizationHeader = request.getHeader(HEADER_AUTHORIZATION);
String accessToken = getAccessToken(authorizationHeader);
if (tokenProvider.validToken(accessToken)) {
Authentication authentication = tokenProvider.getAuthentication(accessToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String getAccessToken(String authorizationHeader) {
if (authorizationHeader != null && authorizationHeader.startsWith(BEARER_AUTH)) {
return authorizationHeader.substring(BEARER_AUTH.length());
}
return null;
}
}
package site.billilge.api.backend.global.security.jwt
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.web.filter.OncePerRequestFilter
class TokenAuthenticationFilter(
private val tokenProvider: TokenProvider
): OncePerRequestFilter() {
override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
val authorizationHeader = request.getHeader(HEADER_AUTHORIZATION)
authorizationHeader?.let {
val accessToken = getAccessToken(authorizationHeader);
if (tokenProvider.validToken(accessToken)) {
SecurityContextHolder.getContext().authentication = tokenProvider.getAuthentication(accessToken)
}
}
}
private fun getAccessToken(authorizationHeader: String): String {
if (authorizationHeader.startsWith(BEARER_AUTH)) {
return authorizationHeader.substring(BEARER_AUTH.length)
}
//TODO: exception handling 만들기
throw Exception()
}
companion object {
const val HEADER_AUTHORIZATION: String = "Authorization"
const val BEARER_AUTH: String = "Bearer "
}
}
또한, @RequiredArgsConstructor같은 Lombok 어노테이션 사용이 줄어든다. 자바에서는 boilerplate한 코드를 줄이기 위해 Lombok 라이브러리의 Getter, Setter 같은 어노테이션을 많이 사용했었는데, 코틀린은 getter, setter 함수를 따로 만들 필요 없이 호출이 가능해서 너무 좋은 것 같다.
코틀린 짱