Spring Projcect/[갠플] Online-mall

[4일차] 오류 해결, 로그인 히스토리

계란💕 2022. 9. 24. 11:51

 

 

확인 사항

  • JPA repository를 상속하는 MemberRepo에서 Member의 필드명과 다른 다르게 구성된 메서드가 있으면 
    • 멤버와 관련한 모든 클래스에 대해 "BeanCreatrion"가 발생한다.
    • 똑같은 오류가 여러 번 발생했다.. 주의하기!.

 


  • 오류 - 순환 참조
  • 원인: Impl 클래스와 securityConfig 간에 순환하는 문제가 발생
<hide/>

The dependencies of some of the beans in the application context form a cycle:

┌─────┐
|  securityConfiguration defined in file [C:\Users\Ran\Desktop\R\zerobase\remote_mall\build\classes\java\main\com\example\mall\configuration\SecurityConfiguration.class]
↑     ↓
|  memberServiceImpl defined in file [C:\Users\Ran\Desktop\R\zerobase\remote_mall\build\classes\java\main\com\example\mall\service\MemberServiceImpl.class]
└─────┘


Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
  • 해결: SecurityConfig 클래스에서 선언한 멤버변수 MemberService를 지운다.

 

 

1. 로그인 History

  • LoginHistory
<hide/>
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@Data   // getter, setter
@Entity
public class LoginHistory {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String userId;
    private LocalDateTime lastLoginTime;
    private String clientIp;
    private String userAgent;
}
  • MemberServiceImpl
    • 로그인 히스토리에 로그인한 계정의 ip와 접속한 기기 정보도 넣을 수 있다. 
    • RequestUtils를 이용한다.
<hide/>
@Override
public boolean authenticate(MemberInput parameter){
    // user의 비번은 인코딩된 상태이다.member의 비번은 암호화되지 않은 상태
    Member user = this.memberRepository.findByUserId(parameter.getUserId())
        .orElseThrow(() -> new RuntimeException("존재하지 않는 ID 입니다."));

    // 비번 확인
    if(!this.passwordEncoder.matches(parameter.getPassword(), user.getPassword())){
        throw new RuntimeException("비밀 번호가 일치하지 않습니다.");

    }
    return true;
}

 

  • controller
    • RequestUtils를 이용하기 위해서는 매개변수로 HttpServlet을 넣어야한다.
    • 따라서 컨트롤러에 넣어줘야한다.
<hide/>
@PostMapping("/member/login")
public String loginSubmit(HttpServletRequest request,
                          Model model,
                          MemberInput memberInput){
    boolean errorMessage = false;
    if(memberService.login(memberInput, request) == null){
        model.addAttribute("errorMassage", errorMessage);
        return "member/login";
    }

    // 로그인 성공
    errorMessage = true;
    model.addAttribute("errorMassage", errorMessage);
    return "index";
}
  • HTML
<hide/>
<!DOCTYPE html>
<html lang="ko"  xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>회원 로그인</title>
</head>
<body>
<h1>회원 로그인</h1>

<div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>
<div th:text="${errorMessage}">
<!-- UserAuthenticationFailureHandler 에서 넘겨 받은 변수-->
</div>

<div class="login">
  <form method="post">

    <table>
      <tbody>
        <tr>
          <th>ID</th>
          <td><input type="email" name="userId" placeholder="아이디(이메일)을 입력해주세요"/></td>
        </tr>
        <tr>
          <th>Password</th>
          <td><input type="password" name="password" placeholder="비밀번호 입력"/></td>
        </tr>

      </tbody>
    </table>
    <p/>
    <div>
      <button type="submit" >로그인</button>
    </div>
     <a href="/member/find-password">비밀번호 찾기</a>
    <div>
    </div>
  </form>
</div>
</body>
</html>

 

  Note) 실행 결과

  • 로그인 성공 화면

 

member

 

 

  • 로그인 실패 화면
    • "로그인에 실패했습니다."라는 errorMessage는 UserAuthenticationFailureHandler에서 html 로 보내는 것이다.
    • request.setAttribute("errorMessage", msg);

 


  • 오류: 로그인 하고 나면 index 페이지로 가야하는데 사진처럼 내용만 index로 가고 url은 멤버 로그인으로 간다.

 

  • 원인 
  • 해결

  • 오류:
<hide/>

Parameter 0 of constructor in com.example.mall.component.MailComponents required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found.


Action:

Consider defining a bean of type 'org.springframework.mail.javamail.JavaMailSender' in your configuration.
  • 원인
  • 해결

  Ex) 로그아웃

  • SecurityConfig
    • 로그아웃 누른 다음에 인덱스 페이지로 이동하도록 설정한다.
<hide/>
http.logout()
        .logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
        .logoutSuccessUrl("/")          // 로그아웃 성공하면 메인페이지 이동
        .invalidateHttpSession(true);   // 로그아웃했으니 새션 초기화

  Note) 실행 결과

 

 

======================== 오류 ======================== 

<hide/>
Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 25; timeout -1;
  nested exception is:
	java.net.ConnectException: Connection refused: connect. Failed messages: com.sun.mail.util.MailConnectException: Couldn't connect to host, port: localhost, 25; timeout -1;
  nested exception is:
	java.net.ConnectException: Connection refused: connect
  • 오류: MailConnectionException
  • 원인: SpringBoot와 메일 보내기를 같이 띄우면 시간이 초과되서 오류가 났다.
  • 해결: 따라서, 스프링 부트를 띄우는 메인 함수에 메일 보내는 코드를 넣지 말고 다른 클래스에 넣는다.

 

  • 오류: 잘못된 매인함수
<hide/>
@SpringBootApplication
public class MallApplication {
    public static void main(String[] args) {
        SpringApplication.run(MallApplication.class, args);
        try {
            Thread.sleep(3000L);

        }catch (Exception e){
            e.printStackTrace();
        }
        MailComponents mailComponents = new MailComponents(new JavaMailSenderImpl());
//        mailComponents.sendMainTest();
        mailComponents.sendMail("받는 사람@naver.com", "제목", "네용");
    }
}

 

  • Impl 클래스의 register()에 메일 보내는 코드 추가
<hide/>
// 메일 보내기
    String email = parameter.getUserId();
    String subject = "Online mall 가입을 축하드립니다.";
    String text = "<p>Online mall 가입을 축하드립니다.</p>" +
        "<p>아래 링크를 클릭하셔서 가입을 완료하세요.</p>" +
        "<div><a target='_blank' href='http://localhost:8080/member/email-auth?id=" +
        uuid +
        "'>가입 완료</a></div>";
    mailComponents.sendMail(email, subject, text);

    return true;
}

  Note) 실행 결과

 

 

2. 이메일 인증 구현하기

  • Impl - register()  가입한 회원에게 이메일 보내기 
  • 위의 링크를 누르면 회원 상태가 활성화되도록 구현한다.