├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── mightyjava │ │ ├── Application.java │ │ ├── config │ │ ├── JSONPrettyPrintConfig.java │ │ └── MyCommandLineRunner.java │ │ ├── data │ │ └── BookData.java │ │ ├── domain │ │ └── Book.java │ │ ├── exception │ │ ├── ApplicationException.java │ │ ├── BookCustomExceptionHandler.java │ │ ├── BookExceptionHandler.java │ │ └── BookNotFoundException.java │ │ ├── filter │ │ ├── ActuatorFilter.java │ │ ├── BookFilter.java │ │ ├── BookFilterTwo.java │ │ └── FilterConfig.java │ │ ├── interceptor │ │ ├── BookInterceptor.java │ │ └── BookInterceptorConfig.java │ │ ├── repository │ │ └── BookRepository.java │ │ ├── resource │ │ ├── Resource.java │ │ └── impl │ │ │ └── BookResourceImpl.java │ │ ├── service │ │ ├── IService.java │ │ └── impl │ │ │ └── BookServiceImpl.java │ │ └── util │ │ └── MethodUtils.java └── resources │ ├── application.properties │ ├── data │ └── books.json │ └── qrcodes │ └── QRCode.png └── test └── java └── com └── mightyjava └── ApplicationTests.java /README.md: -------------------------------------------------------------------------------- 1 | # GET 2 | http://localhost:8081/rest/books 3 | # GET By ID 4 | http://localhost:8081/rest/books/cff6c1c3-be92-4cb3-9c79-5a67f63a3d61 5 | # POST 6 | http://localhost:8081/rest/books 7 | # PUT 8 | http://localhost:8081/rest/books 9 | # PATCH 10 | http://localhost:8081/rest/books/cff6c1c3-be92-4cb3-9c79-5a67f63a3d61 11 | # DELETE 12 | http://localhost:8081/rest/books/cff6c1c3-be92-4cb3-9c79-5a67f63a3d61 13 | # Image QR Code 14 | http://localhost:8081/rest/books/generateImageQRCode/{bookId} 15 | # Byte QR Code 16 | http://localhost:8081/rest/books/generateByteQRCode/{bookId} 17 | 18 |
19 | 20 | # After Spring Data Rest 21 | # Book 22 | http://localhost:8081/rest/book 23 | # Search 24 | http://localhost:8081/rest/book/search 25 | # Find By Title 26 | http://localhost:8081/rest/book/search/findByTitle?title=Spring%20Microservices%20in%20Action 27 | # Find By Author 28 | http://localhost:8081/rest/book/search/findByAuthor?author=John%20Carnell 29 | # Find By ISBN Number 30 | http://localhost:8081/rest/book/search/findByIsbnNumber?isbnNumber=9351199193 31 | # Find By Language 32 | http://localhost:8081/rest/book/search/findByLanguage?language=English 33 | # Find By Price 34 | http://localhost:8081/rest/book/search/findByPrice?price=2776 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.4.3 10 | 11 | 12 | com.mightyjava 13 | book-rest-api 14 | 0.0.1-SNAPSHOT 15 | war 16 | book-rest-api 17 | Demo project for Spring Boot 18 | 19 | 20 | 1.8 21 | 22 | 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-web 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-actuator 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-devtools 37 | runtime 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-data-jpa 43 | 44 | 45 | 46 | com.h2database 47 | h2 48 | runtime 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-test 54 | test 55 | 56 | 57 | 58 | com.sun.jersey 59 | jersey-json 60 | 1.4 61 | 62 | 63 | 64 | com.sun.jersey 65 | jersey-server 66 | 1.4 67 | 68 | 69 | 70 | org.projectlombok 71 | lombok 72 | provided 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-starter-hateoas 78 | 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-data-rest 83 | 84 | 85 | 86 | com.google.zxing 87 | core 88 | 3.4.1 89 | 90 | 91 | 92 | com.google.zxing 93 | javase 94 | 3.4.1 95 | 96 | 97 | 98 | 99 | 100 | 101 | org.springframework.boot 102 | spring-boot-maven-plugin 103 | 104 | 105 | 106 | org.projectlombok 107 | lombok 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/Application.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(Application.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/config/JSONPrettyPrintConfig.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.config; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.converter.HttpMessageConverter; 7 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 9 | 10 | @Configuration 11 | public class JSONPrettyPrintConfig extends WebMvcConfigurationSupport { 12 | 13 | @Override 14 | protected void extendMessageConverters(List> converters) { 15 | converters.forEach(converter -> { 16 | if (converter instanceof MappingJackson2HttpMessageConverter) { 17 | MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter; 18 | jsonConverter.setPrettyPrint(true); 19 | } 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/config/MyCommandLineRunner.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.config; 2 | 3 | import java.io.InputStream; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.CommandLineRunner; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import com.fasterxml.jackson.core.type.TypeReference; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | import com.mightyjava.data.BookData; 14 | import com.mightyjava.domain.Book; 15 | import com.mightyjava.service.IService; 16 | 17 | @Configuration 18 | public class MyCommandLineRunner implements CommandLineRunner { 19 | 20 | private final String BOOKS_JSON = "/data/books.json"; 21 | 22 | @Autowired 23 | private IService service; 24 | 25 | @Override 26 | public void run(String... args) throws Exception { 27 | if (service.findAll().size() == 0) { 28 | try { 29 | TypeReference> typeReference = new TypeReference>() { 30 | }; 31 | InputStream inputStream = TypeReference.class.getResourceAsStream(BOOKS_JSON); 32 | List books = new ObjectMapper().readValue(inputStream, typeReference); 33 | if (books != null && !books.isEmpty()) { 34 | List bookList = new ArrayList<>(); 35 | books.forEach(book -> bookList.add(new Book(book.getTitle(), book.getAuthor(), 36 | book.getCoverPhotoURL(), book.getIsbnNumber(), book.getPrice(), book.getLanguage()))); 37 | List savedBookList = service.saveAll(bookList); 38 | System.out.println(savedBookList.size()); 39 | } 40 | } catch (Exception ex) { 41 | System.out.println("Unable to save books " + ex.getMessage()); 42 | } 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/data/BookData.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.data; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class BookData { 9 | private String title; 10 | private String author; 11 | private String coverPhotoURL; 12 | private Long isbnNumber; 13 | private Double price; 14 | private String language; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/domain/Book.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.domain; 2 | 3 | import java.util.UUID; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | 9 | import org.springframework.hateoas.RepresentationModel; 10 | 11 | import com.fasterxml.jackson.annotation.JsonCreator; 12 | import com.fasterxml.jackson.annotation.JsonProperty; 13 | 14 | import lombok.Getter; 15 | import lombok.NoArgsConstructor; 16 | import lombok.Setter; 17 | 18 | @Entity 19 | @Getter 20 | @Setter 21 | @NoArgsConstructor 22 | public class Book extends RepresentationModel { 23 | 24 | @Id 25 | @GeneratedValue 26 | private UUID id; 27 | private String title; 28 | private String author; 29 | private String coverPhotoURL; 30 | private Long isbnNumber; 31 | private Double price; 32 | private String language; 33 | private byte[] base64QRCode; 34 | 35 | @JsonCreator 36 | public Book(@JsonProperty("id") UUID id, @JsonProperty("title") String title, @JsonProperty("author") String author, 37 | @JsonProperty("coverPhotoURL") String coverPhotoURL, @JsonProperty("isbnNumber") Long isbnNumber, 38 | @JsonProperty("price") Double price, @JsonProperty("language") String language) { 39 | this.id = id; 40 | this.title = title; 41 | this.author = author; 42 | this.coverPhotoURL = coverPhotoURL; 43 | this.isbnNumber = isbnNumber; 44 | this.price = price; 45 | this.language = language; 46 | } 47 | 48 | public Book(String title, String author, String coverPhotoURL, Long isbnNumber, Double price, String language) { 49 | this.title = title; 50 | this.author = author; 51 | this.coverPhotoURL = coverPhotoURL; 52 | this.isbnNumber = isbnNumber; 53 | this.price = price; 54 | this.language = language; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/exception/ApplicationException.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.exception; 2 | 3 | public class ApplicationException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = -3101984166649269624L; 6 | 7 | public ApplicationException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/exception/BookCustomExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.exception; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | 8 | import com.mightyjava.util.MethodUtils; 9 | 10 | @ControllerAdvice 11 | public class BookCustomExceptionHandler { 12 | 13 | @ExceptionHandler(value = ApplicationException.class) 14 | public ResponseEntity applicationException(ApplicationException exception) { 15 | HttpStatus status = HttpStatus.BAD_REQUEST; 16 | return new ResponseEntity<>(MethodUtils.prepareErrorJSON(status, exception), status); 17 | } 18 | 19 | @ExceptionHandler(value = BookNotFoundException.class) 20 | public ResponseEntity bookNotFoundException(BookNotFoundException exception) { 21 | HttpStatus status = HttpStatus.NOT_FOUND; 22 | return new ResponseEntity<>(MethodUtils.prepareErrorJSON(status, exception), status); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/exception/BookExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.exception; 2 | 3 | import org.springframework.http.HttpHeaders; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.http.converter.HttpMessageNotReadableException; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.context.request.WebRequest; 9 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 10 | 11 | import com.mightyjava.util.MethodUtils; 12 | 13 | @ControllerAdvice 14 | public class BookExceptionHandler extends ResponseEntityExceptionHandler { 15 | 16 | @Override 17 | protected ResponseEntity handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, 18 | HttpStatus status, WebRequest request) { 19 | return new ResponseEntity<>(MethodUtils.prepareErrorJSON(status, ex), status); 20 | } 21 | 22 | @Override 23 | protected ResponseEntity handleHttpMessageNotReadable(HttpMessageNotReadableException ex, 24 | HttpHeaders headers, HttpStatus status, WebRequest request) { 25 | return new ResponseEntity<>(MethodUtils.prepareErrorJSON(status, ex), status); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/exception/BookNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.exception; 2 | 3 | public class BookNotFoundException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = -2533194229906054487L; 6 | 7 | public BookNotFoundException(String message) { 8 | super(message); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/filter/ActuatorFilter.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.ServletRequest; 9 | import javax.servlet.ServletResponse; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | @Component 16 | public class ActuatorFilter implements Filter { 17 | 18 | private static Logger log = LoggerFactory.getLogger(ActuatorFilter.class); 19 | 20 | @Override 21 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 22 | throws IOException, ServletException { 23 | log.info("ActuatorFilter - doFilter"); 24 | chain.doFilter(request, response); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/filter/BookFilter.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.ServletRequest; 9 | import javax.servlet.ServletResponse; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.core.annotation.Order; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | @Order(2) 18 | public class BookFilter implements Filter { 19 | 20 | private static Logger log = LoggerFactory.getLogger(BookFilter.class); 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 24 | throws IOException, ServletException { 25 | log.info("BookFilter - doFilter"); 26 | // log.info("Local Port - " + request.getLocalPort()); 27 | // log.info("Server Name - " + request.getServerName()); 28 | // log.info("Protocol - " + request.getProtocol()); 29 | // HttpServletRequest httpServletRequest = (HttpServletRequest) request; 30 | // log.info("Method - " + httpServletRequest.getMethod()); 31 | // log.info("Request URI - " + httpServletRequest.getRequestURI()); 32 | // log.info("Servlet Path - " + httpServletRequest.getServletPath()); 33 | chain.doFilter(request, response); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/filter/BookFilterTwo.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.filter; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.ServletRequest; 9 | import javax.servlet.ServletResponse; 10 | 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.core.annotation.Order; 14 | import org.springframework.stereotype.Component; 15 | 16 | @Component 17 | @Order(1) 18 | public class BookFilterTwo implements Filter { 19 | 20 | private static Logger log = LoggerFactory.getLogger(BookFilterTwo.class); 21 | 22 | @Override 23 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 24 | throws IOException, ServletException { 25 | log.info("BookFilterTwo - doFilter"); 26 | chain.doFilter(request, response); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/filter/FilterConfig.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.filter; 2 | 3 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class FilterConfig { 9 | 10 | @Bean 11 | public FilterRegistrationBean registrationBean() { 12 | FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); 13 | registrationBean.setFilter(new ActuatorFilter()); 14 | registrationBean.addUrlPatterns("/actuator/*"); 15 | return registrationBean; 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/interceptor/BookInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.interceptor; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.servlet.HandlerInterceptor; 10 | import org.springframework.web.servlet.ModelAndView; 11 | 12 | @Component 13 | public class BookInterceptor implements HandlerInterceptor { 14 | 15 | private static Logger log = LoggerFactory.getLogger(BookInterceptor.class); 16 | 17 | @Override 18 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 19 | throws Exception { 20 | log.info("BookInterceptor - preHandle"); 21 | boolean flag = true; 22 | String method = request.getMethod(); 23 | // int contentLength =request.getContentLength(); 24 | if(method.equalsIgnoreCase("post") || method.equalsIgnoreCase("put")) { 25 | String contentType = request.getContentType(); 26 | if(contentType != null && !contentType.equalsIgnoreCase("application/json")) { 27 | flag = false; 28 | } 29 | // else if(contentLength <= 2) { 30 | // flag = false; 31 | // } 32 | } 33 | if(!flag) { 34 | response.sendRedirect("/rest/books/invalid"); 35 | } 36 | return flag; 37 | //return HandlerInterceptor.super.preHandle(request, response, handler); 38 | } 39 | 40 | @Override 41 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, 42 | ModelAndView modelAndView) throws Exception { 43 | log.info("BookInterceptor - postHandle"); 44 | HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); 45 | } 46 | 47 | @Override 48 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 49 | throws Exception { 50 | log.info("BookInterceptor - afterCompletion"); 51 | HandlerInterceptor.super.afterCompletion(request, response, handler, ex); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/interceptor/BookInterceptorConfig.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.interceptor; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; 7 | 8 | @Component 9 | public class BookInterceptorConfig extends WebMvcConfigurationSupport { 10 | 11 | @Autowired 12 | private BookInterceptor bookInterceptor; 13 | 14 | @Override 15 | protected void addInterceptors(InterceptorRegistry registry) { 16 | registry.addInterceptor(bookInterceptor); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/repository/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.repository; 2 | 3 | import java.util.List; 4 | import java.util.UUID; 5 | 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.repository.query.Param; 8 | import org.springframework.data.rest.core.annotation.RepositoryRestResource; 9 | 10 | import com.mightyjava.domain.Book; 11 | 12 | @RepositoryRestResource(collectionResourceRel = "book", path = "book") 13 | public interface BookRepository extends JpaRepository { 14 | 15 | Book findByTitle(@Param("title") String title); 16 | 17 | Book findByAuthor(@Param("author") String author); 18 | 19 | Book findByIsbnNumber(@Param("isbnNumber") Long isbnNumber); 20 | 21 | List findByLanguage(@Param("language") String language); 22 | 23 | Book findByPrice(@Param("price") Double price); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/resource/Resource.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.resource; 2 | 3 | import java.util.Collection; 4 | import java.util.Map; 5 | import java.util.UUID; 6 | 7 | import org.springframework.http.MediaType; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.DeleteMapping; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.PatchMapping; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.PostMapping; 14 | import org.springframework.web.bind.annotation.PutMapping; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | 17 | public interface Resource { 18 | @GetMapping 19 | ResponseEntity> findAll(); 20 | 21 | @GetMapping("{id}") 22 | ResponseEntity findById(@PathVariable UUID id); 23 | 24 | @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) 25 | ResponseEntity save(@RequestBody T t); 26 | 27 | @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE) 28 | ResponseEntity update(@RequestBody T t); 29 | 30 | @PatchMapping("{id}") 31 | ResponseEntity patch(@PathVariable UUID id, @RequestBody Map fields); 32 | 33 | @DeleteMapping("{id}") 34 | ResponseEntity deleteById(@PathVariable UUID id); 35 | 36 | @GetMapping("/invalid") 37 | ResponseEntity invalid(); 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/resource/impl/BookResourceImpl.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.resource.impl; 2 | 3 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; 4 | import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; 5 | 6 | import java.lang.reflect.Field; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.Optional; 12 | import java.util.UUID; 13 | 14 | import org.codehaus.jettison.json.JSONException; 15 | import org.codehaus.jettison.json.JSONObject; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.util.ReflectionUtils; 20 | import org.springframework.web.bind.annotation.GetMapping; 21 | import org.springframework.web.bind.annotation.PathVariable; 22 | import org.springframework.web.bind.annotation.RequestMapping; 23 | import org.springframework.web.bind.annotation.RestController; 24 | 25 | import com.mightyjava.domain.Book; 26 | import com.mightyjava.exception.ApplicationException; 27 | import com.mightyjava.exception.BookNotFoundException; 28 | import com.mightyjava.resource.Resource; 29 | import com.mightyjava.service.IService; 30 | import com.mightyjava.util.MethodUtils; 31 | 32 | import lombok.extern.slf4j.Slf4j; 33 | 34 | @Slf4j 35 | @RestController 36 | @RequestMapping("/books") 37 | public class BookResourceImpl implements Resource { 38 | 39 | @Autowired 40 | private IService bookService; 41 | 42 | private final String imagePath = "./src/main/resources/qrcodes/QRCode.png"; 43 | 44 | @GetMapping("/generateByteQRCode/{bookId}") 45 | public ResponseEntity generateByteQRCode(@PathVariable("bookId") UUID bookId) { 46 | log.info("BookResourceImpl - generateByteQRCode"); 47 | Book bookObject = null; 48 | Optional book = bookService.findById(bookId); 49 | if (!book.isPresent()) { 50 | throw new BookNotFoundException("Book not found"); 51 | } else { 52 | bookObject = book.get(); 53 | bookObject.setBase64QRCode(MethodUtils.generateByteQRCode(bookObject.getCoverPhotoURL(), 250, 250)); 54 | bookObject.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 55 | } 56 | return new ResponseEntity<>(bookObject, HttpStatus.OK); 57 | } 58 | 59 | @GetMapping("/generateImageQRCode/{bookId}") 60 | public ResponseEntity generateImageQRCode(@PathVariable("bookId") UUID bookId) { 61 | log.info("BookResourceImpl - generateImageQRCode"); 62 | Book bookObject = null; 63 | Optional book = bookService.findById(bookId); 64 | if (!book.isPresent()) { 65 | throw new BookNotFoundException("Book not found"); 66 | } else { 67 | bookObject = book.get(); 68 | MethodUtils.generateImageQRCode(bookObject.getCoverPhotoURL(), 250, 250, imagePath); 69 | bookObject.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 70 | } 71 | return new ResponseEntity<>(bookObject, HttpStatus.OK); 72 | } 73 | 74 | @Override 75 | public ResponseEntity> findAll() { 76 | log.info("BookResourceImpl - findAll"); 77 | Collection books = bookService.findAll(); 78 | List response = new ArrayList<>(); 79 | books.forEach(book -> { 80 | book.add(linkTo(methodOn(BookResourceImpl.class).findById(book.getId())).withSelfRel()); 81 | response.add(book); 82 | }); 83 | return new ResponseEntity<>(response, HttpStatus.OK); 84 | } 85 | 86 | @Override 87 | public ResponseEntity findById(UUID id) { 88 | log.info("BookResourceImpl - findById"); 89 | Book bookObject = null; 90 | Optional book = bookService.findById(id); 91 | if (!book.isPresent()) { 92 | throw new BookNotFoundException("Book not found"); 93 | } else { 94 | bookObject = book.get(); 95 | bookObject.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 96 | } 97 | return new ResponseEntity<>(bookObject, HttpStatus.OK); 98 | } 99 | 100 | @Override 101 | public ResponseEntity save(Book book) { 102 | log.info("BookResourceImpl - save"); 103 | if (book.getId() != null) { 104 | throw new ApplicationException("Book ID found, ID is not required for save the data"); 105 | } else { 106 | Book savedBook = bookService.saveOrUpdate(book); 107 | savedBook.add(linkTo(methodOn(BookResourceImpl.class).findById(savedBook.getId())).withSelfRel()); 108 | savedBook.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 109 | return new ResponseEntity<>(savedBook, HttpStatus.CREATED); 110 | } 111 | } 112 | 113 | @Override 114 | public ResponseEntity update(Book book) { 115 | log.info("BookResourceImpl - update"); 116 | if (book.getId() == null) { 117 | throw new ApplicationException("Book ID not found, ID is required for update the data"); 118 | } else { 119 | Book updatedBook = bookService.saveOrUpdate(book); 120 | updatedBook.add(linkTo(methodOn(BookResourceImpl.class).findById(updatedBook.getId())).withSelfRel()); 121 | updatedBook.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 122 | return new ResponseEntity<>(updatedBook, HttpStatus.OK); 123 | } 124 | } 125 | 126 | @Override 127 | public ResponseEntity patch(UUID id, Map fields) { 128 | Optional book = bookService.findById(id); 129 | if (book.isPresent()) { 130 | fields.forEach((key, value) -> { 131 | Field field = ReflectionUtils.findField(Book.class, (String) key); 132 | field.setAccessible(true); 133 | ReflectionUtils.setField(field, book.get(), value); 134 | }); 135 | Book updatedBook = bookService.saveOrUpdate(book.get()); 136 | updatedBook.add(linkTo(methodOn(BookResourceImpl.class).findById(updatedBook.getId())).withSelfRel()); 137 | updatedBook.add(linkTo(methodOn(BookResourceImpl.class).findAll()).withSelfRel()); 138 | return new ResponseEntity<>(updatedBook, HttpStatus.OK); 139 | } 140 | return null; 141 | } 142 | 143 | @Override 144 | public ResponseEntity deleteById(UUID id) { 145 | log.info("BookResourceImpl - deleteById"); 146 | Optional book = bookService.findById(id); 147 | if (!book.isPresent()) { 148 | throw new BookNotFoundException("Book not found"); 149 | } 150 | return new ResponseEntity<>(bookService.deleteById(id), HttpStatus.OK); 151 | } 152 | 153 | @Override 154 | public ResponseEntity invalid() { 155 | log.info("BookResourceImpl - invalid"); 156 | JSONObject jsonObject = new JSONObject(); 157 | try { 158 | jsonObject.put("message", "something is missing, please check everything before sending the request!!!"); 159 | } catch (JSONException e) { 160 | e.printStackTrace(); 161 | } 162 | return new ResponseEntity<>(jsonObject.toString(), HttpStatus.OK); 163 | } 164 | 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/service/IService.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.service; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.UUID; 7 | 8 | public interface IService { 9 | Collection findAll(); 10 | 11 | Optional findById(UUID id); 12 | 13 | T saveOrUpdate(T t); 14 | 15 | List saveAll(List t); 16 | 17 | String deleteById(UUID id); 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/service/impl/BookServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.service.impl; 2 | 3 | import java.util.Collection; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import java.util.UUID; 7 | 8 | import org.codehaus.jettison.json.JSONException; 9 | import org.codehaus.jettison.json.JSONObject; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import com.mightyjava.domain.Book; 14 | import com.mightyjava.repository.BookRepository; 15 | import com.mightyjava.service.IService; 16 | 17 | @Service 18 | public class BookServiceImpl implements IService { 19 | 20 | @Autowired 21 | private BookRepository bookRepository; 22 | 23 | @Override 24 | public Collection findAll() { 25 | return bookRepository.findAll(); 26 | } 27 | 28 | @Override 29 | public Optional findById(UUID id) { 30 | return bookRepository.findById(id); 31 | } 32 | 33 | @Override 34 | public Book saveOrUpdate(Book book) { 35 | return bookRepository.saveAndFlush(book); 36 | } 37 | 38 | @Override 39 | public String deleteById(UUID id) { 40 | JSONObject jsonObject = new JSONObject(); 41 | try { 42 | bookRepository.deleteById(id); 43 | jsonObject.put("message", "Book deleted successfully"); 44 | } catch (JSONException e) { 45 | e.printStackTrace(); 46 | } 47 | return jsonObject.toString(); 48 | } 49 | 50 | @Override 51 | public List saveAll(List books) { 52 | return bookRepository.saveAll(books); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/mightyjava/util/MethodUtils.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.nio.file.FileSystems; 6 | 7 | import org.codehaus.jettison.json.JSONException; 8 | import org.codehaus.jettison.json.JSONObject; 9 | import org.springframework.http.HttpStatus; 10 | 11 | import com.google.zxing.BarcodeFormat; 12 | import com.google.zxing.WriterException; 13 | import com.google.zxing.client.j2se.MatrixToImageConfig; 14 | import com.google.zxing.client.j2se.MatrixToImageWriter; 15 | import com.google.zxing.common.BitMatrix; 16 | import com.google.zxing.qrcode.QRCodeWriter; 17 | 18 | public class MethodUtils { 19 | 20 | private MethodUtils() { 21 | } 22 | 23 | public static byte[] generateByteQRCode(String text, int width, int height) { 24 | ByteArrayOutputStream outputStream = null; 25 | QRCodeWriter qrCodeWriter = new QRCodeWriter(); 26 | try { 27 | outputStream = new ByteArrayOutputStream(); 28 | BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height); 29 | MatrixToImageConfig config = new MatrixToImageConfig(0xFF000000, 0xFFFFFFFF); 30 | MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream, config); 31 | } catch (WriterException | IOException e) { 32 | e.printStackTrace(); 33 | } 34 | return outputStream.toByteArray(); 35 | } 36 | 37 | public static void generateImageQRCode(String text, int width, int height, String path) { 38 | QRCodeWriter qrCodeWriter = new QRCodeWriter(); 39 | try { 40 | BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height); 41 | MatrixToImageWriter.writeToPath(bitMatrix, "PNG", FileSystems.getDefault().getPath(path)); 42 | } catch (WriterException | IOException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | 47 | public static String prepareErrorJSON(HttpStatus status, Exception ex) { 48 | JSONObject errorJSON = new JSONObject(); 49 | try { 50 | errorJSON.put("status", status.value()); 51 | errorJSON.put("error", status.getReasonPhrase()); 52 | errorJSON.put("message", ex.getMessage().split(":")[0]); 53 | } catch (JSONException e) { 54 | e.printStackTrace(); 55 | } 56 | return errorJSON.toString(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8081 2 | server.servlet.context-path=/rest 3 | 4 | #H2 5 | spring.h2.console.enabled=true 6 | spring.h2.console.path=/h2 7 | 8 | spring.datasource.url=jdbc:h2:mem:book-db 9 | spring.datasource.driver-class-name=org.h2.Driver 10 | spring.datasource.username=sa 11 | spring.datasource.password= 12 | 13 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect -------------------------------------------------------------------------------- /src/main/resources/data/books.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Spring Microservices in Action", 4 | "author": "John Carnell", 5 | "coverPhotoURL": "https://images-na.ssl-images-amazon.com/images/I/417zLTa1uqL._SX397_BO1,204,203,200_.jpg", 6 | "isbnNumber": 1617293989, 7 | "price": 2776, 8 | "language": "English" 9 | }, 10 | { 11 | "title": "Spring in Action", 12 | "author": "Craig Walls", 13 | "coverPhotoURL": "https://images-na.ssl-images-amazon.com/images/I/51gHy16h5TL.jpg", 14 | "isbnNumber": 9789351197997, 15 | "price": 630, 16 | "language": "English" 17 | }, 18 | { 19 | "title": "Java Persistence with Hibernate", 20 | "author": "Christian Bauer and Gavin King", 21 | "coverPhotoURL": "https://images.manning.com/720/960/resize/book/d/2ea186d-c683-4d54-95f9-cca25b6fe49e/bauer2.png", 22 | "isbnNumber": 9351199193, 23 | "price": 771, 24 | "language": "English" 25 | }, 26 | { 27 | "title": "Grails in Action", 28 | "author": "Glen Smith and Peter Ledbrook", 29 | "coverPhotoURL": "https://images.manning.com/720/960/resize/book/6/3e9d5ed-4155-466d-ab46-538bb355948d/gsmith2.png", 30 | "isbnNumber": 1617290963, 31 | "price": 2907, 32 | "language": "English" 33 | }, 34 | { 35 | "title": "Spring Boot in Action", 36 | "author": "Craig Walls", 37 | "coverPhotoURL": "https://images.manning.com/720/960/resize/book/6/bb80688-f898-4df7-838a-253b1de123c4/Walls-SpringBoot-HI.png", 38 | "isbnNumber": 1617292540, 39 | "price": 3149, 40 | "language": "English" 41 | }, 42 | { 43 | "title": "Head First Java: A Brain-Friendly Guide", 44 | "author": "Kathy Sierra", 45 | "coverPhotoURL": "https://covers.oreillystatic.com/images/9780596004651/lrg.jpg", 46 | "isbnNumber": 8173666024, 47 | "price": 498, 48 | "language": "English" 49 | } 50 | ] -------------------------------------------------------------------------------- /src/main/resources/qrcodes/QRCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mightyjava/book-rest-api/3d967fb2952689ee4539fe063c3f5e594a05d991/src/main/resources/qrcodes/QRCode.png -------------------------------------------------------------------------------- /src/test/java/com/mightyjava/ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.mightyjava; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | public class ApplicationTests { 8 | 9 | @Test 10 | public void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------