반응형
table
CREATE TABLE USER_INFO"
("USER_NO" NUMBER(10,0) NOT NULL ENABLE,
"ID" VARCHAR2(20) NOT NULL ENABLE,
"PASSWORD" VARCHAR2(50) NOT NULL ENABLE,
"NAME" VARCHAR2(20) NOT NULL ENABLE,
"EMAIL" VARCHAR2(50) NOT NULL ENABLE,
"CREATE_DATE" DATE NOT NULL ENABLE,
"UPDATE_DATE" DATE DEFAULT SYSDATE,
CONSTRAINT "USER_PK" PRIMARY KEY ("USER_NO", "ID")
);
COMMENT ON COLUMN USER_INFO.USER_NO IS '사용자 순번(시퀀스:USER_NO_SEQ)';
COMMENT ON COLUMN USER_INFO.ID IS '아이디';
COMMENT ON COLUMN USER_INFO.PASSWORD IS '비밀번호';
COMMENT ON COLUMN USER_INFO.NAME IS '이름';
COMMENT ON COLUMN USER_INFO.EMAIL IS '이메일';
COMMENT ON COLUMN USER_INFO.CREATE_DATE IS '등록일';
COMMENT ON COLUMN USER_INFO.UPDATE_DATE IS '수정일';
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="study.example.thboard.mapper.UserMapper">
<!--로그인한 회원 정보-->
<select id="selectById" parameterType="map" resultType="UserVo">
SELECT USER_NO AS userNo
, ID AS id
, PASSWORD AS password
, NAME AS name
, EMAIL AS email
FROM USER_INFO
WHERE 1=1
AND ID = #{id}
</select>
</mapper>
Vo
package study.example.thboard.vo;
import lombok.Data;
@Data
public class UserVo extends CommonVo{
private Long userNo;
private String id;
private String password;
private String name;
private String email;
}
mapper interface
package study.example.thboard.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import study.example.thboard.vo.BoardVo;
import study.example.thboard.vo.UserVo;
import java.util.List;
@Repository @Mapper
public interface UserMapper {
/* 아이디로 사용자 정보 조회 */
UserVo selectById(@Param("id") String id);
}
service
package study.example.thboard.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import study.example.thboard.mapper.BoardMapper;
import study.example.thboard.mapper.UserMapper;
import study.example.thboard.vo.BoardVo;
import study.example.thboard.vo.UserVo;
import java.util.List;
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
private final UserMapper userMapper;
/**
* 아이디/패스워드 확인
* @param id
* @param password
* @return
*/
public String login(String id, String password) {
UserVo useInfo = userMapper.selectById(id);
return useInfo.getPassword().equals(password) ? useInfo.getId() : null;
}
}
controller
package study.example.thboard.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import study.example.thboard.service.UserService;
import study.example.thboard.vo.UserVo;
import javax.servlet.http.HttpSession;
@Controller
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserService userService;
/**
* 로그인 화면
* @param session
* @return
*/
@GetMapping("/login")
public String loginForm(HttpSession session) {
String id = (String) session.getAttribute("id");
log.info("세션에 저장된 사용자 아이디 = {} ", id);
return id != null ? "redirect:/" : "pages/login" ;
}
/**
* 로그인 처리
* @param userVo
* @param session
* @return
*/
@PostMapping("/login")
public String login(UserVo userVo, HttpSession session) {
String id = userService.login(userVo.getId(), userVo.getPassword());
if(id == null) return "redirect:/login";
session.setAttribute("id", id);
return "redirect:/";
}
/**
* 로그아웃
* @param session
* @return
*/
@PostMapping("/logout")
public String logout(HttpSession session) {
log.info("로그아웃!");
session.invalidate();
return "redirect:/login";
}
}
login.html
디자인은 무시하고 로그인 클릭 이벤트 시 post방식으로 id와 password만 서버로 넘김
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/default_layout}">
<script layout:fragment="script" th:inline="javascript" type="text/javascript">
$(document).ready(function () {
});
</script>
<!-- Content -->
<div layout:fragment="content">
<form id="frm" action="/login" method="post">
<div id="layoutAuthentication">
<div id="layoutAuthentication_content">
<main>
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-5">
<div class="card shadow-lg border-0 rounded-lg mt-5">
<div class="card-header"><h3 class="text-center font-weight-light my-4">Login</h3></div>
<div class="card-body">
<form>
<div class="form-floating mb-3">
<input class="form-control" id="id" name="id" type="id" placeholder="name@example.com" />
<label for="inputEmail">ID</label>
</div>
<div class="form-floating mb-3">
<input class="form-control" id="password" name="password" type="password" placeholder="Password" />
<label for="inputPassword">Password</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" id="inputRememberPassword" type="checkbox" value="" />
<label class="form-check-label" for="inputRememberPassword">Remember Password</label>
</div>
<div class="d-flex align-items-center justify-content-between mt-4 mb-0">
<a class="small" href="password.html">Forgot Password?</a>
<button type="submit" class="btn btn-success">Login</button>
</div>
</form>
</div>
<div class="card-footer text-center py-3">
<div class="small"><a href="register.html">Need an account? Sign up!</a></div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
<div id="layoutAuthentication_footer">
<footer class="py-4 bg-light mt-auto">
<div class="container-fluid px-4">
<div class="d-flex align-items-center justify-content-between small">
<div class="text-muted">Copyright © Your Website 2023</div>
<div>
<a href="#">Privacy Policy</a>
·
<a href="#">Terms & Conditions</a>
</div>
</div>
</div>
</footer>
</div>
</div>
</form>
</div>
</html>
logout.html
타임리프로 레이아웃을 나눠 놨지만 무시하고 로그아웃 버튼 클릭 이벤트로
post방식으로 서버 호출만 하면 됨
<html lagn="ko" xmlns:th="http://www.thymeleaf.org">
<!--headerFragment 선언-->
<nav th:fragment="headerFragment" class="sb-topnav navbar navbar-expand navbar-dark bg-dark">
<!-- Navbar Brand-->
<a class="navbar-brand ps-3" th:href="@{/}">Start Bootstrap</a>
<!-- Sidebar Toggle-->
<button class="btn btn-link btn-sm order-1 order-lg-0 me-4 me-lg-0" id="sidebarToggle" href="#!"><i class="fas fa-bars"></i></button>
<!-- Navbar Search-->
<form class="d-none d-md-inline-block form-inline ms-auto me-0 me-md-3 my-2 my-md-0">
<div class="input-group">
<input class="form-control" type="text" placeholder="Search for..." aria-label="Search for..." aria-describedby="btnNavbarSearch" />
<button class="btn btn-primary" id="btnNavbarSearch" type="button"><i class="fas fa-search"></i></button>
</div>
</form>
<!-- Navbar-->
<ul class="navbar-nav ms-auto ms-md-0 me-3 me-lg-4">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="navbarDropdown" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false"><i class="fas fa-user fa-fw"></i></a>
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#!">Settings</a></li>
<li><a class="dropdown-item" href="#!">Activity Log</a></li>
<li><hr class="dropdown-divider" /></li>
<li><a class="dropdown-item" id="logout" href="#">Logout</a></li>
<script>
$(document).ready(function () {
$("#logout").on("click", function () {
let form = $("<form></form>");
form.attr("method","post");
form.attr("action", "/logout");
form.appendTo("body");
form.submit();
});
});
</script>
</ul>
</li>
</ul>
</nav>
</html>
index.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/default_layout}">
<script layout:fragment="script" th:inline="javascript" type="text/javascript">
$(document).ready(function () {
//글쓰기
$("#btnSave").on("click", function () {
$("#frm").attr("action", "/regForm").submit();
});
//검색
$("#btnSearch").on("click", function (e) {
e.preventDefault();
$("#pageNum").val(1);
$("#frm").submit();
});
});
//삭제
function del(no) {
let boardNo = $("<input>").attr("type", "hidden").attr("name", "boardNo").val(no);
$("#frm").attr("method", "post")
.attr("action", "del")
.append(boardNo)
.submit();
}
</script>
<!-- Content -->
<div layout:fragment="content">
<form id="frm" th:object="${pageMaker}" action="" method="get">
<main>
<div class="container-fluid px-4">
<h1>게시글 관리</h1>
<div class="input-group mb3">
<select name="type" th:field="${cri.type}">
<option value="">--</option>
<option value="W">작성자</option>
<option value="T">제목</option>
<option value="C">내용</option>
</select>
<input type="text" name="keyword" th:field="${cri.keyword}">
<input type="hidden" id="pageNum" name="pageNum" th:value="${cri.pageNum}">
<input type="hidden" id="amount" name="amount" th:value="${cri.amount}">
<button type="button" id="btnSearch" class="btn btn-secondary">검색</button>
</div>
<table class="table table-striped table-sm">
<thead>
<tr>
<th>순번</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th>등록일</th>
<th>수정일</th>
<th></th>
</tr>
</thead>
<tbody>
<tr th:if="${#lists.size(list) >0}" th:each="list : ${list}">
<td th:text="${list.no}"></td>
<td><a th:href="@{/detail(boardNo=${list.boardNo})}" th:text="${list.title}"></a></td>
<td th:text="${list.content}"></td>
<td th:text="${list.writer}"></td>
<td th:text="${list.createDate}"></td>
<td th:text="${list.updateDate}"></td>
<td><a href="#" th:href="'javascript:del('+${list.boardNo}+')'" class="btn btn-danger">삭제</a></td>
</tr>
</tbody>
</table>
</div>
<!-- 게시판 하단 페이지네이션 영역 start -->
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center">
<!-- prev -->
<li class="page-item" th:if="${pageMaker.prev} == true">
<a class="page-link" th:href="@{/(pageNum=${pageMaker.startPage}-1, type=${pageMaker.cri.type}, keyword=${pageMaker.cri.keyword})}">Prev</a>
</li>
<!-- pageMaker의 startPage부터 endPage까지 루프, a태그의 href에 idx를 링크(get방식으로 pageNum을 붙여서) -->
<li class="page-item" id="paginate_btn" th:each="idx: ${#numbers.sequence(pageMaker.startPage, pageMaker.endPage)}" th:classappend="${pageMaker.cri.pageNum} == ${idx} ? active : null">
<a class="page-link" th:href="@{/(pageNum=${idx}, type=${pageMaker.cri.type}, keyword=${pageMaker.cri.keyword})}" th:text="${idx}"></a>
</li>
<!-- next -->
<li class="page-item" th:if="${pageMaker.next} == true and ${pageMaker.endPage > 0}">
<a class="page-link" th:href="@{/(pageNum=${pageMaker.endPage}+1, type=${pageMaker.cri.type}, keyword=${pageMaker.cri.keyword})}">Next</a>
</li>
</ul>
</nav>
<!-- // 게시판 하단의 페이지네이션 영역 end -->
<!-- 로그인 한 사용자만 글쓰기 버튼 표시 -->
<th:block th:if="${session.id != null}">
<button type="button" id="btnSave" class="btn btn-info">글쓰기</button>
</th:block>
</main>
</form>
</div>
</html>
반응형
'IT > development' 카테고리의 다른 글
[springBoot] springBoot Interceptor 로그인 체크 (0) | 2023.05.13 |
---|---|
[springBoot] spring boot jar파일 배포 삽질(feat. 리눅스) (0) | 2023.05.13 |
[springBoot] 페이지네이션 처리(feat. Oracle) (0) | 2023.05.07 |
[springBoot] 첨부파일 업/다운로드(Oracle) (0) | 2023.05.07 |
[springBoot] UrlResource 사용 시 경로 에러 (0) | 2023.05.07 |