feat: enhance Firearm entity and add query services with controllers
This commit is contained in:
@@ -49,6 +49,7 @@ dependencies {
|
|||||||
implementation(libs.flyway.core)
|
implementation(libs.flyway.core)
|
||||||
implementation(libs.flyway.mysql)
|
implementation(libs.flyway.mysql)
|
||||||
implementation(libs.jackson.jsr310)
|
implementation(libs.jackson.jsr310)
|
||||||
|
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.16")
|
||||||
testImplementation(libs.spring.boot.starter.test)
|
testImplementation(libs.spring.boot.starter.test)
|
||||||
testImplementation(libs.reactor.test)
|
testImplementation(libs.reactor.test)
|
||||||
testImplementation(libs.mybatis.starter.test)
|
testImplementation(libs.mybatis.starter.test)
|
||||||
|
|||||||
@@ -23,12 +23,16 @@ public class CorsConfig implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**")
|
registry.addMapping("/**")
|
||||||
.allowedOrigins(properties.allowedOrigins())
|
.allowedOrigins(toSafeArray(properties.allowedOrigins()))
|
||||||
.allowedHeaders(properties.allowedHeaders())
|
.allowedHeaders(toSafeArray(properties.allowedHeaders()))
|
||||||
.allowedMethods(toHttpMethodNames(properties.allowedMethods()))
|
.allowedMethods(toHttpMethodNames(properties.allowedMethods()))
|
||||||
.allowCredentials(properties.allowCredentials())
|
.allowCredentials(properties.allowCredentials())
|
||||||
.maxAge(properties.maxAge().toSeconds())
|
.maxAge(properties.maxAge().toSeconds())
|
||||||
.exposedHeaders(properties.exposedHeaders());
|
.exposedHeaders(toSafeArray(properties.exposedHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] toSafeArray(String[] values) {
|
||||||
|
return values == null ? new String[0] : values;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] toHttpMethodNames(HttpMethod[] methods) {
|
private static String[] toHttpMethodNames(HttpMethod[] methods) {
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.controller;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.FirearmResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.service.FirearmQueryService;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/firearms")
|
||||||
|
public class FirearmQueryController {
|
||||||
|
|
||||||
|
private final FirearmQueryService firearmQueryService;
|
||||||
|
|
||||||
|
public FirearmQueryController(FirearmQueryService firearmQueryService) {
|
||||||
|
this.firearmQueryService = firearmQueryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public PageResponse<FirearmResponse> pageQuery(
|
||||||
|
@RequestParam(defaultValue = "0") @Min(0) int page,
|
||||||
|
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
|
||||||
|
@RequestParam(defaultValue = "id") String sortBy,
|
||||||
|
@RequestParam(defaultValue = "DESC") Sort.Direction direction
|
||||||
|
) {
|
||||||
|
return firearmQueryService.pageQuery(PageRequest.of(page, size, Sort.by(direction, sortBy)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public FirearmResponse queryById(@PathVariable Long id) {
|
||||||
|
return firearmQueryService.queryById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.controller;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.ModificationResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.service.ModificationQueryService;
|
||||||
|
import jakarta.validation.constraints.Max;
|
||||||
|
import jakarta.validation.constraints.Min;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
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;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/modifications")
|
||||||
|
public class ModificationQueryController {
|
||||||
|
|
||||||
|
private final ModificationQueryService modificationQueryService;
|
||||||
|
|
||||||
|
public ModificationQueryController(ModificationQueryService modificationQueryService) {
|
||||||
|
this.modificationQueryService = modificationQueryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public PageResponse<ModificationResponse> pageQuery(
|
||||||
|
@RequestParam(defaultValue = "0") @Min(0) int page,
|
||||||
|
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
|
||||||
|
@RequestParam(defaultValue = "id") String sortBy,
|
||||||
|
@RequestParam(defaultValue = "DESC") Sort.Direction direction
|
||||||
|
) {
|
||||||
|
return modificationQueryService.pageQuery(PageRequest.of(page, size, Sort.by(direction, sortBy)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}")
|
||||||
|
public ModificationResponse queryById(@PathVariable Long id) {
|
||||||
|
return modificationQueryService.queryById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.domain.converter;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.enumeration.FirearmType;
|
||||||
|
import jakarta.persistence.AttributeConverter;
|
||||||
|
import jakarta.persistence.Converter;
|
||||||
|
|
||||||
|
@Converter
|
||||||
|
public class FirearmTypeConverter implements AttributeConverter<FirearmType, Integer> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer convertToDatabaseColumn(FirearmType attribute) {
|
||||||
|
return attribute == null ? null : attribute.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FirearmType convertToEntityAttribute(Integer dbData) {
|
||||||
|
return FirearmType.fromCode(dbData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.domain.dto;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
||||||
|
import com.onixbyte.deltaforceguide.enumeration.FirearmType;
|
||||||
|
|
||||||
|
public record FirearmResponse(
|
||||||
|
Long id,
|
||||||
|
String name,
|
||||||
|
FirearmType type,
|
||||||
|
String level,
|
||||||
|
String review
|
||||||
|
) {
|
||||||
|
public static FirearmResponse from(Firearm firearm) {
|
||||||
|
return new FirearmResponse(
|
||||||
|
firearm.getId(),
|
||||||
|
firearm.getName(),
|
||||||
|
firearm.getType(),
|
||||||
|
firearm.getLevel(),
|
||||||
|
firearm.getReview()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.domain.dto;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record ModificationResponse(
|
||||||
|
Long id,
|
||||||
|
Long firearmId,
|
||||||
|
String name,
|
||||||
|
String code,
|
||||||
|
List<String> tags,
|
||||||
|
String note,
|
||||||
|
String author,
|
||||||
|
String videoUrl
|
||||||
|
) {
|
||||||
|
public static ModificationResponse from(Modification modification) {
|
||||||
|
return new ModificationResponse(
|
||||||
|
modification.getId(),
|
||||||
|
modification.getFirearm().getId(),
|
||||||
|
modification.getName(),
|
||||||
|
modification.getCode(),
|
||||||
|
modification.getTags(),
|
||||||
|
modification.getNote(),
|
||||||
|
modification.getAuthor(),
|
||||||
|
modification.getVideoUrl()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.domain.dto;
|
||||||
|
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record PageResponse<T>(
|
||||||
|
List<T> items,
|
||||||
|
int page,
|
||||||
|
int size,
|
||||||
|
long totalElements,
|
||||||
|
int totalPages
|
||||||
|
) {
|
||||||
|
public static <T> PageResponse<T> from(Page<T> source) {
|
||||||
|
return new PageResponse<>(
|
||||||
|
source.getContent(),
|
||||||
|
source.getNumber(),
|
||||||
|
source.getSize(),
|
||||||
|
source.getTotalElements(),
|
||||||
|
source.getTotalPages()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.onixbyte.deltaforceguide.domain.entity;
|
package com.onixbyte.deltaforceguide.domain.entity;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.converter.FirearmTypeConverter;
|
||||||
|
import com.onixbyte.deltaforceguide.enumeration.FirearmType;
|
||||||
import jakarta.persistence.CascadeType;
|
import jakarta.persistence.CascadeType;
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Convert;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
@@ -24,10 +27,11 @@ public class Firearm {
|
|||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Column(name = "type", nullable = false)
|
@Column(name = "type", nullable = false)
|
||||||
private Integer type;
|
@Convert(converter = FirearmTypeConverter.class)
|
||||||
|
private FirearmType type;
|
||||||
|
|
||||||
@Column(name = "level", nullable = false)
|
@Column(name = "level", nullable = false)
|
||||||
private Integer level;
|
private String level;
|
||||||
|
|
||||||
@Column(name = "review", columnDefinition = "TEXT")
|
@Column(name = "review", columnDefinition = "TEXT")
|
||||||
private String review;
|
private String review;
|
||||||
@@ -51,19 +55,19 @@ public class Firearm {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getType() {
|
public FirearmType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(Integer type) {
|
public void setType(FirearmType type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getLevel() {
|
public String getLevel() {
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLevel(Integer level) {
|
public void setLevel(String level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.enumeration;
|
||||||
|
|
||||||
|
public enum FirearmType {
|
||||||
|
|
||||||
|
RIFLE(0),
|
||||||
|
SUB_MACHINE_GUN(1),
|
||||||
|
SHOTGUN(2),
|
||||||
|
LIGHT_MACHINE_GUN(3),
|
||||||
|
DESIGNATED_MARKSMAN_RIFLE(4),
|
||||||
|
SNIPER_RIFLE(5),
|
||||||
|
PISTOL(6),
|
||||||
|
SPECIAL(7);
|
||||||
|
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
FirearmType(int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FirearmType fromCode(Integer code) {
|
||||||
|
if (code == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FirearmType type : values()) {
|
||||||
|
if (type.code == code) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unknown FirearmType code: " + code);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.repository;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Firearm;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface FirearmRepository extends JpaRepository<Firearm, Long> {
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.repository;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.jpa.repository.EntityGraph;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface ModificationRepository extends JpaRepository<Modification, Long> {
|
||||||
|
|
||||||
|
@EntityGraph(attributePaths = {"firearm"})
|
||||||
|
Page<Modification> findAllBy(Pageable pageable);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@EntityGraph(attributePaths = {"firearm"})
|
||||||
|
Optional<Modification> findById(Long id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.service;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.FirearmResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.repository.FirearmRepository;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FirearmQueryService {
|
||||||
|
|
||||||
|
private final FirearmRepository firearmRepository;
|
||||||
|
|
||||||
|
public FirearmQueryService(FirearmRepository firearmRepository) {
|
||||||
|
this.firearmRepository = firearmRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public PageResponse<FirearmResponse> pageQuery(Pageable pageable) {
|
||||||
|
return PageResponse.from(
|
||||||
|
firearmRepository.findAll(pageable)
|
||||||
|
.map(FirearmResponse::from)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public FirearmResponse queryById(Long id) {
|
||||||
|
return firearmRepository.findById(id)
|
||||||
|
.map(FirearmResponse::from)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Firearm not found: " + id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.service;
|
||||||
|
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.ModificationResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
|
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ModificationQueryService {
|
||||||
|
|
||||||
|
private final ModificationRepository modificationRepository;
|
||||||
|
|
||||||
|
public ModificationQueryService(ModificationRepository modificationRepository) {
|
||||||
|
this.modificationRepository = modificationRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public PageResponse<ModificationResponse> pageQuery(Pageable pageable) {
|
||||||
|
return PageResponse.from(
|
||||||
|
modificationRepository.findAllBy(pageable)
|
||||||
|
.map(ModificationResponse::from)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public ModificationResponse queryById(Long id) {
|
||||||
|
return modificationRepository.findById(id)
|
||||||
|
.map(ModificationResponse::from)
|
||||||
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Modification not found: " + id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE firearm
|
||||||
|
MODIFY level VARCHAR(2) NOT NULL;
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.onixbyte.deltaforceguide;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
class DeltaForceGuideApplicationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void contextLoads() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user