❤ 김춘장이의 위키백과 - 나만의 공부 기록 Tistory ❤
🙏 양해의 말씀
그동안 포스팅을 잠시 미뤘다.
마지막 프로젝트에 집중하고 싶었고, 이 프로젝트는 이력서에도 포트폴리오에도 첨삭되는 거라
옵시디언에 열심히 중간중간 메모 하며 포스팅만 미루었다.
지금은 최종 PPT가 완료되고, 포트폴리오 정리를 하면서 미루었던 포스팅을 다시 올려 본다
처리 순서
1. 사용자에게 병원관계자인지 응급구조사인지 확인을 받아야 함
(이전 JSP에서 라디오 버튼으로 확인을 함)
2. 분류에 따라 보이는 양식이 달라야 함
(라디오 버튼의 값에 따라 컨트롤러가 보내주는 type 번호가 있음, 번호에 따라 회원가입 폼에 양식이 달라야함)
3. 회원가입 폼 양식
3-1. 병원 관계자 : 근무 지역에 따른 병원목록이 다르게 보여야 함
signup.jsp ➡️ signup.js ➡️ controller ➡️ service ➡️ api request ➡️ api response ➡️
service parsing ➡️ controller + model ➡️ signup.js ➡️ signup.jsp
3-2. 응급 구조사 : DB에 등록된 소속 단체명이 나와야 함
signup.jsp ➡️ signup.js ➡️ controller ➡️ service ➡️ DAO ➡️ mabatis ➡️ Oracle ➡️ mabatis ➡️ DAO ➡️ service ➡️ controller + model ➡️ signup.js ➡️ signup.jsp
사용자의 카테고리 분류와 jstl을 이용한 사용자별 양식을 다르게 보이도록 하기
로그인할 때 라디오버튼으로 응급구조사인지 병원관계자인지 선택하게끔 진행했다
JSP
<section>
<div style="width: 100%; height: 800px">
<div id="map" style="width: 100%; height: 800px; position: relative; filter: blur(5px);"
class="blurred-map"></div>
<div class="overlay">
<div class="shadow p-3 mb-5 bg-body-tertiary rounded" style="width: 30%; height: 450px;">
<form class="articleLogin" action="/prmLogins" method="post">
<p class="fs-2">Login</p>
<div id="loginBox">
<div class="form-check">
<input class="form-check-input" type="radio" name="userType" value="1" id="flexRadioDefault1">
<label class="form-check-label" for="flexRadioDefault1">
응급구조사
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="userType" value="2" id="flexRadioDefault2"
checked>
<label class="form-check-label" for="flexRadioDefault2">
병원관계자
</label>
</div>
</div>
<div class="mb-3">
<label for="exampleFormControlInput1" class="form-label">Email</label>
<input type="email" class="form-control" id="exampleFormControlInput1"
placeholder="name@example.com" name="staffEmail">
<label for="inputPassword5" class="form-label">Password</label>
<input type="password" id="inputPassword5" class="form-control"
aria-describedby="passwordHelpBlock" name="staffPass">
</div>
<button type="submit" class="btn btn-outline-primary">로그인</button>
</form>
<a class="icon-link icon-link-hover" onclick="joinus()">
회원가입
<svg class="bi" aria-hidden="true">
<use xlink:href="#arrow-right"></use>
</svg>
</a>
</div>
</div>
</div>
</section>
<%@ include file="/WEB-INF/views/include/footer.jsp" %>
<script type="text/javascript">
var mapContainer = document.getElementById('map'),
mapOption = {
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 3 // 지도의 확대 레벨
};
var map = new kakao.maps.Map(mapContainer, mapOption);
function joinus() {
// 라디오 버튼들을 가져옵니다.
var radioButtons = document.getElementsByName('userType'); // 'type'이 아닌 'userType'으로 수정
var selectedType = '';
// 선택된 라디오 버튼의 값을 찾습니다.
for (var i = 0; i < radioButtons.length; i++) {
if (radioButtons[i].checked) {
selectedType = radioButtons[i].value;
break;
}
}
// URL 생성 부분 수정
location.href = "<%=request.getContextPath()%>/signUp?userType=" + selectedType;
}
</script>
컨트롤러
/**
* @param : int 병원관계자 1, 구급구조사 2
*/
@RequestMapping(value = "signUp", method = RequestMethod.GET)
public String signUp(Model model, @RequestParam("userType") String type) {
model.addAttribute("type", type);
if (type.equals("1")) {
List<PrmVO> prmList = prmService.prmListAll();
model.addAttribute("prmList", prmList);
}
return "signup";
}
라디오 버튼 선택에 따른 userType 값 (1 or 2)를 가지고 signup.jsp에 전달한다.
이 값을 가지고 회원가입 폼 양식에 응급구조사 폼을 출력할 지, 병원 관계자 폼으로 출력할 지 결정한다
Signup.JSP
jstl문법으로 진행했다
이유는 컨트롤러에서 전달 받은 userType을 가지고 값에 따라 보여지는 폼을 다르게 해야 함으로 c:if 문을 쓰기 위함이다.
jstl 문법을 사용할 경우 JSP파일 제일 상단에
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--<%@ page session="false" %>--%>
이 부분을 명시 해줘야 한다.
JSTL 문법이란 ?
JSTL(JSP Standard Tag Library)은 JSP 페이지 내에서 자바 코드를 사용하지 않고 태그를 이용하여 반복, 조건문 처리, 국제화 지원, XML 데이터 처리 등을 수행할 수 있게 하는 라이브러리입니다. JSTL은 웹 개발을 더 효율적이고 깔끔하게 할 수 있도록 도와주며, 코드의 가독성과 유지 보수성을 향상시킵니다. JSTL은 크게 다음과 같은 태그 라이브러리로 구성됩니다:
<주요 기능>
- Core 태그 라이브러리: 변수 지원, 흐름 제어, URL 처리 등 기본적인 작업을 수행합니다.
예: <c:set>, <c:if>, <c:forEach>
- Formatting 태그 라이브러리: 숫자, 날짜, 시간을 포맷하고, 국제화(i18n) 지원을 합니다.
예: <fmt:formatDate>, <fmt:formatNumber>, <fmt:message>
- SQL 태그 라이브러리: 데이터베이스 쿼리를 직접 실행합니다. (사용을 자제하며, 비즈니스 로직에서 데이터베이스 처리를 권장)
예: <sql:query>, <sql:update>
- XML 태그 라이브러리: XML 문서 처리와 관련된 작업을 수행합니다.
예: <x:parse>, <x:forEach>
- Functions 태그 라이브러리: 문자열 처리에 관련된 함수를 제공합니다.
예: ${fn:contains()}, ${fn:toUpperCase()}
<필수 설정>
- Maven 기준 -
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
- JSP 파일 상단 -
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<사용예제>
<c:set var="message" value="Hello, JSTL!" />
<c:if test="${not empty message}">
<p>${message}</p>
</c:if>
<c:forEach var="number" begin="1" end="5">
<p>Number ${number}</p>
</c:forEach>
<c:if test="${type==1}">
<label class="form-label">소속 단체명</label>
<!-- select box로 DB에 저장된 소속단체 가져오기 -->
<select id="prmName">
<c:forEach items="${prmList}" var="list">
<option value="${list.prmNumber}"> ${list.prmName}</option>
</c:forEach>
</select>
<input type="hidden" id="userType" value="${type}"/>
</c:if>
</div>
<div>
<c:if test="${type==2}">
<div>
<label class="form-label">근무 지역</label>
<select id="city">
<option> 지역 선택</option>
<option value="서울특별시">서울특별시</option>
<option value="인천광역시">인천광역시</option>
<option value="고양시">고양시</option>
<option value="광명시">광명시</option>
<option value="광주시">광주시</option>
<option value="구리시">구리시</option>
<option value="군포시">군포시</option>
<option value="김포시">김포시</option>
<option value="남양주시">남양주시</option>
<option value="동두천시">동두천시</option>
<option value="부천시">부천시</option>
<option value="성남시">성남시</option>
<option value="수원시">수원시</option>
<option value="시흥시">시흥시</option>
<option value="안산시">안산시</option>
<option value="안성시">안성시</option>
<option value="안양시">안양시</option>
<option value="오산시">오산시</option>
<option value="용인시">용인시</option>
<option value="의왕시">의왕시</option>
<option value="의정부시">의정부시</option>
<option value="이천시">이천시</option>
<option value="파주시">파주시</option>
<option value="평택시">평택시</option>
<option value="포천시">포천시</option>
<option value="하남시">하남시</option>
<option value="화성시">화성시</option>
</select>
</div>
<div>
<label class="form-label">근무 병원</label>
<select id="dutyNameList">
<option value=""> 병원 선택</option>
</select>
</div>
<input type="hidden" id="userType" value="${type}"/>
<div id="hpidHidden" style="display: none"> </div>
</c:if>
Javascript
정의한 기능
- 비밀번호 유효성 검사
- 전화번호 유효성 검사
- 모든 필드 입력 검사
- 모든 필드 값 가져오는 기능
기능 흐름
회원가입 버튼 입력 시
1. 화면 번환은 잠시 멈춤
2. 유효성 검사 진행
2-1. 모든 필드 값을 가져옴
2-2 모든 필드에 값이 있는지 체크하며 유효성까지 체크
2-3 전달할 객체를 생성함
3. 객체 생성이 정상으로 되면 fetch를 통해 컨트롤러에게 전달 - URL : /sendUserData , 메서드 : POST , 컨텐츠타입 : json
- POST메서드는 body에 데이터가 입력되어 전달 되므로 생성된 객체를 JSON.stringify(객체명)으로 명시해야함
4. fetch 후 응답값은 res 변수로 받음. header 응답 코드
4-1 header응답코드가 ok아닐 경우 에러 관련 처리진행
5. ok일 경우 json양식인 데이터를 변수에 받은 뒤 전달해 온 result값이 true로 되어있는지 확인
5-1 확인 시 alert창 출력 후 지정해 놓은 jsp 경로로 이동
5-2 에러일 경우 console창에 에러 문구만 출력 , 반응 없음
var prmNumber , prmName;
// 회원가입 버튼 입력 시 처리 로직 수정
document.getElementById('userSend').addEventListener('submit', async function (event) {
event.preventDefault();
console.log("event 실행 userSend");
let sendData = processForm();
if(!sendData){
return alert('유효성 검사 실패');
}
// 데이터를 컨트롤러에게 전달함
try {
let res = await fetch('/sendUserData', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(sendData)
});
if (!res.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
let jsonText = await res.json();
if (jsonText.result == true){
alert("회원가입 완료\n초기화면으로 돌아갑니다");
goToInfo();
}
} catch(Error) {
console.log(Error);
}
});
/*-------------------------------------------------------------------------------------*/
// 비밀번호 유효성 검사 및 모든 필드 입력 검사 후 객체생성 로직
// 리턴값 : controller에게 전달할 object
function processForm() {
var elements = getFormElements();
if (validateFormElements(elements)) {
return createUserObject(elements);
}
}
/**
* DOM 요소 전체 가져오기 : 리턴값 object
* */
function getFormElements() {
let temp = {
userType: document.getElementById('userType').value,
staffName: document.getElementById('staffName').value,
staffEmail: document.getElementById('staffEmail').value,
staffPass: document.getElementById('staffPass').value,
phoneNumber1: document.getElementById('phoneNumber1').value,
phoneNumber2: document.getElementById('phoneNumber2').value,
phoneNumber3: document.getElementById('phoneNumber3').value,
prmName: prmName ? prmName : null,
prmNumber: prmNumber ? prmNumber : null,
dutyNumber: dutyNumber? dutyNumber: null,
dutyName: dutyName ? dutyName : null
};
console.log(temp)
return temp;
}
// 필드 유효성 체크 : 리턴값 Boolean
function validateFormElements(elements) {
if (
!elements.staffName ||
!elements.staffEmail ||
!elements.phoneNumber1 ||
!elements.phoneNumber2 ||
!elements.phoneNumber3 ||
(elements.userType === '1' && (!elements.prmNumber || !elements.prmName)) ||
(elements.userType === '2' && (!elements.dutyName || !elements.dutyNumber)) ||
!isValidPassword(elements.staffPass)) {
return false; // 유효성 체크 실패
}
// 전화번호 유효성 검사 추가
if (!isValidPhoneNumber(elements.phoneNumber1, elements.phoneNumber2, elements.phoneNumber3)) {
return false; // 전화번호 유효성 체크 실패
}
return true; // 유효성 체크 성공
}
// 비밀번호 유효성 체크
function isValidPassword(password) {
if (password.length < 8) {
alert("비밀번호 길이가 너무 짧습니다 ")
return false; // 비밀번호 길이가 8자 미만
}
if (/[`'"\&\$]/.test(password)) {
alert(" `, ', \", &, $ 를 포함 불가 ")
return false; // 특수문자 `, ', ", &, $ 포함
}
return true; // 유효한 비밀번호
}
// 구급대원 가입으로 목록 변경시 데이터 추출
// 리스너를 통해 자동으로 계속 전달옴
document.getElementById('dutyNameList').addEventListener('change', function() {
var selectedOption = this.options[this.selectedIndex];
dutyNumber = selectedOption.value;
dutyName = selectedOption.text;
});
// 전달 객체 생성 수정: 전화번호 형식 조정
function createUserObject(elements) {
var phone = `${elements.phoneNumber1}-${elements.phoneNumber2}-${elements.phoneNumber3}`;
return {
userType: elements.userType === '1' ? 1 : 2, // 병원이면 컨트롤러가 서비스 방향을 정할 수 있도록 1 , 구급이면 2 로 전달
dutyName: elements.userType === '2' ? elements.dutyName : null,
hpid: elements.userType === '2' ? elements.dutyNumber : null,
prmName: elements.userType === '1' ? elements.prmName : null,
prmNumber: elements.userType === '1' ? elements.prmNumber : null,
staffEmail: elements.staffEmail,
staffName: elements.staffName,
staffPass: elements.staffPass,
staffPhone: phone.replace(/-/g, '') // 전화번호에서 '-' 제거
};
}
// 전화번호 유효성 검사
function isValidPhoneNumber(phoneNumber1, phoneNumber2, phoneNumber3) {
var phoneRegex = /^\d{2,3}$/; // 지역번호 형식 (2~3자리 숫자)
var phoneRegexMid = /^\d{3,4}$/; // 중간자리 형식 (3~4자리 숫자)
var phoneRegexLast = /^\d{4}$/; // 마지막자리 형식 (4자리 숫자)
if (!phoneRegex.test(phoneNumber1)) {
alert("전화번호의 지역번호가 올바르지 않습니다.");
return false;
}
if (!phoneRegexMid.test(phoneNumber2)) {
alert("전화번호의 중간자리가 올바르지 않습니다.");
return false;
}
if (!phoneRegexLast.test(phoneNumber3)) {
alert("전화번호의 마지막자리가 올바르지 않습니다.");
return false;
}
return true;
}
'👀 Side Project > Eᴍʙᴀᴅ (23.12~24.01)' 카테고리의 다른 글
이메일 발송 동작 구현 및 테스트 (2) | 2024.01.31 |
---|---|
디자인, 이게 최선이였냐?! , 불호령 떨어진 디자인 개편 (1) | 2024.01.28 |
Spring email 정의하기 (0) | 2024.01.28 |
공공데이터포털 API serviceKey 오류/SERVICE KEY IS NOT REGISTERED ERROR/해결 (0) | 2024.01.28 |
공공데이터포털 API 적용 및 구현 (1) | 2024.01.28 |