Group Study (2022-2023)/Spring 입문

3주차 레퍼런스

민휘 2023. 1. 12. 18:27

3주차 레퍼런스 문서와 멤버분들이 추가 공부한 내용을 스크랩했습니다.

✅ SSR, CSR

이번 챕터의 주제가 화면 구성인 만큼, 템플릿 엔진에 대해서 자세하게 다루었는데요. 우리가 웹 페이지를 위한 서버를 만들고 있기 때문에 템플릿 엔진이 필요합니다. (모바일 앱을 위한 서버라면 HTML을 내려주는 것이 의미가 없으므로 템플릿 엔진이 필요하지 않겠죠?)

서버 템플릿 엔진을 사용하면 SSR(Server Side Rendering) 방식을, 클라이언트 템플릿 엔진을 사용하면 CSR(Client Side Rendering) 방식을 채택하는 것입니다. 추가 실습에서 CSR을 위한 REST 컨트롤러를 만들어봤는데요, 여기서 반환하는 JSON 데이터들을 클라이언트가 받아서 미리 만들어둔 HTML과 조립해 사용자에게 제공합니다.

SSR과 CSR이 무엇이 다른지는 알겠는데, 각각 어떤 장단점이 있을까요? 어떠한 기준으로 HTML 파일을 내려줄 방식을 채택해야할까요? 또 웹 프론트에 관심 있으신 분들은 Next.js를 들어보셨을 것 같은데요, Next.js는 SSR과 CSR의 장점을 취하고 단점을 극복하기 위해 나온 프레임워크라고 합니다. Next.js의 전략이 무엇인지 살펴보시는 것도 재밌을 것 같아요.

SSR(서버사이드 렌더링)과 CSR(클라이언트 사이드 렌더링)

 

SSR(서버사이드 렌더링)과 CSR(클라이언트 사이드 렌더링)

MPA와 SPA, SSR과 CSR에 대한 포스트입니다. 목차 MPA vs SPA SSR 개념, 동작과정, 장단점 CSR 개념, 동작과정, 장단점 렌더링 방식 선택 기준 Universal Rendering MPA vs SPA 먼저 MPA, multi page application의 약자로 여

miracleground.tistory.com

👩‍💻 SSR vs CSR 비교 설명, Next.js가 탄생하게 된 이유

 

👩‍💻 SSR vs CSR 비교 설명, Next.js가 탄생하게 된 이유

SSR(Server Side Rendering) 👆 위의 그림은 전통적인 방식인 SSR…

www.sarah-note.com

✅ View Resolver

IndexController의 index() 메소드를 보면 코드는 단순히 문자열을 반환하고 있는데, 지정된 경로에 있는 문자열 이름의 파일을 찾아서 클라이언트에 반환해줍니다. 이 작업은 View Resolver가 해주는데요, 뷰 리졸버는 단순히 경로 찾기만 해주는 것이 아닙니다. 뷰 리졸버는 controller가 반환한 데이터 타입에 따라 결과를 지정해주는 역할을 합니다. 템플릿 엔진을 썼다면 고정된 경로에서 파일을 찾고, RestController에서 객체를 반환했다면 JSON 타입으로 내려줍니다. 스프링 프레임워크의 코드에서 뷰 리졸버는 인터페이스이고, 타입별로 구현된 구현체 클래스가 동적으로 선택되어 실행되겠죠? 무슨 말인지 이해가 가지 않으신다면 인터페이스 다형성에 대해 찾아보시면 좋을 것 같습니다.

[Spring] 뷰 리졸버(View Resolver) 개념 이해하기

 

[Spring] 뷰 리졸버(View Resolver) 개념 이해하기

스프링 백엔드에서 데이터를 처리하거나 가지고 왔다면, 이 데이터를 View의 영역으로 전달을 해야 한다. 이때 View를 어떤 것을 사용할지 자유롭게 설정을 할 수 있는데 이 설정 역할을 하는 것이

needneo.tistory.com

뷰가 무엇인지, 뷰에는 어떠한 종류가 있는지, 또 어떠한 종류의 뷰 리졸버의 구현체가 있는지 궁금하신 분들은 아래 링크를 한번 읽어보세요.

[spring] View, ViewResolver

 

[spring] View, ViewResolver

뷰는 모델이 가진 정보를 어떻게 표현해야 하는지에 대한 로직을 갖고 있는 컴포넌트이다. 일반적인 뷰의 결과물은 브라우저에서 볼 수 있는 HTML이다. 이 외에도 엑셀, PDF, RSS 등 다양한 결과를

joont92.github.io

✅ PRG 패턴

index.js 파일을 보면 등록 후 인덱스 페이지로 리다이렉트하는 코드를 볼 수 있습니다.

    save : function () {
        var data = {
            title: $('#title').val(),
            author: $('#author').val(),
            content: $('#content').val()
        };

        $.ajax({
            type: 'POST',
            url: '/api/v1/posts',
            dataType: 'json',
            contentType:'application/json; charset=utf-8',
            data: JSON.stringify(data)
        }).done(function() {
            alert('글이 등록되었습니다.');
            **window.location.href = '/';**
        }).fail(function (error) {
            alert(JSON.stringify(error));
        });
    }

왜 등록 후에 인덱스 페이지로 바로 리다이렉트하게 만든걸까요? 이는 게시글이 중복 등록되는 것을 방지하기 위함인데요. 네트워크 상황이 나빠서 유저가 게시글 등록 이후 새로고침을 여러번 한다고 생각해봅시다. 내용이 같은 게시글이 여러개 등록되겠죠? 만약 서비스가 게시글 등록이 아니라 결제라면, 여러번 결제가 되는 대참사가 벌어질 것입니다. 이런 상황을 막기 위해 Post 요청이 성공적으로 처리된 이후 바로 Get 요청을 합니다. 이러한 패턴을 PRG 패턴이라고 하는데요, 웹 개발에서 많이 사용되는 패턴이므로 아래 링크를 읽어보면서 어떤 느낌인지 파악해보세요.

 

✅ JPQL, QueryDSL

글의 전체 목록을 아이디 기준 내림차순으로 정렬하여 가져오는 쿼리를 다음과 같이 PostsRepository에서 정의하여 사용했습니다.

@Query("SELECT p FROM Posts p ORDER BY p.id DESC")
List<Posts> findAllDesc();

어라, 근데 우리가 알고 있는 SQL과 조금 다르지 않나요? 동일한 질의를 h2에 하려면 다음과 같은 쿼리를 실행해야 합니다.

SELECT * FROM POSTS ORDER BY ID DESC;

키워드는 동일한데, 형태가 조금 다릅니다. Posts p, p.id와 같은 코드를 보면 마치 객체를 선언하고 참조 연산자로 필드 값을 얻어오는 것 같지 않나요? 눈치채신 분들도 있을 것 같은데요, 쿼리 애노테이션의 값으로 사용한 쿼리문은 JPQL이라는 언어입니다. JPA가 제공하는 쿼리 언어로, 객체 지향 쿼리라고 불려요. Spring Data Jpa가 메소드 이름만으로 제공하는 쿼리에는 한계가 있기 때문에 @Query 애노테이션을 사용해서 JPQL을 실행합니다.

JPQL은 객체를 탐색하므로, 일반 SQL이 테이블을 대상으로 탐색한다는 점과 다릅니다. 또 SQL을 추상화했기 때문에 특정 벤더에 종속적이지 않아요. JPA는 JPQL을 분석하여 SQL을 따로 생성한 후 DB에 쿼리를 날립니다.

[JPA] JPQL(Java Persistence Query Language)이란?

 

[JPA] JPQL(Java Persistence Query Language)이란?

JPA는 복잡한 조건을 사용해서 엔티티 객체를 조회할 수 있는 다양한 쿼리 기술을 지원한다. 이번 글에서는 다양한 객체지향 쿼리 중 JPQL에 대해 알아보도록 하자. 참고 JPQL(Java Persistence Query Langua

dev-coco.tistory.com

그러나 JPQL을 문자열로 적는 것에는 여전히 한계가 있습니다. 프로젝트의 규모가 커지면, 데이터를 조회할 때 여러 테이블 조인하고, 여러 조건을 붙여 조회를 해야하는데요. 이런 복잡한 쿼리를 문자열로 작성하면 오타 나기도 쉽고 유지 보수가 너무 힘들겠죠. 그래서 조회용 프레임워크로 많이 사용하는 것이 QueryDSL입니다. 메소드를 기반으로 쿼리를 생성해주기 때문에, 오타나 유효하지 않은 컬럼명을 작성하면 IDE에서 검출이 가능합니다. 다음과 같이 사용할 수 있어요.

@Repository
public class AcademyRepositorySupport extends QuerydslRepositorySupport {
    private final JPAQueryFactory queryFactory;

    public AcademyRepositorySupport(JPAQueryFactory queryFactory) {
        super(Academy.class);
        this.queryFactory = queryFactory;
    }

    public List<Academy> findByName(String name) {
        return **queryFactory
                .selectFrom(academy)
                .where(academy.name.eq(name))
                .fetch();**
    }

}

Spring Boot Data Jpa 프로젝트에 Querydsl 적용하기

 

Spring Boot Data Jpa 프로젝트에 Querydsl 적용하기

안녕하세요? 이번 시간에는 Spring Boot Data Jpa 프로젝트에 Querydsl을 적용하는 방법을 소개 드리겠습니다. 모든 코드는 Github에 있습니다. Spring Data Jpa를 써보신 분들은 아시겠지만, 기본으로 제공해

jojoldu.tistory.com

✅ stream, lambda

Service의 findAllDesc()은 정렬한 글 목록을 DB에서 조회하여 객체 리스트로 받고, 이를 Dto 리스트로 변환하여 반환하고 있습니다. 아니 근데 이 희안한 문법은 무엇일까요? 그냥 for문을 사용해서 하나씩 객체를 Dto로 바꾸면 안되는 걸까요?

@Transactional(readOnly = true)
public List<PostsListResponseDto> findAllDesc(){
    return postsRepository.findAllDesc()**.stream()
        .map(PostsListResponseDto::new)
        .collect(Collectors.toList());**
}

코드를 보면 stream, map, ::, collect 등의 키워드가 보이는데요. 이들은 모두 자바8에서 새로 등장한 문법입니다. 하나씩 살펴볼게요.

stream은 데이터 집합을 읽는 객체입니다. 위의 예제에서는 postsRepository.findAllDesc()가 반환한 List 데이터 집합을 읽는데 사용되었습니다. 함께 사용된 map은 대표적인 stream 연산으로, stream의 요소들을 새로운 타입으로 변환하는데 주로 사용합니다. 예제에서 stream의 각각의 요소는 Posts가 될 것이고, 각 Posts 객체에 대해 map 메소드에 파라미터로 넘긴 작업을 수행할 것입니다. collect도 map과 마찬가지로 stream 연산입니다. stream 요소들을 List, Set, Map 등 다른 종류의 결과로 수집하고 싶은 경우 사용합니다. 예제에서는 map의 연산 결과로 받은 stream을 List로 반환하였습니다.

map 메소드에 파라미터로 넘긴 작업은 무엇일까요?( PostsListResponseDto::new ) PostsListResponseDto의 생성자를 호출하고 있다는 느낌이 팍팍 드는데요. 이 문법은 자바8에서 도입된 람다식의 축약 표현인 메소드 레퍼런스입니다.

// 1. 람다 표현식
numList.forEach(x -> System.out.println(x));

// 2. 메서드 레퍼런스 (클래스::메소드)
numList.forEach(System.out::println);

메소드를 참조해서 매개변수의 정보 및 리턴 타입을 알아내어, 람다식에 불필요한 매개 변수를 제거하는 것이 목적입니다. 위의 예제에서 람다식은 단순히 x를 System.out.println()로 전달하는 역할만 하기 때문에, 코드가 불필요하게 길어졌습니다. 메서드 레퍼런스를 사용하면 이러한 매개변수 전달 코드를 줄일 수 있습니다.

다시 교재 코드를 보면서 정리해보겠습니다. 이 코드는 JpaRepository로 찾아온 List를 List로 변환하는 코드입니다. for문을 사용하는 대신, 자바8의 Stream API와 람다의 추상 표현을 사용했습니다. stream으로 List를 읽었고, map으로 Posts를 PostsListResponseDto로 변환했고, collect로 map의 연산 결과인 stream을 List로 변환했습니다.

그런데 조금 이상하지 않나요? 왜 for문을 사용하지 않고 stream을 사용했을까요? stream이 무언가 특별한 기능을 제공하는걸까요? 그리고 Posts를 PostsListResponseDto로 변환할 때, 그냥 PostsListResponseDto의 생성자에 바로 Posts를 넣어서 List에 추가하지, 왜 람다식을 사용한걸까요? 람다식은 함수형 프로그래밍 언어에서 등장하는 문법인데, 왜 객체 지향 언어인 자바에서 함수식을 사용하는 걸까요?

코딩교육 티씨피스쿨

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

Java 8부터 지원되는 Stream API

 

Java 8부터 지원되는 Stream API

스트림(Stream)이란? FileInputStream과 같은 I/O 스트림과는 다른 개념이다. (I/O 스트림은 데이터 가져오기와 내보내기를 하는 일종의 통로 역할을 하는 것이다.) 스트림은 간단하게 한 줄로 요약하면

pamyferret.tistory.com

Java 8과 함수형 프로그래밍: Lambda, Stream, Functional Interface

 

Java 8과 함수형 프로그래밍: Lambda, Stream, Functional Interface

Intro. 왜 Java 8인가? Java 8 (=Java 1.8) 은 2014년에 발표된 자바 버전이다. 내가 대학에서 자바를 배웠던 것은 Java 8이 발표되기 전이었다. 당연히 Java 8의 신기능에 대해서 대학 수업에서는 배우지 못했

gsmesie692.tistory.com

Java 8 에서 왜 함수형 프로그래밍이 도입되었을까?

 

Java 8 에서 왜 함수형 프로그래밍이 도입되었을까?

우선 당신에게 질문을 던져본다. 객체지향 프로그래밍과 함수형 프로그래밍은 상호 배제 관계에 있다고 생각하는가? 객체지향과 함수형 프로그래밍 Java…

tecoble.techcourse.co.kr

면접에서 동기 & 비동기 묻는 이유

 

면접에서 동기 & 비동기 묻는 이유

면접에서 왜 동기 & 비동기를 묻는 걸까?

velog.io

✅ Optional

Spring Data Jpa가 기본으로 제공하는 findById로 가져온 객체를 사용할 때, 다음과 같은 요상한 코드를 사용했습니다.

@Transactional(readOnly = true)
    public PostsResponseDto findById(Long id) {
        Posts entity = postsRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다. id=" + id));

        return new PostsResponseDto(entity);
    }

사실 findById()는 Optional<엔티티>라는 객체를 반환합니다. Optional 역시 Java8에 나온 문법인데요, Optional은 어떠한 필요에 의해 나온 것일까요? Optional은 어떻게 사용할까요? Optional은 null을 안전하게 사용하려면 다뤄야할 타입입니다. 다른 사람들의 코드를 보면서 그 역할을 깨우쳐보세요!

[Java] Optional이란? Optional 개념 및 사용법 - (1/2)

 

[Java] Optional이란? Optional 개념 및 사용법 - (1/2)

이번에는 Java8부터 지원하는 Optional 클래스에 대해 알아보도록 하겠습니다. 1. Optional이란? Optional 개념 및 사용법 [ NPE(NullPointerException) 이란? ] 개발을 할 때 가장 많이 발생하는 예외 중 하나가 바

mangkyu.tistory.com

[Java] 언제 Optional을 사용해야 하는가? 올바른 Optional 사용법 가이드 - (2/2)

 

[Java] 언제 Optional을 사용해야 하는가? 올바른 Optional 사용법 가이드 - (2/2)

앞선 포스팅에서는 Optional의 개념과 문법을 살펴보았습니다. Optional은 Null이 될 수 있는 객체를 감싸는 Wrapper 클래스이기 때문에 비용이 발생합니다. 그래서 Optional은 필요한 경우에만 사용하는

mangkyu.tistory.com

 


 

❄️ 멤버들 추가공부 자료

'Group Study (2022-2023) > Spring 입문' 카테고리의 다른 글

5주차 레퍼런스  (0) 2023.01.12
4주차 레퍼런스  (0) 2023.01.12
2주차 레퍼런스  (0) 2023.01.12
1주차 레퍼런스  (0) 2023.01.12
[spring 입문] 토이프로젝트 - TwoYeon  (1) 2022.12.20