package com.example.springintroduction.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig {
// 빈 등록 , 비밀번호 암호화
@Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
@configuration = @Been을 등록할 때 사용하는 어노테이션 (설정파일의 느낌이 난다.)
@Bean = 스프링에 의하여 생성되고 관리되는 자바 객체
package com.example.springintroduction.controller;
import com.example.springintroduction.member.Member;
import com.example.springintroduction.member.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.net.URI;
import java.net.URISyntaxException;
@Controller
@RequiredArgsConstructor
public class LoginController {
private final MemberService memberService;
@GetMapping("/signin")
public String signInPage(Model model){
Member member = new Member();
model.addAttribute("member",member);
return "signin";
}
@PostMapping("/signin")
public ResponseEntity signIn(@ModelAttribute Member member, HttpServletRequest request) throws URISyntaxException {
// 비밀번호 검사
memberService.validate(member);
// 세션 생성
HttpSession session = request.getSession();
session.setAttribute("sessionUsername",member.getUsername());
return ResponseEntity.status(HttpStatus.FOUND).location(new URI("/")).build();
}
@GetMapping("/signup")
public String signUpPage(Model model){
model.addAttribute(new Member()); // member
return "signup";
}
@PostMapping("signup")
public String signUp(@ModelAttribute @Valid Member member, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "signup";
}
memberService.save(member);
return "redirect:/#signup=ok"; //# 은 없어도 되나 보기 편하기위해 해놓은거
}
@PostMapping("/signout")
public String signOut(HttpServletRequest request){
request.getSession().invalidate();
return "redirect:/";
}
}
@RequiredArgsConstructor = 어떠한 빈에 생성자가 오직 하나만 있고, 생성자의 파라미터 타입이 빈으로 등록 가능한 존재라면 이 빈은 @Autowired 어노테이션 없이도 의존성 주입을 가능하게 해준다.
package com.example.springintroduction.controller;
import com.example.springintroduction.member.Member;
import com.example.springintroduction.member.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Queue;
@Controller
@RequiredArgsConstructor
public class MainController {
private final MemberService memberService;
@GetMapping("/")
public String mainPage(Model model, @RequestParam(required = false) String query){
if(query == null){
List<Member> members = memberService.findAll();
model.addAttribute("members",members);
return "home";
}
List<Member> members = memberService.findByUsername(query);
model.addAttribute("members",members);
return "home";
}
// 더미 데이터 생성
@PostConstruct
public void createdDummyDate(){
memberService.save(new Member("상남자","1234"));
memberService.save(new Member("하남자","1234"));
}
@GetMapping("/formembers")
public String forMembers(HttpServletRequest request){
// 파라미터 false로 하면, 기존 세션이 유효할 경우만 해당 세션을 가져옴
HttpSession session = request.getSession(false);
if( session == null || session.getAttribute("sessionUsername") == null){
// 미인증 사용자 홈 화면으로 강제 이동
return "redirect:/";
}
return "formembers";
}
}
@PostConstruct = 종속성 주입이 완료된 후 실행되어야 하는 메서드에 사용된다. 이 어노테이션은 다른 리소스에서 호출되지 않아도 수행된다.
package com.example.springintroduction.member;
import lombok.*;
import org.hibernate.validator.constraints.Length;
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class Member {
@Length(min = 2, max = 8, message = "2~8자 사이로 하세요")
private String username;
@Length(min = 2, max = 8, message = "2~8자 사이로 하세요")
private String password;
}
@Data가 아닌 @Setter, @Getter 을 사용하는 이유 = @Data를 사용하면 @Getter, @Setter , @ToString, @EqualsAndHashCode, @RequiredArgsConstructor 를 사용하는 거와 같다. 그러면 필요없는 어노테이션을 무분별하게 사용하게 되어 stackoverflow가 발생할 수 있다. 상황에 맞게 사용하는 게 중요하다.
package com.example.springintroduction.member;
import org.springframework.stereotype.Repository;
import java.util.*;
@Repository
public class MemberRepository {
// DB
public static Map<String,Member> memberMap = new HashMap<>();
// Member 저장
public void save(Member member){
memberMap.put(member.getUsername(),member);
}
// 멤버 모두 조회
public List<Member> findAll(){
Collection<Member> values = memberMap.values();
return new ArrayList<>(values);
}
//이름으로 찾기
public List<Member> findByUsername(String username){
return List.of(memberMap.get(username));
}
}
@Repository = 해당 클래스를 루트 컨테이너에 빈 객체를 생성해주는 어노테이션
package com.example.springintroduction.member;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MemberService {
private final MemberRepository memberRepository;
private final PasswordEncoder passwordEncoder;
public void save(Member member){
String encodedPassword = passwordEncoder.encode(member.getPassword());
member.setPassword(encodedPassword);
memberRepository.save(member);
}
//전체 조회
public List<Member> findAll(){
return memberRepository.findAll();
}
// 이름으로 단건 조회
public List<Member> findByUsername(String username){
return memberRepository.findByUsername(username);
}
// 로그인 시도한 회원정보 검증
public void validate(Member member){
Member foundMember =MemberRepository.memberMap.get(member.getUsername());
// 사용자가 입력한 비밀번호가 암호화된 DB상 비밀번호와 일치하는지 검사
if(!passwordEncoder.matches(member.getPassword(),foundMember.getPassword())){
throw new IllegalArgumentException("비밀번호 틀림");
}
}
}
@Service = 해당 클래스를 루트 컨테이너에 빈 객체를 생성해주는 어노테이션