CREATE TABLE memberinfo1(
id1 varchar2(50) PRIMARY KEY,
info varchar2(255),
regdate timestamp DEFAULT current_timestamp,
FOREIGN KEY (id1) REFERENCES member1(id)
);
memberinfo1 테이블을 생성한다.
---
```java
@ToString.Exclude
@OneToOne(mappedBy = "member1", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private MemberInfo1 memberInfo1;
entity폴더의 Member1.java에 위 코드를 추가한다.
// one to one
@GetMapping(value="/join1.do")
public String join1GET(){
try{
return "/member/join1";
}catch(Exception e){
e.printStackTrace();
return "redirect:/home.do";
}
}
@PostMapping(value="/join1.do")
public String join1POST(@ModelAttribute Member1 member1,
@ModelAttribute MemberInfo1 memberInfo1){
try{
// Member1(id=b11, pw=a, name=b, age=1, regdate=null, memberInfo1=null)
log.info("{}", member1);
member1.setMemberInfo1(memberInfo1);
// MemberInfo1(id=null, member1=null, info=정보, regdate=null)
log.info("{}", memberInfo1);
memberInfo1.setMember1(member1);
m1Repository.save(member1); // 두 개의 테이블에 값이 동시에 추가됨
return "redirect:/member1/join1.do";
}catch(Exception e){
e.printStackTrace();
return "redirect:/home.do";
}
}
Member1Controller에 join1을 추가한다.
<body>
<h3>join1(one to one)</h3>
<form th:action="@{member1/join.do}" method="post">
<input type="text" name="id" /><br />
<input type="text" name="pw" value="a"/><br />
<input type="text" name="name" value="b" /><br />
<input type="number" name="age" value="1" /><br />
<input type="text" name="info" value="정보" /><br />
<input type="submit" value="회원가입" /><br />
</form>
</body>
join1.html또한 생성한다.
@Slf4j
@Controller
@RequestMapping(value = "/menu1")
@RequiredArgsConstructor
public class Menu1Controller {
final Restaurant1Repository r1Repository;
final Menu1Repository m1Repository;
@Value("${default.image}") String DEFAULTIMAGE;
final ResourceLoader resourceLoader;
@GetMapping(value="/update.food")
public String updateGET(
Model model,
@RequestParam(name="no") long no,
@RequestParam(name="rno") long rno,
@RequestParam(name="rphone") String rphone) {
try {
Menu1 obj = m1Repository
.findById(BigInteger.valueOf(no)).orElse(null);
model.addAttribute("obj", obj);
model.addAttribute("rno", rno);
model.addAttribute("rphone", rphone);
return "/menu1/update";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@Transactional(value = Transactional.TxType.NEVER)
@PostMapping(value="/update.food")
public String updatePOST(
@ModelAttribute Menu1 obj,
@RequestParam(name="tmpFile") MultipartFile file ) {
try {
log.info(obj.toString());
log.info(file.toString());
// 기존데이터 읽기
Menu1 obj1 = m1Repository.findById( obj.getNo() ).orElse(null);
// 저장하면 자동으로 DB에 변경됨.
obj1.setName( obj.getName() );
obj1.setPrice( obj.getPrice() );
// 기존데이터를 읽어서 필요한 부분 변경후 다시 저장하기
if(file.isEmpty() == false) {
obj1.setImagedata( file.getBytes() );
obj1.setImagename( file.getOriginalFilename() );
obj1.setImagesize( BigInteger.valueOf( file.getSize() ) );
obj1.setImagetype( file.getContentType() );
}
m1Repository.saveAndFlush(obj1);
return "redirect:/menu1/insert.food?rno=" + obj.getRestaurant1().getNo()
+ "&rphone=" + obj.getRestaurant1().getPhone();
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@PostMapping(value="/delete.food")
public String deletePOST(
@RequestParam(name="no") long no,
@RequestParam(name="rno") long rno,
@RequestParam(name="rphone") String rphone){
try {
m1Repository.deleteById( BigInteger.valueOf(no) );
log.info("{}",no);
return "redirect:/menu1/insert.food?rno=" + rno + "&rphone=" + rphone;
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
// 이미지는 DB에서 꺼내서 url형태로 변경시키야 함.
// 127.0.0.1:9090/ROOT/menu1/image?no=1
// <img src="/ROOT/menu1/image?no=????" />
@GetMapping(value = "/image")
public ResponseEntity<byte[]> image(@RequestParam(name = "no", defaultValue = "0") long no) throws IOException {
Menu1ImageProjection obj = m1Repository.findByNo( BigInteger.valueOf(no) );
HttpHeaders headers = new HttpHeaders();
if(obj != null) { //이미지가 있는 경우
if(obj.getImagesize().longValue() > 0) {
headers.setContentType( MediaType.parseMediaType( obj.getImagetype() ) );
return new ResponseEntity<>( obj.getImagedata(), headers, HttpStatus.OK );
}
}
//이미지가 없을 경우
InputStream is = resourceLoader.getResource(DEFAULTIMAGE).getInputStream(); // exception 발생됨.
headers.setContentType(MediaType.IMAGE_PNG);
return new ResponseEntity<>( is.readAllBytes(), headers, HttpStatus.OK );
}
// 127.0.0.1:9090/ROOT/menu1/insert.food
@GetMapping(value="/insert.food")
public String insertGET(Model model,
@RequestParam(name="rno") long rno,
@RequestParam(name="rphone") String rphone) {
try {
List<Menu1> list = m1Repository.findByRestaurant1_phone(rphone);
model.addAttribute("list", list);
model.addAttribute("rphone", rphone);
model.addAttribute("rno", rno);
return "/menu1/insert";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@PostMapping(value="/insert.food")
public String insertPOST(
@ModelAttribute Menu1 obj,
@RequestParam(name = "tmpFile") MultipartFile file) {
try {
// 파일은 수동으로 obj에 추가하기
obj.setImagedata( file.getInputStream().readAllBytes() );
obj.setImagesize( BigInteger.valueOf( file.getSize() ) );
obj.setImagetype( file.getContentType() );
obj.setImagename( file.getOriginalFilename() );
log.info("Menu1 => {}", obj.toString());
m1Repository.save(obj);
return "redirect:/menu1/insert.food?rno=" + obj.getRestaurant1().getNo()
+ "&rphone=" + obj.getRestaurant1().getPhone();
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
}
<body>
<h3>메뉴 관리</h3>
<a th:href="@{/restaurant1/selectlist.food}"><button>식당목록</button></a><br />
식당번호 : <label th:text="${rno}"></label><br />
식당연락처 : <label th:text="${rphone}"></label><br />
<hr>
<h3>현재 등록된 메뉴 목록</h3>
<table border="1">
<tr>
<td>메뉴이미지</td>
<td>메뉴번호</td>
<td>메뉴이름</td>
<td>메뉴가격</td>
</tr>
<tr th:each="obj : ${list}">
<td><img th:src="@{/menu1/image(no=${obj.no})}" style="width:50px;height:50px" /></td>
<td th:text="${obj.no}"></td>
<td th:text="${obj.name}"></td>
<td th:text="${obj.price}"></td>
<td th:text="${obj.regdate}"></td>
<td>
<a th:href="@{/menu1/update.food(no=${obj.no}, rno=${rno}, rphone=${rphone})}"><button>수정</button></a>
<button th:onclick="deleteAction([[${obj.no}]])">삭제</button>
</td>
</tr>
</table>
<hr>
<h3>메뉴등록</h3>
<form th:action="@{/menu1/insert.food}" method="post" enctype="multipart/form-data">
메뉴명 : <input type="text" name="name"/><br />
가격 : <input type="number" name="price" /><br />
식당번호(변경x) : <input type="text" name="restaurant1.no" th:value="${rno}" readonly /><br />
식당연락처(변경x) : <input type="text" name="restaurant1.phone" th:value="${rphone}" readonly /><br />
이미지 : <input type="file" name="tmpFile" /><br />
<input type="submit" value="메뉴등록" />
</form>
<form th:action="@{/menu1/delete.food}" method="post" id="form2" style="display:none">
<input type="hidden" name="no" id="hidden_no" />
<input type="hidden" name="rno" th:value="${rno}" />
<input type="hidden" name="rphone" th:value="${rphone}" />
</form>
<script th:inline="javascript">
function deleteAction(no){
if( confirm('삭제할까요?')){
document.getElementById('hidden_no').value = no;
document.getElementById('form2').submit();
}
}
</script>
</body>
메뉴등록에 값들을 입력, 파일을 선책한 후에 메뉴등록을 누르면
이렇게 정상적으로 메뉴가 등록된다.
수정 버튼을 눌러서 해당 페이지로 이동한다.
변경할 값과 변경할 이미지를 선택하여 메뉴변경을 누르면
입력한 값과 이미지로 변경된 모습을 볼 수 있다.
삭제를 누르면 삭제할까요? 라는 알림창이 뜬다.
확인을 누르면 삭제된 모습을 볼 수 있다.
CREATE SEQUENCE seq_library2_code START WITH 1 INCREMENT BY 1 NOCACHE NOMAXVALUE;
CREATE SEQUENCE seq_book2_code START WITH 101 INCREMENT BY 1 NOCACHE NOMAXVALUE;
CREATE SEQUENCE seq_admin2_no START WITH 201 INCREMENT BY 1 NOCACHE NOMAXVALUE;
CREATE SEQUENCE seq_checkout2_code START WITH 301 INCREMENT BY 1 NOCACHE NOMAXVALUE;
CREATE TABLE library2(
code number(19) DEFAULT seq_library2_code.nextval,
name varchar2(50),
address varchar2(200),
phone varchar2(20),
regdate timestamp DEFAULT current_timestamp,
PRIMARY key(code)
);
library2
CREATE TABLE student2(
email varchar2(100),
name varchar2(50),
phone varchar2(20),
regdate timestamp DEFAULT current_timestamp,
PRIMARY key(email)
);
student2
CREATE TABLE admin2(
num number(19) DEFAULT seq_admin2_no.nextval,
name varchar2(50),
libcode number(19),
regdate timestamp DEFAULT current_timestamp,
PRIMARY key(num),
FOREIGN key(libcode) REFERENCES library2(code)
);
admin2
CREATE TABLE book2(
code number(19) DEFAULT seq_book2_code.nextval,
title varchar2(50),
price number(19),
author varchar2(50),
regdate timestamp DEFAULT current_timestamp,
libcode number(19),
PRIMARY key(code),
FOREIGN key(libcode) REFERENCES library2(code)
);
book2
CREATE TABLE checkout2(
code number(19) DEFAULT seq_checkout2_code.nextval,
bkcode number(19),
stdemail varchar2(50),
regdate timestamp DEFAULT current_timestamp,
PRIMARY key(code),
FOREIGN key(bkcode) REFERENCES book2(code),
FOREIGN key(stdemail) REFERENCES student2(email)
);
checkout2
entity 폴더에 library 폴더를 생성하고 그 안에 아래 파일들을 생성하여 추가한다.
@EntityScan(basePackages = { "com.example.entity","com.example.entity.library" }) // 엔티티 위치
Boot20230427Application.java를 수정하고
@Data
@Entity
@Table(name="LIBRARY2")
@SequenceGenerator(name = "SEQ_LIBRARY2_CODE", sequenceName = "SEQ_LIBRARY2_CODE", initialValue = 1, allocationSize = 1)
public class Library2 {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_LIBRARY2_CODE")
@Column(name="CODE")
private BigInteger code;
private String name;
private String address;
private String phone;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name="REGDATE", updatable = false)
private Date regdate;
@ToString.Exclude
@OneToMany(mappedBy = "libcode", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
private List<Admin2> admin2 = new ArrayList<>();
@ToString.Exclude
@OneToMany(mappedBy = "libcode", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
private List<Book2> book2 = new ArrayList<>();
}
Library2.java
@Data
@Entity
@Table(name="ADMIN2")
@SequenceGenerator(name = "SEQ_ADMIN2_NO", sequenceName = "SEQ_ADMIN2_NO", initialValue = 1, allocationSize = 1)
public class Admin2 {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ADMIN2_NO")
private BigInteger num;
private String name;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="LIBCODE", referencedColumnName = "CODE")
private Library2 libcode;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name="REGDATE", updatable = false)
private Date regdate;
}
Admin2.java
@Data
@Entity
@Table(name="BOOK2")
@SequenceGenerator(name = "SEQ_BOOK2_CODE", sequenceName = "SEQ_BOOK2_CODE", initialValue = 1, allocationSize = 1)
public class Book2 {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_BOOK2_CODE")
private BigInteger code;
private String title;
private BigInteger price;
private String author;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="LIBCODE", referencedColumnName = "CODE")
private Library2 libcode;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name="REGDATE", updatable = false)
private Date regdate;
@ToString.Exclude
@OneToMany(mappedBy = "bkcode", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
private List<Checkout2> checkout2 = new ArrayList<>();
}
Book2.java
@Data
@Entity
@Table(name="STUDENT2")
public class Student2 {
@Id
private String email;
private String name;
private String phone;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name="REGDATE", updatable = false)
private Date regdate;
@ToString.Exclude
@OneToMany(mappedBy = "stdemail", cascade=CascadeType.REMOVE, fetch=FetchType.LAZY)
private List<Checkout2> checkout2 = new ArrayList<>();
}
Student2.java
@Data
@Entity
@Table(name="CHECKOUT2")
@SequenceGenerator(name = "SEQ_CHECKOUT2_CODE", sequenceName = "SEQ_CHECKOUT2_CODE", initialValue = 1, allocationSize = 1)
public class Checkout2 {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_CHECKOUT2_CODE")
private BigInteger code;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="BKCODE", referencedColumnName = "CODE")
private Book2 bkcode;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="STDEMAIL", referencedColumnName = "EMAIL")
private Student2 stdemail;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name="REGDATE", updatable = false)
private Date regdate;
}
Checkout2.java
이렇게 서로 연동을 시킨다.