드롭다운 기능

oYJo·2025년 3월 12일

Spring

목록 보기
12/29

드롭다운 기능

1️⃣ Visual Studio Code

✔️webapp(WEB-INF(views(common))) → header.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<link rel="stylesheet" href="/resources/css/main-style.css">

<!-- font awesome 라이브러리 추가 + key 등록 -->
<script src="https://kit.fontawesome.com/f8b69bd1ba.js" crossorigin="anonymous"></script>

<link rel="stylesheet" href="/resources/css/header-style.css">

<header>
    <section>
        <!-- 클릭 시 메인 페이지로 이동하는 로고 -->
        <a href="/">
            <img src="/resources/images/logo.jpg" alt="로고" id="homeLogo">
        </a>
    </section>


    <section class="search-content">
        <!-- 검색어 입력할 수 있는 요소 배치 -->

        <article class="search-area">

            <!-- 
                action : 내부 input에 작성된 값을 제출할 경로/주소 
                method : 어떤 방식으로 제출할지 지정

                - GET : input태그 값을 주소에 담아서 제출(주소에 보임)
                - POST : input태그 값을 주소에 담지 않고 제출(주소에 안보임)
                        -> HTTP Body에 담아서 제출
            -->
            <form action="/board/1" method="GET">

                <fieldset> <!-- form태그 내 영역 구분 -->

                    <!-- 
                        input의 name 속성 == 제출 시 key
                        input에 입력된 내용 == 제출 시 value

                        autocomplete="off" : 브라우저 제공 자동완성 off
                    -->
                    <input type="search" name="query" id="query"
                    placeholder="검색어를 입력해주세요."
                    autocomplete="off" value="${param.query}">

                    <%-- 제목 검색 --%>
                    <input type="hidden" name="key" value="t">

                    <!-- 검색 버튼 -->
                    <!-- button type="submit" 이 기본값 -->
                    <button id="searchBtn" class="fa-solid fa-magnifying-glass"></button>

                </fieldset>

            </form>

            <%-- 검색어 자동완성이 보여질 구역 --%>
            <!--  --><ul id="autoComplete"></ul>
            <!-- board/1/3116?cp=1 -->
            
        </article>

    </section>


    <section></section>

    <%-- 우측 상단 드롭다운 메뉴 --%>
    <div class="header-top-menu">

        <c:choose>
        
            <c:when test="${empty loginMember}">
                <%-- 로그인 X --%>
                <a href="/">메인 페이지</a> | <a href="/member/login">로그인</a>
            </c:when>
        
            <c:otherwise>
                <%-- 로그인 O --%>
                <label for="headerMenuToggle">
                    ${loginMember.memberNickname} <i class="fa-solid fa-caret-down"></i>
                </label>

                <input type="checkbox" id="headerMenuToggle">

                <div class="header-menu">
                    <a href="/myPage/info">내정보</a>
                    <a href="/member/logout">로그아웃</a>
                </div>
            </c:otherwise>

        </c:choose>

    </div>

</header>

<nav>
    <ul>
    <%-- 
        <li><a href="#">공지사항</a></li>
        <li><a href="#">자유 게시판</a></li>
        <li><a href="#">질문 게시판</a></li>
        <li><a href="#">FAQ</a></li>
        <li><a href="#">1:1문의</a></li>
       --%>
       
      <%-- interceptor를 이용해서 조회된 boardTypeList를 application scope에서 얻어와서 화면에 출력 --%>
      <c:forEach var="boardType" items="${boardTypeList}">
       <li>
       	<a href="/board/${boardType.BOARD_CODE}">${boardType.BOARD_NAME}</a>
       </li>
   	</c:forEach>

    <%-- 로그인 했을 때 채팅 보여짐 --%>
    <c:if test="${!empty loginMember}">
        <li><a href="/chatting">채팅</a></li>
    </c:if>
    </ul>
    
</nav>
<script>

const autoComplete = document.getElementById("autoComplete");
const query = document.getElementById("query");

query.addEventListener("input", () => {
    if (query.value.trim() == "") {
        autoComplete.hidden = true;
        return;
    }

    fetch("/board/searchAutoComplete", {
        method: "POST",
        headers: { "Content-Type": "application/text" },
        body: query.value // JS 객체 -> JSON 파싱
    })
        .then(response => response.json())
        .then(data => {
            autoComplete.innerHTML = "";
            autoComplete.hidden = false;
            console.log(data)
            if (data.length > 0) {
                data.forEach(item => {
                    const li = document.createElement("li");
                    li.classList.add("autocomplete-item");
                    const a = document.createElement("a");
                    a.innerText = item.boardName + " - " + item.boardTitle;
                    a.setAttribute("href", `/board/\${item.boardCode}/\${item.boardNo}`);
                    li.append(a);
                    autoComplete.append(li);
                });
            } else {
                const div = document.createElement("div");
                div.classList.add("autocomplete-item");
                div.innerText = "검색 결과가 없습니다.";
                autoComplete.appendChild(div);
            }
        })
        .catch(e => {
            console.log("예외 발생");
            console.log(e);
        })

    
});
document.addEventListener("click", (event) => {
    const isClickInsideInput = query.contains(event.target);
    const isClickInsideAutoComplete = autoComplete.contains(event.target);

    if (!isClickInsideInput && !isClickInsideAutoComplete) {
        autoComplete.hidden = true;
    }
});


</script>

위치를 고정적으로 하기 위해서는 css를 absoulte, 부모는 relative 넣기
header에 메인페이지 , 로그인 창을 만들어주기

<a href=”/member/logout”>로그아웃</a>
로그아웃은 이미 기능이 있으니깐 불러온다

<label for="headerMenuToggle"> ${loginMember.memberNickname} <i class="fa-solid fa-caret-down"></i> </label>
닉네임 대신으로 유저일으로 표현하고싶다
${loginMember.memberNickname}

✔️webapp(resources(css)) → main-style.css

* { 
    box-sizing: border-box;
    padding: 0;
    margin: 0;
}

/* div, main, section, header, footer, article, nav, aside, form
{ border : 1px solid black; }  */
/* 다 만들고 삭제 */


main{
    width: 1140px;
    margin : auto;

    /* min-height : 요소의 최소 높이
            -> 내부 요소가 없어도 최소 높이 유지
            -> 내부 요소가 지정된 크기를 초과하면
                그에 맞에 늘어남
    */
    min-height: 500px;
}

/* header */
header{
    height: 200px;
    display: flex;
    flex-direction: row;
}

header > section:nth-child(1){ width: 15%;}
header > section:nth-child(2){ width: 70%;}
header > section:nth-child(3){ width: 15%; }


/* 로고 */
header > section:first-child{
    display: flex;
    justify-content: center;
    align-items: center;
}

#homeLogo{
    width: 120px;
    height: auto; /* 이미지 기본 비율에 맞게 자동 지정 */
}


/* 검색 영역 */
header > section:nth-child(2){
    display: flex;
    justify-content: center;
    align-items: center;
}

.search-area{
    width: 500px;
}

.search-area fieldset{
    border: 2px solid #455ba8;
    padding : 2px;
    border-radius: 5px;
    display: flex;
}

/* 검색 창 */
#query{
    border : none; /* 테두리 없애기 */
    /* outline : 
        포커스가 맞춰진 input의 테두리 */
    /* outline : none; */
    outline : 0;
    font-size: 18px;
    font-weight: bold;
    padding : 10px;

    width: 92%;
}

/* 검색 버튼 */
#searchBtn{
    width: 8%;
    cursor: pointer;
    border : none;

    font-size: 1.2em;
    color : #455ba8;
    background-color: white;
}
/* ---------------------------- */
/* 헤더 오른쪽 상단 메뉴 */

header{
    position: relative;
}

.header-top-menu{
    position: absolute;
    right: 10px;
    top: 5px;
}

.header-top-menu *{
    font-size: 15px;
    font-weight: bold;
}

/* 헤더 메뉴 체크 박스 */
#headerMenuToggle{display: none;}

/* 오른쪽 상단 닉네임 부분 */
label[for='headerMenuToggle']{cursor: pointer;}
label[for='headerMenuToggle']:hover{text-decoration: underline;}

/* 체크박스 다음 형제 요소 div */
#headerMenuToggle + div{display: none;}

/* 체크된 #headerMenuToggle의 다음 형제 요소 div */
#headerMenuToggle:checked + div{display: block;}

/* 닉네임 클릭 시 보이는 메뉴 */
.header-menu{
    position: absolute;
    width: 100px;
    height: 80px;
    right: 0;
    margin-top: 5px;
    border: 1px solid black;
}

.header-menu > a{
    display: flex;
    height: 50%;
    justify-content: center;
    align-items: center;
}

.header-menu > a:first-child{
    border-bottom: 1px solid #ccc;
}

.header-menu > a:hover{
    background-color: #455ba8;
    color: white;
}


/* nav */
nav{
    height: 50px;
    position: sticky;
    /* 화면 밖으로 벗어났을 때 
        지정된 위치에 고정*/

    top : 0; /* 최상단에 붙임 */

    background-color: white;
    border-bottom: 2px solid black;
    z-index: 1000;
}

nav > ul{
    display: flex;

    /* li 태그 앞에 기호 삭제 */
    list-style: none;
    height: 100%;
}


nav li{
    flex : 0 1 150px;
        /* grow shrink basis */
}

nav a{
    text-decoration: none;
    color : black;
    font-size: 18px;
    font-weight: bold;
    padding : 11px 0;
    display: block;
    text-align: center;

    border-radius: 5px;
    transition-duration: 0.1s;
    height: 100%;
}


nav a:hover{
    color : white;
    background-color: #455ba8;
}




/* content */
.content{
    height: 800px;
    display: flex;
    
    /* flex 지정 시 기본값 */
    flex-direction: row;
    justify-content: flex-start;
    align-items: stretch;
}

.content-1{ 
    flex-basis: 70%;
    padding : 20px;
}
.content-2{ flex-basis: 30%;}

.content-1 > *{
    margin-bottom: 20px;
}

.content-1 > pre{
    font-size: 1rem;
    font-family: '고딕';
}

/* 로그인 영역 */
.content-2 > form{
    height: 150px;
    padding : 10px;
    margin-top : 10px;

    display: flex;

    flex-direction: column;
    justify-content: center;
}

.id-pw-area{
    border: 1px solid #ccc;
    display: flex;

    /* 중심축 방향 크기 지정 */
    flex-basis: 60%;
}

/* id/pw 입력 영역*/
.id-pw-area > section:first-child{
    width: 75%;
    display: flex;
    flex-direction: column;
}

.id-pw-area > section:first-child > input{
    border : 0;
    border-right : 1px solid #ccc;
    flex-basis: 50%;
    outline: none;
    padding: 5px;
}

/* id input 태그 */
input[name='inputId']{
    border-bottom : 1px solid #ccc !important;
}

/* id/pw에 초점이 맞춰졌을 때 */
.id-pw-area > section:first-child > input:focus{
    border: 2px solid #455ba8 !important;
}


/* 로그인 버튼 영역 */
.id-pw-area > section:last-child{
    width: 25%;
    display: flex;
    justify-content: center;
}

/* 로그인 버튼 */
.id-pw-area > section:last-child > button{
    width: 100%;
    background-color: white;
    cursor: pointer;
    border : none;
}

/* 로그인 버튼에 마우스가 올라갔을 때 */
.id-pw-area > section:last-child > button:hover{
    background-color: #455ba8;
    color: white;
}

/* 아이디 저장 label */
.content-2 label{
    margin-top: 5px;
    font-size: 14px;
    display: flex;
    padding: 5px 0;
}

input[name='saveId']{
    margin-right: 5px;
}

/* 회원가입, ID/PW 찾기 영역 */
.signup-find-area{
    margin-top: 10px;
    padding-left: 5px;
}

.signup-find-area > a{
    color : black;
    text-decoration: none;
    font-size: 14px;
}

.signup-find-area > span{
    padding: 0 10px;
}




/* footer */
footer{
    height: 200px;
    background-color: #a3add342;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

footer > p{ 
    font-weight: bold;
    margin : 16px 0;
}

footer > article > *{
    font-size: 14px;
}

footer a{
    color:black;
    text-decoration: none;
}

footer span{
    padding : 0 10px;
}


/* ---------------------------------------------------------------------------- */

/* 로그인 성공 시 화면 */
.login-area{
    height: 120px;
    padding: 30px 10px;
    margin: 10px 0;
    border: 1px solid black;
    border-radius: 10px;
    display: flex;
    align-items: center;
}

/* 프로필 이미지 */
#memberProfile{
    width: 64px;
    height: 64px;
    border-radius: 50%;
}


/* 프로필 이미지를 감싸고 있는 a태그 */
.login-area > a{
    display: block;
    width: 70px;
    height: 70px;
    border: 3px solid #ddd;
    border-radius: 50%;
}

/* 회원 정보 + 로그아웃 버튼 영역 설정 */

.my-info{
    width: 100%;
    height: 100%;
    margin-left: 20px;
}

.my-info > div{
    display: flex;
    justify-content: space-between;
}

a{ 
    text-decoration: none;
    color : black;
}

/* 닉네임 */
#nickname{
    color : black;
    font-size: 20px;
    font-weight: bold;
    letter-spacing: -3px;
}

/* 로그아웃 버튼 */
#logoutBtn{
    color : gray;
    font-size: 14px;
    font-weight: bold;

    border: 2px solid gray;
    padding : 3px 5px;
    border-radius: 10px;
}

#logoutBtn:hover{
    color : white;
    background-color: gray;
}

#logoutBtn:active{
    transform: scale(0.8);
}

/* 내정보 - 이메일 */
.my-info > p{
    margin: 0;
    color : gray;
}

#autoDisplayList{
    display: none;
}
/* 오른쪽 상단 닉네임 부분 */
label[for='headerMenuToggle']{cursor: pointer;}
label[for='headerMenuToggle']:hover{text-decoration: underline;}
/* 체크박스 다음 형제 요소 div */
#headerMenuToggle + div{display: none;}
/* 체크된 #headerMenuToggle의 다음 형제 요소 div */
#headerMenuToggle:checked + div{display: block;}

따로 js 처리 귀찮으니깐 checked 넣기


근데 MemberController에 로그인을 @PostMapping으로 함
그래서 get방식으로 줘야하는데 문제가 생김
따로 방식이 다르니깐 만들 수 있음

✔️ → login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html lang="ko">


<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>로그인 페이지</title>


    <link rel="stylesheet" href="/resources/css/member/login.css">


    <script src="https://kit.fontawesome.com/f7459b8054.js" crossorigin="anonymous"></script>
</head>


<body>
    <main>


        <section class="logo-area">
            <a href="/">
                <img src="/resources/images/logo.jpg">
            </a>
        </section>




        <form action="/member/login" method="post">
            <section class="input-box">
                <input type="text" name="memberEmail" placeholder="Email" value="${cookie.saveId.value}"/>
            </section>


            <section class="input-box">
                <input type="password" name="memberPw" placeholder="Password"/>
            </section>


            <button class="login-btn">Login</button>


            <%-- 쿠키에 saveId가 있는 경우--%>
            <c:if test="${ !empty cookie.saveId.value}">
                <%-- chk 변수 생성(page scope)--%>
                <c:set var="chk" value="checked"/>
            </c:if>


            <div class="saveId-area">
                <input type="checkbox" name="saveId" id="saveId" ${chk}>
                <label for="saveId"><i class="fas fa-check"></i>아이디 저장</label>
            </div>


            <p class="text-area">
                <a href="#">회원가입</a>
                |
                <a href="#">ID/PW 찾기</a>
            </p>
        </form>
    </main>


  </body>
</html>

✔️ → login.css

* {
    box-sizing: border-box;
    margin : 0;
    padding : 0;
}


body {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100vh;
    overflow: hidden;
    margin: 0;
}


main {
    padding: 20px 40px;
    border-radius: 5px;
}


main .logo-area {
    text-align: center;
    margin-bottom: 30px;
}


.logo-area img{
    width: 150px;
}

.input-box {
    position: relative;
    margin: 20px 0 40px;
    width: 300px;
}


.input-box input {
    border: 0;
    border-bottom: 2px solid black;
    display: block;
    width: 100%;
    padding: 15px 0;
    font-size: 18px;
}


.input-box input:focus{
    outline: 0;
    border-bottom-color: lightblue;
}


.login-btn {
    cursor: pointer;
    display: inline-block;
    width: 100%;
    background: #455ba8;
    color : white;
    padding: 15px;
    font-size: 18px;
    border: 0;
    border-radius: 5px;
}


.login-btn:focus {
    outline: 0;
}


.login-btn:active {
    transform: scale(0.98);
}

.saveId-area{
    margin-top: 10px;
    padding: 10px 0;
    border-bottom: 2px solid #ccc;
    display: flex;
    align-items: center;
}        


.saveId-area > input{
    display: none;
}


#saveId+label{
    display: flex;
    cursor: pointer;
}


#saveId+label > i{
    display: flex;
    justify-content: center;
    align-items: center;


    width: 25px;
    height: 25px;
    border: 1px solid #ccc;
    border-radius: 50%;
    margin-right: 10px;
    color : #ccc;
    font-size: 1.05em;
}


.saveId-area > input:checked + label > i{
    background-color: #455ba8;
    border-color: #455ba8;
    color: white !important;
}


.text-area {
    margin-top: 10px;
    text-align: center;
}


.text-area a{
    text-decoration: none;
    color: black;
    margin: 0 20px;
}

✔️webapp(WEB-INF(views(common))) → main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>게시판 프로젝트</title>

    <link rel="stylesheet" href="/resources/css/main-style.css">
</head>
<body>

    <main>

        <%-- header.jsp 추가(포함) --%>

        <%-- 
            <jsp:include page="jsp파일경로" /> 

            - JSP 액션 태그 (jsp에 기본 내장된 태그)
            - 다른 jsp 파일의 코드를 현재 위치에 추가(포함)
            - jsp 파일 경로는 webapp 폴더를 기준으로 작성
        --%>
        <jsp:include page="/WEB-INF/views/common/header.jsp" />


        <section class="content">
            <section class="content-1">

                <h3>로그인된 회원 정보</h3>

                ${sessionScope.loginMember}

                <h3>닉네임이 일치하는 회원의 전화번호 조회</h3>

                <input type="text" id="inputNickname">
                <button id="btn1">조회</button>
                <h4 id="result1"></h4>

                <hr>
                
                <h3>이메일을 입력받아 일치하는 회원의 정보를 조회</h3>
                email : <input type="text" id="inputEmail">
                <button id="btn2">조회</button>
                <ul id="result2">
                </ul>

                <hr>

                <h3>이메일이 일부라도 일치하는 모든 회원 조회</h3>
                검색어 : <input type="text" id="input">
                <button id="btn3">조회</button>

                <table border="1" style="border-collapse: collapse;">
                    <thead>
                        <tr>
                            <th>회원번호</th>
                            <th>이메일</th>
                            <th>닉네임</th>
                        </tr>
                    </thead>

                    <tbody id="result3">
                        <tr>
                            <td>1</td>
                            <td>user01@kh.or.kr</td>
                            <td>유저일</td>
                        </tr>
                    </tbody>
                </table>

            </section>

            <section class="content-2">

                <c:choose>  
                    <%-- 
                        c:choose 내부에는 c:when, c:otherwise, jsp 주석만 작성 가능
                        c:when, c:otherwise 내부에는 다른 코드 작성 가능!
                    --%>

                    <%-- EL empty 연산자 : 비어 있거나 null 이면 true --%>
                    <c:when test="${empty sessionScope.loginMember}">

                        <!-- method="POST" : 제출 되는 값이 주소에 안보임 -->
                        <form action="/member/login" method="POST" id="loginFrm">
                            <fieldset class="id-pw-area">
                                <section>
                                    <input type="text" name="memberEmail" placeholder="이메일" autocomplete="off"
                                           value="${cookie.saveId.value}" id="memberEmail">
                                    <input type="password" name="memberPw" placeholder="비밀번호" id="memberPw">                  
                                </section>
                                <section>
                                    <button>로그인</button>
                                </section>
                            </fieldset>

                            <label>
                                <%-- <c:if test="${empty cookie.saveId.value}">
                                    <input type="checkbox" name="saveId"> 아이디 저장
                                </c:if>
                                
                                <c:if test="${!empty cookie.saveId.value}">
                                    <input type="checkbox" name="saveId" checked> 아이디 저장
                                </c:if> --%>
                                
                                <c:if test="${!empty cookie.saveId.value}">
                                    <%-- 쿠키에 저장된 이메일이 있으면 save 변수 선언
                                    -> page scope(페이지 내에서 사용 가능, if문 끝나도 가능!)
                                    --%>
                                    <c:set var="save" value="checked" />
                                </c:if>
                                
                                <input type="checkbox" name="saveId" ${save}> 아이디 저장
                            </label>

                            <article class="signup-find-area">
                                <a href="/member/signUp">회원가입</a>
                                <span>|</span>
                                <a href="#">ID/PW 찾기</a>
                            </article>
                        </form>

                    </c:when>

                    
                    <%-- 로그인 되었을 때 --%>
                    <c:otherwise>
                        <article class="login-area">

                            <a href="/myPage/profile">
                                
                                <%-- 프로필 이미지가 없으면 기본 이미지 --%>
                                <c:if test="${empty loginMember.profileImage}" >
                                    <img src="/resources/images/user.png" id="memberProfile">
                                </c:if>

                                <%-- 프로필 이미지가 있으면 있는 이미지 --%>
                                <c:if test="${!empty loginMember.profileImage}" >
                                    <img src="${loginMember.profileImage}" id="memberProfile">
                                </c:if>

                            </a>

                            <div class="my-info">
                                <div>
                                    <a href="/myPage/info" id="nickname">${sessionScope.loginMember.memberNickname}</a>

                                    <a href="/member/logout" id="logoutBtn">로그아웃</a>
                                </div>   

                                <p>${loginMember.memberEmail}</p>

                            </div>

                        
                        </article>
                    </c:otherwise>


                </c:choose>

                
            </section>
        </section>
    </main>

    <%-- footer --%>
    <jsp:include page="/WEB-INF/views/common/footer.jsp"/>

    <%-- SockJS 추가 --%>
    <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
    
    <!-- main.js 추가 -->
    <script src="/resources/js/main.js"></script>

</body>
</html>
<!--  main.js 추가 -->
<script src="/resources/js/main.js"></script>

✔️webapp(resources(js)) → main.js

const loginFrm = document.getElementById("loginFrm");

const memberEmail = document.querySelector("#loginFrm input[name='memberEmail']");
const memberPw = document.querySelector("#loginFrm input[name='memberPw']");

if(loginFrm != null){
    // 로그인 시도를 할 때
    loginFrm.addEventListener("submit", e => {
        // alert("로그인");
    
        // form 태그 기본 이벤트 제거
        // e.preventDefault();
  
        // 이메일이 입력되지 않은 경우
        if(memberEmail.value.trim().length == 0){
            alert("이메일을 입력해 주세요.");

            // 잘못 입력된 값(공백) 제거
            memberEmail.value = "";

            // 이메일 input 태그에 초점 맞춤
            memberEmail.focus();

            // 제출 못 하게 하기
            e.preventDefault();
            return;
        }
        
        // 비밀번호가 입력되지 않은 경우
        if(memberPw.value.trim().length == 0){
            alert("비밀번호를 입력해 주세요.");

            // 잘못 입력된 값(공백) 제거
            memberPw.value = "";

            // 이메일 input 태그에 초점 맞춤
            memberPw.focus();

            // 제출 못 하게 하기
            e.preventDefault();
            return;
        }

    })
}

e라고 쓰면 event

근데 로그인이 main 화면에만 있는 게 아니잖아!
login.jsp에도 있잖아!

2️⃣ Spring

✔️project(member(controller)) → MemberController.java

...
	// 로그인 전용 화면 이동
	@GetMapping("/login")
	public String login() { // 오버로딩
		return "member/login";
	}
...
profile
Hello! My Name is oYJo

0개의 댓글