70일차 내용 정리

채공부·2025년 9월 1일

JPA

사용자 생성 & 권한 부여

CMD 창 열기

  1. ORACLE 에 접속
C:\Users\USER>sqlplus system/oracle
  1. USER 생성
create USER kimgura IDENTIFIED BY kimgura1234;
  1. 해당 USER 에 권한 주입
GRANT CONNECT, RESOURCE TO kimgura;

Spring09_JPA 프로젝트 설정

Spring09_JPA 프로젝트 생성

  • application.properties 에 서버 포트 설정 및 Oracle DataSource 설정
spring.application.name=Spring09_JPA

server.port=9000

# oracle DataSource Setting ( Connection Pool )
#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
#spring.datasource.username=kimgura
#spring.datasource.password=kimgura1234

H2 데이터베이스 설정

playground 폴더 안에 h2db 폴더 생성

  • application.properties 에 H2 DB 접속 관련 설정 코드 추가
# H2 DataBase 접속 정보
# http://localhost:9000/h2-console/
# 위의 주소로 h2 database 콘솔에 접속할수 있다.
# JDBC URL 에 아래의 url 정보를 붙여 넣기해서 접속한다.
spring.datasource.url=jdbc:h2:file:C:/playground/h2db
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=user
spring.datasource.password=
spring.h2.console.enabled=true

Entity

step09.entity 패키지 생성

  • Member 클래스 생성

  • entity 클래스에는 @Data 어노테이션을 붙이면 나중에 문제가 발생

@Setter
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity(name="MEMBER_INFO")
public class Member {
   // num 이라는 필드에 대해서 2개의 어노테이션 추가
   // PK 개념
   @Id  
   // 자동으로 번호를 넣을 수 있도록 (sequence 개념)
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer num;
   
   private String name;
   private String addr;
}
  • Spring09JpaApplication 에 EntityManagerFactory 객체 주입
  • spring data JPA 를 dependency 로 추가하고 application.properties 파일에 적절한 jpa 설정을 해 놓으면 EntityManagerFactory 가 bean 으로 관리된다
@SpringBootApplication
public class Spring09JpaApplication {

   @Autowired
   EntityManagerFactory emf;
   
   public static void main(String[] args) {
      SpringApplication.run(Spring09JpaApplication.class, args);
   }
}
  • Spring09JpaApplication 에 helloJPA 메소드 생성
  • EntityManager 객체의 persist() 메소드를 이용해서 객체에 저장된 정보를 영속화 (영구저장)
@PostConstruct
public void helloJPA() {
	// EntityManager 객체를 얻어와서
	EntityManager em = emf.createEntityManager();
	// 트랜잭션을 시작
	EntityTransaction tx = em.getTransaction();
	tx.begin();
	try {
		// Entity 객체를 생성하고
		Member m1 = Member.builder().name("김구라").addr("노량진").build();
		Member m2 = Member.builder().name("해골").addr("행신동").build();
		Member m3 = Member.builder().name("원숭이").addr("동물원").build();

		em.persist(m1);
		em.persist(m2);
		em.persist(m3);
		tx.commit(); // commit 하는 시점에 저장
	} catch (Exception e) {
		e.printStackTrace();
		tx.rollback(); // 예외가 발생한 경우 저장하지 않고 취소 할 수 있다.
	} finally {
		em.close();
	}
}
  • MEMBER_INFO 라는 테이블의 별칭을 m 이라고 하고
    m 의 모든 칼럼의 정보를 select 해서 Member.class type 객체에 담겠다는 의미
  • row 가 여러개인 경우 .getResultList() 메소드를 호출해서 결과를 얻어낸다
  • Member.class type 을 전달했기 때문에 List 의 generic 이 Member type 이 된다
EntityManager em2 = emf.createEntityManager();

List<Member> members = em2.createQuery("SELECT m FROM MEMBER_INFO m", Member.class)
	.getResultList();
for (Member mem : members) {
	System.out.println(mem.getNum() + " : " + mem.getName() + " : " + mem.getAddr());
}
em2.close();

JPA 테이블 자동 생성 설정

  • ddl-auto 옵션

    • create : 실행 시마다 기존 테이블 삭제 후 새로 생성 (데이터 삭제됨)
    • create-drop : 종료 시점에 테이블도 삭제
    • update : 기존 데이터 유지하며 필요한 테이블/컬럼만 추가/수정
  • application.properties 에 jpa 설정 추가

# jpa 설정
spring.jpa.show-sql=true
# update 는 테이블 유지, create 는 시작할 때 테이블 삭제 및 다시 만들기
# create-drop 은 시작할 때 테이블 생성, 종료될 때 테이블 삭제
spring.jpa.hibernate.ddl-auto=create-drop

H2 데이터베이스 콘솔 접속 방법

  1. 주소를 웹 브라우저 주소창에 붙여넣기
    H2 Console

  2. URL 정보를 복사해서 JDBC URL 에 붙여넣기
    jdbc:h2:file:C:/playground/h2db

  3. 설정된 userName을 넣고 userName : user

  4. Connect click

  1. MEMBER_INFO 테이블 click

  2. 자동으로 생성된 SQL 문 실행 (Run 버튼 click)

  3. 해당 결과 확인

➜ 자동으로 sequence 도 생성되어 있다

Repository 생성

step09.repository 패키지 생성

  • MemberRepository 인터페이스 생성
  • JpaRepository 인터페이스를 상속받은 인터페이스를 정의하는 것 만으로 구현 클래스가 만들어지고 해당 클래스로 생성된 객체가 bean 으로 관리가 된다
  • Dao 가 자동으로 만들어 진다고 생각하면 된다
  • extends JpaRepository<Entity 클래스명, 해당 Entity에서 PK의 data type
public interface MemberRepository extends JpaRepository<Member, Integer>{
   
}

➜ entity 만으로 DML 작업 가능

  • Spring09JpaApplication 에 MemberRepository 의존 객체 주입
@Autowired
MemberRepository memberRepo;
finally{
	// MemberRepository 객체를 이용해서 select 작업하기
	List<Member> list = memberRepo.findAll();
	for(Member tmp : list) {
		System.out.println(tmp.getNum() + "|" + tmp.getName() + "|" + tmp.getAddr());
	}
}
1|김구라|노량진
2|해골|행신동
3|원숭이|동물원

Controller 및 View 연동

Spring04 프로젝트의 templates 안에 있는 member 폴더와 home.html 복사해서 붙여넣기

spring09.controller 패키지 생성

  • HomeController 클래스 생성
@Controller
public class HomeController {
	
	@GetMapping("/")
	public String home(Model model) {
		List<String> notice = List.of("공지사항 입니다", "공지사항1", "공지사항2");
		model.addAttribute("notice", notice);
		return "home";
	}
}
  • MemberController 클래스 생성
@Controller
@RequiredArgsConstructor
public class MemberController {	
	// 필요한 의존 객체를 주입 받는다
	private final MemberService service;
	
	@PostMapping("/member/update")
	public String update(MemberDto dto) {
		// 수정할 회원의 정보가 MemberDto 객체에 담겨서 전달된다
		service.updateMember(dto);
		return "member/update";
	}
	
	@GetMapping("/member/edit")
	public String edit(int num, Model model) {
		// 수정할 회원의 정보를 얻어와서
		MemberDto dto  = service.getMember(num);
		// Model 객체에 담고
		model.addAttribute("dto", dto);
		// view page 로 forward 이동해서 응답
		return "member/edit";
	}
	
	@GetMapping("/member/delete")
	public String delete(int num) {
		/*
		 * 매개변수에 int num 을 선언하면 요청 파라미터 중에서 num 이라는 파라미터 명으로 전달되는
		 * 문자열을 자동추출해서 Integer.parseInt() 를 수행해서 실제 int 값으로 바꾼 다음
		 * 해당 값을 매개 변수에 전달해 준다
		 * int 값으로 바꿀 수 없는 문자열이 넘어오면 에러가 발생한다
		 * */
		service.deleteMember(num);
		
		return "member/delete";
	}
	
	@PostMapping("/member/save")
	public String save(MemberDto dto) {
		/*
		 * 매개변수에 MemberDto 를 선언하면 폼 전송되는 파라미터가 자동 추출되어서
		 * MemberDto 객체에 담긴 채로 전달된다
		 * 단 MemberDto 클래스의 필드명과 폼 전송되는 파라미터명이 같아야 한다
		 * private String name <=> <input type="text" name="name">
		 * private String addr <=> <input type="text" name"addr">
		 * */
		service.addMember(dto);
		
		// 회원 목록 보기 "/member/list" 요청을 다시 하라는 redirect 응답 하기
		// "redirect:리다이렉트 경로" 처럼 redirect: 으로 시작하는 문자열을 리턴하면 된다
		return "redirect:/member/list";
	}
	
	@GetMapping("/member/new-form")
	public String newForm() {
		// 현재 여기서 수행할 로직은 없고 view page 의 위치만 리턴해준다
		return "member/new-form";
	}
	
	@GetMapping("/member/list")
	public String list(Model model) {
		// 회원 목록
		List<MemberDto> list = service.getAll();
		// 응답에 필요한 객체를 Model 객체에 담는다
		model.addAttribute("list", list);
		
		// "/WEB-INF/views/member/list.jsp" 에서 응답하기
		return "member/list";
	}
}

DTO 클래스 생성

spring09.dto 패키지 생성

  • MemberDto 클래스 생성
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class MemberDto {
	private int num;
	private String name;
	private String addr;
}
⭐ Entity ⟷ Dto
    Entity : DB 테이블과 연관
    Dto : 요청과 응답에 사용

Service 계층 구현

spring09.service 패키지 생성

  • MemberService 인터페이스 생성
public interface MemberService {
	public List<MemberDto> getAll();
	public MemberDto getMember(int num);
	public void addMember(MemberDto dto);
	public void updateMember(MemberDto dto);
	public void deleteMember(int num);
}
  • MemberServiceImpl 클래스 생성 및 MemberRepository JPA Repository 객체 주입
@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService{
	
	private final MemberRepository memberRepo;
	
	@Override
	public List<MemberDto> getAll() {
		return null;
	}

	@Override
	public MemberDto getMember(int num) {
		return null;
	}

	@Override
	public void addMember(MemberDto dto) {
		
	}

	@Override
	public void updateMember(MemberDto dto) {
		
	}

	@Override
	public void deleteMember(int num) {
		
	}
}
  • MemberServiceImpl 에 getAll() 메소드 완성
  • Entity 와 Dto 를 구분해야 하기 때문에 반복문 돌면서 Entity 의 list 를 dto 의 list 로 변환 (Entity 하나당 Dto 를 생성해서 넣기)

  • 잘 설계한다면 해당 코드들을 1줄 coding 으로 간단히 해결 가능

  • select 전용 메소드는 @Transactinal(readOnly-true) 를 붙이면 안전하다

  • 의도치 않은 수정, 삭제를 방지하기 위해

@Transactional(readOnly = true)
@Override
public List<MemberDto> getAll() {
	// 전체 회원 목록을 얻어낸다 (Entity 의 목록)
	List<Member> list = memberRepo.findAll();
		
	List<MemberDto> dtoList = new ArrayList<>();
	for(Member tmp : list) {
		MemberDto dto = MemberDto.builder()
				.num(tmp.getNum())
				.name(tmp.getName())
				.addr(tmp.getAddr())
				.build();
		dtoList.add(dto);
	}		
	return dtoList;
}
  • MembeDto 에 toDto static 메소드 생성

  • Entity 를 매개변수로 전달하면 dto 를 리턴하는 static 메소드 만들어두기

public static MemberDto toDto(Member entity) {
	return MemberDto.builder()
			.num(entity.getNum())
			.name(entity.getName())
			.addr(entity.getAddr())
			.build();
}
  • MemberServiceImpl 에 getAll 메소드 안에 코드 한 줄 코딩으로 수정
  • Entity 의 List 를 stream 으로 만들어서 map() 함수를 이용해서 stream 에 저장된 Entity 를 dto 로 변경한 다음 List 로 변경한다
  • 클래스명 :: static 메소드명 : 클래스 안에 만들어진 static 메소드를 참조하는 표현식
  • 즉 .map() 함수 안에서 사용될 메소드를 미리 만들어진 메소드를 참조해서 전달하는 방식
List<MemberDto> dtoList = memberRepo.findAll().stream().map(MemberDto :: toDto).toList();
  • Member 에 dto 를 Entity 로 변경하는 toEntity 메소드 생성
  • Member entity 의 num 이라는 필드에 값이 null 이어야지 .save() 할 때 새로운 row 가 추가된다
  • 따라서 dto 에 num 이 만일 0 이면 0 을 넣는 것이 아니고 null 을 넣어주어야 .save() 가 우리가 의도하는 바 대로 동작한다
public static Member toEntity(MemberDto dto) {
	   return Member.builder()
			   .num(dto.getNum() == 0 ? null : dto.getNum())
			   .name(dto.getName())
			   .addr(dto.getAddr())
			   .build();
   }

테이블 정렬

  • MemberServiceImple 에 getMember 메소드 완성

  • id 칼럼에 대해서 default 로 오름차순 정렬된 List 가 반환된다

@Transactional(readOnly = true)
@Override
public MemberDto getMember(int num) {
	// 번호를 이용해서 Member entity 객체를 얻어내서
	// Member entity = memberRepo.findById(num).get();
    
    // num 에 해당하는 Member entity 를 얻어내는데 만일 존재하지 않는다면 예외 발생 시키기
	Member entity = memberRepo.findById(num)
			.orElseThrow(()-> new IllegalArgumentException("회원이 존재하지 않습니다 num = "+num));
                
	// entity 를 dto 로 변경해서 리턴한다
	return MemberDto.toDto(entity);
}
  • MemberServiceImple 에 addMember 메소드 완성
  • dto 를 Entity 로 변경해서 save() 메소드에 전달하면 된다
  • Entity 의 id 필드에 해당하는 정보가 DB 에 없으면 insert 된다
  • Entity 의 id 필드에 해당하는 정보가 DB 에 이미 존재하면 update 된다
@Transactional
@Override
public void addMember(MemberDto dto) {
	memberRepo.save(Member.toEntity(dto));
}
  • MemberServiceImple 에 updateMember 메소드 완성
@Transactional
@Override
public void updateMember(MemberDto dto) {
	// memberRepo.save(Member.toEntity(dto));
		
		
	// 위의 경우 잘못된 데이터가 DB 에 insert 될 위험이 있기 때문에 아래의 방식을 많이 사용
	Member entity = memberRepo.findById(dto.getNum())
			.orElseThrow(() -> new IllegalArgumentException("수정할 회원이 존재하지 않습니다"));
	// 존재할 경우 entity 객체를 수정하면 DB 에 자동 반영된다
	entity.setName(dto.getName()); // 객체를 수정하는 것만으로 DB 가 수정되는 것을 확인한다
	entity.setAddr(dto.getAddr());
}
  • MemberServiceImple 에 deleteMember 메소드 완성
@Transactional
@Override
public void deleteMember(int num) {
	// 만일 삭제할 Entity 가 존재하지 않으면
	if(!memberRepo.existsById(num)) {
		throw new IllegalArgumentException("삭제할 회원이 존재하지 않습니다 num = "+num);
	}
	// 번호를 이용해서 삭제 (실패 시 예외가 발생하지 않는다)
	memberRepo.deleteById(num);
}
  • MemberServiceImpl 에 getMember 메소드 수정
  • Sort.Direction.ASC or Sort.Direction.DESC
  • "num" 은 num 이라는 칼럼에 대해서 정렬하라는 의미
List<MemberDto> dtoList = memberRepo.findAll(Sort.by(Sort.Direction.DESC, "num"))
			.stream().map(MemberDto :: toDto).toList();
  • MemberRepository findAllByOrderByNumDesc & findAllByOrderByNumAsc 메소드 생성

  • 미리 정해진 형식으로 메소드를 만들면 알아서 정렬된다

    • findAllByOrderByNumDesc()
    • findAllByOrderByNumAsc()
    • findAllByOrderByNameDesc()
    • findAllByOrderByAddrDesc()
  • 칼럼명을 Camel Case 로 작성하면 된다

    • findAllByOrderBy칼럼명Asc()
    • findAllByOrderBy칼럼명Desc()
public List<Member> findAllByOrderByNumDesc();
public List<Member> findAllByOrderByNumAsc();
  • MemberServiceImpl 에 getMember 메소드 수정

  • repository 인터페이스에 정해진 형식의 메소드를 만들어서 정렬된 결과를 얻어낼 수 있다

List<MemberDto> dtoList = memberRepo.findAllByOrderByNumAsc()
			.stream().map(MemberDto :: toDto).toList();

JPQL

Java Persistence Query Language
1. sql 처럼 생겼지만 entity 중심으로 작성하는 객체 지향 쿼리 언어
2. DB 종류에 종속되지 않는다

  • MemberServiceImpl 에 getMember 메소드 수정
  • JPQL 문법 형식의 select 문을 직접 작성해서 실행의 결과를 얻어낼 수도 있다
  • 메소드명은 마음대로 지을 수 있다
@Query("SELECT m FROM MEMBER_INFO m ORDER BY m.num DESC")
public List<Member> findAllQuery();
  • MemberServiceImpl 에 getMember 메소드 수정

  • repository 인터페이스에 작성한 JPQL 를 이용해서 정렬된 결과 얻어내기

List<MemberDto> dtoList = memberRepo.findAllQuery()
		.stream().map(MemberDto :: toDto).toList();

Native Query

  • MemberRepository 에 findAllNativeQuery 메소드 생성
  • 특정 DB 에서만 실행될 수 있는 원래의 Query 문을 실행할 수도 있다
    • nativeQuery = true 옵션을 주면 된다
@Query(value = "SELECT num, name, addr FROM MEMBER_INFO ORDER BY num DESC", nativeQuery = true)
public List<Member> findAllNativeQuery();
  • MemberServiceImpl 에 getMember 메소드 수정

  • repository 인터페이스에 작성된 Native Query 문을 이용해서 정렬된 결과 얻어내기

List<MemberDto> dtoList = memberRepo.findAllNativeQuery()
		.stream().map(MemberDto :: toDto).toList();

실습

도서(book) 정보

  • id(번호) name (이름) author(저자)
  1. Book 엔티티 클래스 (private Long id)
  2. BookDto 클래스 (private long id)
  3. BookRepository 인터페이스
  4. BookService 인터페이스, BookServiceImpl 클래스
  5. BookController 클래스
  6. /book/list , /book/new, /book/insert, /book/edit, /book/update, /book/delete 요청 처리할 컨트롤러 메소드와 thymeleadf view page

를 만들어 구현해 보세요

  • home.html 에 도서 목록 링크 추가
<li><a th:href="@{/book/list}">도서 목록</a></li>
  1. Book Entity 클래스 생성
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity(name="BOOK_INFO")
public class Book {
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long id;
	private String name;
	private String author;
	
	public static Book toEntity(BookDto dto) {
		return Book.builder()
				.id(dto.getId() == 0 ? null : dto.getId())
				.name(dto.getName())
				.author(dto.getAuthor())
				.build();		
	}
}
  1. BookDto 클래스 생성
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class BookDto {
	private long id;
	private String name;
	private String author;
	
	public static BookDto toDto(Book entity) {
		return BookDto.builder()
				.id(entity.getId())
				.name(entity.getName())
				.author(entity.getAuthor())
				.build();
	}
}
  1. BookRepository 인터페이스
public interface BookRepository extends JpaRepository<Book, Long>{

	@Query("SELECT b FROM BOOK_INFO b ORDER BY b.id ASC")
	public List<Book> findAllQuery();
}
  1. BookService 인터페이스 생성
public interface BookService {
	public List<BookDto> getAll();
	public BookDto getBook(long id);
	public void addBook(BookDto dto);
	public void updateBook(BookDto dto);
	public void deleteBook(long id);
}
  1. BookServiceImpl 클래스
@Service
@RequiredArgsConstructor
public class BookServiceImpl implements BookService{

	private final BookRepository bookRepo;
	
	@Transactional(readOnly = true)
	@Override
	public List<BookDto> getAll() {
		List<BookDto> dtoList = bookRepo.findAllQuery()
				.stream().map(BookDto :: toDto).toList();
		return dtoList;
	}

	@Transactional(readOnly = true)
	@Override
	public BookDto getBook(long id) {
		Book entity = bookRepo.findById(id)
				.orElseThrow(()-> new IllegalArgumentException("도서가 존재하지 않습니다"));
		return BookDto.toDto(entity);
	}

	@Transactional
	@Override
	public void addBook(BookDto dto) {
		bookRepo.save(Book.toEntity(dto));
	}

	@Transactional
	@Override
	public void updateBook(BookDto dto) {
		Book entity = bookRepo.findById(dto.getId())
				.orElseThrow(()-> new IllegalArgumentException("수정할 도서가 존재하지 않습니다"));
		entity.setName(dto.getName());
		entity.setAuthor(dto.getAuthor());
	}

	@Transactional
	@Override
	public void deleteBook(long id) {
		if(!bookRepo.existsById(id)) {
			throw new IllegalArgumentException("삭제할 도서가 존재하지 않습니다 id = "+id);
		}
		bookRepo.deleteById(id);
	}
}
  1. BookController 클래스 생성
  • /book/list , /book/new , /book/insert , /book/edit , /book/update , /book/delete 요청 처리할 컨트롤러 메소드 생성
@Controller
@RequiredArgsConstructor
public class BookController {
	private final BookService service;
	
	@GetMapping("/book/list")
	public String list(Model model) {
		List<BookDto> list = service.getAll();
		model.addAttribute("list", list);
		return "book/list";
	}
	
	@GetMapping("/book/new")
	public String newForm() {
		return "book/new";
	}
	
	@PostMapping("/book/insert")
	public String insert(BookDto dto) {
		service.addBook(dto);
		return "redirect:/book/list";
	}
	
	@GetMapping("/book/edit")
	public String edit(long id, Model model) {
		BookDto dto = service.getBook(id);
		model.addAttribute("dto", dto);
		return "book/edit";
	}
	
	@PostMapping("/book/update")
	public String update(BookDto dto) {
		service.updateBook(dto);
		return "book/update";
	}
	
	@GetMapping("/book/delete")
	public String delete(long id) {
		service.deleteBook(id);
		return "book/delete";
	}
}
  1. thymeleadf view page 생성
  • list.html 생성
<div class="container">
	<a th:href="@{/book/new}">도서 추가</a>
	<h1>도서 목록</h1>
	<table>
		<thead>
			<tr>
				<th>번호</th>
				<th>이름</th>
				<th>저자</th>
				<th>수정</th>
				<th>삭제</th>
			</tr>
		</thead>
		<tbody>
			<tr th:each="tmp : ${list}">
				<td th:text="${tmp.id}"></td>
				<td th:text="${tmp.name}"></td>
				<td th:text="${tmp.author}"></td>
				<td>
					<a th:href="@{/book/edit(id=${tmp.id})}">수정</a>
				</td>
				<td>
					<a th:href="@{/book/delete(id=${tmp.id})}">삭제</a>
				</td>
			</tr>
		</tbody>
	</table>
</div>
  • new.html 생성
<div class="container">
	<h1>도서 추가 양식</h1>
	<form th:action="@{/book/insert}" method="post">
		<div>
			<label for="name">이름</label>
			<input type="text" name="name" id="name"/>
		</div>
		<div>
			<label for="addr">저자</label>
			<input type="text" name="author" id="author"/>
		</div>
		<button type="submit">저장</button>
	</form>
</div>
  • edit.html 생성
<div class="container">
	<h1>도서 수정 폼</h1>
	<form th:action="@{/book/update}" method="post">
		<input type="hidden" name="id" th:value="${dto.id}"/>
		<div>
			<label for="name">이름</label>
			<input type="text" name="name" id="name" th:value="${dto.name}"/>
		</div>
		<div>
			<label for="addr">저자</label>
			<input type="text" name="author" id="author" th:value="${dto.author}"/>
		</div>
		<button type="submit">수정 확인</button>
		<button type="reset">취소</button>
	</form>
</div>
  • update.html 생성
<div class="container">
	<p>
		<strong th:text="${param.name}">[[${param.name}]]</strong>의 도서 정보 수정 완료
		<a th:href="@{/book/list}">목록 보기</a>
	</p>
</div>
  • delete.html 생성
<script th:inline="javascript">
	alert([[${param.id}]] + " 번 도서의 정보를 삭제 했습니다");
	location.href = [[@{/book/list}]];
</script>

내일 할 내용

  • Client 객체 생성
@Entity // 테이블명을 지정하지 않으면 클래스명과 동일하게 테이블이 만들어진다
public class Client {
	// 고객 번호
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long num;
	
	// 고객의 이름
	@Column(nullable = false, length = 20) // null 허용하지 않음, 최대 길기 20 글자
	private String userName;
	
	// 등록일
	@CreationTimestamp // 최초 저장되는 시점의 시간이 자동으로 들어 가도록
	private LocalDateTime createdAt;
	
	// 수정일
	@UpdateTimestamp // 수정되는 시점의 시간이 자동으로 들어 가도록
	private LocalDateTime updatedAt;
	
	// 생일
	@Column(nullable = true) // 처음에는 바워두었다가 나중에 입력 가능하도록
	private LocalDate birthday; // 생일은 시간을 입력하지 않으므로 LocalDate type 으로
}
profile
학원 공부 내용 정리

0개의 댓글