묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Spring Boot JWT Tutorial
jjwt 버전을 올렸더니 jwt가 유효하지 않다고 합니다
강의 예제를 보면 springboot 3.2.0 버전이고 java도 17버전으로 기준하여 작성된 것 같습니다.제 jdk 환경도 17버전이고요. cmd 창에서 java -version으로 확인도 했습니다.내려받아 돌려보면 잘 작동합니다. 그런데 jjwt 0.11.5 버전이 아닌 jjwt 0.12.3 버전을 사용해보고 싶어서 코드를 일부 수정했습니다.또한 Bcrypt알고리즘이 이제는 더 이상 안전하지 않다는 얘길 들어서 Argon2 알고리즘을 사용해보고자 했습니다.dependency에 jjwt 0.12.3 버전으로 변경하였고Jwts 이하 메서드가 jjwt에서는 바뀌어서 key에 타입을 명시해주어야 했습니다.PostMan에서 JWT Bearer로 설정하고 encode체크를 하지 않은 채로(이미되어있으니) HS512알고리즘으로 Secret을 입력하고 localhost:8080/api/authenticate 로 요청을 보내봤습니다.{"username": "user","password", "user"}하지만 jjwt 0.11.5 버전일 때는 잘 오던 token 내용이 500error를 내면서 토큰이 유효하지 않다고 합니다;제 코드에서 잘못 한 점이 있을까요? P.S 스스로 gradle refresh, clean build 등을 한 후에 테스트해본 결과jjwt 0.12.3은 0.11.5와 vscode의 REST Client로 api 테스트 시에 강의와 동일한 결과를 보여주었습니다. 그러나 Argon2 알고리즘을 사용하여 생성한 비밀번호를 사용하면 엉뚱하게도 jwt토큰이 유효하지 않다며 401 에러가 났습니다. 강의대로 Bcrypt 알고리즘을 쓰면 없는 일입니다...다만 이런 오류를 내는 연관성을 모르겠습니다 ;; package com.gyull.jwt.jwt; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.crypto.argon2.Argon2PasswordEncoder; import org.springframework.security.crypto.keygen.BytesKeyGenerator; @ExtendWith(MockitoExtension.class) @SpringBootTest class JwtApplicationTests { private static final Logger logger = LoggerFactory.getLogger(JwtApplicationTests.class); @Mock private BytesKeyGenerator keyGeneratorMock; private Argon2PasswordEncoder encoder = Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8(); @Test void contextLoads() { } //argon2알고리즘으로 비밀번호를 생성하기 위해 테스트를 했습니다 //data.sql로 table에 insert하기 위함. @Test public void encodeWhenEqualPasswordWithCustomParamsThenMatches() { encoder = new Argon2PasswordEncoder(16, 32, 4, 65536, 3); String result = encoder.encode("admin"); logger.info("인코딩완료: "+result); assertTrue(encoder.matches("admin", result)); } } package com.gyull.jwt.jwt.security.config; import org.springframework.boot.autoconfigure.security.servlet.PathRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.argon2.Argon2PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.filter.CorsFilter; import com.gyull.jwt.jwt.security.filter.JwtFilter; import com.gyull.jwt.jwt.security.filter.JwtSecurityConfig; import com.gyull.jwt.jwt.security.handler.JwtAccessDeniedHandler; import com.gyull.jwt.jwt.security.handler.JwtAuthenticationEntryPoint; import com.gyull.jwt.jwt.security.provider.TokenProvider; import lombok.RequiredArgsConstructor; @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final TokenProvider tokenProvider; private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; private final JwtAccessDeniedHandler jwtAccessDeniedHandler; private final CorsFilter corsFilter; //Bcrypt 알고리즘은 예제 연습할 때는 쓰지만 연산속도가 발전한 지금은 //취약점이 있기 때문에 Argon2를 비롯한 대체 알고리즘을 더 권장하고 있다. @Bean public PasswordEncoder passwordEncoder(){ return new Argon2PasswordEncoder(16, 32, 4, 65536, 3); } //Spring Security 6.1.x 버전부터는 Lambda DSL의 사용으로 .and()와 같은 메서드가 불필요하다 //Spring Security 7을 염두로 두고 deprecated, removal 되는 메서드가 무척 많았다 @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf((csrf) -> csrf.disable()) // .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) .exceptionHandling((exceptionHandling) -> exceptionHandling .authenticationEntryPoint(jwtAuthenticationEntryPoint) .accessDeniedHandler(jwtAccessDeniedHandler) ) .headers(headers -> headers.frameOptions(frameOptions -> frameOptions.sameOrigin())) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests( authorize -> authorize .requestMatchers("/").permitAll() .requestMatchers("/api/hello", "/api/authenticate", "/api/signup").permitAll() .requestMatchers("/admin/**").permitAll() .requestMatchers("/favicon.ico").permitAll() .requestMatchers(PathRequest.toH2Console()).permitAll() .anyRequest().authenticated() ) //Spring Security 6.2.0 javadoc에서는 .apply()메서드가 deprecated되었으니 .with()을 대신 쓰라고 되어있다. //다른 github 예제들은 jwtSecurityConfig를 따로 작성하지 않고 //addFilterBefore을 사용하여 직접 추가해주고 있는데, jwtSecurityConfig 또한 내부적으로 addFilterBefore을 사용해서 httpSecurity에 추가해줄 수도 있다. .with(new JwtSecurityConfig(tokenProvider), customizer -> {}); return http.build(); } } implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.12.3' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.12.3' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.12.3' import javax.crypto.SecretKey; //나머진 동일하여 생략 public String createToken(Authentication authentication){ String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); long now = (new Date()).getTime(); Date validity = new Date(now + this.tokenValidityInMilliseconds); return Jwts.builder() .subject(authentication.getName()) .claim(AUTHORITIES_KEY, authorities) .signWith((SecretKey) key, Jwts.SIG.HS512) .expiration(validity) .compact(); } public Authentication getAuthentication(String token){ Claims claims = Jwts .parser() .verifyWith((SecretKey) key) .build() .parseSignedClaims(token) .getPayload(); Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); User principal = new User(claims.getSubject(), "", authorities); return new UsernamePasswordAuthenticationToken(principal, token, authorities); } public boolean validateToken(String token){ try { Jwts.parser().verifyWith((SecretKey) key).build().parseSignedClaims(token); return true; } catch(SecurityException | MalformedJwtException e){ logger.info("잘못된 JWT 서명입니다."); } catch(ExpiredJwtException e){ logger.info("만료된 JWT 토큰입니다."); } catch(UnsupportedJwtException e){ logger.info("지원되지 않는 JWT 토큰입니다."); } catch(IllegalArgumentException e){ logger.info("JWT 토큰이 잘못되었습니다."); } return false; }
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
SpingConfig가 궁금합니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.강의 중 SpingConfig 클래스의 작동방식이 궁금해서 질문 올립니다!@Autowired 아래 생성자에 매개변수에는 bean에 있는 객체이거나 @Service, @Repository 등의 아래의 인스턴스가 들어가는 것 아니었나요?SpringConfig 생성자의 매개변수에 MemberRepository를 구현한 JpaMemberRepository의 인스턴스가 들어가야하는 것으로 알고있습니다.어떠한 구조로 스프링 컨테이너가 JpaMemberRepository의 인스턴스를 넣어서 호출해주는 것인지 궁금합니다!!+찾아보던 중 스프링 데이터 JPA는 JpaRepository와 같은 인터페이스를 상속받은 인터페이스를 스캔하여 자동으로 빈으로 등록한다는 사실을 확인하였습니다
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Intellij IDEA가 아니라 Gradle을 사용하면 에러가 나와요
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 여기서 Build and run using과 Run tests using을 Intellij IDEA로 설정하면 아무런 에러가 나오지 않고 잘 작동이 되는데, Gradle을 사용하게 되면 에러가 납니다. 이런 에러가 나옵니다. Project Structure의 SDK는 17로 해두었고,스프링부트 버전은 3.2.1, java는 17입니다. 현재 Gradle 버전은 8.5입니다. 제공해주신 피피티에서는 스프링 부트 3.2부터 JDK 17과 꼭 Gradle을 선택하라고 하셔서 고민이 되어 질문 남깁니다. 그냥 Intellij IDEA를 사용하여 수업을 들어도 괜찮을까요? 에러는 어떻게 해야 해결이 될까요..? 검색해봐도 잘 나오지 않아 여쭤봅니다.
-
미해결스프링 부트 - 핵심 원리와 활용
[공유]허용되지 않는 메서드 (http://localhost:8080/hello-servlet)
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]프로그래밍 방식으로 서블릿 등록 후혹시 http://localhost:8080/hello-servlet 호출 할때 허용되지 않는 메서드 나오시는분들은 HelloServlet 에 super.service(req,resp); 호출 되고 있는지 확인 해보세요..!
-
해결됨Java 마이크로서비스(MSA) 프로젝트 실습
스케일업 개념 관련 질문드려요
안녕하세요! 강의 잘 보고있습니다.이번 강의에서 블루그린배포 개념을 설명해주시며 스케일 업에 대해 알려주셨는데요! 제가 공부했던 얕은 지식을 떠올려보면,스케일 업은 기존 서버의 사양 등을 업그레이드해 시스템을 확장 (수직적)스케일 아웃은 서버를 여러대 추가하여 시스템을 확장 - 로드밸런싱 동반 (수평적)라고 배웠던 것 같은데.. 아무튼, 질문의 요점은 블루 그린 배포는 여러 대의 서버가 있는 스케일 아웃 방식에서 무중단 배포가 가능한 배포 모델이 아니라, 스케일 업 방식인가요?? 감사합니다!
-
미해결Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA)
instance_id 설정이 적용되지 않고 있습니다.
안녕하세요 위 사진처럼 인스턴스의 ID가 아래의 yml파일로 설정한데로 적용되지 않고 있어 질문드렸습니다. 커서를 두었을 때 포트번호도 확인해서 해당 인스턴스인것도 확인하였습니다. 원인이나 해결방법을 알 수 있을까요 ㅠㅠ
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
Member 에러
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. MemeberRepository.java에서 Member save(Member member); 를 입력하면 Member에 에러가 뜹니다영한님도 강의 중에 에러가 뜨셨는데 빠르게 고치시더라구요뭘 고치셨는지 알려주시면 감사하겠습니다!! import class를 눌러봤는데 import java.lang.reflect.Member;가 위에 입력되면 에러가 해결되긴 하더라구요근데 강의와 코드가 다른데 괜찮나요?
-
미해결호돌맨의 요절복통 개발쇼 (SpringBoot, Vue.JS, AWS)
Permission targetId null
당연히 구글링 해보셨져? 원하는 결과를 못찾으셨나요? 어떤 검색어를 입력했는지 알려주세>> hasPermission targetId null문제가 발생한 코드(프로젝트)를 Github에 올리시고 링크를 알려주세요.https://github.com/IE-MangChi/RepositoryForAsk.git영상에선 그냥 넘어갔지만 targetId값이 null로 찍히는게 맞는지 잘모르겠습니다.강의내용대로면 저값이 매핑되어야하는데, 공식홈페이지보니 아닌거 같아서 질문드립니다!
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
localhost:8080/hello가 whitelabel error가 떠요
View 환경설정 강의 그대로 폴더를 만들었는데 localhost:8080/hello를 하면 화이트라벨 에러가 나오고, localhost:8080만 치면 강의에서 /hello 붙인 결과 페이지랑 똑같이 나오는데 어디가 문제인지 모르겠어요.ㅜㅜㅜㅜ
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
submit 버튼을 눌렀을때 어떤 api 가 불러와지는지 코드 어디에 쓰여있나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]저 submit 버튼을 눌렀을때 어떤 api를 호출하는지 html에 없는것 같아서요. <!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head th:replace="fragments/header :: header"/> <body> <div class="container"> <div th:replace="fragments/bodyHeader :: bodyHeader"/> <form th:object="${form}" method="post"> <!-- id --> <input type="hidden" th:field="*{id}"/> <div class="form-group"> <label th:for="name">상품명</label> <input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"/> </div> <div class="form-group"> <label th:for="price">가격</label> <input type="number" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요"/> </div> <div class="form-group"> <label th:for="stockQuantity">수량</label> <input type="number" th:field="*{stockQuantity}" class="form-control" placeholder="수량을 입력하세요"/> </div> <div class="form-group"> <label th:for="author">저자</label> <input type="text" th:field="*{author}" class="form-control" placeholder="저자를 입력하세요"/> </div> <div class="form-group"> <label th:for="isbn">ISBN</label> <input type="text" th:field="*{isbn}" class="form-control" placeholder="ISBN을 입력하세요"/> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> <div th:replace="fragments/footer :: footer"/> </div> <!-- /container --> </body> </html>설명해주시면 감사하겠습니다ㅜㅜ
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
devtools 오류
devtools가 적용이 안되어서 인터넷에 나와 있는 내용 다 긁어서 해봐도 안됩니다. ㅠㅠㅠ 어떻게 해야 하나요
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
섹션7 상품 수정이 페이지가 연결이 안됩니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]상품 수정시, 수정 버튼을 누르면 위와 같이 나옵니다. 프론트를 하나도 몰라서, 오류가 뭔지 모르겠어요 ㅜㅜ package jpabook.jpashop.controller; import jpabook.jpashop.domain.item.Item; import jpabook.jpashop.domain.item.Book; import jpabook.jpashop.service.ItemService; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.List; @Controller @RequiredArgsConstructor public class ItemController { private final ItemService itemService; @GetMapping("/items/new") public String createform(Model model) { model.addAttribute("form", new BookForm()); return "items/createItemForm"; } @PostMapping("/items/new") public String create(BookForm form) { Book book = new Book(); book.setName(form.getName()); book.setPrice(form.getPrice()); book.setStockQuantity(form.getStockQuantity()); book.setAuthor(form.getAuthor()); book.setIsbn(form.getIsbn()); itemService.saveItem(book); return "redirect:/"; } @GetMapping("/items") public String list(Model model) { List<Item> items = itemService.findItems(); model.addAttribute("items", items); return "items/itemList"; } @GetMapping("/items/{itemId}/edit") public String updateItemForm(@PathVariable("itemId") Long itemId, Model model) { Book item = (Book) itemService.findOne(itemId); BookForm form = new BookForm(); form.setId(item.getId()); form.setName(item.getName()); form.setPrice(item.getPrice()); form.setStockQuantity(item.getStockQuantity()); form.setAuthor(item.getAuthor()); form.setIsbn(item.getIsbn()); model.addAttribute("form", form); return "items/updateItemForm"; } @PostMapping("items/{itemId}/edit") public String updateItem(@PathVariable String itemId, @ModelAttribute("form") BookForm form) { Book book = new Book(); book.setId(form.getId()); book.setName(form.getName()); book.setPrice(form.getPrice()); book.setStockQuantity(form.getStockQuantity()); book.setAuthor(form.getAuthor()); book.setIsbn(form.getIsbn()); itemService.saveItem(book); return "redirect:/items"; } } <!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head th:replace="fragments/header :: header"/> <body> <div class="container"> <div th:replace="fragments/bodyHeader :: bodyHeader"/> <form th:object="${form}" method="post"> <!-- id --> <input type="hidden" th:field="*{id}"/> <div class="form-group"> <label th:for="name">상품명</label> <input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"/> </div> <div class="form-group"> <label th:for="price">가격</label> <input type="number" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요"/> </div> <div class="form-group"> <label th:for="stockQuantity">수량</label> <input type="number" th:field="*{stockQuantity}" class="form-control" placeholder="수량을 입력하세요"/> </div> <div class="form-group"> <label th:for="author">저자</label> <input type="text" th:field="*{author}" class="form-control" placeholder="저자를 입력하세요"/> </div> <div class="form-group"> <label th:for="isbn">ISBN</label> <input type="text" th:field="*{isbn}" class="form-control" placeholder="ISBN을 입력하세요"/> </div> <button type="submit" class="btn btn-primary">Submit</button> </form> <div th:replace="fragments/footer :: footer"/> </div> <!-- /container --> </body> </html> 코드 올려드립니다! 확인 요청드립니다 ㅜ
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
컨트롤러단 페이징 테스트
// 컨트롤러 코드 @GetMapping public ResponseEntity<?> postList(@PageableDefault(size = 10, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) { Page<Post> posts = postService.getPosts(pageable); return ResponseEntity.ok() .body(ApiResponse.of("success", "게시물 전체 조회 성공", posts)); } // 테스트 코드 @DisplayName("게시물 전체를 페이징해서 조회해 온다.") @Test void postList() throws Exception { //given String sortProperty = "id"; String direction = "desc"; int pageNo = 0; int pageSize = 10; Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.Direction.DESC, sortProperty); given(postService.getPosts(pageable)).willReturn(Page.empty()); //when ResultActions result = mvc.perform(get("/api/posts") .queryParam("page", String.valueOf(pageNo)) .queryParam("size", String.valueOf(pageSize)) .queryParam("sort", sortProperty + "," + direction)); //then result .andExpect(status().isOk()) .andExpect(jsonPath("$.status").value("success")) .andExpect(jsonPath("$.message").value("게시물 전체 조회 성공")) .andDo(print()); then(postService).should().getPosts(pageable); } 위 테스트 코드를 실행하면 httpstatus 200을 기대했지만 500이 떴다고 테스트 실패를 합니다.위 코드대로면 /api/posts?page=0&size=10&sort=id,desc이렇게 요청이 가는건데, 테스트코드 말고 포스트맨으로 직접 저렇게 요청 보내면 저는 정상적으로 응답이 옵니다 ㅠㅠ왜 저 테스트코드 실행하면 500에러가 나는걸까요..? 500 날만한 곳을 전혀 모르겠습니다 혼자 몇시간동안 끙끙앓다가 질문드립니다 ㅜㅜㅜ
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
예외처리가 된 건가요? 아님 에러인가요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요.package hello.hellospring.service; import hello.hellospring.domain.Member; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import java.util.Optional; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.*; class MemberServiceTest { MemberService memberService = new MemberService(); @Test void join() { //given Member member = new Member(); member.setName("hello"); //when Long saveId = memberService.join(member); //then Member findMember = memberService.findOne(saveId).get(); Assertions.assertThat(member.getName()).isEqualTo(findMember.getName()); } @Test public void 중복_회원_예외() { //given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); //when memberService.join(member1); try { memberService.join(member2); fail(); } catch (IllegalAccessError e) { //예외가 터져서 정상적으로 성공한 것 assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); } //then } @Test void findMembers() { } @Test void findOne() { } } java.lang.IllegalStateException: 이미 존재하는 회원입니다. at hello.hellospring.service.MemberService.lambda$validateDuplicateMember$0(MemberService.java:26) at java.base/java.util.Optional.ifPresent(Optional.java:178) at hello.hellospring.service.MemberService.validateDuplicateMember(MemberService.java:25) at hello.hellospring.service.MemberService.join(MemberService.java:18) at hello.hellospring.service.MemberServiceTest.중복_회원_예외(MemberServiceTest.java:45) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Process finished with exit code -1 이렇게 빨간 느낌표가 뜨면 테스트 자체가 잘못된다는 건가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
주문할 경우 null값으로 member에 행이 추가되는
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 주문할 경우 따로 오류는 발생하지 않는데 주문 목록을 보면 회원명이 보이지 않습니다. 또한 주문할때마다 member 테이블에 null값으로 행이 하나씩 추가가 됩니다. 오류가 따로 안떠서 어떻게 해결해야할지 몰라 질문드립니다. 구글 드라이브에 파일올립니다..https://drive.google.com/drive/folders/1faJLS1AmApbM9t_cW_olFKj3YLvaBfQg?usp=drive_link
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
포스트매핑은
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기서 print가 되는것은 제가 등록버튼을 눌렀을 때 되더라구요 postmapping은 등록하는 경우에 실행되게 해주는 것 맞나요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
타임리프 태그??
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]<html lang="en">로 해도 정상실행이 되는데 했을 때와 차이는 무엇인가요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
외래키 제약 조건
[질문 내용]강의 내용 중 "외래키를 꼭 사용해야할까?" 에 대한 물음에 두 가지 방안을 주셨는데요.빠른 처리가 중요하며 실시간 트래픽이 많은 시스템인 경우 -> "외래키를 사용하지 않는 쪽도 고려해볼만 함"돈이 왔다갔다 하는 등의 reliablity가 중요한 시스템인 경우 -> "외래키를 꼭 사용하라"그렇다면 질문이 있습니다.질문 1. 만약 외래키 제약조건이 관계형 DB에 이미 걸려있는 상태라면 Java 코드상에서는 아무런 설정 없이 비즈니스 로직을 개발해도 되나요?질문 2. 만약 외래키 제약조건이 관계형 DB에 걸려있지 않고 관계형 DB의 성능상의 이슈로 외래키 제약 조건을 애플리케이션에서 해결해야 한다면 해당 로직 또한 개발해야 하나요? 즉, JPA가 외래키 제약 조건을 체크해주는 기능이 있는지 궁금합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
컨트롤러 테스트 (예외처리 테스트)
// 컨트롤러 코드 @PostMapping public ResponseEntity<?> postAdd(@RequestBody @Valid PostCreateRequest postCreateRequest, BindingResult bindingResult) { if (bindingResult.hasErrors()) { Map<String, String> errorMap = new HashMap<>(); for (FieldError error: bindingResult.getFieldErrors()) { errorMap.put(error.getField(), error.getDefaultMessage()); } throw new ValidationException("유효성 검사 오류", errorMap); } postService.addPost(postCreateRequest.toEntity()); return ResponseEntity.status(HttpStatus.CREATED) .body(ApiResponse.of("success", "게시글 작성 성공", null)); }// 테스트 코드 @DisplayName("게시물의 제목과 본문을 반드시 작성해야 한다.") @Test void postAddWithoutTitleOrContent() throws Exception { PostCreateRequest post = PostCreateRequest.of("", " "); Assertions.assertThrows(ValidationException.class, () -> { mvc.perform(post("/api/posts") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(mapper.writeValueAsString(post))) .andDo(print()); }); } 위 컨트롤러 코드를 보면 title과 content에 빈 값이 들어가면 ValidationException이 발생하고 유효성 검사 오류가 응답되어야 합니다. 그런데 응답을 보면Body = {"status":"fail","message":"유효성 검사 오류","data":{"title":"must not be blank","content":"must not be blank"}}이렇게 정상적으로 오류 발생 응답이 옵니다. 그런데 assertThrows 테스트코드는 통과하지 못합니다. 그럼 ValidationException이 발생하지 않았다는 뜻인데 응답은 예외가 발생했을 때의 응답입니다. 왜 테스트코드를 통과하지 못하는지 궁금합니다!
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
hello와 hello-static.html 의 차이
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 주소창에 입력할 때static 폴더에 있는 hello-static과 index는 확장자 (.html)을 붙여야 하고templates 폴더에 있는 hello는 .html을 붙이면 안되는? 걸로 알고 있는데 이유가 궁금합니다! hello는 th: 문법을 사용해서 그런건가요? 확실하게 이유를 알고 싶습니다 ㅎㅎ