부트캠프81일차 spring 소규모프로젝트 (controller , 상품등록,상품업데이트,삭제)
1) 아이템등록,수정,삭제
1-1) create(상품등록 페이지)
1-2) 상품등록 후
1-3) (목록에서 수정)update
1-4) 아이템삭제 ( delete)
1) 아이템등록,수정,삭제 (controller동작방식 간단하게)
package controller;
@Controller
@RequestMapping("item") // http://localhost:8080/shop1/item
public class ItemController {
@Autowired
private ShopService service;
//http://localhost:8080/shop1/item/list 요청 시 호출되는메서드
@RequestMapping("list")
public ModelAndView list() {
//ModelAndView : view에 이름과 , 전달데이터를 저장
ModelAndView mav = new ModelAndView();
List<Item> itemList = service.itemList();
mav.addObject("itemList",itemList);
//mav.setViewName("item/list"); view이름이 null인경우 요청url에서 알아서가져옴
return mav;
}
@GetMapping("detail")
public ModelAndView detail(@RequestParam Integer id) {
ModelAndView mav = new ModelAndView();
Item item = service.getItem(id);
mav.addObject("item",item);
return mav;
}
@GetMapping("create") //GET방식
public ModelAndView create() {
ModelAndView mav = new ModelAndView();
mav.addObject(new Item());
return mav;
}
/*
* Item item : 파라미터의 이름들과 같은
* item클래스의 setProperty를 이용해 파라미터값 자동 저장
*/
@PostMapping("create")//POST방식
public ModelAndView register(@Valid Item item, BindingResult bresult) {
System.out.println("@@item : "+item+"@@");
ModelAndView mav = new ModelAndView();
return mav;
}
}
반환되는 view이름이없다면 requestMapping을 이용해서 알아서 가져온다
또한 ModelAndView객체에 addObject를 실행해
view에 전달할 데이터를 저장해놓음
1-1) create(상품등록 페이지)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><c:catch></c:catch>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!--파일업로드 , 유효성검증 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품등록</title>
</head>
<body>
<%-- enctype="multipart/form-date : POST방식 --%>
<form:form modelAttribute="item" action="create" enctype="multipart/form-data">
<h2>상품등록</h2>
<table>
<tr><td>상품명</td>
<td><form:input path="name"/></td>
<td><font color="red"><form:errors path="name"/></font></td></tr>
<tr><td>상품가격</td>
<td><form:input path="price"/></td>
<td><font color="red"><form:errors path="price"/></font></td></tr>
<tr><td>상품이미지</td>
<td colspan="2"><input type="file" name="picture"></td></tr>
<tr><td>상품설명</td>
<td><form:textarea path="description" cols="20" rows="5"/></td>
<td><font color="red"><form:errors path="description"/></font></td></tr>
<tr><td colspan="3"><input type="submit" value="상품등록">
<input type="button" value="상품목록" onclick="location.href='list'"></td></tr>
</table>
</form:form>
</body>
</html>
여기서 form:errors 라는 이름을 처음볼거다(유효성검증 이라고 봐도 무방함)
path=객체의 get프로퍼티명(파라미터)
또한 form태그에서 넘기지않고 form:form태그를 이용해 객체를 post방식으로 넘겨줌
해당 방식으로 유효성검사를 진행하려면 다음과같이 의존성을 추가해주어야한다
(valid_사용을 위해)
<!--유효성검증-->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.7.Final</version>
</dependency>
Item객체에 다음과같이 notEmpty ,min ,max 등의 어노테이션 설정
package logic;
@Data //getter,setter,toString, EqualsAndHash
public class Item {
private int id;
@NotEmpty(message="상품명 입력")
private String name;
@Min(value=10,message="10원 이상 가능합니다")
@Max(value=100000,message="10만원 이하만 가능합니다")
private int price;
@NotEmpty(message="상품설명 입력하세요")
private String description;
private String pictureUrl;
private MultipartFile picture;
}
controller의 register메서드부분
(BidingResult : 유효성검사의결과를 담고있음)
/*@Valid : Item 클래스에 정의된내용으로 입력값 검증
검증결과 =>bresult에 저장*/
@PostMapping("create")
//valid : 유효성검사
//BindingResult : error를 담고있는 객체
public ModelAndView register(@Valid Item item, BindingResult bresult,
HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
if(bresult.getErrorCount() > 0) { //입력값 검증 오류발생 시
return mav;
}
//정상인경우
service.itemCreate(item,request);
mav.setViewName("redirect:list");
return mav;
}
1-2) 상품등록 후
ShopService의
itemCreate(DB에 item저장)
uploadFileCreate(사진등록담당)
public void itemCreate(Item item, HttpServletRequest request) {
//업로드파일이 존재 시
if(item.getPicture() != null && !item.getPicture().isEmpty()) {
//프로젝트의 img폴더 하위에 저장
String path =request.getServletContext().getRealPath("/")+"img/";
uploadFileCreate(item.getPicture(),path);
item.setPictureUrl(item.getPicture().getOriginalFilename());
}
int maxid = itemDao.maxId();
item.setId(maxid+1); //현재 최대 id에 +1을 해준다.
itemDao.insert(item);
}
private void uploadFileCreate(MultipartFile picture, String path) {
String orgFile = picture.getOriginalFilename();//업로드된 파일명
File f = new File(path);
if(!f.exists()) {
f.mkdirs();
}
try {
//transferTo 메서드를 호출하여 업로드된 파일을 지정된 경로에 저장
picture.transferTo(new File(path+orgFile));
}
catch(Exception e) {
e.printStackTrace();
}
}
ItemDao(mapper에게 쿼리문을 받아옴)
public int maxId() {
return template.getMapper(cls).maxId();
}
public void insert(Item item) {
template.getMapper(cls).insert(item);
}
쿼리문(itemMapper)은 다음과같이 작성했다
@Insert("insert into item values(#{id},#{name},#{price},#{description},#{pictureUrl})")
public void insert(Item item);
@Select("select ifnull(max(id),0) from item")
public int maxId();
1-3) (목록에서 수정)update
이번엔 JSP(view)까지는 보여주지않으려한다.
로직의 흐름정도만 설명하겠음
1) 컨트롤러에서 유효성검사를 끝냈다면
2)service에 itemUpdate(item,request)를 호출함
service의 itemUpdate 메서드
(파일을 업로드하고 업데이트문을 실행함)
public void itemUpdate(Item item, HttpServletRequest request) {
//업로드파일이 존재 시
if(item.getPicture() != null && !item.getPicture().isEmpty()) {
//프로젝트의 img폴더 하위에 저장
String path =request.getServletContext().getRealPath("/")+"img/";
uploadFileCreate(item.getPicture(),path);//폴더에업로드
item.setPictureUrl(item.getPicture().getOriginalFilename());
}
itemDao.update(item);
}
쿼리는 뭐 다음과같이 구성되어있는 간단한 update문임
@Update("update item set name=#{name},"
+ " price=#{price},description=#{description},pictureUrl=#{pictureUrl}"
+ " where id=#{id}")
public void update(Item item);
1-4) 아이템삭제 ( delete)
getMapping을 이용해 delete에 접근하기전에 id를 이용해
item객체를 받아서 모든정보들을 출력해줄거임
delete.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품 삭제 전 확인</title>
</head>
<body>
<h2>상품 삭제 전 확인</h2>
<table>
<tr>
<td><img src="../img/${item.pictureUrl}"></td>
<td><table>
<tr><td>상품명</td><td>${item.name}</td></tr>
<tr><td>가격</td><td>${item.price}</td></tr>
<tr><td>상품설명</td><td>${item.description}</td></tr>
<tr><td colspan="2">
<form action="delete" method="post">
<input type="hidden" name="id" value="${item.id}">
<input type="submit" value="상품 삭제">
<input type="button" value="상품목록" onclick="location.href='list'">
</form>
</table>
</td>
</tr>
</table>
</body>
</html>
폼이넘어가는곳 postMapping
@PostMapping("delete")
public ModelAndView postDelete(@RequestParam Integer id) {
ModelAndView mav = new ModelAndView();
service.deleteItem(id);
mav.setViewName("redirect:list"); //list 재요청
return mav;
}
service와 dao는 그냥 deleteItem메서드를 호출하는 용도로만 사용되므로 간단하다(생략)
쿼리(mapper)
@Delete("delete from item where id=#{id}")
public void deleteItem(Integer id);