intial project add

This commit is contained in:
John Thompson
2019-05-26 15:30:24 -04:00
commit 0f2095870f
22 changed files with 1241 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package guru.springframework.sfgrestdocsexample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SfgRestdocsExampleApplication {
public static void main(String[] args) {
SpringApplication.run(SfgRestdocsExampleApplication.class, args);
}
}

View File

@@ -0,0 +1,49 @@
package guru.springframework.sfgrestdocsexample.bootstrap;
import guru.springframework.sfgrestdocsexample.domain.Beer;
import guru.springframework.sfgrestdocsexample.repositories.BeerRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
/**
* Created by jt on 2019-05-17.
*/
@Component
public class BeerLoader implements CommandLineRunner {
private final BeerRepository beerRepository;
public BeerLoader(BeerRepository beerRepository) {
this.beerRepository = beerRepository;
}
@Override
public void run(String... args) throws Exception {
loadBeerObjects();
}
private void loadBeerObjects() {
if(beerRepository.count() == 0){
beerRepository.save(Beer.builder()
.beerName("Mango Bobs")
.beerStyle("IPA")
.quantityToBrew(200)
.minOnHand(12)
.upc(337010000001L)
.price(new BigDecimal("12.95"))
.build());
beerRepository.save(Beer.builder()
.beerName("Galaxy Cat")
.beerStyle("PALE_ALE")
.quantityToBrew(200)
.minOnHand(12)
.upc(337010000002L)
.price(new BigDecimal("11.95"))
.build());
}
}
}

View File

@@ -0,0 +1,52 @@
package guru.springframework.sfgrestdocsexample.domain;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.UpdateTimestamp;
import javax.persistence.*;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.UUID;
/**
* Created by jt on 2019-05-17.
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Beer {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@Column(length = 36, columnDefinition = "varchar", updatable = false, nullable = false)
private UUID id;
@Version
private Long version;
@CreationTimestamp
@Column(updatable = false)
private Timestamp createdDate;
@UpdateTimestamp
private Timestamp lastModifiedDate;
private String beerName;
private String beerStyle;
@Column(unique = true)
private Long upc;
private BigDecimal price;
private Integer minOnHand;
private Integer quantityToBrew;
}

View File

@@ -0,0 +1,12 @@
package guru.springframework.sfgrestdocsexample.repositories;
import guru.springframework.sfgrestdocsexample.domain.Beer;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.util.UUID;
/**
* Created by jt on 2019-05-17.
*/
public interface BeerRepository extends PagingAndSortingRepository<Beer, UUID> {
}

View File

@@ -0,0 +1,40 @@
package guru.springframework.sfgrestdocsexample.web.controller;
import guru.springframework.sfgrestdocsexample.web.model.BeerDto;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.UUID;
/**
* Created by jt on 2019-05-12.
*/
@RequestMapping("/api/v1/beer")
@RestController
public class BeerController {
@GetMapping("/{beerId}")
public ResponseEntity<BeerDto> getBeerById(@PathVariable("beerId") UUID beerId){
//todo impl
return new ResponseEntity<>(BeerDto.builder().build(), HttpStatus.OK);
}
@PostMapping
public ResponseEntity saveNewBeer(@RequestBody @Validated BeerDto beerDto){
//todo impl
return new ResponseEntity(HttpStatus.CREATED);
}
@PutMapping("/{beerId}")
public ResponseEntity updateBeerById(@PathVariable("beerId") UUID beerId, @RequestBody @Validated BeerDto beerDto){
//todo impl
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
}

View File

@@ -0,0 +1,27 @@
package guru.springframework.sfgrestdocsexample.web.controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jt on 2019-05-25.
*/
@ControllerAdvice
public class MvcExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<List> validationErrorHandler(ConstraintViolationException ex){
List<String> errorsList = new ArrayList<>(ex.getConstraintViolations().size());
ex.getConstraintViolations().forEach(error -> errorsList.add(error.toString()));
return new ResponseEntity<>(errorsList, HttpStatus.BAD_REQUEST);
}
}

View File

@@ -0,0 +1,16 @@
package guru.springframework.sfgrestdocsexample.web.mappers;
import guru.springframework.sfgrestdocsexample.domain.Beer;
import guru.springframework.sfgrestdocsexample.web.model.BeerDto;
import org.mapstruct.Mapper;
/**
* Created by jt on 2019-05-25.
*/
@Mapper(uses = {DateMapper.class})
public interface BeerMapper {
BeerDto BeerToBeerDto(Beer beer);
Beer BeerDtoToBeer(BeerDto dto);
}

View File

@@ -0,0 +1,31 @@
package guru.springframework.sfgrestdocsexample.web.mappers;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
/**
* Created by jt on 2019-05-25.
*/
@Component
public class DateMapper {
public OffsetDateTime asOffsetDateTime(Timestamp ts){
if (ts != null){
return OffsetDateTime.of(ts.toLocalDateTime().getYear(), ts.toLocalDateTime().getMonthValue(),
ts.toLocalDateTime().getDayOfMonth(), ts.toLocalDateTime().getHour(), ts.toLocalDateTime().getMinute(),
ts.toLocalDateTime().getSecond(), ts.toLocalDateTime().getNano(), ZoneOffset.UTC);
} else {
return null;
}
}
public Timestamp asTimestamp(OffsetDateTime offsetDateTime){
if(offsetDateTime != null) {
return Timestamp.valueOf(offsetDateTime.atZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());
} else {
return null;
}
}
}

View File

@@ -0,0 +1,54 @@
package guru.springframework.sfgrestdocsexample.web.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Null;
import javax.validation.constraints.Positive;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.util.UUID;
/**
* Created by jt on 2019-05-12.
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class BeerDto {
@Null
private UUID id;
@Null
private Integer version;
@Null
private OffsetDateTime createdDate;
@Null
private OffsetDateTime lastModifiedDate;
@NotBlank
private String beerName;
@NotNull
private BeerStyleEnum beerStyle;
@Positive
@NotNull
private Long upc;
@Positive
@NotNull
private BigDecimal price;
private Integer quantityOnHand;
}

View File

@@ -0,0 +1,21 @@
package guru.springframework.sfgrestdocsexample.web.model;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import java.util.List;
/**
* Created by jt on 2019-05-12.
*/
public class BeerPagedList extends PageImpl<BeerDto> {
public BeerPagedList(List<BeerDto> content, Pageable pageable, long total) {
super(content, pageable, total);
}
public BeerPagedList(List<BeerDto> content) {
super(content);
}
}

View File

@@ -0,0 +1,8 @@
package guru.springframework.sfgrestdocsexample.web.model;
/**
* Created by jt on 2019-05-12.
*/
public enum BeerStyleEnum {
LAGER, PILSNER, STOUT, GOSE, PORTER, ALE, WHEAT, IPA, PALE_ALE, SAISON
}

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,14 @@
package guru.springframework.sfgrestdocsexample;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class SfgRestdocsExampleApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -0,0 +1,65 @@
package guru.springframework.sfgrestdocsexample.web.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import guru.springframework.sfgrestdocsexample.web.model.BeerDto;
import guru.springframework.sfgrestdocsexample.web.model.BeerStyleEnum;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import java.math.BigDecimal;
import java.util.UUID;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(BeerController.class)
class BeerControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@Test
void getBeerById() throws Exception {
mockMvc.perform(get("/api/v1/beer/" + UUID.randomUUID().toString()).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
@Test
void saveNewBeer() throws Exception {
BeerDto beerDto = getValidBeerDto();
String beerDtoJson = objectMapper.writeValueAsString(beerDto);
mockMvc.perform(post("/api/v1/beer/")
.contentType(MediaType.APPLICATION_JSON)
.content(beerDtoJson))
.andExpect(status().isCreated());
}
@Test
void updateBeerById() throws Exception {
BeerDto beerDto = getValidBeerDto();
String beerDtoJson = objectMapper.writeValueAsString(beerDto);
mockMvc.perform(put("/api/v1/beer/" + UUID.randomUUID().toString())
.contentType(MediaType.APPLICATION_JSON)
.content(beerDtoJson))
.andExpect(status().isNoContent());
}
BeerDto getValidBeerDto(){
return BeerDto.builder()
.beerName("Nice Ale")
.beerStyle(BeerStyleEnum.ALE)
.price(new BigDecimal("9.99"))
.upc(123123123123L)
.build();
}
}