1. 어제 검색 기능 이어서 설명
1) 검색 폼에서는 키워드, page, amount 데이터를 넘깁니다.
2) 목록 조회 and total 동적 쿼리로 변경
* productMapper.xml
<select id="getList" resultType="ProductVO">
select * from PRODUCT
where prod_writer = #{user_id}
<if test="cri.startDate != null and cri.startDate != '' ">
<![CDATA[ and date_format(prod_enddate, '%Y-%m-%d') >= date_format( #{cri.startDate}, '%Y-%m-%d')]]>
</if>
<if test="cri.endDate != null and cri.endDate != '' ">
<![CDATA[ and date_format(prod_enddate, '%Y-%m-%d') <= date_format( #{cri.endDate}, '%Y-%m-%d') ]]>
</if>
<if test="cri.searchName != null and cri.searchName != '' ">
and prod_name like concat('%', #{cri.searchName}, '%')
</if>
<if test="cri.searchContent != null and cri.searchContent != '' ">
and prod_content like concat('%', #{cri.searchContent}, '%')
</if>
order by
<if test="cri.searchPrice == 'asc' ">
prod_price asc,
</if>
<if test="cri.searchPrice == 'desc' ">
prod_price desc,
</if>
prod_id desc
limit #{cri.pageStart}, #{cri.amount}
</select>
<select id="getTotal" resultType="int">
select count(*) as total from PRODUCT
where prod_writer = #{user_id}
<if test="cri.startDate != null and cri.startDate != '' ">
<![CDATA[ and date_format(prod_enddate, '%Y-%m-%d') >= date_format( #{cri.startDate}, '%Y-%m-%d')]]>
</if>
<if test="cri.endDate != null and cri.endDate != '' ">
<![CDATA[ and date_format(prod_enddate, '%Y-%m-%d') <= date_format( #{cri.endDate}, '%Y-%m-%d') ]]>
</if>
<if test="cri.searchName != null and cri.searchName != '' ">
and prod_name like concat('%', #{cri.searchName}, '%')
</if>
<if test="cri.searchContent != null and cri.searchContent != '' ">
and prod_content like concat('%', #{cri.searchContent}, '%')
</if>
</select>
- getTotal도 cri 받아줄 것!(컨트롤러, 서비스, 서비스 impl, mapper도 getTotal 수정)
3) 페이지 네이션에 키워드, page, amount 데이터를 넘깁니다.
- productList에 내용 변경해줄 것!
<div class="page">
<ul>
<li><a th:href="@{productList(page=1,
amount=${pageVO.amount},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><i class="fa fa-angle-left" aria-hidden="true"></i></a></li>
</th:block>
<th:block th:each="page : ${pageVO.pageList}">
<li th:class="${page == pageVO.page ? 'on' : ''}">
<a th:href="@{productList(page=${page},
amount=${pageVO.amount},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}">[[${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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice} )}"><i class="fa fa-angle-double-right" aria-hidden="true"></i></a></li>
</ul>
</div>
4) 검색 키워드 화면에서 유지시킴(초기화 버튼 있으면 좋을 것 같음)
* productList(아래 스크립트 태그 부분 수정)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<th:block th:replace="~{./include/basicLayout :: 함수( ~{:: .wrap } ) }">
<div class="wrap">
<div class="warp_inner">
<!-- left_menu end -->
<div class="right_content">
<div class="midiaq">
<div class="page_title">관리자검색</div>
<form name="actionForm" action="productList" method="get" >
<!--
1. 검색폼 에서는 키워드, page, amount 데이터를 넘깁니다.
-->
<input type="hidden" name="page" th:value="1">
<input type="hidden" name="amount" th:value="${pageVO.amount}">
<div class="search_block flfull">
<div class="fl">
<div>
<span class="search_th">상품이름 검색</span>
<input type="text" class="" name="searchName" th:value="${pageVO.cri.searchName}" placeholder="상품 검색">
</div>
<div>
<span class="search_th">상품내용 검색</span>
<input type="text" class="" name="searchContent" th:value="${pageVO.cri.searchContent}" placeholder="상품 검색">
</div>
<div>
<span class="search_th">판매가 정렬</span>
<select class="" name="searchPrice">
<option value="none" th:selected="${pageVO.cri.searchPrice} == 'none'">정렬방식</option>
<option value="asc" th:selected="${pageVO.cri.searchPrice} == 'asc'">낮은순</option>
<option value="desc" th:selected="${pageVO.cri.searchPrice} == 'desc'">높은순</option>
</select>
</div>
<!-- 2row -->
<div class="pdt15"></div>
<div>
<span class="search_th">판매마감일</span>
<input type="text" class="datepicker" name="startDate" th:value="${pageVO.cri.startDate}" readonly placeholder="날짜선택" /> -
<input type="text" class="datepicker" name="endDate" th:value="${pageVO.cri.endDate}" readonly placeholder="날짜선택" />
</div>
<!--
<div>
<span class="search_th">처리자 ID</span>
<input type="text" class="" placeholder="처리자 ID">
</div>
-->
</div>
<div class="fr">
<div class="search_btn_area">
<!--
<a href="#" class="normal_btn purplebtn">검색</a>
-->
<input type="submit" class="normal_btn purplebtn" value="검색">
<a href="#" class="normal_btn purplebtn02">등록</a>
</div>
</div>
</div>
<div class="full_collum collum">
<ul>
<li class="collum_tit">
<h2>상품 관리</h2>
<select class="" id="handleAmount">
<option value="10" th:selected="${pageVO.amount} == 10">10개 보기</option>
<option value="20" th:selected="${pageVO.amount} == 20">20개 보기</option>
<option value="40" th:selected="${pageVO.amount} == 40">40개 보기</option>
<option value="80" th:selected="${pageVO.amount} == 80">80개 보기</option>
</select>
<span class="showtoggle minus"></span>
<ul>
<li>
<table cellpadding="0" cellspacing="0" class="col_14" width="100%;">
<tr>
<th>순서</th>
<th>표시</th>
<th>상품번호</th>
<th>카테고리</th>
<th>제목(상품명)</th>
<th>등록일</th>
<th>판매가</th>
<th>재고상태</th>
<th>할인율</th>
<th>상품 구매제한</th>
<th>판매마감일</th>
<th>등록자</th>
</tr>
<tr th:each="vo, status : ${list}">
<td>[[${status.count}]]</td>
<td>
<a href="#" class="normal_btn">정보수정</a>
<a href="#" class="normal_btn modalOn">이미지수정</a>
</td>
<td>[[${vo.prod_id}]]</td>
<td>.....</td>
<td>
<a title="상세보기(클릭)" th:href="@{ productDetail(prod_id = ${vo.prod_id}) }">
[[${vo.prod_name}]]
</a>
</td>
<td>[[${ #temporals.format(vo.prod_regdate, 'yyyy-MM-dd') }]]</td>
<td>[[${vo.prod_price}]]원</td>
<td>[[${vo.prod_count}]]개</td>
<td>[[${vo.prod_discount}]]%</td>
<td>[[${vo.prod_purchase_yn == 'Y' ? '제한없음' : '1회제한'}]]</td>
<td>[[${vo.prod_enddate}]]</td>
<td>[[${vo.prod_writer}]]</td>
</tr>
</table>
<!--
<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>
<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>
-->
<div class="page">
<ul>
<li><a th:href="@{productList(page=1,
amount=${pageVO.amount},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><i class="fa fa-angle-left" aria-hidden="true"></i></a></li>
</th:block>
<th:block th:each="page : ${pageVO.pageList}">
<li th:class="${page == pageVO.page ? 'on' : ''}">
<a th:href="@{productList(page=${page},
amount=${pageVO.amount},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}">[[${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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice}
)}"><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},
startDate=${pageVO.cri.startDate},
endDate=${pageVO.cri.endDate},
searchName=${pageVO.cri.searchName},
searchContent=${pageVO.cri.searchContent},
searchPrice=${pageVO.cri.searchPrice} )}"><i class="fa fa-angle-double-right" aria-hidden="true"></i></a></li>
</ul>
</div>
</li>
</ul>
</li>
</ul>
</div>
</form>
</div>
</div>
</div>
<!-- 모달창 -->
<div id="basicModal" class="modal-overlay">
<div class="modal-content">
<div class="modalOff">X</div>
<p class="title">이미지수정</p>
<div class="content">
<div class="sub-form">
<!--미리보기 폼-->
<div class="filebox preview-image">
<!--1 -->
<div class="left">
<span>추가이미지</span>
<label class="upload-display" for="a_file">
<span class="upload-thumb-wrap">
<img class="upload-thumb" src="../img/item_main.jpg">
</span>
</label>
<input class="upload-name" value="파일선택" disabled="disabled">
<input type="file" name="file" id="a_file" class="upload-hidden">
<input type="hidden" value="">
<input type="hidden" value="">
<button type="button" class="normal_btn" style="display: block;">삭제</button>
</div>
<div class="left">
<span>추가이미지</span>
<label class="upload-display" for="b_file">
<span class="upload-thumb-wrap">
<img class="upload-thumb" src="../img/plus_btn.png">
</span>
</label>
<input class="upload-name" value="파일선택" disabled="disabled">
<input type="file" name="file" id="b_file" class="upload-hidden">
<input type="hidden" value="">
<input type="hidden" value="">
<button type="button" class="normal_btn" style="display: block;">삭제</button>
</div>
<div class="left">
<span>추가이미지</span>
<label class="upload-display" for="c_file">
<span class="upload-thumb-wrap">
<img class="upload-thumb" src="../img/plus_btn.png">
</span>
</label>
<input class="upload-name" value="파일선택" disabled="disabled">
<input type="file" name="file" id="c_file" class="upload-hidden">
<input type="hidden" value="">
<input type="hidden" value="">
<button type="button" class="normal_btn" style="display: block;">삭제</button>
</div>
</div>
</div>
</div>
<div class="btn_area">
<a href="수정!!" class="save" >수정</a>
</div>
</div>
</div>
</div><!-- end wrap -->
</th:block>
<script th:inline="javascript">
var msg = JSON.parse('[[${msg}]]');
if(msg != null) {
alert(msg);
}
//dataHandler
var handleAmount = document.getElementById("handleAmount");
handleAmount.onchange = function(e) {
//location.href="productList?page=1&amount=" + e.target.value;
document.actionForm.amount.value = e.target.value;
document.actionForm.submit();
}
</script>
2. RestAPI
- return 값에 내가 보내고 싶은 데이터를 담을 수 있음
- xml, JSON(약속 되어있는 데이터 형태)
- xml에 태그 형태로 데이터를 실어서 xml 문서를 주거니 받거니 할 수 있음.
- 구글에서 확장 프로그램 선택해서 다운로드
- api 예시(컨트롤러)
- text, 객체, 리스트 형식의 반환, get 형식으로 값 받기<get방식>
- post 형식으로 값 받기
- JSON이 안되는 이유: JSON과 Java의 객체는 다름, JSON의 문자열을 분해 시켜서 자바 Object로 맵핑 시켜야함
- 꼭 @RequestBody 넣어줄 것!
* RestBasicController
package com.simple.basic.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.function.ServerRequest.Headers;
import com.simple.basic.command.SimpleVO;
@RestController //controller + responsebody
public class RestBasicController {
/*
* 1. ResponseBody는 return값이 뷰 리졸버가 아니고, 요청이 들어온 곳으로 반환됩니다.
*
*/
@GetMapping("/getText")
public String getText() {
return "hello world";
}
//객체를 담게 되면 application/json 형식으로 반환하게 됩니다.
/*
* produces - 보내는 데이터에 대한 타입
* consumer - 받는 데이터에 대한 타입
*/
@Value("${값")
String server;
@GetMapping(value = "/getObject", produces = "application/json")
public SimpleVO getObject() {
SimpleVO vo = new SimpleVO("aaa123", "홍길동", "1");
return vo;
}
@GetMapping("/getObject2")
public Map<String, Object> getObject2(){
Map<String, Object> map = new HashMap<>();
SimpleVO vo = new SimpleVO("aaa123", "홍길동", "1");
map.put("total", 100);
map.put("data", vo);
return map;
}
//리스트 형식의 반환
@GetMapping("/getObject3")
public List<SimpleVO> getObject3(){
List<SimpleVO> list = new ArrayList<>();
for(int i = 1; i<= 10; i++)
list.add( new SimpleVO("aaa123" + i, "홍길동" + i, "1") );
return list;
}
//값을 받는 방법(get, post 방식이 다름)
//get 형식 값을 받는 방법1 - 쿼리 스트링: ?키=값
//http://localhost:8383/getKey?id=aaa123&name=민정
@GetMapping("/getKey")
public String getKey(@RequestParam("id") String id,
@RequestParam("name") String name) {
System.out.println(id);
System.out.println(name);
return "success";
}
//get 형식 값을 받는 방법2 - 쿼리 파람 URL/키/키
//http://localhost:8383/getPath/desc/aaa123
@GetMapping("/getPath/{sort}/{apiKey}")
public String getPath(@PathVariable("sort") String sort,
@PathVariable("apiKey") String key) {
System.out.println(sort);
System.out.println(key);
return "success";
}
////////////////////////////////////////////////////////////
//post 형식의 처리
// 값을 받는 방법1 - post형은 VO로 맵핑
//JSON형식의 데이터를 자바의 객체로 맵핑 @RequestBody
//{"id" : "aaa", "name" : "bbb"}
//cors-기본적으로 서버가 다르면 요청을 거절하는데 (특정 서버의 요청에 대하여 허용)
//@CrossOrigin(*)
@PostMapping("/getJson")
@CrossOrigin("http://localhost:3000")
public String getJson(@RequestBody SimpleVO vo) {
System.out.println(vo.toString());
return "success";
}
//값을 받는 방법2 - Map으로 맵핑
@PostMapping("/getMap")
public String getMap(@RequestBody Map<String, Object> map) {
System.out.println(map.toString());
return "success";
}
//consumer
//consumer는 특정 타입의 데이터를 받도록 처리하는 옵션(기본값 JSON: 안적으면 JSON 형식)
//옵션을 명시하면 클라이언트에는 Content-type을 이용해서 보내는 데이터에 대한 타입을 명시(반드시 필수)
@PostMapping(value = "/getResult", consumes = "text/plain")
public String getResult(@RequestBody String data) {
System.out.println(data);
return "success";
}
//응답 문서의 형태를 직접 선언 - ReponseEntity
@PostMapping("/createRes")
public ResponseEntity createRes() {
SimpleVO vo = new SimpleVO("aaa", "홍길동", "1"); //데이터
HttpHeaders header = new HttpHeaders(); //헤더 정보
//내용 증명
// header.add("키", "값");
header.add("Authrization", "token");
HttpStatus status = HttpStatus.ACCEPTED; //상태코드(성공 or 실패)
//제네릭은 데이터를 따라갑니다.
// new ResponseEntity<>(데이터, 헤더, 상태코드);
ResponseEntity<SimpleVO> entity = new ResponseEntity<>(vo, header, status);
return entity;
}
}
- vscode에서 라우터 폴더 열고 기존 app.js 다른걸로 바꾸고 app.js 생성(컨트롤러에 CrossOrigin 어노테이션 선언)
- 원래는 서버가 달랐을 때 실행이 안되는데 crossOrigin 어노테이션 달면 데이터 전송됨
* app.js
import axios from "axios";
const App = () => {
const handleClick = async () => {
const data = {id : "aaa", name: "bbb"}
const result = await axios.post("http://localhost:8383/getJson", data)
console.log(result);
}
return (
<div>
<input type="button" onClick={handleClick} value="데이터 요청하기" />
</div>
)
}
export default App;
'TIL > Spring boot' 카테고리의 다른 글
day90-spring boot (0) | 2023.02.21 |
---|---|
day88-spring boot (0) | 2023.02.17 |
day85-spring boot (0) | 2023.02.15 |
day84-spring boot (0) | 2023.02.14 |
day83-spring boot (0) | 2023.02.13 |