JPA 설명
https://ultrakain.gitbooks.io/jpa/content/chapter1/chapter1.3.html
https://dbjh.tistory.com/77
프로젝트 생성할 때 MySQL Driver, Spring Data JPA 추가
<!-- jaxb-runtime -->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<!-- jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
jpa 관련 dependency들을 https://mvnrepository.com/ 에서 복사해준다.
#server
server.port=9002
#mysql_setting
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sist?serverTimezone=Asia/Seoul
spring.datasource.username=dragon
spring.datasource.password=1234
#JPA_setting
#스키마 생성 create: 기존 테이블 삭제 후 생성, update: 변경된 부분만 반영
spring.jpa.hibernate.ddl-auto=update
#ddl 생성시 고유기능 사용할 지
spring.jpa.generate-ddl=true
#api 호출시 실행되는 sql문을 콘솔에 보여줄 것인지
spring.jpa.show-sql=true
#사용할 데이터베이스 종류
spring.jpa.database=mysql
#mysql 상세지정
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
#JSP_setting
spring.mvc.view.prefix=/WEB-INF/
spring.mvc.view.suffix=.jsp
spring.devtools.livereload.enabled=true
그리고 properties에 setting을 해준다.(나중에 .yml 써보면 더 편하다)
@SpringBootApplication
@ComponentScan({"mycar.*"})
public class SpringBootJpaEx3Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaEx3Application.class, args);
}
}
src/main/java에 mycar.data라는 패키지를 만들어서 @ComponentScan으로 패키지 등록을 해주었다.
이 다음엔 dto를 만들어보자. jpa에선 dto가 매우 중요하다.
Dto에서 테이블을 생성한다.
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") //mycar이라는 테이블에 mysql에 만들어진다
@Data
public class MyCarDto {
@Id //각 엔티티 구별하도록 하는 식별 아이디(시퀀스)
@GeneratedValue(strategy = GenerationType.AUTO)
private long num; //int보다 long을 많이 사용하는 편
@Column(name = "carname")
private String carname;
@Column(name = "carprice")
private int carprice;
@Column(name = "carcolor")
private String carcolor;
@Column(name = "carguip") //이름을 그대로 하는 경우 (name="")을 생략해도 되긴 하지만 @Column은 필수
private String carguip;
@CreationTimestamp //엔티티가 생성되는 시점의 시간을 자동 등록
@Column(updatable = false) //수정했을 때 이 컬럼은 수정하지 않겠다는 뜻, 이게 없으면 null값이 들어감
private Timestamp guipday;
}
@Entity: 자동완성에서 org.hibernate.annotations(X) 말고 javax.persistence(O)를 선택해줘야 한다. 테이블을 만드는 하나의 대응 클래스라고 생각하면 된다.
@Table(name="mycar"): 이것도 javax.persistence로 선택, mycar라는 테이블이 db에 생성된다. (변수를 변경하는 경우 자동 수정됨)
@Data: lombok, setter+getter+toString
@Id: javax.persistence, private long num;이 시퀀스 역할을 할 수 있게 @Id를 준다. Hibernate으로 만들어질 예정
@GenerateVlue(strategy = GenerationType.AUTO): long num이 있는지 없는지에 따라 save가 insert인지 update인지를 구분해준다.
@Column(name="carname"): carname이라는 컬럼을 만든다는 뜻, dto와 컬럼명이 일치하는 경우 name을 생략해도 되지만 @Column은 필수
@CreationTimestamp: 엔티티가 생성되는 시점의 시간을 자동 등록
@Column(updatable = false): 수정했을 때 이 컬럼은 수정하지 않겠다는 뜻, 이게 없으면 null값이 들어감
dto를 다 작성했으면 main으로 다시 ㄱㄱ
import javax.persistence.Entity;
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.*"})
@EntityScan("mycar.data") //dto를 인식
@EnableJpaRepositories("mycar.data") //dao 인식
public class SpringBootJpaEx3Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaEx3Application.class, args);
}
}
(사실 테이블을 만드는 시점에선 @ComponentScan({"mycar.*"}), @EnableJpaRepositories("mycar.data") 이 두가지는 없어도 테이블 생성이 제대로 된다.)
package mycar.data;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MyCarInter extends JpaRepository<MyCarDto, Long>{
}
JpaRepository<T,ID>: T는 table 의미, ID는 Id의 type 의미
이렇게만 해주면 Interface 끝.
@Repository
public class MyCarDao {
@Autowired
MyCarInter carInter;
//insert
public void insertCar(MyCarDto dto) {
carInter.save(dto);
}
}
save는 id타입 유무에 따라 자동으로 insert/update 구분
@Controller
public class MyCarController {
@Autowired
MyCarDao dao;
// http://localhost:9002/carform -> addform.jsp 뜨게 하기
@GetMapping("/carform")
public String form() {
return "mycar/addform";
}
//insert
@PostMapping("/insert")
public String add(@ModelAttribute MyCarDto dto) {
dao.insertCar(dto);
return "redirect:list";
}
//처음 시작할 때(루트), /list일 때 list.jsp 뜨게
@GetMapping({"/","/list"})
public ModelAndView list() {
ModelAndView mview = new ModelAndView();
return mview;
}
<body>
<form action="insert" method="post">
<table class="table table-bordered" style="width: 400px;">
<caption>차 정보 입력</caption>
<tr>
<th bgcolor="pink">차 종류</th>
<td>
<input type="text" name="carname" class="form-control" style="width: 200px;" required="required">
</td>
</tr>
<tr>
<th bgcolor="pink">차 가격</th>
<td>
<input type="text" name="carprice" class="form-control" style="width: 200px;" required="required">
</td>
</tr>
<tr>
<th bgcolor="pink">차 색상</th>
<td>
<input type="color" name="carcolor" class="form-control" style="width: 200px;" required="required">
</td>
</tr>
<tr>
<th bgcolor="pink">차 구입일</th>
<td>
<input type="date" name="carguip" class="form-control" style="width: 200px;" required="required">
</td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="submit">정보 입력</button>
<button type="button" onclick="location.href='list'">목록으로</button>
</td>
</tr>
</table>
</form>
//전체 출력
public List<MyCarDto> getAllList(){
return carInter.findAll();
}
@GetMapping({"/","/list"})
public ModelAndView list() {
ModelAndView mview = new ModelAndView();
List<MyCarDto> list = dao.getAllList();
//저장
mview.addObject("list", list);
mview.addObject("totalCount", list.size());
mview.setViewName("mycar/list");
return mview;
}
<body>
<img alt="" src="icon05.png" style="width: 60px;">
<button type="button" onclick="location.href='carform'">차 등록</button>
<h3>차 목록</h3>
<h4>총 ${totalCount}대의 차가 등록되어 있습니다.</h4>
<table class="table table-bordered" style="width: 1000px;">
<caption>자동차 정보</caption>
<tr>
<th width="60">번호</th>
<th width="130">차종</th>
<th width="80">색상</th>
<th width="150">가격</th>
<th width="180">구입일</th>
<th width="180">등록일</th>
<th width="120">편집</th>
</tr>
<c:forEach var="dto" items="${list}" varStatus="i">
<tr>
<td>${i.count}</td>
<td><a href='detail?num=${dto.num}'>${dto.carname }</a></td>
<td><div class="box" style="background-color: ${dto.carcolor}"></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 HH:mm"/></td>
<td>
<button type="button" onclick="location.href='updateform?num=${dto.num}'">수정</button>
<button type="button" onclick="location.href='delete?num=${dto.num}'">삭제</button>
</td>
</tr>
</c:forEach>
</table>
</body>
수정하려면 수정 버튼을 눌렀을 때 updateform이 나와야 하고, 그 updateform에 내가 수정하고자 하는 데이터의 기존 값이 나와있어야 한다. 그리고 submit 했을 때 수정한 데이터로 db에 저장되어야 한다.
//num에 맞는 dto 출력
public MyCarDto getData(Long num) {
return carInter.getById(num);
}
//수정
public void updateCar(MyCarDto dto) {
carInter.save(dto); //insert와 같은 save지만 num이 포함되어 있으므로 수정으로 인식함
}
insert와 같은 save지만 updateform에는 num이 있으므로 알아서 update임을 인식함
수정 버튼 눌렀을 때 수정폼으로 가고 수정폼에 기존 데이터 뜨게 하기
//수정 버튼 누르면 updateform.jsp 뜨게+기존 데이터 나오게
@GetMapping("/updateform")
public String updateform(@RequestParam Long num, Model model) {
MyCarDto dto = dao.getData(num);
model.addAttribute("dto", dto);
return "mycar/updateform";
}
//수정하기
@PostMapping("/update")
public String update(@ModelAttribute MyCarDto dto) {
dao.updateCar(dto);
return "redirect:list";
}
addform.jsp를 복사하고
1. form의 action 수정
2. hidden으로 num값 넘기기
3. 각 input에 기존 데이터 value값으로 넣기
세가지를 해줘야 한다.
<body>
<form action="update" method="post">
<input type="hidden" name="num" value="${dto.num}">
<table class="table table-bordered" style="width: 500px;">
<caption>차 정보 수정</caption>
<tr>
<th bgcolor="pink">차 종류</th>
<td>
<input type="text" name="carname" class="form-control" style="width: 200px;" value="${dto.carname }">
</td>
</tr>
<tr>
<th bgcolor="pink">차 가격</th>
<td>
<input type="text" name="carprice" class="form-control" style="width: 200px;" value="${dto.carprice }">
</td>
</tr>
<tr>
<th bgcolor="pink">차 색상</th>
<td>
<input type="color" name="carcolor" class="form-control" style="width: 200px;" value="${dto.carcolor}">
</td>
</tr>
<tr>
<th bgcolor="pink">차 구입일</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">정보 수정</button>
<button type="button" onclick="location.href='list'">목록으로</button>
</td>
</tr>
</table>
</form>
</body>
//삭제
public void deleteCar(Long num) {
carInter.deleteById(num);
}
//삭제
@GetMapping("/delete")
public String delete(@RequestParam Long num) {
dao.deleteCar(num);
return "redirect:list";
}
<td><a href='detail?num=${dto.num}'>${dto.carname }</a></td>
//디테일 페이지
@GetMapping("/detail")
public String detail(@RequestParam Long num, Model model) {
MyCarDto dto = dao.getData(num);
model.addAttribute("dto", dto);
return "mycar/detailpage";
}