Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.redislabs.edu.redi2read.boot;

import java.util.Random;
import java.util.stream.IntStream;

import com.redislabs.edu.redi2read.models.Book;
import com.redislabs.edu.redi2read.models.BookRating;
import com.redislabs.edu.redi2read.models.User;
import com.redislabs.edu.redi2read.repositories.BookRatingRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Order(4)
@Slf4j
public class CreateBookRatings implements CommandLineRunner {

@Value("${app.numberOfRatings}")
private Integer numberOfRatings;

@Value("${app.ratingStars}")
private Integer ratingStars;

@Autowired
private RedisTemplate<String, String> redisTemplate;

@Autowired
private BookRatingRepository bookRatingRepository;

@Override
public void run(String... args) throws Exception {
if (bookRatingRepository.count() == 0) {
Random random = new Random();
IntStream.range(0, numberOfRatings).forEach(n -> {
String bookId = redisTemplate.opsForSet().randomMember(Book.class.getName());
String userId = redisTemplate.opsForSet().randomMember(User.class.getName());
int stars = random.nextInt(ratingStars) + 1;

User user = new User();
user.setId(userId);

Book book = new Book();
book.setId(bookId);

BookRating rating = BookRating.builder() //
.user(user) //
.book(book) //
.rating(stars).build();
bookRatingRepository.save(rating);
});

log.info(">>>> BookRating created...");
}
}
}
84 changes: 84 additions & 0 deletions src/main/java/com/redislabs/edu/redi2read/boot/CreateBooks.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.redislabs.edu.redi2read.boot;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.redislabs.edu.redi2read.models.Book;
import com.redislabs.edu.redi2read.models.Category;
import com.redislabs.edu.redi2read.repositories.BookRepository;
import com.redislabs.edu.redi2read.repositories.CategoryRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Order(3)
@Slf4j
public class CreateBooks implements CommandLineRunner {
@Autowired
private BookRepository bookRepository;

@Autowired
private CategoryRepository categoryRepository;

@Override
public void run(String... args) throws Exception {
if (bookRepository.count() == 0) {
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<Book>> typeReference = new TypeReference<List<Book>>() {
};

List<File> files = //
Files.list(Paths.get(getClass().getResource("/data/books").toURI())) //
.filter(Files::isRegularFile) //
.filter(path -> path.toString().endsWith(".json")) //
.map(java.nio.file.Path::toFile) //
.collect(Collectors.toList());

Map<String, Category> categories = new HashMap<String, Category>();

files.forEach(file -> {
try {
log.info(">>>> Processing Book File: " + file.getPath());
String categoryName = file.getName().substring(0, file.getName().lastIndexOf("_"));
log.info(">>>> Category: " + categoryName);

Category category;
if (!categories.containsKey(categoryName)) {
category = Category.builder().name(categoryName).build();
categoryRepository.save(category);
categories.put(categoryName, category);
} else {
category = categories.get(categoryName);
}

InputStream inputStream = new FileInputStream(file);
List<Book> books = mapper.readValue(inputStream, typeReference);
books.stream().forEach((book) -> {
book.addCategory(category);
bookRepository.save(book);
});
log.info(">>>> " + books.size() + " Books Saved!");
} catch (IOException e) {
log.info("Unable to import books: " + e.getMessage());
}
});

log.info(">>>> Loaded Book Data and Created books...");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.redislabs.edu.redi2read.controllers;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.redislabs.edu.redi2read.models.Book;
import com.redislabs.edu.redi2read.models.Category;
import com.redislabs.edu.redi2read.repositories.BookRepository;
import com.redislabs.edu.redi2read.repositories.CategoryRepository;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/books")
public class BookController {
@Autowired
private BookRepository bookRepository;

@Autowired
private CategoryRepository categoryRepository;

@GetMapping
public ResponseEntity<Map<String, Object>> all( //
@RequestParam(defaultValue = "0") Integer page, //
@RequestParam(defaultValue = "10") Integer size //
) {
Pageable paging = PageRequest.of(page, size);
Page<Book> pagedResult = bookRepository.findAll(paging);
List<Book> books = pagedResult.hasContent() ? pagedResult.getContent() : Collections.emptyList();

Map<String, Object> response = new HashMap<>();
response.put("books", books);
response.put("page", pagedResult.getNumber());
response.put("pages", pagedResult.getTotalPages());
response.put("total", pagedResult.getTotalElements());

return new ResponseEntity<>(response, new HttpHeaders(), HttpStatus.OK);
}

@GetMapping("/categories")
public Iterable<Category> getCategories() {
return categoryRepository.findAll();
}

@GetMapping("/{isbn}")
public Book get(@PathVariable("isbn") String isbn) {
return bookRepository.findById(isbn).get();
}
}
40 changes: 40 additions & 0 deletions src/main/java/com/redislabs/edu/redi2read/models/Book.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.redislabs.edu.redi2read.models;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Reference;
import org.springframework.data.redis.core.RedisHash;

import lombok.Data;
import lombok.EqualsAndHashCode;

@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@RedisHash
public class Book {

@Id
@EqualsAndHashCode.Include
private String id;

private String title;
private String subtitle;
private String description;
private String language;
private Long pageCount;
private String thumbnail;
private Double price;
private String currency;
private String infoLink;

private Set<String> authors;

@Reference
private Set<Category> categories = new HashSet<Category>();

public void addCategory(Category category) {
categories.add(category);
}
}
29 changes: 29 additions & 0 deletions src/main/java/com/redislabs/edu/redi2read/models/BookRating.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.redislabs.edu.redi2read.models;

import javax.validation.constraints.NotNull;

import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Reference;
import org.springframework.data.redis.core.RedisHash;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
@RedisHash
public class BookRating {
@Id
private String id;

@NotNull
@Reference
private User user;

@NotNull
@Reference
private Book book;

@NotNull
private Integer rating;
}
17 changes: 17 additions & 0 deletions src/main/java/com/redislabs/edu/redi2read/models/Category.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.redislabs.edu.redi2read.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
@RedisHash
public class Category {
@Id
private String id;

private String name;
}
2 changes: 1 addition & 1 deletion src/main/java/com/redislabs/edu/redi2read/models/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import lombok.EqualsAndHashCode;
import lombok.ToString;

@JsonIgnoreProperties({ "password", "passwordConfirm" })
@JsonIgnoreProperties(value = { "password", "passwordConfirm" }, allowSetters = true)
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@ToString(onlyExplicitlyIncluded = true)
@Data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.redislabs.edu.redi2read.repositories;

import com.redislabs.edu.redi2read.models.BookRating;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRatingRepository extends CrudRepository<BookRating, String> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.redislabs.edu.redi2read.repositories;

import com.redislabs.edu.redi2read.models.Book;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface BookRepository extends PagingAndSortingRepository<Book, String> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.redislabs.edu.redi2read.repositories;

import com.redislabs.edu.redi2read.models.Category;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CategoryRepository extends CrudRepository<Category, String> {
}
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
spring.redis.host=localhost
spring.redis.port=6379
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
app.numberOfRatings=5000
app.ratingStars=5