묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
환경설정 질문입니다.
안녕하세요 환경설정에서 제가 자바17을 이용하고 있는데 자바11을 권장하다고 하셔서 상관없는지 유무를 알고 싶습니다.그리고 build,execution,deployment 빌드 툴에서 gradle로 들어가서 intelliJ로 바꾸는과정을 해보았는데 그 아래 gradle JVM이 강의에서는 자바11로 체크가 되어있는데 전 Project SDK openjdk-21로 되어있습니다 이경우는 상관이없을까요? 또 distribution에 Wrapper로 되어있습니다 이것도 상관없을까요?
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
외래키 중복 관련 질문
import com.example.banking.domain.user.User import com.example.banking.support.BaseEntity import jakarta.persistence.Entity import jakarta.persistence.FetchType import jakarta.persistence.JoinColumn import jakarta.persistence.ManyToOne @Entity class Account( var balance: Double, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") val user: User, id: Long = 0 ) : BaseEntity(id) { fun addAccount(user: User) { user.accounts.add(this) } fun addBalance(amount: Double) { balance += amount } fun subtractBalance(amount: Double) { balance -= amount } }import com.example.banking.domain.account.Account import com.example.banking.support.BaseEntity import jakarta.persistence.* @Entity class Transaction( val amount: Double, @Enumerated(EnumType.STRING) val type: TransactionType, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn val sender: Account, @ManyToOne(fetch = FetchType.LAZY) @JoinColumn val recipient: Account?, id: Long = 0L ) : BaseEntity(id) { constructor(amount: Double, type: TransactionType, sender: Account) : this(amount, type, sender, null) } import com.example.banking.domain.account.Account import com.example.banking.domain.user.User import com.example.banking.domain.user.UserInfo import com.example.banking.repository.account.AccountRepository import com.example.banking.repository.transaction.TransactionRepository import com.example.banking.repository.user.UserRepository import jakarta.persistence.EntityManager import jakarta.transaction.Transactional import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.annotation.Rollback @SpringBootTest @Transactional @Rollback(value = false) class TransactionTest( @Autowired private val em: EntityManager, @Autowired private val transactionRepository: TransactionRepository, @Autowired private val userRepository: UserRepository, @Autowired private val accountRepository: AccountRepository ) { @Test fun testTransaction() { val user1 = User(UserInfo("b", "Seoul", "123", "123")) val user2 = User(UserInfo("b2", "Seoul", "123", "123")) userRepository.save(user1) userRepository.save(user2) em.flush() em.clear() val account1 = Account(100.0, user1) val account2 = Account(100.0, user2) account1.addAccount(user1) account2.addAccount(user2) accountRepository.save(account1) accountRepository.save(account2) em.flush() em.clear() val sender = accountRepository.findById(account1.id).get() val recipient = accountRepository.findById(account2.id).get() val transaction = Transaction(50.0, TransactionType.TRANSFER, sender, recipient) transactionRepository.save(transaction) em.flush() em.clear() val transaction2 = Transaction(50.0, TransactionType.DEPOSIT, sender) transactionRepository.save(transaction2) // assertThat(sender.balance).isEqualTo(50.0) // assertThat(recipient.balance).isEqualTo(150.0) } } 위와같이 Transaction 엔티티와 Account 엔티티가 ManyToOne 으로 매핑되었을때, 테스트코드를 위와같이 작성시,transactionRepository.save(transaction2) 이 라인에서 Duplicate entry '97' for key 'transaction.UK_96vb4d846be64bta5qbxiicb1' 에러가 발생합니다.제가 알기론 외래키의 경우 중복된 값을 가지는것이 가능한것으로 알고 있는데, 같은 account id로 새로운 Transaction 을 생성할 시에 키가 중복이라는 에러가 발생하는데 왜 그런지 알고싶습니다. 코틀린으로 코드 작성한 점 양해부탁드립니다..
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
MemoryMemberRepository와 MemberService의 차이는 무엇인가요?
이 둘은 비슷한 메서드를 구현한다고 느껴집니다.(save=join) 왜 이런 구조로 작성하나요?
-
해결됨아키텍처 패턴 with iOS - GUI Architecture Patterns(이론)
MVVM in iOS - 리액티브 프로그래밍, 자동바인딩과 수동바인딩에서 질문이있습니다
안녕하세요강사님WPF에서는 자동바인딩이 제공되기때문에 MVVM을 사용하는데있어서 이점이있다고 말씀을해주셨고 iOS에서는 자동바인딩을 시스템레벨에서 제공해주지않기때문에 그런점에서 iOS의 MVVM패턴은 등장배경에서의 이유로 쓰이고있는지 고민해봐야한다고 말씀을 해주셨는데 여기서 궁금한점이 combine의 published는 uikit에서도 사용이가능하고 이는 combine이라는 도구를 시스템레벨에서 제공해주기때문에 combine의 등장으로 자동바인딩이 iOS에서도 제공된다고 할수있는게 아닌가라는 생각이들었습니다결국 $를 통해 binding변수로 만들어주면 해당 published변수의 변화에따라 view가 업데이트되니까 이런점에서는 uikit도 시스템레벨에서 자동바인딩을 지원한다라고 말할수있는게아닌가라는 생각이들었습니다 혹시 이부분에대해서 강사님의 생각이 궁금합니다!
-
미해결스프링 DB 2편 - 데이터 접근 활용 기술
의존성 주입
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]강의를 듣다가 순간 애매해서 질문드립니다. V2config에서 해당 코드를@Bean public ItemService itemService() { return new ItemServiceV2(itemRepositoryV2, itemQueryRepositoryV2()); } @Bean public ItemQueryRepositoryV2 itemQueryRepositoryV2(){ return new ItemQueryRepositoryV2(em); }@Bean public ItemService itemService() { return new ItemServiceV2(itemRepositoryV2, new ItemQueryRepositoryV2(em)); } /** @Bean public ItemQueryRepositoryV2 itemQueryRepositoryV2(){ return new ItemQueryRepositoryV2(em); } **/ 처럼 ItemQueryRepositoryV2부분은 주석처리 해서 @Bean으로 등록을 하지 않으면 작동이 안돼야 할까요?? 변경하고 작동해봤는데 문제가 없어서 질문드립니다.
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
혹시 김영한 선생님 자바 중급/고급 강의 정확히 언제 나오는지 알 수 있을까요
혹시 김영한 선생님 자바 중급/고급 강의 정확히 언제 나오는지 알 수 있을까요~강의 듣는데 이해 안가는 문법들이 많아서요.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
Post 폼 요청 시, 타입 미스매치에 대한 질문
JSON 요청 시, 타입을 맞지 않게 입력하게 되면, 컨트롤러 자체가 아예 호출되지 않는 것을 강의를 통해 확인했습니다. Post 폼 요청 시, 이런 타입에 대한 올바르지 않은 입력을 하게 되어도, 컨트롤러가 호출되고 검증 단계까지 도달할 수 있는 이유가 스프링 프레임워크가 자동으로 타입을 적절하게 형변환해주기 때문인가요? 이유가 궁금합니다!
-
미해결
버튼 클릭 시 페이지가 로드되지 않는 문제 해결 방법 질문
개요로그인 성공 후 인덱스 페이지로 넘어갑니다.인덱스 페이지에는 "테스트 버튼" 이라는 버튼을 클릭하면, test 로드하는 api 를 호출하도록 했습니다.그러나 api 요청만 진행되고, 페이지는 바뀌지 않습니다.개발자도구 메시지에 해당 페이지의 html 코드만 출력됩니다. 참고자료index.html<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <title>인덱스 페이지</title> <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script> </head> <body> <h1>환영합니다!</h1> <p>성공적으로 로그인하셨습니다.</p> <button id="logoutButton">로그아웃</button> <button id="testButton">테스트 버튼</button> <script> $(document).ready(function() { // 로그아웃 버튼 이벤트 $('#logoutButton').click(function() { // 로컬 스토리지에서 토큰 제거 localStorage.removeItem('accessToken'); // 로그인 페이지로 리다이렉션 window.location.href = '/login'; }); // 테스트 버튼 이벤트 $('#testButton').click(function() { // 로컬 스토리지에서 토큰 가져오기 const token = localStorage.getItem('accessToken'); if (token) { $.ajax({ url: '/api/test', // 요청할 서버의 URL type: 'GET', // HTTP 메서드 beforeSend: function(xhr) { // 요청 헤더에 토큰 추가 xhr.setRequestHeader('Authorization', token); }, success: function(data) { // 요청 성공 시 로직 console.log("테스트 요청 성공:", data); alert("테스트 요청 성공"); }, error: function(xhr, status, error) { // 요청 실패 시 로직 console.error("테스트 요청 실패:", xhr.responseText); alert("테스트 요청 실패"); } }); } else { alert("토큰이 없습니다. 다시 로그인해주세요."); } }); }); </script> </body> </html> 보이는 것처럼 로컬 스토리지에서 토큰을 가져온 후 요청 헤더에 다시 담아서 전송합니다.JwtAuthorizationFilter@Override protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException { // 헤더에서 토큰 추출 log.info("헤더에서 토큰 추출"); String tokenValue = jwtUtil.getJwtFromHeader(req); log.info("토큰 : " + tokenValue); if (StringUtils.hasText(tokenValue)) { // 토큰 유효성 검사 if (!jwtUtil.validateToken(tokenValue)) { log.info("Token Error"); return; } Claims info = jwtUtil.getUserInfoFromToken(tokenValue); try { setAuthentication(info.getSubject()); } catch (Exception e) { log.error(e.getMessage()); return; } } else { log.info("토큰이 없습니다."); } filterChain.doFilter(req, res); } // 인증 처리 public void setAuthentication(String loginId) { log.info("인증 성공"); SecurityContext context = SecurityContextHolder.createEmptyContext(); Authentication authentication = createAuthentication(loginId); context.setAuthentication(authentication); SecurityContextHolder.setContext(context); } // 인증 객체 생성 private Authentication createAuthentication(String loginId) { log.info("인증 객체 생성"); UserDetails userDetails = userDetailsService.loadUserByUsername(loginId); return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); }이렇게 JwtAuthorizationFilter 가 있을 때 헤더에서 토큰이 추출되는 거까지 로그에 다 출력되고, 인증 객체까지 생성되는 걸 확인했습니다. Console2024-02-26T14:31:24.699+09:00 INFO 59767 --- [nio-8081-exec-3] JWT 검증 및 인가 : 토큰 : eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0NiIsImF1dGgiOiJPV05FUiIsImlhdCI6MTcwODkyNDY0NiwiZXhwIjoxNzA4OTI4MjQ2fQ.TLjHCc1_ZtTbzGb-2c0ueLmxgCyxQf1rUQs4DkqMv_c 2024-02-26T14:31:24.706+09:00 INFO 59767 --- [nio-8081-exec-3] JWT 검증 및 인가 : 인증 성공 2024-02-26T14:31:24.706+09:00 INFO 59767 --- [nio-8081-exec-3] JWT 검증 및 인가 : 인증 객체 생성 Hibernate: /* <criteria> */ select u1_0.id, u1_0.email, u1_0.login_id, u1_0.password, u1_0.role from users u1_0 where u1_0.login_id=? 2024-02-26T14:31:24.722+09:00 INFO 59767 --- [nio-8081-exec-3] TestController : test controller로그를 보면 test controller 를 호출하는 거까지 확인할 수 있었습니다.그러나 페이지는 로드되지 않고, 메시지에 html 코드만 출력이 됩니다. 자료 Test.html<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script> <title>Test Page</title> </head> <body> <h1>This is a test page.</h1> </body> </html> 정리로그인 성공 후 인덱스 페이지로 넘어감해당 인덱스 페이지에서 test 페이지로 넘어가고자 함인가 필터 모두 거치고, 토큰 값이 전달되는 거까지 확인했음test controller 까지 요청되지만, 정작 페이지는 불러와지지 않음 대체 제가 뭘 놓친 걸까요 ㅠㅠㅠㅠ 이거때문에 며칠 동안 머리 싸매고 있습니다,,, 제발 도와주세요,,,
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
예외를 여기서 마무리하기
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. 강의 잘 보고 있습니다.한 가지 궁금한 점이 생겼는데 바로 직전 강의에서는 똑같이HandlerExceptionResolver를 아래와 같이 사용했는데 서블릿 컨테이너까지 에러를 전달해서 서블릿 컨테이너가 다시 서버 내부에서 BasicErrorController로 재요청하는 방식으로 이루어진 것 같은데, 왜 여기서는 HandlerException 에서 처리가 마무리 되었는지 헷갈립니다. 제가 생각하기에는 response.sendError 때문에 이전 강의에서는 서블릿 컨테이너까지 에러가 갔다가 다시 재요청을 한 것이고, 이번에는 response.sendError를 쓰지 않았기 때문에 HandlerExceptionResolver에서 마무리가 된 것 같은데 이게 맞나요?? 이전 강의와 현재 강의의 코드 비교 입니다.이전 강의 코드package hello.exception.resolver; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; @Slf4j public class MyHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { try { if (ex instanceof IllegalArgumentException) { log.info("IllegalArgumentException resolver to 400"); response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); return new ModelAndView(); } } catch (Exception e) { log.error("resolver ex", e); } return null; } } 현재 강의 코드package hello.exception.resolver; import com.fasterxml.jackson.databind.ObjectMapper; import hello.exception.exception.UserException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.Map; @Slf4j public class UserHandlerExceptionResolver implements HandlerExceptionResolver { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { try { if (ex instanceof UserException) { log.info("UserException resolver to 400"); String acceptHeader = request.getHeader("accept"); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); if ("application/json".equals(acceptHeader)) { Map<String, Object> errorResult = new HashMap<>(); errorResult.put("ex", ex.getClass()); errorResult.put("message", ex.getMessage()); String result = objectMapper.writeValueAsString(errorResult); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); response.getWriter().write(result); return new ModelAndView(); } else { // TEXT/HTML return new ModelAndView("error/400"); } } } catch (Exception e) { log.error("resolver ex", e); } return null; } }
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
request.getAttribute
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. 강의를 듣는데 ErrorPageController의request.getAttribute(ERROR_EXCEPTION); request.getAttribute(ERROR_STATUS_CODE);사용이 궁금합니다. request에 setAttribute로 넣어준 값이 없는데 어떻게해서 저렇게 작동하는 것인지 잘 모르곘습니다.얼핏 기억나는 내용으론 이전 강의 8장에서 디스패처 서블릿이 에러 내용을 넣어준다고 했던거 같은데 그게 맞나요?맞다면 복습을 하고 싶은데 혹시 어떤 파트를 다시 보면 될지 알려주시면 감사하겠습니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
타임리프 에러
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 아니오3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]본 강의에 그대로 따라서 코드를 작성했는데, 에러가 발생합니다. @Controller @RequestMapping("/basic") public class BasicController { @GetMapping("/text-basic") public String textBasic(Model model) { model.addAttribute("data", "hello spring!"); return "basic/text-basic"; } @GetMapping("/text-unescaped") public String textUnescaped(Model model) { model.addAttribute("data", "Hello <b>Spring!</b>"); return "basic/text-unescaped"; } @GetMapping("/variable") public String variable(Model model) { User userA = new User("userA", 10); User userB = new User("userB", 10); List<User> list = new ArrayList<>(); list.add(userA); list.add(userB); Map<String, User> map = new HashMap<>(); map.put("userA", userA); map.put("userB", userB); model.addAttribute("user", userA); model.addAttribute("users", list); model.addAttribute("userMap", map); return "basic/variable"; } @GetMapping("/basic-objects") public String basicObjects(Model model, HttpServletRequest request, HttpServletResponse response, HttpSession session) { session.setAttribute("sessionData", "Hello Session"); model.addAttribute("request", request); model.addAttribute("response", response); model.addAttribute("servletContext", request.getServletContext()); return "basic/basic-objects"; } @GetMapping("/date") public String date(Model model) { model.addAttribute("localDateTime", LocalDateTime.now()); return "basic/date"; } @Component("helloBean") static class HelloBean { public String hello(String data) { return "Hello " + data; } } @Data static class User { private String username; private int age; public User(String username, int age) { this.username = username; this.age = age; } } }<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>LocalDateTime</h1> <ul> <li>default = <span th:text="${localDateTime}"></span></li> <li>yyyy-MM-dd HH:mm:ss = <span th:text="${#temporals.format(localDateTime, 'yyyy-MM-dd HH:mm:ss')}"></span></li> </ul> <h1>LocalDateTime - Utils</h1> <ul> <li>${#temporals.day(localDateTime)} = <span th:text="${#temporals.day(localDateTime)}"></span></li> <li>${#temporals.month(localDateTime)} = <span th:text="$ {#temporals.month(localDateTime)}"></span></li> <li>${#temporals.monthName(localDateTime)} = <span th:text="$ {#temporals.monthName(localDateTime)}"></span></li> <li>${#temporals.monthNameShort(localDateTime)} = <span th:text="$ {#temporals.monthNameShort(localDateTime)}"></span></li> <li>${#temporals.year(localDateTime)} = <span th:text="${#temporals.year(localDateTime)}"></span></li> <li>${#temporals.dayOfWeek(localDateTime)} = <span th:text="$ {#temporals.dayOfWeek(localDateTime)}"></span></li> <li>${#temporals.dayOfWeekName(localDateTime)} = <span th:text="$ {#temporals.dayOfWeekName(localDateTime)}"></span></li> <li>${#temporals.dayOfWeekNameShort(localDateTime)} = <span th:text="$ {#temporals.dayOfWeekNameShort(localDateTime)}"></span></li> <li>${#temporals.hour(localDateTime)} = <span th:text="${#temporals.hour(localDateTime)}"></span></li> <li>${#temporals.minute(localDateTime)} = <span th:text="$ {#temporals.minute(localDateTime)}"></span></li> <li>${#temporals.second(localDateTime)} = <span th:text="$ {#temporals.second(localDateTime)}"></span></li> <li>${#temporals.nanosecond(localDateTime)} = <span th:text="$ {#temporals.nanosecond(localDateTime)}"></span></li> </ul> </body> </html>다른 질문을 찾아보니까 ul 태그 밑에 li 태그가 한줄로 넣어야 된다고 해서 그렇게 했는데도 오류가 발생합니다. 정확하게는 <h1>LocalDateTime - Utils</h1> 아래의 ul 태그 밑에서 부터 오류가 발생합니다. 오류 메시지는 다음과 같습니다. org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: "$ {#temporals.month(localDateTime)}" (template: "basic/date" - line 16, col 56)도움 주시면 감사하겠습니다 ㅠ
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
@PathVariable 질문 입니다.
@PathVariable 어노테이션 사용 시 위와 같이 GetMapping의 {userId} 와 변수 명이 같으면name="userId" 옵션을 생략해도 된다고 말씀해주셨는데 옵션을 생략하면 500 에러가 나고,옵션을 작성해주면 성공하는데 이런 경우에는 뭐가 문제인가요?
-
미해결스프링 프레임워크는 내 손에 [스프2탄]
idx, boardGroup 번호에 대해
idx는 1번부터 시작하고 boardGroup은 0번부터 시작하셨는데, boardGroup도 idx와 동일하게 1번부터 해도 상관없을까요? 관습적으로 0번부터 하는건지 다른 이유가 있는 건지 궁금합니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
filter 질문
@PostMapping("/login") public String loginHttpSession(@Validated @ModelAttribute("member") LoginForm loginForm, BindingResult bindingResult,HttpServletRequest request, @RequestParam(value = "redirectURL") String redirectURL) { if(bindingResult.hasErrors()) { log.info("로그인 에러"); return "login/login"; } SignUpMember signUpMember = loginService.loginMember(loginForm.getLoginId(), loginForm.getPassword()); if(signUpMember == null) { bindingResult.reject("loginFail", "아이디 또는 비밀번호가 틀렸습니다"); return "login/login"; } HttpSession session = request.getSession(); session.setAttribute(SessionConst.LOGIN_MEMBER, signUpMember); return "redirect:/guPage/index"; } 위 코드를 작성해서 http://localhost:8080/login?redirectURL=/basic/items위 url을 post로 받으려 하는데 405 error가 뜨네요 어떻게 하면 될까요?그리고 제가 알기론 @RequestParam(value = "redirectURL") String redirectURL에서 value를 제거해도 된다고 알고 있는데 value를 안적어주니 이것도 에러가 나더라고요 어떻게 하면 될까요?
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
jsp파일의 html 태그에 대해 궁금한 것이 있습니다.
강의록을 보면 이전의 MemberFormServlet 코드에서는 응답 메시지 상단에 <!DOCTYPE HTML>을 명시해주었는데, 왜 이번 jsp에서는 html 태그 위에 <!DOCTYPE HTML>를 명시해주지 않아도 정상적으로 동작하나요?https://developer.mozilla.org/en-US/docs/Web/HTML/Quirks_Mode_and_Standards_Mode위에서 <!DOCTYPE HTML>는 브라우저한테 어떤 document 타입을 사용하는지를 알려주기 위해 반드시 최상단에 명시해야 한다고 되어 있습니다. 만약 이것을 명시하지 않으면 quirk mode로 동작이 되서 현재 널리 채택된 full-standard mode와 다르게 렌더링될 수 있다고 되어있습니다.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
WebMvcConfigurer에 대해서 궁금합니다.
@Configuration @RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { private final AppConfig appConfig; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new AuthResolver(appConfig)); } }안녕하세요 제가 지금 프로젝트를 하나 하고있는데요이 코드에서resolver.add()를 하면 어떻게 되는건지 궁금합니다.AuthResolver에 대한 의존성을 추가해주는 코드인가요?resolvers.add()의 동작방식이 궁금합니다.그리고 resolver의 정확한 의미가 뭔지 궁금합니다
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
No DataSource specified 에러가 뜹니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]선생님, 스프링을 통해서 제가 생각한 대로 설계해서 잘 만드는 백엔드 개발자가 꿈인 사람입니다.앞부분에는 천천히 강의 설명을 잘 해주셔서 이상없이 잘 따라왔는데요.순수 jdbc 강의부터 복사 붙여넣기로 강의 속도가 빨라지면서낯선 메소드와 코드들이 보여서 이해가 안가고 있습니다.실무에서 쓰는데 순수 jdbc 원리는 꼭 깊이 있게 짚고 나가지 않아도 될까요? 어렵습니다ㅠㅠ 게다가 SpringConfig에서 JdbcMemberRepository로바꾸면서 db접근도 안되고 화이트라벨 에러만 계속 발생하고 있습니다..ㅠ chatgpt에 물어보고 검색을 해도 이 문제를 도저히 해결할 수가 없네요.. [에러 내용]java.lang.IllegalArgumentException: No DataSource specified윈도우에서 사용하고 있으며, 스프링부트 버전은 3.xh2 데이터베이스도 최신버전으로 설치해서 실행했습니다.[구글 드라이브]https://drive.google.com/file/d/1HzXNwnwBzOTJIvrzJZisrvoO2LkbYIDI/view?usp=sharing
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
name을 name2로 바꿀려면 어떻게 하나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.API 강의에서 @ResponseBody를 이용해 JSON 으로 객체를 변환받는 내용의 코드에서 name이 너무많아 반환받는 JSON 키를 "name2"로 변경해보고싶어 코드와 url등등 name2를 넣어 계속 실행해봣지만 계속 키는 "name"에서 변하지가 않습니다. 어디를 변경해야 하는걸까요??
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
섹션4_Model추가 V3 강의 질문 입니다.
섹션4_Model추가 V3 강의 내용 중FrontControllerServletV3 클레스 에서 해당 render 메서드의 파라미터 mv.getModel()에는 createParamMap 메서드에서 만들어진 paramMap? 즉 key, value로 생성된 모든 request 값이 들어가고, view.render(mv.getModel(), request, response); 메서드 내부에 modelToRequestAttribute 메서드는 위에서 넘겨준 paramMap을 다시 request에 새팅해주는게 맞나요? 어질 어질 하네요.. ㅜㅜ
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
HttpSession 정리
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]HttpSession에 관해서 공부한 내용을 정리해보았는데 한번 피드백해주시면 감사하겠습니다1. 정리한 부분getSession()을 통해 이미 생성되어있는 세션 저장소에 할당할 HttpSession 빈 세션 객체 하나를 생성 후 반환 getSession()을 통해 생성된 HttpSession 빈 세션 객체에 setAttribute()를 통하여 map 형태의 세션 정보를 저장할 수 있다. 이때 세션 정보는 (세션 이름 , 회원 정보) 로 형태로 저장되고 이 순간 해당 세션을 식별하기 위한 세션id는 톰캣에서 자동으로 생성해줌 따라서 getSession()을 통해 세션 저장소에 저장될 한 세션 객체 HttpSession의 형태를 굳이 표현해보자면 (sessiondId , Map<String , Object>)이고 , 거기다가 setAttribute()를 통해 “세션 이름”과 “회원 정보”를 지정해서 저장하면 (UD3R9A33 , (“loginMember” , member)) 형태로 저장됨 그럼 이 순간 톰캣 서버가 자동으로 Set-Cookie: JSESSIONID=UD3R9A33를 지정해서 클라이언트에 전달함 그에 따라 서버와 클라이언트 간 쿠키를 통해 자동 지정된 세션id를 통해 사용자 여부를 식별할 수 있는 것이렇게 이해하면 될까요? 2. 추가 질문 사항세션 저장소의 한 공간을 차지하는 한 세션 객체 HttpSession에 setAttribute()를 여러 개 호출할 수 있는데 이는 한 HttpSession 공간에서 또 여러 개의 세션 정보를 가질 수 있다고 이해하면 될까요?만약 이가 맞다면 getSession()을 통해 여러 개의 HttpSession을 생성하는 것과 setAttribute()를 통해 한 HttpSession 안에서 여러 개의 세션을 생성하는 것의 차이가 궁금합니다