GlobalAward首次提交

This commit is contained in:
litianxiang
2026-01-16 16:37:03 +08:00
parent 9e9df5367d
commit 7b619aa4cb
6 changed files with 361 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.ai.da.controller;
import com.ai.da.common.response.Response;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.service.GlobalAwardService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
@RestController
@RequestMapping("/api/global-award")
public class GlobalAwardController {
@Resource
private GlobalAwardService globalAwardService;
@PostMapping("/uploads/pdf")
public Response<String> uploadPdf(@RequestParam("file") MultipartFile file,
@RequestParam(value = "email", required = false) String email) throws Exception {
return Response.success(globalAwardService.uploadPdf(file, email));
}
@PostMapping("/uploads/video")
public Response<String> uploadVideo(@RequestParam("file") MultipartFile file,
@RequestParam(value = "email", required = false) String email) throws Exception {
return Response.success(globalAwardService.uploadVideo(file, email));
}
@PostMapping("/contestants/save")
public Response<Map<String,Object>> submit(@RequestBody ContestantDTO request) {
return Response.success(globalAwardService.saveContestant(request));
}
@GetMapping("/contestants/by-email")
public Response<ContestantDTO> getContestantByEmail(@RequestParam("email") String email) {
ContestantDTO dto = globalAwardService.getContestantByEmail(email);
return Response.success(dto);
}
}

View File

@@ -0,0 +1,12 @@
package com.ai.da.mapper.primary;
import com.ai.da.mapper.primary.entity.Contestant;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface ContestantMapper extends BaseMapper<Contestant> {
}

View File

@@ -0,0 +1,72 @@
package com.ai.da.mapper.primary.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
/**
* submissions 表对应实体 — 参赛选手信息 (Contestant)
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@TableName("submissions")
public class Contestant {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String email;
@TableField("first_name")
private String firstName;
@TableField("last_name")
private String lastName;
private String gender;
private String occupation;
private Integer age;
@TableField("country_region_city")
private String countryRegionCity;
@TableField("phone_number")
private String phoneNumber;
@TableField("portfolio_url")
private String portfolioUrl;
@TableField("design_title")
private String designTitle;
@TableField("design_description")
private String designDescription;
@TableField("pdf_path")
private String pdfPath;
@TableField("video_path")
private String videoPath;
@TableField("created_at")
private LocalDateTime createdAt;
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("created_by")
private Long createdBy;
}

View File

@@ -0,0 +1,29 @@
package com.ai.da.model.dto;
import lombok.Data;
/**
* Contestant request DTO for Global Award
*/
@Data
public class ContestantDTO {
private String email;
private String firstName;
private String lastName;
private String gender;
private String occupation;
private Integer age;
private String countryRegionCity;
private String phoneNumber;
private String portfolioUrl;
private String designTitle;
private String designDescription;
private String pdfPath;
private String videoPath;
/**
* 是否确认覆盖已存在记录false 表示发现已有记录时仅返回 existingRecord不覆盖
*/
private Boolean confirm = false;
}

View File

@@ -0,0 +1,15 @@
package com.ai.da.service;
import com.ai.da.model.dto.ContestantDTO;
import org.springframework.web.multipart.MultipartFile;
import java.util.Map;
public interface GlobalAwardService {
String uploadPdf(MultipartFile file, String email) throws Exception;
String uploadVideo(MultipartFile file, String email) throws Exception;
Map<String, Object> saveContestant(ContestantDTO request);
com.ai.da.model.dto.ContestantDTO getContestantByEmail(String email);
}

View File

@@ -0,0 +1,190 @@
package com.ai.da.service.impl;
import com.ai.da.common.config.exception.BusinessException;
import com.ai.da.mapper.primary.ContestantMapper;
import com.ai.da.mapper.primary.entity.Contestant;
import com.ai.da.model.dto.ContestantDTO;
import com.ai.da.service.GlobalAwardService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import com.ai.da.common.utils.MinioUtil;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service
@Slf4j
public class GlobalAwardServiceImpl implements GlobalAwardService {
@Resource
private ContestantMapper contestantMapper;
@Value("${file.upload.dir:uploads}")
private String uploadDir;
private static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy/MM");
@Value("${minio.bucket:contestants}")
private String minioBucket;
@Resource
private MinioUtil minioUtil;
@Override
public String uploadPdf(MultipartFile file, String email) throws Exception {
validatePdf(file);
String path = storeFile(file, email, "pdf");
return path;
}
@Override
public String uploadVideo(MultipartFile file, String email) throws Exception {
validateVideo(file);
String path = storeFile(file, email, "video");
return path;
}
private void validatePdf(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BusinessException("file is empty");
}
String ct = file.getContentType();
if (ct == null || !ct.toLowerCase().contains("pdf")) {
throw new BusinessException("only pdf allowed");
}
// size limit example 20MB
if (file.getSize() > 20L * 1024 * 1024) {
throw new BusinessException("pdf too large");
}
}
private void validateVideo(MultipartFile file) {
if (file == null || file.isEmpty()) {
throw new BusinessException("file is empty");
}
String ct = file.getContentType();
if (ct == null || !(ct.toLowerCase().contains("mp4") || ct.toLowerCase().contains("video") )) {
throw new BusinessException("invalid video type");
}
// size limit example 100MB
if (file.getSize() > 100L * 1024 * 1024) {
throw new BusinessException("video too large");
}
}
private String normalizeEmail(String email) {
if (email == null) {
return "anonymous";
}
return email.replaceAll("[^a-zA-Z0-9]", "_");
}
private String storeFile(MultipartFile file, String email, String kind) throws IOException {
String normalized = normalizeEmail(email);
String datePart = LocalDateTime.now().format(YYYY_MM_DD);
String ext = "";
String original = file.getOriginalFilename();
if (original != null && original.contains(".")) {
ext = original.substring(original.lastIndexOf('.'));
}
String filename = System.currentTimeMillis() + "_" + UUID.randomUUID().toString() + ext;
String relativePath = "contestants/" + normalized + "/" + datePart + "/" + filename;
String uploadedPath = minioUtil.upload(minioBucket, relativePath, file, null);
log.info("uploaded via MinioUtil: {}", uploadedPath);
return uploadedPath;
}
@Override
public Map<String, Object> saveContestant(ContestantDTO request) {
Map<String,Object> resp = new HashMap<>();
if (request.getEmail() == null) {
throw new IllegalArgumentException("email required");
}
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", request.getEmail());
Contestant existing = contestantMapper.selectOne(qw);
LocalDateTime now = LocalDateTime.now();
if (existing == null) {
Contestant toInsert = Contestant.builder()
.email(request.getEmail())
.firstName(request.getFirstName())
.lastName(request.getLastName())
.gender(request.getGender())
.occupation(request.getOccupation())
.age(request.getAge())
.countryRegionCity(request.getCountryRegionCity())
.phoneNumber(request.getPhoneNumber())
.portfolioUrl(request.getPortfolioUrl())
.designTitle(request.getDesignTitle())
.designDescription(request.getDesignDescription())
.pdfPath(request.getPdfPath())
.videoPath(request.getVideoPath())
.createdAt(now)
.updatedAt(now)
.build();
contestantMapper.insert(toInsert);
resp.put("success", true);
return resp;
} else {
// update existing contestant
existing.setFirstName(request.getFirstName());
existing.setLastName(request.getLastName());
existing.setGender(request.getGender());
existing.setOccupation(request.getOccupation());
existing.setAge(request.getAge());
existing.setCountryRegionCity(request.getCountryRegionCity());
existing.setPhoneNumber(request.getPhoneNumber());
existing.setPortfolioUrl(request.getPortfolioUrl());
existing.setDesignTitle(request.getDesignTitle());
existing.setDesignDescription(request.getDesignDescription());
existing.setPdfPath(request.getPdfPath());
existing.setVideoPath(request.getVideoPath());
existing.setUpdatedAt(now);
contestantMapper.updateById(existing);
resp.put("success", true);
return resp;
}
}
@Override
public ContestantDTO getContestantByEmail(String email) {
if (email == null) {
throw new BusinessException("email required");
}
QueryWrapper<Contestant> qw = new QueryWrapper<>();
qw.eq("email", email);
Contestant existing = contestantMapper.selectOne(qw);
if (existing == null) {
return null;
}
ContestantDTO dto = new ContestantDTO();
dto.setEmail(existing.getEmail());
dto.setFirstName(existing.getFirstName());
dto.setLastName(existing.getLastName());
dto.setGender(existing.getGender());
dto.setOccupation(existing.getOccupation());
dto.setAge(existing.getAge());
dto.setCountryRegionCity(existing.getCountryRegionCity());
dto.setPhoneNumber(existing.getPhoneNumber());
dto.setPortfolioUrl(existing.getPortfolioUrl());
dto.setDesignTitle(existing.getDesignTitle());
dto.setDesignDescription(existing.getDesignDescription());
dto.setPdfPath(existing.getPdfPath());
dto.setVideoPath(existing.getVideoPath());
return dto;
}
}