교육 (Today I Learned)/Hanaro

[Hanaro] 53일차 / Jar 생성, Bootstrap, H2 DB 연동, Spring Boot (JPA, JPQL, Native SQL)

Bay Im 2024. 4. 6. 12:24

Jar 파일 생성

  1. 인텔리제이 File - Project Structure
  2. Project Settings - Artifacts에서 + 버튼 누르고 Jar - From modules with dependencies… 클릭
  3. Main Class 선택 (psvm 있는 클래스 지정) 후 OK
  4. Build - Build Artifact에서 Action - Build 선택하면 jar 파일 생성 완료
  5. 마우스 오른쪽 누른 후 run 하거나, 터미널에서 java -jar jar파일명 입력 으로 실행

 

 

Bootstrap

  • html 코드 자동생성
    • ! 누르고 엔터
  • 부트스트랩 적용하기
    • head 태그 블록 안에 title 태그 바로 밑에 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> 붙여 넣기
    • body 태그 끝나는 줄 바로 위에 아래 코드넣기
      • ... 
            <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
            <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
        </body>
    • 부트스트랩의 모든 속성은 클래스 예약어(class=” “)로 지정된다.
  • 버튼
    • <button class="btn btn-primary">버튼</button>
    • 종류
      •     <button type="button" class="btn btn-primary">Primary</button>
            <button type="button" class="btn btn-secondary">Secondary</button>
            <button type="button" class="btn btn-success">Success</button>
            <button type="button" class="btn btn-danger">Danger</button>
            <button type="button" class="btn btn-warning">Warning</button>
            <button type="button" class="btn btn-info">Info</button>
            <button type="button" class="btn btn-light">Light</button>
            <button type="button" class="btn btn-dark">Dark</button>
            <button type="button" class="btn btn-link">Link</button>
  • 레이아웃
    • 화면 너비에 따른 중단점
      • xs - 576px미만
      • sm - 576px이상
      • md - 786px이상
      • lg - 992px이상
      • xl - 1200px이상
      • 예시
        •     <div class="container-sm">100% 너비: small 중단점까지</div>
              <div class="container-md">100% 너비: medium 중단점까지</div>
              <div class="container-lg">100% 너비: large 중단점까지</div>
              <div class="container-xl">100% 너비: extra large 중단점까지</div>
    • 레이아웃은 12 그리드 시스템 사용
      • 내부적으로 flex를 기본으로 사용
      • 화면의 한줄을 12칸으로 구분한다. (12가 넘으면 다음줄로 가버린다)
        • col-12
        • col-6 col-6
        • col-4 col-4 col-4
      • 예시
      •     <div class="container">
                <div class="row">
                    <div class="col-12">
                        col-12
                    </div>
                </div>
            </div>
            <div class="container-fluid">
                <div class="row">
                    <div class="col-12">
                        col-12
                    </div>
                </div>
            </div>
            <div class="container">
                <div class="row">
                    <div class="col-6">
                        col-6
                    </div>
                    <div class="col-6">
                        col-6
                    </div>
                </div>
            </div>
            <div class="container">
                <div class="row">
                    <div class="col-4">
                        col-4
                    </div>
                    <div class="col-4">
                        col-4
                    </div>
                    <div class="col-4">
                        col-4
                    </div>
                </div>
            </div>
    • container
      • 반응형으로 관리하는 부트스트랩 예약어 (창을 늘리면 같이 작아지거나 커지는)
      • 화면너비가 중단점에 따라 나누어 떨어진다.
    • container-fluid
      • 화면너비에 따라서 같이 커지나 작아진다. (창을 늘려도 고정되는 )
    • row
      • 12그리드에서 1행을 의미한다.
    • display
      • none
        • d-none
          • 해당 자리가 옆의 값으로 대체
        • invisible
          • 내용만 보이지 않는다.
      • block
        • d-sm-block
          • sm 사이즈 일때만 보이도록 한다.
      • inline
      • inline-block
  • 아코디언
    • 내용 접기/펼치기 가능
  • 캐러셀
    • 이미지, 텍스트 슬라이드

 

 

H2 DB 연결

  • 자바 프로젝트에서 데이터베이스에 접근하는 방법 4가지
    • JDBC Driver Class
      • Connection, Statement, ResultSet
    • JDBC Template Class
    • MyBatis(iBatis)
      • XML에 SQL을 넣어서 사용
    • JPA
      • SQL을 사용하지 않는다.
  • 스프링부트 H2 데이터베이스 연결 방법
    • dependencies
      • runtimeOnly 'com.h2database:h2' 추가
    • application.properties 추가
      • # H2 Database
        # H2 DB 콘솔화면을 활성화
        spring.h2.console.enabled=true
        
        # H2 DB 콘솔화면 경로 (localhost:8080/h2-console)
        spring.h2.console.path=/h2-console
        
        # in-memory DB로 설정한다.
        spring.datasource.url=jdbc:h2:mem:testdb
        spring.datasource.driver-class-name=org.h2.Driver
        
        # file DB
        #spring.datasource.url=jdbc:h2:~/testdb
        #spring.datasource.driver-class-name=org.h2.Driver
  • 스프링부트 JPA 연결 방법
    • dependencies
      • implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 추가
    • application.properties
      • # Datasource JPA
        spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
        spring.jpa.hibernate.ddl-auto=create
        
        # show JPA generated SQL
        spring.jpa.show-sql=true
        # pretty sql format
        spring.jpa.properties.hibernate.format_sql=true
        # binding parameter show
        logging.level.org.hibernate.type.descriptor.sql=trace
    • spring.jpa.hibernate.ddl-auto= 종류
      • none
        • 아무것도 안함
      • create
        • 엔티티 클래스대로 테이블 생성
      • create-drop
        • create 옵션과 동일하나 종료 시점에 테이블을 DROP 한다.
      • update
        • 테이블이 없다면 생성, 변경사항이 있다면 업데이트
      • validate
        • 테이블 생성 및 업데이트는 하지않고, 검사만 한다.
  • 스프링부트 H2 데이터베이스 테이블 생성 방법
    1. resources 폴더 안에 db.sql 추가
      • 예시
        • -- 회원가입 DB 만들기
          -- H2 Database SQL
          
          -- 테이블 삭제
          DROP TABLE IF EXISTS member CASCADE;
          
          -- 테이블 생성 (H2 DB SQL 문법으로 작성)
          CREATE TABLE member (
              id bigint generated by default as identity,
              user_id varchar(255),
              user_pw varchar(255),
              user_name varchar(255),
              user_role varchar(255),
              joindate date default CURRENT_TIMESTAMP()
          );
          
          -- ROW 추가
          INSERT INTO member VALUES (1, 'hong', '1234', '홍길동', 'ROLE_USER', '2023-09-09');
          INSERT INTO member VALUES (2, 'tom', '1234', '톰아저씨', 'ROLE_USER', '2023-09-09');
          INSERT INTO member VALUES (3, 'admin', '1234', '관리자', 'ROLE_ADMIN', '2023-09-09');
          
          -- 검색
          SELECT * FROM member;
          
          -- 커밋하기 (실제 물리적으로 파일에 쓰기)
          commit;
    2. 엔티티 클래스 생성
      • 엔티티 클래스위에 @Entity 어노테이션 추가
      • @Table(name=”테이블명”) 어노테이션 추가
      • 테이블의 컬럼명 그대로 멤버 변수 작성
        • id (또는 primary key 컬럼) 멤버변수 위에 @Id, @GeneratedValue(strategy = GenerationType.IDENTITY) 어노테이션 추가
        • 나머지 멤버 변수는 @Column(name=”컬럼명”) 어노테이션 추가
        • 날짜 관련 멤버 변수가 있다면 @DateTimeFormat(pattern = “yyyy-mm-dd”) 어노테이션 추가하여 날짜 형식 지정
      • 엔티티 클래스에 @Getter 어노테이션 추가 (@Setter 사용은 비추천)
      • @Builder, @AllArgsConstructor, @NoArgsConstructor 어노테이션 추가
  • DB 관련 어노테이션
    • @Entity
      • DB 테이블과 1:1로 매칭되는 JPA 클래스
    • @Table
      • 클래스 이름이 테이블 이름으로 자동으로 설정되는데, 이럴때 테이블명 직접 지정할 때 사용
    • @Id
      • 기본키 id 열로 사용
    • @GeneratedValue(strategy = GenerationType.IDENTITY)
      • GenerationType 종류
        • IDENTITY
          • MySQL, MariaDB, PostreSQL, H2DB
        • SEQUENCE
          • Oracle, PostreSQL
        • AUTO
          • 자동 선택
    • @Column(name=”컬럼명”)
      • 해당 멤버 변수의 컬럼명 지정
    • @DateTimeFormat(pattern = “yyyy-mm-dd”)
      • Date 데이터를 가져올 때 날짜 형식 사용자 지정 가능
      • @RequestParam @ModelAttribute 매핑
    • @JsonFormat
      • @RequestBody @ResposeBody 매핑
  • 데이터 모델링 클래스 종류
    • Entity 클래스
      • DB 테이블과 Entity 클래스는 1:1 매칭(연결)
      • 로직 코드를 작성하면 안된다.
      • JPA에서 사용한다.
    • DTO 클래스 (Data Transfer Object)
      • 다른 계층 간에 데이터 교환을 위해 데이터를 변형하여 사용하는 객체
      • 로직 코드를 가지고 있지 않고, 순수하게 getter/setter로 이루어져 있다.
      • 엔티티 클래스에 있는 모든 멤버변수(컬럼)을 사용할 필요없이 원하는 컬럼만 담는 DTO를 만들어 사용할 수 있다.
    • VO 클래스 (Value Object)
      • DTO 클래스와 동일한 개념이지만 Getter만 가지는 Read Only의 속성을 갖고있다.
    • DAO 클래스 (Data Access Object)
      • DB에 실제 접근하여 CRUD 하는 객체를 말한다.
      • JPA의 Repository를 사용하는 경우를 말한다.

 

 

Spring Boot (JPA, JPQL, Native SQL)

  • JpaRepository
    • 스프링 JPA 라이브러리에서 Entity에 대한 기본적인 CRUD가 가능하도록 만든 인터페이스
  • Repository
    • JpaRepository를 상속받아 엔티티Repository 인터페이스를 생성한다. (@Repository 어노테이션 추가)
  • JPA
    • Repository에서 작성하는 SQL문 자동 실행되는 함수
    • JPA 기본 함수 종류
      • finaAll()
        • SELECT * FROM 테이블명 을 실행
      • findBy열이름()
        • SELECT 열이름 FROM 테이블명 을 실행
        • 예시
          • findById((long)2) ⇒ SELECT * FROM 테이블명 WHERE id=2;
          • findByUser_id(”hong”) ⇒ SELECT * FROM 테이블명 WHERE user_id = ‘hong’;
      • save()
        • 테이블 값(row) 추가/업데이트
        • INSERT문과 UPDATE문 동시 실행
        • id 값을 보고 없으면 추가하고, 있으면 수정한다.
      • delete()
        • DELETE 문 실행
      • count()
        • SELECT COUNT(*) FROM 테이블명 을 실행
    • JPA 사용자 함수
      • Repository에서 사용자가 직접 패턴에 맞는 메소드 이름을 작성하여 SQL문 자동 실행하는 메서드를 만들 수 있다.
      • 메소드 이름의 패턴
        • find + By + 필드이름 + And + 필드이름
        • And, Or을 메소드 이름에 추가 가능
        • OrderBy와 Desc, Asc 추가 가능
        • First5, Last5 같이 n개로 개수 제한을 할 수 있다.
        • 예시
          • List<MemberEntity> findFirst5ByUserIdAndUserNameOrderByIdDesc(String userId, String userName);
            • SQL문으로 SELECT * FROM member where user_id = :userId AND user_name = :userName ORDER BY id DESC LIMIT 5; 와 같다.
    • JPA 쿼리 메소드 공식 레퍼런스
  • JPA에서 SQL을 사용하는 방법
    • JPQL
      • 표준 ANSI SQL 문법을 지원한다. 특정 데이터베이스에 종속적인 기능은 지원하지 않는다.
      • DB에 직접적인 쿼리를 실행하지 않으며 엔티티 테이블에 매핑하여 사용한다.
      • @Query(value=”SQL 문 작성”) 어노테이션을 추가하여 작성한다.
      • FROM 절 뒤에는 엔티티 클래스 이름을 넣어준다. (테이블명이 아닌 클래스이름!)
      • 예시
        • @Query(value = "SELECT m FROM MemberEntity m WHERE m.userId = :userid")
          List<MemberEntity> findByUserId_JPQL_Query(String userid);​
          • 매개변수의 userid가 쿼리의 :userid에 대입하여 검색한다.
          • 매개변수는 @Param(”userid”) String userid같이 입력 값도 가져올 수 있다.
    • Native SQL
      • DB에 직접적으로 쿼리를 실행시켜 속도가 빠르다. 여러 조인이나 복잡한 쿼리 작성 시 적합
      • @Query(value=”SQL 문 작성”, nativeQuery = true) 어노테이션을 추가하여 작성한다.
      • 추가로 UPDATE, INSERT, DELETE 문은 @Modifying, @Transactional 어노테이션을 추가해야 한다.
      • 예시
        •     @Query(value = "SELECT * FROM member WHERE user_id = :userid",
                      nativeQuery = true)
              List<MemberEntity> findByUserId_nativeQuery(String userid);
          
              @Modifying
              @Transactional
              @Query(value = "UPDATE member SET user_id = :userid where id = :id",
                      nativeQuery = true)
              int updateById_nativeQuery(Long id, String userid);
  • JPA 사용하여 테이블 열 추가 및 조회 방법
    1. Repository 인터페이스 생성
      • JpaRepository<엔티티클래스명, Long>을 상속(extends)하여 엔티티Repository 인터페이스 생성
      • 인터페이스 위에 @Repository 어노테이션 추가
      • 예시
        • @Repository public interface MemberRepository extends JpaRepository<MemberEntity, Long> { }
    2. Controller 클래스 생성
      • 위에서 생성한 Repository 인터페이스 생성자 주입
        • private final 엔티티Repository 엔티티Repository;
      • Controller 클래스 위에 @Controller, @RequiredArgsConstructor 어노테이션 추가
      • save(), findAll() 등 Repository의 함수 사용
      • 예시
        • @Controller
          @RequiredArgsConstructor
          public class MainController {
              private final MemberRepository memberRepository;
          
              @GetMapping("/")
              public String main(Model model) {
          	      // 테이블 값(row) 추가 (save와 new 사용)
                  memberRepository.save(new MemberEntity(Long.valueOf(1), "hong", "1234", "홍길동", "ROLE_USER", LocalDate.now()));
                  memberRepository.save(new MemberEntity(Long.valueOf(2), "tom", "1234", "톰아저씨", "ROLE_USER", LocalDate.now()));
                  memberRepository.save(new MemberEntity(Long.valueOf(3), "admin", "1234", "관리자", "ROLE_ADMIN", LocalDate.now()));
          			
          				// 테이블의 전체 값 리스트에 추가 (findAll 사용)
                  List<MemberEntity> list = memberRepository.findAll();
                  
                  model.addAttribute("list", list);
                  return "index";
              }
          }
    3. html 생성
      • 컨트롤러에서 addAttribute 한 리스트 전체값 출력하기
      • 타임리프 th:each 문 사용하여 리스트 값 전체 출력
      • 예시
        • <!DOCTYPE html>
          <html lang="ko" xmlns:th="http://www.thymeleaf.org">
          <head>
              <meta charset="UTF-8">
              <title>Title</title>
              <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
          </head>
          <body>
              <h2>회원목록</h2>
              <table class="table">
                  <thead>
                      <tr>
                          <th scope="col">번호</th>
                          <th scope="col">ID</th>
                          <th scope="col">아이디</th>
                          <th scope="col">비밀번호</th>
                          <th scope="col">이름</th>
                          <th scope="col">권한</th>
                          <th scope="col">가입일</th>
                      </tr>
                  </thead>
                  <tbody>
                      <tr th:each="member, status: ${list}">
                          <td><span th:text="${status.count}"></span></td>
                          <td><span th:text="${member.id}"></span></td>
                          <td><span th:text="${member.user_id}"></span></td>
                          <td><span th:text="${member.user_pw}"></span></td>
                          <td><span th:text="${member.user_name}"></span></td>
                          <td><span th:text="${member.user_role}"></span></td>
                          <td><span th:text="${member.joindate}"></span></td>
                      </tr>
                  </tbody>
              </table>
          
              <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" crossorigin="anonymous"></script>
              <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous"></script>
          </body>
          </html>

 

 

728x90