@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ImportWebSocketHandler(), "/import-progress").setAllowedOrigins("*");
}
}
@Component
public class ImportWebSocketHandler extends TextWebSocketHandler {
private Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) {
sessions.put(session.getId(), session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
sessions.remove(session.getId());
}
public void sendProgress(String sessionId, String progress) throws IOException {
WebSocketSession session = sessions.get(sessionId);
if (session != null && session.isOpen()) {
session.sendMessage(new TextMessage(progress));
}
}
public void closeSession(String sessionId) throws IOException {
WebSocketSession session = sessions.get(sessionId);
if (session != null && session.isOpen()) {
session.close();
}
}
}
@Path("/import")
@Produces(MediaType.APPLICATION_JSON)
@Component
public class ImportResource {
@Autowired
private ImportWebSocketHandler webSocketHandler;
@Autowired
private ExcelReadListener excelReadListener;
@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(@FormDataParam("file") InputStream fileInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetail,
@HeaderParam("session-id") String sessionId) {
try {
String fileName = fileDetail.getFileName().toLowerCase();
if (!fileName.endsWith(".xls") && !fileName.endsWith(".xlsx")) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("{\"status\": \"error\", \"message\": \"Please upload an Excel file (.xls or .xlsx)\"}")
.build();
}
long totalRows = getExcelRowCount(fileInputStream);
fileInputStream.reset();
excelReadListener.setSessionId(sessionId);
excelReadListener.setTotalRows(totalRows);
EasyExcel.read(fileInputStream, ExcelData.class, excelReadListener)
.sheet()
.doRead();
return Response.ok("{\"status\": \"success\"}").build();
} catch (Exception e) {
return Response.serverError()
.entity("{\"status\": \"error\", \"message\": \"" + e.getMessage() + "\"}")
.build();
}
}
private long getExcelRowCount(InputStream inputStream) {
AtomicLong rowCount = new AtomicLong(0);
EasyExcel.read(inputStream, new NoModelDataListener() {
@Override
public void invoke(Object data, AnalysisContext context) {
rowCount.incrementAndGet();
}
}).sheet().doRead();
return rowCount.get();
}
}
@Component
public class ExcelReadListener implements ReadListener<ExcelData> {
@Autowired
private ImportWebSocketHandler webSocketHandler;
private String sessionId;
private long totalRows;
private long currentRow = 0;
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public void setTotalRows(long totalRows) {
this.totalRows = totalRows;
}
@Override
public void invoke(ExcelData data, AnalysisContext context) {
currentRow++;
try {
processRow(data);
double progress = (double) currentRow / totalRows * 100;
webSocketHandler.sendProgress(sessionId, String.format("%.2f%%", progress));
} catch (IOException e) {
throw new RuntimeException("Failed to send progress: " + e.getMessage());
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
try {
webSocketHandler.sendProgress(sessionId, "100%");
webSocketHandler.closeSession(sessionId);
} catch (IOException e) {
throw new RuntimeException("Failed to send final progress: " + e.getMessage());
}
}
private void processRow(ExcelData data) {
System.out.println("Processing: " + data);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异