✨ 개요
요구사항: 관리자는 전체 회원 중 좌석/사물함을 이용하고 있지 않은 회원 목록을 조회할 수 있고, 그 목록을 이용해 좌석/사물함 이용을 등록할 수 있다.
미등록 회원 목록에서 회원의 이름을 누르면 회원 목록과 좌석 배치도 사이에 등록 폼이 보이면서 해당 회원의 정보가 자동으로 기입되고, 좌석 배치도에서 비어 있는 좌석을 선택하면 해당 좌석 번호가 기입된다. 사물함 번호와 기간을 선택하지 않으면 등록을 진행할 수 없도록 했다.
+) 이용자가 이용 등록을 할 땐 결제 처리까지 함께 이루어지는데, 관리자 페이지에서의 등록을 할 때 어떻게 해야 할지 고민이 되었다. 나는 결제 처리가 되어서 '결제 내역'에 데이터가 들어가야 이용 현황 차트에 반영시킬 수 있다고 생각했는데, 조원들과 얘기해 본 결과 관리자가 하는 등록은 '이용 등록 정보' 테이블에만 넣는 걸로 하기로 했다.
++) 이용자 화면에서의 좌석배치도와 관리자 화면에서의 좌석배치도 디자인도 달라졌는데, 이용자 화면에서는 다른 이용자의 정보 노출을 최소화 하고, 관리자 화면에서는 이용자의 정보가 한 눈에 보이면 편하기 때문에 이렇게 설계하였다.
+++) 글이 길어진다면 나눠서 올릴 예정이다. 진행하면서 몇몇 클래스들은 공동 작성하게 되어 문서주석으로 표시를 해 놓았다.
🍍 AdminMapper
public interface AdminMapper {
/**
* 회원 중 좌석/사물함 미등록 회원 목록
* @author 김보경
* @Date 2021. 5. 28.
*/
List<MemberVO> getUnregList(Criteria cri);
}
<!-- 회원 중 좌석/사물함 미등록 회원 목록 페이징처리 포함 작성자: 김보경 -->
<resultMap type="xyz.sumtplus.domain.MemberVO" id="unRegMemberMap">
<id property="userNo" column="userNo" />
<result property="userNo" column="userNo"/>
<result property="userId" column="userId"/>
<result property="userPw" column="userPw"/>
<result property="userName" column="userName"/>
<result property="email" column="email"/>
<result property="tel" column="tel"/>
<result property="enabled" column="enabled"/>
<collection property="address" resultMap="addressMap2"></collection>
</resultMap>
<resultMap type="xyz.sumtplus.domain.AddressVO" id="addressMap2">
<result property="addrNo" column="addrNo"/>
<result property="userNo" column="userNo"/>
<result property="post" column="post"/>
<result property="addr" column="addr"/>
<result property="detail" column="detail"/>
<result property="extra" column="extra"/>
</resultMap>
<select id="getUnregList" resultMap="unRegMemberMap">
SELECT * FROM (
SELECT MB.USERNO, MB.USERID, MB.USERNAME, MB.EMAIL, MB.TEL, MB.ADDR, MB.ENABLED, ROWNUM RN
FROM
(SELECT /*+INDEX_DESC(TBL_MEMBER TBL_MEMBER_PK)*/
M.USERNO, M.USERID, M.USERNAME, M.EMAIL, M.TEL,
(SELECT ADDR|| ' ' || DETAIL
FROM TBL_ADDRESS A WHERE A.USERNO = M.USERNO) ADDR
, M.ENABLED
FROM TBL_MEMBER M WHERE USERNO>0 ORDER BY USERNO) MB
WHERE USERNO IN (SELECT USERNO FROM TBL_MEMBER MINUS SELECT USERNO FROM TBL_REGINFO)
<![CDATA[AND ROWNUM <= #{pageNum} * #{amount}]]>
)
WHERE RN > (#{pageNum} -1) * #{amount}
</select>
🔶 resultMap을 이용하였다.
🔶 미등록 회원의 수가 많기 때문에 페이징 처리가 필수로 들어가야 했고, 별칭을 써서 그런 건지 인덱스를 제대로 안 타서 고생했다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/security-context.xml"})
@Log4j
public class AdminMapperTests {
@Autowired
private AdminMapper mapper;
/**
* 회원 중 좌석/사물함 미등록 회원 페이징 처리 된 목록 불러오기 테스트
* @author 김보경
* @Date 2021. 5. 28.
*/
@Test
public void getUnregListTest() {
Criteria cri = new Criteria();
cri.setPageNum(1);
cri.setAmount(20);
mapper.getUnregList(cri).forEach(log::info);
}
}
🍏 AdminService
public interface AdminService {
/**
* 회원 중 좌석/사물함 미등록 회원 목록 조회
* @author 김보경
* @Date 2021. 5. 28.
*/
List<MemberVO> getUnregListTest(Criteria cri);
}
@Service
@Log4j
@AllArgsConstructor
public class AdminServiceImpl implements AdminService{
private AdminMapper mapper;
private SeatMapper seatMapper;
private LockerMapper lockerMapper;
/**
* 회원 중 좌석/사물함 미등록 회원 목록 조회
* @author 김보경
* @Date 2021. 5. 28.
*/
@Override
public List<MemberVO> getUnregListTest(Criteria cri) {
return mapper.getUnregList(cri);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/security-context.xml"})
@Log4j
public class AdminServiceTests {
@Autowired
AdminService adminService;
/**
* 회원 중 좌석/사물함 미등록 회원 목록 조회 서비스 테스트
* @author 김보경
* @Date 2021. 5. 28.
*/
@Test
public void getUnregListTest() {
adminService.getUnregListTest(new Criteria(1,20)).forEach(log::info);
}
🔶 한 페이지 당 20개씩 불러오는 테스트.
🥕 AdminController
@Controller
@Log4j
@RequestMapping("/admin/*")
@AllArgsConstructor
public class AdminController {
private AdminService service;
private SeatService seatService;
private ChartService chartService;
private LockerService lockerService;
private RegInfoService regInfoService;
private PaymentService paymentService;
/**
* @author 김보경
* @Date 2021. 5. 28.
*/
@GetMapping("admin_seat")
public void getSeat(Criteria cri, Model model) {
log.warn("관리자 좌석 관리 페이지..");
model.addAttribute("UnregList", service.getUnregListTest(cri)); // 미등록 회원 목록
model.addAttribute("cri", cri);
model.addAttribute("pageMaker", new PageDTO(service.getMemberTotal(cri), cri));
model.addAttribute("etSeat", seatService.getEmptySeatList()); // 빈 좌석 목록
model.addAttribute("etLocker", lockerService.getEmptyLockerList()); // 빈 좌석 목록
model.addAttribute("planInfo",service.showSeatPlanInfo()); // 배치도 정보
}
/**
* @author 김보경
* @Date 2021. 5. 31.
*/
@PostMapping("admin_seat")
public String postSeat(RegInfoVO infoVO, Model model) {
log.warn("전송된 infoVO:: " + infoVO);
FeeVO feeVO = paymentService.findBy(infoVO.getFno());
model.addAttribute("feeVO", feeVO);
log.info("feeVO : " + feeVO);
regInfoService.RegisterRegInfo(infoVO);
return "redirect:/admin/admin_seat";
}
🔶 이용자 시점에서 등록할 때 결제로 넘어가면서 요금제 정보를 줘야 해서 feeVO를 이용했었는데, 관리자 쪽에서도 이것을 이용하려다가 관리자 시점에서의 등록은 결제 처리를 하지 않기로 했기 때문에 사용할 필요가 없어져서 지울 예정이다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml",
"file:src/main/webapp/WEB-INF/spring/security-context.xml"})
@Log4j
@WebAppConfiguration
public class AdminControllerTests {
@Autowired
private WebApplicationContext ctx;
public MockMvc mvc;
@Before
public void setup(){
mvc = MockMvcBuilders.webAppContextSetup(ctx).build();
}
/**
* 회원 중 좌석/사물함 미등록 회원 목록 조회
* + 좌석배치도에 이용 중인 상태와 회원 이름, 만료일 보여주는
* 컨트롤러 테스트
* @author 김보경
* @Date 2021. 5. 28, 29.
*/
@Test
public void testUnregList() throws Exception{
log.info(mvc.perform(MockMvcRequestBuilders.get("/admin/admin_seat")
.param("pageNum", "2")
.param("amount", "10"))
.andReturn().getModelAndView().getViewName());
}
}
🔶 컨트롤러 테스트에서는 2페이지에서 10개씩 목록 출력을 해봤다.
🍄 admin_seat.jsp
<script>
$(function() {
$(".regCard").hide(); // 등록 폼 숨김.
/* 미등록 회원의 이름을 클릭하면 등록 폼이 나타나고 폼에 회원 정보 자동 입력 */
$(".mDetail").click(function() {
var tr = $(this).parent().parent();
var td = tr.children();
var uno = td.eq(0).text();
var uname = td.eq(2).text();
$(".regCard").show();
$(".uno").val(uno);
$(".uName").val(uname);
});
/* 좌석 배치도에서 빈 좌석의 '선택'버튼을 누르면 등록 폼의 희망 좌석 번호에 자동 입력 */
$(".sRegBtn").click(function() {
sno = $(this).data("sno");
$(".wSno").val(sno);
});
/* 좌석 등록 폼에서 등록 버튼 클릭 시 유효성 검증 */
$(".adSeatBtn").click(function() {
if($('input:text[name="seatNo"]').val() == '') alert("좌석 번호를 선택해 주세요.");
if($('input:radio[name="lockerNo"]').is(':checked') == false) alert("사물함 번호를 체크해 주세요.(미 이용시 '이용 안 함' 체크)");
if($('input:radio[name="period"]').is(':checked') == false) alert("이용 기간을 체크해 주세요.");
else {
var result = confirm("등록하시겠습니까?");
if(!result) return false;
else alert("등록되었습니다.");
}
});
});
/* 회원이름 클릭 시 등록 폼으로 스크롤 이동 */
function fnMove(seq){
var offset = $("#div" + seq).offset();
$('html, body').animate({scrollTop : offset.top}, 400);
}
</script>
🔶 회원의 이름이 <a>
태그로 되어 있는데 이 <a>
태그의 클래스가 mDetail이다. 선택자에서 조금 헷갈렸다. 😅
🔶 "선택" <button>
의 클래스명이 sRegBtn이고, 등록 폼에서의 "등록" <button>
클래스명이 adSeatBtn이다. 유효성 검증 부분은 조금 더 수정해야 한다.
🔶 미등록 회원 목록의 윗쪽에서 등록폼까지 스크롤이 어느 정도 있기 때문에, 자동으로 그 위치로 내려가야겠다고 생각해서 jQuery의 스크롤 이동을 이용했고 이동 될 <div>
태그에 id로 div1, div2 이런 식으로 주고 회원 이름의 <a>
와 좌석 배치도에서의 선택 <button>
에 onclick="fnMove('2')"
, onclick="fnMove('1')"
이런 식으로 줬다.
'JAVA > JAVA-Project' 카테고리의 다른 글
[Spring Framework] OAuth2.0 카카오톡 로그인/회원가입 (Spring Security 적용) (0) | 2021.08.17 |
---|---|
테이블 3개 조인하기. (관리자-좌석관리에서 좌석 배치도에 정보 입력 하기 위함) 21. 05. 29. (0) | 2021.05.29 |
[스프링] 독서실 관리 프로그램- 좌석 변경 21. 05. 27. (0) | 2021.05.27 |
[스프링] 독서실 관리 프로그램- 이용 기간 연장하기 21. 06. 02. 수정 (0) | 2021.05.26 |
[스프링] 독서실 관리 프로그램 1인 1좌석 자바스크립트 21. 05. 26. (0) | 2021.05.26 |