구현
1. JPA를 이용하여 회원 정보를 관리하는 User Entity Class
package com.gld.model.dto;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "G_USER")
public class UserDto {
@Id
private Long Id;
@Column(name = "USER_ID",nullable = false, unique = true)
private String userId;
@Column(name = "USER_PW",nullable = false)
private String userPw;
@Column(name = "USER_NAME",nullable = false)
private String userName;
@Column(name = "COMPLETED_CHALLENGE",nullable = false)
private int completedChallenge;
@Column(name = "ONOFF_NOTY",nullable = false)
private String onOffNoty;
@Column(name = "USER_LOGINTYPE",nullable = false)
private String userLoginType;
@Column(name = "USER_PHONE",nullable = false)
private String userPhone;
@Column(name = "USER_BIRTH",nullable = false)
private Date userBirth;
//생성자, getter, setter
}
2. 로그인 기능을 구현하기 위한 UserRepository 인터페이스
package com.gld.model.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.gld.model.dto.UserDto;
@Repository
public interface UserRepository extends JpaRepository<UserDto, Long> {
UserDto findByUserId(String userId);
}
3. LoginBiz
package com.gld.model.biz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gld.model.dto.UserDto;
import com.gld.model.repository.UserRepository;
@Service
public class LoginBiz {
@Autowired
private UserRepository userRepository;
public UserDto findByUserId(String userId) {
UserDto user = userRepository.findByUserId(userId);
return user;
}
}
4. 로그인 기능을 처리하는 LoginController
package com.gld.model.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
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 com.gld.model.biz.LoginBiz;
import com.gld.model.dto.UserDto;
import com.gld.model.repository.UserRepository;
@Controller
@RequestMapping("/login")
public class LoginController {
@Autowired
private LoginBiz loginBiz;
@GetMapping("/login")
public String moveToLogin() {
System.out.println("go to loginform");
return "loginform";
}
@PostMapping("/logincheck")
public String login(String userId, String userPw, HttpSession session,Model model) {
UserDto user = loginBiz.findByUserId(userId);
if (user != null && user.getUserPw().equals(userPw)) {
session.setAttribute("user", user);
return "redirect:/index/main";
} else {
model.addAttribute("error", "아이디 또는 비밀번호가 일치하지 않습니다.");
return "loginform";
}
}
@GetMapping("/logout")
public String logout(HttpSession session) {
session.removeAttribute("user");
return "redirect:/";
}
}
문제 상황
위의 내용대로 모두 구현 후 실행 시 오류도 없고 SQL 쿼리도 맞는데 값을 못찾아서 계속 헤맸다.
문제는 바로 Entity Class에 @Table Annotation으로 DB Table 명을 대문자로 입력했음에도 소문자로 매핑하고 있었던 것이었다.
문제 원인
Spring Boot의 DB Physical Naming Strategy 때문이었다.
Spring Boot의 기본 DB Physical Naming 전략은 아래와 같다.
1. Entity 클래스의 이름 그대로 사용
2. CamelCase를 언더스코어(_)로 대체
3. 모든 문자를 소문자로 변환
문제 해결
Spring Boot의 Physical Naming Strategy를 hibernate의 Physical Naming Strategy로 변경하면 된다.
hibernate의 PhysicalNamingStrategyStandardImpl 전략은 설정한 변수 이름을 그대로 사용하여
@Table에서 지정한 설정대로 그대로 사용할 수 있다.
application.properties에 아래 설정을 추가하여 해결했다.
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# Server port
server.port=8787
# View Resolver
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
# Datasource Setup
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/multi?characterEncoding=UTF-8&serverTimezone=Asia/Seoul
spring.datasource.username=root
spring.datasource.password=
# Swagger "Failed to start bean 'documentationPluginsBootstrapper'" fix
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
spring.mvc.static-path-pattern=/resources/**
# 세션 만료 시간 설정 (단위: 초)
server.servlet.session.timeout=3600
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.naming.physical-strategy = org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Interceptor 추가
1. LoginInterceptor Class
package com.gld.model.interceptor;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoginInterceptor implements HandlerInterceptor{
//Controller 실행 요청 전에 수행되는 메소드
//return false일 경우 controller 실행 x
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
if(request.getSession().getAttribute("user")==null) {
response.sendRedirect(request.getContextPath() + "/login/login");
return false;
}
return true;
} //${pageContext.request.contextPath}
//view단으로 forward 되기전에 수행
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
//view까지 처리 끝난 후 수행
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){
}
}
2. 인터셉터 등록
package com.gld.model.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 로그인 체크를 할 URL 패턴
.excludePathPatterns("/login/**","/css/**", "/js/**", "/images/**","/","/resources/**","/index/main"); // 로그인 체크를 제외할 URL 패턴
}
}
혼자 처음 구현한 기능이다 뿌듯해 🥹
'Spring' 카테고리의 다른 글
[Spring Security] 비밀번호 암호화 (0) | 2023.06.12 |
---|---|
[Spring + JPA] No Property Found for Type Exception 에러 해결 (2) | 2023.06.03 |
[Spring + Jpa] 테이블 Join & 문제해결 (0) | 2023.05.15 |