package repository; import hello.hellospring.domain.Member; import hello.hellospring.repository.MemoryMemberRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.*; class MemoryMemberRepositoryTest { MemoryMemberRepository repository = new MemoryMemberRepository(); @AfterEach public void afterEach() { repository.clearStore(); } @Test public void save() { //given Member member = new Member(); member.setName("spring"); //when repository.save(member); //then Member result = repository.findById(member.getId()).get(); assertThat(result).isEqualTo(member); } @Test public void findByName() { //given Member member1 = new Member(); member1.setName("spring1"); repository.save(member1); Member member2 = new Member(); member2.setName("spring2"); repository.save(member2); //when Member result = repository.findByName("spring1").get(); assertThat(result).isEqualTo(member1); //then } @Test public void findAll() { //given Member member1 = new Member(); member1.setName("spring1"); repository.save(member1); Member member2 = new Member(); member2.setName("spring2"); repository.save(member2); //when List<Member> result = repository.findAll(); //then assertThat(result.size()).isEqualTo(2); } } package hello.hellospring.repository; import hello.hellospring.domain.Member; import java.util.List; import java.util.Optional; public interface MemberRepository { Member save(Member member); Optional<Member> findById(Long id); Optional<Member> findByName(String name); List<Member> findAll(); } package hello.hellospring.repository; import hello.hellospring.domain.Member; import java.util.*; public class MemoryMemberRepository implements MemberRepository { private static Map<Long, Member> store = new HashMap<>(); private static long sequence = 0L; @Override public Member save(Member member) { member.setId(++sequence); store.put(member.getId(), member); return member; } @Override public Optional<Member> findById(Long id) { return Optional.ofNullable(store.get(id)); } @Override public List<Member> findAll() { return new ArrayList<>(store.values()); } @Override public Optional<Member> findByName(String name) { return store.values().stream() .filter(member -> member.getName().equals(name)) .findAny(); } public void clearStore() { store.clear(); } } 이렇게 오류가 발생하는데 이유가 뭘까요? 아래와 같이 코드를 수정해보기도 하였습니다만, findAll 과 같이 노란색이 될뿐 초록색 마크가 나오지는 않습니다. @Test public void findByName() { // given Member member1 = new Member(); member1.setName("spring1"); repository.save(member1); Member member2 = new Member(); member2.setName("spring2"); repository.save(member2); // when Optional<Member> result = repository.findByName("spring1"); // then assertThat(result.isPresent()).isTrue(); assertThat(result.get()).isEqualTo(member1); }
ItemService에서는 ItemRepository의 기능을 위임받아 저장 및 검색 기능을 구현했는데 OrderService에서는 검색기능을 구현하지 않았더라구요. ItemService에서 위임 받는 것 처럼 하면 간단할 것 같은데 굳이 만들지 않고 OrderRepository의 findOne기능을 사용하는 이유가 따로 있는 것일까요?
질문 내용] 여기에 질문 내용을 남겨주세요. 일단 두 사진 보시면, 예외 처리를 해주면 예외 처리가 try 내부 코드가 예외를 안던지니까 catch 빼라고 하고, 예외 처리를 안해주면, IOException이 예외처리가 안됐다고 하네요.. 뭐가 문제죠..? 람다를 사용했다고 해서 안될리가 없어보이는데 ㅠㅠ 추가로 out.write();가 Writer 추상 클래스의 write(); 메서드고 checked예외를 던지던데, try-catch로 안잡아줘도 되는 이유가 뭔가요??
안녕하세요! 선생님 강의를 재밌고 유익하게 수강하고 있는 학생입니다. 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 강의의 bean validation - HTTP 메시지 컨버터 부분을 수강하던 중 강의 내용과 제 결과 케이스의 다른 부분이 있어 다른 결과가 나오게 된 원인이 궁금하여 질문 드립니다! 강의와 결과가 달랐던 부분은 postman으로 실패 요청을 send했을 때의 응답 결과 입니다. 강의의 결과입니다. { "timestamp": "2021-04-20T00:00:00.000+00:00", "status": 400, "error": "Bad Request", "message": "", "path": "/validation/api/items/add" } 제가 실행한 결과입니다. { "timestamp": "2021-04-20T00:00:00.000+00:00", "status": 400, "error": "Bad Request", "path": "/validation/api/items/add" } 보이는 바와 같이, 제가 실행한 결과에서는 message에 대한 json 객체가 존재하지 않습니다. 혹시 스프링 부트의 버전과 관련된 부분에 있어서 차이가 있을까요? 현재 사용 중인 스프링 부트 버전은 2.7.11 버전입니다.
main/resources/application.yml 을 따라가게 되는 건가요 ? 자바에서는 디비를 사용하고 싶고, test에서만 메모리 DB를 사용하고 싶다면 아무런 내용이 없는 application.yml를 test/resources 아래 생성만 하면 되는 건가요 ?
로컬에서 파일 업로드를 구현할 때는 강의때 해준 방법 처럼 file.dir변수에 C:/test_img/ 이런식으로 변수를 지정하고 저장을 하였는데 이번에 cafe24를 사용해서 프로젝트를 배포하는 작업중인데 어떻게 경로를 설정해야할 지 모르겠어서 질문드립니다ㅠㅠ cafe24에 문의 해보았는데 server.xml 파일에서 해당 경로를 매핑 해줘야 한다고 하였습니다. <Context docBase ="서버의 업로드 폴더 경로" path=" localhost 뒤에 붙을 업로드 폴더의 경로" reloadable="true"/> https://yn971106.tistory.com/104?category=1016466 https://kang0312.tistory.com/95 https://tibang.tistory.com/entry/%EC%82%AC%EC%A7%84%EA%B0%99%EC%9D%80-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C%EC%8B%9C-%EA%B2%BD%EB%A1%9C-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95tomcat-%EA%B8%B0%EC%A4%80 아래 블로그를 참고하라고 하긴하던데 매핑하는 방법만 알려주고, 파일업 업로드하는 로직은 없고, 구글링을 해봐도 강사님께서 알려주신 파일 업로드 로직과는 다른 글들 뿐이여서 파일 업로드 로직을 다 뜯어 고쳐야 하는건가.... 고민입니다. 혹시 file.dir값만 딱 수정해서 서버에서 파일 업로드 할 수 있는 방법 아시면 알려주시면 감사하겠습니다.... 참고로 cafe24서버에 올린 폴더 경로입니다 upload폴더는 제가 생성한거고 권한도 777로 주었습니다. file.dir=/tomcat/webapps/upload/ 위와같이 경로 값을 주었는데 잘 작동하지 않습니다ㅠㅠ +추가 강사님이 알려주신 file.dir을 통해 파일 경로를 지정하는 방법은 spring boot에서 톰캣서버를 내장하고 있어서 가능한건가요?? cafe24에 배포할 때는 서버를 내장하지 않으므로 server.xml에 <Context docBase="D:\IMAGES" path="/IMAGES" reloadable="false"/> 이거를 추가해야하는 건가요?? 서버쪽 영역으로 가니까 아직 모르는게 많네요ㅠㅠㅠ
안녕하세요. 로그인 처리1 마지막 부분 세션 타임아웃 설정부분. pdf 41page가 안됩니다. application.properties 파일에서 server.servlet.session.timeout=10 이렇게 해보기도 하고 SessionInfoController에서 session.setMaxInactiveInterval(10); 이렇게 해보아도 타임아웃이 되지 않습니다. 제가 기대하는 것은 10초 뒤에는 세션아웃이 되어서 로그인이 필요한 페이지에 접근이 않되는 것인데요. 제가 잘못이해하거나 설정이 안된 부분이 있다면 알려주시면 감사하겠습니다. 제가 작성한 프로젝트는 여기에 올렸습니다. https://drive.google.com/file/d/1q1VbFHc21BpUgeTIjCvCd5WmXW-abwHm/view?usp=share_link
//==연관관계 메서드==// 가 주석으로 달린 메서드들이 연관관계에 있는 객체에 값을 넣어줄 때 반대편에도 자동으로 값을 넣어주는 역할을 하는 메서드가 맞나요? 이렇게 따로 메서드를 구현해주는 이유가 있나요? CASCADE 옵션을 사용하면 어차피 알아서 다 해주지 않나요 ?? 기본편에서 설명해주셨다고 했는데 어떤 강의를 다시 수강해보면 될까요 ? 지연로딩에서 ***ToMany의 디폴트는 Lazy고, ***ToOne의 디폴트는 Eager인 이유가 ***ToMany같은 경우 하나만 불러와도 기본적으로 수많은 값이 따라오기 때문에 스프링 측에서 Lazy로 해놓았고, (Member의 Order을 조회하면 수많은 Order이 자동으로 따라오기 때문에 디폴트가 Lazy) ***ToOne의 경우 객체 하나만 조회하면 쿼리문을 하나밖에 더 날리지 않기 때문에 Eager로 해놓았지만, 실무에서는 테이블 전체를 조회할 때가 있기 때문에 디폴트값인 Eager를 쓰지 않고 Lazy를 사용한다 이게 맞을까요? (Order하나만 조회하면 Member 1개만 따라오기때문에 디폴트가 Eager지만, select o from Order o 와 같은 쿼리문으로 Order를 전체 조회했을 때는 Order에 따른 멤버가 전부 따라오므로 그냥 Lazy 옵션을 준다) 이렇게 이해했는데 맞을까요?
기본편에서 관계에 따른 연관관계 설정하는 방법은 공부했는데, 위와 같은 기능 목록을 보고 기능목록을 보고 위와 같이 어떤 도메인을 써야 할지, 도메인끼리 1:N인지, N:N인지, 1:1인지 단방향인지, 양방향인지(실무에서는 N:N과 양방향은 지양하라고 하셨지만) 등 도메인 모델과 테이블 설계가 어렵다면 무엇을 참고하는 것이 좋을까요 ? ( 영한님이 분석해 놓은 회원 엔티티와 회원 테이블을 보고 코드를 작성할 순 있는데 스스로 회원 엔티티와 테이블을 분석하기가 너무 어렵습니다.) Category 클래스 안에서 스스로 일대다 관계를 맺고 있는데 이것은 무엇을 위해 만든건가요 ?
3:58초 경에 findMember.setAge(20)으로 결과가 바뀌면 영속성 컨텍스트에 관리가 되는 거고, 안바뀌면 관리가 되지 않는다라는데 이유가 뭔가요 ? JPA가 DB의 데이터에 접근하고 수정하고 작성,삭제 할 수 있다 = 영속성 컨텍스트가 관리한다 같은 말일까요 ?
두가지 궁금사항이 있습니다. 1.첫번째 @Aspect 애노테이션 을 사용한다면 의존성 추가해야된다고 인터넷에 나와있는데, 꼭 안해도 되는건가요??? implementation 'org.springframework.boot:spring-boot-starter-aop' 2.두번째 TimeTraceAop class에 @Component 애노테이션을 추가하면 에러가 안나는데, SpringConfig class에 @bean 으로 등록시 에러가 납니다. 콘피그에 빈으로 등록코드를 적을경우 또다른 코드를 주입해야되나요?
@GetMapping("/formatter/edit") public String formatterForm(Model model){ Form form = new Form(); form.setNumber(10000); form.setLocalDateTime(LocalDateTime.now()); log.info("form={}",form); model.addAttribute("form",form); return "formatter-form"; } @PostMapping("/formatter/edit") public String formatterEdit(@ModelAttribute Form form){ log.info("post form={}",form); return "formatter-view"; } 로그를 통해 form, post form을 출력해보았습니다. 저는 처음 form은 그냥 입력한 값이 나오고 그다음 post form은 ModelAttribute에 들어갈 때 public String formatterEdit(@ModelAttribute Form form){ 포멧터가 form의 타입을 변경하고 입력한다고 예상했습니다. 하지만 로그를 보니 form=FormatterController.Form(number=10000, localDateTime=2023-04-23T12:39:53.251212) post form=FormatterController.Form(number=10000, localDateTime=2023-04-23T12:39:53) 값은 값이 나오는 것을 확인했습니다. 제가 생각했을 때는 Argument Resolver 안에 ConversionService 안에 Formatter 가 controller를 호출하기 전 @ModelAttribute에 입력할 때 실행되지만 @Data static class Form{ @NumberFormat(pattern = "###,###") private Integer number; @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime localDateTime; } 에서 @NumberFormat(pattern = "###,###") 패턴이 적용 되는 시점은 html에서 "${{form.number}}" 중괄호2개가 있을 때다. 그래서 로그는 값은 같은 값이 출력이 되지만 html에서는 다른 값이 출력된다. 라고 이해를 했는 데 맞게 생각한 것인지 궁금합니다. 답변주시면 정말 감사하겠습니다.