Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
bd1f2441f3
|
|||
|
0992635391
|
|||
|
a28033ff4c
|
|||
|
1a88cf37bc
|
+1
-1
@@ -1 +1 @@
|
|||||||
artefactVersion = 1.0.0
|
artefactVersion = 1.1.0
|
||||||
@@ -15,6 +15,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Validated
|
@Validated
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/modifications")
|
@RequestMapping("/modifications")
|
||||||
@@ -32,9 +34,10 @@ public class ModificationController {
|
|||||||
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
|
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size,
|
||||||
@RequestParam(required = false) @Positive Long firearmId,
|
@RequestParam(required = false) @Positive Long firearmId,
|
||||||
@RequestParam(defaultValue = "id") String sortBy,
|
@RequestParam(defaultValue = "id") String sortBy,
|
||||||
@RequestParam(defaultValue = "DESC") Sort.Direction direction
|
@RequestParam(defaultValue = "DESC") Sort.Direction direction,
|
||||||
|
@RequestParam(required = false) List<String> tags
|
||||||
) {
|
) {
|
||||||
return modificationService.pageQuery(firearmId, PageRequest.of(page, size, Sort.by(direction, sortBy)));
|
return modificationService.pageQuery(firearmId, tags, PageRequest.of(page, size, Sort.by(direction, sortBy)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
@@ -42,4 +45,3 @@ public class ModificationController {
|
|||||||
return modificationService.queryById(id);
|
return modificationService.queryById(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.onixbyte.deltaforceguide.controller;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import com.onixbyte.deltaforceguide.service.ModificationService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/tags")
|
||||||
|
public class TagController {
|
||||||
|
|
||||||
|
private final ModificationService modificationService;
|
||||||
|
|
||||||
|
public TagController(ModificationService modificationService) {
|
||||||
|
this.modificationService = modificationService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<String> getTags(@RequestParam(required = false) Long firearmId) {
|
||||||
|
return modificationService.findAllTags(firearmId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,10 @@ public record FirearmResponse(
|
|||||||
String name,
|
String name,
|
||||||
FirearmType type,
|
FirearmType type,
|
||||||
String level,
|
String level,
|
||||||
|
String calibre,
|
||||||
|
Integer fireRate,
|
||||||
|
Integer armourDamage,
|
||||||
|
Integer bodyDamage,
|
||||||
String review
|
String review
|
||||||
) {
|
) {
|
||||||
public static FirearmResponse from(Firearm firearm) {
|
public static FirearmResponse from(Firearm firearm) {
|
||||||
@@ -16,6 +20,10 @@ public record FirearmResponse(
|
|||||||
firearm.getName(),
|
firearm.getName(),
|
||||||
firearm.getType(),
|
firearm.getType(),
|
||||||
firearm.getLevel(),
|
firearm.getLevel(),
|
||||||
|
firearm.getCalibre(),
|
||||||
|
firearm.getFireRate(),
|
||||||
|
firearm.getArmourDamage(),
|
||||||
|
firearm.getBodyDamage(),
|
||||||
firearm.getReview()
|
firearm.getReview()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,18 @@ public class Firearm {
|
|||||||
@Column(name = "review", columnDefinition = "TEXT")
|
@Column(name = "review", columnDefinition = "TEXT")
|
||||||
private String review;
|
private String review;
|
||||||
|
|
||||||
|
@Column(name = "calibre")
|
||||||
|
private String calibre;
|
||||||
|
|
||||||
|
@Column(name = "fire_rate")
|
||||||
|
private Integer fireRate;
|
||||||
|
|
||||||
|
@Column(name = "armour_damage")
|
||||||
|
private Integer armourDamage;
|
||||||
|
|
||||||
|
@Column(name = "body_damage")
|
||||||
|
private Integer bodyDamage;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "firearm", cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToMany(mappedBy = "firearm", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
private List<Modification> modifications = new ArrayList<>();
|
private List<Modification> modifications = new ArrayList<>();
|
||||||
|
|
||||||
@@ -79,6 +91,38 @@ public class Firearm {
|
|||||||
this.review = review;
|
this.review = review;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCalibre() {
|
||||||
|
return calibre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalibre(String calibre) {
|
||||||
|
this.calibre = calibre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getFireRate() {
|
||||||
|
return fireRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFireRate(Integer fireRate) {
|
||||||
|
this.fireRate = fireRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getArmourDamage() {
|
||||||
|
return armourDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setArmourDamage(Integer armourDamage) {
|
||||||
|
this.armourDamage = armourDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBodyDamage() {
|
||||||
|
return bodyDamage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBodyDamage(Integer bodyDamage) {
|
||||||
|
this.bodyDamage = bodyDamage;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Modification> getModifications() {
|
public List<Modification> getModifications() {
|
||||||
return modifications;
|
return modifications;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
package com.onixbyte.deltaforceguide.repository;
|
package com.onixbyte.deltaforceguide.repository;
|
||||||
|
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.repository.EntityGraph;
|
import org.springframework.data.jpa.repository.EntityGraph;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@@ -20,7 +24,22 @@ public interface ModificationRepository extends JpaRepository<Modification, Long
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@EntityGraph(attributePaths = {"firearm"})
|
@EntityGraph(attributePaths = {"firearm"})
|
||||||
Optional<Modification> findById(Long id);
|
@NonNull
|
||||||
|
Optional<Modification> findById(@NonNull Long id);
|
||||||
|
|
||||||
|
@Query(value = """
|
||||||
|
SELECT * FROM modification m
|
||||||
|
WHERE (:firearmId IS NULL OR m.firearm_id = :firearmId)
|
||||||
|
AND (CAST(:tagsJson AS text) IS NULL OR cast(m.tags as jsonb) @> cast(CAST(:tagsJson AS text) as jsonb))
|
||||||
|
""",
|
||||||
|
countQuery = """
|
||||||
|
SELECT count(*) FROM modification m
|
||||||
|
WHERE (:firearmId IS NULL OR m.firearm_id = :firearmId)
|
||||||
|
AND (CAST(:tagsJson AS text) IS NULL OR cast(m.tags as jsonb) @> cast(CAST(:tagsJson AS text) as jsonb))
|
||||||
|
""",
|
||||||
|
nativeQuery = true)
|
||||||
|
Page<Modification> pageQueryByFirearmAndTags(@Param("firearmId") Long firearmId, @Param("tagsJson") String tagsJson, Pageable pageable);
|
||||||
|
|
||||||
|
@Query(value = "SELECT DISTINCT jsonb_array_elements_text(cast(tags as jsonb)) FROM modification WHERE (:firearmId IS NULL OR firearm_id = :firearmId)", nativeQuery = true)
|
||||||
|
List<String> findAllTags(@Param("firearmId") Long firearmId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import com.onixbyte.deltaforceguide.domain.dto.ModificationResponse;
|
|||||||
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
import com.onixbyte.deltaforceguide.domain.dto.PageResponse;
|
||||||
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
import com.onixbyte.deltaforceguide.domain.entity.Modification;
|
||||||
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
import com.onixbyte.deltaforceguide.repository.ModificationRepository;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -11,20 +13,36 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class ModificationService {
|
public class ModificationService {
|
||||||
|
|
||||||
private final ModificationRepository modificationRepository;
|
private final ModificationRepository modificationRepository;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
public ModificationService(ModificationRepository modificationRepository) {
|
public ModificationService(ModificationRepository modificationRepository, ObjectMapper objectMapper) {
|
||||||
this.modificationRepository = modificationRepository;
|
this.modificationRepository = modificationRepository;
|
||||||
|
this.objectMapper = objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public PageResponse<ModificationResponse> pageQuery(Long firearmId, Pageable pageable) {
|
public PageResponse<ModificationResponse> pageQuery(Long firearmId, List<String> tags, Pageable pageable) {
|
||||||
Page<Modification> page = firearmId == null
|
String tagsJson = null;
|
||||||
? modificationRepository.findAllBy(pageable)
|
if (tags != null && !tags.isEmpty()) {
|
||||||
: modificationRepository.findAllByFirearm_Id(firearmId, pageable);
|
try {
|
||||||
|
tagsJson = objectMapper.writeValueAsString(tags);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
throw new RuntimeException("Failed to serialize tags", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Page<Modification> page;
|
||||||
|
if (tagsJson != null || firearmId != null) {
|
||||||
|
page = modificationRepository.pageQueryByFirearmAndTags(firearmId, tagsJson, pageable);
|
||||||
|
} else {
|
||||||
|
page = modificationRepository.findAllBy(pageable);
|
||||||
|
}
|
||||||
|
|
||||||
return PageResponse.from(page.map(ModificationResponse::from));
|
return PageResponse.from(page.map(ModificationResponse::from));
|
||||||
}
|
}
|
||||||
@@ -35,5 +53,9 @@ public class ModificationService {
|
|||||||
.map(ModificationResponse::from)
|
.map(ModificationResponse::from)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Modification not found: " + id));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Modification not found: " + id));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<String> findAllTags(Long firearmId) {
|
||||||
|
return modificationRepository.findAllTags(firearmId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
-- 创建新表
|
||||||
|
CREATE TABLE firearm_new
|
||||||
|
(
|
||||||
|
id BIGSERIAL NOT NULL,
|
||||||
|
name VARCHAR(64) NOT NULL,
|
||||||
|
type INTEGER NOT NULL,
|
||||||
|
level VARCHAR(10) NOT NULL,
|
||||||
|
calibre VARCHAR(20) NOT NULL,
|
||||||
|
fire_rate INTEGER NOT NULL,
|
||||||
|
armour_damage INTEGER NOT NULL,
|
||||||
|
body_damage INTEGER NOT NULL,
|
||||||
|
review TEXT NULL,
|
||||||
|
CONSTRAINT firearm_new_pkey PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 迁移数据
|
||||||
|
INSERT INTO firearm_new(id, name, type, level, calibre, fire_rate, armour_damage, body_damage,
|
||||||
|
review)
|
||||||
|
SELECT id,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
level,
|
||||||
|
calibre,
|
||||||
|
0,
|
||||||
|
armour_damage,
|
||||||
|
body_damage,
|
||||||
|
review
|
||||||
|
FROM firearm;
|
||||||
|
|
||||||
|
-- 处理外键(关键步骤)
|
||||||
|
-- 先删除指向旧表的外键约束
|
||||||
|
ALTER TABLE modification
|
||||||
|
DROP CONSTRAINT fk_modification_firearm;
|
||||||
|
|
||||||
|
-- 重命名旧表和索引
|
||||||
|
ALTER TABLE firearm
|
||||||
|
RENAME TO firearm_legacy;
|
||||||
|
ALTER INDEX firearm_pkey RENAME TO firearm_legacy_pkey;
|
||||||
|
|
||||||
|
-- 重命名新表和索引
|
||||||
|
ALTER TABLE firearm_new
|
||||||
|
RENAME TO firearm;
|
||||||
|
ALTER INDEX firearm_new_pkey RENAME TO firearm_pkey;
|
||||||
|
|
||||||
|
-- 重新建立外键,指向新的 firearm 表
|
||||||
|
ALTER TABLE modification
|
||||||
|
ADD CONSTRAINT fk_modification_firearm
|
||||||
|
FOREIGN KEY (firearm_id) REFERENCES firearm (id);
|
||||||
|
|
||||||
|
-- 序列所有权与名称修正
|
||||||
|
ALTER SEQUENCE firearm_id_seq RENAME TO firearm_legacy_id_seq;
|
||||||
|
ALTER SEQUENCE firearm_new_id_seq RENAME TO firearm_id_seq;
|
||||||
|
ALTER SEQUENCE firearm_id_seq OWNED BY firearm.id;
|
||||||
|
|
||||||
|
-- 更新序列计数器
|
||||||
|
SELECT setval('firearm_id_seq', coalesce(max(id), 1))
|
||||||
|
FROM firearm;
|
||||||
|
|
||||||
|
-- 删除旧表
|
||||||
|
DROP TABLE IF EXISTS firearm_legacy CASCADE;
|
||||||
Reference in New Issue
Block a user