1. 제네릭(Generic)
제네릭(Generic)은 타입을 미리 고정하지 않고 다양한 타입을 처리할 수 있는 코드를 작성하는 방식입니다. 제네릭을 사용하면, 클래스나 메소드를 정의할 때 타입을 구체적으로 지정하지 않고, 나중에 사용할 때 개발자가 원하는 타입을 결정할 수 있게 됩니다. 이는 코드의 재사용성을 높이고, 타입 안전성을 보장하는 중요한 개념입니다.
제네릭은 무엇인가?
제네릭은 타입에 의존하지 않는 코드를 작성하는 방법입니다. 예를 들어, 어떤 클래스나 메소드가
Integer
, String
, Double
등 여러 타입에 대해 동일한 동작을 수행해야 할 때, 제네릭을 사용하면 하나의 코드로 모든 타입을 처리할 수 있습니다. 이렇게 하면 코드를 여러 번 중복해서 작성할 필요가 없으며, 잘못된 타입을 사용하는 실수를 줄일 수 있습니다.제네릭의 기본 구조
제네릭은 보통 타입 파라미터를 사용해 정의됩니다. 이 타입 파라미터는 클래스나 메소드 정의에서 사용되며, 그 타입은 나중에 개발자가 이 클래스를 사용할 때 결정됩니다.
이 코드를 통해 제네릭(Generic)의 동작 방식과 개발자가 타입을 결정하는 방법에 대해 설명드리겠습니다.
코드 분석
1. Box<T>
클래스
class Box<T> {
T data;
}
Box<T>
는 제네릭 클래스로, T
라는 타입 파라미터를 사용하여 data
라는 필드를 선언합니다. 이 T
는 타입이 아직 결정되지 않았으며, 클래스를 사용할 때 개발자가 타입을 지정하게 됩니다. 즉, Box<T>
는 어떤 타입이든 처리할 수 있는 유연한 클래스입니다.2. test
메소드
public static <B> Box<?> test(B data) {
Box<B> b = new Box();
b.data = data;
return b;
}
- 이 메소드는 제네릭 메소드로,
<B>
라는 제네릭 타입 파라미터를 선언했습니다. 이는 메소드를 호출할 때B
가 어떤 타입인지를 개발자가 결정하게 됩니다.
test
메소드는Box<B>
라는 제네릭 객체를 생성하고,B
타입의 데이터를 받아서Box<B>
의data
필드에 저장한 후,Box<?>
타입으로 반환합니다.
- *
Box<?>
*는 와일드카드(?
)로, 반환되는Box
의 구체적인 타입이 무엇인지 명시하지 않고, 어떤 타입이든 받아들일 수 있음을 의미합니다. 즉, 이 메소드는 어떤 타입의 데이터를 담는Box
라도 반환할 수 있지만, 반환된 후 그 안에 들어간 타입이 무엇인지 모른다는 의미입니다.
3. main
메소드
public static void main(String[] args) {
Box b = test(1);
여기서
main
메소드에서 test
메소드를 호출하고 있습니다.test(1)
은1
이라는int
값을 전달하므로, 컴파일러는B
를Integer
로 결정합니다. 즉,B
는Integer
타입이 되고,Box<Integer>
가 생성됩니다.
- 하지만
test
메소드는 **Box<?>
*를 반환하기 때문에, 반환된 값은 타입 정보가 사라진 상태로 다루어집니다. 즉, 반환된Box
가Box<Integer>
라는 타입 정보를 가지고 있지만,<?>
로 인해 그 타입이 명시되지 않습니다.
제네릭과 개발자의 역할
이 코드에서 개발자가 타입을 결정하는 과정을 다시 설명하겠습니다.
Box<T>
클래스는 제네릭 타입T
를 사용합니다. 하지만 이때T
는 아직 구체적인 타입이 결정되지 않았습니다. 개발자가 이 클래스를 사용할 때 타입을 결정하게 됩니다.
test
메소드에서는 제네릭 타입B
를 사용합니다. 이B
역시 호출 시점에 결정됩니다.test(1)
이라고 호출했을 때, 컴파일러는B
를Integer
로 추론합니다. 즉, 개발자가 호출할 때 전달하는 값의 타입에 따라B
가 결정됩니다.
- *와일드카드
Box<?>
*는 반환될 때 타입을 제한하지 않기 때문에, 반환된Box
의 타입을 정확히 알 수 없게 됩니다. 이는 제네릭에서 타입 정보를 숨기기 위한 방식 중 하나입니다. 즉, 개발자는 타입을 결정할 수 있지만, 특정 상황에서는 그 타입을 숨기거나 모호하게 처리할 수 있습니다.
중요한 개념들
1. 제네릭 타입 파라미터 <T>
, <B>
제네릭 클래스나 메소드에서
T
나 B
와 같은 타입 파라미터는 코드 작성 시점에 구체적인 타입을 명시하지 않고 유연하게 처리할 수 있도록 합니다. 이 타입 파라미터는 클래스나 메소드가 호출될 때 결정됩니다.2. 와일드카드 <?>
와일드카드
<?>
는 모든 타입을 수용할 수 있지만, 구체적인 타입을 알 수 없게 만듭니다. 이 경우에는 해당 타입의 값을 읽을 수는 있지만, 추가적인 타입 체크나 타입 캐스팅을 해야 할 수 있습니다.
Box<?> b = test(1); // 와일드카드를 사용하여 반환된 타입을 명시하지 않음
위 코드에서는 반환된
Box
의 내부 타입이 무엇인지 모르는 상태로 다루기 때문에, Box<Integer>
라고 명시적으로 선언하지 않은 상태에서 타입 정보를 숨긴 셈입니다.3. 개발자의 타입 결정권
이 코드에서 중요한 점은 개발자가
test
메소드를 호출할 때 전달하는 값에 따라 제네릭 타입이 결정된다는 것입니다. test(1)
을 호출하면 B
가 Integer
로 결정되고, test("Hello")
를 호출하면 B
가 String
으로 결정됩니다. 제네릭 코드는 동일하지만, 구체적인 타입은 개발자가 사용하는 상황에 맞게 결정됩니다.결론
이 코드는 제네릭을 사용해 타입을 일반화하는 예시입니다. 제네릭을 사용하면 코드가 타입에 종속되지 않으며, 개발자가 사용하는 시점에서 타입을 결정할 수 있게 됩니다. 또한, 와일드카드(
<?>
)를 통해 타입을 유연하게 다루면서도, 반환된 타입의 정보를 숨기거나 제약을 걸 수 있습니다. 이로 인해 유연성과 타입 안전성을 동시에 유지할 수 있게 되는 것이 제네릭의 장점입니다.2. 아작스(Ajax)
Ajax(Asynchronous JavaScript and XML)는 웹 개발에서 비동기적인 통신을 가능하게 하는 기술입니다. Ajax를 사용하면 페이지를 새로 고침하지 않고 웹 서버와 데이터를 주고받을 수 있습니다. 이로 인해 사용자 경험이 더 향상되며, 빠르고 동적인 웹 페이지를 만들 수 있게 됩니다.
Ajax의 핵심 개념
- Asynchronous (비동기적): Ajax 요청은 웹 페이지를 다시 로드하지 않고 서버와 통신합니다. 즉, 페이지의 특정 부분만 서버와 통신하여 변경할 수 있습니다. 이로 인해 사용자 인터페이스가 중단되지 않고 더 빠르고 매끄럽게 동작합니다.
- JavaScript: Ajax는 JavaScript를 기반으로 동작합니다. JavaScript를 사용하여 HTTP 요청을 보내고, 서버로부터 받은 데이터를 처리합니다.
- XML/JSON: 처음에는 XML 형식을 많이 사용했으나, JSON(JavaScript Object Notation)이 더 가볍고 처리하기 쉬워서 현재는 주로 JSON을 사용합니다.
Ajax의 동작 방식
Ajax는 웹 페이지가 서버와 비동기적으로 데이터를 주고받을 수 있도록 합니다. 이 과정을 단계별로 설명하면 다음과 같습니다.
- 사용자의 요청: 사용자가 페이지에서 특정 동작(버튼 클릭 등)을 수행하면, JavaScript가 Ajax 요청을 생성합니다.
- Ajax 요청 생성: JavaScript는
XMLHttpRequest
객체 또는fetch
API를 사용하여 서버에 HTTP 요청을 보냅니다. 이 요청은 동기적이거나 비동기적으로 처리할 수 있지만, 보통 비동기적으로 사용됩니다.
- 서버 처리: 서버는 클라이언트로부터 요청을 받아 필요한 처리를 한 후, 결과 데이터를 클라이언트로 응답합니다. 이 데이터는 주로 JSON이나 XML 형식입니다.
- 응답 처리: JavaScript는 서버로부터 받은 데이터를 처리하고, 웹 페이지의 일부를 업데이트하거나 사용자에게 결과를 보여줍니다.
- 페이지 재로딩 없음: 전체 페이지를 새로고침하지 않고, 필요한 부분만 변경됩니다.
간단한 Ajax 예시 (JavaScript)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ajax Example</title>
</head>
<body>
<h1>Ajax Example</h1>
<button id="loadDataBtn">Load Data</button>
<div id="result"></div>
<script>
document.getElementById("loadDataBtn").addEventListener("click", function() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "<https://jsonplaceholder.typicode.com/posts/1>", true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
document.getElementById("result").innerHTML = xhr.responseText;
}
};
xhr.send();
});
</script>
</body>
</html>
설명
XMLHttpRequest
객체: Ajax 요청을 보내기 위한 객체입니다. 이 객체를 사용하여 비동기적으로 서버에 데이터를 요청하고, 그 결과를 처리합니다.
- GET 요청: 이 예시에서는 외부 API에서 데이터를 받아옵니다. 서버에서 데이터를 가져와
#result
라는div
태그에 결과를 표시합니다.
- 비동기 요청:
xhr.open("GET", "URL", true)
에서 마지막true
는 비동기적으로 요청을 보내겠다는 의미입니다.
fetch
API를 사용한 Ajax (ES6+)
최근에는
fetch
API가 도입되어 Ajax 요청을 더 간단하고 직관적으로 처리할 수 있습니다. fetch
는 Promise
를 기반으로 하여 더 깔끔한 비동기 처리가 가능합니다.document.getElementById("loadDataBtn").addEventListener("click", function() {
fetch("<https://jsonplaceholder.typicode.com/posts/1>")
.then(response => response.json())
.then(data => {
document.getElementById("result").innerHTML = JSON.stringify(data);
})
.catch(error => console.error('Error:', error));
});
설명
fetch
API는 HTTP 요청을 쉽게 보낼 수 있게 해주는 최신 JavaScript API입니다.XMLHttpRequest
보다 가독성이 좋고, 비동기 처리를 더 간편하게 할 수 있습니다.
- *
then()
*과catch()
:fetch
는 비동기적으로 데이터를 처리하고, 응답이 성공하면then()
으로 처리하고, 오류가 발생하면catch()
로 처리합니다.
Ajax의 장점
- 빠른 데이터 전송: 페이지 전체를 새로 고침하지 않고 필요한 데이터만 서버로부터 받아오기 때문에 응답 속도가 빠릅니다.
- 향상된 사용자 경험: 페이지가 중단 없이 동작하므로, 더 매끄럽고 반응성 좋은 UI/UX를 제공합니다.
- 서버 부하 감소: 페이지 전체를 다시 로드하지 않기 때문에 불필요한 서버 요청이 줄어듭니다.
Ajax의 단점
- SEO 문제: Ajax로 로딩된 콘텐츠는 초기 HTML에 포함되지 않기 때문에, 검색 엔진에서 인덱싱이 어려울 수 있습니다.
- 브라우저 호환성: 최신 브라우저에서는 대부분 지원되지만, 매우 구버전 브라우저에서는 제대로 작동하지 않을 수 있습니다.
- 복잡한 디버깅: 비동기 요청과 콜백 함수로 인해 디버깅이 복잡할 수 있습니다.
Ajax의 사용 사례
- 실시간 검색: 검색창에 입력할 때마다 결과를 서버에서 비동기적으로 가져오는 기능.
- 무한 스크롤: 스크롤할 때마다 서버에서 데이터를 받아와서 페이지에 추가하는 기능.
- 양방향 채팅: 페이지를 새로 고침하지 않고 서버와 주고받는 실시간 메시지 서비스.
Ajax는 현대 웹 개발에서 동적이고 빠른 웹 페이지를 만들기 위한 핵심 기술로, 전체 페이지가 아닌 필요한 데이터만 서버와 주고받아 사용자 경험을 크게 개선할 수 있는 도구입니다.
3. 아작스 오류
- 아작스 요청이 잘못 됐을때 이걸 사용한다.

GlobalApiExceptionHandler
코드 설명
public ResponseEntity<?> ex400(Exception e) {
//프론트앤드 개발자가 알기 쉽게 해주기 위해(배려)
return new ResponseEntity<>(Resp.fail(400, e.getMessage()), HttpStatus.BAD_REQUEST);
}
ResponseEntity<?>
: Spring의ResponseEntity
는 HTTP 응답을 표현하는 객체입니다. 이 객체는 응답 본문(body), 상태 코드(status), 헤더(headers)를 설정할 수 있습니다.<?>
: 제네릭으로 사용되었으며, 반환하는 데이터 타입에 제한을 두지 않겠다는 의미입니다. 즉, 어떤 타입의 응답이든 보낼 수 있습니다.
ex400(Exception e)
: 이 메소드는Exception
객체를 매개변수로 받아 처리합니다.e
는 발생한 예외에 대한 정보를 담고 있으며, 예외의 메시지(e.getMessage()
)를 통해 오류 내용을 확인할 수 있습니다.
new ResponseEntity<>(...)
:ResponseEntity
객체를 생성하여 반환합니다. 여기서 반환하는 내용은 클라이언트로 전송될 HTTP 응답입니다.Resp.fail(400, e.getMessage())
:Resp.fail()
메소드를 호출하여 응답 본문(body)를 생성합니다.400
: HTTP 상태 코드 **400 (Bad Request)**를 나타냅니다. 이는 클라이언트의 잘못된 요청을 의미합니다.e.getMessage()
: 예외의 상세 메시지를 가져와서 응답 본문에 포함시킵니다. 이 메시지는 예외 발생 원인에 대한 설명입니다.HttpStatus.BAD_REQUEST
: 응답의 HTTP 상태 코드를 설정합니다. 여기서는400 Bad Request
상태 코드를 나타냅니다. 이는 클라이언트의 요청이 잘못되었을 때 반환하는 코드입니다.
요약:
이 메소드는 클라이언트가 잘못된 요청을 보냈을 때(예: 유효성 검사 실패) 이를 처리하여, HTTP 400 상태 코드와 함께 예외 메시지를 포함한 응답을 반환합니다. 이때 프론트엔드 개발자가 쉽게 이해할 수 있도록 상태 코드와 메시지를 명확하게 제공합니다.
Share article