Update README.md

This commit is contained in:
johnA1331
2019-10-30 22:12:05 +08:00
committed by GitHub
parent db85c8f275
commit 33998bdac8
20533 changed files with 1642695 additions and 0 deletions
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>svc-book</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>svc-book</name>
<parent>
<artifactId>parent-boot-1</artifactId>
<groupId>com.baeldung</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../../parent-boot-1</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<spring-cloud-dependencies.version>Dalston.RELEASE</spring-cloud-dependencies.version>
</properties>
</project>
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.bootstrap.svcbook;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.sleuth.metric.SpanMetricReporter;
import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter;
import org.springframework.cloud.sleuth.zipkin.ZipkinProperties;
import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import zipkin.Span;
@SpringBootApplication
@EnableEurekaClient
public class BookServiceApplication {
@Autowired
private EurekaClient eurekaClient;
@Autowired
private SpanMetricReporter spanMetricReporter;
@Autowired
private ZipkinProperties zipkinProperties;
@Value("${spring.sleuth.web.skipPattern}")
private String skipPattern;
public static void main(String[] args) {
SpringApplication.run(BookServiceApplication.class, args);
}
@Bean
public ZipkinSpanReporter makeZipkinSpanReporter() {
return new ZipkinSpanReporter() {
private HttpZipkinSpanReporter delegate;
private String baseUrl;
@Override
public void report(Span span) {
InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false);
if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) {
baseUrl = instance.getHomePageUrl();
delegate = new HttpZipkinSpanReporter(new RestTemplate(), baseUrl, zipkinProperties.getFlushInterval(), spanMetricReporter);
if (!span.name.matches(skipPattern)) delegate.report(span);
}
}
};
}
}
@@ -0,0 +1,25 @@
package com.baeldung.spring.cloud.bootstrap.svcbook;
import com.baeldung.spring.cloud.bootstrap.svcbook.book.Book;
import com.baeldung.spring.cloud.bootstrap.svcbook.book.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
public class DataLoader implements ApplicationRunner {
private BookService bookService;
@Autowired
public DataLoader(BookService bookService) {
this.bookService = bookService;
}
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
this.bookService.createBook(new Book("Aldous Huxley", "Brave new world"));
this.bookService.createBook(new Book("George Orwell", "Animal Farm"));
}
}
@@ -0,0 +1,36 @@
package com.baeldung.spring.cloud.bootstrap.svcbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal1(AuthenticationManagerBuilder auth) throws Exception {
//try in memory auth with no users to support the case that this will allow for users that are logged in to go anywhere
auth.inMemoryAuthentication();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic()
.disable()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/books").permitAll()
.antMatchers(HttpMethod.GET, "/books/*").permitAll()
.antMatchers(HttpMethod.POST, "/books").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/books/*").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/books/*").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.csrf()
.disable();
}
}
@@ -0,0 +1,10 @@
package com.baeldung.spring.cloud.bootstrap.svcbook;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;
@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer {
}
@@ -0,0 +1,50 @@
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String author;
private String title;
public Book() {
}
public Book(String author, String title) {
this.author = author;
this.title = title;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
@@ -0,0 +1,53 @@
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping
public List<Book> findAllBooks() {
return bookService.findAllBooks();
}
@GetMapping("/{bookId}")
public Book findBook(@PathVariable Long bookId) {
return bookService.findBookById(bookId);
}
@PostMapping
public Book createBook(@RequestBody Book book) {
return bookService.createBook(book);
}
@DeleteMapping("/{bookId}")
public void deleteBook(@PathVariable Long bookId) {
bookService.deleteBook(bookId);
}
@PutMapping("/{bookId}")
public Book updateBook(@RequestBody Book book, @PathVariable Long bookId) {
return bookService.updateBook(book, bookId);
}
@PatchMapping("/{bookId}")
public Book updateBook(@RequestBody Map<String, String> updates, @PathVariable Long bookId) {
return bookService.updateBook(updates, bookId);
}
}
@@ -0,0 +1,11 @@
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
class BookNotFoundException extends RuntimeException {
BookNotFoundException(String message) {
super(message);
}
}
@@ -0,0 +1,6 @@
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
import org.springframework.data.jpa.repository.JpaRepository;
interface BookRepository extends JpaRepository<Book, Long>{
}
@@ -0,0 +1,66 @@
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.base.Preconditions;
@Service
@Transactional(readOnly = true)
public class BookService {
@Autowired
private BookRepository bookRepository;
public List<Book> findAllBooks() {
return bookRepository.findAll();
}
public Book findBookById(Long bookId) {
return Optional.ofNullable(bookRepository.findOne(bookId))
.orElseThrow(() -> new BookNotFoundException("Book not found. ID: " + bookId));
}
@Transactional(propagation = Propagation.REQUIRED)
public Book createBook(Book book) {
final Book newBook = new Book();
newBook.setTitle(book.getTitle());
newBook.setAuthor(book.getAuthor());
return bookRepository.save(newBook);
}
@Transactional(propagation = Propagation.REQUIRED)
public void deleteBook(Long bookId) {
bookRepository.delete(bookId);
}
@Transactional(propagation = Propagation.REQUIRED)
public Book updateBook(Map<String, String> updates, Long bookId) {
final Book book = findBookById(bookId);
updates.keySet()
.forEach(key -> {
switch (key) {
case "author":
book.setAuthor(updates.get(key));
break;
case "title":
book.setTitle(updates.get(key));
}
});
return bookRepository.save(book);
}
@Transactional(propagation = Propagation.REQUIRED)
public Book updateBook(Book book, Long bookId) {
Preconditions.checkNotNull(book);
Preconditions.checkState(book.getId() == bookId);
Preconditions.checkNotNull(bookRepository.findOne(bookId));
return bookRepository.save(book);
}
}
@@ -0,0 +1,7 @@
spring.cloud.config.name=book-service
spring.cloud.config.discovery.service-id=config
spring.cloud.config.discovery.enabled=true
spring.cloud.config.username=configUser
spring.cloud.config.password=configPassword
eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@@ -0,0 +1,23 @@
package org.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.baeldung.spring.cloud.bootstrap.svcbook.BookServiceApplication;
/**
*
* This Live Test requires:
* * A Redis instance running in port 6379 (e.g. using `docker run --name some-redis -p 6379:6379 -d redis`)
*
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BookServiceApplication.class)
public class SpringContextLiveTest {
@Test
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
}
}
@@ -0,0 +1,2 @@
# This property would be provided by the config service in a real-case scenario
spring.sleuth.web.skipPattern=(^cleanup.|.+favicon.)