스프링 쇼핑몰 만들기 #14. 관리자 모드 다듬기
아직 상품 등록/조회/수정/삭제 기능 정도만 있는 관리자 모드지만, 기본적인 기능은 모두 구현되었습니다.
상품 소감과 유저 목록은 사용자 모드가 개발되고 난 뒤 이어서 개발하게 됩니다. 일단 소감을 작성해야 관리자가 볼 수 있을텐데, 사용자 모드가 없으면 소감을 작성할 수 없을테니까요.
사용자 모드를 개발하기 전, 관리자 모드를 다듬고 가겠습니다.
먼저 상품 등록 화면입니다.
상품가격과 상품수량은 숫자만 입력해야하는데, 만약 숫자가 다른 다른 문자를 입력하게되면 데이터 베이스가 입력을 받지 못해 에러가 발생합니다.
실수로라도 숫자가 아닌 다른 문자를 입력하지 못하게 막는편이 좋습니다.
register.jsp의 </body>
위에 스크립트를 추가합니다.
<script> var regExp = /[^0-9]/gi; $("#gdsPrice").keyup(function(){ numCheck($(this)); }); $("#gdsStock").keyup(function(){ numCheck($(this)); }); function numCheck(selector) { var tempVal = selector.val(); selector.val(tempVal.replace(regExp, "")); } </script>
/[^0-9]/gi
는 정규표현식 중 하나로, 숫자만 허용하게 됩니다.
상품 가격(gdsPrice)와 상품 수량(gdsStock)을 입력할 때마다 numCheck() 함수를 호출하며, 이때 현재 선택자 $(this)
같이 보냅니다.
$(this)
는 현재 실행중인 선택자로서, 상품 가격에 입력할 때 $(this)
는 $("#gdsPrice")
를 의미하고, 상품 수량을 입력할 땐 $("#gdsStock")
이 됩니다.
numCheck()함수는 현재 선택된 선택자를 selector에 저장한 뒤, selector에 입력된 값을 정규표현식 맞게 변경합니다.
상품 가격과 상품 수량에 숫자가 아닌 다른 문자를 입력하려고하면, 곧바로 지워지게됩니다.
상품 수정(modify.jsp)도 같은 방법으로 코드를 추가합니다.
이번에는 상품 목록입니다.
기껏 이미지도 첨부하고 썸네일도 생성했는데, 상품 목록에 아무것도 나오지 않는건 조금 아쉽습니다. 그리고 카테고리가 저렇게 숫자로 되어서는 한눈에 알아보기 어렵습니다.
먼저 매퍼에서 목록을 불러오는 쿼리를 수정합니다.
이미지 첨부 기능 구현에서 했던것 처럼, 2개의 테이블을 조인하여 쿼리를 작성했습니다.
<select id="goodslist" resultType="com.kubg.domain.GoodsViewVO"> select g.gdsNum, g.gdsName, g.cateCode, c.cateCodeRef, c.cateName, gdsPrice, gdsStock, gdsDes, gdsImg, gdsDate, g.gdsImg, g.gdsThumbImg from tbl_goods g inner join goods_category c on g.cateCode = c.cateCode </select>
이때 반환되는 타입은 GoodsVo가 아닌 GoodsViewVO인것에 주의해야합니다.
DAO와 Service에서도 GoodsVO를 GoodsViewVO로 변경합니다.
마찬가지로 컨트롤러도 수정합니다.
이제 list.jsp의 출력되는 코드를 살짝 수정합니다.
<c:forEach items="${list}" var="list"> <tr> <td> <img src="${list.gdsThumbImg}"> </td> <td> <a href="/admin/goods/view?n=${list.gdsNum}">${list.gdsName}</a> </td> <td> <!-- ${list.cateCode} --> ${list.cateName} </td> <td> <fmt:formatNumber value="${list.gdsPrice}" pattern="###,###,###"/> </td> <td>${list.gdsStock}</td> <td> <fmt:formatDate value="${list.gdsDate}" pattern="yyyy-MM-dd" /> </td> </tr> </c:forEach>
테이블을 좀 더 보기 좋게 스타일을 추가합니다.
썸네일도 나오고, 카테고리도 표시되지만.. 이미지를 첨부하지 않았을 때 나오는 이미지가 없어서 이상하게 나오고 있습니다.
이미지 주소를 보니, 경로가 이상하게 되어있는걸 확인할 수 있습니다.
경로를 지정하는 코드를 찾아서 수정해야겠습니다.
그전에 src/main/webapp/resources에 images 폴더를 생성합니다.
images 폴더에 미리 준비해둔 이미지를 추가합니다. 전 그냥 회색으로 된 이미지 파일입니다.
servlet-context.xml에 대체 이미지 경로를 추가합니다.
<!-- 대체 이미지 경로 --> <resources mapping="/images/**" location="/resources/images/" />
컨트롤러를 보니 문제점이 바로 보입니다.
밑줄된 코드는 각각 첨부된 파일이 있을 때와 없을 때입니다. 파일이 있을 때는 빨간 박스에있는 코드와 맞물려서 정상적으로 vo에 입력되는데, 파일이 없을 때는 이미 경로가 모두 입력된 상태인데 다시금 빨간박스에서 경로를 추가적으로 입력하기 때문에 생긴 에러입니다.
vo에 값을 넣는 코드를 첨부파일이 있을 때와 없을 때 두가지로 분류했습니다.
// 상품 등록 @RequestMapping(value = "/goods/register", method = RequestMethod.POST) public String postGoodsRegister(GoodsVO vo, MultipartFile file) throws Exception { String imgUploadPath = uploadPath + File.separator + "imgUpload"; // 이미지를 업로드할 폴더를 설정 = /uploadPath/imgUpload String ymdPath = UploadFileUtils.calcPath(imgUploadPath); // 위의 폴더를 기준으로 연월일 폴더를 생성 String fileName = null; // 기본 경로와 별개로 작성되는 경로 + 파일이름 if(file.getOriginalFilename() != null && file.getOriginalFilename() != "") { // 파일 인풋박스에 첨부된 파일이 없다면(=첨부된 파일이 이름이 없다면) fileName = UploadFileUtils.fileUpload(imgUploadPath, file.getOriginalFilename(), file.getBytes(), ymdPath); // gdsImg에 원본 파일 경로 + 파일명 저장 vo.setGdsImg(File.separator + "imgUpload" + ymdPath + File.separator + fileName); // gdsThumbImg에 썸네일 파일 경로 + 썸네일 파일명 저장 vo.setGdsThumbImg(File.separator + "imgUpload" + ymdPath + File.separator + "s" + File.separator + "s_" + fileName); } else { // 첨부된 파일이 없으면 fileName = File.separator + "images" + File.separator + "none.png"; // 미리 준비된 none.png파일을 대신 출력함 vo.setGdsImg(fileName); vo.setGdsThumbImg(fileName); } adminService.register(vo); return "redirect:/admin/index"; }
이제 첨부파일이 있을 때와 없을 때, 특히 없을 때 제대로 등록되는지 확인하겠습니다.
내용은 대충 입력하고, 이미지는 첨부하지 않은 상태에서 등록 버튼을 클릭합니다.
이제 회색 이미지가 정상적으로 표시됩니다.
관리자 모드는 여기까지 하고, 다음부터는 사용자 모드입니다.
$(this) 나 this를 굳이 구분하지않고 사용해도 될까요??
답글삭제$(this)는 제이쿼리 선택자로서의 this이며, button이나 input같은 HTML 요소를 의미합니다.
삭제그리고 this는 자바스크립트 객체로서의 this이며, 함수나 메서드등을 의미합니다.
즉, $(this)와 this는 전혀 다른것이기 때문에 구분해서 사용하셔야합니다.
selector.val(tempVal.replace(regExp, ""))이 이해가 잘 안갑니다. replace 함수 두번째 패러미터가 단순히 공백제거 기능은 아닌거 같아요
답글삭제안녕하세요? 방문해주셔서 감사합니다.
삭제작성한 정규식에 맞지 않는 값.. 즉 숫자 이외의 값은 제거("")하는 작업입니다.
안녕하세요 게시글들이 이해하기 쉽게 나와있어 잘 따라하고 있습니다!
답글삭제하지만 약간 이해가 되지 않는 부분이 있어서요!
if(file.getOriginalFilename() != null && file.getOriginalFilename() != "") {
// 파일 인풋박스에 첨부된 파일이 없다면(=첨부된 파일이 이름이 없다면)
->이 의미가 파일이름이 null이 아니라면, 즉 파일이름이 존재한다면 이라는 의미 아닌가요? 왜 이 의미가 되는지 이해가 가지 않습니다!
안녕하세요? 방문해주셔서 감사합니다.
삭제file.getOriginalFilename()의 값이 "" 로 들어오거나 null로 들어올 경우, 둘다 조건에 포함해야합니다.
왜냐하면, js 로직에 따라서 아무것도 없는 공백값인 ""가 올수도 있고, 없다는 의미의 null이 들어올 수 있기 때문입니다.
null 비교는 존재 유무를 판단하는것이기 때문에, if문에서 가장 먼저 비교해야합니다.