관심사 분리 MemberApp 변경전 public class MemberApp { public static void main(String[] args) { MemberService memberService = new MemberServiceImpl(); Member member = new Member(1L, "memberA", Grade.VIP); memberService.join(member); Member findMember = memberService.findMember(1L); System.out.println("findMember = " + member.getName()); System.out.println("findMember = " + findMember.getName()); } } 변경코드..
Springboot
비지니스 요구사항과 설계 회원 도메인 협력 관계 : 기획자들도 볼 수 있다. 회원클래스다이어그램 (정적): 회원 도메인 협력 관계를 분석해서 만든것 회원 클래스 다이어그램은 서버를 실행하지 않고 클래스들만 분석해서 볼 수 있는 그림 db 구현체를 넣을지 외부 구현체를 넣을지 결정하는건 동적으로 결정하기 때문에 클래스다이어그램으로 판단하기 어려움 그래서 객체 다이어그램(동적)을 만든다 빌드하면 main에 대한 코드만 나가고 test 코드는 빌드될때 빠진다. 회원 도메인 실행과 테스트 순수 자바 코드로 테스트하기 public class MemberApp { public static void main(String[] args) { MemberService memberService = new MemberServ..
좋은 객체지향 설계의 5가지 원칙(SOLID) SRP 단일 책임 원칙 한 클래스는 하나의 책임만 가져야한다 중요한건 변경이다. 변경이 있을때 파급효과가 적으면 단일 책임 원칙을 잘 따른것 OCP 개방-폐쇄 원칙 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야한다 => 다형성 활용 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현 아래는 멤버서비스에서 메모리멤버리포지토리를 Jdbc 멤버리포지토리로 갈아끼우려고 하는 상황이다. 두번째 코드를 보면 다형성만 사용하면 OCP 원칙을 지킬 수 없다. 구현 객체를 변경하려면 클라이언트 코드를 변경해야하는 문제가 생긴다. LSP 리스코프 치환 원칙 차를 만든다고 했을때 인터페이스에서 엑셀 기능을 속도를 올리는 것으로 규정을 했다면 구현..
AOP가 필요한 상황 모든 메소드의 호출 시간을 측정하고 싶다고 해서 메소드에 다 추가해버리면 다음과 같은 문제 생긴다. 1.핵심 관심사항이 아니다 2.공통 관심사항이다. 3.시간 측정 로직과 비지니스 로직이 섞여 유지보수가 어렵다. 4.시간을 측정하는 로직을 별도의 공통 로직으로 만들기 어렵다. 해결 방법 : AOP 적용하기 공통 관심 사항과 핵심 관심사항을 분리하고 원하는 곳에 공통 관심사항을 적용하면 된다. 기존 의존 관계 가짜 멤버 서비스를 만들어서 시간 측정을 하고 joinPoint.proceed()를 통해서 실제 멤버 서비스를 실행한다. AOP 적용 후 전체 그림은 이렇게 된다. 실제로 Proxy가 주입되는지 콘솔에 출력해보면 아래처럼 가짜 멤버서비스가 만들어짐을 알 수 있다. AOP를 스프링..
H2 데이터베이스 설치 sql문 generated by default as identity null 값이 들어오면 자동으로 id 세팅해줌 팁:sql ddl을 sql 파일을 만들어 관리한다. 순수 JDBC 자바가 DB랑 붙으려면 JDBC가 꼭 있어야한다 이번 강의에서는 과거에 사용하던 방식으로 구현을 했다. JdbcMemberRepository public class JdbcMemberRepository implements MemberRepository { private final DataSource dataSource; public JdbcMemberRepository(DataSource dataSource) { this.dataSource = dataSource; } 스프링부트가 데이터소스(접속정보)를..
회원 웹 기능 - 홈 화면 추가 컨트롤러가 정적페이지보다 우선순위가 높다. @Controller public class HomeController { @GetMapping("/") public String home(){ return "home"; } } 처음에 만들었던 웰컴 페이지(index.html)는 컨트롤러 생성 후에는 무시된다. 아래 이미지를 보면 첫 번째로 관련 컨트롤러를 찾는데 관련 컨트롤러가 맵핑된게 있으니까 발견하고 종료된다. Url에 직접 치는 방식: get 방식 데이터를 홈같은 곳에 넣어서 전달할때 : post 방식 MemberController @GetMapping("/members") public String list(Model model){ List members = memberS..
컴퍼넌트 스캔과 자동 의존관계 설정 멤버컨트롤러가 멤버 서비스를 통해서 회원가입하고 데이터를 조회할 수 있어야함 =>의존관계 (멤버컨트롤러가 멤버서비스를 의존한다) @Controller public class MemberController { } 스프링컨테이너가 컨트롤러 애노테이션이 있으면 객체를 생성해서 스프링에 넣고 관리함 그래서 컨트롤러 기능이 동작할 수 있다 @Controller public class MemberController { private final MemberService memberService = new MemberService(); } private final MemberService memberService = new MemberService(); 이 코드의 문제:다른 컨트롤러..
회원 도메인과 리포지토리 만들기 MemoryMemberRepository @Override public Optional findById(Long id) { return Optional.ofNullable(store.get(id));//null 반환될 수 있으면 Optional로 감싸서 반환 } return값으로 null이 반환될 수 있어서 반환 타입을 Optional로 감싸서 반환한다. 회원 리포지토리 테스트 케이스 작성 MemoryMemberRepositoryTest @Test public void save() { Member member = new Member(); member.setName("spring"); repository.save(member); Member result = repositor..
정적 컨텐츠, MVC와 템플릿 엔진, API가 있는데 템플릿 엔진과 API만 기억하면 된다. 이 둘은 html로 내리냐, 데이터로 내리냐의 차이다. 1.정적 컨텐츠 @GetMapping("hello") public String hello(Model model){ model.addAttribute("data","hello!!"); return "hello"; //얘한테 가서 렌더링해라 } 정적 컨텐츠 입니다. 그냥 파일을 그대로 내보내는 것 hello-static 컨트롤러를 먼저 찾아본다. 즉 컨트롤러가 우선순위를 가진다. 없으니까 hello-static.html을 찾아서 웹브라우저로 보냄 2.MVC와 템플릿 엔진 @GetMapping("hello-mvc") public String helloMvc(@Re..
알림을 위해 초기 기준 날짜를 설정해야했는데 설정하지 않아서 비교가 되지 않아 알림이 울리지 않았다. 아래의 코드처럼 String을 LocalDate로 변환해서 넣었다. 출처 /* String을 LocalDate로 만들기 */ LocalDate dateParse = LocalDate.parse("2020-01-26"); 실제 바꾼 코드 초기 기준 날짜를 아예 과거로 잡아서 현재 날짜와 비교해서 현재 날짜로 업데이트 되도록 만들었다. public class ReviewNotifyEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "reviewnotify_id") private Long notifyId; @Column..