SpringBoot
바꾸고 싶을 경우 앞, 뒤 값 변경하면 됨.
<!DOCTYPE html>
<!-- 현재 HTML 문서에 타임리프 문법을 사용한다고 선언 -->
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>프로젝트</title>
</head>
<body>
<main>
<!-- th:block
- html 태그가 아닌 단순히 타임리프를 쓰기 위한 태그가 필요할 때 사용
- 타임리프 해석 시 다른 타임리프 수행 후 사라짐
-->
<th:block th:replace="~{common/header}"></th:block>
<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>
<input id="inputEmail">
<button id="btn2">조회</button>
<ul id="result2">
</ul>
<h3>삼항 연산자</h3> <!-- 타임리프에서 쓸 수 있는 연산자 -->
<!-- ${name} 값이 있으면 true, 없으면 false -->
<p th:text="${name} ? ${name} : '이름 없음'"></p>
<!-- 조건 ? true : false -->
<p th:text="${name2} ? ${name2} : '이름 없음'"></p>
<h3>Elvis 연산자</h3> <!-- 삼항 연산자보다 간단하게 쓸 수 있는 연산자 -->
<p th:text="${name} ?: '이름 없음'"></p>
<p th:text="${name2} ?: '이름 없음'"></p>
<h3>No-Operation</h3> <!-- 타임리프에서 만든 연산자 -->
<p th:text="${name} ?:_">(태그에작성)이름 없음</p>
<p th:text="${name2} ?:_">(태그에작성)이름 없음</p>
</section>
<!-- 아이디/비밀번호/로그인버튼 영역 -->
<section class="content-2">
<!-- 로그인 X -->
<th:block th:unless="${session.loginMember}">
<form th:action="@{/member/login}" method="post" name="login-form" id="loginFrm">
<fieldset class="id-pw-area">
<section>
<input type="text" name="memberEmail" placeholder="이메일"
autocomplete="off"
value=""
>
<input type="password" name="memberPw" placeholder="비밀번호">
</section>
<section>
<button>로그인</button>
</section>
</fieldset>
<label>
<input type="checkbox" name="saveId"> 아이디 저장
</label>
<!-- 회원가입/ Id/pw 찾기 영역 -->
<section class="signup-find-area">
<a th:href="@{/member/signUp}">회원가입</a>
<span>|</span>
<a th:href="@{#}">ID/PW 찾기</a>
</section>
</form>
</th:block>
<!-- 로그인 O -->
<!-- request Scope는 그냥 써도 인식함.
session Scope는 session.loginMember 이런식으로 session.을 꼭 붙여야한다.
-->
<th:block th:if="${session.loginMember}">
<article class="login-area">
<a th:href="@{/myPage/profile}">
<img th:src="@{/images/user.png}" id="memberProfile">
</a>
<div class="my-info">
<div>
<a th:href="@{/myPage/info}" id="nickname">[[${session.loginMember.memberNickname}]]</a>
<!-- <th:block th:text="${session.loginMember.memberNickname}">로그인 회원의 닉네임</th:block>
너무 길기 때문에 위의 방법으로 사용 가능!
-->
<a th:href="@{/member/logout}" id="logoutBtn">로그아웃</a>
</div>
<p></p>
</div>
</article>
</th:block>
</section>
</section>
</main>
<th:block th:replace="~{common/footer}"></th:block>
<!-- SockJS 추가 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script> -->
<!-- main.js 추가 -->
<script th:src="@{/js/main.js}"></script>
</body>
</html>
fragment = 태그 일부분만 가져오는 것 가능
<link rel="stylesheet" th:href="@{/css/main-style.css}">
<!-- 경로나 주소 작성할 때 쓰는 타임리프 표기법 :
타임리프 사용 시, 하나로 통일하는 것이 좋아서 이렇게 작성하는 것! -->
<!-- fontaswesom 아이콘 사용할 수 있는 스크립트 연결-->
<script th:src="@{https://kit.fontawesome.com/f821b57119.js}" crossorigin="anonymous"></script>
<header>
<!-- 클릭 시 메인페이지로 이동하는 로고 -->
<section>
<a th:href="@{/}">
<img th:src="@{/images/logo.jpg}" id="homeLogo">
</a>
</section>
<!-- 검색창 부분 -->
<section>
<section class="search-area">
<!-- form 내부 input 태그 값을 서버 또는 페이지로 전달 -->
<form th:action="@{/search}" method="GET" name="search-form">
<!-- fieldset : form 내부에서 input을 종류별로 묶는 용도로 자주 사용 -->
<fieldset>
<!-- search : 텍스트 타입과 기능적으로는 똑같으나,
브라우저에 의해 다르게 표현될 수 있음. -->
<!-- autocomplete : HTML 기본 자동완성 사용 X -->
<input type="search" id="query" name="query"
autocomplete="off" placeholder="회원을 닉네임으로 검색해주세요."
>
<button id="searchBtn" class="fa-solid fa-magnifying-glass"></button>
</fieldset>
</form>
</section>
</section>
<section></section>
</header>
<!-- 보통은 header안에 작성하나 사이드에 nav가 있는 경우도 있기 때문에 따로 작성해본다! -->
<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>
</ul>
</nav>
참고
-> 타임리프에 대한 문법들은 개발자 도구에서 보이지 않음
<footer>
<p>Copyright © KH Information Educational Institute E-Class</p>
<section>
<a href="#">프로젝트 소개</a>
<span>|</span>
<a href="#">이용약관</a>
<span>|</span>
<a href="#">개인정보처리방침</a>
<span>|</span>
<a href="#">고객센터</a>
</section>
</footer>
<!-- javascript 영역에서 타임리프를 적용/ 해석 함 -->
<!-- html 안에 있는 script 태그 안에서만 사용 가능! 확장자가 .js인 곳에서는 사용 불가능 -->
<script th:inline="javascript">
/* Natural Template */
const message = /*[[${message}]]*/ "전달 받은 메세지";
// 타임리프 해석 값(자료형 알아서 해석) 사라짐(설명)
// 문자, 숫자 구분
if(message != null) alert(message);
</script>
package edu.kh.project.member.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import edu.kh.project.member.model.dto.Member;
import jakarta.servlet.http.HttpSession;
@RequestMapping("/member")
@Controller
@SessionAttributes({"loginMember"})
public class MemberController {
// 로그인
@PostMapping("/login")
public String login(Member inputMember, Model model, RedirectAttributes ra) {
if(inputMember.getMemberEmail().equals("user01") &&
inputMember.getMemberPw().equals("pass01!")) {
Member loginMember = new Member();
loginMember.setMemberEmail("user01");
loginMember.setMemberNickname("유저일");
loginMember.setMemberNo(1);
model.addAttribute("loginMember", loginMember);
} else {
// 로그인 실패 시 테스트
ra.addFlashAttribute("message", "아이디 또는 비밀번호 일치하지 않음");
}
return "redirect:/";
}
// 로그아웃
@GetMapping("/logout")
public String logout(SessionStatus status, HttpSession session) {
status.setComplete();
return "redirect:/";
}
}
package edu.kh.project.member.model.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Member {
private int memberNo;
private String memberEmail;
private String memberPw;
private String memberNickname;
private String memberTel;
private String memberAddress;
private String profileImage;
private String enrollDate;
private String memberDeleteFlag;
private int authority; // 회원권한(1:일반, 2:관리자)
}
package edu.kh.project.main.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/")
public String mainForward(Model model) {
model.addAttribute("name", "홍길동");
// Spring MVC : /webapp/WEB-INF/views/common/main.jsp
// Spring Boot (+ thymeleaf 템플릿 엔진)
// src/main/resources/templates/common/main.html
return "common/main";
}
}
[ 구현 화면 ]
아이디 user01 비밀번호 pass01! 입력 후 로그인 버튼 클릭 시,
잘못된 아이디, 비밀번호 입력 후 로그인 버튼 클릭 시,
해당 alert창 뜸