Skip to content

Commit 4f5e127

Browse files
committed
Align with Boot 2.0.0.M4
1 parent 65b791a commit 4f5e127

File tree

134 files changed

+1322
-1511
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

134 files changed

+1322
-1511
lines changed

1/part1/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// tag::buildscript[]
22
buildscript {
33
ext {
4-
springBootVersion = '2.0.0.BUILD-SNAPSHOT'
4+
springBootVersion = '2.0.0.M4'
55
}
66
repositories {
77
mavenCentral()
@@ -38,6 +38,8 @@ repositories {
3838
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
3939
}
4040

41+
ext['thymeleaf-spring5.version'] = '3.0.8-SNAPSHOT'
42+
4143
// tag::deps[]
4244
dependencies {
4345
compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')

10/part1/chat/build.gradle

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// tag::propdeps-plugin-1[]
22
buildscript {
33
ext {
4-
springBootVersion = '2.0.0.BUILD-SNAPSHOT'
4+
springBootVersion = '2.0.0.M4'
55
springCloudVersion = 'Finchley.BUILD-SNAPSHOT'
6+
springCloudStreamVersion = 'Elmhurst.M1'
67
}
78
repositories {
89
mavenCentral()
@@ -57,8 +58,11 @@ configurations {
5758
all*.exclude group: 'org.springframework', module: 'spring-webmvc'
5859
}
5960

61+
ext['thymeleaf-spring5.version'] = '3.0.8-SNAPSHOT'
62+
6063
dependencies {
6164
compile('org.springframework.boot:spring-boot-starter-webflux')
65+
compile('org.synchronoss.cloud:nio-multipart-parser:1.1.0')
6266
compile('org.springframework.boot:spring-boot-starter-actuator')
6367
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
6468
compile('org.springframework.boot:spring-boot-devtools')
@@ -69,24 +73,15 @@ dependencies {
6973
compile('org.springframework.cloud:spring-cloud-starter-hystrix')
7074
compile('org.springframework.cloud:spring-cloud-starter-config')
7175

72-
compile('org.webjars:requirejs:2.2.0')
73-
compile('org.webjars.npm:stompjs:2.3.3') {
74-
exclude module: 'websocket' // We are using SockJS for websocket functionality
75-
}
76-
compile('org.webjars.bower:sockjs-client:1.1.0')
77-
76+
compile('org.springframework.security:spring-security-config')
7877
compile('org.springframework.security:spring-security-webflux')
7978

80-
compile('org.springframework.session:spring-session-data-mongodb:2.0.0.BUILD-SNAPSHOT')
79+
compile('org.springframework.session:spring-session-data-mongodb:2.0.0.M3')
8180

8281
// tag::zuul[]
8382
compile('org.springframework.cloud:spring-cloud-starter-gateway')
8483
// end::zuul[]
8584

86-
// tag::thymeleaf-security[]
87-
compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity4:2.1.3.RELEASE')
88-
// end::thymeleaf-security[]
89-
9085
// tag::configuration-processor[]
9186
optional "org.springframework.boot:spring-boot-configuration-processor"
9287
// end::configuration-processor[]
@@ -101,5 +96,6 @@ compileJava.dependsOn(processResources)
10196
dependencyManagement {
10297
imports {
10398
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
99+
mavenBom "org.springframework.cloud:spring-cloud-stream-dependencies:${springCloudStreamVersion}"
104100
}
105101
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.greglturnquist.learningspringboot.chat;
17+
18+
import java.security.Principal;
19+
20+
import reactor.core.publisher.Mono;
21+
22+
import org.springframework.security.core.Authentication;
23+
import org.springframework.web.reactive.socket.WebSocketHandler;
24+
import org.springframework.web.reactive.socket.WebSocketSession;
25+
26+
/**
27+
* @author Greg Turnquist
28+
*/
29+
// tag::code[]
30+
abstract class AuthorizedWebSocketHandler
31+
implements WebSocketHandler {
32+
33+
@Override
34+
public final Mono<Void> handle(WebSocketSession session) {
35+
return session.getHandshakeInfo().getPrincipal()
36+
.filter(this::isAuthorized)
37+
.then(doHandle(session));
38+
}
39+
40+
private boolean isAuthorized(Principal principal) {
41+
Authentication authentication = (Authentication) principal;
42+
return authentication.isAuthenticated() &&
43+
authentication.getAuthorities().contains("ROLE_USER");
44+
}
45+
46+
abstract protected Mono<Void> doHandle(
47+
WebSocketSession session);
48+
}
49+
// end::code[]
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.greglturnquist.learningspringboot.chat;
17+
18+
import org.springframework.cloud.stream.annotation.Input;
19+
import org.springframework.cloud.stream.annotation.Output;
20+
import org.springframework.messaging.MessageChannel;
21+
import org.springframework.messaging.SubscribableChannel;
22+
23+
/**
24+
* @author Greg Turnquist
25+
*/
26+
// tag::code[]
27+
public interface ChatServiceStreams {
28+
29+
String NEW_COMMENTS = "newComments";
30+
String CLIENT_TO_BROKER = "clientToBroker";
31+
String BROKER_TO_CLIENT = "brokerToClient";
32+
33+
String USER_HEADER = "User";
34+
35+
@Input(NEW_COMMENTS)
36+
SubscribableChannel newComments();
37+
38+
@Output(CLIENT_TO_BROKER)
39+
MessageChannel clientToBroker();
40+
41+
@Input(BROKER_TO_CLIENT)
42+
SubscribableChannel brokerToClient();
43+
}
44+
// end::code[]

10/part1/chat/src/main/java/com/greglturnquist/learningspringboot/chat/CommentService.java

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,64 @@
1717

1818
import org.slf4j.Logger;
1919
import org.slf4j.LoggerFactory;
20+
import reactor.core.publisher.Flux;
21+
import reactor.core.publisher.FluxSink;
22+
import reactor.core.publisher.Mono;
2023
import org.springframework.cloud.stream.annotation.EnableBinding;
2124
import org.springframework.cloud.stream.annotation.StreamListener;
22-
import org.springframework.cloud.stream.messaging.Sink;
23-
import org.springframework.messaging.simp.SimpMessagingTemplate;
2425
import org.springframework.stereotype.Service;
26+
import org.springframework.web.reactive.socket.WebSocketSession;
27+
28+
import com.fasterxml.jackson.core.JsonProcessingException;
29+
import com.fasterxml.jackson.databind.ObjectMapper;
2530

2631
/**
2732
* @author Greg Turnquist
2833
*/
2934
// tag::code[]
3035
@Service
31-
@EnableBinding(Sink.class)
32-
public class CommentService {
36+
@EnableBinding(ChatServiceStreams.class)
37+
public class CommentService extends AuthorizedWebSocketHandler {
3338

34-
private final static Logger log = LoggerFactory.getLogger(CommentService.class);
39+
private final static Logger log =
40+
LoggerFactory.getLogger(CommentService.class);
3541

36-
private final SimpMessagingTemplate simpMessagingTemplate;
42+
private ObjectMapper mapper;
43+
private Flux<Comment> flux;
44+
private FluxSink<Comment> webSocketCommentSink;
3745

38-
public CommentService(SimpMessagingTemplate simpMessagingTemplate) {
39-
this.simpMessagingTemplate = simpMessagingTemplate;
46+
CommentService(ObjectMapper mapper) {
47+
this.mapper = mapper;
48+
this.flux = Flux.<Comment>create(
49+
emitter -> this.webSocketCommentSink = emitter,
50+
FluxSink.OverflowStrategy.IGNORE)
51+
.publish()
52+
.autoConnect();
4053
}
4154

42-
@StreamListener(Sink.INPUT)
55+
@StreamListener(ChatServiceStreams.NEW_COMMENTS)
4356
public void broadcast(Comment comment) {
44-
log.info("Publishing " + comment.toString() + " to websocket...");
45-
simpMessagingTemplate.convertAndSend("/topic/comments.new", comment);
57+
if (webSocketCommentSink != null) {
58+
log.info("Publishing " + comment.toString() +
59+
" to websocket...");
60+
webSocketCommentSink.next(comment);
61+
}
4662
}
4763

64+
@Override
65+
public Mono<Void> doHandle(WebSocketSession session) {
66+
return session.send(this.flux
67+
.map(comment -> {
68+
try {
69+
return mapper.writeValueAsString(comment);
70+
} catch (JsonProcessingException e) {
71+
throw new RuntimeException(e);
72+
}
73+
})
74+
.log("encode-as-json")
75+
.map(session::textMessage)
76+
.log("wrap-as-websocket-message"))
77+
.log("publish-to-websocket");
78+
}
4879
}
4980
// end::code[]
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.greglturnquist.learningspringboot.chat;
17+
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
import org.springframework.cloud.gateway.filter.factory.WebFilterFactory;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.tuple.Tuple;
25+
import org.springframework.web.server.WebFilter;
26+
import org.springframework.web.server.WebSession;
27+
28+
/**
29+
* @author Greg Turnquist
30+
*/
31+
// tag::code[]
32+
@Configuration
33+
public class GatewayConfig {
34+
35+
private static final Logger log =
36+
LoggerFactory.getLogger(GatewayConfig.class);
37+
38+
/**
39+
* Force the current WebSession to get saved
40+
*/
41+
static class SaveSessionWebFilterFactory
42+
implements WebFilterFactory {
43+
@Override
44+
public WebFilter apply(Tuple args) {
45+
return (exchange, chain) -> exchange.getSession()
46+
.map(webSession -> {
47+
log.debug("Session id: " + webSession.getId());
48+
webSession.getAttributes().entrySet()
49+
.forEach(entry ->
50+
log.debug(entry.getKey() + " => " +
51+
entry.getValue()));
52+
return webSession;
53+
})
54+
.map(WebSession::save)
55+
.then(chain.filter(exchange));
56+
}
57+
}
58+
59+
@Bean
60+
SaveSessionWebFilterFactory saveSessionWebFilterFactory() {
61+
return new SaveSessionWebFilterFactory();
62+
}
63+
}
64+
// end::code[]

10/part1/chat/src/main/java/com/greglturnquist/learningspringboot/chat/HomeController.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
*/
1616
package com.greglturnquist.learningspringboot.chat;
1717

18+
import org.springframework.security.core.Authentication;
19+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1820
import org.springframework.stereotype.Controller;
21+
import org.springframework.ui.Model;
1922
import org.springframework.web.bind.annotation.GetMapping;
2023

2124
/**
@@ -24,9 +27,12 @@
2427
@Controller
2528
public class HomeController {
2629

30+
// tag::code[]
2731
@GetMapping("/")
28-
public String index() {
32+
public String index(@AuthenticationPrincipal Authentication auth, Model model) {
33+
model.addAttribute("authentication", auth);
2934
return "index";
3035
}
36+
// end::code[]
3137

3238
}

0 commit comments

Comments
 (0)