BAEL-684 Adding spring JPA to resource servers
This commit is contained in:
parent
5f0f26e374
commit
2ee0a8a7a1
|
@ -1,69 +0,0 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
public class GatewayApplicationLiveTest {
|
||||
|
||||
@Test
|
||||
public void testAccess() throws Exception {
|
||||
TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||
String testUrl = "http://localhost:8080";
|
||||
|
||||
ResponseEntity<String> response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//try the protected resource and confirm the redirect to login
|
||||
response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class);
|
||||
Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode());
|
||||
Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0));
|
||||
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "user");
|
||||
form.add("password", "password");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//request the admin protected resource to determine it is still protected
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings/all", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
|
||||
|
||||
//login as the admin
|
||||
form.clear();
|
||||
form.add("username", "admin");
|
||||
form.add("password", "admin");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings/all", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//request the discovery resources as the admin
|
||||
response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.gateway;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
public class IntegrationTest {
|
||||
|
||||
private TestRestTemplate testRestTemplate = new TestRestTemplate();
|
||||
private String testUrl = "http://localhost:8080";
|
||||
|
||||
@Test
|
||||
public void testAccess() throws Exception {
|
||||
ResponseEntity<String> response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//try the protected resource and confirm the redirect to login
|
||||
response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class);
|
||||
Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode());
|
||||
Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0));
|
||||
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "user");
|
||||
form.add("password", "password");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
HttpEntity<String> httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
addBook();
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
addRatings();
|
||||
|
||||
//request the admin protected resource to determine it is still protected
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
|
||||
|
||||
//login as the admin
|
||||
form.clear();
|
||||
form.add("username", "admin");
|
||||
form.add("password", "admin");
|
||||
response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
httpEntity = new HttpEntity<>(headers);
|
||||
|
||||
//request the protected resource
|
||||
response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
Assert.assertNotNull(response.getBody());
|
||||
|
||||
//request the discovery resources as the admin
|
||||
response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class);
|
||||
Assert.assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
}
|
||||
|
||||
private void addRatings() {
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "user");
|
||||
form.add("password", "password");
|
||||
ResponseEntity<String> response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType());
|
||||
Rating rating = new Rating(1L, 4);
|
||||
|
||||
HttpEntity<Rating> httpEntity = new HttpEntity<>(rating, headers);
|
||||
|
||||
//request the protected resource
|
||||
ResponseEntity<Rating> bookResponse = testRestTemplate.postForEntity(testUrl + "/rating-service/ratings", httpEntity, Rating.class);
|
||||
Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode());
|
||||
Assert.assertEquals(rating.getBookId(), bookResponse.getBody().getBookId());
|
||||
Assert.assertEquals(rating.getStars(), bookResponse.getBody().getStars());
|
||||
}
|
||||
|
||||
private void addBook(){
|
||||
//login as user/password
|
||||
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
|
||||
form.add("username", "admin");
|
||||
form.add("password", "admin");
|
||||
ResponseEntity<String> response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class);
|
||||
|
||||
//extract the session from the cookie and propagate it to the next request
|
||||
String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0];
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Cookie", sessionCookie);
|
||||
headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType());
|
||||
Book book = new Book("Baeldung", "How to spring cloud");
|
||||
|
||||
HttpEntity<Book> httpEntity = new HttpEntity<>(book, headers);
|
||||
|
||||
//request the protected resource
|
||||
ResponseEntity<Book> bookResponse = testRestTemplate.postForEntity(testUrl + "/book-service/books", httpEntity, Book.class);
|
||||
Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode());
|
||||
Assert.assertEquals(book.getAuthor(), bookResponse.getBody().getAuthor());
|
||||
Assert.assertEquals(book.getTitle(), bookResponse.getBody().getTitle());
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Book {
|
||||
|
||||
private Long id;
|
||||
private String author;
|
||||
private String title;
|
||||
|
||||
public Book() {
|
||||
}
|
||||
|
||||
public Book(String author, String title) {
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Rating {
|
||||
private Long id;
|
||||
private Long bookId;
|
||||
private int stars;
|
||||
|
||||
public Rating() {
|
||||
}
|
||||
|
||||
public Rating(Long bookId, int stars) {
|
||||
this.bookId = bookId;
|
||||
this.stars = stars;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getBookId() {
|
||||
return bookId;
|
||||
}
|
||||
|
||||
public void setBookId(Long bookId) {
|
||||
this.bookId = bookId;
|
||||
}
|
||||
|
||||
public int getStars() {
|
||||
return stars;
|
||||
}
|
||||
|
||||
public void setStars(int stars) {
|
||||
this.stars = stars;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -42,6 +42,17 @@
|
|||
<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.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
|
|
@ -3,35 +3,11 @@ package com.baeldung.spring.cloud.bootstrap.svcbook;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@RestController
|
||||
@RequestMapping("/books")
|
||||
public class BookServiceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BookServiceApplication.class, args);
|
||||
}
|
||||
|
||||
private List<Book> bookList = Arrays.asList(
|
||||
new Book(1L, "Baeldung goes to the market", "Tim Schimandle"),
|
||||
new Book(2L, "Baeldung goes to the park", "Slavisa")
|
||||
);
|
||||
|
||||
@GetMapping("")
|
||||
public List<Book> findAllBooks() {
|
||||
return bookList;
|
||||
}
|
||||
|
||||
@GetMapping("/{bookId}")
|
||||
public Book findBook(@PathVariable Long bookId) {
|
||||
return bookList.stream().filter(b -> b.getId().equals(bookId)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ 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;
|
||||
|
@ -22,8 +23,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
http.httpBasic()
|
||||
.disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/books").permitAll()
|
||||
.antMatchers("/books/*").hasAnyRole("USER", "ADMIN")
|
||||
.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()
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcbook;
|
||||
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(Long id, String title, String author) {
|
||||
this.id = id;
|
||||
this.author = author;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Book() {
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@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,55 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcbook.book;
|
||||
|
||||
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 java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@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) {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,17 @@
|
|||
<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.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
|
|
@ -3,39 +3,11 @@ package com.baeldung.spring.cloud.bootstrap.svcrating;
|
|||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@RestController
|
||||
@RequestMapping("/ratings")
|
||||
public class RatingServiceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RatingServiceApplication.class, args);
|
||||
}
|
||||
|
||||
private List<Rating> ratingList = Arrays.asList(
|
||||
new Rating(1L, 1L, 2),
|
||||
new Rating(2L, 1L, 3),
|
||||
new Rating(3L, 2L, 4),
|
||||
new Rating(4L, 2L, 5)
|
||||
);
|
||||
|
||||
@GetMapping("")
|
||||
public List<Rating> findRatingsByBookId(@RequestParam Long bookId) {
|
||||
return bookId == null || bookId.equals(0L) ? Collections.EMPTY_LIST : ratingList.stream().filter(r -> r.getBookId().equals(bookId)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GetMapping("/all")
|
||||
public List<Rating> findAllRatings() {
|
||||
return ratingList;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package com.baeldung.spring.cloud.bootstrap.svcrating;
|
|||
|
||||
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;
|
||||
|
@ -22,8 +23,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
http.httpBasic()
|
||||
.disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/ratings").hasRole("USER")
|
||||
.antMatchers("/ratings/all").hasRole("ADMIN")
|
||||
.regexMatchers("^/ratings\\?bookId.*$").authenticated()
|
||||
.antMatchers(HttpMethod.POST,"/ratings").authenticated()
|
||||
.antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN")
|
||||
.antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN")
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
.csrf()
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating;
|
||||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
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 Rating {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private Long bookId;
|
||||
private int stars;
|
|
@ -0,0 +1,38 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/ratings")
|
||||
public class RatingController {
|
||||
|
||||
@Autowired
|
||||
private RatingService ratingService;
|
||||
|
||||
@GetMapping("")
|
||||
public List<Rating> findRatingsByBookId(@RequestParam(required = false, defaultValue = "0") Long bookId) {
|
||||
if (bookId.equals(0L)) {
|
||||
return ratingService.findAllRatings();
|
||||
}
|
||||
return ratingService.findRatingsByBookId(bookId);
|
||||
}
|
||||
|
||||
@PostMapping("")
|
||||
public Rating createRating(@RequestBody Rating rating) {
|
||||
return ratingService.createRating(rating);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{ratingId}")
|
||||
public void deleteRating(@PathVariable Long ratingId) {
|
||||
ratingService.deleteRating(ratingId);
|
||||
}
|
||||
|
||||
@PatchMapping("/{ratingId")
|
||||
public Rating updateRating(@RequestBody Map<String, String> updates, @PathVariable Long ratingId) {
|
||||
return ratingService.updateRating(updates, ratingId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
class RatingNotFoundException extends RuntimeException {
|
||||
RatingNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface RatingRepository extends JpaRepository<Rating, Long>{
|
||||
List<Rating> findRatingsByBookId(Long bookId);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.baeldung.spring.cloud.bootstrap.svcrating.rating;
|
||||
|
||||
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 java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Transactional(readOnly = true)
|
||||
public class RatingService {
|
||||
|
||||
@Autowired
|
||||
private RatingRepository ratingRepository;
|
||||
|
||||
public Rating findRatingById(Long ratingId) {
|
||||
return Optional.ofNullable(ratingRepository.findOne(ratingId))
|
||||
.orElseThrow(() -> new RatingNotFoundException("Rating not found. ID: " + ratingId));
|
||||
}
|
||||
|
||||
public List<Rating> findRatingsByBookId(Long bookId) {
|
||||
return ratingRepository.findRatingsByBookId(bookId);
|
||||
}
|
||||
|
||||
public List<Rating> findAllRatings() {
|
||||
return ratingRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public Rating createRating(Rating rating) {
|
||||
Rating newRating = new Rating();
|
||||
newRating.setBookId(rating.getBookId());
|
||||
newRating.setStars(rating.getStars());
|
||||
return ratingRepository.save(newRating);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public void deleteRating(Long ratingId) {
|
||||
ratingRepository.delete(ratingId);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
public Rating updateRating(Map<String, String> updates, Long ratingId) {
|
||||
Rating rating = findRatingById(ratingId);
|
||||
updates.keySet().forEach(key -> {
|
||||
switch (key) {
|
||||
case "stars":
|
||||
rating.setStars(Integer.parseInt(updates.get(key)));
|
||||
break;
|
||||
}
|
||||
});
|
||||
return ratingRepository.save(rating);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue