
학원에서 final 프로젝트를 진행중, 난관에 부딪혔다.
현재 수거요청에 대한 흐름은 수거신청 → 수거신청 내용 확인 → 최종결제 이렇게 구상이 되어있다. 수거신청 후, 해당 데이터가 DB에 저장되지 않기 때문에(장바구니를 따로 만들지 않기로 함) 어떤 식으로 파라미터를 넘겨야 할 지 고민하게되었다.
그래서 해당 부분을 담당한 팀원 한서현씨와 함께 머리를 맞대고 고민한 결과, 총 3가지 방법을 생각하였다.
- 수거요청 버튼 클릭 시, 이벤트 발생! → 리스트 개수 만큼 input 만들기
- 각각 하나의 리스트에 대한 VO를 만들고, List<VO>를 담는 VO 만들기
- 객체를 redirect되는 페이지로 넘기기
수거요청 버튼을 클릭하여 이벤트가 발생할 때, 상품의 수량만큼 input을 만들어서 controller로 넘기는 방식으로 생각을 하였다.
위에 화면과 비슷하게 마크업을 하였다. 주황색 박스는 이해를 돕기 위해 임시로 보이게 만들었으며, 저 부분이 'CategoryName'이라는 이름의 파라미터로 Controller로 넘어간다.
그 후 선택한 상품만 골라낼 수 있도록 HashSet의 특징을 이용하여 파라미터의 중복을 제거하고, for문으로 최종 로직을 완성하였다.
전체 코드
- JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>Title</title> <script src="https://code.jquery.com/jquery-3.6.0.min.js" type="text/javascript"></script> </head> <body> <select name="select" id="select-test"> <option value="0">선택하세요</option> <option value="cat_1">testCategory_1</option> <option value="cat_2">testCategory_2</option> <option value="cat_3">testCategory_3</option> <option value="cat_4">testCategory_4</option> </select> <button id="cat-btn" onclick="catAdd()">추가</button> <hr/> <hr/> <hr/> <div id="list-part"> </div> <button id="res-btn" onclick="resOn()">완료</button> <hr/> <hr/> <form name="form-data" method="post" action="<c:url value='/paramPost'/>"> </form> <script> function catAdd() { const selVal = document.getElementById("select-test").value; //카테고리의 value let sumOpt = ""; for(let i = 1; i <= 10; i++) sumOpt += "<option value='" + i + "'>" +i+ "</option>" if(selVal !== "0") { const chkInput = document.querySelector("input[value=" + selVal +"]"); if(chkInput) { alert("이미 추가된 항목입니다."); return; } $("#list-part").append("<div class='param'>" + "<input name='categoryName' value='" + selVal + "'/>" + "<select name='sum'>" + sumOpt + "</select>" + "</div>"); }else { alert("선택하세요."); document.getElementById("select-test").focus(); } } function resOn() { document.querySelectorAll(".param").forEach((item, idx) => { //리스트의 div를 forEach const itemSum = item.childNodes[1].value; //1번 인덱스는 select for(let i = 0; i < itemSum; i++) { $("form[name=form-data]").append("<input name='categoryName' value='" + item.childNodes[0].value + "'/>") } }); $("form[name=form-data]").submit(); } </script> </body> </html>
- Controller(JAVA)
@Controller public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); public String mainView() { return "index"; } @RequestMapping("/c") public String main() { logger.info("메인화면"); return mainView(); } @ResponseBody @PostMapping("/paramPost") public Map<String, Integer> testJson(HttpServletRequest request) { logger.info("post넘김"); String[] parameterValues= request.getParameterValues("categoryName"); //'categoryName'의 이름을 가진 파라미터가 여러개이기 때문에 for(String parameterValue : parameterValues) //정상적으로 파라미터가 들어왔는지 체크용 logger.info("parameterValue={}", parameterValue); Map<String, Integer> resJson = new HashMap<>(); //최종 아이템, 개수가 담길 객체 Set<String> setset = new HashSet<>(Arrays.asList(parameterValues));//파라미터 중복 제거용 String[] resString = setset.toArray(new String[0]); //중복제거 완료 for (String text : resString) { int cnt = 0; //개수 초기화 for (String parameterValue : parameterValues) { if (text.equals(parameterValue)) cnt++; } resJson.put(text, cnt); } return resJson; } }
이 방법은 안쓰기로했다. 뭔가... 이게 맞나..? 싶기도하고, 비효율적이다.
이 내용은 추후 포스팅하여 작성하겠습니다.
여러 방법을 찾다가 의문이 들었다. 뭔가.. 클라이언트 부분에서 리스트에 대한 데이터를 JSON으로 만들고, 그 객체를 서버(Controller)로 넘기는게 아닌, 클라이언트 → 클라이언트로 넘겨주는 방법이 없을지... 이 방법만 쓴다면 엄청 간단하게 로직이 구성될텐데!
그동안 데이터의 대한 처리 방법을 'Controller → Model에 데이터 저장, view 리턴' 이러한 구조가 익숙하다보니 'view → view'로 데이터를 넘기는 방법을 생각을 못했다.
결론은 있었다!!!
클라이언트에서 Storage관련 Web Storage API를 제공한다.
localStorage : 웹페이지의 세션이 끝날 때 데이터 소멸sessionStorage : 웹페이지의 세션이 끝나도 데이터가 소멸하지 않음클라이언트 상에서 데이터를 저장하는 것인데, 아마 Cookie와 비슷한 원리인 거 같다.
Controller에서 Model에 데이터를 저장하는 것처럼 Key와 Value로 이뤄져있다. 한가지 주의할 점은 String으로만 데이터를 저장할 수 있다.
// 데이터 쓰기(저장)
localStorage.setItem("key", "ABCD 데이터");
// 데이터 읽기
localStorage.getItem("key");
// 데이터 삭제
localStorage.removeItem("key");
// 모든 데이터 삭제(초기화)
localStorage.clear();
// 저장된 키/값 쌍의 개수
localStorage.length;
정확하게는 localStorage가 아닌 window.localStorage이지만 window는 최상위 객체로 생략 가능하다. 해당 방식으로 앞서 했던 이상한 방식이 아닌 Web Storage API를 사용하면 아래와 같이 로직을 구성할 수 있다.
- 완료 버튼 클릭 이벤트 함수(리스트 정보를 객체로 만들고, 저장한다)
function resOn() { let jsonData = []; //데이터가 넣어질 변수 document.querySelectorAll(".param").forEach((item, idx) => { const catName = item.childNodes[0].value; const catSum = item.childNodes[1].value; jsonData.push({catName, catSum}); }); localStorage.setItem("jsonData", JSON.stringify(jsonData)); //객체(json)을 문자열로 변환 후, 저장 }
- 페이지 전환 후(꺼낼 때)
const jsonStrData = localStorage.getItem("jsonData"); //데이터를 key로 꺼냄 localStorage.removeItem("jsonData"); //해당 key의 데이터 삭제(혹시몰라서) const jsonData = JSON.parse(jsonStrData); //문자열을 객체(json)으로 변환 console.log(jsonData);![]()
끝!