Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/crud word #6

Merged
merged 3 commits into from
Nov 6, 2024
Merged
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
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.6.0</version>
</dependency>
<!-- Mapper -->
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.0.0</version>
</dependency>

</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.kdp.learn_vocabulary_kdp.config;

import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ModelMapperConfig {
@Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT).setSkipNullEnabled(true);
return modelMapper;
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
package org.kdp.learn_vocabulary_kdp.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
@ComponentScan(basePackages = {"org.kdp.learn_vocabulary_kdp.controller"})
@ComponentScan(basePackages = "org.kdp.learn_vocabulary_kdp.controller.v1")
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("API Documentation")
.version("1.0")
.description("API documentation for website learn English vocabulary")
.contact(new Contact()
.name("Kiet Hoang")
.email("kiethoang101.dev@gmail.com")
.url("https://github.com/K1ethoang")));
}
public OpenAPI defineOpenApi() {
Server server = new Server();
server.setDescription("Development");

@Bean
public Components customComponents() {
return new Components()
.addSecuritySchemes("basicScheme", new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("basic"));
Contact myContact = new Contact();
myContact.setName("Kiet Hoang");
myContact.setEmail("kiethoang101.dev@gmail.com");
myContact.setUrl("https://github.com/K1ethoang");

Info information = new Info().title("Learn Vocabulary KDP System API").version("1.0").description("API documentation for website learn English vocabulary").contact(myContact);
return new OpenAPI().info(information).servers(List.of(server));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.kdp.learn_vocabulary_kdp.controller.v1;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.kdp.learn_vocabulary_kdp.message.GlobalMessage;
import org.kdp.learn_vocabulary_kdp.model.DTO.word.WordDto;
import org.kdp.learn_vocabulary_kdp.response.ApiResponse;
import org.kdp.learn_vocabulary_kdp.service.interfaces.WordService;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/v1/words")
@AllArgsConstructor
@Log4j2
public class WordControllerV1 {
private final WordService wordService;
private final String DEFAULT_PAGE_NO = "0";
private final String DEFAULT_PAGE_SIZE = "10";
private final String DEFAULT_SORT_BY = "updatedAt";

@GetMapping("")
public ResponseEntity<Object> getAllWords(@RequestParam(defaultValue = DEFAULT_PAGE_NO) int pageNo, @RequestParam(defaultValue = DEFAULT_PAGE_SIZE) int pageSize, @RequestParam(defaultValue = DEFAULT_SORT_BY) String sortBy) {
Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.by(Sort.Direction.DESC, sortBy));

return ApiResponse.responseBuilder(HttpStatus.OK, GlobalMessage.SUCCESSFULLY, wordService.getAllWords(pageable));
}

@GetMapping("/{id}")
public ResponseEntity<Object> getWordById(@PathVariable String id) {
log.info("Received request to get word with id: {}", id);
return ApiResponse.responseBuilder(HttpStatus.OK, GlobalMessage.SUCCESSFULLY, wordService.getWordById(id));
}

@PostMapping("")
public ResponseEntity<Object> createWord(@RequestBody WordDto wordDto) {
return ApiResponse.responseBuilder(HttpStatus.CREATED, GlobalMessage.SUCCESSFULLY, wordService.createWord(wordDto));
}

@PutMapping("/{id}")
public ResponseEntity<Object> updateWord(@PathVariable String id, @RequestBody WordDto wordDto) {
return ApiResponse.responseBuilder(HttpStatus.OK, GlobalMessage.SUCCESSFULLY, wordService.updateWord(id, wordDto));
}

@DeleteMapping("/{id}")
public ResponseEntity<Object> deleteWord(@PathVariable String id) {
wordService.deleteWord(id);
return ApiResponse.responseBuilder(HttpStatus.OK, GlobalMessage.SUCCESSFULLY, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.kdp.learn_vocabulary_kdp.exception;

import org.kdp.learn_vocabulary_kdp.response.ApiResponse;
import org.kdp.learn_vocabulary_kdp.response.ErrorResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
// System exception
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handlerException(Exception e) {
return ApiResponse.responseError(HttpStatus.INTERNAL_SERVER_ERROR,
e.getMessage());
}

@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handlerNotFoundException(NotFoundException e) {
return ApiResponse.responseError(e.getHttpStatus(),
e.getMessage());
}

@ExceptionHandler(InvalidException.class)
public ResponseEntity<ErrorResponse> handlerInvalidException(InvalidException e){
return ApiResponse.responseError(e.getHttpStatus(), e.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.kdp.learn_vocabulary_kdp.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@AllArgsConstructor
@Getter
public class InvalidException extends RuntimeException {
private final HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.kdp.learn_vocabulary_kdp.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public class NotFoundException extends RuntimeException{
private final HttpStatus httpStatus = HttpStatus.NOT_FOUND;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.kdp.learn_vocabulary_kdp.message;

public class GlobalMessage {
public static String SUCCESSFULLY = "Successfully";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.kdp.learn_vocabulary_kdp.message;

public class WordMessage {
public static String NOT_FOUND = "Word is not found";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.kdp.learn_vocabulary_kdp.model.DTO.paging;

import lombok.Data;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.List;

@Data
public class PageableDto {
List<Object> content;
int pageNo;
int pageSize;
long totalElements;
int totalPages;
boolean sorted;
boolean first;
boolean last;
boolean empty;

public <T> PageableDto(Page<T> page) {
Pageable pageable = page.getPageable();

setPageNo(pageable.getPageNumber());
setPageSize(pageable.getPageSize());
setTotalElements(page.getTotalElements());
setTotalPages(page.getTotalPages());
setSorted(pageable.getSort().isSorted());
setFirst(page.isFirst());
setLast(page.isLast());
setEmpty(page.isEmpty());
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.kdp.learn_vocabulary_kdp.model.DTO.word;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.time.LocalDateTime;

@AllArgsConstructor
@Data
public class WordDto {
@JsonIgnore
private LocalDateTime createdAt;
@JsonIgnore
private LocalDateTime updatedAt;
@JsonIgnore
private Boolean isDeleted;
@JsonIgnore
private String id;
private String word;
private String pronounce;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.kdp.learn_vocabulary_kdp.model.mapper;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.kdp.learn_vocabulary_kdp.entity.Word;
import org.kdp.learn_vocabulary_kdp.model.DTO.word.WordDto;
import org.modelmapper.ModelMapper;

@AllArgsConstructor
@Data
public class DtoToEntity {
private static ModelMapper mapper;

public static Word Word(WordDto wordDto) {
return mapper.map(wordDto, Word.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.kdp.learn_vocabulary_kdp.response;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.util.HashMap;
import java.util.Map;

public class ApiResponse {
public static ResponseEntity<Object> responseBuilder(HttpStatus httpStatus, String message, Object responseObject) {
Map<String, Object> response = new HashMap<>();
response.put("status", httpStatus.value());
response.put("message", message);
response.put("data", responseObject);

return new ResponseEntity<>(response, httpStatus);
}

public static ResponseEntity<ErrorResponse> responseError(HttpStatus httpStatus, String message) {
ErrorResponse errorResponse = new ErrorResponse(httpStatus.value(), message);
return new ResponseEntity<>(errorResponse, httpStatus);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.kdp.learn_vocabulary_kdp.response;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public class ErrorResponse {
private int statusCode;
private String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.kdp.learn_vocabulary_kdp.service.impl;

import lombok.AllArgsConstructor;
import org.kdp.learn_vocabulary_kdp.entity.Word;
import org.kdp.learn_vocabulary_kdp.exception.NotFoundException;
import org.kdp.learn_vocabulary_kdp.message.WordMessage;
import org.kdp.learn_vocabulary_kdp.model.DTO.paging.PageableDto;
import org.kdp.learn_vocabulary_kdp.model.DTO.word.WordDto;
import org.kdp.learn_vocabulary_kdp.model.mapper.EntityToDto;
import org.kdp.learn_vocabulary_kdp.repository.WordRepository;
import org.kdp.learn_vocabulary_kdp.service.interfaces.WordService;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
@AllArgsConstructor
public class WordServiceImpl implements WordService {
private final WordRepository wordRepository;
private final ModelMapper modelMapper;

@Override
public PageableDto getAllWords(Pageable pageable) {
Page<Word> wordPage = wordRepository.findAll(pageable);

List<Word> wordList = wordPage.getContent();

List<WordDto> content = wordList.stream().map(EntityToDto::word).toList();

PageableDto pageableDto = new PageableDto(wordPage);

pageableDto.setContent(Arrays.asList(content.toArray()));

return pageableDto;
}

@Override
public WordDto getWordById(String id) throws NotFoundException {
Word wordFromDb = wordRepository.findById(id).orElseThrow(() -> new NotFoundException(WordMessage.NOT_FOUND));

return EntityToDto.word(wordFromDb);
}

@Override
public WordDto createWord(WordDto wordDto) {
return null;
}

@Override
public WordDto updateWord(String id, WordDto wordDto) {
return null;
}

@Override
public void deleteWord(String id) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.kdp.learn_vocabulary_kdp.service.interfaces;

import org.kdp.learn_vocabulary_kdp.model.DTO.paging.PageableDto;
import org.kdp.learn_vocabulary_kdp.model.DTO.word.WordDto;
import org.springframework.data.domain.Pageable;

public interface WordService {
PageableDto getAllWords(Pageable pageable);

WordDto createWord(WordDto wordDto);

WordDto updateWord(String id, WordDto wordDto);

void deleteWord(String id);

WordDto getWordById(String id);
}
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
springdoc.api-docs.path=/api-docs