mjeongriver
article thumbnail
Published 2023. 2. 16. 16:05
day86-spring boot TIL/Spring boot

1. 어제 검색 기능 이어서 설명

1) 검색 폼에서는 키워드, page, amount 데이터를 넘깁니다.

2) 목록 조회 and total 동적 쿼리로 변경

 

2번째 사진: 있을 때만 실행

 

* 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) 검색 키워드 화면에서 유지시킴(초기화 버튼 있으면 좋을 것 같음)

 

3번째 사진처럼 검색을 하더라도 유지가 되어야함!

 

보기를 바꾸면 search 내역이 사라지게 됨

 

검색 키워드처럼 똑같아짐!(이렇게 하면 보기를 바꿔도 검색 데이터가 유지 됩니다)

 

* 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방식>

 

produce는 생략이 가능합니다.

 

- post 형식으로 값 받기

- JSON이 안되는 이유: JSON과 Java의 객체는 다름, JSON의 문자열을 분해 시켜서 자바 Object로 맵핑 시켜야함

- 꼭 @RequestBody 넣어줄 것!

 

post 형식의 처리: form 형식에는 처리가 되는데 JSON에서는 못받음(requestBody 꼭 붙여줄 것: 붙여주면 받을 수 있음)

 

6번째 사진은 변화는 없지만 데이터 명세가 나옴

 

* 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
profile

mjeongriver

@mjeongriver

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그