728x90
반응형
728x90

 

 

 

연관 관계 매핑이란 ❓

연관 관계 매핑객체 간의 관계를 데이터베이스의 관계로 어떻게 매핑할지를 정의하는 것입니다. 객체 지향 프로그래밍에서는 객체 간의 관계를 사용하여 현실 세계를 모델링하고, 이를 데이터베이스에 저장하려면 효과적인 방법이 필요합니다. JPA(Java Persistence API)는 이러한 연관 관계 매핑을 지원하며, 이를 통해 객체 모델과 데이터베이스 스키마를 매핑할 수 있습니다.

객체와 테이블 연관관계의 차이를 이해하고 객체의 참조와 테이블의 외래키를 매핑할 수 있습니다.

✍️ 연관 관계 매핑에서 사용되는 주요 용어

  1. 방향(Direction)
    • 연관 관계가 양방향인지 단방향인지를 나타냅니다.
    • 양방향 연관 관계는 서로를 참조하는 관계로, 한 객체가 다른 객체를 참조하고 동시에 다른 객체도 그 객체를 참조하는 관계를 말합니다. (예: 주문과 회원 간의 관계)
    • 단방향 연관 관계는 한 객체에서만 다른 객체를 참조하는 관계로, 한 쪽 방향으로만 참조가 가능합니다. (예: 주문과 배송 간의 관계)
  2. 다중성(Multiplicity)
    • 객체 간의 관계가 1:1, 1:N, N:1, N:N 등 얼마나 많은 객체가 연결되어 있는지를 나타냅니다.
    • 1:1은 한 객체가 다른 객체와 하나의 관계만 가지는 경우를 말합니다.
    • 1:N은 한 객체가 여러 개의 다른 객체와 관계를 가지는 경우를 말합니다.
    • N:1은 여러 개의 객체가 하나의 객체와 관계를 가지는 경우를 말합니다.
    • N:N은 여러 개의 객체가 여러 개의 다른 객체와 관계를 가지는 경우를 말합니다. (예: 주문과 상품 간의 관계)
  3. 연관 관계의 주인(Owner)
    • 양방향 연관 관계에서 관계를 주도하는 쪽을 연관 관계의 주인이라고 합니다.
    • 연관 관계의 주인은 데이터베이스에서 외래 키(Foreign Key)를 관리하며, 데이터베이스에 데이터를 저장하거나 수정할 때 주인 쪽의 변화가 반영됩니다.
    • 주인이 아닌 쪽은 읽기만 가능하고 데이터베이스에 영향을 주지 않습니다.

주의해야 할 점은 연관 관계의 주인은 데이터베이스의 관점에서 중요한 역할을 하며, 객체지향의 관점에서 중요하지 않을 수 있습니다. 때문에 연관 관계의 주인을 선택할 때는 데이터베이스의 특성과 운영을 고려하여 결정하는 것이 좋습니다.

이러한 방향, 다중성, 연관 관계의 주인 개념은 객체 간의 관계를 데이터베이스에 매핑할 때 혼란을 방지하고 일관된 관계를 구성하기 위해 중요한 역할을 합니다.

 

✅ 예제 시나리오

회원과 팀으로 구분지어 연관관계를 지어보도록 하겠습니다.

⭐ 회원은 하나의 팀에만 소속될 수 있습니다.
⭐ 회원과 팀은 다대일 (N:1)의 관계로 맺어집니다.

객체를 테이블에 맞춰 모델링을 한 경우 아래와 같은 ER 다이어그램이 그려집니다.

 

💥 테이블에 객체를 맞춘 데이터 중심 모델링

 

 
       public static void main(String[] args) {

                EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");

                EntityManager em = emf.createEntityManager();
                EntityTransaction tx = em.getTransaction();
                tx.begin();

                //외래 키 식별자를 직접 다루는 코드
                try {

                    //Team 저장 코드
                    Team team = new Team();
                    team.setName("TeamA");
                    em.persist(team);

                    //Member 저장코드
                    Member member = new Member();
                    member.setUsername("회원 1");
                    member.setTeamId(team.getId()); //회원 1을 TeamA에 소속시키고자 함
                    em.persist(member);


                    tx.commit();

                } catch (Exception e) {
                    e.printStackTrace();//추가
                    tx.rollback();
                }finally {
                    em.close();
                }

                emf.close();

                }

 

객체를 테이블에 맞추어 데이터 중심으로 모델링하면 협력 관계를 만들 수 엇습니다. 테이블은 외래 키로 조인을 사용해서 연관 테이블을 찾는 반면, 객체는 참조를 사용해서 연관된 객체를 찾는 큰 차이점이 존재합니다.

객체지향 프로그래밍에서는 객체 간의 관계가 더 복잡한 경우가 많습니다. 이를 데이터베이스에 매핑할 때에는 단순한 테이블 간의 관계만으로 표현하기 어려울 수 있습니다. 단방향 / 양방향 연관관계는 이러한 객체지향 모델을 데이터베이스 모델로 효과적으로 매핑하기 위해 사용됩니다.

 

단방향 연관관계

Team 객체를 Getter나 Setter로 호출하여 사용하는 것이 아닌 Team Entity 그 자체를 Member Entity와 연관 관계를 주어 사용하고자 합니다. JPA에게 관계를 지정해주어야 하며, 일 대 일 or 일 대 다인지가 중요한 부분입니다. Member의 관점에서는 Member가 N , Team이 1의 입장이기 때문에 @ManyToOne 어노테이션이 Member 테이블에 선언된 Team 클래스에 작성해야 합니다.

단방향 연관관계두 개의 객체 간의 관계를 나타내는데, 한 객체가 다른 객체를 참조하는 것입니다. 즉, 한 객체에서 다른 객체로의 관계를 설정하고 사용하는 것이지만, 반대 방향의 참조는 없는 상태를 의미합니다.

예를 들어, 팀(Team)과 팀원(Member)라는 두 개의 엔티티가 있다고 가정해보겠습니다. 여기서 팀원은 팀원을 참조하므로, 팀원 엔티티에 팀원의 정보를 저장하는 멤버 변수를 추가합니다. 이 때 팀원의 정보를 저장하기 위해 외래 키를 사용할 수 있습니다.

단방향 연관관계의 특징은 다음과 같습니다:

  1. 한 객체에서 다른 객체로의 참조만 존재하며, 그 반대는 성립하지 않습니다. 예를 들어, 팀에서 팀원을 참조할 수 있지만 작성자 객체에서 해당 작성글을 바로 참조하는 것은 어렵습니다.

  2. 객체의 참조를 통해 다른 객체를 조회하거나 조작할 수 있습니다. 위의 예에서 팀 객체에서 팀원을 조회하거나 수정할 수 있습니다.

  3. 데이터베이스 테이블 간의 관계로는 해당 연관관계를 한쪽 방향으로만 설정하면 됩니다. 즉, 팀의 테이블에 팀원 정보를 저장하는 컬럼을 추가하면 됩니다.

단방향 연관관계는 간단하고 명확한 구조를 가지고 있어 일반적인 상황에서 유용하게 활용됩니다. 하지만 객체지향 모델링의 관점에서는 한쪽 방향으로만 접근할 수 있는 구조이므로, 양방향 연관관계가 필요한 경우도 있을 수 있습니다.

 

💡 Team과 Member ⇒ @ManyToOne (member기준)

 

                public static void main(String[] args) {

                        생략..

                        //외래 키 식별자를 직접 다루는 코드
                        try {

                            //연관 관계 매핑 후 Team 저장 코드
                            Team team = new Team();
                            team.setName("TeamA");
                            em.persist(team);

                            //연관 관계 매핑 후 Member 저장코드
                            Member member = new Member();
                            member.setUsername("회원 1");
                            member.setTeam(team);
                            em.persist(member);

                            Member findMember = em.find(Member.class, member.getId());
                            Team findTeam = findMember.getTeam();

                            System.out.println("findTeam.getName = " + findTeam.getName());

                        생략..


                ============== 쿼리문 출력 결과=======================
                Hibernate: 
                    select
                        m1_0.MEMBER_ID,
                        t1_0.TEAM_id,
                        t1_0.name,
                        m1_0.USERNAME 
                    from
                        Member m1_0 
                    left join
                        Team t1_0 
                            on t1_0.TEAM_id=m1_0.TEAM_ID 
                    where
                        m1_0.MEMBER_ID=?

                System.out.println("findTeam.getName = " + findTeam.getName());
                findTeam.getName = TeamA
728x90
반응형

'[ BACKEND] > Spring' 카테고리의 다른 글

[SPRING] 다양한 연관관계의 종류  (0) 2023.08.11
[SPRING] 양방향 연관관계  (0) 2023.08.09
[SPRING] Entity Mapping (엔티티 매핑)  (0) 2023.08.07
[SPRING] Entity와 영속성  (0) 2023.08.06
[SPRING] ORM 그리고 JPA  (0) 2023.08.05
728x90

객체와 테이블 매핑 : @Entity, @ Table

필드와 컬럼 매핑 : @Column

기본 키 매핑 : @Id

연관관계 매핑 : @ManyToOne , @JoinColumn

 


⭐ Entity 매핑

 

Entity 매핑객체와 데이터베이스 테이블 간의 매핑을 정의하는 작업을 말합니다. Java 언어로 정의된 엔티티 클래스와 데이터베이스의 릴레이션(테이블) 간에 어떤 관계를 맺을지를 지정하는 것이며, 이를 통해 객체 지향 프로그래밍과 관계형 데이터베이스 간의 변환을 가능하게 합니다.

Entity 매핑을 통해 엔티티 클래스의 필드와 데이터베이스의 컬럼을 매핑하고, 객체 간의 관계를 데이터베이스의 외래 키(Foreign Key)와 연결합니다. JPA를 사용하여 데이터베이스와 상호작용하는데 필요한 정보를 제공합니다.

@Entity 어노테이션을 클래스에 붙이면 해당 클래스가 JPA 엔티티임을 나타냅니다.JPA는 @Entity 어노테이션이 붙은 클래스를 데이터베이스의 테이블과 매핑하여 객체를 영구 저장소에 저장하고 관리합니다.

@Entity 어노테이션의 주요 특징은 다음과 같습니다:

JPA에서 관리하는 엔티티 클래스는 반드시 @Entity 어노테이션이 붙어야 합니다.@Entity 어노테이션이 붙은 클래스는 JPA의 영속성 컨텍스트에서 관리되며, 데이터베이스와 매핑되는 역할을 수행합니다. @Entity 어노테이션을 사용하는 클래스는 기본 생성자가 반드시 필요하며, 파라미터가 없는 기본 생성자를 갖고 있어야 합니다.

@Entity 어노테이션을 사용하여 JPA 엔티티 클래스를 정의하면, JPA는 해당 클래스와 연결된 데이터베이스 테이블을 자동으로 생성하고,엔티티의 상태를 추적하고, 영속성 컨텍스트를 통해 엔티티를 관리하는 등의 기능을 제공합니다.

주요한 엔티티 매핑 어노테이션은 다음과 같습니다:

  1. @Entity : 엔티티 클래스를 정의할 때 사용하는 어노테이션입니다. 해당 클래스가 JPA에서 관리하는 엔티티임을 지정합니다. JPA를 사용해서 테이블과 매핑할 클래스는 @Entity가 필수입니다. 작성 시 주의점으로는 기본 생성자가 필수적입니다.
    • name : 엔티티의 이름을 지정합니다. 기본적으로 클래스 이름과 동일하게 사용되지만, 다른 이름을 사용하고 싶을 때에는 이 속성을 이용하여 이름을 설정할 수 있습니다

    • catalog : 엔티티의 카탈로그(catalog)를 지정합니다. 데이터베이스에는 여러 개의 카탈로그가 존재할 수 있으며, 엔티티가 속한 카탈로그를 지정할 때 사용합니다.

    • schema : 엔티티의 스키마(schema)를 지정합니다. 스키마는 테이블의 집합을 그룹화하는 개념으로 사용되며, 엔티티가 속한 스키마를 지정할 때 사용합니다.

    • indexes : 엔티티에 대한 인덱스(index)를 정의합니다. @Index 어노테이션을 통해 여러 개의 인덱스를 정의할 수 있습니다.

    • uniqueConstraints : 엔티티에 대한 유니크 제약 조건(unique constraint)을 정의합니다. @UniqueConstraint 어노테이션을 통해 여러 개의 유니크 제약 조건을 정의할 수 있습니다.

    • listeners : 엔티티의 이벤트를 처리하는 리스너(listener)를 지정합니다. @EntityListeners 어노테이션을 통해 엔티티 리스너를 등록할 수 있습니다.
  2. @Column : 엔티티 클래스의 필드를 데이터베이스 컬럼과 매핑할 때 사용하는 어노테이션입니다. 컬럼명, 데이터 타입, 길이 등을 설정할 수 있습니다.

  3. column unique 조건은 데이터베이스 테이블의 열(Column)에 대해 고유한(unique) 값만 저장하도록 제약을 설정하는 것을 말합니다. 이러한 제약조건은 데이터베이스에서 중복된 값을 허용하지 않도록 하는데 사용됩니다.
    ex) @Column(nullable = false , length 10); NotNull(필수 작성) , column의 길이는 10자 초과 X

  4. @Id : 엔티티의 주키(primary key)를 정의하는 어노테이션입니다.

  5. @GeneratedValue: 주키의 값을 자동으로 생성하기 위해 사용되는 어노테이션으로, 주로 자동증가(Auto Increment)를 지정합니다.

  6. @OneToMany, @ManyToOne, @OneToOne, @ManyToMany: 엔티티 간의 관계를 매핑할 때 사용하는 어노테이션으로, 객체의 연관관계를 데이터베이스의 외래 키로 매핑합니다.

  7. @Embedded: 다른 엔티티를 포함한 복합 타입(Embeddable)을 정의할 때 사용하는 어노테이션입니다.

 


 

데이터 베이스 스키마 자동 생성


DataBase Schema 자동 생성은 JPA(Java Persistence API)를 사용할 때 제공되는 기능 중 하나입니다. JPA는 객체와 데이터베이스 테이블을 매핑하기 위해 사용되는 ORM(Object-Relational Mapping) 기술로,
엔티티 클래스를 바탕으로 데이터베이스 테이블을 자동으로 생성할 수 있습니다.

스프링 프레임워크를 사용하는 경우, 스프링 부트를 통해 JPA 설정을 간단하게 구성할 수 있으며, 스키마 자동 생성을 활성화할 수 있습니다. 스키마 자동 생성은 주로 개발 환경에서 사용합니다. DDL 생성 기능은 DDL을 자동 생성할때만 사용되고 JPA의 실행 로직에는 영향을 주지 않습니다.

스프링 부트를 사용하여 데이터베이스 스키마 자동 생성을 활성화하려면, application.properties 또는 application.yml 파일에 다음과 같이 설정합니다

            # application.properties -> 스키마 자동 생성
            spring.jpa.hibernate.ddl-auto=create

            # application.properties -> 스키마 자동 생성을 비활성화
            spring.jpa.hibernate.ddl-auto=none

 

위의 설정은 애플리케이션을 실행할 때마다 엔티티 클래스를 기반으로 데이터베이스에 테이블을 자동으로 생성합니다. 그러나 스키마 자동 생성을 사용할 때는 주의해야 합니다.
이미 데이터베이스에 데이터가 존재하는 경우, 스키마 자동 생성 시 기존 데이터가 삭제될 수 있으므로, 테스트 환경 등 개발 시에만 사용하는 것이 좋습니다.

배포나 운영 환경에서는 spring.jpa.hibernate.ddl-auto 값을 none으로 설정하거나 주석 처리하여 스키마 자동 생성을 비활성화하고, 데이터베이스 스키마를 수동으로 관리하는 것을 권장합니다.

데이터베이스 스키마를 수동으로 관리하는 경우에는 변경된 엔티티 클래스를 기반으로 데이터베이스 테이블을 직접 변경해야 합니다. 이러한 방식은 운영 환경에서 더 안전하고 안정적입니다.

스키마 자동 생성과 관련된 주요 속성

  • create: 애플리케이션 시작 시 스키마를 생성합니다. 이미 존재하는 경우는 삭제하고 다시 생성합니다. (개발 초기 단계에는 create , update)

  • update : 변경된 부분만 반영해주고, 운영 DB에는 절대 사용하면 안됩니다.

  • drop: 애플리케이션 종료 시 스키마를 삭제합니다.

  • none: 스키마 생성 액션을 수행하지 않습니다. 개발자가 수동으로 스키마를 생성해야 합니다.

  • validate : Entity와 테이블이 정상 매핑되었는지 확인할 때 사용합니다.

 


 

📋 필드와 컬럼 매핑

 

요구사항 선정

  • 회원은 일반 회원과 관리자로 구분해야 한다.
  • 회원 가입일과 수정일이 있어야 한다.
  • 회원을 설명할 수 있는 필드가 있어야 하고, 필드의 길이는 제한이 없다.

필드와 컬럼 매핑

 

필드(Field)와 컬럼(Column) 매핑은 JPA(Entity) 클래스의 필드와 데이터베이스의 컬럼을 연결해주는 작업을 말합니다. 이를 통해 JPA 클래스의 필드 값을 데이터베이스에 저장하고 조회할 수 있습니다.

JPA에서 필드와 컬럼을 매핑하는 방법은 다음과 같습니다:

  1. 필드 매핑: JPA 클래스의 필드를 데이터베이스 컬럼과 연결합니다. 필드의 타입과 이름, 접근 제어자 등을 이용하여 데이터베이스 컬럼과 매핑합니다.

            @Entity
            public class Member {

                @Id
                @GeneratedValue
                private Long id;

                @Column(name = "username")
                private String name;

            }


@Column(name = "username") 어노테이션은 name 필드를 데이터베이스의 username 컬럼과 매핑하는 역할을 합니다. 이렇게 필드와 컬럼을 매핑하면, name 필드의 값을 데이터베이스의 username 컬럼에 저장하고 조회할 수 있습니다.

 

 2. 테이블 매핑: JPA 클래스를 데이터베이스의 테이블과 연결합니다. JPA 클래스에 @Entity 어노테이션을 사용하여 테이블과 매핑합니다.

            @Entity
            @Table(name = "members")
            public class Member {

                // 필드 매핑 생략
            }

 

위의 예시에서 @Table(name = "members") 어노테이션은 Member 클래스를 데이터베이스의 members 테이블과 매핑하는 역할을 합니다.
이렇게 테이블과 클래스를 매핑하면, Member 클래스의 인스턴스를 데이터베이스의 members 테이블과 연결하여 데이터를 주고 받을 수 있습니다.

필드와 컬럼 매핑을 통해 JPA 클래스의 필드와 데이터베이스의 컬럼을 연결하여 데이터를 영속화하고 조회할 수 있으며, JPA의 기능과 편의성을 최대한 활용하여 데이터베이스와 자바 객체 간의 변환 작업을 간편하게 수행할 수 있습니다.

 

✍️ @Column의 대표적인 속성들

  1. name : 필드를 데이터베이스 컬럼과 매핑할 때 사용할 컬럼의 이름을 지정합니다. 기본값은 필드의 이름과 동일합니다.

  2. unique : 해당 컬럼의 값이 고유(unique)해야 하는지를 지정합니다. 기본값은 false입니다.

  3. nullable : 해당 컬럼의 값이 null을 허용하는지를 지정합니다. 기본값은 true입니다.

  4. length : 해당 컬럼의 최대 길이를 지정합니다. 문자열 필드에만 적용되며, 기본값은 255입니다.

  5. precision, scale : 숫자 타입 필드에서 사용되며, precision은 전체 자리수를, scale은 소수점 이하 자리수를 지정합니다.

  6. columnDefinition : 컬럼의 데이터 타입과 제약 조건을 직접 지정할 때 사용합니다. 데이터베이스에 따라 특정 데이터 타입을 사용해야 하는 경우에 유용합니다.

  7. insertable, updatable : 해당 컬럼의 값이 삽입(insertable) 또는 변경(updatable) 가능한지를 지정합니다. 기본값은 true입니다.

 

           
           
       	1. name 
            @Column(name = "username")
            private String name;

            2. unique 
            @Column(unique = true)
            private String email;

            3.nullable 
            @Column(nullable = false)
            private String name;

            4. length 
            @Column(length = 100)
            private String description;

            5.precision, scale
            @Column(precision = 10, scale = 2)
            private BigDecimal price;

            6.columnDefinition
            @Column(columnDefinition = "varchar(100) default 'N/A'")
            private String category;

            7.insertable, updatable
            @Column(insertable = false, updatable = false)
            private LocalDateTime createdAt;
728x90
반응형

'[ BACKEND] > Spring' 카테고리의 다른 글

[SPRING] 양방향 연관관계  (0) 2023.08.09
[SPRING] 연관 관계 매핑 (단방향)  (0) 2023.08.08
[SPRING] Entity와 영속성  (0) 2023.08.06
[SPRING] ORM 그리고 JPA  (0) 2023.08.05
[SPRING] Servlet / JSP / MVC  (0) 2023.08.04
728x90

 

https://yozm.wishket.com/magazine/detail/2160/

 

Entity데이터베이스 테이블과 매핑되는 자바 객체를 의미합니다. 각각의 Entity 클래스는 테이블의 레코드(row)와 일치하는 필드를 가지고 있으며, JPA를 사용하여 이러한 Entity 객체들을 데이터베이스에 저장, 조회, 수정, 삭제 등의 작업을 수행합니다. Entity 클래스에는 @Entity 어노테이션을 사용하여 선언합니다.

예를 들어, Member라는 Entity 클래스로 Member 테이블과 매핑 후 id, name, age를 필드값으로 선언한다면 아래와 같이 작성할 수 있습니다.

        
        
        	@Entity
            public class Member {

                @Id
                @GeneratedValue
                private Long id;

                private String name;
                private int age;

                // Getter, Setter, 생성자 등의 메서드들은 생략
            }

 

📋 EntityManager는 JPA에서 가장 중요한 인터페이스 중 하나로, Entity와 데이터베이스를 연결하여 CRUD(Create, Read, Update, Delete) 작업을 수행하는 역할을 담당합니다. EntityManager는 JPA에서 영속성 컨텍스트(Persistence Context)를 통해 Entity 객체의 상태를 관리합니다.

EntityManager는 보통 트랜잭션 단위로 사용됩니다. 트랜잭션을 시작하면 EntityManager를 생성하여 작업을 수행하고, 트랜잭션을 커밋하거나 롤백하면 변경된 Entity 객체들을 데이터베이스에 반영합니다.

EntityManager의 주요 메서드로는 다음과 같은 것들이 있습니다:

  1. persist(Object entity): Entity 객체를 영속성 컨텍스트에 추가합니다. 데이터베이스에 저장되지는 않습니다.

  2. find(Class<T> entityClass, Object primaryKey): 주어진 기본 키에 해당하는 Entity 객체를 조회합니다.

  3. merge(T entity): Entity 객체의 변경사항을 영속성 컨텍스트에 병합합니다.

  4. remove(Object entity): Entity 객체를 영속성 컨텍스트에서 삭제합니다.

📋 EntityManagerFactory는 JPA의 핵심적인 요소 중 하나로, EntityManager를 생성하는 역할을 담당합니다. 애플리케이션이 시작될 때 한 번 생성되며, 보통 애플리케이션 전체에서 하나의 EntityManagerFactory 인스턴스를 공유하여 사용합니다.

EntityManagerFactory는 데이터베이스에 연결하고 Entity와 테이블의 매핑 정보를 로딩하여 EntityManager를 생성할 때 필요한 정보들을 제공합니다. 따라서 EntityManagerFactory를 통해 EntityManager를 여러 개 생성하여 여러 개의 트랜잭션을 동시에 처리할 수 있습니다.

EntityManagerFactory는 보통 애플리케이션 컨텍스트(ApplicationContext)에서 관리되며, 사용이 끝나면 애플리케이션 종료 시점에 명시적으로 닫아주어야 합니다.

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
        EntityManager em = emf.createEntityManager();

        종료시점에는 em.close(); / emf.close(); 를 실행

 

위와 같이 EntityManagerFactory를 생성한 후, createEntityManager() 메서드를 호출하여 EntityManager를 생성합니다.

요약하면, Entity는 데이터베이스 테이블과 매핑되는 자바 객체를 나타내고, EntityManager는 Entity 객체의 영속성 상태를 관리하고 CRUD 작업을 수행하며,
EntityManagerFactory는 EntityManager를 생성하는 데 사용되는 팩토리 역할을 합니다. 이들은 JPA를 통해 데이터베이스와 자바 객체를 효율적으로 관리하는 데 중요한 역할을 수행합니다.

 


 

JPQL이란 ❓

 

JPQL(Java Persistence Query Language)은 JPA(Java Persistence API)에서 사용하는 객체 지향 쿼리 언어입니다. 데이터베이스 테이블이 아닌 엔티티 객체를 대상으로 쿼리를 작성할 수 있어서 객체 지향적인 접근을 할 수 있습니다. JPQL은 SQL과 유사한 구문을 가지고 있지만, 테이블이 아닌 엔티티와 필드를 대상으로 쿼리를 작성하는 차이가 있습니다.

JPQL은 데이터베이스 특정 SQL 문법에 종속되지 않고, JPA가 지원하는 모든 데이터베이스에서 사용할 수 있습니다. 따라서 JPA를 사용하는 애플리케이션은 데이터베이스에 상관없이 일관성 있는 쿼리를 작성할 수 있습니다.

JPQL 쿼리는 엔티티 객체에 대한 조회, 필터링, 정렬, 집계 등 다양한 작업을 수행할 수 있습니다. JPQL은 SELECT, UPDATE, DELETE 등의 작업을 지원하며, 파라미터 바인딩 등의 기능도 제공합니다.

JPQL은 엔티티 클래스와 필드를 대상으로 작성되기 때문에 테이블과 컬럼의 이름이 변경되어도 쿼리를 수정할 필요가 없습니다. 또한, JPQL을 사용하면 런타임 시점에 쿼리의 오타나 오류를 미리 파악할 수 있어서 안전성이 높습니다.

JPQL 사용 예시

       
       
       // JPQL 쿼리 예시: 회원 이름이 '푸바오'인 회원을 조회하는 쿼리
        String jpql = "SELECT m FROM Member m WHERE m.name = '푸바오'";

        // JPQL 쿼리를 실행하기 위해 EntityManager를 이용하여 Query 객체를 생성
        Query query = entityManager.createQuery(jpql);

        // 결과를 가져오기 위해 getResultList() 메서드를 호출하여 List<Member> 형태로 결과를 반환
        List<Member> members = query.getResultList();

 

 


 

📋 영속성 컨텍스트

영속성 컨텍스트(Persistence Context)JPA(Java Persistence API)에서 관리하는 엔티티(Entity)들의 상태를 관리하는 공간입니다. 영속성 컨텍스트는 엔티티의 생명주기를 관리하고,
데이터베이스와의 상호작용을 최적화하는 데 도움이 됩니다. JPA를 이해하는데 가장 중요한 논리적 개념이고 눈에 보이지 않으며,엔티티 매니저를 통해 영속성 컨텍스트에 접근이 가능합니다.

엔티티의 생명주기는 비영속(new/transient) : 영속성 컨텍스트와 전혀 관계없는 새로운 상태
→ new 연산자로 객체를 생성한 상태를 의미
영속 (managed) : 영속성 컨텍스트에 관리되는 상태
준영속 (detached) : 영속성 컨텍스트에 저장되었다가 분리된 상태
삭제 (removed) : 삭제된 상태

 

 

🎈 영속 상태

 

                EntityManagerFactory emf = PersistenceDelegate.createEntityManagerFactory ("hello");

                EntityManager em = emf.createEntityManager();
                EntityTransaction tx = em.getTransaction();
                tx.begin();

                //비영속
                Member member = New Member();
                member.setId(100L);
                member.setName("HelloJPA");

                //영속성 (DB에 저장되는 것은 아님)     
                    System.out.println("=====em.persist(영속처리 하기 전)=======");
                    em.persist(member);
                    System.out.println("=====em.persist(영속처리 하기 후)=======");

                    tx.commit();


         <----- ↓ 로그에 출력된 결과물 ----->

        =====em.persist(영속처리 하기 전)=======
        =====em.persist(영속처리 하기 후)=======
        Hibernate: 
            /* insert for
                com.study.jpa.Member */insert 
            into
                MBR (name,id) 
            values
                (?,?)

        tx.commit();  --> 이 커밋이 실행되면서 바로 쿼리문이 전달되게 됩니다!

 

✅ 영속성 컨텍스트의 장점

  1. 엔티티의 관리
    • 영속성 컨텍스트는 엔티티를 관리하고, 엔티티의 상태를 추적합니다. 즉, 엔티티의 변경 사항을 감지하고, 데이터베이스에 자동으로 반영합니다.
    • 엔티티를 영속성 컨텍스트에 저장하면, 영속 상태(Persistent)가 됩니다. 이후 변경 사항을 감지하고, 트랜잭션을 커밋할 때 데이터베이스에 반영됩니다.
  2. 1차 캐시
    • 영속성 컨텍스트 내부에 1차 캐시를 가지고 있습니다. 1차 캐시는 엔티티를 메모리에 저장하여 데이터베이스 조회를 최소화하고 성능을 향상시킵니다. 1차 캐시는 @Id(키)와 Entity(값)으로 만들어져있고 Id는 Pk값으로 매핑한것, 값은 Entity객체 자체가 값이 됩니다.
    • em.find(”member1”)을 찾으면 바로 DB를 찾는 것이 아니라 1차 캐시를 먼저 조회하고, 해당 데이터가 있다면 영속성 컨텍스트에서 해당 데이터를 조회합니다.
    • 같은 엔티티를 여러 번 조회해도, 영속성 컨텍스트 내에 이미 캐싱되어 있는 엔티티가 있다면 데이터베이스를 다시 조회하지 않고 캐시된 엔티티를 반환합니다. 만약 1차 캐시에 없는 데이터를 조회한다면 DB에서 조회하여 가져온 후 1차 캐시에 저장한 후 반환합니다.
  3. 트랜잭션 단위의 변경 관리
    • 영속성 컨텍스트는 트랜잭션 단위로 변경 사항을 관리합니다. 트랜잭션을 커밋할 때 변경 사항이 데이터베이스에 반영됩니다.
    • 트랜잭션 롤백이 발생하면, 영속성 컨텍스트에 저장된 변경 사항도 롤백되어 데이터베이스와 일관성을 유지합니다.
  4. 지연 로딩
    • 영속성 컨텍스트는 지연 로딩(Lazy Loading)을 지원합니다. 연관된 엔티티를 실제로 사용할 때에만 데이터베이스에서 조회하게 됩니다.
    • 이를 통해 성능이 향상되고, 필요하지 않은 데이터를 불러오지 않아도 되므로 효율적인 데이터베이스 사용이 가능합니다.
  5. Dirty Checking(더티 체킹)
    • 영속성 컨텍스트는 엔티티의 상태 변화를 감지하여 변경된 엔티티만 데이터베이스에 반영합니다. 이를 Dirty Checking이라고 합니다.

 


 

📋 JPA에서의 Entity 등록 ( 버퍼링(Buffering) 지원)

JPA에서 엔티티를 영속성 컨텍스트에 등록하는 방법은 크게 두 가지가 있습니다.

  1. 즉시 등록(Immediate Persisting)
    • 엔티티를 생성하거나 조회한 후 즉시 영속성 컨텍스트에 등록합니다. 이때, 트랜잭션을 커밋하기 전에도 데이터베이스에 즉시 등록됩니다.
    • 일반적으로 persist() 메서드를 사용하여 엔티티를 즉시 등록합니다.
  2. 지연 등록(Deferred Persisting)
    • 엔티티를 영속성 컨텍스트에 등록하는 것을 지연시킵니다. 즉, 엔티티를 생성하거나 조회한 후, 트랜잭션을 커밋할 때까지 영속성 컨텍스트에 등록하지 않습니다.
    • 지연 등록을 사용하면 한 트랜잭션 안에서 여러 개의 엔티티를 생성하고 수정할 때, 트랜잭션 커밋 시점에 한 번에 데이터베이스에 등록하여 성능을 최적화할 수 있습니다.
    • 일반적으로 JPA는 지연 등록을 기본 전략으로 사용합니다.

 

            
            	// 즉시 등록
                EntityManager em = ...; // EntityManager 생성
                EntityTransaction tx = em.getTransaction();

                tx.begin();
                Member member = new Member("John");
                em.persist(member); // 즉시 등록
                tx.commit();

                // 지연 등록
                EntityManager em = ...; // EntityManager 생성
                EntityTransaction tx = em.getTransaction();

                tx.begin();
                Member member1 = new Member("Alice");
                Member member2 = new Member("Bob");
                em.persist(member1); // 지연 등록
                em.persist(member2); // 지연 등록
                tx.commit(); // 트랜잭션 커밋 시점에 등록

 

위의 예시에서 persist() 메서드를 호출할 때, 엔티티는 바로 데이터베이스에 등록되는 것이 아니라 영속성 컨텍스트에 등록(1차 캐시)됩니다. 트랜잭션이 커밋될 때, 영속성 컨텍스트에 등록된 엔티티들이 한 번에 데이터베이스에 등록되게 됩니다. 이렇게 함으로써 데이터베이스와의 상호작용을 최소화하여 성능을 향상시킬 수 있습니다.

 


 

💡 배치(Batch)란 ?

 

JPA에서의 "배치(batch)"는 일괄 처리 또는 일괄 업데이트를 의미합니다. 배치 처리는 여러 개의 엔티티를 한 번에 데이터베이스에 영속화하는 기법으로, 엔티티를 하나씩 처리하는 것보다 성능을 향상시키고 데이터베이스와의 라운드 트립 횟수를 줄일 수 있습니다.

JPA에서 배치를 사용하려면 EntityManager의 flush()와 clear() 메서드를 사용합니다. 트랜잭션 내에서 엔티티를 영속화 또는 업데이트하면, 해당 엔티티들은 영속성 컨텍스트에 의해 관리되며, 트랜잭션이 커밋될 때 자동으로 데이터베이스와 동기화됩니다.

하지만 대량의 엔티티를 영속화하거나 업데이트하는 경우, 각 엔티티마다 개별적인 데이터베이스 작업을 수행하는 것은 비효율적일 수 있습니다. 이런 경우 배치를 사용하여 여러 개의 엔티티 변경을 하나의 배치로 묶어서 실행할 수 있습니다.

JPA에서 배치 처리가 작동하는 방식은 다음과 같습니다:

  1. 엔티티 변경 모으기: 트랜잭션 내에서 영속성 컨텍스트를 통해 여러 개의 엔티티를 영속화 또는 업데이트합니다.
  2. 영속성 컨텍스트 플러시: entityManager.flush()를 호출하면 영속성 컨텍스트가 데이터베이스와 동기화되고, 엔티티 변경에 대한 SQL 문이 생성되지만, 변경 사항은 아직 커밋되지 않습니다.
  3. 배치 업데이트 실행: SQL 문을 즉시 실행하는 대신, JPA는 일정 개수의 변경 사항 (배치 크기) 또는 일정 시간이 경과할 때까지 배치 업데이트를 대기합니다. 이렇게 하여 여러 개의 변경 사항을 하나의 배치로 데이터베이스에 보냅니다.
  4. 영속성 컨텍스트 초기화: 배치 업데이트가 실행된 후 entityManager.clear()를 호출하여 영속성 컨텍스트를 초기화하고 관리되는 엔티티에 대한 메모리를 해제할 수 있습니다. 대량의 엔티티를 처리할 때 메모리 문제를 피하는 데 도움이 됩니다.
  5. 트랜잭션 커밋: 마지막으로 트랜잭션이 커밋되면, 모든 배치 처리된 변경 사항이 데이터베이스에 일괄 처리로 기록됩니다.

배치를 사용하면 대량의 데이터를 영속화하거나 업데이트할 때 개별적인 데이터베이스 작업의 오버헤드를 크게 줄여 성능을 향상시킬 수 있습니다. 하지만 특정 상황과 데이터베이스 설정에 따라 적절한 배치 크기를 선택하는 것이 중요하며, 성능 문제를 피하기 위해 신중하게 결정해야 합니다.

 

📋 JPA에서의 Entity 수정 시 Dirty Checking(더티 체킹)

JPA의 목적은 자바 컬렉션과 유사하게 객체를 다루고자 합니다. JPA에서는 값을 찾아 불러온 후 값만 변경해주면, 마치 자바 컬렉션을 다루듯이 변경을 감지하여 데이터를 변경하기 위한 쿼리문을 작성합니다.

Entity Dirty Checking은 JPA(Java Persistence API)의 영속성 컨텍스트(Persistence Context)에서 엔티티(Entity)의 변경 상태를 감지하는 메커니즘입니다. 이를 통해 JPA는 엔티티가 변경되었는지를 자동으로 감지하고, 변경된 내용을 데이터베이스에 동기화할 필요가 있는지 판단합니다.

일반적으로 JPA에서 엔티티를 조회하면 해당 엔티티는 영속성 컨텍스트에 올라가게 됩니다. 그리고 트랜잭션이 끝나기 전까지 영속성 컨텍스트에서 관리되며, 이때 엔티티의 상태를 주기적으로 확인하여 변경 여부를 감지합니다. 이렇게 변경된 엔티티를 찾아내는 기능을 Dirty Checking이라고 합니다.

Dirty Checking은 다음과 같은 방식으로 동작합니다:

JPA는 데이터 베이스 트랜잭션을 커밋하는 순간 내부적으로 flush()가 호출되며 Entity와 스냅샷을 비교합니다. 스냅샷은 영속성 컨텍스트에 들어온 데이터가 1차 캐시에 담긴 시점을 의미합니다. 내부 데이터의 값이 변경되면 JPA가 데이터베이스가 트랜잭션이 되는 시점에 Entity와 스냅샷들을 비교하고, 변경된 데이터가 있다면 지연 등록에 Update 쿼리를 만들어 둔 후 DB로 전달합니다.

  1. 트랜잭션 시작 시, 엔티티의 스냅샷을 만듭니다. 스냅샷은 엔티티가 영속성 컨텍스트에 올라가기 이전 상태를 저장하는 것으로, 엔티티의 초기 상태를 기록합니다.

  2. JPA는 데이터 베이스 트랜잭션을 커밋하는 순간 내부적으로 flush()가 호출되며 Entity와 스냅샷을 비교합니다. 트랜잭션 도중 엔티티가 변경되면, 영속성 컨텍스트는 이전 스냅샷과 현재 엔티티 상태를 비교하여 변경 여부를 감지합니다.

  3. 변경된 엔티티가 발견되면, 해당 엔티티를 데이터베이스에 자동으로 동기화합니다. 즉, 변경된 내용을 UPDATE 쿼리로 데이터베이스에 반영합니다.

Dirty Checking을 사용하면 개발자가 직접 변경 감지 로직을 구현할 필요가 없으며, 효율적인 데이터베이스 업데이트를 자동으로 처리할 수 있습니다. 따라서 JPA를 사용하는 경우 엔티티의 상태 변경과 관련된 로직을 보다 간단하고 안정적으로 구현할 수 있습니다.

💥 flush란?

**flush()**는 영속성 컨텍스트의 변경 내용을 데이터베이스에 동기화하는 작업을 수행하는 메서드입니다. 데이터 베이스에 트랜잭션 커밋이 되는 순간 바로 flush()가 자동으로 발생합니다.

영속성 컨텍스트는 엔티티를 관리하며, 엔티티의 상태가 변경되면 해당 변경 내용은 먼저 영속성 컨텍스트에 저장됩니다. 그러나 데이터베이스와의 실제 동기화는 일반적으로 트랜잭션이 커밋되는 시점에 일괄적으로 수행됩니다.

하지만 때에 따라서는 트랜잭션이 커밋되기 전에 데이터베이스와 영속성 컨텍스트를 동기화해야 하는 상황이 발생할 수 있습니다. 이 때 **flush()를 호출하면 변경 내용이 데이터베이스에 즉시 반영**됩니다. 즉, flush()를 호출하면 영속성 컨텍스트의 변경 내용이 데이터베이스에 쓰여지고, 트랜잭션이 커밋되지 않아도 데이터베이스에는 변경된 내용이 반영됩니다.

**flush()**를 사용할 때 주의할 점은, 변경 내용이 데이터베이스에 반영되기 때문에 롤백이 불가능해지고, 데이터베이스와 영속성 컨텍스트의 상태가 일치하지 않을 수 있습니다. 따라서 적절한 시점에 **flush()**를 호출하여 사용하는 것이 중요합니다. 보통 **flush()**를 명시적으로 호출할 일은 적지만, 필요한 경우에는 이를 적절하게 활용하여 **데이터베이스와 영속성 컨텍스트를 동기화(영속성 컨텍스트를 비우는 것은 아님)**할 수 있습니다.

flush()가 실행된다고 해도, 영속성 컨텍스트를 비우는 기능은 없습니다. 트랜잭션의 작업 단위가 중요하며, 커밋 직전에만 변경 내용을 DB에 전달하면 됩니다.


준영속 상태

준영속 상태(Detached)란 영속성 컨텍스트에서 분리된 상태를 말합니다. 이 상태에서는 영속성 컨텍스트가 더 이상 해당 엔티티를 관리하지 않으며, 데이터베이스와의 동기화가 이루어지지 않습니다.

준영속 상태로 변환되면 해당 엔티티는 영속성 컨텍스트가 더 이상 관리하지 않기 때문에 변경 내용을 추적하지 않습니다. 따라서 데이터베이스와의 동기화도 이루어지지 않습니다. 그러나 해당 엔티티는 여전히 식별자를 가지고 있으며, 이를 통해 다시 영속 상태로 변경하거나 데이터베이스에서 조회할 수 있습니다.

일반적으로 영속 상태의 엔티티가 준영속 상태로 전환되는 경우는 다음과 같습니다:

  1. 트랜잭션이 커밋되어 영속성 컨텍스트가 종료되는 경우.

  2. EntityManager의 detach() 메서드를 호출하여 명시적으로 엔티티를 준영속 상태로 전환하는 경우.

  3. EntityManager의 clear() 메서드를 호출하여 영속성 컨텍스트를 완전히 초기화하는 경우.

  4. 영속 상태의 엔티티를 직렬화하여 세션 등에 저장한 뒤, 이후에 역직렬화하여 사용하는 경우.

준영속 상태에서는 엔티티의 변경이 데이터베이스에 영향을 주지 않기 때문에 주의해야 합니다. 만약 다시 영속 상태로 전환하고자 할 때는 EntityManager의 merge() 메서드를 사용하여 데이터베이스와의 동기화를 수행해야 합니다.

728x90
반응형
728x90

 

 

 

 

JPA란 ❓

 

JPA(Java Persistence API)는 자바 진영의 ORM(Object-Relational Mapping) 기술 표준입니다. ORM은 객체 지향 프로그래밍 언어로 작성된 객체와 관계형 데이터베이스의 데이터를 자동으로 매핑(연결)해주는 기술을 의미합니다.

JPA는 Java 언어로 작성된 객체와 관계형 데이터베이스 간의 매핑을 간단하고 편리하게 처리할 수 있도록 도와줍니다. 이를 통해 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체를 통해 데이터베이스에 접근하고 관리할 수 있습니다.

ORM을 구현한 여러 프레임워크 중 하나로, Java EE(Java Platform, Enterprise Edition)에서 제공하는 표준 기술입니다. JPA를 사용하려면 JPA를 구현한 구현체를 선택하여 프로젝트에 추가해야 합니다. 대표적인 JPA 구현체로는 Hibernate, EclipseLink, OpenJPA 등이 있습니다.

JPA의 주요 기능과 장점은 다음과 같습니다:

  1. 객체와 테이블 간의 매핑: JPA를 사용하면 객체와 관계형 데이터베이스 테이블 간의 매핑을 어노테이션 또는 XML 설정을 통해 정의할 수 있습니다.

  2. SQL 작성의 간소화: JPA를 사용하면 개발자가 직접 SQL 쿼리를 작성하지 않아도 됩니다. 대신 객체 지향적인 방식으로 쿼리를 작성하고 JPA가 해당 쿼리를 데이터베이스에 맞는 SQL로 변환해줍니다.

  3. 트랜잭션 관리: JPA를 사용하면 데이터베이스 트랜잭션을 자동으로 처리할 수 있습니다. 트랜잭션 관리를 편리하게 처리할 수 있으며, 롤백과 커밋을 자동으로 처리하여 데이터 무결성을 보장합니다.

  4. 캐시 기능: JPA는 엔티티 객체를 캐시하여 성능을 향상시킬 수 있습니다. 반복적으로 조회되는 데이터를 캐시하여 데이터베이스에 매번 접근하지 않아도 되므로 응답 속도를 개선할 수 있습니다.

  5. 객체 지향적인 프로그래밍: JPA를 사용하면 객체 지향 프로그래밍 언어인 Java를 그대로 활용하여 데이터베이스를 다룰 수 있습니다. 이로 인해 코드의 가독성과 유지보수성이 향상됩니다.

JPA는 Java 진영에서 가장 많이 사용되는 ORM 기술이며, 자바 개발자들에게 데이터베이스와의 상호작용을 편리하고 효율적으로 처리할 수 있는 강력한 도구입니다.


ORM이란 ❓

ORM은 Object-Relational Mapping의 약어로, 객체와 관계형 데이터베이스 간의 데이터 매핑을 자동화하는 프레임워크 또는 기술을 의미합니다. ORM은 객체 지향 프로그래밍 언어와 관계형 데이터베이스 간의 불일치를 해결하기 위해 사용됩니다.

관계형 데이터베이스는 테이블로 구성되어 있고, 데이터는 행과 열의 형태로 저장됩니다. 반면에 객체 지향 프로그래밍에서는 객체들이 상속, 연관 관계 등으로 구성되어 있고, 데이터는 객체의 속성으로 표현됩니다. 이렇게 객체와 테이블 간의 차이로 인해 데이터를 저장, 조회, 변경하기 위해서는 데이터베이스와 객체 사이에 변환 작업이 필요합니다.

 

https://yozm.wishket.com/magazine/detail/2160/

 

객체와 테이블 사이의 매핑 정보를 기반으로 자동으로 SQL 쿼리를 생성하고 데이터를 변환하여 객체에 매핑해줍니다. 이를 통해 개발자는 SQL 쿼리를 직접 작성하지 않고도 객체 지향 프로그래밍 방식으로 데이터를 다룰 수 있습니다.
ORM을 사용함으로써 개발자는 데이터베이스에 종속되지 않고 객체를 직접 다루므로 유지보수가 용이해지고 생산성이 향상됩니다. 또한 객체 지향적인 설계를 유지할 수 있어서 애플리케이션의 유지보수성과 확장성을 높일 수 있습니다.

ORM의 장단점을 살펴보겠습니다.

장점:

  1. 생산성 향상: ORM을 사용하면 개발자는 SQL 쿼리를 직접 작성하지 않아도 되므로 개발 시간이 단축되고 생산성이 향상됩니다. 객체 지향적인 코드로 데이터를 다룰 수 있어서 개발자가 비즈니스 로직에 집중할 수 있습니다.

  2. 유지보수성 증가: ORM은 데이터베이스 스키마와의 결합도를 낮추기 때문에 데이터베이스의 변경에 더 유연하게 대응할 수 있습니다. 데이터베이스 스키마의 변경이 필요할 때도 ORM 매핑만 수정하면 되므로 유지보수성이 증가합니다.

  3. 데이터베이스 독립성: ORM을 사용하면 데이터베이스의 종류에 상관없이 동일한 코드를 사용할 수 있어서 데이터베이스 독립성이 높아집니다. 애플리케이션이 다른 데이터베이스로 이전하더라도 비교적 쉽게 대응할 수 있습니다.

  4. 객체와 데이터베이스 간의 매핑 지원: ORM은 객체와 데이터베이스 간의 매핑을 자동으로 처리해주기 때문에 개발자가 직접 데이터 변환 작업을 하지 않아도 됩니다. 이를 통해 객체지향 설계를 그대로 유지할 수 있습니다.

단점:

  1. 성능 문제: ORM은 SQL 쿼리를 자동으로 생성해주지만, 때로는 개발자가 직접 최적화된 쿼리를 작성하는 것보다 성능이 떨어질 수 있습니다. 복잡한 쿼리를 처리할 때 성능 문제가 발생할 수 있으며, 이를 해결하기 위해서는 추가적인 튜닝이 필요할 수 있습니다.

  2. 학습 곡선: ORM을 처음 사용하는 개발자들은 ORM의 개념과 사용법을 익히는 데 시간이 걸릴 수 있습니다. ORM을 올바르게 이해하고 사용하기 위해서는 ORM의 동작 원리와 제공하는 기능들을 숙지해야 합니다.

  3. 복잡한 매핑: 일부 경우에는 복잡한 객체와 데이터베이스 간의 매핑이 필요할 수 있습니다. 특히 다대다 관계나 상속 관계 등을 매핑하는 것은 어려울 수 있습니다.

  4. 완벽한 대체물은 아님: ORM은 객체와 데이터베이스를 매핑해주는 유용한 기술이지만, 모든 상황에 완벽하게 대체물은 아닙니다. 특정 상황에서는 직접 SQL 쿼리를 작성하는 것이 더 효율적일 수 있습니다.

 


 

✅ Lombok

  • Lombok은 자바에서 반복적으로 작성해야 하는 코드들을 자동으로 생성해주는 라이브러리입니다. Lombok을 사용하면 @Getter, @Setter, @ToString, @EqualsAndHashCode, @Data 등의
    어노테이션을 사용하여 Getter/Setter 메서드, toString(), equals(), hashCode() 메서드 등을 자동으로 생성할 수 있습니다.

  • 또한, @NoArgsConstructor, @AllArgsConstructor, @RequiredArgsConstructor 등의 어노테이션을 사용하여 생성자를 자동으로 생성할 수도 있습니다.

Thymleaf

  • Thymeleaf는 서버 사이드 Java 템플릿 엔진으로, 웹 페이지를 동적으로 생성하는 데 사용됩니다. Thymeleaf는 HTML 파일 내에 Thymeleaf 템플릿 속성을 사용하여
    서버에서 전달한 데이터를 동적으로 삽입하거나 반복문, 조건문 등을 사용하여 웹 페이지를 동적으로 렌더링할 수 있습니다.

  • Spring Boot와 함께 사용하면 Spring Boot의 기능과 통합하여 편리하게 웹 애플리케이션을 개발할 수 있습니다.

Oracle DataBase

  • Oracle Database는 오라클이 개발한 관계형 데이터베이스 관리 시스템(RDBMS)입니다. Oracle Database를 사용하기 위해서는 해당 데이터베이스와의 연동을 위한 JDBC(Java Database Connectivity) 드라이버가 필요합니다.

  • ojdbc10은 오라클의 JDBC 드라이버 중 하나로, JDK 10 버전 이상을 지원합니다. Oracle Database와 Java 애플리케이션 간의 데이터베이스 연동을 위해 이 드라이버를 사용할 수 있습니다.
728x90
반응형
728x90

 

 

 

🎈 서블릿으로 회원 관리 웹 어플리케이션 만들기

 

👉 MemberForm 서블릿을 생성하여 회원을 등록할 수 있는 로직을 서블릿으로 작성

        -> 회원 등록용 html form을 서블릿을 통해서 볼 수 있도록 설정
        @WebServlet(name="memberFormServlet", urlPatterns = "/servlet/members/new-form")
        public class MemberFormServlet extends HttpServlet {

            private MemberRepository memberRepository = MemberRepository.getInstance();
                -> 싱글톤이므로 new로 생성할 수 없기 때문에 getInstance()를 사용

            @Override
            protected void service(HttpServletRequest request, HttpServletResponse response) 
                                                                    throws ServletException, IOException {

                     -> contentType과 Encoding을 설정
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");

                PrintWriter w = response.getWriter();
                w.write("<!DOCTYPE html>\n" +
                        "<html>\n" +
                        "<head>\n" +
                        " <meta charset=\"UTF-8\">\n" +
                        " <title>Title</title>\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "<form action=\"/servlet/members/save\" method=\"post\">\n" +
                        " username: <input type=\"text\" name=\"username\" />\n" +
                        " age: <input type=\"text\" name=\"age\" />\n" +
                        " <button type=\"submit\">전송</button>\n" +
                        "</form>\n" +
                        "</body>\n" +
                        "</html>\n");
            }
        }

 

위 코드에서 service 메서드는 HttpServlet 클래스의 메서드로, 클라이언트로부터 들어오는 모든 요청을 처리하는 역할을 합니다. 서블릿은 웹 애플리케이션에서 클라이언트와 서버 간의 통신을 담당하는 Java 클래스입니다.
서블릿은 HTTP 요청을 처리하여 동적인 웹 페이지를 생성하거나 데이터를 처리하는 데 사용됩니다.

HttpServlet 클래스는 GenericServlet 클래스를 상속받아서 만들어진 클래스로, HTTP 프로토콜을 사용하는 웹 애플리케이션에서 사용됩니다. HttpServlet 클래스의 service 메서드는
HTTP 요청 방식(GET, POST, PUT, DELETE 등)에 따라 적절한 메서드(doGet, doPost, doPut, doDelete 등)를 호출하여 요청을 처리합니다.

예제에서 보여준 service 메서드는 클라이언트로부터 들어오는 모든 요청을 처리하고 있습니다. 먼저 response 객체를 이용하여 HTTP 응답을 설정합니다.
response.setContentType("text/html")은 응답으로 보낼 데이터의 MIME 타입을 설정하는 것이며, 여기서는 HTML 데이터를 전송한다는 의미입니다. response.setCharacterEncoding("utf-8")은 응답 데이터의 인코딩 방식을 설정합니다.

그리고 PrintWriter를 이용하여 HTML 형식의 응답 데이터를 작성합니다. 해당 HTML은 간단한 폼(form)을 생성하고,
action 속성에 /servlet/members/save 경로로 요청을 보내도록 설정되어 있습니다. save로 이동되어 회원이 저장된 코드를 볼 수 있는 로직을 작성해보겠습니다.


👉 SaveServlet을 생성하여 가입하는 회원의 데이터를 저장할 수 있는 로직을 서블릿으로 작성

 

        @WebServlet(name="memberSaveServlet", urlPatterns = "/servlet/members/save")
        public class MemberSaveServlet extends HttpServlet {

            private MemberRepository memberRepository = MemberRepository.getInstance();

            @Override
          -> form 에서 전송된 데이터를 getParameter로 꺼낸 후 비즈니스 로직 작성을 위해 member를 만든 후 save 함
            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                System.out.println(" MemberSaveServlet.service ");
                String username = request.getParameter("username");
                int age = Integer.parseInt(request.getParameter("age"));

                Member member = new Member(username, age);
                memberRepository.save(member);

            -> 결과는 html 형식으로 출력하기 위해 response.set으로 타입 설정 후, Printwriter객체로 작성 
                response.setContentType("text/html");
                response.setCharacterEncoding("utf-8");
                PrintWriter w = response.getWriter();
                w.write("<html>\n" +
                        "<head>\n" +
                        " <meta charset=\"UTF-8\">\n" +
                        "</head>\n" +
                        "<body>\n" +
                        "성공\n" +
                        "<ul>\n" +
                        " <li>id="+member.getId()+"</li>\n" +
                        " <li>username="+member.getUsername()+"</li>\n" +
                        " <li>age="+member.getAge()+"</li>\n" +
                        "</ul>\n" +
                        "<a href=\"/index.html\">메인</a>\n" +
                        "</body>\n" +
                        "</html>");
            }
        }

 

🎈 JSP로 회원 관리 웹 어플리케이션 만들기

 

JSP(JavaServer Pages)동적 웹 페이지를 생성하는 데 사용되는 서버 사이드 기술입니다. JSP는 HTML 문서 안에 Java 코드를 삽입하여 웹 페이지를 동적으로 생성하고, 서버 측에서 로직을 처리할 수 있도록 지원합니다.

JSP는 Java 코드와 HTML 코드를 혼합하여 작성할 수 있으며, 서블릿과 매우 유사한 구조를 가지고 있습니다.
JSP 파일은 서블릿 클래스로 변환되어 실행됩니다. 웹 애플리케이션이 요청을 받으면 JSP 컨테이너가 해당 JSP 파일을 처리하여 자바 코드를 생성하고, 이 코드를 컴파일하여 서블릿 클래스를 생성한 뒤 실행합니다.

JSP의 주요 특징은 다음과 같습니다

  1. 간편한 웹 페이지 작성: JSP는 HTML과 유사한 태그를 사용하여 동적 웹 페이지를 작성할 수 있습니다. Java 코드는 <% %> 태그로 삽입하여 사용할 수 있으며, ${ } 태그를 이용하여 변수 값을 출력할 수 있습니다.

  2. 서버 사이드 로직 지원: JSP는 서버 사이드에서 데이터를 처리하고 동적으로 페이지를 생성하는데 사용됩니다. 사용자 입력을 받아 처리하거나 데이터베이스와 상호작용하는 등의 로직을 쉽게 구현할 수 있습니다.

  3. MVC 디자인 패턴과의 통합: JSP는 Model-View-Controller (MVC) 디자인 패턴과 함께 사용하기 쉽습니다. 데이터 처리는 서블릿이나 자바 빈(Java Bean)에서 처리하고, JSP는 뷰(View) 역할을 담당합니다.

JSP는 주로 웹 애플리케이션의 프론트엔드를 구현하는 데 사용되며, 동적인 컨텐츠를 생성하는 데 적합합니다. 그러나 비즈니스 로직이나 데이터 처리 로직과 같은 백엔드 부분은 주로 서블릿이나 다른 백엔드 기술을 활용하여 구현하는 것이 일반적입니다.

JSP를 사용하면 개발자들은 웹 프로그래밍을 좀 더 쉽게 시작할 수 있으며, 더 빠르게 동적인 웹 페이지를 구현할 수 있습니다. 그러나 복잡한 로직이나 규모가 큰 웹 애플리케이션을 개발할 때는
JSP의 한계를 극복하기 위해 프레임워크(Spring, Struts 등)나 템플릿 엔진(Thymeleaf, Freemarker 등)을 사용하는 경우가 많습니다.

 


 

💡 MVC 패턴

 

📋 MVC

MVC는 "Model-View-Controller"의 약자로, 소프트웨어 디자인 패턴 중 하나입니다. 웹 애플리케이션을 개발하는 데 널리 사용되며, 사용자 인터페이스와 비즈니스 로직을 분리하여 유지보수성과 확장성을 향상시키는 데 도움이 됩니다.

하나의 서블릿이나 JSP만으로 비즈니스 로직과 뷰 렌더링을 함께 처리하게 되면 너무 많은 역할을 가지고 있고, 유지보수가 어려워집니다. 비즈니스 로직을 호출하는 부분에 변경이 발생해도 해당 코드를 수정해야하고, UI를 변경할 일이 있어도 비즈니스 로직이 있는 파일을 수정해야 하는 번거로움이 발생합니다.

UI와 비즈니스로직의 변경의 라이프 사이클이 다르다는 점이 패턴으로 영역을 분리하게된 가장 큰 부분입니다. JSP 같은 뷰 템플릿은 화면을 렌더링하는 데 최적화 되어있기 때문에 해당 업무만 담당하는 것이 ㅏ장 효과적입니다.

컨트롤러 : HTTP 요청을 받아서 파라미터를 검증하고, 비즈니스 로직을 실행합니다. 그리고 뷰에 전달할 결과 데이터를 조회해서 모델에 담습니다.

모델 : 뷰에 출력할 데이터를 담아둡니다. 뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링 하는 일에 집중할 수 있습니다.

  • ModelHttpServletRequest 객체를 사용한다. request는 내부에 데이터 저장소를 가지고 있는데, request.setAttribute() , request.getAttribute() 를 사용하면 데이터를 보관하고, 조회할 수 있다.

뷰 : 모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중합니다 . 여기서는 HTML을 생성하는 부분입니다.

 

MVC 중 Controller 역할을 하는 class

        package hello.servlet.web.servletmvc;

        ★ 컨트롤러의 역할 
        @WebServlet(name="mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
        public class MvcMemberFormServlet extends HttpServlet {

            //mvc 패턴은 컨트롤러를 거쳐 뷰로 전달되기 때문에, memberForm을 보여주고 싶으려면 controller로 요청이 들어와야 함
            @Override
            protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

                String viewPath = "/WEB-INF/views/new-form.jsp"; //해당 jsp 파일로 이동하는 경로를 viewPath로 만들어줌
                RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);//컨트롤러에서 뷰로 이동할때 해당 경로로 이동할 수 있도록 해줌
                dispatcher.forward(request, response); // 다른 서블릿이나 JSP로 이동할 수 있는 기능 , 서버 내부에서 다시 호출이 발생
                                   // -> 리다이렉트로 이동하는 것이 아니라 서블릿 호출 -> jsp 호출 -> jsp에서 응답 만든 후 클라이언트에게 전송
            }
        }

         1. 고객의 요청이 오면 service 메서드가 호출된 후 viewPath의 jsp 경로를 호출함
         2. dispatcher.forward(request, response)로 서버 내부의 경로로 다시 호출
         3. new-form.jsp로 이동한 후 패당 view가 클라이언트에게 전달되어 보여

 

리다이렉트는 실제 클라이언트(웹 브라우저)에 응답이 나갔다가, 클라이언트가 redirect 경로로 다시 요청합니다. 따라서 클라이언트가 인지할 수 있고, URL 경로도 실제로 변경되는 반면에 포워드는 서버 내부에서 일어나는 호출이기 때문에 클라이언트가 전혀 인지하지 못합니다.

 

View 역할을 하게 될 jsp

 

        <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>

        <head>
            <meta charset="UTF-8">
            <title>Title</title>
        </head>
        <body>
        <!-- 상대경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
        <form action="save" method="post">
            username: <input type="text" name="username" />
            age: <input type="text" name="age" />
            <button type="submit">전송</button>

        </form>
        </body>
        </html

        WEB-INF내부에 있는 파일들은 외부에서 직접적으로 불러와지는 것이 아니라
        무조건 컨트롤러를 통해서 뷰가 호출될 수 있도록 설정할 수 있음 (WEB-INF 안에 넣어두면 됨!)
        ex)localhost:8080/WEB-INF/views/new-form.jsp url을 작성한다고 해도 호출되지 않음

 

mvc 패턴의 한계점

  1. 복잡성 : MVC 패턴은 애플리케이션을 세 가지 기능으로 분리하므로 각각의 역할을 확실하게 정의하고 구현해야 합니다. 이로 인해 프로젝트가 커질수록 컨트롤러, 뷰, 모델 간의 관계가 복잡해질 수 있습니다.

  2. 과도한 중재자 역할: 컨트롤러가 모든 요청을 중재하고 전달하므로 컨트롤러가 애플리케이션 내에서 중재자 역할을 맡게 됩니다. 이로 인해 컨트롤러가 비대해지고 유지보수가 어려워질 수 있습니다.

  3. 높은 결합도: MVC 패턴은 각 기능을 분리하지만 여전히 서로 간에 의존성이 존재합니다. 이로 인해 하나의 기능을 변경할 때 다른 기능에도 영향을 미칠 수 있습니다.

  4. 코드 중복: 여러 컨트롤러가 비슷한 기능을 구현해야 할 경우, 코드 중복이 발생할 수 있습니다. 이로 인해 유지보수가 어려워질 수 있습니다. View로 이동하는 코드가 항상 중복 호출되고, viewPath도 중복하여 작성되고 있습니다.

  5. 테스트의 어려움 : 컨트롤러는 외부 요청을 처리하므로 단위 테스트가 어려울 수 있습니다. 특히, 컨트롤러가 다른 컴포넌트와 강하게 결합되어 있을 경우 테스트하기 어려울 수 있습니다. 테스트 코드 작성시 HttpServletRequest , HttpServletResponse를 사용하는 코드는 테스트 케이스를 작성하기 어렵습니다.

  6. 공통부분 처리 어려움 : 단순하게 공통 기능을 하나의 메서드로 생성하면 될 것 같지만, 결과적으로는 해당 메서드를 항상 호출해야하고, 실수로 호출하지 않으면 문제가되고 해당 메서드를 반복해서 호출하는 것 또한 중복으로 호출이 됩니다.

해당 문제점을 해결하기 위해 컨트롤러 호출 전에 먼저 공통 기능을 처리하는 프론트 컨트롤러(Front Controller) 패턴을 도입하여 해당 문제를 해결할 수 있습니다.

 


 

💡 MVC 프레임 워크 만들기

프론트 컨트롤러 패턴이란 ❓

 

프론트 컨트롤러 패턴웹 애플리케이션의 디자인 패턴 중 하나로, 클라이언트의 모든 요청을 하나의 컨트롤러로 집중시켜 처리하는 패턴입니다.
프론트 컨트롤러도 하나의 서블릿이며, 이 서블릿 하나로 클라이언트의 요청을 받아서 해당 요청에 대한 처리를 담당하는 컨트롤러로서의 역할을 수행합니다. 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됩니다.

일반적으로 웹 애플리케이션은 여러 개의 컨트롤러로 이루어져 있으며, 각 컨트롤러는 특정한 요청을 처리하는 역할을 합니다. 하지만 프론트 컨트롤러 패턴에서는 클라이언트의 모든 요청이 먼저 프론트 컨트롤러로 집중되고, 프론트 컨트롤러가 각 요청에 맞는 적절한 컨트롤러를 호출하여 요청을 처리합니다.

프론트 컨트롤러의 특징

  1. 중앙 집중화 : 모든 클라이언트 요청을 하나의 프론트 컨트롤러로 집중시킴으로써 애플리케이션의 구조를 단순화합니다. 이로 인해 각 컨트롤러가 클라이언트 요청을 직접 처리하는 것이 아니라 프론트 컨트롤러를 통해 처리됩니다.

  2. 공통 로직 처리 : 프론트 컨트롤러에서는 모든 요청에 공통적으로 필요한 로직을 처리할 수 있습니다. 예를 들어, 로그인 여부 확인, 권한 검사, 국제화 등의 작업을 한 곳에서 처리할 수 있습니다.

  3. 중복 코드 제거 : 프론트 컨트롤러에서 공통 로직을 처리하므로 다른 컨트롤러에서 해당 로직을 중복해서 작성할 필요가 없어집니다. 이로 인해 코드의 중복성을 줄이고 유지보수가 용이해집니다.

  4. 유연한 확장성 : 새로운 기능이나 요청이 추가되더라도 프론트 컨트롤러만 수정하면 됩니다. 기존의 컨트롤러를 수정할 필요가 없기 때문에 애플리케이션의 확장성이 좋아집니다.

  5. 보안 강화 : 프론트 컨트롤러를 통해 모든 요청을 중앙에서 관리하기 때문에 보안 강화가 가능합니다. 애플리케이션의 보안 로직을 한 곳에서 관리하면서 보안에 대한 일관성을 유지할 수 있습니다.

  6. 코드 재사용성 : 공통 로직을 프론트 컨트롤러에서 처리하므로 다른 컨트롤러에서도 해당 로직을 재사용할 수 있습니다.

  7. 유지보수 용이성 : 프론트 컨트롤러 패턴을 사용하면 모든 요청이 한 곳에서 처리되기 때문에 유지보수가 용이해집니다. 추가 기능의 변경이나 버그 수정 등을 프론트 컨트롤러에서 처리하면 다른 컨트롤러의 코드를 건드릴 필요가 없습니다.

프론트 컨트롤러 패턴은 웹 애플리케이션의 구조를 더욱 효율적이고 유연하게 만들어주며, 중복 코드를 줄이고 보안을 강화하는 데에 도움이 됩니다. 스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현되어 있습니다.

728x90
반응형

'[ BACKEND] > Spring' 카테고리의 다른 글

[SPRING] Entity와 영속성  (0) 2023.08.06
[SPRING] ORM 그리고 JPA  (0) 2023.08.05
[SPRING] Storage (저장소) & URL 패턴  (0) 2023.08.03
[SPRING] Servlet / HTTP Request , Response  (0) 2023.08.02
[SPRING] Web Application  (0) 2023.07.31
728x90

 

 

 

 

 

 

HTTP의 특징 중 하나가 바로 상태정보를 저장하지 않는 (stateless) 라는건데, 데이터를 저장하기 위해 사용 목적에 따라 4개의 저장소로 나눌 수 있습니다.



👉 서버에서 사용하는 4개의 저장소

 

  1. 페이지 컨텍스트 저장소 (PageContext Storage): 페이지 컨텍스트 저장소는 JSP(JavaServer Pages)에서 사용되는 저장소입니다. 각 JSP 페이지의 실행에 대한 정보를 저장하고 공유하는 데 사용됩니다.
    페이지 컨텍스트는 JSP 페이지가 실행되는 동안에만 유효하며, 유효범위 또한 JSP 내부 시작부터 끝까지이고 페이지 간의 데이터 공유에 활용됩니다.

  2. 애플리케이션 저장소 (Application Storage) : 애플리케이션 저장소는 서버 애플리케이션의 전역적인 범위에서 데이터를 저장하는 저장소입니다. 서버가 실행되고 있는 동안 유지되며,
    모든 클라이언트 간에 공유됩니다. 애플리케이션 저장소는 ServletContext 객체를 통해 접근하고, 주로 애플리케이션의 설정 정보, 공통 데이터, 캐시 등을 저장하는 데 사용됩니다. 유효범위는 Servlet Context 전체입니다.

  3. 세션 저장소 (Session Storage) : 세션 저장소는 서버와 클라이언트 간에 상태 정보를 유지하기 위해 사용되는 저장소입니다. 각 클라이언트의 세션에 대한 데이터를 저장하고,
    클라이언트와의 연결이 유지되는 동안 데이터를 유지(편리성👍)합니다. 세션 저장소는 HttpSession 객체를 통해 접근하고, 로그인 정보, 장바구니 정보, 사용자 설정 등을 저장하는 데 사용됩니다.
    각 클라이언트마다 개별적으로 가지고 있는 저장소이기 때문에 메모리 부담이 큰 특징이 있습니다.

  4. 요청 저장소 (Request Storage): 요청 저장소는 클라이언트의 각 요청에 대한 데이터를 저장하는 저장소입니다. 각 요청이 처리되는 동안에만 유효하며, 해당 요청에 대한 응답이 완료되면 데이터는 삭제됩니다.
    요청 저장소는 HttpServletRequest 객체를 통해 접근하고, 해당 요청에 대한 파라미터, 헤더, 쿠키 등의 정보를 저장하는 데 사용됩니다. 데이터를 저장하고 전달하는데 가장 적절하고, 메모리 부담이 적습니다.

 


 

👉 URL 패턴

 

URL 패턴은 웹 애플리케이션에서 요청된 URL을 처리하기 위해 사용되는 패턴입니다. URL 패턴은 일반적으로 웹 애플리케이션의 라우팅 및 요청 처리를 제어하기 위해 사용됩니다.

@WebServlet을 사용하여 URL에 맵핑할 때 사용하합니다. Servlet은 기본적으로 laze init으로 늦은 초기화입니다. URL 맵핑에는 패턴의 종류가 4가지가 있으며, 아래에 나열된 순서대로 우선순위가 정해집니다.

  1. Exact Mapping (정확한 매핑) : 정확한 매핑은 URL 패턴과 서블릿 또는 핸들러 메서드의 경로가 정확히 일치해야 매핑이 이루어집니다. 예를 들어, URL 패턴이 "/hello"인 경우 "/hello" 요청과만 정확히 매핑됩니다. 다른 경로의 요청은 매핑되지 않습니다.

  2. Path Mapping (경로 매핑) : 경로 매핑은 URL 패턴에 와일드카드를 사용하여 여러 경로를 매핑할 수 있습니다. "" 와일드카드는 한 수준의 디렉토리 경로를 대체합니다. 예를 들어, URL 패턴이 "/users/"인 경우 "/users/abc", "/users/123", "/users/profile" 등 모든 "/users" 경로 하위의 요청과 매핑됩니다.

  3. Extension Mapping (확장자 매핑) : 확장자 매핑은 URL 패턴에 파일 확장자를 사용하여 특정 종류의 파일 요청을 매핑할 수 있습니다. 예를 들어, URL 패턴이 "*.html"인 경우 "/index.html", "/about.html", "/contact.html" 등의 HTML 파일 요청과 매핑됩니다. 일반적으로 정적 리소스(HTML, CSS, 이미지 등)를 처리할 때 사용됩니다.

  4. Default Mapping (기본 매핑) : 기본 매핑은 모든 요청에 대해 매핑되는 특별한 유형의 매핑입니다. 기본 매핑은 다른 모든 매핑이 실패한 경우 실행됩니다. 예를 들어, URL 패턴이 "/"인 경우 웹 애플리케이션의 루트에 대한 모든 요청과 매핑됩니다.

 

✍️ EL (Expression Language)

EL(Expression Language)은 JSP(JavaServer Pages)와 같은 웹 애플리케이션에서 데이터를 동적으로 표현하기 위해 사용되는 스크립팅 언어입니다. EL은 JSP 페이지에서 Java 코드를 작성하지 않고도 편리하게 데이터에 접근하고 조작할 수 있는 간결하고 강력한 표현 방식을 제공합니다.

  1. 변수 접근: EL을 사용하여 JSP 페이지에서 변수에 쉽게 접근할 수 있습니다. **${} 표기법을 사용**하여 변수 이름을 감싸고, 해당 변수의 값을 동적으로 출력할 수 있습니다.

  2. 프로퍼티 접근: EL을 사용하여 JavaBeans 객체의 프로퍼티에 접근할 수 있습니다. .(도트) 연산자를 사용하여 객체의 프로퍼티에 접근하고 값을 가져오거나 설정할 수 있습니다.

  3. 컬렉션 접근: EL을 사용하여 배열이나 List, Map 등의 컬렉션 객체에 접근할 수 있습니다. 인덱스나 키를 사용하여 컬렉션의 요소에 접근하고 값을 가져올 수 있습니다.

  4. 연산: EL은 산술 연산, 논리 연산, 비교 연산 등 다양한 연산을 지원합니다. 변수나 프로퍼티에 대한 연산을 수행하여 계산된 값을 가져올 수 있습니다.

  5. 조건문과 반복문: EL은 if-else 문이나 foreach 문과 같은 조건문과 반복문을 지원합니다. 데이터의 조건에 따라 특정 블록을 실행하거나 반복할 수 있습니다.

 

        Person person = new Person();
            request.setAttribute("person", person);
            request.setAttribute("name", "가나다");   
            request.setAttribute("list", new java.util.ArrayList());

            person.getCar().getColor()=<%=person.getCar().getColor()%> <br>
            person.getCar().getColor()=${person.getCar().getColor()} <br>
            person.getCar().getColor()=${person.car.color} <br>    

            name=<%=request.getAttribute("name")%> <br>   
            name=${requestScope.name} <br>
            name=${name} <br>

            id=<%=request.getParameter("id")%> <br>
            id=${pageContext.request.getParameter("id")} <br>

 

 

✍️ JSTL(JavaServer Pages Standard Tag Library)

JSTL(JavaServer Pages Standard Tag Library)은 JSP(JavaServer Pages)에서 자주 사용되는 태그들의 모음인 라이브러리입니다. JSTL은 JSP 페이지에서 보다 간편하고 효율적인 코드 작성을 위해 개발되었습니다.

  1. 제어 흐름 태그(Control Flow Tags): 조건문(if, choose), 반복문(forEach, forTokens), 분기문(switch) 등을 사용하여 동적인 제어 흐름을 구현할 수 있습니다.

  2. 데이터 처리 태그(Data Processing Tags): 변수 설정(set), 변수 출력(out), URL 생성 및 리다이렉트(redirect), 파라미터 전달(param) 등을 처리하는 태그들을 제공합니다.

  3. 데이터베이스 액세스 태그(Database Access Tags): JSTL을 사용하여 데이터베이스에 접근하고 데이터를 조회, 추가, 수정, 삭제할 수 있는 태그들을 제공합니다.

  4. 형식화 태그(Formatting Tags): 숫자, 날짜, 시간 등을 형식화하는 태그들을 제공하여 데이터를 보다 쉽게 형식화할 수 있습니다.
728x90
반응형

'[ BACKEND] > Spring' 카테고리의 다른 글

[SPRING] ORM 그리고 JPA  (0) 2023.08.05
[SPRING] Servlet / JSP / MVC  (0) 2023.08.04
[SPRING] Servlet / HTTP Request , Response  (0) 2023.08.02
[SPRING] Web Application  (0) 2023.07.31
[SPRING] 싱글톤 방식의 주의점 💥  (0) 2023.07.25

+ Recent posts