여러 모듈로 구성된 스프링 프레임워크
Core
: 스프링의 핵심 기술 (DI 컨테이너, AOP, 이벤트, 검증, ...)Web
: 웹 어플리케이션 개발과 관련된 기술을 제공(Spring Web MVC)Data Access
: 데이터 접근과 관련된 기술을 제공 (트랜잭션, JDBC, ORM, XML, ...)Integration
: 스프링과 통합될 수 있는 기술들 (REST client, ...)Test
: 스프링기반유닛테스트,통합테스트를지원Language
: 자바 뿐만 아니라 JVM 기반인 코틀린, 그루비 언어도 지원Model
View
Controller
MVC + Service + Repository
Service
: 핵심 비즈니스 로직을 수행Repository
: 데이터베이스에 있는 데이터에 접근Dispatcher Servlet
: 가장 앞에서 사용자의 모든 요청을 받아 처리함Handler Mapping
: 요청 URL에 매핑된 핸들러를 찾음Handler Adapter
: 핸들러 매핑에서 찾은 핸들러를 실행Controller
: 서비스의 비즈니스 로직을 호출한 후 모델에 필요한 데이터를 담고, 사용자에게 응답할 뷰의 정보를 리턴Service & Repository
: 비즈니스 로직을 수행하며 데이터를 가져오고 저장View Resolver
: 사용자에게 응답할 뷰를 찾음View
: 모델에서 데이터를 꺼내 화면을 렌더링✚ Handler?
- Controller를 포함하는 개념
- Handler Adapter는 Handler와 Dispatcher Servlet 간의 데이터 형식 통일이 필요할 때 사용자 요청 정보를 핸들러의 파라미터 형식에 맞게 변환하여 사용자 요청 정보를 핸들러의 파라미터 형식에 맞게 변환하는 역할을 함.
@ResponseBody
또는 @ResponseEntity
리턴HTTP Message Converter
에서 수행✚ HTTP Message Converter?
- HTTP 메시지 body를 읽고 쓰는 역할
- Handler 파라미터로 HTTP request 메시지 body가 필요한 경우 (
@RequestBody
,@RequestEntity
사용)
: Argument Resolver → Message Converter 호출- Hanlder 리턴값을 HTTP response 메시지 body로 써야 하는 경우 (
@ResponseBody
,@ResponseEntity
사용)
: ReturnValueHandler → Message Converter 호출
기본적인 작성 방법
@Controller
@RequireArgsConstructor
public class ExampleController {
private final ExampleService exampleService;
@GetMapping("/examples)
@ResponseBody
public List<Example> listExamples() {
return exampleService.getAllExamples();
}
}
기본적인 작성 방법
@Service
public class ExampleService {
@Autowired
private ExampleRepository exampleRepository;
public List<Example> getAllExamples() {
return exampleRepository.findAll();
}
}
DB 데이터에 접근하는 로직을 담고 있는 객체
@Repository
사용@Repository
public class ExampleRepository {
@PersistenceContext
private EntityManager entityManager;
public Example save(Example example) {
entityManager.persist(example);
return example;
}
public Example findById(Long id) {
return entityManager.find(Example.class, id);
}
}
JpaRepository
인터페이스를 구현public interface ExampleRepository extends JpaRepository<Product, Long> {}
데이터베이스 테이블과 매핑되는 객체
도메인 모델을 나타냄
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "examples")
public class Example {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
private String description;
}
계층 간 데이터 전달을 위해 사용되는 객체
전달할 데이터와 getter/setter 메소드만 가짐
@NoArgsConstructor
@AllArgsConstrunctor
public class ExampleDTO {
private Long id;
private String name;
private String description;
}
값을 표현하는 객체 ➡️ 불변으로 구현(@Setter
사용 X, 필드값으로 비교)
로직을 포함하기도 함
equals()
, hashode()
오버라이딩 필수
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ExampleVO {
private Long id;
private String name;
private String description;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceOf ExampleVO)) return false;
ExampleVO example = (ExampleVO) o;
return Objects.equals(id, example.id) &&
Objects.equals(name, example.name) &&
Objects.equals(description, example.description);
}
@Override
public int hashCode() {
return Objects.hash(id, name, description);
}
}
✚ hashCode?
해시 알고리즘에 의해 생성된 정수 값
해시코드 규약
- equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 그 객체의 hashCode 메소드는 몇 번을 호출해도 일관되게 항상 같은 값을 반환해야 함
- equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야 함
- equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode가 서로 다른 값을 반환할 필요는 없음. 하지만 다른 객체에 대해서는 다른 값을 반환해야 해시테이블의 성능이 좋아짐.