🐢🐢꼬부기 LV.2 | 실습•에러/🛡️껍질에 숨기(에러해결)

스프링 부트 과제 에러 해결

서화 2026. 1. 19. 23:20

🐞Field memberService in com.example.demo.membercontroller🐞

에러문구를 읽어보면 멤버서비스 빈을 찾을수 없다는 내용이다

🔎원인분석

해당 에러는 멤버서비스가 로그인컨트롤러와 같은 패키지에 있지 않아서 발생한 오류다

멤버컨트롤러 위치                                                   멤버서비스 위치

멤버컨트롤러는 스프링 부트를 실행하기 위해 데모애플리케이션과 같은 패키지에 넣어 만들어 주었고 멤버서비스 같은 경우에는 기존에 수업들었던 자료였어서 패키지에 위치에 달랐다 스프링부트 컨테이너는 메인클래스의 하위만 확인하기 때문에 패키지가 다르다면 다른패키지는 아예 보지 않는다 따라서 빈도 등록되지 않는다

🛠️ 해결방법

DemoApplication.java에 @ComponentScan("com.example")이라는 어노테이션을 추가한다

이 어노테이션을 추가하면 컨테이너가 demo 패키지만 보는게 아니고 com.example의 이름을 가진 패키지 까지 보게된다

@SpringBootApplication
@ComponentScan("com.example")// demo만 보는게 아니고 com.example 까지 보게한다
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

따라서 콘솔에 에러 없이 잘 실행된 모습을 볼수 있다


🐞 type = Method Not Allowed,status=405🐞

인덱스페이지에서 로그인을 시도하다 만난 에러로 405(Method Not Allowed)에러는 URL은 잘 매핑 되있는데 요청한 HTTP메서드(GET/POST)가 그 매핑에서 허용되지 않는다는 에러다

🔎원인분석

로그인을 하기위한 폼태그에서 메소드를 포스트로 지정했는데 컨트롤러에서 어노테이션을 @GetMapping(/"main") 이렇게 설정해서 발생한 오류였다

index.jsp

<form action="login" method="post">

MemberController

@GetMapping("/main")
	public String LoginController(MemberDTO memberDTO, Model model,HttpSession session) {

🛠️해결방법

멤버 컨트롤러에서 어노테이션을 포스트 매핑으로 변경하고

  • 로그인 기능을 처리할 로직
  • 로그인확인해서 메인페이지로 이동후 게시글 띄우기 로직
  • 인덱스페이지 띄울 로직
  • 로그아웃 기능 처리할 로직 

이렇게 네가지로 쪼개서 각 기능별로 만들어주었다  로그인을 처리할때만 포스트매핑을 사용하고 나머지는 겟매핑을 사용하였다

@PostMapping("/login") //로그인 처리
	public String LoginController(MemberDTO memberDTO, Model model,HttpSession session) {
		//커맨드 객체 = DTO와 모델, 세션을 인자로받는다
		MemberDTO loginUser = memberService.getMember(memberDTO); //멤버서비스에 있는 멤버DAO데이터 가져오기
		
		//로그인 실패
		if(loginUser == null) {
			model.addAttribute("msg","아이디 또는 비밀번호 올바르지 않습니다");
			return "index"; // -> 로그인 실패하면 이페이지로 이동해줘 
			// /WEB-INF/views/ + index + .jsp //뷰 리졸버가 처리
		}
		//로그인 성공
		session.setAttribute("user",loginUser);//로그인 정보 세션에 저장
		System.out.println("[로그] 로그인 성공: " + loginUser.getMid());
		return "redirect:/main";// 사용자가 로그인 요청
	}
	@GetMapping("/main")//메인화면 조회
	public String mainPage(Model model,HttpSession session) { // 인자로 모델과 세션만 받음
		//세션에 유저정보가 없으면 인덱스로 보냄
		//사용자가 주소창에서 입력해서 들어오는것을 방지함
		//세션 유효시간 만료됬을때 로그인화면으로 안내
		if(session.getAttribute("user")==null){//로그인정보가 없다면
			return "redirect:/index";//로그인페이지로 이동 요청
		}
		//게시글 목록 가져오기
		model.addAttribute("datas",boardService.getBoardList(null));
		System.out.println("[로그] DB에서 가져온 데이터 개수: " + boardService.getBoardList(null).size());
		return "main"; // WEB-INF/views/ + main + .jsp //뷰리졸버가 처리함
	}

기능 실행후 가야할 페이지를 정하는데 스프링부트는 컨트롤러에서 반환값에 redirect:를 표시하지 않으면
DispatcherServlet이 ViewResolver를 통해 뷰를 해석하고 해당 JSP로 forward 방식으로 이동한다

따라서  단순 페이지 이동인지 요청인지에 따라 리다이렉트를 설정해주었다 리다이렉트가 없으면 단순 페이지 이동으로 뷰 리졸버에서 처리하고 리다이렉트가 있으면 디스패쳐 서블릿에서 처리한다


📌에러는 아니었지만 어려웠던 점

1. 로그인 컨테이너에서 메인페이지까지 한번에 처리하려고 했을때 

오늘 배운 커맨드 객체를 써보겟다고 적용했는데 멤버DTO를 세번이나 호출한것을 알게 되었을때 수정방향에 대해서 고민이 되었다

처음 작성했던 코드

@GetMapping("/main")//컨트롤러에서 반환한 메인 커맨드와 매핑
//로그인 처리 결과로 메인으로 갈지말지 결정

public String LoginController(MemberDTO memberDTO, Model model,HttpSession session) {
memberDTO = memberService.getMember(memberDTO); //멤버서비스에 있는 멤버DAO데이터 가져오기

//로그인 실패
if(memberService.getMember(memberDTO) == null) {
model.addAttribute("msg","아이디 또는 비밀번호 올바르지 않습니다");
return "index";
}

//로그인 성공
else if(memberService.getMember(memberDTO) != null) {
model.addAttribute("datas",boardService.getBoardList(null));
System.out.println("[로그] 로그인 성공");
}
return "main"; // /WEB-INF/views/ + main + .jsp
}

변경 후

로그인유저라는 변수를 하나 만들어서 한번만 호출하고 로그인 기능 작성시에는 만든 변수명 사용하는것으로 변경했다

@PostMapping("/login") //로그인 처리
	public String LoginController(MemberDTO memberDTO, Model model,HttpSession session) {
		//커맨드 객체 = DTO와 모델, 세션을 인자로받는다
		MemberDTO loginUser = memberService.getMember(memberDTO); //멤버서비스에 있는 멤버DAO데이터 가져오기
		
		//로그인 실패
		if(loginUser == null) {
			model.addAttribute("msg","아이디 또는 비밀번호 올바르지 않습니다");
			return "index"; // -> 로그인 실패하면 이페이지로 이동해줘 
			// /WEB-INF/views/ + index + .jsp //뷰 리졸버가 처리
		}
		//로그인 성공
		session.setAttribute("user",loginUser);//로그인 정보 세션에 저장
		System.out.println("[로그] 로그인 성공: " + loginUser.getMid());
		return "redirect:/main";// 사용자가 로그인 요청
	}

2. 가야할 페이지 지정하기

아 이거 헷갈린다고 생각 못했는데 직접 구현 해보니까 어떤걸 ds가 처리하고 vr이 처리해야하는지 헷갈렸다 위의 코드처럼 구조를 바꾸기전에 로그인 컨트롤러에서 한번에 처리하려고 하니까 너무 헷갈려서 처음에는 다 return main,return index만 적어놨다가 구조 바꾸면서 리다이렉트를 추가하기 시작했는데 왜 이게 리다이렉트를 사용하는거지? 같은 의문들이 있어서 찾아보면서 구조를 변경했다

3. 기능 분리후 메인페이지 로직 작성시 로그인 세션확인

if(session.getAttribute("user")==null){//로그인정보가 없다면
			return "redirect:/index";//로그인페이지로 이동요청
		}

처음에 메인페이지 에서는 게시판 글만 보이면 되는데 왜 로그인 정보를 확인하지? 싶어서 찾아봤는데 사용자가 로그인을 요청하지 않아도 주소창에서 주소를 입력해서 들어오는것을 방지하고 세션 유효시간이 만료되었을 때 로그인화면으로 안내하기 위한 보안적요소 때문이라는것을 이해했고 배웠다