GithubHelp home page GithubHelp logo

freelec-springboot2-webservice's Introduction

스프링부트2로 웹서비스 출시하기 (프리렉)

예제 코드

주의

이 프로젝트는 실제로 실행하면 정상작동 하지 않습니다. 구글/네이버 토큰 정보가 없기 떄문입니다.
테스트 코드 수행만 정상적으로 되니 코드만 참고하세요

오타 & 오류 제보

상단의 Issue 탭에서 검색 혹은 추가 이슈등록을 부탁드립니다!

질문 올리는 법

  • 페이지 번호
  • 문제가 된 프로젝트가 올라간 Github 저장소 주소
  • 문제가 된 로그 혹은 콘솔 출력 화면

을 함께 포함해서 남겨주세요.
그렇지 않으면 확인 하기가 너무 어렵습니다.

프로젝트 환경 점검

이 책의 모든 예제는 다음의 환경에서 진행됩니다.

  • Java 8
  • Gradle 4.x
  • Spring Boot 2.1.x

즉, 현재 spring.io 에서 만들어주는 기본 환경인 Spring Boot 2.2.xGradle 5.x에서는 정상작동 하지 않습니다.

Spring Boot 2.2와 Gradle 5로 오면서 너무 많은 설정들이 변경되었습니다. 현재 실무에서 가장 많이 사용되는 버전들인 2.1.x와 Gradle 4를 선택할 수 밖에 없는 이유입니다.

아래를 따라 본인의 프로젝트 환경을 점검해보세요.

Gradle 버전 체크

먼저 현재 프로젝트의 그레이들 버전을 체크해봅니다.

1

위와 같이 5 버전을 사용중인게 확인된다면
인텔리제이에서 alt+F12 (윈도우/맥 동일) 을 눌러 해당 프로젝트 기준으로 터미널을 열어봅니다.
거기서 아래와 같이 명령어를 실행하시면 됩니다.

gradlew wrapper --gradle-version 4.10.2

Spring Boot 버전 체크

Spring Boot 버전은 다음과 같이 되어있어야 합니다.

build.gradle

buildscript {
    ext {
        springBootVersion = '2.1.7.RELEASE' // 2.1.7, 2.1.8, 2.1.9 다 괜찮습니다.
    }
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

아래와 같이 되어있으면 안됩니다.

plugins {
    id 'org.springframework.boot' version '2.2.1.RELEASE'
    ...
}

이외 나머지는 프로젝트 코드와 책 내용을 참고하시면 됩니다.

freelec-springboot2-webservice's People

Contributors

jojoldu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

freelec-springboot2-webservice's Issues

p.190 IndexController

...
    @GetMapping("/")
    public String index(Model model) {
        SessionUser user = (User) httpSession.getAttribute("user");
...

형변환하는 라인의 코드가 이상한 거 같습니다.. 아닌가용 ㅠ

p141. p153 index.js

p141에서는 var index = ... 로 하다가 p.153에서는 var main = ... 으로 바뀌는데
설명에는 update function을 하나 추가하겠다는 말 밖에 없어서 독자들이 약간 좀 헷갈리지않을까 싶습니다..!

p.199 그림 5-24

p.199 그림 5-24 패키지 구조를 보면
CustomOidcUserService라고 되어있는데
CustomOAuth2UserService인 것 같습니다:)

p.152 posts-update.mustache 오타

...
 <form>
            <div class="form-group">
                <label for="title">글번호</label>
                <input type="text" class="form-control" id="id" value="{{post.id}}" readonly>
            </div>
...

label for="title" 이 아니라 label for="id" 가 아닐까 싶습니다!

Spring Security & OAuth2 구현 코드 관련 질문

현재 이 코드를 참고하고 있는데요,
https://github.com/jojoldu/freelec-springboot2-webservice/blob/master/src/main/java/com/jojoldu/book/springboot/config/auth/CustomOAuth2UserService.java
의문이 들었던 부분은, Service에게 명령을 내리는 주체가 Controller가 아닌 Security라는 점이었습니다.

저에게 익숙한 구조는 Controller가 Serivce의 메서드를 구현함으로써 로직을 수행하는 것인데

  1. DispatcherServlet보다 외곽에 위치한 Security Filter가 직접적으로 Service 레이어에 접근하고
  2. Repository 등 프로그램의 내부 상태에 영향을 미치는 구조가 보안에는 문제가 없는 것일까라는 의문이 들었습니다.

이렇게 구현을 한다면 Resource 서버가 가진 User의 상태 변화를 즉각적으로 반영할 수 있다는 장점이 있을 것 같습니다.
하지만 위에 말씀드린 의문이 해결되지는 않아 혹시 다른 이유나 생각이 있다면 의견을 들어보고 싶습니다!

P.134 3번째 줄 오타

오타부분 : HTML도 결국은 규칙이 있는 문자열입니다. estRestTemplate를 통해...

T가 누락되었습니다.

P74 테스트코드에서 에러가 발생합니다.

HelloResponseDtoTest.java에서 메소드 실행 시 아래와 같은 에러가 발생합니다.


Testing started at 오후 11:08 ...

Task :cleanTest UP-TO-DATE
Task :compileJava FAILED
C:\Users\ssooy\Desktop\dev\springboot-book\src\main\java\com\ssooya\book\springboot\web\dto\HelloResponseDto.java:10: error: variable name not initialized in the default constructor
private final String name;
^
C:\Users\ssooy\Desktop\dev\springboot-book\src\main\java\com\ssooya\book\springboot\web\dto\HelloResponseDto.java:11: error: variable amount not initialized in the default constructor
private final int amount;
^
2 errors
FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':compileJava'.

Compilation failed; see the compiler error output for details.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
  • Get more help at https://help.gradle.org
    BUILD FAILED in 1s
    2 actionable tasks: 1 executed, 1 up-to-date

책에서 나온대로 진행했는데, 에러가 발생해서 구글링을 좀 해보았습니다.
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')

**annotationProcessor("org.projectlombok:lombok")
compileOnly("org.projectlombok:lombok")**

testCompile('org.springframework.boot:spring-boot-starter-test')

}

위처럼 바꾸니 정상적으로 실행이 되는데,
무엇이 문제였을까요?

그리고 2-29 테스트 결과가 앞에서 테스트한 hello_리턴된다의 이미지처럼 보입니다^^;
사용중인 환경은 아래와 같습니다.
intellij ultimate 2019.3
windows10
사용중입니다.

감사합니다.

p.s. 질문을 여기에 올리는게 맞는지 정확하게 몰라서 이곳에 남겼습니다. 혹 이곳이 아니라면 말씀해주시면 참고하겠습니다.

p.110 Junit Test 실습 오류

105page PostApiController.java 에서 save가 @PutMapping으로 되어 있는데

110page junit test 코드에는
ResponseEntity responseEntity = testRestTemplate.postForEntity(url, requestDto, Long.class);
라고 되어 있습니다.

테스트 자체가 post로 넘기니까 method 불가 에러(405)가 납니다.

Put을 Post로 바꾸던지 junit code를

HttpEntity entity = new HttpEntity(postsSaveRequestDto);
ResponseEntity responseEntity = testRestTemplate.exchange(url, HttpMethod.PUT, entity, Long.class);
로 바꿈이 좋겠네요...

초보자를 위한 책인데.. 실습코드는 문제없이 나왔으면 좋은데 아쉽네요

p198. 오타

다음과 같이 바꾸는 것이 읽기 편한 것 같아요!
LoginUserArgumentResolver가 스프링에서 인식할 수 있도록
-> LoginUserArgumentResolver '를' 스프링에서 인식할 수 있도록
-> LoginUserArgumentResolver가 스프링에서 인식 '될' 수 있도록

p.111 ApiControllerTest 작성 후 기존 HelloControllerTest 깨짐

p.111
ApiControllerTest 작성 => 전체 테스트시 HelloControllerTest 실패
관련없는 ApiController 의 빈 생성을 시도하면서 연관된 빈을 제대로 주입받지 못해 테스트가 깨집니다.
뒷장에서 추가되는건 확인했습니다만 중간중간 전체 테스트를 돌려보는 분들을 위해서
처음 작성 시 WebMvcTest의 범위를 명시해주는게 어떨까합니다.

@WebMvcTest(HelloController.class)

p101. 비지니스 로직 처리에 대한 궁금증

[블로그에 올렸던 질문을 옮겨 왔습니다.]

너무 초보적인 질문이어서 죄송합니다! 책에서 비즈니스 로직을 도메인(Entity 클래스)에 담아야 한다는 말씀은 너무나 이해가는데, 혹시 redisTemplate를 사용하는 코드는 어디에 넣으시나요? persistence 레이어 접근이라 Service에 넣어야 할 것 같기도 하고 자세한 로직은 도메인(Entity 클래스)에 담아야 할 것 같기도 해서 헷갈려 질문드려봅니다.

(1쇄 p.111) Posts 등록 API 테스트 결과

안녕하세요 개발자님!
1판 사서 열심히 따라 치고 있었는데
p.111 그림 3-15 Posts 등록 API 테스트 결과가 책이랑 다르더라구요...ㅜㅜ
image
이것은 제가 작성한 코드와 테스트 결과입니다.
image

이것은 개발자님께서 올려주신 코드입니다.

개발자님께서 깃허브에 올려주신 코드를 확인해보니 책에 나와 있는 코드하고 다르던데

앞으로도 그냥 책보다는 깃허브에 있는 코드를 보고 따라하는 것이 맞을까요?ㅜㅜ
따라가다가 갑자기 안 되니까 어느 것을 따라가야 할 지 모르겠네요ㅜㅜ

P.188 google 로그인 연동 에러

안녕하세요!!!

chapter 5에서 구글 로그인 연동하는 부분 따라하는 중인데
아래와 같은 에러가 뜨더라구요 ㅠㅠ

gradle 버전의 문제인가해서 버전을 4.대로 수정해보기도 했지만 계속 같은 에러가 발생해서 질문드립니다 ㅠㅠ


APPLICATION FAILED TO START


Description:

Method springSecurityFilterChain in org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration required a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' that could not be found.

The following candidates were found but could not be injected:
- Bean method 'clientRegistrationRepository' in 'OAuth2ClientRegistrationRepositoryConfiguration' not loaded because OAuth2 Clients Configured Condition registered clients is not available

Action:

Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.client.registration.ClientRegistrationRepository' in your configuration.

Task :Application.main() FAILED

Execution failed for task ':Application.main()'.

Process 'command '/Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1

아직 책을 마무리 짓지 못했지만 정말 많은 걸 배우고 있습니다.

정말 감사합니다.

142p. 들여쓰기

단순하지만 도움이 될까 이슈에 올려봅니다.
다음과 같이 예제에서 첫 문장을 제외하고 들여쓰기가 되어있습니다.

var init = function() {
        ....
    };

p.276 오타

....

  • character-set-filesystem
  • character-set-results
  • character-set-filesystem
    ...

character-set-filesystem 이 두 개 적혀있슴다

질문. @LoginUser 전까지 실습을 진행했는데, 궁금한 부분이 있습니다!

public class CustomOAuth2UserService {
...
@Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
 httpSession.setAttribute("user", new SessionUser(user));
}
...
}
public class IndexController {
...
 @GetMapping("/")
    public String index(Model model) {
...
        User user = (User) httpSession.getAttribute("user");

        if(user != null) {
            model.addAttribute("userName", user.getName());
        }
...
    }
...
}

책에서는
CustomOAuth2UserService클래스에는 세션에 SessionUser 타입을 담고,
IndexController 클래스에는 세션에서 꺼냈는데 이걸 SessionUser타입으로 형변환을 하지 않고 User타입으로 형변환하는데..(#22 ) 이렇게하면 500에러가 납니다 ㅠ

SessionUser타입으로 형변환해서 SessionUser 타입으로 받으면 잘 작동됩니다.. 실습오류인지 ㅠ 아니면 제가 뭘 잘못하고있는건지 궁금합니다 어딜 봐야될까요?

p.115 // when부분 HttpMehod.PUT 오타

p.115

// when
 ResponseEntity<Long> responseEntity = restTemplate.exchange(url, 
HttpMethod.PUT, requestEntity, Long.class);

HttpMethod.PUT으로 적혀있습니다. -> HttpMethod.POST로 정정 부탁드립니다:)

항상 블로그 잘 보고 있습니다. 책에 설명이 쉽게 되어 있어서 이해가 잘됩니다. 감사합니다!

p.100 properties에 코드 추가후 테스트 오류

p.100
application.properties에
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
설정후 테스트 진행하면 아래 오류가 뜹니다
일단 무시하고 책보면서 따라해보지만 아래 오류 때문에 진도가 안나가네요.. ㅠ
따로 뭘 더 설치해야하는지...

Multiple Failures (2 failures)
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into posts (author, content, title) values (?, ?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select posts0_.id as id1_0_, posts0_.author as author2_0_, posts0_.content as content3_0_, posts0_.title as title4_0_ from posts posts0_]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [insert into posts (author, content, title) values (?, ?, ?)]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [select posts0_.id as id1_0_, posts0_.author as author2_0_, posts0_.content as content3_0_, posts0_.title as title4_0_ from posts posts0_]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
at org.junit.vintage.engine.execution.TestRun.getStoredResultOrSuccessful(TestRun.java:179)
at org.junit.vintage.engine.execution.RunListenerAdapter.fireExecutionFinished(RunListenerAdapter.java:211)
at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:177)
at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:76)
at org.junit.runner.notification.SynchronizedRunListener.testFinished(SynchronizedRunListener.java:56)
at org.junit.runner.notification.RunNotifier$7.notifyListener(RunNotifier.java:190)
at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:72)
at org.junit.runner.notification.RunNotifier.fireTestFinished(RunNotifier.java:187)
at org.junit.internal.runners.model.EachTestNotifier.fireTestFinished(EachTestNotifier.java:38)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:331)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:40)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:71)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:92)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$100(JUnitPlatformTestClassProcessor.java:77)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:73)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:131)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.base/java.lang.Thread.run(Thread.java:834)

63page 테스트 오류가 뭔지 모르겠습니다.

image

환경은 window 10, intellij ultimate입니다.

gradle 4.12로 다운그레이드를 하였고, SETTIING에서 인코딩도 UTF8로 하였는데

빌드창에 한글 깨짐으로 나오는데 이유가 뭘까요 ㅜㅜ

p.109 PostsApiControllerTest 통과 실패

Error while extracting response for type [class java.lang.Long] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 1]
org.springframework.web.client.RestClientException: Error while extracting response for type [class java.lang.Long] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 1]
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:117)
	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:994)
	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:977)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:737)
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)
	at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:445)
	at org.springframework.boot.test.web.client.TestRestTemplate.postForEntity(TestRestTemplate.java:489)
	at kr.gracelove.jojoldu.springboot.web.PostsApiControllerTest.Posts_등록된다(PostsApiControllerTest.java:57)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
	at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
	at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
	at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:117)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
	at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
	at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 1]
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:102)
	... 63 more
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Long` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 1, column: 1]
	at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
	at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1343)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1139)
	at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1093)
	at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$LongDeserializer._parseLong(NumberDeserializers.java:593)
	at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$LongDeserializer.deserialize(NumberDeserializers.java:557)
	at com.fasterxml.jackson.databind.deser.std.NumberDeserializers$LongDeserializer.deserialize(NumberDeserializers.java:535)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3084)
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:239)
	... 65 more

kr.gracelove.jojoldu.springboot.web.PostsApiControllerTest > Posts_등록된다 FAILED
    org.springframework.web.client.RestClientException at PostsApiControllerTest.java:57
        Caused by: org.springframework.http.converter.HttpMessageNotReadableException at PostsApiControllerTest.java:57
            Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException at PostsApiControllerTest.java:57

PostsApiController의 save 메소드를
@PutMapping -> @PostMapping 으로 바꾸니까 됩니다~

P.281 보안그룹

그림 7-24 EC2의 보안 그룹 복사라고 되어 있는데요.

보안 그룹메뉴로 들어가면 default VPC security group 이라고만 되어 있고 Name은 Blank로 되어 있는데요. 이 부분을 EC2 보안 그룹으로 보면 되나요?

p.53 톰캣 오타

아래에서 5번째 줄 "왜 계속 톰갯을 내렸다가 다시 실행하는 일을 반복할까요?" 에서 "톰갯" 오타인 것 같습니다!

p.111에 나오는 PostsApiController.java의 update메소드 인자 PostsUpdateRequestDto

@PutMapping("/api/v1/posts/{id}
public Long update(@PathVariable Long id, @RequestBody **PostsUpdateRequestDto** requestDto) {
   ...
}

책에는 PostsUpdateRequestDto소스코드가 없는 거 같아요.. 제가 못찾은 걸까요 ㅠ

** Posts 클래스의 update메소드도 구현부분이 없습니다. 나중에 확인 편하게 하시라고 본문에 추가합니다

p.207 application-oauth.properties 내용 오타인건가용

spring.security.oauth2.client.provider.naver.authorization_uri=...........
책에는 이렇게 적혀있는데

자동완성에서는 authorization-uri 라고 나타납니다 (언더바 - 대시)
상관없는 건가용~~?
(지금 확인해보니까 그 밑에 있는 코드들도 자동완성에서는 '-' 로 되는데, 책에는 '_'로 되어있네용~)

P.276 collation_server

collation_server 와 collation_connection은 utf8mb4_unicode_ci 로 변경하면 되나요?

P74 AssertJ 설명 부분 오타

안녕하세요! P.74

QR코드 옆 assertJ의 자세한 설명 참고 부분에

백기선님의 유투브 'ssertJ가 JUnit의....' 로 a가 빠져있습니다.

사소한 오타라 조심스럽게 공유드립니다.

P71 HelloResponseDto 클래스명 오타

본문에서 (그림2-27 바로 위) 이 패키지에 HelloReponseDto를 생성합니다. 라고 적혀있고
그림 2-27에서는 HelloResponseDto 클래스를 생성했네요!

단순한 오타인것 같습니다. 아마 본문의 글이 's'를 빼먹은 단순한 오타인것 같지만 !! (글 읽는데에는 문제가 없었습니다) 혹시나 싶어 글 남깁니다.

현재 책 읽으면서 많은 도움 받고있습니다. 완전히 제것으로 만들어서 다른 웹사이트도 만들어보고싶습니다.

p.153 오타

안녕하세요:)
(#38)과 비슷한 오타가 p.153에도 있어서 제보드립니다.

코드설명 ①에 {post.id}} 라고 되어있는데 { 가 하나 빠진 것 같습니다:)

좋은 책 만들어 주셔서 감사합니다!

p101. 오타

맨 아랫줄에 @Transactionl -> @transactional
으로 오타가 있습니다~!

책 읽고 있는데 너무 너무 잘 쓰셨네요.
제가 본 스프링부트 서적 중에 제일 잘 읽히고 좋습니다!! ㅎㅎ

p.190,195 코드 오타

190 페이지 IndexController 클래스 수정하는 부분에서,

SessionUser user = (User) httpSession.getAttribute("user");
-> SessionUser user = (SessionUser) httpSession.getAttribute("user");

타입 캐스팅이 잘못됐습니다.

195 페이지도 가운데 인용문 부분에서 User -> SessionUser로 바뀌어야 될 거 같습니다.

p.208 오타

private static OAuthAttributes ofNaver(...){
...
     .picture((String) response.get("profileImage")) 
...
    .picture((String) response.get("profile_image")) 

로 수정되어야 할 것 같습니다.

P111 PostsUpdateRequestDto 누락건

안녕하세요~ 1쇄 구매자입니다

@PutMapping("/api/v1/posts/{id}")
public Long update(@PathVariable Long id, @RequestBody PostsUpdateRequestDto requestDto){
    return postsService.update(id, requestDto);
}

여기에서 PostsUpdateRequestDto 클래스를 찾을 수 없네요 ㅠㅠ
git code에서 따와서 실습 하고있습니다.

p.206 네이버 로그인 application-oauth.properties 관련

p.206 네이버 로그인 application-oauth.properties 파일

기존) spring.security.oauth2.client.registration.naver.redirect_uri_template={baseUrl}/{action}/oauth2/code/{registrationId}

변경) spring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}

네이버 로그인 테스트 중에 기존 코드대로 로그인이 안되서 아래 방법으로 로그인 성공해서 이슈 등록 합니다.

p.113 IllegalArgumentException 메시지 문의

안녕하세요! 책 구입하여 잘 보고 있습니다!

p.113 페이지의 PostService 구현 관련하여 문의드릴 것이 있습니다!

    @Transactional
    public Long update(Long id, PostsUpdateRequestDto requestDto) {
        Posts posts = postsRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다. id=" + id));

        posts.update(requestDto.getTitle(), requestDto.getContent());

        return id;
    }

    @Transactional
    public void delete (Long id) {
        Posts posts = postsRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다. id=" + id));

        postsRepository.delete(posts);
    }

    @Transactional(readOnly = true)
    public PostsResponseDto findById(Long id) {
        Posts entity = postsRepository.findById(id)
                .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다. id=" + id));

        return new PostsResponseDto(entity);
    }

위 코드에서 Exception throw 할 때 메시지가 사용자가 아닌 게시글이 맞다고 생각되어 말씀드립니다.

id를 게시글(posts)의 id로 이해했는데 에러 메시지는 사용자로 적혀있어서요!

사소한 부분인데 제가 잘못 이해했나 싶은 마음에 문의드립니다 :)

(X)

h2 console로 posts 데이터 조회 시 조회 API를 요청한다고 써있는데, 요청 API 코드가 없는 것 같습니다!

@GetMapping("/api/v1/posts/{id}")
public PostsResponseDto findById(@PathVariable Long id) {
    return postsService.findById(id);
}

질문 - save() vs Transactional

@transactional에 대해 찾아보던 중 의문이 생겨 질문드립니다!

JPA 엔티티를 업데이트할 때 Dirty Checking을 지원해 트랜잭션 안에서는 save를 명시적으로 호출하지 않아도 commit 시에 판단해서 업데이트해준다고 알고 있습니다.

@Transactional
public Notice update(Long noticeId, String content) {
    Notice notice = noticeRepository.findById(noticeId).get();
    notice.setContent(content);
}

위의 코드와 아래의 코드의 차이가 뭔지 궁금합니다. (여러 repository를 접근하는 코드가 있을 시 Transactional을 명시해주지 않으면 해당 접근하는 코드마다 트랜잭션 단위가 설정되나 어노테이션을 선언하면 해당 메소드 내의 명령문을 원자적으로 처리해준다고 이해했는데 맞는 것인지..)

public Notice update(Long noticeId, String content) {
    Notice notice = noticeRepository.findById(noticeId).get();
    notice.setContent(content);
    noticeRepository.save(notice);
}
  1. 생성 코드에서 save를 하고 있는데도 Transactional을 붙이신 이유가 궁금합니다.
@Transactional
public Long save(PostsSaveRequestDto requestDto) {
    return postsRepository.save(requestDto.toEntity()).getId();
}
  1. 목록 조회 시 Transactional을 붙이면 조회 속도가 왜 개선되고 트랜잭션 범위를 유지해야 하는 이유는 무엇인지 궁금합니다!
@Transactional(readOnly = true)
public PostsResponseDto findById(Long id) {
    Posts entity = postsRepository.findById(id)
            .orElseThrow(() -> new IllegalArgumentException("해당 사용자가 없습니다. id=" + id));

    return new PostsResponseDto(entity);
}

p.99 그림 3-11 이 잘못 첨부된것 같습니다..

p.99에 그림 3-11 쿼리 로그 확인 그림에 중간에 메시지가 Hibernate: create table posts (id bigint not null auto_increment, author varchar(255), cont ...로 나와있는데, 해당 부분까지 코드 실행했을때나, 도서 하단의 설명에 따르면 id bigint generated by default as identity라는 옵션이 나오는게 정상..?! 같습니다ㅠ

혹시나 제가 따라오다가 뭘 잘못쳤나 하고, 올려주신 예제 코드 clone후 이부분 스냅샷까지 Checkout 한 뒤에, 동일한 테스트코드 실행해도 Hibernate: create table posts (id bigint generated by default as identity,라는 메시지가 발생 해서 혹시나 하고 이슈 올려봅니다..!

엉뚱한걸 찾아서 이슈올린거라면 바쁘신데 죄송합니다...

P276 오타

중간에 8가지 나열(중복1개 포함)을 보면 전부 바로 표시되어 있는데요.

  • character-set-client

라고 적혀있는데요.

아래 스크린샷에서 보면 언더바로 표시되어 있습니다.
character_set_client

aws 가보니 언더바가 맞는것 같아요.

p.299 deploy.sh 생성경로 오타

책 잘 보고 있습니다!

다름이 아니라 299페이지 14번째 줄

vim ~/app/git/deploy.sh를

바로 윗 줄에 쓰여진 대로
vim ~/app/step1/deploy.sh로 바꿔야 될 것 같습니당

P.105 @PutMapping("/api/v1/posts")

페이지 144 게시글 등록 실습 하다보니 오타가 있는거 같습니다~

P.105 PostsApiController
@PutMapping("/api/v1/posts")
-> @PostMapping("/api/v1/posts")

p.36~37 build.gradle 코드에 특이점이 있는것 같습니다..

p.33p.34repositories{ }jcenter()를 추가하도록 코드가 적혀있고, p.35 중간 문맥에

여기서는 mavenCentral, jcenter 둘 다 등록해서 사용하겠습니다.

로 되어있는데, p.36~37에 전체코드에서는 빌드스크립트 내부 및 하단 repositories{ }에는 jcenter()가 누락되어있네요..

P.146 오타

안녕하세요. 1쇄 구독자입니다.
코드설명에

  1. {#posts}}
    라고 쓰여져 있는데요. {{#posts}} 가 아닐까 합니다.

  2. {id}} 등의 {{변수명}}
    이것도 {{id}} 가 아닐까 하네요.

p.58 애플리케이션 오타

p.58 아래 추가된 내용에 "대표적인 WAS인 톰캣 역시 서블릿으로 이루어진 자바 애플이케이션입니다." 에서 "애플이케이션" 오타인 것 같습니다!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.