: 스프링에서데이타를처리할수있도록돕는라이브러리이다
데이타베이스에종속적인 SQL문없이도개발이가능하기때문에개발의생산성을높일수있다
기존의 JDBC 등을이용해서직접구현했던 데이타베이스관련작업을대신처리해주는추상화된계층의구현스펙이다
JPA에서는 엔티티는 테이블에 대응하는 하나의 클래스라고 생각하면 된다
spring-boot-starter-data-jpa 의존성을 추가하고 @Entiy 어노테이션을 붙이면 테이블과 자바 클래스가 매핑이 됩니다.
그래서 JPA에서 '하나의 엔티티 타입을 생성한다'라는 의미는 '하나의 클래스를' 작성한다는 의미가 됩니다.
엔티티라는 용어는 때로는 클래스를 의미하는 경우도 있고, 클래스에 의해 생성된 인스턴스를 의미하는 경우가 있습니다.
정확히 얘기 하자면, 엔티티클래스 와 엔티티인스턴스 혹은 엔티티객체라는 표현이 정확합니다
자바 언어를 위한 ORM 프레임워크. JPA의 구현체로, JPA 인터페이스를 구현하며, 내부적으로 JDBC API를 사용한다.
초기세팅
<!-- https://mvnrepository.com/artifact/org.glassfish.jaxb/jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
# mysql setting
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/클래스명?serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=비밀번호
# JPA setting
# 스키마 생성 create:기존 테이블을 삭제 후 생성해준다. (이름이 겹치는 경우 삭제 후 만들어버린다.),
# update:변경된 부분만 반영된다. 아래 한줄이 이 개념을 설명해주는것이다.
spring.jpa.hibernate.ddl-auto=update
# ddl 생성시 데이터베이스의 고유기능 사용 유,무 설정
spring.jpa.generate-ddl=true
# api호출 시 내부적으로 실행되는 sql문을 콘솔에 보여주기 설정 유,무
spring.jpa.show-sql=true
# 사용할 database 종류 선택(mysql,oracle,mariadb 등등..)
spring.jpa.database=mysql
# mysql 상세지정하기 (mysql 고유 특성 지정) // 내부적인 기본 platform 지정.
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
실행하기
여기서 seq역할을 하는 변수는 long type으로 사용해야 한다!!
package mycar.data;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import lombok.Data;
@Entity // 기본 설정
@Table(name="mycar") // 자동으로 mysql에 mycar 라는 table이 만들어진다.
@Data
public class MyCarDto {
@Id // 각 엔티티를 구별할 수 있는 식별 id 이다. 즉 seq라고 봐도 된다. 기본키, primary key를 지정하는 것. // Id만 써도 된다 라고 하는데.. 보통 쌤은 2개 쓴다.
@GeneratedValue(strategy = GenerationType.AUTO) // 이것도 엔티티를 구별할 수 있는 식별자.
private long num;
// 멤버등록하기
@Column(name = "carname") // 이름을 지정할 시에 이름을 지정해줘야 한다.
private String carname;
@Column // 이름을 똑같이 쓸 경우 안써도 된다.
private int carprice;
@Column
private String carcolor;
@Column
private String carguip;
@CreationTimestamp // 엔티티가 생성되는 시점의 시간을 자동지정. 날짜는 now()로 해서 바로 기입되잖아 ^^
@Column(updatable = false) // 업데이트시에 이 컬럼은 수정하지 않겠다. 이게 없으면 값이 null로 들어간다(자동 업데이트). updateform에 해당 guipday를 기입하지 않기 때문이다.
private Timestamp guipday;
@Column
private String carphoto;
}
package mycar.data;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MyCarDaoInter extends JpaRepository<MyCarDto, Long>{
// 레포지터리 라는거 JpaRepository 는 추상 클래스이다...
// 추상 클래스는 모든 추상메서드들을 무조건 오버라이딩 해야한다.
// 그렇기 때문에 extends 하면 내가 사용하지 않은것들 포함하여 갯수가 너무 많다.
// 그래서 dao에서 extends 해서 가져오는게 아니라 호출(@Autowired)해서 사용한다.
}
package mycar.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.ModelAttribute;
@Repository // dao를 bean에 등록
//public class MyCarDao implements MyCarDaoInter { // 상속을 수십개를 받아야 하기 때문에 implements 없애준다.
public class MyCarDao {
@Autowired
MyCarDaoInter carInter;
// insert
public void insertMyCar(MyCarDto dto) {
carInter.save(dto); // insert를 save라고 한다. update도 save라고 한다.
// id type의 유,무에 따라 insert와 update가 자동으로 갈린다...
// insert는 auto_increment로 id가 추가되고(id값을 모르는 상태), update는 원래 있는 id를 기준으로(id를 알고있는 상태) 변경하기에 구분 해준다.
}
// select
public List<MyCarDto> getAllData(){
return carInter.findAll();
}
// update하기
// num에 대한 값(dto) 반환
public MyCarDto getData(long num) {
return carInter.getReferenceById(num);
}
// update
public void updateCar(MyCarDto dto) { // insert와 동일하므로, insert로 사용해도 무관함
carInter.save(dto);
}
// delete
public void deleteCar(long num) {
carInter.deleteById(num);
}
}
package mycar.data;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("/car") // 중복 경로 전체 자동 기입
public class MyCarController {
@Autowired
MyCarDao dao;
@GetMapping("/carlist") //..시작 // 중간경로는 해도 되고, 안해도 되고
public ModelAndView list() {
ModelAndView model=new ModelAndView();
List<MyCarDto> list=dao.getAllData();
model.addObject("list", list);
model.addObject("totalCount", list.size());
model.setViewName("carlist");
return model;
}
@GetMapping("/carform")
public String form() {
return "addform";
}
// insert
@PostMapping("/insert") // multipart 관련사항 수정해주기. MultiPart, HttpSession,등등 받아오면 끝!
public String insert(@ModelAttribute MyCarDto dto,
MultipartFile carupload,
HttpSession session) {
// 업로드할 save 위치 구하기
String path=session.getServletContext().getRealPath("/save");
// 업로드한 파일 dto얻기
dto.setCarphoto(carupload.getOriginalFilename());
// 실제 업로드
try {
carupload.transferTo(new File(path+"/"+carupload.getOriginalFilename()));
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// insert
dao.insertMyCar(dto);
return "redirect:carlist";
}
// updateform 연결하기
@GetMapping("/updateform")
public String uform(Model model,@RequestParam long num) {
MyCarDto dto=dao.getData(num);
model.addAttribute("dto", dto);
return "uform";
}
// 업데이트
@PostMapping("/updatecar")
public String updatecar(@ModelAttribute("dto") MyCarDto dto) {
dao.updateCar(dto); // insert와 동일하므로, insert로 사용해도 무관함
return "redirect:carlist";
}
// 삭제
@GetMapping("/deletecar")
public String delete(@RequestParam long num) {
dao.deleteCar(num);
return "redirect:carlist";
}
// detail page
@GetMapping("/detail")
public String detail(@RequestParam long num,Model model) {
MyCarDto dto=dao.getData(num);
model.addAttribute("dto", dto);
return "detail";
}
}
package boot.mvc.tea;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@ComponentScan({"mycar.data"})// 패키징 등록
@EntityScan("mycar.data") // table이 어디에 생성되는지 지정 // dto 인식
@EnableJpaRepositories("mycar.data") // dao인식 (method인식) // Repositoriy를 bean에 자동 등록해줘!!
public class SpringBootJpaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaApplication.class, args);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
<style type="text/css">
.box{
border: 1px solid gray;
width: 30px;
height: 30px;
border-radius: 30px;
}
</style>
</head>
<body>
<div style="margin: 50px 100px;">
<img alt="" src="../20.jpg" style="width: 150px;">
<button type="button" class="btn btn-info" onclick="location.href='carform'">자동차정보입력</button>
<br><br>
<h3 class="alert alert-info">
<b>총 ${totalCount }개의 자동차 정보가 있습니다.</b>
</h3>
<table class="table table-bordered">
<tr>
<th style="width: 60px;">번호</th>
<th style="width: 120px;">자동차명</th>
<th style="width: 100px;">색상</th>
<th style="width: 160px;">가격</th>
<th style="width: 220px;">구입일</th>
<th style="width: 220px;">등록일</th>
<th style="width: 200px;">편집</th>
</tr>
<c:forEach var="dto" items="${list }" varStatus="i">
<tr>
<td>${i.count }</td>
<td>
<a href="detail?num=${dto.num }">
<img alt="" src="../save/${dto.carphoto }" width="40" height="40" border="1" hspace="10">
${dto.carname }
</a>
</td>
<td><div style="background-color: ${dto.carcolor}" class="box"></div></td>
<td><fmt:formatNumber value="${dto.carprice }" type="currency"/></td>
<td>${dto.carguip }</td>
<td><fmt:formatDate value="${dto.guipday }" pattern="yyyy.MM.dd"/></td>
<td>
<button type="button" class="btn btn-outline-warning" onclick="location.href='updateform?num=${dto.num}'">수정</button>
<button type="button" class="btn btn-outline-danger" onclick="location.href='deletecar?num=${dto.num}'">삭제</button>
</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 100px 100px; width: 500px;">
<form action="insert" method="post" enctype="multipart/form-data">
<table class="table table-bordered">
<tr>
<th>자동차명</th>
<td>
<input type="text" name="carname" class="form-control" style="width: 120px;" required="required">
</td>
</tr>
<tr>
<th>가격</th>
<td>
<input type="text" name="carprice" class="form-control" style="width: 150px;" required="required">
</td>
</tr>
<tr>
<th>색상</th>
<td>
<input type="color" name="carcolor" class="form-control" style="width: 200px;" required="required" value="#ff0000">
</td>
</tr>
<tr>
<th>구입일</th>
<td>
<input type="date" name="carguip" class="form-control" style="width: 200px;" value="2023-10-01">
</td>
</tr>
<!-- 파일 업로드의 경우 이름과 dto가 같다고 해서 바로 올라가는게 아니다.. -->
<!-- 이름을 똑같이 할 경우 오류 찾기가 어려워,, 구분을 위해 dto name과 여기 input의 Name을 다르게 준다. -->
<tr>
<th>자동차 이미지</th>
<td>
<input type="file" name="carupload" class="form-control" style="width: 200px;" required="required">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-outline-info">저장</button>
<button type="button" class="btn btn-outline-success" onclick="location.href='carlist'">목록</button>
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
</head>
<body>
<div style="margin: 100px 100px; width: 500px;">
<form action="updatecar" method="post">
<input type="hidden" name="num" value="${dto.num }">
<table class="table table-bordered">
<tr>
<th>자동차명</th>
<td>
<input type="text" name="carname" class="form-control" style="width: 120px;" required="required" value="${dto.carname }">
</td>
</tr>
<tr>
<th>가격</th>
<td>
<input type="text" name="carprice" class="form-control" style="width: 150px;" required="required" value="${dto.carprice }">
</td>
</tr>
<tr>
<th>색상</th>
<td>
<input type="color" name="carcolor" class="form-control" style="width: 200px;" required="required" value="${dto.carcolor }">
</td>
</tr>
<tr>
<th>구입일</th>
<td>
<input type="date" name="carguip" class="form-control" style="width: 200px;" value="${dto.carguip }">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit" class="btn btn-outline-info">저장</button>
<button type="button" class="btn btn-outline-success" onclick="location.href='carlist'">목록</button>
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css2?family=Bagel+Fat+One&family=Dongle:wght@300&family=East+Sea+Dokdo&family=Gamja+Flower&family=Gowun+Dodum&family=Nanum+Gothic+Coding&family=Nanum+Pen+Script&family=Orbit&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<script src="https://code.jquery.com/jquery-3.7.0.js"></script>
<title>Insert title here</title>
<style type="text/css">
.photo{
width: 300px;
height: 300px;
border: 1px solid gray;
border-radius: 20px;
}
div.box{
width: 50px;
height: 50px;
border-radius: 30px;
border: 1px solid gray;
}
</style>
</head>
<body>
<h3 class="alert alert-info">구입 자동차 정보</h3>
<table class="table table-bordered" style="width: 500px;">
<tr>
<td width="320" rowspan="4">
<img alt="" src="../save/${dto.carphoto }" class="photo">
</td>
<td>
<div class="box" style="background-color: ${dto.carcolor};"></div>
${dto.carcolor}
</td>
</tr>
<tr>
<td>자동차명: ${dto.carname }</td>
</tr>
<tr>
<td>단가: <fmt:formatNumber value="${dto.carprice }" type="currency"></fmt:formatNumber></td>
</tr>
<tr>
<td>구입일 :${dto.carguip }</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="button" class="btn btn-outline-warning" onclick="location.href='updateform?num=${dto.num}'">수정</button>
<button type="button" class="btn btn-outline-danger" onclick="location.href='deletecar?num=${dto.num}'">삭제</button>
<button type="button" class="btn btn-outline-info" onclick="location.href='carform'">등록</button>
<button type="button" class="btn btn-outline-success" onclick="location.href='carlist'">목록</button>
</td>
</tr>
</table>
</body>
</html>