반응형

💡 SQL을 추상화한 JPQL

JPA : ORM(Object-Relational Mapping) 프레임워크

JPQL(Java Persistence Query Language)

JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공합니다.

따라서 테이블을 대상으로 쿼리 하는 것이 아닌 엔티티 객체를 대상으로 쿼리합니다.

JPQL은 SQL을 추상화했기 때문에 특정 데이터베이스 SQL에 의존하지 않는 장점이 있습니다.

JPQL은 SQL과 문법이 유사하며, SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN을 지원합니다.


💡 쿼리메소드를 사용한 쿼리문 만들기

✅ TODO 1) 전체 조회 + 정렬(내림차순)

📂 DeptRepository.java

package com.example.jpacustomexam.repository;

import com.example.jpacustomexam.model.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.repository
 * fileName : DeptRepository
 * author : GGG
 * date : 2023-10-17
 * description : 부서 레포지토리 (기본 CRUD 함수)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
    // 개발자가 직접 SQL 작성 하는 기능(JPQL) : 1) 쿼리메소드
    //                                      2) @Query 쓰는 방법
    // todo: 1) 전체조회 + 정렬(내림차순)
    List<Dept> findAllByOrderByDnoDesc();
}

📂 DeptService.java

package com.example.jpacustomexam.service;

import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.repository.DeptRepository;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.service
 * fileName : DeptService
 * author : GGG
 * date : 2023-10-17
 * description : 부서 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Service
public class DeptService {
    @Autowired
    DeptRepository deptRepository;

    /** 전체조회 + 정렬(dno 내림차순) */
    // todo) 쿼리메소드를 사용한 함수
    public List<Dept> findAllByOrderByDnoDesc(){
        List<Dept> list = deptRepository.findAllByOrderByDnoDesc();
        return list;
    }
}

 

📂 DeptController.java

package com.example.jpacustomexam.controller;

import com.example.jpacustomexam.model.Dept;
import com.example.jpacustomexam.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * packageName : com.example.jpacustomexam.controller
 * fileName : DeptController
 * author : GGG
 * date : 2023-10-17
 * description : 부서 컨트롤러 (리액트 용)
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-17         GGG          최초 생성
 */
@Slf4j
@RestController
public class DeptController {
    @Autowired
    DeptService deptService;    // DI

    /** 전체 조회 + 정렬(dno 내림차순) */
    @GetMapping("/dept/desc")
    public ResponseEntity<Object> getDeptAllDesc(){
        try {
            // todo : 전체 조회 + 정렬(dno 내림차순)함수 호출
            List<Dept> list = deptService.findAllByOrderByDnoDesc();
            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

 

✔ 서버 재시작 후 API 테스트 

부서번호가 내림차순으로 정렬된 것을 알 수 있습니다.

1) 쿼리메소드 : 함수이름으로 sql문 생성

예) findAllByOrderByDnoDesc

findAllByOrderByDnoDesc
findAll 전체조회
OrderBy 정렬
Dno 대상컬럼명
Desc 내림차순

 

💡 JPA의 쿼리메소드 샘플은 다음과 같습니다.

출처:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods         

Distinct findDistinctByLastnameAndFirstname select distinct …​ where x.lastname = ?1 and x.firstname = ?2
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is, Equals findByFirstname,findByFirstnameIs,findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull, Null findByAge(Is)Null … where x.age is null
IsNotNull, NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstname) = UPPER(?1)

✅ TODO 2) 전체 조회 + 정렬(내림차순) - 부서명으로 내림차순, 부서번호 오름차순

📂 DeptRepository.java 추가

    // todo: 2) 전체조회 + 정렬(부서명 내림차순)
    List<Dept> findAllByOrderByDnameDesc();

    // todo: 3) 전체조회 + 정렬(부서번호 오름차순) : Asc 생략가능
    List<Dept> findAllByOrderByDno();
}

📂 DeptService.java 추가

/** 전체조회 + 정렬(dname 내림차순) : 쿼리메소드 */
public List<Dept> findAllByOrderByDnameDesc(){
    List<Dept> list = deptRepository.findAllByOrderByDnameDesc();
    return list;
}

/** 전체조회 + 정렬(dno 오름차순) : 쿼리메소드 */
public List<Dept> findAllByOrderByDno(){
    List<Dept> list = deptRepository.findAllByOrderByDno();
    return list;
}

📂 DeptController.java 추가

 /** 전체 조회 + 정렬(dname 내림차순) */
    @GetMapping("/dept/dname/desc")
    public ResponseEntity<Object> findAllByOrderByDnameDesc(){
        try {
            // todo : 전체 조회 + 정렬(dno 내림차순)함수 호출
            List<Dept> list = deptService.findAllByOrderByDnameDesc();
            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    /** 전체 조회 + 정렬(dno 오름차순) */
    @GetMapping("/dept/dno/asc")
    public ResponseEntity<Object> findAllByOrderByDno(){
        try {
            // todo : 전체 조회 + 정렬(dno 내림차순)함수 호출
            List<Dept> list = deptService.findAllByOrderByDno();
            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

✔ 서버 재시작 후 API 테스트 

1) 전체조회 - 부서이름으로 내림차순

2) 전체조회 - 부서번호 오름차순

✅ TODO 3) 전체조회 + dname(부서명) like 검색 + dname 내림차순 조회

📂 DeptRepository.java 추가

// todo: 4) dname like 검색(DnameContaining)+ dname 내림차순 조회
List<Dept> findAllByDnameContainingOrderByDnameDesc(String dname);

📂 DeptService.java 추가

/** dname(부서명) like 검색 + dname 내림차순 조회 */
public List<Dept> findAllByDnameContainingOrderByDnameDesc(String dname){
    List<Dept> list 
            = deptRepository.findAllByDnameContainingOrderByDnameDesc(dname);
    return list;
}

📂 DeptController.java 추가

 /** 전체조회 + dname(부서명) like 검색 + dname 내림차순 조회 */
    @GetMapping("/dept/dname/containing/desc/{dname}")
    public ResponseEntity<Object> findAllByDnameContainingOrderByDnameDesc(
            @PathVariable String dname
    ){
        try {
            // todo : 전체 조회 + 정렬(dno 내림차순)함수 호출
            List<Dept> list
                    = deptService
                    .findAllByDnameContainingOrderByDnameDesc(dname);
            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

✔ 서버 재시작 후 API 테스트 

1) 전체조회 - 부서명 like 검색 + dname 내림차순 조회

✅ TODO 4) 쿼리메소드 응용 연습문제

// todo) 응용연습
//    todo: 응용 연습문제 
//    todo: 연습 4) EMP 테이블에서 Job 이 manager 이고
//              매개변수로 부서번호(dno)를 받는 함수를 작성하세요.

//    todo: 연습 5) Emp 테이블에서 salary 가 1000 ~ 1500 사이의 값을 같는
//     사원을 조회하려고 합니다.  함수를 작성해 주세요
더보기

📂 EmpRepository.java

 

List<Emp> findAllByJobAndDno(String job, int dno);

List<Emp> findAllBySalaryBetween(int first, int last);

📂 EmpService.java

//    todo: 연습 4) EMP 테이블에서 Job 이 manager 이고
//              매개변수로 부서번호(dno)를 받는 함수를 작성하세요.
public List<Emp> findAllByJobAndDno(String job, int dno){
    List<Emp> list = empRepository.findAllByJobAndDno(job, dno);
    return list;
}

//    todo: 연습 5) Emp 테이블에서 salary 가 1000 ~ 1500 사이의 값을 같는
//     사원을 조회하려고 합니다.  함수를 작성해 주세요
public List<Emp> findAllBySalaryBetween(int first, int last){
    List<Emp> list = empRepository.findAllBySalaryBetween(first, last);
    return list;
}

📂 EmpController.java

  /** 연습 4) : 쿼리메소드 */
    @GetMapping("/emp/dno/{dno}")
    public ResponseEntity<Object> findAllByEnameContaining(
            @PathVariable int dno
    ) {
        try {
//         전체 조회 + 정렬(dno 내림차순) 호출
            List<Emp> list
                    = empService.findAllByJobAndDno("MANAGER", dno);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 연습5 */

    @GetMapping("emp/salary/{first}/{last}")
    public ResponseEntity<Object> findAllBySalaryBetween(@PathVariable int first, @PathVariable int last){
        try {
            List<Emp> list
                    = empService.findAllBySalaryBetween(first, last);
            if(list.isEmpty() == false){
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

✔ 서버 재시작 후 API 테스트 

연습 4)

 

연습 5)

[
  {
    "insertTime": "2023-10-17 06:38:45",
    "updateTime": null,
    "eno": 7521,
    "ename": "WARD",
    "job": "SALESMAN",
    "manager": 7698,
    "hiredate": "1981-02-22 00:00:00",
    "salary": 1250,
    "commission": 500,
    "dno": 30
  },
  {
    "insertTime": "2023-10-17 06:38:45",
    "updateTime": null,
    "eno": 7654,
    "ename": "MARTIN",
    "job": "SALESMAN",
    "manager": 7698,
    "hiredate": "1981-09-28 00:00:00",
    "salary": 1250,
    "commission": 1400,
    "dno": 30
  },
  {
    "insertTime": "2023-10-17 06:38:45",
    "updateTime": null,
    "eno": 7844,
    "ename": "TURNER",
    "job": "SALESMAN",
    "manager": 7698,
    "hiredate": "1981-09-08 00:00:00",
    "salary": 1500,
    "commission": 0,
    "dno": 30
  },
  {
    "insertTime": "2023-10-17 06:38:45",
    "updateTime": null,
    "eno": 7876,
    "ename": "ADAMS",
    "job": "CLERK",
    "manager": 7788,
    "hiredate": "1987-07-13 00:00:00",
    "salary": 1100,
    "commission": null,
    "dno": 20
  },
  {
    "insertTime": "2023-10-17 06:38:45",
    "updateTime": null,
    "eno": 7934,
    "ename": "MILLER",
    "job": "CLERK",
    "manager": 7782,
    "hiredate": "1982-01-23 00:00:00",
    "salary": 1300,
    "commission": null,
    "dno": 10
  }
]
응답 파일이 저장되었습니다.
> 2023-10-17T153953.200.json

Response code: 200; Time: 25ms (25 ms); Content length: 933 bytes (933 B)

💡 @Query 이용한 쿼리문 작성

데이터베이스에서 값을 가져올 때는 위의 코드처럼 메서드의 이름만으로 쿼리 메서드를 생성할 수 도 있습니다.

이번에는 @Query 어노테이션을 사용해 직접 JPQL을 작성해봅시다.

 

📂 DeptRepository.java

    //    ----------------------------------------
    //    @Query 예제
    //    1) 오라클 쿼리
    //    2) 객체 쿼리
    //    ----------------------------------------
    //    todo 1) ename like 검색
    @Query(value = "SELECT TD.* FROM TB_EMP TD WHERE TD.ENAME LIKE '%' || :dname || '%'", nativeQuery = true)
    List<Emp> selectByEname(@Param("ename") String ename);

위 코드를 다르게 작성하는 방법(JDK 버전에 따라 사용 불가능할 수도 있음)

//    todo: 1-1) 위의 코드를 다르게 코딩
    @Query(value = "SELECT TD.* FROM TB_DEPT TD WHERE TD.DNAME LIKE '%'||:dname||'%'",
            nativeQuery = true)
    List<Dept> selectByDname(String dname);
//    todo: 1-2) 위의 코드를 다르게 코딩 : 참고
@Query(value = "SELECT TD.* FROM TB_DEPT TD WHERE TD.DNAME LIKE '%'|| ?1 ||'%'",
        nativeQuery = true)
List<Dept> selectByDname(String dname);

✅ SQL에서 쿼리문 결과가 올바른지 확인

📂 DeptService.java

/** 전체조회 + dname like 검색 : @Query */
public List<Dept> selectByDname(String dname) {
    List<Dept> list
            = deptRepository.selectByDname(dname);

    return list;
}

📂 DeptController.java

 /** 전체조회 + dname like 검색 : @Query */
    @GetMapping("/dept/dname/{dname}")
    public ResponseEntity<Object> selectByDname(
            @PathVariable String dname
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Dept> list
                    = deptService.selectByDname(dname);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

✅ 실행결과

부서명 중에 'S'가 들어가는 부서명 검색하기

GET http://localhost:8000/dept/dname/S

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 18 Oct 2023 00:11:16 GMT
Keep-Alive: timeout=60
Connection: keep-alive

[
  {
    "insertTime": "2023-10-18 00:11:06",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS"
  },
  {
    "insertTime": "2023-10-18 00:11:06",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO"
  },
  {
    "insertTime": "2023-10-18 00:11:06",
    "updateTime": null,
    "dno": 40,
    "dname": "OPERATIONS",
    "loc": "BOSTON"
  }
]
응답 파일이 저장되었습니다.
> 2023-10-18T091116.200.json

Response code: 200; Time: 277ms (277 ms); Content length: 295 bytes (295 B)

✅ 객체쿼리를 이용한 쿼리문 작성

//    todo: 2) dname like 검색 (객체 쿼리)
    // 객체 쿼리 만드는 방법 : 테이블 -> 클래스명
    //                      컬럼명 -> 속성명
    //                      * -> 사용하지 않음, 클래스명의 별칭을 붙여서 사용
    //                      (대소문자를 구분함, nativeQuery=true(생략))
    @Query(value = "SELECT TD FROM Dept TD WHERE TD.dname LIKE '%'||:dname||'%'")
    List<Dept> selectByDname(@Param("dname") String dname);

 

✅ TODO) 부서 테이블에서 부서명(dname)과 위치(loc)를 매개변수로 받아 조회하는 함수 만들기

📂 DeptRepository.java

@Query(value = "SELECT D.* FROM TB_DEPT D " +
        "WHERE D.DNAME = :dname " +
        "AND   D.LOC = :loc ", nativeQuery = true)
List<Dept> selectByDnameAndLoc(@Param("dname") String dname,@Param("loc") String loc);

📂 DeptService.java

/** 전체조회 + dname like 검색 : @Query */
public List<Dept> selectByDnameAndLoc(String dname, String loc) {
    List<Dept> list
            = deptRepository.selectByDnameAndLoc(dname, loc);

    return list;
}

📂 DeptController.java

    /** 전체조회 + dname like 검색 : @Query */
    @GetMapping("/dept/dname/{dname}/loc/{loc}")
    public ResponseEntity<Object> selectByDnameAndLoc(
            @PathVariable String dname,
            @PathVariable String loc
    ) {
        try {
//         전체 조회 + 정렬(dno 오름차순) 호출
            List<Dept> list
                    = deptService.selectByDnameAndLoc(dname, loc);

            if (list.isEmpty() == false) {
//                성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
//                데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }

        } catch (Exception e){
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

 

반응형

'Spring Boot > 스프링부트 예제' 카테고리의 다른 글

JPA - 연관관계 매핑  (0) 2023.10.19
JPA 페이징 처리  (1) 2023.10.18
JPA 상세조회, 저장함수, 수정함수, 삭제함수  (0) 2023.10.17
JPA를 활용한 CRUD 구현하기  (0) 2023.10.16
JSTL 라이브러리  (0) 2023.10.06
반응형

이전 블로그 글 : https://devjunyeok.tistory.com/181

 

JPA를 활용한 CRUD 구현하기

안녕하세요! 이번 시간에는 JPA 를 활용한 예제 프로젝트를 생성해보겠습니다. 들어가기 전에 JPA의 특징으로는 SQL문을 자동생성하는 것이 특징입니다. 💡 프로젝트 준비 및 환경설정 프로젝트

devjunyeok.tistory.com

📂 DeptService.java

package com.example.jpaexam.service;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * packageName : com.example.jpaexam.service
 * fileName : DeptService
 * author : GGG
 * date : 2023-10-16
 * description : 부서 업무 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Service
public class DeptService {

    @Autowired
    DeptRepository deptRepository; // DI 객체 가져오기

    /** 전체조회 */
    public List<Dept> findAll() {
        List<Dept> list = deptRepository.findAll(); // db 전체조회 함수 호출
        return list;
    }

    /** 상세조회(1건조회) */
    public Optional<Dept> findById(int dno) {
        Optional<Dept> optionalDept = deptRepository.findById(dno);

        return optionalDept;
    }

    /** 저장(수정)함수 */
    public Dept save(Dept dept) {
//      todo: jpa 저장함수 호출 ( 기본키 없으면 insert, 있으면 update )
        Dept dept2 = deptRepository.save(dept);

        return dept2; // 저장된 부서객체
    }

    /** 삭제함수 */
    public boolean removeById(int dno){
        // todo : existsById : jpa 함수 - 리턴값 있으면 true, 없으면 false
        if(deptRepository.existsById(dno)) {
            deptRepository.deleteById(dno); // db 삭제(dno)
            return true;
        }
        return false;
    }


}

📂 DeptController.java

package com.example.jpaexam.controller.exam01;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

/**
 * packageName : com.example.jpaexam.controller.exam01
 * fileName : DeptController
 * author : GGG
 * date : 2023-10-16
 * description : 부서 컨트롤러 : @RestController 사용
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Slf4j
@RestController
@RequestMapping("/exam01")
public class DeptController {

    @Autowired
    DeptService deptService;    // 객체 가져오기 (DI)

    /** 전체조회 함수 */
    @GetMapping("/dept")
    public ResponseEntity<Object> getDeptAll() {
        try {
            // todo) 전체조회 함수 호출
            List<Dept> list = deptService.findAll();
            if (list.isEmpty() == false) {
                // todo) 성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
                // todo) 데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 상세 조회 함수 */
    @GetMapping("/dept/{dno}")
    public ResponseEntity<Object> getDeptId(@PathVariable int dno){
        try {
            // todo) 전체조회 함수 호출
            Optional<Dept> optionalDept = deptService.findById(dno);
            if (optionalDept.isEmpty() == false) {
                // todo) 성공
                return new ResponseEntity<>(optionalDept.get(), HttpStatus.OK);
            } else {
                // todo) 데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 저장함수 */
    @PostMapping("/dept")
    public ResponseEntity<Object> createDept(@RequestBody Dept dept){
        try {
            // todo : jap 서비스 저장함수 호출 : dept2(DB 저장된 객체)
            Dept dept2 = deptService.save(dept);
            return new ResponseEntity<>(dept2, HttpStatus.OK);
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 수정함수 */
    @PutMapping("/dept/edit/{dno}")
    public ResponseEntity<Object> updateDept(@RequestBody Dept dept, @PathVariable int dno){
        try {
            // todo : jap 서비스 수정함수 호출 : dept2(DB 저장된 객체)
            Dept dept2 = deptService.save(dept);
            return new ResponseEntity<>(dept2, HttpStatus.OK);
        } catch (Exception e) {
            log.debug(e.getMessage());
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    /** 삭제함수 */
    @DeleteMapping("/dept/delete/{dno}")
    public ResponseEntity<Object> deleteDept(
            @PathVariable int dno
    ){
        try {
            // todo) 삭제 함수 호출
            boolean bSuccess = deptService.removeById(dno);
            if (bSuccess == true) {
                // todo) 삭제성공
                return new ResponseEntity<>(HttpStatus.OK);
            } else {
                // todo) 0건 삭제(삭제할 대상이 없을경우)
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

}

📌 실행해보기

1) 상세조회

부서번호 10번을 조회

2) 저장함수

임의의 값을 지정해서 저장하기

저장함수 테스트시 기본키(dno)와 insertTime, updateTime 제외하고 입력

3) 수정함수

부서번호 10번 조회 - updateTime과 dname, loc가 수정된 것을 알 수 있습니다.

 

4) 삭제함수 - 부서번호 10번 삭제하기

전체조회해서 10번 부서에 해당하는 데이터가 삭제되었는지 확인

 

반응형
반응형

안녕하세요!

이번 시간에는 JPA 를 활용한 예제 프로젝트를 생성해보겠습니다.

 

들어가기 전에

JPA의 특징으로는 SQL문을 자동생성하는 것이 특징입니다.

 

💡 프로젝트 준비 및 환경설정


프로젝트 준비시 스프링부트의 종속성을 추가합니다.

생성 후 시간이 소요됩니다.

 

한글 깨짐 방지를 위해 설정 - 에디터 - 파일 인코딩 부분에 UTF-8로 변경해줍니다.

build.gradle 파일의 dependencies 부분에  오라클과 logback, log4jdbc 종속성을 추가해줍니다.

	//   todo: 오라클 라이브러리( 19c )
	implementation 'com.oracle.database.jdbc:ucp:19.14.0.0'
	implementation 'com.oracle.database.security:oraclepki:19.14.0.0'
	implementation 'com.oracle.database.security:osdt_cert:19.14.0.0'
	implementation 'com.oracle.database.security:osdt_core:19.14.0.0'
	//   todo: logback , log4jdbc 설정
	implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
	implementation 'ch.qos.logback:logback-classic:1.2.11'
	implementation 'org.slf4j:slf4j-api:1.7.36'
	implementation 'org.slf4j:jcl-over-slf4j:1.7.36'

 

 

그리고 main > resources > application.properties 파일에 설정을 추가합니다.

# 서버 포트
server.port=8000


# todo : docker db 설정
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy

# todo : spring.datasource.url=jdbc:log4jdbc:oracle:thin:@ip주소:db포트번호/db이름
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xepdb1

spring.datasource.username=scott
spring.datasource.password=!Ds1234567890

# todo : jpa 설정
# todo : ddl-auto - create(모든 테이블 재생성)/update(수정된 테이블만 생성)/none(안함)
spring.jpa.hibernate.ddl-auto=create
#spring.jpa.hibernate.ddl-auto=update
#spring.jpa.hibernate.ddl-auto=none

# todo : db 제품 연결 ( oracle 12 이상 : Oracle12cDialect )
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect

# todo : generate-ddl=true (테이블 자동 생성 옵션)
spring.jpa.generate-ddl=true

# todo : sql log 보기 (true/false)
spring.jpa.show-sql=true

# 1) resource/data.sql 자동 실행 ( DML 실행 )
#  -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
# todo : DML, DDL 스크립트 (실습용 샘플 테이블) 실행을 위한 옵션
spring.jpa.defer-datasource-initialization=true

# todo :  sql log 좀 더 정리된 형태로 찍기
spring.jpa.properties.hibernate.format_sql=true

# todo : 로깅 레벨 : error < info < debug < trace (정보 많은 순서)
logging.level.org.hibernate=info

# 2)  resource/data.sql 자동 실행 ( DML 실행 )
#  -> data.sql ( dml 실행 ), schema.sql ( ddl 실행 )
spring.sql.init.mode=always

# sql 에러 무시하고 스프링 서버 로딩
spring.sql.init.continue-on-error=true


# 자바 소스 변경시 스프링 서버 자동 재시작
spring.devtools.restart.enabled=true

# PUT , DELETE 방식도 form 에서 사용할 수 있게 만들어줌 : jsp에서 사용함
spring.mvc.hiddenmethod.filter.enabled=true

실습을 위해 resources 폴더 아래에 4가지 파일을 추가합니다.

 

📂 data.sql

INSERT INTO TB_DEPT VALUES (10,'ACCOUNTING','NEW YORK',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_DEPT VALUES (20,'RESEARCH','DALLAS',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_DEPT VALUES (30,'SALES','CHICAGO',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_DEPT VALUES (40,'OPERATIONS','BOSTON',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);

INSERT INTO TB_EMP VALUES (7369,'SMITH','CLERK',    7902,TO_CHAR(to_date('17-12-1980','dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),800, NULL,20, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7499,'ALLEN','SALESMAN', 7698,TO_CHAR(to_date('20-2-1981', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1600, 300,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7521,'WARD','SALESMAN',  7698,TO_CHAR(to_date('22-2-1981', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1250, 500,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7566,'JONES','MANAGER',  7839,TO_CHAR(to_date('2-4-1981',  'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),2975,NULL,20, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7654,'MARTIN','SALESMAN',7698,TO_CHAR(to_date('28-9-1981', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1250,1400,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7698,'BLAKE','MANAGER',  7839,TO_CHAR(to_date('1-5-1981',  'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),2850,NULL,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7782,'CLARK','MANAGER',  7839,TO_CHAR(to_date('9-6-1981',  'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),2450,NULL,10, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7788,'SCOTT','ANALYST',  7566,TO_CHAR(to_date('13-07-1987','dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),3000,NULL,20, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7839,'KING','PRESIDENT', NULL,TO_CHAR(to_date('17-11-1981','dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),5000,NULL,10, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7844,'TURNER','SALESMAN',7698,TO_CHAR(to_date('8-9-1981',  'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1500,   0,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7876,'ADAMS','CLERK',    7788,TO_CHAR(to_date('13-07-1987','dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1100,NULL,20, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7900,'JAMES','CLERK',    7698,TO_CHAR(to_date('3-12-1981', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),950, NULL,30, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7902,'FORD','ANALYST',   7566,TO_CHAR(to_date('3-12-1981', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),3000,NULL,20, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);
INSERT INTO TB_EMP VALUES (7934,'MILLER','CLERK',   7782,TO_CHAR(to_date('23-1-1982', 'dd-mm-yyyy'), 'YYYY-MM-DD HH24:MI:SS'),1300,NULL,10, TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), NULL);


INSERT INTO TB_FAQ VALUES (1,'제목','해결방법',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_FAQ VALUES (2,'제목2','해결방법2',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_FAQ VALUES (3,'제목3','해결방법3',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);
INSERT INTO TB_FAQ VALUES (4,'제목4','해결방법4',  TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'), null);

COMMIT;

📂log4jdbc.log4j2.properties

# sql \uB85C\uADF8 \uC124\uC815
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
# \uCD5C\uB300 \uBA87 \uB77C\uC778\uAE4C\uC9C0 \uCD9C\uB825\uD560 \uAC83\uC778\uAC00\uB97C \uACB0\uC815 : 0 \uC774\uBA74 \uC81C\uD55C\uC5C6\uC74C
log4jdbc.dump.sql.maxlinelength=0

📂 logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">

    <!-- Appenders -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
          <Pattern>%d %5p [%c] %m%n</Pattern>
       </encoder>
    </appender>

    <appender name="console-infolog" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
          <Pattern>%d %5p %m%n</Pattern>
       </encoder>
    </appender>

    <!-- Logger -->
    <logger name="com.example.jpaexam" level="DEBUG" appender-ref="console" />
    <logger name="jdbc.sqlonly" level="INFO" appender-ref="console-infolog" />
    <logger name="jdbc.resultsettable" level="INFO" appender-ref="console-infolog" />

    <!-- Root Logger : 기본 OFF -->
<!--    하위 로거에서 재정의해서 사용함 : INFO, DEBUG 등으로 -->
    <root level="off">
       <appender-ref ref="console" />
    </root>
</configuration>

📂 shema.sql

DROP SEQUENCE SQ_DEPT;
CREATE SEQUENCE SQ_DEPT START WITH 50 INCREMENT BY  10;

DROP SEQUENCE SQ_EMP;
CREATE SEQUENCE SQ_EMP START WITH 8000 INCREMENT BY  1;

DROP SEQUENCE SQ_FAQ;
CREATE SEQUENCE SQ_FAQ START WITH 1 INCREMENT BY  1;

DROP TABLE TB_EMP CASCADE CONSTRAINT;
DROP TABLE TB_DEPT CASCADE CONSTRAINT;
DROP TABLE TB_FAQ CASCADE CONSTRAINT;

CREATE TABLE TB_DEPT (
                         DNO NUMBER NOT NULL PRIMARY KEY,
                         DNAME VARCHAR2(255),
                         LOC VARCHAR2(255),
                         INSERT_TIME VARCHAR2(255),
                         UPDATE_TIME VARCHAR2(255)
);

CREATE TABLE TB_EMP
(ENO NUMBER NOT NULL PRIMARY KEY,
 ENAME VARCHAR2(255),
 JOB   VARCHAR2(255),
 MANAGER  NUMBER,
 HIREDATE VARCHAR2(255),
 SALARY NUMBER,
 COMMISSION NUMBER,
 DNO NUMBER,
 INSERT_TIME VARCHAR2(255),
 UPDATE_TIME VARCHAR2(255)
);

CREATE TABLE TB_FAQ (
                        NO NUMBER NOT NULL PRIMARY KEY,
                        TITLE VARCHAR2(255),
                        CONTENT VARCHAR2(255),
                        INSERT_TIME VARCHAR2(255),
                        UPDATE_TIME VARCHAR2(255)
);

 

그리고 java > com.example.jpaexam 폴더 아래에 다음과 같이 폴더를 생성합니다.

 

💡 model 폴더에 공통모델 파일 생성


 

model 폴더 아래에 생성일자/수정일자를 만들어주는 추상클래스를 생성합니다.

실습에서는 파일명을 BaseTimeEntity 로 생성하였습니다.

📂 model > BaseTimeEntity.java

1) 먼저 추상클래스 위에 어노테이션 3개를 추가합니다.

package com.example.jpaexam.model;

import lombok.Getter;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;

/**
 * packageName : com.example.jpaexam.model
 * fileName : BaseTimeEntity
 * author : GGG
 * date : 2023-10-16
 * description : JPA 에서 자동으로 생성일자/수정일자를 만들어주는 클래스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Getter
// todo : 자동으로 생성일자/수정일자 컬럼을 sql 문에 추가시키는 어노테이션 2개
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
    // todo) 공통 속성
    private  String insertTime;
    private  String updateTime;
}

 

여기서 @MappedSuperclass 어노테이션의 의미는

생성일자/수정일자를 모든 엔티티에 공통으로 가져가야하는 상황에서 위의 코드처럼

BaseTimeEntity를 정의해서 활용할 때 사용합니다.

 

2) 공통 속성의 형태를 변경하는 함수 추가

위의 코드는 time의 형태가 yyyy-MM-dd HH:mm:ss 형태가 아닌 기본 형태로 보이게 됩니다.

가독성을 좋게하기 위해 공통속성 코드 아래에 함수를 추가합니다.

 

...
private String updateTime;

// todo) 해당 테이블에 데이터가 만들어 질 때(insert 문) 실행되는 이벤트 함수
@PrePersist
void OnPerPersist(){
    this.insertTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

}
// todo) 해당 테이블에 데이터가 수정될 때(update 문) 실행되는 이벤트 함수
@PreUpdate
void OnPreUpdate(){
    this.updateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    this.insertTime = this.updateTime; // 생성일시 == 수정일시 동일하게 처리
}

 

💡 Dept 모델 생성


model 폴더 아래에 Dept 클래스를 생성합니다.

JPA에서 사용하는 어노테이션의 설명은 아래 코드에 todo로 표시되어있습니다.

📂 model > Dept.java

package com.example.jpaexam.model;

import lombok.*;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

import javax.persistence.*;

/**
 * packageName : com.example.jpaexam.model
 * fileName : Dept
 * author : GGG
 * date : 2023-10-16
 * description : 부서 모델 클래스 ( 엔티티(entity) )
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
// todo) @Entity - JPA 기능을 클래스에 부여하는 어노테이션
@Entity
// todo) @Table(name = "생성될 테이블명")
@Table(name = "TB_DEPT")
// todo 사용법 : @SequenceGenerator(
//        name = "시퀀스 함수 이름"
//        , sequenceName = "DB에 생성된 시퀀스 이름"
//        , initialValue = 시작값
//        , allocationSize = jpa에서 관리용숫자(성능지표)
//  )
@SequenceGenerator(
        name = "SQ_DEPT_GENERATOR"
        , sequenceName = "SQ_DEPT"
        , initialValue = 1
        , allocationSize = 1
)
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
// todo) JPA 어노테이션 SQL 자동 생성시 null 값 컬럼은 제외하고 생성하는 어노테이션
//  예) insert into 테이블명(컬럼1, 컬럼2, 컬럼3) values(1, 2, null)
//    => insert into 테이블명(컬럼1, 컬럼2) values(1, 2)
@DynamicInsert
@DynamicUpdate
public class Dept extends BaseTimeEntity{
    @Id // todo) 기본키임을 알려주는 어노테이션
    // todo) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "시퀀스함수이름")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_DEPT_GENERATOR") // 시퀀스 기능 부여
    // todo : @Column(columnDefinition = "DB컬럼 자료형")
    @Column(columnDefinition = "NUMBER")
    private Integer dno;    // 부서번호(기본키) - 시퀀스 기능 부여

    @Column(columnDefinition = "VARCHAR2(255)")
    private String dname;   // 부서명

    @Column(columnDefinition = "VARCHAR2(255)")
    private String loc;     // 부서위치
}

 

repository 파일 만들기

DB 접속 함수들(CRUD)을 만들어주기 위한 인터페이스 파일을 생성합니다.

📂 repository > DeptRepository.java 

package com.example.jpaexam.repository;

import com.example.jpaexam.model.Dept;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * packageName : com.example.jpaexam.repository
 * fileName : DeptRepository
 * author : GGG
 * date : 2023-10-16
 * description : JPA 레포지토리 인터페이스 (DB 접속 함수들(CRUD) 있음)
 *                  == DAO랑 비슷함
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
// todo) @Repository - 클래스위에 붙이고, 스프링서버가 실행될 때 자동으로 객체 1개를 만들어줌( IOC )
//    사용법 : 인터페이스명 extends JpaRepository<모델클래스명, 기본키의 자료형>
@Repository
public interface DeptRepository extends JpaRepository<Dept, Integer> {
}

JpaRepository를 상속받으면 DB접속에 사용할 수 있는 CRUD함수 기능을 사용할 수 있습니다.

 

💡 업무 service 클래스 생성

📂 service > DeptService.java

package com.example.jpaexam.service;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.repository.DeptRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * packageName : com.example.jpaexam.service
 * fileName : DeptService
 * author : GGG
 * date : 2023-10-16
 * description : 부서 업무 서비스
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Service
public class DeptService {
    
    @Autowired
    DeptRepository deptRepository;  // DI 객체 가져오기
    
    /** 전체 조회 */
    public List<Dept> findAll(){
        List<Dept> list = deptRepository.findAll(); // db 전체조회 함수 호출
        return list;
    }
    
}

 

💡 controller 생성

📂 controller > DeptController

package com.example.jpaexam.controller.exam01;

import com.example.jpaexam.model.Dept;
import com.example.jpaexam.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * packageName : com.example.jpaexam.controller.exam01
 * fileName : DeptController
 * author : GGG
 * date : 2023-10-16
 * description : 부서 컨트롤러 : @RestController 사용
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-16         GGG          최초 생성
 */
@Slf4j
@RestController
@RequestMapping("/exam01")
public class DeptController {

    @Autowired
    DeptService deptService;    // 객체 가져오기 (DI)

    /** 전체조회 함수 */
    @GetMapping("/dept")
    public ResponseEntity<Object> getDeptAll() {
        try {
            // todo) 전체조회 함수 호출
            List<Dept> list = deptService.findAll();
            if (list.isEmpty() == false) {
                // todo) 성공
                return new ResponseEntity<>(list, HttpStatus.OK);
            } else {
                // todo) 데이터 없음
                return new ResponseEntity<>(HttpStatus.NO_CONTENT);
            }
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

REST API 테스트를 위해 아래 그림의 빨간색 박스를 누릅니다.

테스트 창에서 ▶ 버튼을 눌러 실행합니다.

실행결과

GET http://localhost:8000/exam01/dept

HTTP/1.1 200 
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 16 Oct 2023 08:15:45 GMT
Keep-Alive: timeout=60
Connection: keep-alive

[
  {
    "insertTime": "2023-10-16 08:15:40",
    "updateTime": null,
    "dno": 10,
    "dname": "ACCOUNTING",
    "loc": "NEW YORK"
  },
  {
    "insertTime": "2023-10-16 08:15:40",
    "updateTime": null,
    "dno": 20,
    "dname": "RESEARCH",
    "loc": "DALLAS"
  },
  {
    "insertTime": "2023-10-16 08:15:40",
    "updateTime": null,
    "dno": 30,
    "dname": "SALES",
    "loc": "CHICAGO"
  },
  {
    "insertTime": "2023-10-16 08:15:40",
    "updateTime": null,
    "dno": 40,
    "dname": "OPERATIONS",
    "loc": "BOSTON"
  }
]
응답 파일이 저장되었습니다.
> 2023-10-16T171545.200.json

Response code: 200; Time: 297ms (297 ms); Content length: 397 bytes (397 B)

JPA에서 자동으로 만든 select 문을 확인해봅시다.

Hibernate: 
    select
        dept0_.dno as dno1_0_,
        dept0_.insert_time as insert_time2_0_,
        dept0_.update_time as update_time3_0_,
        dept0_.dname as dname4_0_,
        dept0_.loc as loc5_0_ 
    from
        tb_dept dept0_

 

반응형
반응형

💡 Core 라이브러리

JSTL의 core 라이브러리를 사용하기 위해서는 JSP 파일 상단에 코드를 선언합니다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

📖 <c:set> : 변수에 값을 저장

변수저장소(사용범위)
page(현재페이지) < request < session < application(전체프로그램)
사용법 : <c:set var="변수명" value="값" scope="page"(scope는 생략가능, 기본이 page)/>

📌 사용 예제

<%--     TODO : jstl 표현식--%>
        <p><c:set var="num" value="10" scope="page"/></p>
        <p><c:set var="num2" value="10" scope="page"/></p>
        <p><c:set var="total" value="${num + num2}" scope="page"/></p>
<%--     TODO : el 표현식--%>
        <p>${num}</p>
        <p>${num2}</p>
        <p>${total}</p>

📌 결과

📖 <c:forTokens> : 문자열 구분자로 구분하여 전체 출력하기

사용법 : 
<c:forTokens items="문자열" delims="구분자" var="변수명">
         실행문
</c:forTokens>

📌 사용예제

<c:forTokens items="1/2/3" delims="/" var="number">
    <h2>토큰 : ${number}</h2>
</c:forTokens>

📌 실행결과

📖 <c:catch> : try ~ catch 예외처리

사용법 : 
<c:catch var="에러변수"> 실행문 </c:catch>
실행문이 에러 발생하면 에러변수에 메세지가 들어감

📌 사용예제

<c:set var="num3" value="20" />
<c:catch var="err">
    <h2>${num3}</h2>
</c:catch>
<c:if test="${not empty err}">
    에러 메세지 : ${err.message}
</c:if>

📌 실행결과

📖 <c:redirect> : 페이지 강제이동

<c:redirect url="이동할_url주소" />

 

📖 <c:import> : 공통페이지 끼워 넣기

<c:import url="보여줄페이지" />

📌 사용예제

📖 <c:url> : url로 페이지 이동하기

<c:url value="url주소" var="변수명" />
[사용]
<a href="${변수명}">표시할내용</a>

📌 사용예제

 

💡 Function 라이브러리

fn 라이브러리를 사용하기전 상단 코드 선언

fn 라이브러리는 el 표현식과 함께 사용합니다.

<%--TODO: fn lib import--%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>

<%-- TODO: fmt lib import--%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

📌 변수 선언

<c:set var="chars" value="안녕하세요 홍길동입니다. Bye"/>
<c:set var="name" value="홍길동"/>

 

📖 fn:contains(string, substr)

string이 substr을 포함하면 return true 없으면 false return

<h2>indexOf : ${fn:indexOf(chars,"홍길동")}</h2>

📖 fn:indexOf(string, substr)

string 문자열에 "substr" 값이 있는 index 번호를 return

<h2>indexOf : ${fn:indexOf(chars,"홍길동")}</h2>

📖 fn:length(string)

전체 길이를 리턴

<h2>length : ${fn:length(chars)}</h2>

📖 fn:replace(string, "기존문자열", "바꿀문자열")

string 문자열에서 기존문자열을 바꿀문자열로 변경

<h2>replace : ${fn:replace(chars,"홍길동","장길산")}</h2>

📖 fn:split(string, 구분자)

string에서 구분자로 문자열 자르기, 리턴은 배열

<h2><c:set var="sChar" value='${fn:split(chars, "")}'/></h2>
<h2>${sChar[0]}</h2>
<h2>${sChar[1]}</h2>
<h2>${sChar[2]}</h2>

📖 fn:substring(string, 시작인덱스번호, 끝인덱스번호)

string 문자열에서 시작인덱스에서 끝인덱스번호-1까지 자르기

<h2>substring : ${fn:substring(chars,0 ,6)}</h2>

📖 fn:toLowerCase/toUpperCase(string)

대소문자 바꾸기

<h2>toLowerCase : ${fn:toLowerCase(chars)}</h2>
<h2>toUpperCase : ${fn:toUpperCase(chars)}</h2>

 

💡 fmt(format) 라이브러리

fmt 라이브러리는 날짜,시간, 숫자 텍스트를 포멧하고 표시하는 fomatter 기능을 제공합니다.

 

📌 변수선언

<c:set var="numtest" value="1234567890"/>

📖 fmt:formatNumber : 세 자리마다 쉼표(,) 추가하여 출력

<h2><fmt:formatNumber value="${numtest}"/> </h2>

1) 숫자에 통화 추가 : value 뒤에 type="currency" 추가

<h2>formatNumber : <fmt:formatNumber value="${numtest}" type="currency"/></h2>

📖 날짜 포멧 주기

날짜 포멧을 주기위해서는 스크립틀릿을 사용합니다. 스크립틀릿은 과거 코딩기법이라 사용은 하지 않습니다.

<%

  자바코딩 가능

 %>

 <%
        Date date = new java.util.Date();
    %>
<%--       TODO: 화면 출력시 : <%=변수명%>--%>
    <h2><%=date%></h2>
    <c:set var="today" value="<%=new java.util.Date()%>" />
    <h2><fmt:formatDate value="${today}" pattern="yyyy-MM-dd hh:mm:ss" /> </h2>

반응형
반응형

💡 파라미터 방식

앞 전 예제에서는 쿼리스트링 방식으로 매개변수를 전달하였습니다. 이번에는 쿼리스트링 방식을 개선한 파라미터 방식의 매개변수 전달 방법에 대해 알아보겠습니다.

 

📂PathVariableController.java

@Controller
@RequestMapping("/exam05")
public class PathVariableController {
//    TODO : url 테스트 파라미터 방식 : http://localhost:8000/exam05/path-variable/LeeJunHyuk
//                                  => @GetMapping("/path-variable/{웹매개변수명}")
//                                  => 웹 브라우저 주소창 사용 : url/값
//    TODO : url 테스트 쿼리스트링 방식 : http://localhost:8000/exam05/path-variable?name=LeeJunHyuk
    @GetMapping("/path-variable/{name}")
    public String getPathVariable(
            @PathVariable String name,
            Model model)
    {
        model.addAttribute("name", name);
        return "exam05/path_variable.jsp";
    }
}

📂path_variable.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<%-- TODO : el 표현식--%>
    <p>${name}</p>
</body>
</html>

파라미터 형식의 매개변수 전달방법은

@GetMapping("url/{웹매개변수명}") 으로 사용하고 메소드 매개변수로 @PathVariable를 사용한 것을 알 수 있습니다.

 

📌 실행결과

반응형
반응형

💡 Lombok 라이브러리

Lombok 라이브러리는 유용한 어노테이션을 모은 라이브러리입니다.

다음 예제 실습을 위한 몇 가지 롬북 어노테이션을 소개합니다.

//   @Setter : setter 함수를 만들어주는 어노테이션
//   @Getter : getter 함수를 만들어주는 어노테이션
//   @ToString : toString 재정의 함수 자동으로 만들어주는 어노테이션
//   @AllArgsConstructor : 모든 속성을 가진 생성자 자동 정의 어노테이션

먼저 실습을 하기 위해 아래와 같이 폴더를 구성합니다.

com.example.controllerexam 폴더 아래에 model 폴더를 생성합니다.

📂 model > Member.java

package com.example.controllerexam.model;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


@Setter
@Getter
@ToString
@AllArgsConstructor
public class Member {
//    TODO : 속성, 생성자 함수(getter/setter)
    String id;      // 회원 id
    String name;    // 회원 이름
}

Lombok 어노테이션을 사용함으로써 코드가 간결해집니다.

 

📂 ObjectParamController.java

package com.example.controllerexam.controller.exam04;

import com.example.controllerexam.model.Member;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * packageName : com.example.controllerexam.controller.exam04
 * fileName : ObjectParamController
 * author : GGG
 * date : 2023-10-05
 * description : @ModelAttribute : 객체 형태로 변환하는 어노테이션
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-05         GGG          최초 생성
 */
@Controller
@RequestMapping("/exam04")
public class ObjectParamController {
//    TODO : URL TEST ) http://localhost:8000/exam04/object-param?id=junyeoke&name=lee
//     @ModelAttribute : 객체의 속성명으로 jsp로 각각 전달
//     Member 클래스의 속성명 == url의 매개변수명 : id, name
    @GetMapping("/object-param")
    public String getObjectParam(
            @ModelAttribute Member member){
        return "exam04/object_param.jsp";
    }
}

 

 

@ModelAttribute는 사용자가 요청시 전달하는 값을 오브젝트 형태로 매핑해주는 어노테이션입니다.

 

📂 object_param.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<%--    TODO : 매개변수 받기 --%>
    <h2>매개변수 받기</h2>
    <p>${member}</p>
</body>
</html>

 

📌 결과출력

반응형
반응형

💡 JSP의 조건문, URL 매개변수에 3개를 전달해서 조건에 따라 출력하기

📂 MultiParamController.java

   TODO : 예제 3) JSP의 조건문, URL 매개변수 3개를 전달해서 조건에 따라 출력하기
//     URL 테스트 : http://localhost:8000/exam03/condition?name=삼식이&color=brown&kind=dog
    @GetMapping("/condition")
    public String setCondition(Model model,
                               @RequestParam(defaultValue = "") String name,
                               @RequestParam(defaultValue = "") String color,
                               @RequestParam(defaultValue = "") String kind)
    {
        model.addAttribute("name", name);
        model.addAttribute("color", color);
        model.addAttribute("kind", kind);
        return "/exam03/condition.jsp";
    }
}

📂 condition.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <h2>매개변수(파라메터) 전달받아 출력하기</h2>
        <p>${name}</p>
        <p>${color}</p>
        <p>${kind}</p>

<%--        TODO : if 조건문으로 출력하기: jstl 표현식, else 없음 사용--%>
<%--         사용법 : <c:if test="${조건식}">실행문</c:if>--%>
        <c:if test="${name == '삼식이'}">
            <p>삼식이가 맞습니다.</p>
        </c:if>
    </div>
</body>
</html>

✅ JSP의 if 조건문

JSP에서 if 조건문을 사용할 경우에는 JSTL 표현식을 사용합니다. 사용법은 아래와 같습니다.

<c:if test="${조건식}> 실행문 </c:if>

단 JSP의 if 조건문은 JAVA에서 처럼 else구문이 따로 없는것이 특징입니다.

 

그럼 else 구문을 사용하려면 어떻게 해야할까요?

 

✅ JSP의 choose 조건문

choose 조건문은 JAVA의 if ~ else if 구문과 비슷합니다.

 

JAVA의 else 구문과 같은 의미인 otherwise가 있습니다.

 

📌 choose 조건문

<%--        TODO : choose 조건문으로 출력하기, else 있음--%>
        <c:choose>
            <c:when test="${color == 'brown'}">
                갈색입니다.
            </c:when>
            <c:when test="${color == 'yellow'}">
                노란색입니다.
            </c:when>
            <c:otherwise>
                다른색입니다.
            </c:otherwise>
        </c:choose>

📌 사용법

// TODO: choose 조건문으로 출력하기 , else 있음

사용법 
<c:choose>
(if, else if): <c:when test="조건문">실행문</c:when>
(else): <c:otherwise>실행문</c:otherwise>
</c:choose>

📌 출력결과

반응형
반응형

💡 ArrayList 형태의 View에서의 출력

📂 MulitParamController.java

@GetMapping("/hello-array")
public String setHelloArray(Model model,
                            @RequestParam(defaultValue = "") String name,
                            @RequestParam(defaultValue = "") String id)
{
    List<String> list = new ArrayList<>();
    list.add(name);
    list.add(id);

    model.addAttribute("list",list);
    return "exam03/hello_array.jsp";
}

setHelloArray 메서드 내에서 문자열 형태의 ArrayList를 생성합니다.

그리고 .add() 를 사용하여 RequestParam의 변수를 넣어줍니다.

 

📂 hello_array.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>예제 2) URL 매개변수를 ArrayList 로 View에 전달</h2>
    <p>${list}</p>

    <table class="table">
        <thead>
        <tr>
            <th scope="col">id</th>
            <th scope="col">name</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <%--    TODO: JSP 반복문 : jstl 표현식 사용    --%>
<%--                  <c:forEach var="일반변수" items="${배열}">   --%>
            <c:forEach var="data" items="${list}">
                <td>${data}</td>
            </c:forEach>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

내용을 깔끔하게 보이게 하기 위해 부트스트랩의 테이블 소스를 사용하였습니다.

JSP에서의 반복문은 JSTL 표현식을 사용합니다.

<c:forEach var="변수명" items="${배열}">
${변수명}
</c:forEach>

📌 결과

 

📖 연습문제

//  TODO: 연습 2) 연습 1에서 작성한 dno, dname, loc 를 ArrayList 담아서 jsp 전달하세요
//    화면에 출력시 부트스트랩 테이블을 이용해서 출력하세요
//    url : /example02
//    jsp : exam03/example02.jsp
//    url 테스트 : http://localhost:8000/exam03/example02?dno=10&dname=Accounting&loc=NewYork
//    결과 : 테이블 형태로
//    부서번호 : 10
//    부서명 : Accounting
//    위치 : NewYork

 

📂 MulitParamController.java

@GetMapping("/example02")
public String setHelloArray2(Model model,
                             @RequestParam(defaultValue = "")int dno,
                             @RequestParam(defaultValue = "")String dname,
                             @RequestParam(defaultValue = "")String loc
                             )
{
    List<String> list = new ArrayList<>();
    list.add(String.valueOf(dno));
    list.add(dname);
    list.add(loc);

    model.addAttribute("list",list);
    return "exam03/example02.jsp";
}

📂 example02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2> 연습1) URL 매개변수를 ArrayList 로 View에 전달</h2>
    <p>${list}</p>

    <table class="table">
        <thead>
        <tr>
            <th scope="col">부서번호</th>
            <th scope="col">부서명</th>
            <th scope="col">위치</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <%--    TODO: JSP 반복문 : jstl 표현식 사용    --%>
            <%--                  <c:forEach var="일반변수" items="${배열}">   --%>
            <c:forEach var="data" items="${list}">
                <td>${data}</td>
            </c:forEach>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

📌 실행결과

 

//  TODO: 연습 3) 아래 결과를 ArrayList 담아서 jsp 전달하세요
//    화면에 출력시 부트스트랩 테이블을 이용해서 출력하세요
//    url : /example03
//    jsp : exam03/example03.jsp
//    url 테스트 : http://localhost:8000/exam03/example03?eno=7788&ename=Scott&salary=3000&job=Manager
//    결과 : 테이블 형태로
//      사원번호 : 7788
//      사원명 : Scott
//      월급 : 3000
//      직위 : Manager

📂  MulitParamController.java

@GetMapping("/example03")
public String setHelloArray3(Model model,
                             @RequestParam(defaultValue = "")int eno,
                             @RequestParam(defaultValue = "")String ename,
                             @RequestParam(defaultValue = "")int salary,
                             @RequestParam(defaultValue = "")String job
)
{
    List<String> list = new ArrayList<>();
    list.add(String.valueOf(eno));
    list.add(ename);
    list.add(String.valueOf(salary));
    list.add(job);

    model.addAttribute("list",list);
    return "exam03/example03.jsp";
}

📂 example03.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2> 연습3) URL 매개변수를 ArrayList 로 View에 전달</h2>
    <p>${list}</p>

    <table class="table">
        <thead>
        <tr>
            <th scope="col">eno</th>
            <th scope="col">ename</th>
            <th scope="col">salary</th>
            <th scope="col">job</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <%--    TODO: JSP 반복문 : jstl 표현식 사용    --%>
            <%--                  <c:forEach var="일반변수" items="${배열}">   --%>
            <c:forEach var="data" items="${list}">
                <td>${data}</td>
            </c:forEach>
        </tr>
        </tbody>
    </table>
</div>
</body>
</html>

📌 실행결과

반응형

'Spring Boot > 스프링부트 예제' 카테고리의 다른 글

객체 형태로 변환하는 어노테이션  (0) 2023.10.05
JSP의 조건문  (1) 2023.10.05
@RequestMapping, @RequestParam  (1) 2023.10.05
Model  (0) 2023.10.04
Hello SpringBoot!  (0) 2023.10.04
반응형

💡 @RequestParam

쿼리스트링 방식으로 변수에 값을 저장해서 다른 페이지로 전달하는 Annotation 입니다.

  • 파라미터 이름으로 바인딩
  • name 속성이 파라미터 이름으로 사용
사용법 : 함수명(Model model, @RequestParam 자료형 변수명) {}
url?변수명=값 (웹 브라우저 주소창 입력)

📌 코드작성해보기

📂 ParamController.java

@Controller
public class ParamController {

    @GetMapping("/exam02/hello-name")
    public String HelloName(Model model
            ,@RequestParam(defaultValue = "") String name) {
        model.addAttribute("greeting", "안녕하세요 " + name);
        return "exam02/hello.jsp";
    }

}

여기서

@RequestParam(defaultValue = "") String name)

defaultValue 부분은 생략이 가능합니다.

만약 defaultValue 부분을 생략하고 주소창에 값을 넘겨주지 않을 경우 오류가 발생하게 됩니다.

즉, 옵션을 생략할 경우 반드시 값을 넘겨줘야합니다!

  • 위의 코드는 HelloName 메서드에 @RequestParam 어노테이션을 사용하여 name 값이 전달이 안될 경우 빈문자열로 기본값을 설정하였습니다.

 

📂 hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>매개변수(파라메터) 전달받아 출력하기</h2>
<%--    TODO : el(Experssion language) 표현식 : ${변수명} --%>
    <p>${greeting}</p>
</div>
</body>
</html>

📌 실행결과

기본 값일 경우 위의 코드처럼 빈 문자열로 출력됨

 

웹 페이지 주소창에 url?변수명=값을 넘겨 실행하면 name 변수에 있는 이순신이 출력됩니다.

✅ URL 매개변수를 2개를 각각 키이름으로 전달하기

위의 예제는 매개변수를 1개를 전달하는 방법이였습니다. 이번에는 매개변수 2개를 전달하는 방법에 대해 알아보겠습니다.

📂 MultiParamController.java

@Controller
@RequestMapping("/exam03")
public class MultiParamController {

//    TODO : 예제 1) URL 매개변수 2개를 각각 키이름으로 전달
//     URL TEST ) http://localhost:8000/exam03/hello-name-id?name=junyeok&id=junyeoke
    @GetMapping("/hello-name-id")
    public String setHelloNameId (Model model,
                                  @RequestParam(defaultValue = "")String name,
                                  @RequestParam(defaultValue = "")String id)
    {
        model.addAttribute("attrName","이름 : " + name);
        model.addAttribute("attrId","아이디 : " + id);
        return "exam03/hello_name_id.jsp";
    }
  • setHelloNameId 메서드에 @RequestParam 어노테이션이 두 개 사용된 것을 알 수 있습니다.

📂 example01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>URL 매개변수를 각각 키이름으로 전달</h2>
    <p>${dno}</p>
    <p>${dname}</p>
    <p>${loc}</p>
</div>
</body>
</html>

 

📌 실행결과

  • URL TEST 주소는 http://localhost:8000/exam03/hello-name-id?name=junyeok&id=junyeoke 이며 매개변수가 2개 이상일 경우 &을 사용하여 입력합니다.

 

💡 @RequestMapping

요청(Request) URL을 어떤 method가 처리할지 mapping 해주는 Annotation 입니다.

즉, 자주쓰는 공통 URL를 생략할수 있게 해주는 어노테이션이라 생각하시면 됩니다.

@RequestMapping("/공통url") : 공통 url을 함수의 url과 합쳐져서 사용됨
예) @RequestMapping("/exam02") + @GetMapping("/hello-name")
=> url : /exam02/hello-name

컨트롤러 클래스 위에 @RequestMapping 어노테이션을 사용합니다.

package com.example.controllerexam.controller.exam02;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/exam02")
public class ParamController {

    @GetMapping("/hello-name")
    public String HelloName(Model model
            ,@RequestParam(defaultValue = "") String name) {
        model.addAttribute("greeting", "안녕하세요 " + name);
        return "exam02/hello.jsp";
    }

....
}

📖 연습문제

//  TODO: 연습 1) url : /exam02/hello-dname
//               jsp : exam02/example01.jsp
//               문제 : dname(Sales)의 값을 url 쿼리스트링으로 전달해서
//                example01.jsp 에 출력해 보세요
//               결과 : 부서명 : Sales

📂 ParamController.java

@GetMapping("/exam02/hello-dname")
public String HelloDname(Model model, @RequestParam(defaultValue = "") String dname) {
    model.addAttribute("greeting", "부서명 : " + dname);
    return "exam02/example01.jsp";
}

📂 example01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>dname(Sales)의 값을 url 쿼리스트링으로 전달해서 출력하기</h2>
    <%--    TODO : el(Experssion language) 표현식 : ${변수명} --%>
    <p>${greeting}</p>
</div>
</body>
</html>

📌 실행결과

url?dname=Sale 를 추가하면 부서명에 Sales가 출력됩니다.

 

//  TODO: 연습 2) 숫자로 url 매개변수를 전달해서 화면에 출력해 보세요.
//         url : /exam02/hello-no
//         jsp : exam02/example02.jsp
//         결과 : 20

 

📂 ParamController.java

    @GetMapping("/exam02/hello-no")
    public String HelloNo(Model model, @RequestParam(defaultValue = "0") int no) {
        model.addAttribute("greeting", + no);
        return "exam02/example02.jsp";
    }

📂 example02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>숫자로 url 매개변수를 전달해서 화면에 출력하기</h2>
    <%--    TODO : el(Experssion language) 표현식 : ${변수명} --%>
    <p>${greeting}</p>
</div>
</body>
</html>

📌 실행결과

 

TODO: 연습 1) URL 매개변수로 dno=10, dName=Accounting 받았다. 아래 결과를 화면에 출력하세요.
url : /example01
jsp : exam03/example01.jsp
<결과>
부서번호 : 10
부서명 : Accounting
위치 : NewYork
url 테스트 : http://localhost:8000/exam03/example01?dno=10&dname=Accounting&loc=NewYork

📂 MultiParamController.java

@GetMapping("/example01")
public String setDnoDname (Model model,
                           @RequestParam(defaultValue = "0")int dno,
                           @RequestParam(defaultValue = "")String dname,
                           @RequestParam(defaultValue = "")String loc){
    model.addAttribute("dno","부서번호 : " + dno);
    model.addAttribute("dname","부서명 : " + dname);
    model.addAttribute("loc","위치 : " + loc);
    return "exam03/example01.jsp";
}

📂 example01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="container">
    <h2>예제 2번 문제</h2>
    <p>${dno}</p>
    <p>${dname}</p>
    <p>${loc}</p>
</div>
</body>
</html>

📌 실행결과

반응형

'Spring Boot > 스프링부트 예제' 카테고리의 다른 글

객체 형태로 변환하는 어노테이션  (0) 2023.10.05
JSP의 조건문  (1) 2023.10.05
URL 매개변수를 ArrayList 형태로 View에 전달  (0) 2023.10.05
Model  (0) 2023.10.04
Hello SpringBoot!  (0) 2023.10.04
반응형

💡 모델을 통해 변수 등록하는 방법

모델은 컨트롤러의 메서드에서 매개변수로 받아옵니다. 모델에서 변수를 등록할 때는 addAttribute() 메서드를 사용합니다.

model.addAttribute("변수명", 변숫값);

📂 HelloController.java

package com.example.controllerexam.controller.exam01;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * packageName : com.example.controllerexam.controller.exam01
 * fileName : HelloController
 * author : GGG
 * date : 2023-10-04
 * description : JSP, 타임리프  : SSR  (Server Side Rendering)
 *                   1) 구조 => Springboot 소스가 같이 있음
 *                   2) html 파일을 Springboot에서 만들어서 웹브라우저로 전송함
 *               React / Vue  : CSR  (Client Side Rendering)
 *                   1) 구조 => 소스가 분리됨
 *                   2) html 파일을 최초 1회 전송하고
 *                     => 다음부터는 변경되는 부분만 서버에서 받고, 나머지는 웹 브라우저에서 자체 만듦
 *               @GetMapping("url")함수(){ return "jsp페이지명"; }
 *               => CRUD => Read 요청일때 사용하는 어노테이션
 * 요약 :
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-04         GGG          최초 생성
 */
// TODO 1) @Controller 붙이기
@Controller
public class HelloController {
    @GetMapping("/exam01/hello")
    public String Hello(Model model){
//     TODO: 해쉬맵 자료구조 : (키, 값) => jsp 페이지로 변수를(greeting, greeting2 ...) 전송
        model.addAttribute("greeting","안녕 Springboot");
        model.addAttribute("greeting2","Springboot 처음이지");
        model.addAttribute("greeting3","수고해!!!");

        return "exam01/hello.jsp";
    }
}

💡 JSP의  el (Expression Language) 표현식

el(Expression Language) 표현식은 자바 Spring에서 전송한(Model) 키 값을 출력할 수 있습니다.

${변수명}

 

📂 hello.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
<%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<%-- jsp 주석 --%>
<%-- TODO: el(Expression Language) 표현식 : ${변수명} --%>
<%--        자바 Spring에서 전송한(Model) 키 값을 출력할 수 있음--%>
    <p>${greeting}</p>
    <p>${greeting2}</p>
    <p>${greeting3}</p>

<%-- TODO: JSTL 표현식(참고) : <c:out value="${변수명}" /> --%>
    <p><c:out value="${greeting}" /></p>
</body>
</html>

 

📌 실행결과

💡 JSP 페이지로 모든 자료형을 보내기

//    TODO: 예제 2) JSP 페이지로 모든 자료형을 보내기
//         url : /exam01/operation
//         jsp : exam01/operation.jsp

✅ JSP에서 JAVA 문법과 같이 사칙연산 / 논리합(곱) / 비교연산자 / 삼항연산자 사용가능!

TODO: 문자열로 생긴 숫자는 자동으로 형변환 됨 (사칙연산시)
JSP : Java Server Page, 자바 문법 모두 사용가능
JSP(.jsp) -> servlet(.java)--%>

 

📂 HelloController.java

@GetMapping("/exam01/operation")
public String Operation(Model model) {

    String strNum = "10";
    int iNum = 100;
    String strVal = "a";
    boolean bVal = true;

    model.addAttribute("strNum",strNum);
    model.addAttribute("iNum",iNum);
    model.addAttribute("strVal",strVal);
    model.addAttribute("bVal",bVal);


    return "exam01/operation.jsp";
}

📂 operation.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--bootstrap css cdn--%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<%--TODO: spring에서 전송한 값으로 사칙연산, 논리연산 해보기--%>
<div class="container p-3">
    <h2>산술연산자</h2>
    <div class="ms-3 mt-3">
<%--   TODO: 문자열로 생긴 숫자는 자동으로 형변환 됨 (사칙연산시)    --%>
<%--    JSP : Java Server Page, 자바 문법 모두 사용가능 --%>
<%--    JSP(.jsp) -> servlet(.java)--%>
        <p>덧셈 : ${strNum + 10}</p>
        <p>뺄셈 : ${strNum - 10}</p>
        <p>곱셈 : ${strNum * 10}</p>
        <p>나눗셈 : ${strNum / 10}</p>
        <p>나머지 : ${strNum % 10}</p>

        <p>숫자 연산 : ${iNum + 10}</p>

        <p>논리 합 : ${bVal || false}</p>
        <p>논리 곱 : ${bVal && false}</p>

        <p>같음 : ${iNum == 100}</p>
        <p>같지않음 : ${iNum != 100}</p>
        <p>보다큼 : ${iNum >= 100}</p>
        <p>보다작음 : ${iNum <= 100}</p>

        <p>조건(삼항) : ${(iNum == 100)? "100임" : "100이 아님"}</p>
<%--    TODO : empty(빈) : 변수의 값이 비었으면(null, 0, "") true, 아니면 false --%>
        <p>empty : ${empty iNum}</p>
        <p>not empty : ${not empty iNum}</p>
    </div>
</div>


</body>
</html>

📌 실행결과

📖 연습문제

//  TODO: 연습 1) url : /exam01/hello2 => "exam01/example01.jsp" 에 "안녕 hello2 페이지 " 출력하기
//                                                                 "Springboot 처음이지"
//                                                                 "수고해!!!"

 

📂 HelloController.java

package com.example.controllerexam.controller.exam01;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;


// TODO 1) @Controller 붙이기
@Controller
public class HelloController {
 
//  TODO: 연습 1) url : /exam01/hello2 => "exam01/example01.jsp" 에 "안녕 hello2 페이지 " 출력하기
//                                                                 "Springboot 처음이지"
//                                                                 "수고해!!!"

    @GetMapping("/exam01/hello2")
    public String Hello2(Model model){
        model.addAttribute("greeting", "안녕 hello2 페이지");
        model.addAttribute("greeting2", "Springboot 처음이지");
        model.addAttribute("greeting3", "수고해!!!");

        return "exam01/example01.jsp";
    }

}

📂 example01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--TODO : JSTL 표현식 사용을 위한 import--%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>


<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <%--    TODO 부트스트랩 CSS CDN --%>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<%-- jsp 주석 --%>
<%-- TODO: el(Expression Language) 표현식 : ${변수명} --%>
<%--        자바 Spring에서 전송한(Model) 키 값을 출력할 수 있음--%>
<p>${greeting}</p>
<p>${greeting2}</p>
<p>${greeting3}</p>


</body>
</html>

📌 실행결과

반응형
반응형

❓ 스프링부트?

스프링부트(Spring Boot)는 자바의 웹 프레임워크로 기존 스프링 프레임워크(Spring Framework)에 톰캣 서버를 내장하고 여러 편의 기능들을 추가하여 꾸준한 인기를 누리고 있는 프레임워크입니다.


 

스프링부트 프로젝트를 생성하는 방법에는 두 가지가 있습니다.

  1. spring initializr 사이트를 이용하여 생성 방법
  2. 인텔리제이에서 생성하는 방법 (인텔리제이 무료버전은 프로젝트 기능이 없습니다.)

💡 spring initializr를 이용한 방법

https://start.spring.io/ 이곳에 접속합니다. 또는 구글에서 spring initalizr를 검색하여 첫 번째 사이트에 접속하시면 됩니다.

 

사이트 메인화면

 

 

  • 프로젝트는 Gradle-Groovy 선택
  • Language는 Java 선택
  • Spring Boot는 2.7.16 버전 선택 -> jdk 11버전과 호환성이 좋음 // 최신 버전이면 3.x.x 버전을 선택하시면 됩니다.
  • Artifact 이 부분만 수정하면 됩니다.
  • Packaging은 War 선택
  • Java는 jdk 버전에 따라 선택해주시면 됩니다.

💡 스프링부트 라이브러리 추가

주로 사용하는 라이브러리 입니다. 그 외에는 프로젝트를 진행하면서 추가할 수 있습니다.

 

라이브러리를 추가하면 오른편에 세 가지가 추가된 것을 볼 수 있습니다.

generate 버튼을 누르면 압축파일로 다운로드가 됩니다.

 

다운받은 압축파일을 작업 폴더에 풀어주신후 인텔리제이로 프로젝트를 열어줍니다.

인텔리제이 내에서 다운로드가 실행됩니다. (시간 소요)

 

💡 프로젝트 구성

HelloworldApplication 은 메인함수가 있는 실행 클래스입니다.

 

💡 JSP 라이브러리 추가

✅ build.gradle 추가

스프링부트에서 JSP 라이브러리 추가 지원이 종료되어 수작업으로 라이브러리를 추가해주어야 합니다.

build.gradle를 찾아 더블클릭합니다.
dpendencies 부분에 라이브러리를 수작업으로 추가해줍니다.

dependencies {
    //    jsp 라이브러리 추가
    implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' // 추가
    implementation 'javax.servlet:jstl' // 추가

    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

그림에 표시된 아이콘을 눌러야 라이브러리 추가가 완료됩니다.

 

💡 MVC 디자인 패턴을 이용한 Java 코딩

설정파일을 담을 config 폴더와 MVC 디자인 패턴중 C인 controller 부분을 만들 폴더를 생성합니다. 

컨트롤러는 일종의 tv리모컨 역할을 한다고 생각하면됩니다.

 

✅ JSP를 위한 설정파일

JSP를 위한 설정파일을 생성합니다.

설정파일은 config 폴더에 생성합니다.

package com.example.helloworld.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * packageName : com.example.HelloSpringBoot.config
 * fileName : WebMvcConfig
 * author : kangtaegyung
 * date : 2023/07/29
 * description : JSP 설정 파일
 * 요약 :
 *      @Configuration : 어노테이션, 자바파일에 환경설정 기능 부여
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2023/07/29         kangtaegyung          최초 생성
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
}

 

✅ controller 만들기

실습을 위한 HelloWorldController 파일을 생성합니다.

파일은 controller 폴더에 생성합니다.

 

✔ Controller 어노테이션 추가

클래스 위에 @Controller 어노테이션을 추가해줍니다.

@Controller
public class HelloWorldController {

    @GetMapping("/exam00/hello")
    public String Hello(Model model){

        return "/exam00/hello.jsp";
    }
}

 

✅ 프로퍼티파일에 환경설정 값 추가

한글깨짐 방지를 위해 파일 인코딩을 UTF-8로 설정합니다.
프로퍼티 파일안에 아래의 코드를 입력합니다.

# 서버 포트
server.port=8000
# jsp 파일 경로
spring.mvc.view.prefix=/WEB-INF/views/
# jsp 파일 확장자 정의
#spring.mvc.view.suffix=.jsp
# 자바 소스 수정시 자동 재시작
spring.devtools.restart.enabled=true

 

✅ view 만들기

뷰를 만들기위해 파일경로를 지정해줍니다.

 

hello.jsp

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

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    Hello.jsp
</body>
</html>

 

✅ 실행

HelloWorldApplication 클래스에서 실행을 합니다.

 

웹 페이지에서 http://localhost:8000 에 접속합니다.

HelloWorldController 클래스에 있는 주소를 복사하고

 http://localhost:8000/exam00/hello 를 입력합니다.

Hello.jsp 파일을 불러온 상태

 

💡 인텔리제이에서 스프링 부트 프로젝트 생성하기

1) 인텔리제이에서 새 프로젝트를 눌러줍니다.

 

2) 새 프로젝트에서 이름을 지정하고 경로를 적절한 위치에 지정 하고 JDK는 11버전 Java도 11버전

패키지 생성은 War 파일로 지정하고 다음을 눌러줍니다.

 

3) dpendencies를 지정해줍니다. 스프링부트 버전은 2.7.16 으로 라이브러리는 사진과 같이 3개만 체크하고 생성합니다.

 

프로젝트 생성이 완료된 상태

✅ UTF-8 설정 : 한글 깨짐 방지

 

✅ 기타 설정


📖 요약

# SpringBoot 프로젝트 생성
1) 웹 제작(Spring initializer) : http://start.spring.io
    - Project 빌드        : Gradle - Groovy
    - spring boot 버전    : 2.7.16 선택
    - spring Metadata    : Artifact : 프로젝트 명 넣기 (예: helloworld)
    - Packaging          : War 선택
    - Java               : jdk 11 선택
    - (오른쪽 화면) Dependencies : ADD Dependencies 버튼 클릭 : 라이브러리 추가
      (1) Spring Boot DevTools
      (2) Lombok
      (3) Spring Web
    - GENERATE 버튼 클릭 : zip 압축된 spring 프로젝트 파일 다운로드 됨

2) 인텔리제이 Ultimate(상용버전) : 위의 기능이 내장되어 있음
    - 이름 : 프로젝트명 넣기 (예 : helloworld)
    - 나머지는 위와 동일 Dependencies는 체크하기

# SpringBoot 환경 설정
1) 인텔리제이 툴 설정 : 에디터 - 파일 인코딩 - (우측화면) 프로퍼티 파일 인코딩 : UTF-8
                                         명확한 Native에서 ASCII로 변환(체크!)
2)                    빌드, 실행, 배포 - 컴파일러 - (우측화면) 프로젝트 자동빌드(체크)
3)                    고급설정 - (우측화면) 컴파일러 - 개발된 애플리케이션이 현재... (체크)

스프링부트 프로젝트의 구조

✅ build.gradle jsp 라이브러리 추가

dependencies {
    //   TODO : jsp 라이브러리 추가 : 오른편 상단에 새로 생기는 아이콘 클릭!
    implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' // 추가
    implementation 'javax.servlet:jstl' // 추가

✅ application.properties : 스프링의 환경을 설정하는 파일

# TODO : 스프링의 환경을 설정하는 파일
# 서버 포트 : 스프링의 기본포트 (8080) -> 8000(변경)
server.port=8000
# jsp 파일 경로 지정 : jsp 폴더 경로 추가
spring.mvc.view.prefix=/WEB-INF/views/
# jsp 파일 확장자를 자동으로 붙여주는 기능 : 컨트롤러 : url -> 연결될 jsp : hello.jsp (확장자 자동으로 붙여줌) 
#spring.mvc.view.suffix=.jsp
# 자바 소스가 수정되면 서버 자동 재시작을 함
spring.devtools.restart.enabled=true

✅ Java 폴더 -> ControllerExamApplication : 스프링부트 실행 파일

 

✅ config 폴더 -> WebMvcConfig : JSP를 사용하기 위한 설정 파일

package com.example.controllerexam.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * packageName : com.example.HelloSpringBoot.config
 * fileName : WebMvcConfig
 * author : kangtaegyung
 * date : 2023/07/29
 * description : JSP를 사용하기 위한 설정 파일
 * 요약 :
 *      @Configuration : 어노테이션, 자바파일에 환경설정 기능 부여
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * -----------------------------------------------------------
 * 2023/07/29         kangtaegyung          최초 생성
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
}

✅ controller 폴더 -> HelloWorldController 파일 : url에 해당하는 jsp 파일로 연결해주는 파일

package com.example.controllerexam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * packageName : com.example.helloworld.controller
 * fileName : HelloWorldController
 * author : GGG
 * date : 2023-10-04
 * description : Hello World Controller
 * 요약 :
 *      url에 해당하는 jsp 파일로 연결하기
 *      @명칭 : 자바의 어노테이션이라고 하고, 주로 함수/클래스/변수 위에 붙여서 사용힘
 *       작은 기능이 함수에 추가됨
 *       목적 : 사용하면 코딩량이 획기적으로 줄어듦
 *      @Controller : 클래스에 컨트롤러 기능을 부여하는 어노테이션
 *      @GetMapping("url")함수() { return "jsp페이지명"; }
 *      => url이 웹브라우저 주소창에 입력되면 -> jsp 페이지가 화면에 출력됨
 * <p>
 * ===========================================================
 * DATE            AUTHOR             NOTE
 * —————————————————————————————
 * 2023-10-04         GGG          최초 생성
 */
@Controller
public class HelloWorldController {

    @GetMapping("/exam00/hello")
    public String Hello(Model model){

        return "/exam00/hello.jsp";
    }
}

📖 연습문제

//    TODO : 연습) url : "/exam00/hello2"
//             => jsp : "/exam00/example01.jsp"
화면에 Hello JSP & Spring boot 출력해보세요!

📌 example01.jsp

<%-- 아래 page 지시자가 있어야 함 --%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    Hello JSP & Spring boot
</body>
</html>

📌 HelloWorldController.java

@Controller
public class HelloWorldController {
//    TODO : 연습) url : "/exam00/hello2"
//             => jsp : "/exam00/example01.jsp" : 화면에 Hello JSP & Spring boot 출력

    @GetMapping("/exam00/hello2")
    public String Hello2(Model model){

        return "/exam00/example01.jsp";
    }
}

📌 ControllerExamApplication 파일에서 실행

 

📌 http://localhost:8000/exam00/hello2 접속

 

📌 실행결과

반응형

'Spring Boot > 스프링부트 예제' 카테고리의 다른 글

객체 형태로 변환하는 어노테이션  (0) 2023.10.05
JSP의 조건문  (1) 2023.10.05
URL 매개변수를 ArrayList 형태로 View에 전달  (0) 2023.10.05
@RequestMapping, @RequestParam  (1) 2023.10.05
Model  (0) 2023.10.04

+ Recent posts