월 66,000원
5개월 할부 시다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨스프링과 JPA 기반 웹 애플리케이션 개발
12:15와는 다른 화면이 나옵니다.
읽기 쉽게 fragments.html에 있는 코드를 settings.tags.html에 옮겨 적었습니다. 코드 내용<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Study Club</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@yaireo/tagify@3.5.1/dist/tagify.css"> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jdenticon@3.2.0/dist/jdenticon.min.js" async integrity="sha384-yBhgDqxM50qJV5JPdayci8wCfooqvhFYbIKhv0hTtLvfeeyJMJCscRfFNKIxt43M" crossorigin="anonymous"> </script> <style> .container{ max-width: 100%; } .tagify-outside{ border: 0; padding: 0; margin: 0; } </style> </head> <body class="bg-light"> <nav class="navbar navbar-expand-sm navbar-dark bg-dark"> <a class="navbar-brand" href="/" th:href="@{/}"> <img src="/images/logo_symbol.png" width="30" height="30"> </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <form th:action="@{/search/study}" class="form-inline" method="get"> <input class="form-control mr-sm-2" name="keyword" type="search" placeholder="스터디 찾기" aria-label="Search" /> </form> </li> </ul> <ul class="navbar-nav justify-content-end"> <li class="nav-item" sec:authorize="!isAuthenticated()"> <a class="nav-link" th:href="@{/login}">로그인</a> </li> <li class="nav-item" sec:authorize="!isAuthenticated()"> <a class="nav-link" th:href="@{/sign-up}">가입</a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link" th:href="@{/notifications}"> <i class="fa fa-bell-o"></i> </a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link btn btn-outline-primary" th:href="@{/notifications}"> <i class="fa fa-plus" aria-hidden="true"></i> 스터디 개설 </a> </li> <li class="nav-item dropdown" sec:authorize="isAuthenticated()"> <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <svg th:if="${#strings.isEmpty(account?.profileImage)}" data-jdenticon-value="user127" th:data-jdenticon-value="${#authentication.name}" width="24" height="24" class="rounded border bg-light"></svg> <img th:if="${!#strings.isEmpty(account?.profileImage)}" th:src="${account.profileImage}" width="24" height="24" class="rounded border"/> </a> <div class="dropdown-menu dropdown-menu-sm-right" aria-labelledby="userDropdown"> <h6 class="dropdown-header"> <span sec:authentication="name">Username</span> </h6> <a class="dropdown-item" th:href="@{'/profile/' + ${#authentication.name}}">프로필</a> <a class="dropdown-item" >스터디</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#" th:href="@{'/settings/profile'}">설정</a> <form class="form-inline my-2 my-lg-0" action="#" th:action="@{/logout}" method="post"> <button class="dropdown-item" type="submit">로그아웃</button> </form> </div> </li> </ul> </div> </nav> <div class="container"> <div class="row mt-5 justify-content-center"> <div class="col-2"> <div class="list-group"> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'profile'}? active" href="#" th:href="@{/settings/profile}">프로필</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'password'}? active" href="#" th:href="@{/settings/password}">비밀번호</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'notifications'}? active" href="#" th:href="@{/settings/notifications}">알림</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'tags'}? active" href="#" th:href="@{/settings/tags}">관심 주제</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'zones'}? active" href="#" th:href="@{/settings/zones}">활동 지역</a> <a class="list-group-item list-group-item-action list-group-item-danger" th:classappend="${currentMenu == 'account'}? active" href="#" th:href="@{/settings/account}">계정</a> </div> </div> <div class="col-8"> <div class="row"> <h2 class="col-12">관심있는 스터디 주제</h2> </div> <div class="row"> <div class="col-12"> <div class="alert alert-info" role="alert"> 참여하고 싶은 스터디 주제를 입력해 주세요. 스터디가 생기면 알림을 받을 수 있습니다. 태그 입력 후 콤마(,) 또는 엔터를 입력하세요. </div> <input id="tags" type="text" name="tags" class="tagify-outside" aria-describedby="tagHelp"/> </div> </div> </div> </div> </div> <script type="application/javascript" th:inline="javascript"> $(function () { var csrfToken = /*[[${_csrf.token}]]*/ null; var csrfHeader = /*[[${_csrf.headerName}]]*/ null; $(document).ajaxSend(function (e, xhr, options){ xhr.setRequestHeader(csrfHeader, csrfToken); }); }); </script> <script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify@3.5.1/dist/tagify.min.js"></script> <script type="application/javascript" th:inline="javascript"> $(function() { function tagRequest(url, tagTitle) { $.ajax({ dataType: "json", autocomplete: { enabled: true, rightKey: true, }, contentType: "application/json; charset=utf-8", method: "POST", url: "[(${baseUrl})]" + url, data: JSON.stringify({'tagTitle': tagTitle}) }).done(function (data, status) { console.log("${data} and status is ${status}"); }); } function onAdd(e) { tagRequest("/add", e.detail.data.value); } function onRemove(e) { tagRequest("/remove", e.detail.data.value); } var tagInput = document.querySelector("#tags"); var tagify = new Tagify(tagInput, { pattern: /^.{0,20}$/, whitelist: JSON.parse(document.querySelector("#whitelist").textContent), dropdown : { enabled: 1, // suggest tags after a single character input } // map tags }); tagify.on("add", onAdd); tagify.on("remove", onRemove); // add a class to Tagify's input element tagify.DOM.input.classList.add('form-control'); // re-place Tagify's input element outside of the element (tagify.DOM.scope), just before it tagify.DOM.scope.parentNode.insertBefore(tagify.DOM.input, tagify.DOM.scope); }); </script> </body> </html>결과 화면
- 해결됨스프링과 JPA 기반 웹 애플리케이션 개발
7:35 부분에서 질문합니다.
혼자 여러 번 연습할 때 마다 여기서 계속 막혀서 적습니다. 코드는 다음과 같습니다.깃허브 주소: https://github.com/KrillM/studyclub @Test @DisplayName("회원 가입 처리 - 입력값 오류") public void signUpSubmit_wrongInputTest() throws Exception{ mockMvc.perform(post("/sign-up") .param("nickname", "keesun") .param("email", "email...") .param("password", "12345") .with(csrf())) .andExpect(status().isOk()) .andExpect(view().name("account/sign-up")); }
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
실제 구동은 되지만 테스트는 실패합니다.
강사님 현재 스프링과 JPA 기반 웹 애플리케이션을 듣는 중입니다.여러 번 반복하면서 개발 흐름을 파악하는 중인데요.AccountControllerTest에서 회원 가입 테스트- 잘못된 입력값을 테스트하는 중인데, 실제로는 구동이 잘 되지만 테스트 중에는 매번 테스트 실패로 뜹니다. 코드는 다음과 같습니다.@Test @DisplayName("회원 가입 테스트 - 잘못된 입력값") public void signUpSubmitTest_wrong() throws Exception{ mockMvc.perform(post("/sign-up") .param("nickname", "yena") .param("email", "yenice") .param("password", "12354") .with(csrf())) .andDo(print()) .andExpect(status().isOk()) .andExpect(view().name("account/sign-up")); }깃허브 주소: https://github.com/KrillM/studyclub이 문제를 넘어가기에는 앞으로 수업을 들으면서, 이후 포트폴리오를 만들 때 발목을 잡을 것 같아 질문합니다.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
SecurityConfig의 WebSecurityConfigurerAdapter 가 deprecated 되어 아래와 같이 코드를 수정하였는데 괜찮을까요?
안녕하세요 강의 잘 듣고 있습니다.해당 수업을 들으면서 코드를 직접 작성을 하고 있었는데 SecurityConfig의 WebSecurityConfigurerAdapter 가 deprecated가 되어서 인식이 안됬습니다.그래서 커뮤니티를 통해 어떤 오류가 났는지 다른 회원님의 글을 보고 알게 되어 해당 코드를 인용했음에도 오류가 발생하여 아래와 같이 코드를 수정을 했는데 괜찮을까요? package com.studyolle.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @Configuration //스프링 설정 클래스 @EnableWebSecurity //웹 보안 활성화, 웹 보안 설정 재정의 public class SecurityConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { RequestMatcher[] matchers = { new MvcRequestMatcher(introspector, "/"), new MvcRequestMatcher(introspector, "/login"), new MvcRequestMatcher(introspector, "/sign-up"), new MvcRequestMatcher(introspector, "/check-email"), new MvcRequestMatcher(introspector, "/check-email-token"), new MvcRequestMatcher(introspector, "/email-login"), new MvcRequestMatcher(introspector, "/check-email-login"), new MvcRequestMatcher(introspector, "/login-link"), new MvcRequestMatcher(introspector, "/profile/*") }; //보안 요청에 대한 권한 및 역활 설정 http.authorizeRequests() //배열에 있는 경로들에 대한 모든 요청을 허용 .requestMatchers(matchers).permitAll() //지저오딘 경로외의 모든 요청은 인증된 사용자만 접근할 수 있도록 함 .anyRequest().authenticated(); // POST에 대한 별도 조건을 설정하려면 추가 코드 필요 return http.build(); } }
- 해결됨스프링과 JPA 기반 웹 애플리케이션 개발
SecurityConfig 파일 작성중,, WebSecurityConfigurerAdapter 가 deprecated 됬다고 해서 extends가 안됩니다.
안녕하세요. 강의를 열심히 들으려고 하는 한 직장인입니다. 해당 수업 (회원가입 컨트롤러) 를 듣는도중, SecurityConfig 파일 만드는 부분에서 WebSecurityConfigurerAdapter 가 deprecated 되었다고 extends가 안되고 있습니다. 저는 현재 스프링 시큐리티 버전을.. 6 버전대 사용중이에요. 정확히는 6.1.2 버전 사용하는것 같네요.. (이렇게 버전확인해도되는건지 몰르겠습니다..ㅠㅠ) 로그분석과,, 구글링을 좀 해본 결과, RequestMatchers(MvcRequestMatcher) orRequestMatchers(AntPathRequestMatcher) 의 패턴으로 사용을 해야한다고 해서,, 결국 소스를 수정하여. permitAll()은 해결하였습니다.그런데 강의에서 프로필 요청 url은 httpMethod중 get만 허용해야 하는 조건에서, mvcMatchers(HttpMethod.GET, "/profile/*").permitAll() 부분을 도무지 어떻게 대치해야할지를 모르겠습니다. 제가 현재 까지 작성한 소스 공유 드립니다. package com.studyolle.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @Configuration @EnableWebSecurity // 시큐리티 활성화 -> 기본 스프링 필터체인에 등록 public class SecurityConfig { @Bean SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); http.authorizeHttpRequests((requests) -> requests .requestMatchers( mvcMatcherBuilder.pattern("/"), mvcMatcherBuilder.pattern("/login"), mvcMatcherBuilder.pattern("/sign-up") ,mvcMatcherBuilder.pattern("/check-email"), mvcMatcherBuilder.pattern("/check-email-token"), mvcMatcherBuilder.pattern("/email-login") ,mvcMatcherBuilder.pattern("/check-email-login"), mvcMatcherBuilder.pattern("/login-link"), mvcMatcherBuilder.pattern("/profile/*") ).permitAll() .anyRequest().authenticated() ); return http.build(); } } 해결방안을 자세하게 알려주시면 감사하겠습니다. 시간이 지남에 따라 스프링 정책은 계속 deprecated 되는 것 같은데,,, 너무 나도 배울게 많다고 생각이 됩니다. 잠깐이라도 놓치면 개발의 세계와 너무 멀어지는 느낌이 드네요. 제가 많이 부족하여 따끔한 쓴소리도 같이 부탁드릴께요. 진심 열심히 하려고 노력중입니다.감사합니다. 빠른 답변 부탁드리겠습니다.
- 해결됨스프링과 JPA 기반 웹 애플리케이션 개발
강의대로했는데안되네요.
강의대로 했는데 안되네요. 우선 깃 링크로 접속하여 코드 다운로드받은뒤 압축풀어서 intellij 로 open 하여 해당 강의처럼 maven -> compile 더블클릭 했는데, 잘 돌던중 에러한줄이 뜹니다. /Users/jjeoV/Desktop/jjeoV/인프런/keesun/studyolle-master 2/target/classes/static/node_modules/.bin/jdenticon jdenticon 파일이 없는건가요? 그냥 딸랑 경로하나뜨니까 뭔지 잘 몰르겠네요. 감사합니다.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
안녕하세요 압축프로그렘을 다운받은후에 compile해보니 오류가 발생해서 질문드립니다
이유가 뭘까요 사진 첨부해드릴게요 이거는 다른 글을 보니 추가해주니 해결되었다던데 저는 여젼히 컴파일에서 오류가 발생하네요
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
프로젝트 compile시 npm install시 No repository field
npm install시 위와같은 오류와 함께 컴파일이 종료됩니다. 혹시 해결 방법이 있나요?
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
AppConfig클래스에 대해 질문있습니다 ㅎㅎ
안녕하세요 강의 6분에 PasswordEncoder 빈등록을 AppConfig 클래스를 하나 추가로 만들어서 하셨는데 저는 SecurityConfig에 추가로 등록해도 괜찮을것같다는 생각이들었는데 AppConfig을 추가했을때 어떤 이점이 있다고 생각하셔서 하신건지 궁금합니다!!
- 해결됨스프링과 JPA 기반 웹 애플리케이션 개발
사진 수정이 계속 안 됩니다.
cdn 방식으로 cropper를 사용하는 중이고요. 자바스크립트를 여러번 검토 하였음에도 프로필 사진 변경 문제는 끝까지 해결되지 않았습니다.https://www.youtube.com/watch?v=k330LVo2yw8setting.profile.html<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://thymeleaf.org/extras/spring-security"> <head th:fragment="head"> <meta charset="UTF-8"> <title>StudyOlle</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jdenticon@3.2.0/dist/jdenticon.min.js" async integrity="sha384-yBhgDqxM50qJV5JPdayci8wCfooqvhFYbIKhv0hTtLvfeeyJMJCscRfFNKIxt43M" crossorigin="anonymous"> </script> <style> .container{ max-width:100%; } </style> </head> <nav th:fragment="main-nav" class="navbar navbar-expand-sm navbar-dark bg-dark"> <a class="navbar-brand" href="/" th:href="@{/}"> <img src="/images/logo_sm.png" width="30" height="30"> </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <form th:action="@{/search/study}" class="form-inline" method="get"> <input class="form-control mr-sm-2" name="keyword" type="search" placeholder="스터디 찾기" aria-label="Search"> </form> </li> </ul> <ul class="navbar-nav justify-content-end"> <li class="nav-item" sec:authorize="isAnonymous()"> <a class="nav-link" th:href="@{/login}">로그인</a> </li> <li class="nav-item" sec:authorize="isAnonymous()"> <a class="nav-link" th:href="@{/sign-up}">가입</a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link" th:href="@{/notifications}"> <i class="fa fa-bell-o" aria-hidden="true"></i> </a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link btn btn-outline-primary" th:href="@{/notifications}"> <i class="fa fa-plus" aria-hidden="true"></i> 모임 개설 </a> </li> <li class="nav-item dropdown" sec:authorize="isAuthenticated()"> <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <svg th:if="${#strings.isEmpty(account?.profileImage)}" th:data-jdenticon-value="${#authentication.name}" width="24" height="24" class="rounded border bg-light"></svg> <img th:if="${!#strings.isEmpty(account?.profileImage)}" th:src="${account.profileImage}" width="24" height="24" class="rounded border"/> </a> <div class="dropdown-menu dropdown-menu-sm-right" aria-labelledby="userDropdown"> <h6 class="dropdown-header"> <span sec:authentication="name">Username</span> </h6> <a class="dropdown-item" th:href="@{'/profile/' + ${#authentication.name}}">프로필</a> <a class="dropdown-item" >스터디</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#" th:href="@{'/settings/profile'}">설정</a> <form class="form-inline my-2 my-lg-0" action="#" th:action="@{/logout}" method="post"> <button class="dropdown-item" type="submit">로그아웃</button> </form> </div> </li> </ul> </div> </nav> <footer th:fragment="footer"> <div class="row justify-content-center"> <img class="mb-2" src="/images/logo_lang_kr.jpg" alt="" width="100"> <small class="d-block mb-3 text-muted">© 2023</small> </div> </footer> <div th:fragment="settings-menu (currentMenu)" class="list-group"> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'profile'}? active" href="#" th:href="@{/settings/profile}">프로필</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'password'}? active" href="#" th:href="@{/settings/password}">비밀번호</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'notification'}? active" href="#" th:href="@{/settings/notification}">알림</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'tags'}? active" href="#" th:href="@{/settings/tags}">관심 주제</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'zones'}? active" href="#" th:href="@{/settings/zones}">활동 지역</a> <a class="list-group-item list-group-item-action list-group-item-danger" th:classappend="${currentMenu == 'account'}? active" href="#" th:href="@{/settings/account}">계정</a> </div> <script type="application/javascript" th:fragment="form-validation"> (function () { 'use strict'; window.addEventListener('load', function () { // Fetch all the forms we want to apply custom Bootstrap validation styles to var forms = document.getElementsByClassName('needs-validation'); // Loop over them and prevent submission Array.prototype.filter.call(forms, function (form) { form.addEventListener('submit', function (event) { if (form.checkValidity() === false) { event.preventDefault(); event.stopPropagation(); } form.classList.add('was-validated') }, false) }) }, false) }()) </script> </html>fragments.html<!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://thymeleaf.org/extras/spring-security"> <head th:fragment="head"> <meta charset="UTF-8"> <title>StudyOlle</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.4.1/dist/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jdenticon@3.2.0/dist/jdenticon.min.js" async integrity="sha384-yBhgDqxM50qJV5JPdayci8wCfooqvhFYbIKhv0hTtLvfeeyJMJCscRfFNKIxt43M" crossorigin="anonymous"> </script> <style> .container{ max-width:100%; } </style> </head> <nav th:fragment="main-nav" class="navbar navbar-expand-sm navbar-dark bg-dark"> <a class="navbar-brand" href="/" th:href="@{/}"> <img src="/images/logo_sm.png" width="30" height="30"> </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarSupportedContent"> <ul class="navbar-nav mr-auto"> <li class="nav-item"> <form th:action="@{/search/study}" class="form-inline" method="get"> <input class="form-control mr-sm-2" name="keyword" type="search" placeholder="스터디 찾기" aria-label="Search"> </form> </li> </ul> <ul class="navbar-nav justify-content-end"> <li class="nav-item" sec:authorize="isAnonymous()"> <a class="nav-link" th:href="@{/login}">로그인</a> </li> <li class="nav-item" sec:authorize="isAnonymous()"> <a class="nav-link" th:href="@{/sign-up}">가입</a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link" th:href="@{/notifications}"> <i class="fa fa-bell-o" aria-hidden="true"></i> </a> </li> <li class="nav-item" sec:authorize="isAuthenticated()"> <a class="nav-link btn btn-outline-primary" th:href="@{/notifications}"> <i class="fa fa-plus" aria-hidden="true"></i> 모임 개설 </a> </li> <li class="nav-item dropdown" sec:authorize="isAuthenticated()"> <a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <svg th:if="${#strings.isEmpty(account?.profileImage)}" th:data-jdenticon-value="${#authentication.name}" width="24" height="24" class="rounded border bg-light"></svg> <img th:if="${!#strings.isEmpty(account?.profileImage)}" th:src="${account.profileImage}" width="24" height="24" class="rounded border"/> </a> <div class="dropdown-menu dropdown-menu-sm-right" aria-labelledby="userDropdown"> <h6 class="dropdown-header"> <span sec:authentication="name">Username</span> </h6> <a class="dropdown-item" th:href="@{'/profile/' + ${#authentication.name}}">프로필</a> <a class="dropdown-item" >스터디</a> <div class="dropdown-divider"></div> <a class="dropdown-item" href="#" th:href="@{'/settings/profile'}">설정</a> <form class="form-inline my-2 my-lg-0" action="#" th:action="@{/logout}" method="post"> <button class="dropdown-item" type="submit">로그아웃</button> </form> </div> </li> </ul> </div> </nav> <footer th:fragment="footer"> <div class="row justify-content-center"> <img class="mb-2" src="/images/logo_lang_kr.jpg" alt="" width="100"> <small class="d-block mb-3 text-muted">© 2023</small> </div> </footer> <div th:fragment="settings-menu (currentMenu)" class="list-group"> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'profile'}? active" href="#" th:href="@{/settings/profile}">프로필</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'password'}? active" href="#" th:href="@{/settings/password}">비밀번호</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'notification'}? active" href="#" th:href="@{/settings/notification}">알림</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'tags'}? active" href="#" th:href="@{/settings/tags}">관심 주제</a> <a class="list-group-item list-group-item-action" th:classappend="${currentMenu == 'zones'}? active" href="#" th:href="@{/settings/zones}">활동 지역</a> <a class="list-group-item list-group-item-action list-group-item-danger" th:classappend="${currentMenu == 'account'}? active" href="#" th:href="@{/settings/account}">계정</a> </div> <script type="application/javascript" th:fragment="form-validation"> (function () { 'use strict'; window.addEventListener('load', function () { // Fetch all the forms we want to apply custom Bootstrap validation styles to var forms = document.getElementsByClassName('needs-validation'); // Loop over them and prevent submission Array.prototype.filter.call(forms, function (form) { form.addEventListener('submit', function (event) { if (form.checkValidity() === false) { event.preventDefault(); event.stopPropagation(); } form.classList.add('was-validated') }, false) }) }, false) }()) </script> </html>SettingsController.java@Controller @RequiredArgsConstructor public class SettingsController { final static String SETTING_PROFILE_VIEW_NAME="settings/profile"; final static String SETTING_PROFILE_URL="/settings/profile"; private final AccountService accountService; @GetMapping(SETTING_PROFILE_URL) public String profileUpdateForm(@CurrentUser Account account, Model model){ model.addAttribute(account); model.addAttribute(new Profile(account)); return SETTING_PROFILE_VIEW_NAME; } @PostMapping(SETTING_PROFILE_URL) public String updateProfile(@CurrentUser Account account, @Valid Profile profile, Errors errors, Model model, RedirectAttributes attributes){ if(errors.hasErrors()){ model.addAttribute(account); return SETTING_PROFILE_VIEW_NAME; } accountService.updateProfile(account, profile); attributes.addFlashAttribute("message","프로필을 수정했습니다."); return "redirect:"+SETTING_PROFILE_URL; } }AccountService.javapublic void updateProfile(Account account, Profile profile){ account.setUrl(profile.getUrl()); account.setBio(profile.getBio()); account.setOccupation(profile.getOccupation()); account.setLocation(profile.getLocation()); account.setProfileImage(profile.getProfileImage()); accountRepository.save(account); }Profile.java@Data @NoArgsConstructor public class Profile { @Length(max = 35) private String bio; @Length(max = 50) private String url; @Length(max = 50) private String occupation; @Length(max = 50) private String location; private String profileImage; public Profile(Account account){ this.bio=account.getBio(); this.url=account.getUrl(); this.occupation=account.getOccupation(); this.location=account.getLocation(); this.profileImage=account.getProfileImage(); } }
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
강사님! 프론트엔드 라이브러리 설정 부분에서 오류가 납니다..
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:testCompile (default-testCompile) on project studyolle: Compilation failure[ERROR] No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK?[ERROR][ERROR] -> [Help 1][ERROR][ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.[ERROR] Re-run Maven using the -X switch to enable full debug logging.[ERROR][ERROR] For more information about the errors and possible solutions, please read the following articles:[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException ./mvnw test 명령어를 입력하면 위에 오류가 나오면서 build failure라고 뜨네요.. 오류메시지처럼 자바 버전 문젠가 해서 제 맥북 환경변수쪽도 보니까 11로 잘 들어가 있는데 왜 그럴까요.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
프로젝트 실행하기 강의에서 compile 클릭시
[ERROR] Failed to execute goal com.github.eirslett:frontend-maven-plugin:1.8.0:npm (npm install) on project studyolle: Failed to run task: 'npm install' failed. org.apache.commons.exec.ExecuteException: Process exited with an error: 236 (Exit value: 236) -> [Help 1][ERROR][ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.[ERROR] Re-run Maven using the -X switch to enable full debug logging.[ERROR][ERROR] For more information about the errors and possible solutions, please read the following articles:[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException해당 오류가 찍히는데 버전 문제일까요.?
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
회원가입 인증 메일 확인
accountService 애서 processNewAccount 을 Account newAccount = saveNewAccount(signUpForm);;newAccount.getGenerateEmailCheckToken();accountRepository.flush();sendSignUpConfirmEmail(newAccount);로하면@Transactional 을 메서드 상단에 선언을 안해도 해결이 가능한데요. @Transactional 를 사용하지않고강제로 플러시를 해준경우에 추후에 문제가 될만 소지가 있을까요?
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
Authentication should not be null 오류 질문
안녕하세요. 백기선님. 좋은 강의 감사합니다. 강의를 따라가다 Authentication 오류 해결에 어려움을 겪고 있어 질문드립니다. test소스 authenticated()에서는 Authentication should not be null 에러가 발생하고 뷰단에서도 isAuthenticated() 체크되지 않습니다. 디버깅을 해보면 UsernamePasswordAuthenticationToken 생성 이후 Authentication 객체가 만들어진 것은 확인을 했는데, 어느 시점에서 객체를 못가져오고 null이 찍힙니다.스프링시큐리티에 대한 지식이 없어 그런지 난감합니다. 도움주시면 감사하겠습니다.Spring-Security6 사용중입니다.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
패키지 이동시 import 깨짐
강좌대로 패키지에 모두 이동시켯더니 기존 refactor로import경로가 바뀌었지만 모두 비활성화 상태가 되어서오류가 나버립니다. 무슨이유일까요?
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
태그가 Account에 반영이 안됩니다.
저장시에 findById로 가져온 부분에는 잘 들어가는데 현재 Account에는 반영이 되지 않습니다. 또한 새로고침을 하면 현재 account도, db 정보에도 null 로 뜹니다. Account 엔티티에 @ManyToMany private Set<Tag> tags = new HashSet<>();했습니다...
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
모임 만들기 페이지에서 시간을 설정할 때, 연월일 제외하고 시간만 입력하려면 어떻게 하면 되는지요?
안녕하세요. 모임 만들기 페이지에서 시간을 설정할 때,연월일 제외하고 시간만 입력하려면 어떻게 하면 되는지요?fragments.html 의 <div th:fragment="event-form (mode, action)"> 에서<input id="endEnrollmentDateTime" type="datetime-local"의 type 부분을 type="time" 으로 하고Event 클래스에서 private LocalDateTime endEnrollmentDateTime;을private DateTime endEnrollmentDateTime;로 변경하고 실행하면 html 상에서는 시간이 입력되나,DB 에는 insert 되어 있지 않습니다.어떻게 하면 가능한지요?자세한 설명 부탁드립니다. 그리고, 제공해 주신 소스를 다운로드해서 프로젝트를 실행한 후, 오른쪽 드롭다운 메뉴 중스터디를 클릭해도 아무 동작이 일어나지 않습니다.소스를 보면<a class="dropdown-item" >스터디</a>이렇게만 나와있고 th:href="@{}" 로 연결된 페이지가 없습니다.이 부분 기능 구현은 안 해 놓으신 건지요? 프로필 페이지에서도왼쪽 프로필 사진 밑에 있는스터디 버튼을 누르면 Study 라고만 나오고별다른 페이지가 나오지 않습니다.이 부분도 기능 구현은 안 해 놓으신 건지요?
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
수업자료로 올려주신 소스가 실행되지 않습니다.
안녕하세요.전체 흐름을 보려고 소스를 실행하려고 공유해주신 수업자료를 내려받아서 실행해 보니 실행되지 않습니다.Intellij Ultiamte 에서 열어서 실행했습니다.클래스가 작성되어 있지 않다고 나옵니다.import com.studyolle.modules.account.QAccount; import com.studyolle.modules.tag.QTag; import com.studyolle.modules.zone.QZone;이 세 개의 클래스들이 작성되어있지 않습니다.그리고, QStudy 는 import 구문도 없습니다.다시 공유해 주시면 좋겠습니다.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
6:44쯤에 EntityGraph의 옵션으로 attributePath로 놓는 게 좋지 않다고 하셨는데 그 이유가 궁금합니다.
안녕하세요. 기선님이 알려주신 팁들로 많은 성장을 하고 있습니다. 감사합니다. 다름이 아니라, 6:44 쯤에 attributePaths로 옵션을 다 변경하시면서 "이게 안 좋다고" 말씀하셨습니다.기존에 EntityGraph의 옵션으로 value를 주면서 Entity 클래스에도 책임이 많아진 터라, 이 소스를 줄이면서 엔티티 클래스의 책임이 덜어져서 더 좋지 않나? 라고 생각하거든요. 혹시 다른 성능상의 이유라도 있을까요? 다른 엔티티 클래스에도 저런 머리 위에 어노테이션(책임)들을 줄이면 코드를 더 깔끔하게 보면서 EntityGraph를 더 잘 활용할 수 있지 않을까 생각합니다. 기선님의 의견을 듣고 싶습니다.
- 미해결스프링과 JPA 기반 웹 애플리케이션 개발
MySQL로 test db 구성하려고 하는데 초기화가 안 된다는 오류가 발생합니다!
안녕하세요. 기선님의 좋은 강의로 덕분에 열심히 성장하고 있습니다. 항상 감사한 마음으로 강의 잘 듣고 있습니다. 다름이 아니라, 이 강좌에서는 PostgreSQL로 test db를 설정했지만, MySQL로 설정하려니 초기화가 안 되어있다는 오류가 계속 발생합니다.java.lang.NoClassDefFoundError: Could not initialize class XXX 이 오류입니다.현재 Spring boot 버전 2.7.7이고, MySQL 버전은 8.0.30입니다.도커 image하고 컨테이너 이름 맞춰서 설정했고 컨테이너 켜져있는 상태에서 시도했는데 안 되네요...현재 시도하려는 DB는 root계정에만 있습니다. 소스 링크는 color scripter링크 보내드리겠습니다.https://colorscripter.com/s/aY0KsBW@Value("${mysql.container.image.name}") static String MYSQL_IMAGE;@Value랑 static은 같이 쓸 수 없기에 이 부분 제거했습니다. 몇 일 째 헤매고 있는 부분이라 해결하고 싶은 마음이 굴뚝같습니다 ㅜㅜ docker compose.yml 파일이 필요한 걸까요? 아니면 sql파일이 따로 필요할까요?