// 외래키 지정(생성되는 컬럼은 MEMID 레퍼런스컬럼은 MEMBER1테이블의 ID)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMID", referencedColumnName = "ID" )
private Member1 member1;
@JoinColumn
어노테이션을 이용해서 외래키를 불러와 새로운 Column으로 지정가능.
// EAGER => member1을 조회시 address1을 join하여 보여줌
// LAZY => member1을 조회시 address1을 join하지 않고 address1을 필요할 때 조인함.
@ToString.Exclude // stackoverflow
@OneToMany(mappedBy = "member1", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
@OrderBy(value = "no desc")
List<Address1> list = new ArrayList<>();
CascadeType
= 외래키가 걸려있는 데이터의 삭제여부
address.pagetotal=표시할 데이터의 수
먼저 global.properries
파일에 위와 같이 셋팅을해준다.
@Value("${address.pagetotal}") int PAGETOTAL;
어노테이션을 컨트롤러 안에 생성해준다.
위와 같이 사용하고자 하는 부분에 객체명을 넣어주면 되겠다. 이처럼 환경설정 파일에서 미리 값을 지정해두면, 추후에 삭제 및 관리하기가 용이하다.
(기존의 경우에는 직접 사용했던 컨트롤러들을 찾아서 하나하나 수정해주어야 하는 단점이 존재함.)
package com.example.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;
@Data
@Entity
@Table(name = "ADDRESS1")
@SequenceGenerator(name = "SEQ_ADDRESS1_NO", sequenceName = "SEQ_ADDRESS1_NO", initialValue = 1, allocationSize = 1)
public class Address1 {
//주소번호, 기본키, 시퀀스
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ADDRESS1_NO")
@Column(name = "NO")
private long no;
// 우편번호
@Column(name = "POSTCODE", length = 10)
private String postcode;
// 주소(생략시 컬럼명 변수명과 같고 길이는 255)
private String address;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@UpdateTimestamp //변경시에도 날짜 정보 변경
private Date regdate;
// 외래키 (생성되는 컬럼은 MEMID 레퍼런스컬럼은 MEMBER1테이블의 ID)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MEMID", referencedColumnName = "ID" )
private Member1 member1;
}
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>주소목록</h3>
<a th:href="@{/member1/selectlist.do}"><button>회원목록</button></a>
<hr />
회원아이디 : <label th:text="${obj.id}"></label><br />
회원이름 : <label th:text="${obj.name}"></label><br />
<hr />
주소목록 :
<table border="1">
<thead>
<tr>
<th>주소번호</th>
<th>주소</th>
<th>주소</th>
<th>날짜</th>
<th>삭제</th>
</tr>
</thead>
<tbody>
<tr th:each="tmp : ${obj.list}">
<td th:text="${tmp.no}"></td>
<td th:text="${tmp.postcode}"></td>
<td th:text="${tmp.address}"></td>
<td th:text="${tmp.regdate}"></td>
<td>
<form th:action="@{/address1/delete.do}" method="post">
<input type="hidden" name="no" th:value="${tmp.no}" />
<input type="hidden" name="id1" th:value="${obj.id}" />
<input type="submit" value="삭제" />
</form>
</td>
</tr>
</tbody>
</table>
<th:block th:each="num : ${#numbers.sequence(1, pages)}">
<a th:href="@{/address1/selectlist.do(id=${param.id}, page=${num})}" th:text="${num}"></a>
</th:block>
<hr />
주소등록 :
<form th:action="@{/address1/insert.do}" method="post">
<input type="text" name="member1.id" th:value="${obj.id}" readonly /><br />
<input type="text" name="postcode" placeholder="우편번호" /><br />
<input type="text" name="address" placeholder="주소" /><br />
<input type="submit" value="주소등록" />
</form>
</body>
</html>
package com.example.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
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 com.example.entity.Address1;
import com.example.entity.Member1;
import com.example.repository.Address1Repository;
import com.example.repository.Member1Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping(value = "/address1")
@RequiredArgsConstructor
public class Address1Controller {
@Value("${address.pagetotal}") int PAGETOTAL;
final Member1Repository m1Repository; // 저장소 객체
final Address1Repository a1Repository;
final String format = "Address1 => {}";
@PostMapping(value = "/delete.do")
public String deletePOST(
@RequestParam(name = "no") Long no,
@RequestParam(name = "id1") String id) {
try {
log.info(format, no);
a1Repository.deleteById(no);
;
return "redirect:/address1/selectlist.do?id=" + id;
} catch (Exception e) {
return "redirect:/home.do";
}
}
@PostMapping(value = "/insert.do")
public String insertPOST(@ModelAttribute Address1 address1) {
try {
log.info(format, address1.toString()); // stackoverflow
a1Repository.save(address1);
return "redirect:/address1/selectlist.do?id=" + address1.getMember1().getId();
} catch (Exception e) { /* address1해당아이디 */
e.printStackTrace();
// redirect: 주소창의 주소 바꿈
return "redirect:/home.do";
}
}
// /address1/selectlist.do?id=아이디값
@GetMapping(value = "/selectlist.do")
public String selectListGET(Model model,
@RequestParam(name = "id") String id,
@RequestParam(name = "page", defaultValue = "0", required = false) int page) {
try {
if(page==0) { // 페이지 정보가 없다면 1로 변경하기
return "redirect:/address1/selectlist.do?id=" + id + "&page=1";
}
// 회원 정보
Member1 member1 = m1Repository.findById(id).orElse(null);
log.info(format, id.toString()); // 오류발생시점 stackoverflow
model.addAttribute("obj", member1);
// 전체 갯수 가져오기
long total = a1Repository.countByMember1_id(member1.getId());
model.addAttribute("pages", (total - 1) / PAGETOTAL + 1);
// 페이지네이션 설정
PageRequest pageRequest = PageRequest.of(0, PAGETOTAL);
List<Address1> addressList = a1Repository.findByMember1_idOrderByNoDesc(member1.getId(), pageRequest);
model.addAttribute("address", addressList);
// redirect 없을때는 html 표시
return "/address1/selectlist";
} catch (Exception e) {
e.printStackTrace();
// redirect: 주소창의 주소로 바꿈.
return "redirect:/home.do";
}
}
}
package com.example.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import org.springframework.format.annotation.DateTimeFormat;
import lombok.Data;
import lombok.ToString;
@Data
@Entity
@Table(name = "BOARDIMAGE1")
@SequenceGenerator(name = "SEQ_BOARDIMAGE1_NO", sequenceName = "SEQ_BOARDIMAGE1_NO", initialValue = 1, allocationSize = 1)
public class BoardImage1 {
// 이미지번호
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_BOARDIMAGE1_NO")
private long no;
// 이미지명
private String imageName;
// 이미지타입(IMAGE_TYPE)
private String imageType;
// 이미지사이즈 (IMAGE_SIZE)
private long imageSize;
// 이미지데이터
@Lob
@ToString.Exclude
private byte[] imageData;
// 등록일
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
@CreationTimestamp
@Column(name = "REGDATE", insertable = true, updatable = false)
private Date regdate;
// 외래키 (게시글번호)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "BRDNO", referencedColumnName = "NO")
private Board1 board1;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>이미지 목록</h3>
<a th:href="@{/board1/selectlist.do}"><button>게시글목록</button></a><br />
대표이미지<img th:src="${board1.imageUrl}" style="width:100px; height: 100px;"><br />
글번호 : <label th:text="${board1.no}"></label><br />
글제목 : <label th:text="${board1.title}"></label>
<hr />
<div th:each="tmp : ${imageList}" style="display: inline-block; border: 10xp;">
<img th:src="${tmp}" style="width: 100px; height: 100px;">
</div>
<hr/>
<h3> 이미지등록 </h3>
<form th:action="@{/boardimage1/insertimage.do}" method="post" enctype="multipart/form-data">
<input type="text" name="board1.no" th:value="${board1.no}" /> <br />
<input type="file" name="tmpfile" accept="image/*" /><br />
<input type="submit" value="이미지업로드" />
</form>
</body>
</html>
package com.example.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.multipart.MultipartFile;
import com.example.entity.Board1;
import com.example.entity.BoardImage1;
import com.example.repository.Board1Repository;
import com.example.repository.BoardImage1Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Controller
@RequestMapping(value = "/boardimage1")
@RequiredArgsConstructor
public class BoardImage1Controller {
final String format = "BImage => {}";
final Board1Repository b1Repository; // 게시글
final BoardImage1Repository bi1Repository; // 게시글이미지
@Value("${default.image}")
String defaultImage;
final ResourceLoader resourceLoader; // resources 폴더의 파일을 읽기 위한 객체 생성
// 127.0.0.1:9090/ROOT/boardimage1/image?no=1
@GetMapping(value = "/image")
public ResponseEntity<byte[]> image(@RequestParam(name = "no", defaultValue = "0")long no)throws IOException {
BoardImage1 obj = bi1Repository.findById(no).orElse(null);
HttpHeaders headers = new HttpHeaders(); // import org.springframework.http.HttpHeaders
if (obj != null) { // 이미지가 존재할 경우
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);
}
@PostMapping(value = "/insertimage.do")
public String insertImagePOST(
@ModelAttribute BoardImage1 image1,
@RequestParam(name = "tmpfile") MultipartFile file) {
try {
image1.setImageSize(file.getSize());
image1.setImageData(file.getInputStream().readAllBytes());
image1.setImageType(file.getContentType());
image1.setImageName(file.getOriginalFilename());
log.info(format, image1.toString());
bi1Repository.save(image1);
return "redirect:/boardimage1/selectlist.do?no=" + image1.getBoard1().getNo();
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
@GetMapping(value = "/selectlist.do")
public String selectListGET(
Model model, HttpServletRequest request,
@RequestParam(name = "no") long no) {
try {
// 게시글 정보
Board1 board1 = b1Repository.findById(no).orElse(null);
// 대표이미지
BoardImage1 image1 = bi1Repository.findTopByBoard1_noOrderByNoAsc(no);
board1.setImageUrl( request.getContextPath() + "/boardimage1/image?no=0");
if (image1 != null) {
board1.setImageUrl( request.getContextPath() + "/boardimage1/image?no=" + image1.getNo() );
}
// 이미지도 포함하여 view로 전달
model.addAttribute("board1", board1);
// 전체이미지
/* List<String> 타입으로 만들어서 view로 전달 후 출력 */
List<String> imageList = new ArrayList<>();
List<BoardImage1> list1 = bi1Repository.findByBoard1_noOrderByNoAsc(no);
if ( !list1.isEmpty() ) { // 리스트는 비어있지 않는지 확인
for(BoardImage1 tmp : list1){
imageList.add( request.getContextPath() + "/boardimage1/image?no=" + tmp.getNo() );
}
}
// 전체이미지 view로 전달
model.addAttribute("imageList", imageList);
return "/boardimage1/selectlist";
} catch (Exception e) {
e.printStackTrace();
return "redirect:/home.do";
}
}
}