Skip to content

Commit

Permalink
Merge pull request hxt001#1 from tabriszhu913/main
Browse files Browse the repository at this point in the history
Add homework 1 solutions
  • Loading branch information
hxt001 authored Sep 20, 2021
2 parents 0414238 + 1e86f7d commit 00aff49
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 3 deletions.
10 changes: 10 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

// https://mvnrepository.com/artifact/joda-time/joda-time
implementation group: 'joda-time', name: 'joda-time', version: '2.10.10'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-joda
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-joda', version: '2.12.5'
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.5.4'
// https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310
implementation group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.12.5'

}

test {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
package com.pivottech.booking;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

@SpringBootApplication
public class BookingApplication {

public static void main(String[] args) {
SpringApplication.run(BookingApplication.class, args);
}
@Service
public class CustomObjectMapper extends ObjectMapper {
public CustomObjectMapper() {
this.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
this.registerModule(new JodaModule());
this.registerModule(new JavaTimeModule());
}
}

@Bean
public javax.validation.Validator localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}

public static void main(String[] args) {
SpringApplication.run(BookingApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.pivottech.booking.controller;

import com.pivottech.booking.model.Reservation;
import com.pivottech.booking.service.BookingService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

import javax.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("reservations")
public class BookingController {

final BookingService bookingService;

public BookingController(BookingService bookingService) {
this.bookingService = bookingService;
}

@GetMapping("/")
public List<Reservation> list(@RequestParam(name="limit", value="10") int limit) {
return bookingService.getReservations(limit);
}

@GetMapping("/{id}")
public Reservation getById(@PathVariable("id") int id) {
Reservation resv = this.bookingService.getReservationById(id);
if (resv == null) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
return resv;
}

@PostMapping("/")
public Reservation create(@Valid @RequestBody Reservation reservation) {
this.bookingService.createReservation(reservation);
return reservation;
}

@DeleteMapping("/{id}")
public void delete(@PathVariable("id") int id) {
if (!this.bookingService.deleteReservation(id)) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.pivottech.booking.controller;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.ArrayList;
import java.util.List;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class MethodArgumentNotValidExceptionHandler {

@ResponseStatus(BAD_REQUEST)
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
public Error methodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<org.springframework.validation.FieldError> fieldErrors = result.getFieldErrors();
return processFieldErrors(fieldErrors);
}

private Error processFieldErrors(List<org.springframework.validation.FieldError> fieldErrors) {
Error error = new Error(BAD_REQUEST.value(), "validation error");
for (org.springframework.validation.FieldError fieldError: fieldErrors) {
error.addFieldError(fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
}
return error;
}

static class Error {
private final int status;
private final String message;
private List<FieldError> fieldErrors = new ArrayList<>();

Error(int status, String message) {
this.status = status;
this.message = message;
}

public int getStatus() {
return status;
}

public String getMessage() {
return message;
}

public void addFieldError(String objectName, String path, String message) {
FieldError error = new FieldError(objectName, path, message);
fieldErrors.add(error);
}

public List<FieldError> getFieldErrors() {
return fieldErrors;
}
}
}
33 changes: 33 additions & 0 deletions backend/src/main/java/com/pivottech/booking/model/Reservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.pivottech.booking.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import org.joda.time.DateTime;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

@Data
public class Reservation {

static int counter = 0;

@Setter(AccessLevel.NONE) final Integer id;
@NotNull DateTime startTime;
@NotNull DateTime endTime;
@NotEmpty String description;

@Builder
@JsonCreator
public Reservation(
@JsonProperty("startTime") DateTime startTime,
@JsonProperty("endTime") DateTime endTime,
@JsonProperty("description") String description
) {
this.id = counter++;
this.startTime = startTime;
this.endTime = endTime;
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.pivottech.booking.service;

import com.pivottech.booking.model.Reservation;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class BookingService {

private final List<Reservation> reservations;

public BookingService() {
this.reservations = new ArrayList<>();
}

public void createReservation(Reservation reservation) {
this.reservations.add(reservation);
}

public boolean deleteReservation(Integer id) {
Reservation toDelete = getReservationById(id);
if (toDelete == null) {
return false;
}
this.reservations.remove(toDelete);
return true;
}

public List<Reservation> getReservations(int limit) {
return this.reservations.stream().limit(limit).collect(Collectors.toList());
}

public Reservation getReservationById(Integer id) {
Optional<Reservation> resv = this.reservations.stream().filter(r -> r.getId().equals(id)).findFirst();
return resv.orElse(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.pivottech.booking.service;

import com.pivottech.booking.model.Reservation;
import org.joda.time.DateTime;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class BookingServiceTest {

BookingService service;

@BeforeEach
void setUp() {
service = new BookingService();
service.createReservation(
Reservation.builder()
.description("initial reservation")
.startTime(DateTime.now())
.endTime(DateTime.now().plusHours(1))
.build()
);
}

@AfterEach
void tearDown() {
}

@Test
void createReservation() {
int totalReservations = service.getReservations().size();
service.createReservation(
Reservation.builder()
.description("initial reservation")
.startTime(DateTime.now().plusHours(3))
.endTime(DateTime.now().plusHours(4))
.build()
);
assertEquals(totalReservations + 1, service.getReservations().size());
}

@Test
void deleteReservation() {
service.deleteReservation(0);
assertEquals(0, service.getReservations().size());
}

@Test
void getReservations() {
}
}

0 comments on commit 00aff49

Please sign in to comment.