SpringBoot
OXTV 회원가입/로그인
김윤지.
2025. 5. 26. 21:21
사용자 테이블
CREATE TABLE `users` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
`user_password` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
`user_name` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
`email` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_uca1400_ai_ci',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `user_id` (`user_id`) USING BTREE,
UNIQUE INDEX `email` (`email`) USING BTREE
)
COLLATE='utf8mb4_uca1400_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;
index.jsp (홈화면)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>OXTV 커뮤니티</title>
</head>
<body>
<h1>뜨개 OXTV 커뮤니티에 오신 것을 환영합니다</h1>
<p>여기가 니가 만들 세상의 시작이다.</p>
<form action="/signup" method="get">
<button type="submit">회원가입</button>
</form>
<%
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
%>
<%= ((com.oxtv.model.User)loginUser).getUserName() %> 님 환영합니다!
<a href="/logout"><button>로그아웃</button></a>
<%
} else {
%>
<a href="/signup"><button>회원가입</button></a>
<a href="/login"><button>로그인</button></a>
<%
}
%>
</body>
</html>
HomeController.java
package com.oxtv.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index"; // src/main/webapp/WEB-INF/views/index.jsp 반환
}
}
signup.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java"%>
<!DOCTYPE html>
<html>
<head>
<title>회원가입</title>
</head>
<body>
<form action="/signup" method="post">
<input type="text" name="userId" placeholder="아이디" required />
<input type="password" name="userPassword" placeholder="비밀번호" required />
<input type="text" name="userName" placeholder="이름" required />
<input type="email" name="email" placeholder="이메일" required />
<button type="submit">회원가입</button>
</form>
</body>
</html>
UserController.java
package com.oxtv.controller;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.oxtv.model.User;
import com.oxtv.repository.UserRepository;
import org.springframework.ui.Model;
import jakarta.validation.Valid;
@Controller
public class UserController {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
public UserController(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
@GetMapping("/signup")
public String showSignupForm(User user) {
return "signup"; // signup.html 또는 signup.jsp
}
@PostMapping("/signup")
public String processSignup(@Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
return "signup";
}
// 아이디 중복 체크
if (userRepository.existsByUserId(user.getUserId())) {
model.addAttribute("userIdError", "이미 사용중인 아이디입니다.");
return "signup";
}
// 이메일 중복 체크
if (userRepository.existsByEmail(user.getEmail())) {
model.addAttribute("emailError", "이미 사용중인 이메일입니다.");
return "signup";
}
// 비밀번호 암호화
user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
userRepository.save(user);
return "redirect:/login"; // 회원가입 끝나면 로그인 페이지로
}
}
User.java
package com.oxtv.model;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@Table(name = "users")
@Getter @Setter @NoArgsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "user_id", unique = true, nullable = false)
private String userId;
@Column(name = "user_password", nullable = false)
private String userPassword;
@Column(name = "user_name", nullable = false)
private String userName;
@Column(unique = true, nullable = false)
private String email;
}
UserRepository
package com.oxtv.repository;
import com.oxtv.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUserId(String userId);
boolean existsByEmail(String email);
boolean existsByUserId(String userId);
}
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<title>로그인</title>
</head>
<body>
<h2>로그인 페이지</h2>
<form action="<c:url value='/login' />" method="post">
<input type="text" name="userId" placeholder="아이디" required />
<input type="password" name="userPassword" placeholder="비밀번호" required />
<button type="submit">로그인</button>
</form>
<c:if test="${not empty errorMessage}">
<p style="color:red">${errorMessage}</p>
</c:if>
<p>계정이 없으면 <a href="<c:url value='/signup' />">회원가입</a> 하세요.</p>
</body>
</html>
LoginController.java
package com.oxtv.controller;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.oxtv.repository.UserRepository;
import com.oxtv.model.User;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.ui.Model;
@Controller
public class LoginController {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
@GetMapping("/login")
public String loginForm() {
return "login"; // login.jsp 보여줌
}
@PostMapping("/login")
public String login(@RequestParam String userId, @RequestParam String userPassword, HttpSession session,
Model model) {
User user = userRepository.findByUserId(userId);
if (user == null) {
model.addAttribute("errorMessage", "아이디가 존재하지 않습니다");
return "login"; // login.jsp 다시 보여줌
}
if (!passwordEncoder.matches(userPassword, user.getUserPassword())) {
model.addAttribute("errorMessage", "비밀번호가 틀렸습니다");
return "login";
}
session.setAttribute("loginUser", user); // 로그인 세션 생성
return "redirect:/"; // 로그인 성공하면 메인 페이지로
}
@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate(); // 세션 제거
return "redirect:/"; // 메인 페이지로 이동
}
}
SecurityConfig.java
package com.oxtv.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.context.annotation.Bean;
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable() // CSRF 보호 비활성화 (개발용)
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) // 모든 요청 허용
.formLogin().disable() // 로그인 폼 비활성화
.httpBasic().disable(); // 기본 인증 비활성화
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} //암호화 비교
}