스프링/4. 스프링 MVC-2 87

47. 쿠키의 보안문제

쿠키... 그냥 웹브라우저에서 값을 직접 바꾸거나 아니면 포스트맨으로 서버로 쿠키를 보낼 수 있다. 그리고 클라이언트 PC에 뭔갈 저장한다는 것도 문제의 요지가 있고, 이 쿠키는 계속 서버로 전송되는 데이터이다. 중간에 누가 가로챌 수 있다.(그래서 https를 써야 한다.) 그래서 쿠키에 중요한 값을 넣어놓으면 안되고, 무언가 대안이 필요하다..

46. 쿠키를 이용한 로그인 구현.

쿠키에 대해선 잘 모르겠다면 https://qwefdg3.tistory.com/204 여기를 참고하도록 하자. 여튼 논리자체는, 쿠키는 영속성 쿠키, 세션 쿠키 이렇게 두가지 종류가 있는데, 영속성 쿠키는 우리가 날짜 (expire 될 날짜) 를 정해주는 것으로, 웹브라우저를 꺼도 쿠키가 지정한 시간만큼 유지가 된다. 세션쿠키는 웹브라우저를 종료하면 그냥 사라진다. 그러므로, 로그인에는 세션쿠키가 더 알맞다. @Slf4j @Controller @RequiredArgsConstructor public class LoginContoller { private final LoginService loginService; @GetMapping("/login") public String loginForm(@Model..

45. 로그인 구현

@Service @RequiredArgsConstructor public class LoginService { private final MemberRepository memberRepository; public Member login(String loginId, String password){ return memberRepository.findByLoginId(loginId) .filter( m -> m.getPassword().equals(password)) .orElse(null); } } 도메인을 먼저 만들었다. 먼저 만든 findByLogin해서 나온 걸 확인하는 거다. 저거 정의할 때 return을 Optional로 하게 해서, Optional 함수 filter를 쓸 수 있다. filter()는..

44. 멤버 회원가입 구현

간단하게 @Data public class Member { private Long id; @NotEmpty private String loginId; @NotEmpty private String name; @NotEmpty private String password; } 검증 애노테이션 추가해 주고. @Slf4j @Repository public class MemberRepository { private static Map store = new HashMap(); private static long sequence = 0L; public Member save(Member member){ member.setId(++sequence); store.put(member.getId(), member); retur..

43. 도메인과 표현 분리

도메인은 핵심 비즈니스 로직이다. 웹은 그걸 표현하기 위한 것이다. 웹은 도메인을 참조해도 되지만, 도메인은 웹을 참조해선 안된다. 언제나 설계의 의존관계는 단방향으로 설계하는 것이 좋다. 예를 들어 web으로 하다가 이제는 템플릿을 이용한 web이 아닌 rest API를 통해 데이터를 주고 받고 싶다면, 만약 도메인이 web을 참조하고 있다면 restAPI를 사용하는데도 web을 거처야 한다. 이러면 안된다. 그렇기 때문에 itemRepository의 save도 web에서만 쓰는 form이 아니라 item으로 바꿔서 하는 것이다. 도메인은 좀.. 무결해야 한다. base적이여야 한다.

42. Http 메시지(Rest API) 검증

@Slf4j @RestController @RequestMapping("/validation/api/items") public class ValidationItemApiController { @PostMapping("/add") public Object addItem(@RequestBody @Validated ItemSaveForm form, BindingResult bindingResult){ log.info("API 컨트롤러 호출"); if(bindingResult.hasErrors()){ log.info("검증 오류 발생 errors = {}", bindingResult); return bindingResult.getAllErrors(); } log.info("성공 로직 실행"); return fo..

41. Form 전송객체 분리

사실 대부분의 경우가 (예를 들어 회원가입 시) 우리가 만든 User 객체등과 맞지 않다. 예를 들어 회원가입 시에는 기본 User에 대한 정보 뿐 아니라 수많은 약관등의 정보를 가지고 온다. 그래서 컨트롤러에서 User로 받기 보다는 따로 Form전용 객체를 만들고, 거기서 User를 만들어 필요에 맞게 쓴다. groups 기능은 실무에서 잘 사용하지 않는다. 보통 등록과 수정은 다른 객체로 만든다. 그래서 검증도 중복이 되질 않는다. @Data public class ItemSaveForm { @NotBlank private String itemName; @NotNull @Range(min=1000,max=100000) private Integer price; @NotNull @Max(value = ..

40. 컨트롤러 간 검증이 다른 경우.

우리는 앞서 public class Item { private Long id; @NotBlank private String itemName; @NotNull @Range(min=1000,max=100000) private Integer price; @NotNull @Max(9999) private Integer quantity; public Item() { } public Item(String itemName, Integer price, Integer quantity) { this.itemName = itemName; this.price = price; this.quantity = quantity; } } 이렇게 애노테이션으로 검증을 손쉽게 적용 했다. 하지만 문제의 요지가 있을 수 있는 점은, id는 ..

39. 빈 검증 오브젝트 에러

@ScriptAssert(lang="javascript", script = "_this.price * _this.quantity >= 10000", message = "총 합이 10000원 이상이어야 합니다.") public class Item { private Long id; @NotBlank(message="공백X") private String itemName; @NotNull @Range(min=1000,max=100000) private Integer price; @NotNull @Max(9999) private Integer quantity; public Item() { } public Item(String itemName, Integer price, Integer quantity) { this..

38. 빈 검증기 오류메시지 바꾸기

검증 실패시 콘솔에서도 나오는데, Field error in object 'item' on field 'quantity': rejected value [null]; codes [NotNull.item.quantity,NotNull.quantity,NotNull.java.lang.Integer,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [item.quantity,quantity]; arguments []; default message [quantity]]; default message [널이어서는 안됩니다] 뭐 길지만, NotNull.item.quantity 애노테이션이름.객체.필..