spring 구동 순서
라이브러리 : pom.xml
환경설정 : resources/application.properties
컨트롤러, 서비스등의 컴포넌트 등록 : Boot20220228Application.java
controller, service, view 구현
파일명 Sequence.java
package com.example.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@NoArgsConstructor
@ToString
@Document(collection = "sequence")
public class Sequence {
@Id // 필드이름 _id
// @Field(name = "_id")
private String seqName = null;
@Field(name = "seq")
private long seq = 0L;
}
파일명 SequenceService.java
package com.example.service;
import com.example.entity.Sequence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
// 컨트롤러에서 사용 X
// 다른 service에서 시퀀스가 필요할때 사용할 용도
@Service
public class SequenceService {
@Autowired
private MongoTemplate mongoDB;
public long generatedSequence(String seqName){
// 조건은 _id가 seqName으로 전달되는 것을 찾음
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(seqName));
// seq를 1증가 시킴
Update update = new Update();
update.inc("seq",1);
// 옵션 반환과 1증가를 동시에 수행
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true);
options.upsert(true); // 없으면 insert, 있으면 update => upsert
Sequence counter = mongoDB.findAndModify(query, update, options, Sequence.class);
if(counter != null){
return counter.getSeq();
}
return 1;
}
}
파일명 Item.java
package com.example.entity;
import java.util.Date;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
@NoArgsConstructor
@Document(collection = "item4")
public class Item {
@Id
private long code = 0L;
// @Field(name = "itemname")
private String name = null;
// @Field(name = "itemprice")
private long price = 0L;
private long quantity = 0L;
// import java.util
private Date regdate = null;
// byte 배열
private byte[] filedata = null;
private String filetype = null;
private String filename = null;
private long filesize = 0L;
}
파일명 insert.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<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>물품등록</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}"/>
<script type="text/javascript" src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<div style="padding: 20px;">
<h3>item insert</h3>
<hr />
<form th:action="@{/item/insert}" method="post" enctype="multipart/form-data">
** 물품코드, 등록일은 자동생성<br />
<label style="width:95px; height: 30px; display:inline-block;">물품명 : </label>
<input type="text" placeholder="물품명" name="name"/></br>
<label style="width:95px; height: 30px; display:inline-block;">가격 : </label>
<input type="text" placeholder="가격" name="price"/></br>
<label style="width:95px; height: 30px; display:inline-block;">수량 : </label>
<input type="text" placeholder="수량" name="quantity"/></br>
<label style="width:95px; height: 30px; display:inline-block;">대표 이미지 : </label>
<input type="file" name="image" /><br />
<label style="width:95px; height: 30px; display:inline-block;"></label>
<input type="submit" class="btn btn-primary" value="등록하기" />
</form>
</div>
</body>
</html>
파일명 select.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<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>물품목록</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}"/>
<script type="text/javascript" src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<div style="padding: 20px;">
<h3>item list</h3>
<hr />
<a th:href="@{/item/insert}">등록</a>
<table class="table table-striped">
<tr>
<th>번호</th>
<th>물품번호</th>
<th>물품이름</th>
<th>물품가격</th>
<th>물품수량</th>
<th>이미지</th>
<th>버튼</th>
</tr>
<tr th:each="tmp, idx : ${list}">
<td th:text="${idx.count}"></td>
<td th:text="${tmp.code}"></td>
<td th:text="${tmp.name}"></td>
<td th:text="${tmp.price}"></td>
<td th:text="${tmp.quantity}"></td>
<td><img th:src="@{/item/image(code = ${tmp.code})}" style="width: 50px; height: 50px;" /></td>
<td>
<a th:href="@{/item/update(code=${tmp.code})}" class="btn btn-primary" >수정</a>
<a th:href="@{/item/delete(code=${tmp.code})}" class="btn btn-primary" >삭제</a>
</td>
</tr>
</table>
<th:block th:each="i : ${#numbers.sequence(1, pages)}">
<a th:href="@{/item/selectlist(page=${i})}" th:text="${i}"></a>
</th:block>
</div>
</body>
</html>
파일명 update.jsp
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<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>물품수정</title>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}"/>
<script type="text/javascript" src="@{/js/bootstrap.min.js}"></script>
</head>
<body>
<div style="padding: 20px;">
<h3>item update</h3>
<hr />
<form th:action="@{/item/update}" method="post" enctype="multipart/form-data">
<label style="width:95px; height: 30px; display:inline-block;">물품코드 : </label>
<input type="text" th:value="${item.code}" name="code" readonly /></br>
<label style="width:95px; height: 30px; display:inline-block;">물품명 : </label>
<input type="text" th:value="${item.name}" name="name"/></br>
<label style="width:95px; height: 30px; display:inline-block;">가격 : </label>
<input type="text" th:value="${item.price}" name="price"/></br>
<label style="width:95px; height: 30px; display:inline-block;">수량 : </label>
<input type="text" th:value="${item.quantity}" name="quantity"/></br>
<label style="width:95px; height: 30px; display:inline-block;">대표 이미지 : </label>
<img th:src="@{/item/image(code = ${item.code})}" style="width: 50px; height: 50px;" />
<input type="file" name="image" /><br />
<label style="width:95px; height: 30px; display:inline-block;"></label>
<input type="submit" class="btn btn-primary" value="수정하기" />
<a th:href="@{/item/selectlist}" class="btn btn-primary">목록으로</a>
</form>
</div>
</body>
</html>
파일명 ItemController.java
package com.example.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import com.example.entity.Item;
import com.example.service.ItemDB;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
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.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
@Controller
@RequestMapping(value = {"/item"})
public class ItemController {
@Autowired
public ItemDB itemDB;
// resources/하위폴더의 파일을 읽기위한 객체생성
// private ResourceLoader = new ResourceLoader();
@Autowired
private ResourceLoader resource;
@PostMapping(value = "/update")
public String updatePOST(
@ModelAttribute Item item,
@RequestParam(name="image")MultipartFile file)
throws IOException{
if( !file.isEmpty() ) { // 첨부됨
item.setFilename(file.getOriginalFilename());
item.setFilesize(file.getSize());
item.setFiletype(file.getContentType());
item.setFiledata(file.getBytes());
}
int ret = itemDB.updateItemOne(item);
if(ret == 1){
return "redirect:/item/selectlist";
}
return "redirect:/item/update?code=" + item.getCode();
}
// 127.0.0.1:8080/item/update?code=2
@GetMapping(value = "/update")
public String updateGET(
Model model,
@RequestParam(name = "code")long code){
// DB에서 1개의 정보 읽음
Item item = itemDB.selectOneItem(code);
// jsp로 전달
model.addAttribute("item", item);
// update.jsp 표시
return "item/update";
}
// 127.0.0.1:8080/item/delete?code=2
@GetMapping(value = {"delete"})
public String deleteGET(@RequestParam(name="code") long code){
int ret = itemDB.deleteItem(code);
if(ret == 1 ){
return "redirect:/item/selectlist";
}
return "redirect:/item/selectlist";
}
// 127.0.0.1:8080/item/image?code=2
@GetMapping(value = "/image")
public ResponseEntity<byte[]> imageGET(
@RequestParam(name="code") long code){
try {
System.out.println(code);
Item item = itemDB.selectOneItemImage(code);
System.out.println(item.getFilesize());
if(item.getFilesize() > 0 ){ //이미지가 있음
HttpHeaders headers = new HttpHeaders();
if(item.getFiletype().equals("image/jpeg")){
headers.setContentType(MediaType.IMAGE_JPEG);
}
else if(item.getFiletype().equals("image/png")){
headers.setContentType(MediaType.IMAGE_PNG);
}
else if(item.getFiletype().equals("image/gif")){
headers.setContentType(MediaType.IMAGE_GIF);
}
// 생성자(실재데잉터, headers, 200)
ResponseEntity<byte[]> response =
new ResponseEntity<byte[]>( item.getFiledata(), headers, HttpStatus.OK );
return response;
}
else{// 이미지가 없는 경우
InputStream stream =
resource.getResource("classpath:/static/img/default.jpg").getInputStream();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG);
ResponseEntity<byte[]> response =
new ResponseEntity<byte[]>( stream.readAllBytes() , headers, HttpStatus.OK );
return response;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 127.0.0.1:8080/item/selectlist
// 127.0.0.1:8080/item/selectlist?page=1
@RequestMapping(value = "/selectlist", method = RequestMethod.GET)
// @GetMapping(value = {"/selectlist"})
public String selectlistGET(Model model,
@RequestParam(name = "page", defaultValue = "0") int page){
if(page == 0 ){ // ?page=1을 추가하는 부분
return "redirect:/item/selectlist?page=1";
}
// 1 페이지 => 0
// 2 페이지 => 1
// 1. 목록
Pageable pageable = PageRequest.of(page-1, 10);
List<Item> list = itemDB.selectListItem(pageable);
// 2. 페이지네이션 개수
long pages = itemDB.selectItemCount();
// 목록
model.addAttribute("list", list);
// 10 => 1
// 11 => 2
// 21 => 3
model.addAttribute("pages", (pages-1)/10+1);
// item폴더의 select.jsp를 표시
return "item/select";
}
// 127.0.0.1:8080/item/insert
@GetMapping(value = "/insert")
public String insertGET(){
// item폴더의 insert.jsp를 표시
return "item/insert";
}
// 127.0.0.1:8080/item/insert
@PostMapping(value = "/insert")
public String insertPOST(
@ModelAttribute Item item,
@RequestParam(name = "image") MultipartFile file)
throws IOException {
if(file.isEmpty() == false){ // 첨부됨
item.setFilename(file.getOriginalFilename());
item.setFilesize(file.getSize());
item.setFiletype(file.getContentType());
item.setFiledata(file.getBytes());
}
System.out.println(item.toString());
int ret = itemDB.insertItem(item);
if(ret == 1 ){
return "redirect:/item/selectlist";
}
// GET으로 변경 127.0.0.1:8080/item/insert
return "redirect:/item/insert";
}
}
파일명 ItemDB.java
package com.example.service;
import java.util.List;
import com.example.entity.Item;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
@Service
public interface ItemDB {
// 물품등록(추가할 물품정보가 처리 후에 int(-1, 0, 1)로 반환)
public int insertItem (Item item);
// 물품목록(페이지 정보 1, 2, 3...)
public List<Item> selectListItem(Pageable page);
// 이미지 정보 1개 조회
public Item selectOneItemImage(long code);
// 물품 1개 조회(이미지 제외)
public Item selectOneItem(long code);
// 물품 전체 개수 구하기 (페이지네이션의 페이지 표시용)
public long selectItemCount();
// 물품삭제
public int deleteItem(long code);
// 물품 수정
public int updateItemOne(Item item);
}
파일명 ItemDBImpl.java
package com.example.service;
import java.util.Date;
import java.util.List;
import com.example.entity.Item;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
@Service
public class ItemDBImpl implements ItemDB{
// DB연결객체
@Autowired
private MongoTemplate mongoDB;
// 직접 만든 시퀀스용 서비스
// SequenceService sequence = new SequenceService //만들때 Autowired를 사용해서 사용 불가
@Autowired
private SequenceService sequence;
@Override
public int insertItem(Item item) {
try {
long seq = sequence.generatedSequence("SEQ_ITEM4_CODE");
item.setCode(seq);
// import java.util.Date
Date date = new Date(); //현재시간 만들기
item.setRegdate( date );
Item item1 = mongoDB.insert(item);
if(item1.getCode() == seq ){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@Override
public List<Item> selectListItem(Pageable pageable) {
try {
Query query = new Query();
query.with(pageable); // skip().limit()
query.fields().exclude("filedata", "filetype", "filesize", "filename"); //projection
Sort sort = Sort.by(Direction.DESC,"_id");
query.with(sort); // sort()
return mongoDB.find(query, Item.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public Item selectOneItemImage(long code) {
try {
// 조건 물품번호가 일치하는 것 1개 가져오기
Query query = new Query();
Criteria criteria = Criteria.where("_id").is(code);
query.addCriteria(criteria);
// projection
query.fields().include("filedata", "filetype", "filesize");
return mongoDB.findOne(query, Item.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public Item selectOneItem(long code) {
try {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(code));
return mongoDB.findOne(query, Item.class);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@Override
public long selectItemCount() {
try {
Query query = new Query();
return mongoDB.count(query, Item.class);
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@Override
public int deleteItem(long code) {
try {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(code));
DeleteResult result = mongoDB.remove(query, Item.class);
if(result.getDeletedCount() == 1L){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
@Override
public int updateItemOne(Item item) {
try {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(item.getCode()));
Update update = new Update();
update.set("name",item.getName());
update.set("price",item.getPrice());
update.set("quantity",item.getQuantity());
if(item.getFilesize() > 0){
update.set("Filedata", item.getFiledata());
update.set("Filesize", item.getFilesize());
update.set("Filetype", item.getFiletype());
update.set("Filename", item.getFilename());
}
UpdateResult result = mongoDB.updateFirst(query, update, Item.class);
if(result.getModifiedCount() == 1L){
return 1;
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return -1;
}
}
}