1. 어제 이어서 mySQL에서 테이블 생성
<java />
CREATE TABLE PRODUCT(
PROD_ID INT PRIMARY KEY AUTO_INCREMENT, ## PK 자동증가값
PROD_REGDATE TIMESTAMP DEFAULT NOW(), ## 등록일 기본값 시간형
PROD_ENDDATE VARCHAR(20), ## 판매종료일 문자형 시간
PROD_CATEGORY VARCHAR(20), ## 카테고리 키
PROD_WRITER VARCHAR(20), ## 작성자 FK
PROD_NAME VARCHAR(300), ## 상품명
PROD_PRICE INT NOT NULL, ## 가격
PROD_COUNT INT NOT NULL, ## 재고
PROD_DISCOUNT INT DEFAULT 0, ## 할인율 기본값 숫자 0
PROD_PURCHASE_YN CHAR(1) DEFAULT 'N' CHECK (PROD_PURCHASE_YN IN ('Y', 'N')), ##체크제약
PROD_CONTENT VARCHAR(5000), ##내용
PROD_COMMENT VARCHAR(5000) ##메모
);
2. VO 생성, productReg 수정, productController 수정
- productVO 생성, 2~5번째 사진처럼 productReg 수정
- 다음에 productController에 registForm 추가
* productVO, productController
- productVO: 처음에 선언 하고, 어노테이션은 후에 추가로 → 그리고 컨트롤러에서 @valid 처리해줄 것!
<java />
package com.coding404.myweb.command;
import java.time.LocalDateTime;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ProductVO {
/*
* @NotNull - null값만 허용하지 않음(wrapper의 Integer, Long, String 등등)
* @NotBlack - 좀 더 강력한 제약 조건, null값과 공백을 허용하지 않음(String에만 적용)
* @Pattern - 정규 표현식에 맞는 문자열을 정의할 수 있음(String에만 적용)
* @NotEmpty - null값을 허용하지 않음(Array, list에 적용)
* @Email - 이메일 형식 검증(공백은 통과)
* @Min - 최소값
* @Max - 최대값
*/
private int prod_id;
private LocalDateTime prod_regdate;
@NotBlank(message = "공백일 수 없습니다.")
@Pattern(regexp = "[0-9]{4}-[0-9]{2}-[0-9]{2}")
private String prod_enddate;
private String prod_category;
@NotBlank(message = "공백일 수 없습니다.")
private String prod_writer;
@NotBlank(message = "공백일 수 없습니다.")
private String prod_name;
@Min(value = 0, message = "0원 이상이어야 합니다.")
private int prod_price;
private int prod_count;
private int prod_discount;
private String prod_purchase_yn;
private String prod_content;
private String prod_comment;
}
- productController: 등록 요청 추가
<java />
package com.coding404.myweb.controller;
import javax.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.coding404.myweb.command.ProductVO;
@Controller
@RequestMapping("/product")
public class ProductController {
@GetMapping("/productReg")
public String reg() {
return "product/productReg";
}
@GetMapping("/productList")
public String list() {
return "product/productList";
}
@GetMapping("/productDetail")
public String detail() {
return "product/productDetail";
}
//등록 요청
@PostMapping("/registForm")
public String registForm(/*@Valid*/ ProductVO vo) {
return "redirect:/product/productList"; //목록으로
}
}
* 순서
- 매퍼.xml에 매퍼 선언하고 매퍼.java에는 mapper 어노테이션 붙이기
- 서비스 임플에 @Service("productService") 얘 선언해줄 것
- 컨트롤러에서 연결 해줄 것!
<java />
@Autowired
@Qualifier("productService")
private ProductService productService;
- 서비스랑 매퍼.java에 public int regist(ProductVO vo); 선언해주기
- impl 오버라이딩 한 후에 autowired 매퍼
<java />
@Autowired
private ProductMapper productMapper;
- 매퍼.xml에 insert구문 넣기
- 그 다음에 컨트롤러 int result = productService.regist(vo);추가하고 위에 매개변수에 RedirectAttributes ra 추가
(필수는 아니지만 상황에 따라서 필요할 수 있습니다)
<java />
@PostMapping("/registForm")
public String registForm(/*@Valid*/ ProductVO vo,
RedirectAttributes ra) {
int result = productService.regist(vo);
String msg = result == 1 ? "정상 입력되었습니다." : "등록에 실패하였습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/product/productList"; //목록으로
}
- 임플에서 return값에 productMapper.regist(vo);
- 다시 화면 productList 돌아와서 스크립트 태그 추가
- 컨트롤러에서 productList 수정
- 조회
- 상세 보기: 컨트롤러에서 detail 부분은 자율적 숙제입니다.
- detail에서 저장 누르면 update, 삭제는 post 방식으로
* ProductMapper.xml, ProductMapper.java, productservice, productServiceImpl, productController
- ProductMapper.xml
<java />
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.coding404.myweb.product.service.ProductMapper">
<insert id="regist" parameterType="ProductVO">
<!-- vo 참고 -->
insert into PRODUCT(prod_enddate,
prod_writer,
prod_name,
prod_price,
prod_count,
prod_discount,
prod_purchase_yn,
prod_content,
prod_comment )
values( #{prod_enddate},
#{prod_writer},
#{prod_name},
#{prod_price},
#{prod_count},
#{prod_discount},
#{prod_purchase_yn},
#{prod_content},
#{prod_comment})
</insert>
<select id="getList" resultType="ProductVO">
select * from PRODUCT
where prod_writer = #{user_id}
order by prod_id desc
</select>
</mapper>
- ProductMapper.java
<java />
package com.coding404.myweb.product.service;
import java.util.ArrayList;
import org.apache.ibatis.annotations.Mapper;
import com.coding404.myweb.command.ProductVO;
@Mapper //선언 꼭 해줄 것
public interface ProductMapper {
public int regist(ProductVO vo);
public ArrayList<ProductVO> getList(String user_id);
}
- productservice
<java />
package com.coding404.myweb.product.service;
import java.util.ArrayList;
import com.coding404.myweb.command.ProductVO;
public interface ProductService {
public int regist(ProductVO vo);
public ArrayList<ProductVO> getList(String user_id); //조회: 특정 회원 정보만 조회함
}
- productServiceImpl
<java />
package com.coding404.myweb.product.service;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.coding404.myweb.command.ProductVO;
@Service("productService")
public class ProductServiceImpl implements ProductService{
@Autowired
private ProductMapper productMapper;
@Override
public int regist(ProductVO vo) {
return productMapper.regist(vo);
}
@Override
public ArrayList<ProductVO> getList(String user_id) {
return productMapper.getList(user_id);
}
}
- productController
<java />
package com.coding404.myweb.controller;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.coding404.myweb.command.ProductVO;
import com.coding404.myweb.product.service.ProductService;
@Controller
@RequestMapping("/product")
public class ProductController {
@Autowired
@Qualifier("productService")
private ProductService productService;
@GetMapping("/productReg")
public String reg() {
return "product/productReg";
}
@GetMapping("/productList")
public String list(HttpSession session,
Model model) { /*, HttpServletRequest request */
//프로세스
//admin이라고 가정
session.setAttribute("user_id", "admin");
//로그인 한 회뭔만 조회
String user_id = (String)session.getAttribute("user_id");
ArrayList<ProductVO> list = productService.getList(user_id);
model.addAttribute("list", list);
return "product/productList";
}
@GetMapping("/productDetail")
public String detail() {
return "product/productDetail";
}
//등록 요청
@PostMapping("/registForm")
public String registForm(/*@Valid*/ ProductVO vo,
RedirectAttributes ra) {
int result = productService.regist(vo);
String msg = result == 1 ? "정상 입력되었습니다." : "등록에 실패하였습니다";
ra.addFlashAttribute("msg", msg);
return "redirect:/product/productList"; //목록으로
}
}
2. 페이징
* 순서
1) 첫번째 작업: 10개 페이지 화면에 보여지게 만들기
- testCode 작성한 후 run as → JUnit : 돌리고 나서는 주석 처리 해둘 것!(나도 모르게 돌리면 계속 생성되니까)
- util 패키지 만들고 criteria 생성: SQL에 전달할 page, amount을 가지고 다니는 클래스
- 그 다음에 productMapper.java
- testcode에서 잘 굴러가는지 확인(test02)
- 서비스, 서비스impl에서 cri 추가
- 컨트롤러 수정
- 결과: 화면에서 10개의 페이지만 나옴
* TestCode, Criteria
- TestCode
<java />
package com.coding404.myweb;
import java.util.ArrayList;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.coding404.myweb.command.ProductVO;
import com.coding404.myweb.product.service.ProductMapper;
import com.coding404.myweb.util.Criteria;
@SpringBootTest
public class TestCode {
@Autowired
ProductMapper productMapper;
// @Test
// public void testCode01() {
// for(int i=1; i<=300; i++) {
//
// ProductVO vo = ProductVO.builder().prod_enddate("2023-02-15")
// .prod_writer("admin")
// .prod_name("test" + i)
// .prod_price(i * 1000)
// .prod_count(i * 100)
// .prod_discount(i)
// .prod_purchase_yn("N")
// .prod_content("컨텐츠" + i)
// .prod_comment("hello world!")
// .build();
//
// productMapper.regist(vo);
// }
// }
@Test
public void testCode02() {
Criteria cri = new Criteria(1, 10);
ArrayList<ProductVO> list = productMapper.getList("admin", cri);
System.out.println(list.toString());
}
}
- Criteria
<java />
package com.coding404.myweb.util;
import lombok.Data;
@Data
public class Criteria {
//SQL에 전달할 page, amount을 가지고 다니는 클래스
private int page; //조회하는 페이지 번호
private int amount; //데이터 갯수
public Criteria() {
this.page = 1;
this.amount = 10;
}
//생성자 생성
public Criteria(int page, int amount) {
super();
this.page = page;
this.amount = amount;
}
//앞쪽에 들어갈 변수
public int getPageStart() {
return (page - 1) * amount;
}
}
2) 2번째 작업(startPage, endPage, realEnd...)
- PageVO 생성
- PageVO
<java />
package com.coding404.myweb.util;
import java.util.ArrayList;
import lombok.Data;
@Data
public class PageVO {
//페이지 네이션을 계산하는 클래스
private int start; //첫 페이지 번호
private int end; //끝 페이지 번호
private boolean prev; //이전 버튼
private boolean next; //다음 버튼
private int page; //조회하는 번호
private int amount; //데이터 갯수
private int total; //전체 게시글 수
private int realEnd; //실제 끝 번호
private int pageCount = 10; //페이지 네이션 갯수
private Criteria cri;
private ArrayList<Integer> pageList; //화면에 반복시킬 페이지 번호
//생성자
public PageVO(Criteria cri, int total) {
this.page = cri.getPage();
this.amount = cri.getAmount();
this.total = total;
this.cri = cri;
//끝 페이지 번호(int)Math.ceil(조회 하는 페이지 번호 / 페이지 네이션 갯수) * 페이지 네이션 갯수
this.end = (int)Math.ceil( this.page / (double)pageCount ) * pageCount;
//시작 페이지 번호: 끝페이지 번호 - 페이지 네이션 갯수 + 1
this.start = this.end - pageCount + 1;
//실제 끝 번호
//데이터가 141개 라면 → 마지막 페이지 번호는 15번
//(int)Math.ceil(전체 게시글 수 / 데이터 갯수)
this.realEnd = (int)Math.ceil( this.total / (double)this.amount );
//실제 끝 번호 재계산
//데이터 141개 라면 → 1~10 end=10번 realEnd=15,
// 11~20 end=20 realEnd=15
this.end = this.end > this.realEnd ? this.realEnd : this.end;
//이전 버튼 활성화
//start는 1, 11, 21..
this.prev = this.start > 1;
//다음 버튼 활성화
//데이터 141개 라면 → 1~10 end=10번 realEnd=15, 이 때 true
this.next = this.realEnd > this.end;
//화면에서 반복시킬 페이지 데이터
this.pageList = new ArrayList<>();
for(int i = this.start; i <= this.end; i++) {
pageList.add(i);
}
}
}
- 컨트롤러에서 pageVO 생성
- pageList에서 page 부분 수정
- pageList: th:href에서 th 안 썼을 때 안넘어가는 오류 생김. 꼭 빠지지 말고 쓸 것!
<java />
<div class="page">
<ul>
<li>
<a th:href="@{productList(page=1, amount=${pageVO.amount} )}">
<i class="fa fa-angle-double-left" aria-hidden="true"></i>
</a>
</li>
<!-- 이전 버튼 -->
<th:block th:if="${pageVO.prev}">
<li style="margin-right: 5px;">
<a th:href="@{productList(page=${pageVO.start -1}, amount=${pageVO.amount} )}"><i class="fa fa-angle-left" aria-hidden="true"></i></a>
</li>
</th:block>
<!-- 1~10번까지 그려짐, on이 들어가있으면 활성화, 이걸 하면 2번, 3번 누를 때 넘어가야함! -->
<th:block th:each="page : ${pageVO.pageList}">
<li th:class="${page == pageVO.page ? 'on' : ''}"><a th:href="@{productList(page=${page}, amount=${pageVO.amount})}">[[${page}]]</a></li>
</th:block>
<!-- 다음 버튼 -->
<th:block th:if="${pageVO.next}">
<li style="margin-left: 5px;">
<a th:href="@{productList(page=${pageVO.end + 1}, amount=${pageVO.amount} )}"><i class="fa fa-angle-right" aria-hidden="true"></i></a>
</li>
</th:block>
<!-- 맨 끝 페이지 -->
<li>
<a th:href="@{productList(page=${pageVO.realEnd}, amount=${pageVO.amount})}"><i class="fa fa-angle-double-right" aria-hidden="true"></i></a>
</li>
</ul>
</div>
- 10, 20, 50, 100개 보기 기능 추가
- 값에 대한 유지
3. 검색
- 검색의 조건이 많아지면 sql문에 대해 잘 생각해 봐야함(어떤 경우의 수에도 돌아가야 하기 때문에)
- 검색 키워드를 넘기고, sql문 조회가 일어나게 함(판매마감일은 이상, 이하)
- 크리테리아에 변수 추가
- 컨트롤러
- sql문, xml: 3번째 사진처럼 문자열 비교는 안됨. date로 형변환 해줄 것. sql문 and로 해야 사이 데이터들이 다 나옴!
'TIL > Spring boot' 카테고리의 다른 글
day88-spring boot (0) | 2023.02.17 |
---|---|
day86-spring boot (0) | 2023.02.16 |
day84-spring boot (0) | 2023.02.14 |
day83-spring boot (0) | 2023.02.13 |
day82-spring boot (0) | 2023.02.09 |