参赛选手加入编号,增加导出功能
This commit is contained in:
@@ -63,7 +63,7 @@ public class AuthenticationFilter extends OncePerRequestFilter {
|
|||||||
//GlobalAwardController
|
//GlobalAwardController
|
||||||
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
|
"/api/global-award/uploads/pdf/init", "/api/global-award/uploads/pdf/chunk", "/api/global-award/uploads/pdf/complete", "/api/global-award/uploads/pdf/status",
|
||||||
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
|
"/api/global-award/uploads/video/init", "/api/global-award/uploads/video/chunk", "/api/global-award/uploads/video/complete", "/api/global-award/uploads/video/status",
|
||||||
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode"
|
"/api/global-award/contestants/save", "/api/global-award/contestants/by-email", "/api/global-award/checkEmail", "/api/global-award/checkCode","/api/global-award/contestants/export"
|
||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -163,6 +163,14 @@ public class GlobalAwardController {
|
|||||||
return Response.success(globalAwardService.checkCode(email, code));
|
return Response.success(globalAwardService.checkCode(email, code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/contestants/export")
|
||||||
|
@ApiOperation(value = "导出参赛者列表为Excel", notes = "导出所有参赛者信息为xlsx并触发下载")
|
||||||
|
public Response<Void> exportContestants() throws Exception {
|
||||||
|
// 将文件保存到服务端本地目录(uploadDir/exports),不返回文件内容给客户端
|
||||||
|
globalAwardService.saveContestantsToLocal();
|
||||||
|
return Response.success();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,17 @@ public interface GlobalAwardService {
|
|||||||
CheckOTPVO checkCode(String email, String otp);
|
CheckOTPVO checkCode(String email, String otp);
|
||||||
|
|
||||||
void checkSecurityToken(String email, String securityToken);
|
void checkSecurityToken(String email, String securityToken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出参赛者列表为 Excel(二进制)
|
||||||
|
* @return Excel 文件的字节数组
|
||||||
|
*/
|
||||||
|
byte[] exportContestants() throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将参赛者列表导出并保存到服务端本地目录(使用服务配置的 uploadDir/exports)
|
||||||
|
*/
|
||||||
|
void saveContestantsToLocal() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
@@ -29,6 +30,20 @@ import java.io.IOException;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.apache.poi.ss.usermodel.Cell;
|
||||||
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -128,6 +143,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Map<String, Object> saveContestant(ContestantDTO request) {
|
public Map<String, Object> saveContestant(ContestantDTO request) {
|
||||||
Map<String,Object> resp = new HashMap<>();
|
Map<String,Object> resp = new HashMap<>();
|
||||||
if (request.getEmail() == null) {
|
if (request.getEmail() == null) {
|
||||||
@@ -142,7 +158,14 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
if (existing == null) {
|
if (existing == null) {
|
||||||
|
// 生成唯一的参赛选手编号(从10000开始),使用数据库行锁保证并发安全与原子性
|
||||||
|
QueryWrapper<Contestant> numQw = new QueryWrapper<>();
|
||||||
|
numQw.isNotNull("contestant_number").orderByDesc("contestant_number").last("FOR UPDATE");
|
||||||
|
Contestant maxRow = contestantMapper.selectOne(numQw);
|
||||||
|
Integer nextContestantNumber = (maxRow == null || maxRow.getContestantNumber() == null) ? 10000 : maxRow.getContestantNumber() + 1;
|
||||||
|
|
||||||
Contestant toInsert = Contestant.builder()
|
Contestant toInsert = Contestant.builder()
|
||||||
|
.contestantNumber(nextContestantNumber)
|
||||||
.email(request.getEmail())
|
.email(request.getEmail())
|
||||||
.firstName(request.getFirstName())
|
.firstName(request.getFirstName())
|
||||||
.lastName(request.getLastName())
|
.lastName(request.getLastName())
|
||||||
@@ -160,6 +183,7 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
.build();
|
.build();
|
||||||
contestantMapper.insert(toInsert);
|
contestantMapper.insert(toInsert);
|
||||||
resp.put("success", true);
|
resp.put("success", true);
|
||||||
|
resp.put("contestant_number", nextContestantNumber);
|
||||||
sendSiteMsg(toInsert.getId(), toInsert.getEmail());
|
sendSiteMsg(toInsert.getId(), toInsert.getEmail());
|
||||||
return resp;
|
return resp;
|
||||||
} else {
|
} else {
|
||||||
@@ -178,10 +202,109 @@ public class GlobalAwardServiceImpl implements GlobalAwardService {
|
|||||||
existing.setUpdatedAt(now);
|
existing.setUpdatedAt(now);
|
||||||
contestantMapper.updateById(existing);
|
contestantMapper.updateById(existing);
|
||||||
resp.put("success", true);
|
resp.put("success", true);
|
||||||
|
resp.put("contestant_number", existing.getContestantNumber());
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] exportContestants() throws Exception {
|
||||||
|
List<Contestant> list = contestantMapper.selectList(new QueryWrapper<>());
|
||||||
|
try (XSSFWorkbook workbook = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||||
|
Sheet sheet = workbook.createSheet("contestants");
|
||||||
|
int rowIdx = 0;
|
||||||
|
Row header = sheet.createRow(rowIdx++);
|
||||||
|
String[] headers = new String[] {
|
||||||
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
|
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||||
|
"pdfPath", "videoPath", "createdAt", "updatedAt"
|
||||||
|
};
|
||||||
|
for (int i = 0; i < headers.length; i++) {
|
||||||
|
Cell c = header.createCell(i);
|
||||||
|
c.setCellValue(headers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Contestant cst : list) {
|
||||||
|
Row r = sheet.createRow(rowIdx++);
|
||||||
|
int ci = 0;
|
||||||
|
r.createCell(ci++).setCellValue(cst.getContestantNumber() == null ? "" : cst.getContestantNumber().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getEmail() == null ? "" : cst.getEmail());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getFirstName() == null ? "" : cst.getFirstName());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getLastName() == null ? "" : cst.getLastName());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getGender() == null ? "" : cst.getGender());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getOccupation() == null ? "" : cst.getOccupation());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getAge() == null ? "" : cst.getAge().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getCountryRegionCity() == null ? "" : cst.getCountryRegionCity());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
workbook.write(out);
|
||||||
|
out.flush();
|
||||||
|
return out.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("export contestants failed", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveContestantsToLocal() throws Exception {
|
||||||
|
List<Contestant> list = contestantMapper.selectList(new QueryWrapper<>());
|
||||||
|
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
|
||||||
|
String ts = LocalDateTime.now().format(fmt);
|
||||||
|
Path exportDir = Paths.get(uploadDir == null ? "uploads" : uploadDir, "exports");
|
||||||
|
Files.createDirectories(exportDir);
|
||||||
|
Path outPath = exportDir.resolve("contestants_" + ts + ".xlsx");
|
||||||
|
|
||||||
|
try (XSSFWorkbook workbook = new XSSFWorkbook(); FileOutputStream fos = new FileOutputStream(outPath.toFile())) {
|
||||||
|
Sheet sheet = workbook.createSheet("contestants");
|
||||||
|
int rowIdx = 0;
|
||||||
|
Row header = sheet.createRow(rowIdx++);
|
||||||
|
String[] headers = new String[] {
|
||||||
|
"contestantNumber", "email", "firstName", "lastName", "gender", "occupation",
|
||||||
|
"age", "countryRegionCity", "phoneNumber", "designTitle", "designDescription",
|
||||||
|
"pdfPath", "videoPath", "createdAt", "updatedAt"
|
||||||
|
};
|
||||||
|
for (int i = 0; i < headers.length; i++) {
|
||||||
|
Cell c = header.createCell(i);
|
||||||
|
c.setCellValue(headers[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Contestant cst : list) {
|
||||||
|
Row r = sheet.createRow(rowIdx++);
|
||||||
|
int ci = 0;
|
||||||
|
r.createCell(ci++).setCellValue(cst.getContestantNumber() == null ? "" : cst.getContestantNumber().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getEmail() == null ? "" : cst.getEmail());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getFirstName() == null ? "" : cst.getFirstName());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getLastName() == null ? "" : cst.getLastName());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getGender() == null ? "" : cst.getGender());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getOccupation() == null ? "" : cst.getOccupation());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getAge() == null ? "" : cst.getAge().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getCountryRegionCity() == null ? "" : cst.getCountryRegionCity());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPhoneNumber() == null ? "" : cst.getPhoneNumber());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getDesignTitle() == null ? "" : cst.getDesignTitle());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getDesignDescription() == null ? "" : cst.getDesignDescription());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getPdfPath() == null ? "" : cst.getPdfPath());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getVideoPath() == null ? "" : cst.getVideoPath());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getCreatedAt() == null ? "" : cst.getCreatedAt().toString());
|
||||||
|
r.createCell(ci++).setCellValue(cst.getUpdatedAt() == null ? "" : cst.getUpdatedAt().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
workbook.write(fos);
|
||||||
|
fos.flush();
|
||||||
|
log.info("Exported contestants to local file: {}", outPath.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("save contestants to local failed", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContestantDTO getContestantByID(String id) {
|
public ContestantDTO getContestantByID(String id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
|
|||||||
@@ -17,3 +17,4 @@
|
|||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user