분류 전체보기

태그 달린 클래스보다는 클래스 계층구조를 활용하라 - [4장. 클래스와 인터페이스(아이템23)]
1. 태그 달린 클래스 🎧 태그 달린 클래스란 두 가지 이상의 의미를 표현할 수 있으며, 그중 현재 표현하는 의미를 태그 값으로 알려주는 클래스를 말한다. 아래 코드는 원과 사각형을 표현할 수 있는 태그 달린 클래스이다. public class Figure { enum Shape {RECTANGLE, CIRCLE}; // 태그 필드 - 현재 모양을 나타낸다. final Shape shape; // 다음 필드들은 모양이 사각형(RECTANGLE)일 때만 쓰인다. double length; double width; // 다음 필드는 모양이 원(CIRCLE)일 때만 쓰인다. double radius; // 원용 생성자 Figure2(double radius){ shape = Shape.CIRCLE; this...

인터페이스는 타입을 정의하는 용도로만 사용하라 - [4장. 클래스와 인터페이스(아이템22)]
1. 인터페이스의 역할 🐣 인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다. 클래스가 어떤 인터페이스를 구현한다는 것은 자신의 인스턴스로 무엇을 할 수 있는지를 클라이언트에 얘기해 주는 것이다. 인터페이스는 오직 이 용도로만 사용해야 한다. (밑에서 살펴볼 것이지만 상수 공개용 수단으로 사용하지 말아야 한다.) 2. 상수 인터페이스 안티패턴 🐥 위에서 말한 인터페이스의 역할에 맞지 않는 예로 상수 인터페이스라는 것이 있다. 상수 인터페이스란 메서드 없이, 상수를 뜻하는 static final 필드로만 가득 찬 인터페이스를 말한다. public interface PhysicalConstants { // 아보가드로 수 (1/몰) static final double AVOGAD..

인터페이스는 구현하는 쪽을 생각해 설계하라 - [4장. 클래스와 인터페이스(아이템21)]
1. 개념 👻 디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다. 기존 인터페이스에 메서드를 추가하는 길이 열렸지만 모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없다. 자바 7까지의 세상에서는 모든 클래스가 "현재의 인터페이스에 새로운 메서드가 추가될 일은 영원히 없다"라고 가정하고 장성됐으니 말이다. 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작성 '삽입'될 뿐이다. 이번 글에서는 이런 경우 발생할 수 있는 문제 상황들을 살펴보고 그에 대한 해결책을 알아보자. 2. [문제 상황 1] 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어렵다. 🤖 자바 8의 Collcti..

추상 클래스보다는 인터페이스를 우선하라(추상 골격 구현(Skeletal Implementation) 클래스)(2) - [4장. 클래스와 인터페이스(아이템20)]
이전 글을 통해 인터페이스의 장점들을 알아보았다. 이번 글에서는 인터페이스와 골격 구현(skeletal implementation) 클래스를 함께 제공하여 인터페이스와 추상 클래스의 장점을 모두 취하는 방법을 알아보자. 인터페이스와 추상 클래스를 같이 사용했을 때의 장점은 '인터페이스에서 구현해 줄 수 있는 것들은 디폴트 메서드로 구현하고, 구현해 줄 수 없는 것들은 추상 골격 클래스에서 나머지 메서드를 구현한다.'는 것이다. 추상 골격 구현 클래스를 활용하였을 때 얻을 수 있는 2가지의 장점에 대해서 자세히 알아보자. (명칭과 관련하여, 추상 골격 클래스라고 부르는 이유는 일부만 구현하고 일부는 구현하지 않아도 되기 때문이다. 인터페이스가 뼈대 역할을 한다고 생각하면 쉬울 거 같다.) 장점 1. 단순히..

추상 클래스보다는 인터페이스를 우선하라(인터페이스의 장점)(1) - [4장. 클래스와 인터페이스(아이템20)]
자바가 제공하는 다중 구현 메커니즘은 '인터페이스와 추상 클래스' 2가지가 있다. 자바 8부터 인터페이스도 Default Method를 제공할 수 있기 때문에 두 메커니즘 모두 인스턴스 메서드를 구현 형태로 제공할 수 있다. 둘의 가장 큰 차이는 추상 클래스가 정의한 타입을 구현하는 클래스는 반드시 추상 클래스의 하위 클래스가 되어야 한다는 점이다. 자바는 단일 상속만 지원하니, 추상 클래스 방식은 새로운 타입을 정의하는 데 커다란 제약을 안게 되는 것이다. 반면 인터페이스가 선언한 메서드를 모두 정의하고 그 일반 규약을 잘 지킨 클래스라면 다른 어떤 클래스를 상속했든 같은 타입으로 취급된다. 여기까지가 추상클래스와 인터페이스에 대한 간단한 설명이다. 이번 글에서 인터페이스의 5가지 장점들을 살펴보면서 ..

[Spring] 검증(Validation) - Validator
1. Validator 🍩 이전까지 검증 기능들은 컨트롤러 안에 있었다. 당연히 이런 경우에는 별도의 클래스를 만들어서 역할을 분리하는 것이 좋다. 기존 코드를 먼저 살펴보고, ItemValidator라는 클래스를 만들어서 어떻게 별도의 클래스로 검증 기능을 분리하였는지 알아보자. // 기존 코드 @Slf4j @Controller @RequiredArgsConstructor public class ValidationController3 { private final ItemRepository itemRepository; @PostMapping("/add") public String addItem(@ModelAttribute Item item, BindingResult bindingResult, Redire..

[Spring] 검증(Validation) - bindingResult.rejectValue(), binding.reject()
이번 글을 통해 이전 글에서 BindingResult, FieldError, ObjectError를 통해 만들어보았던 검증 기능을 조금 더 쉽게 만들어보고자 한다. 1. rejectValue() & reject() 🍣 FieldError와 ObjectError는 너무 복잡하다. BindingResult의 rejectValue와 reject를 사용하면 조금 더 간결하게 검증을 진행할 수 있다. 이전 글에서 BindingResult는 항상 검증해야 할 객체 바로 뒤에 이어서 작성해야 한다고 말한 적이 있다. 이는 BindingResult가 검증해야 할 객체를 이미 알고 있는 것이다. 이 정보를 바탕으로 아래 내용들을 계속해서 살펴보자. rejectValue와 reject의 생성자는 다음과 같다. void r..

[Spring] 검증(Validation) - BindingResult, FieldError, ObjectError
이번 글을 통해 BindingResult를 활용한 검증(Validation)을 알아보고자 한다. 글의 순서는 서버에서 검증이 필요한 이유 왜 서버에서 검증을 추가적으로 해야 하는가? BindingResult BindingResult를 활용하여 검증을 수행하는 방법 사용자의 입력 값 유지 방법 바인딩을 하지 못한 상황에서도 사용자의 입력 값을 저장하는 방법 으로 진행하겠다. 1. 서버에서 검증이 필요한 이유 🧲 컨트롤러의 중요한 역할 중 하나는 HTTP 요청이 정상인지 검증하는 것이다. 그러나 클라이언트에서 검증을 하고 서버에서는 검증된 값을 그냥 쓰면 되는 거 아닌가라고 생각할 수 있다. 하지만 아래와 같은 이유로 인해서 서버에서도 검증을 수행해야 한다. 클라이언트 검증은 조작할 수 있으므로 보안에 취약..

스프링 인터셉터(Spring Interceptor)
서블릿 필터와 같이 스프링 인터셉터(Spring Interceptor) 또한 웹과 관련된 공통 관심 사항을 효과적으로 해결할 수 있는 기술이다. 이번 글을 통해 '스프링 인터셉터의 개념'을 알아보고, '요청 로그 예제'와 '인증 체크 예제'를 통해서 사용 방법을 알아보도록 하자. 1. 개념 🌠 📘 1. 스프링 인터셉터 흐름 스프링 인터셉터는 기본적으로 다음과 같은 흐름을 가진다. HTTP 요청 → WAS → 필터 → 서블릿(Dispatcher Servlet) → 스프링 인터셉터 → 컨트롤러 스프링 인터셉터는 디스패처 서블릿과 컨트롤러 사이에서 컨트롤러 호출 직전에 호출된다. 📘 2. 스프링 인터셉터 제한 서블릿 필터와 같이 로그인하지 않은 사용자의 접근과 같은 '적절하지 않은 요청'에 대하여 판단하고 거..

서블릿 필터(Servlet Filter)
이번 글에서는 서블릿 필터(Servlet Filter)의 개념에 대해서 알아보고, '요청 로그 예제'와 '인증 체크 예제'를 통해서 어떻게 필터를 사용하는지 알아보고자 한다. 1. 개념 🌌 📘 1. 필터 흐름 필터는 기본적으로 다음과 같은 흐름을 가진다. HTTP 요청 → WAS → 필터 → 서블릿(Dispatcher Servlet) → 컨트롤러 필터를 적용하면 필터가 호출되고 그리고 서블릿이 호출된다. 즉, 서블릿이 호출되기 전에 필터가 호출되는 것이다. 그렇게 때문에 모든 고객의 요청 로그를 남기거나 인증 체크(로그인 여부 등)등의 행위를 필터를 이용해서 할 수 있다. 📘 2. 필터 제한 필터에서는 로그인하지 않은 사용자의 접근과 같이 적절하지 않은 요청에 대하여 판단하고 거기에서 끝을 낼 수 있다...

쿠키와 보안 문제
이번 글을 통해 '쿠키를 사용했을 때 발생할 수 있는 보안 문제'와 '세션을 이용한 해결책'을 알아보려고 한다. 혹시나 쿠키(Cookie)와 세션(Session)에 대한 기본 지식이 필요하다면 아래의 글을 먼저 참고하기를 바란다. 쿠키(Cookie) 기본 지식 세션(Session) 기본 지식 1. 쿠키를 사용했을 때 발생할 수 있는 보안 문제 🕌 쿠키를 이용해서 로그인 기능을 아래와 같이 만들었다고 생각해 보자. 쿠키의 값으로 사용자를 구별할 수 있는 ID값(= memberId, 예를 들어 DB에 저장된 인덱스 값이 될 수 있음)이 전달되게 된다. 🔎 로그인 🔎 로그인 후 접근 위와 같이 동작한다고 하면 3가지 보안 문제가 발생할 수 있다. 📕 문제 1. 임의로 쿠키 값을 변경하는 문제 클라이언트가 쿠키..

상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 - [4장. 클래스와 인터페이스(아이템19)]
상속을 고려해 설계하고 문서화하는 방법들을 알아보자. 1. 상속용 클래스는 재정의할 수 있는 메서드들을 내부적으로 어떻게 이용하는지(자기 사용) 문서로 남겨야 한다. 🛺 재정의 가능 메서드를 호출할 수 있는 모든 상황을 문서로 남겨야 한다. 유명한 격언 중 하나인 "좋은 API 문서란 '어떻게'가 아닌 '무엇'을 하는지를 설명해야 한다"와 대치되는 내용이기도 하다. 하지만 상속이 캡슐화를 해치기 때문에 클래스를 안전하게 상속할 수 있도록 하려면 '상속만 아니었다면 기술하지 않았어야 할' 내부 구현 방식을 설명해야 한다. AbstractCollection.java의 remove 메서드를 살펴보자. 위와 같이 API 문서의 메서드 설명 끝에 "Implementation Requirements"가 붙은 걸 볼..