From 28eaa63e1908b7342cf0be46dee1bb27bb549bdb Mon Sep 17 00:00:00 2001
From: xx572959496 <572959496@qq.com>
Date: Mon, 4 Nov 2024 15:11:00 +0800
Subject: [PATCH] first commit
---
.gitignore | 52 ++++---
pom.xml | 124 +++++++++++++++
.../CustomerApplicationRunner.java | 16 ++
.../easychatting/EasyChattingApplication.java | 15 ++
.../easychatting/ServletInitializer.java | 13 ++
.../easychatting/channel/ReceiveChannel.java | 56 +++++++
.../configuration/WebSocketConfiguration.java | 25 +++
.../controller/AutoGeneratorController.java | 59 +++++++
.../controller/FileController.java | 109 +++++++++++++
.../controller/MessageController.java | 91 +++++++++++
.../easychatting/cron/DeleteFileCronJob.java | 34 ++++
.../easychatting/entity/FileEntity.java | 38 +++++
.../easychat/easychatting/entity/Message.java | 56 +++++++
.../entity/vo/request/SendOfferEntity.java | 79 ++++++++++
.../filter/CorsCustomerFilter.java | 55 +++++++
.../handler/WebSocketReceiveHandler.java | 147 ++++++++++++++++++
.../easychatting/mapper/FileEntityMapper.java | 16 ++
.../easychatting/mapper/MessageMapper.java | 9 ++
.../service/FileEntityService.java | 7 +
.../easychatting/service/MessageService.java | 7 +
.../service/impl/FileEntityServiceImpl.java | 12 ++
.../service/impl/MessageServiceImpl.java | 12 ++
src/main/resources/application-dev.yml | 31 ++++
src/main/resources/application-prod.yml | 30 ++++
src/main/resources/application.yml | 3 +
.../EasyChattingApplicationTests.java | 13 ++
26 files changed, 1087 insertions(+), 22 deletions(-)
create mode 100644 pom.xml
create mode 100644 src/main/java/com/dx/easychat/easychatting/CustomerApplicationRunner.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/EasyChattingApplication.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/ServletInitializer.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/channel/ReceiveChannel.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/configuration/WebSocketConfiguration.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/controller/AutoGeneratorController.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/controller/FileController.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/controller/MessageController.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/cron/DeleteFileCronJob.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/entity/FileEntity.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/entity/Message.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/entity/vo/request/SendOfferEntity.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/filter/CorsCustomerFilter.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/handler/WebSocketReceiveHandler.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/mapper/FileEntityMapper.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/mapper/MessageMapper.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/service/FileEntityService.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/service/MessageService.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/service/impl/FileEntityServiceImpl.java
create mode 100644 src/main/java/com/dx/easychat/easychatting/service/impl/MessageServiceImpl.java
create mode 100644 src/main/resources/application-dev.yml
create mode 100644 src/main/resources/application-prod.yml
create mode 100644 src/main/resources/application.yml
create mode 100644 src/test/java/com/dx/easychat/easychatting/EasyChattingApplicationTests.java
diff --git a/.gitignore b/.gitignore
index 9154f4c..32de00b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,26 +1,34 @@
-# ---> Java
-# Compiled class file
-*.class
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
-# Log file
-*.log
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
-# BlueJ files
-*.ctxt
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-replay_pid*
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+### VS Code ###
+.vscode/
+/.mvn/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..a98cca4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,124 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.3.1
+
+
+ com.dx.easychat
+ EasyChatting
+ 0.0.1-SNAPSHOT
+ war
+ EasyChatting
+ EasyChatting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 21
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-websocket
+
+
+
+ com.alibaba.fastjson2
+ fastjson2
+ 2.0.51
+
+
+
+ com.mysql
+ mysql-connector-j
+ runtime
+
+
+
+
+ com.baomidou
+ mybatis-plus-spring-boot3-starter
+ 3.5.5
+
+
+
+
+ com.baomidou
+ mybatis-plus-generator
+ 3.5.7
+
+
+
+ org.freemarker
+ freemarker
+ compile
+
+
+
+
+
+ org.apache.commons
+ commons-lang3
+ 3.14.0
+
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ runtime
+ true
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/dx/easychat/easychatting/CustomerApplicationRunner.java b/src/main/java/com/dx/easychat/easychatting/CustomerApplicationRunner.java
new file mode 100644
index 0000000..5379e0b
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/CustomerApplicationRunner.java
@@ -0,0 +1,16 @@
+package com.dx.easychat.easychatting;
+
+import lombok.extern.log4j.Log4j2;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Log4j2
+@Component
+public class CustomerApplicationRunner implements ApplicationRunner {
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ log.info("启动netty");
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/EasyChattingApplication.java b/src/main/java/com/dx/easychat/easychatting/EasyChattingApplication.java
new file mode 100644
index 0000000..00b84b1
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/EasyChattingApplication.java
@@ -0,0 +1,15 @@
+package com.dx.easychat.easychatting;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@EnableScheduling
+public class EasyChattingApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(EasyChattingApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/ServletInitializer.java b/src/main/java/com/dx/easychat/easychatting/ServletInitializer.java
new file mode 100644
index 0000000..7d996f4
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/ServletInitializer.java
@@ -0,0 +1,13 @@
+package com.dx.easychat.easychatting;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+public class ServletInitializer extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(EasyChattingApplication.class);
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/channel/ReceiveChannel.java b/src/main/java/com/dx/easychat/easychatting/channel/ReceiveChannel.java
new file mode 100644
index 0000000..2e00839
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/channel/ReceiveChannel.java
@@ -0,0 +1,56 @@
+package com.dx.easychat.easychatting.channel;
+
+
+import jakarta.websocket.*;
+import jakarta.websocket.server.ServerEndpoint;
+import lombok.extern.log4j.Log4j2;
+
+import java.io.IOException;
+import java.time.Instant;
+
+@Log4j2
+@ServerEndpoint(value = "/channel/echo")
+public class ReceiveChannel {
+
+ private Session session;
+
+ // 收到消息
+ @OnMessage
+ public void onMessage(String message) throws IOException {
+
+ log.info("[websocket] 收到消息:id={},message={}", this.session.getId(), message);
+
+ if (message.equalsIgnoreCase("bye")) {
+ // 由服务器主动关闭连接。状态码为 NORMAL_CLOSURE(正常关闭)。
+ this.session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Bye"));;
+ return;
+ }
+
+
+ this.session.getAsyncRemote().sendText("["+ Instant.now().toEpochMilli() +"] Hello " + message);
+ }
+
+ // 连接打开
+ @OnOpen
+ public void onOpen(Session session, EndpointConfig endpointConfig){
+ // 保存 session 到对象
+ this.session = session;
+ log.info("[websocket] 新的连接:id={}", this.session.getId());
+ }
+
+ // 连接关闭
+ @OnClose
+ public void onClose(CloseReason closeReason){
+ log.info("[websocket] 连接断开:id={},reason={}", this.session.getId(),closeReason);
+ }
+
+ // 连接异常
+ @OnError
+ public void onError(Throwable throwable) throws IOException {
+
+ log.info("[websocket] 连接异常:id={},throwable={}", this.session.getId(), throwable.getMessage());
+
+ // 关闭连接。状态码为 UNEXPECTED_CONDITION(意料之外的异常)
+ this.session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, throwable.getMessage()));
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/configuration/WebSocketConfiguration.java b/src/main/java/com/dx/easychat/easychatting/configuration/WebSocketConfiguration.java
new file mode 100644
index 0000000..1a30790
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/configuration/WebSocketConfiguration.java
@@ -0,0 +1,25 @@
+package com.dx.easychat.easychatting.configuration;
+
+import com.dx.easychat.easychatting.handler.WebSocketReceiveHandler;
+import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
+
+
+@Configuration
+@EnableWebSocket
+public class WebSocketConfiguration implements WebSocketConfigurer {
+
+ @Resource
+ private WebSocketReceiveHandler webSocketReceiveHandler;
+
+ @Override
+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
+ registry.addHandler( webSocketReceiveHandler, "/websocket/message")
+ .setAllowedOrigins("*")
+ .addInterceptors(new HttpSessionHandshakeInterceptor());
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/controller/AutoGeneratorController.java b/src/main/java/com/dx/easychat/easychatting/controller/AutoGeneratorController.java
new file mode 100644
index 0000000..04c9e5d
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/controller/AutoGeneratorController.java
@@ -0,0 +1,59 @@
+package com.dx.easychat.easychatting.controller;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
+import jakarta.annotation.Resource;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/code")
+@Log4j2
+public class AutoGeneratorController {
+
+ @Resource
+ private DataSourceProperties dataSourceProperties;
+
+ @Value("${spring.customer.config.file-path:/opt/file_temp/}")
+ private String filePath;
+
+ @GetMapping("/generator")
+ @ResponseBody
+ public JSONObject generatorCode(@RequestParam String tableName) {
+ JSONObject jsonObject = new JSONObject();
+ String url = dataSourceProperties.getUrl();
+ String username = dataSourceProperties.getUsername();
+ String password = dataSourceProperties.getPassword();
+ FastAutoGenerator.create(url, username, password)
+ .globalConfig(builder -> builder
+ .author("xu.x")
+ .outputDir(filePath)
+ .disableOpenDir()
+ .commentDate("yyyy-MM-dd")
+ )
+ .packageConfig(builder -> builder
+ .parent("com.dx.easychat.easychatting")
+ .entity("entity")
+ .mapper("mapper")
+ .service("service")
+ .serviceImpl("service.impl")
+ .xml("mapper.xml")
+ )
+ .strategyConfig(builder ->
+ builder.addInclude(tableName) // 设置需要生成的表名
+ .addTablePrefix("db_") // 设置过滤表前缀
+ .entityBuilder()
+ .enableLombok()
+ )
+ .templateEngine(new FreemarkerTemplateEngine())
+ .execute();
+ jsonObject.put("code", "success");
+ jsonObject.put("data", null);
+ return jsonObject;
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/controller/FileController.java b/src/main/java/com/dx/easychat/easychatting/controller/FileController.java
new file mode 100644
index 0000000..ba5dfad
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/controller/FileController.java
@@ -0,0 +1,109 @@
+package com.dx.easychat.easychatting.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dx.easychat.easychatting.entity.FileEntity;
+import com.dx.easychat.easychatting.service.FileEntityService;
+import jakarta.annotation.Resource;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Date;
+import java.util.UUID;
+
+@RestController
+@Log4j2
+@RequestMapping("/api/file")
+public class FileController {
+
+ // TODO 文件上传同名问题
+ // TODO 删除消息时 同步删除物理文件
+ @Value("${spring.customer.config.file-path:/opt/file_temp/}")
+ private String filePath;
+
+ @Resource
+ private FileEntityService fileEntityService;
+
+ @PostMapping("/upload")
+ @ResponseBody
+ public String uploadImageFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
+ JSONObject jsonObject = new JSONObject();
+ //获取文件名
+ String fileName = multipartFile.getOriginalFilename();
+ //获取文件后缀名
+ assert fileName != null;
+ String contentType = multipartFile.getContentType();
+ String fileType = "";
+ int index = fileName.lastIndexOf(".");
+ if (index != -1) {
+ fileType = fileName.substring(index + 1);
+ }
+ FileEntity fileEntity = new FileEntity();
+ String uuid = UUID.randomUUID().toString();
+ fileEntity.setUuid(uuid);
+ fileEntity.setFileName(fileName);
+ String realFilePath = filePath + uuid;
+ fileEntity.setFilePath(realFilePath);
+ fileEntity.setUploadTime(new Date());
+ fileEntity.setFileMimeType(contentType);
+ fileEntity.setFileType(fileType);
+ log.info("文件名:{}", fileName);
+ log.info("filePath:{}", filePath);
+ File uploadFile = new File(realFilePath);
+ //将临时文件转存到指定磁盘位置
+ multipartFile.transferTo(uploadFile);
+ fileEntityService.save(fileEntity);
+ jsonObject.put("code", 200);
+ jsonObject.put("uuid", uuid);
+ jsonObject.put("fileType", fileType);
+ jsonObject.put("fileMimeType", contentType);
+ return jsonObject.toJSONString();
+ }
+
+ /**
+ * 下载文件:将输入流中的数据循环写入到响应输出流中,而不是一次性读取到内存
+ *
+ * @param fileId 文档id
+ * @param response 返回体
+ */
+ @GetMapping("/{fileId}")
+ public void downLoadFile(HttpServletResponse response, @PathVariable String fileId) throws IOException {
+ response.setContentType("text/json;charset=utf-8");
+ PrintWriter writer = response.getWriter();
+ try {
+ // 读到流中
+ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
+ lambdaQueryWrapper.eq(FileEntity::getUuid, fileId);
+ FileEntity fileEntity = fileEntityService.getOne(lambdaQueryWrapper);
+ log.info("下载时的查询:{}", fileEntity);
+ InputStream inputStream = Files.newInputStream(Paths.get(fileEntity.getFilePath()));
+ String fileName = fileEntity.getFileName();
+ response.reset();
+ response.setContentType("application/octet-stream");
+ response.addHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
+ ServletOutputStream outputStream = response.getOutputStream();
+ byte[] b = new byte[1024];
+ int len;
+ //从输入流中读取一定数量的字节,并将其存储在缓冲区字节数组中,读到末尾返回-1
+ while ((len = inputStream.read(b)) > 0) {
+ outputStream.write(b, 0, len);
+ }
+ inputStream.close();
+ } catch (Exception e) {
+ log.error("下载文件异常:{}", e.getMessage());
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("code",500);
+ jsonObject.put("message",e.getMessage());
+ writer.write(jsonObject.toJSONString());
+ }
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/controller/MessageController.java b/src/main/java/com/dx/easychat/easychatting/controller/MessageController.java
new file mode 100644
index 0000000..a195e49
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/controller/MessageController.java
@@ -0,0 +1,91 @@
+package com.dx.easychat.easychatting.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dx.easychat.easychatting.entity.FileEntity;
+import com.dx.easychat.easychatting.entity.Message;
+import com.dx.easychat.easychatting.service.FileEntityService;
+import com.dx.easychat.easychatting.service.MessageService;
+import jakarta.annotation.Resource;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController()
+@Log4j2
+@RequestMapping("/api/message")
+public class MessageController {
+
+ @Resource
+ private MessageService messageService;
+
+ @Resource
+ private FileEntityService fileEntityService;
+
+ @PostMapping("/config")
+ @ResponseBody
+ public JSONObject getConfig(@RequestBody JSONObject jsonObject) {
+ JSONObject result = new JSONObject();
+ String string = jsonObject.getString("id");
+ log.info(string);
+ int length = string.length();
+ log.info(length);
+ log.info(jsonObject);
+ return result;
+ }
+
+ // todo 增加校验webservice的session
+ @GetMapping("/get")
+ @ResponseBody
+ public JSONObject getHistoryMessage() {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("code", 200);
+ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
+ lambdaQueryWrapper.eq(Message::getIsDelete, 0);
+ List list = messageService.list(lambdaQueryWrapper);
+ for (Message message : list) {
+ if ("file".equals(message.getType())) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(FileEntity::getUuid, message.getFile());
+ FileEntity fileEntity = fileEntityService.getOne(queryWrapper);
+ if (fileEntity != null) {
+ String fileMimeType = fileEntity.getFileMimeType();
+ message.setFileMimeType(fileMimeType);
+ message.setFileName(fileEntity.getFileName());
+ }
+ }
+ }
+ jsonObject.put("data", list);
+ return jsonObject;
+ }
+
+ @GetMapping("/message")
+ @ResponseBody
+ public JSONObject getMessage(String message_id) {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("code", 200);
+ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
+ lambdaQueryWrapper.eq(Message::getIsDelete, 0);
+ if (StringUtils.isNotBlank(message_id)) {
+ lambdaQueryWrapper.and(wrapper ->
+ wrapper.eq(Message::getId, message_id).or()
+ .eq(Message::getId, 1));
+ }
+ List list = messageService.list(lambdaQueryWrapper);
+ for (Message message : list) {
+ if ("file".equals(message.getType())) {
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.eq(FileEntity::getUuid, message.getFile());
+ List fileEntityList = fileEntityService.list(queryWrapper);
+ if (fileEntityList != null) {
+ message.setFileEntityList(fileEntityList);
+ }
+ }
+ }
+ jsonObject.put("data", list);
+ return jsonObject;
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/cron/DeleteFileCronJob.java b/src/main/java/com/dx/easychat/easychatting/cron/DeleteFileCronJob.java
new file mode 100644
index 0000000..5369d86
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/cron/DeleteFileCronJob.java
@@ -0,0 +1,34 @@
+package com.dx.easychat.easychatting.cron;
+
+import com.dx.easychat.easychatting.mapper.FileEntityMapper;
+import jakarta.annotation.Resource;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * 定时任务:每五分钟执行一次
+ * 查询出已经到达过期时间的数据,删除物理文件同时更新回表单
+ */
+@Component
+@Log4j2
+public class DeleteFileCronJob {
+
+ @Resource
+ FileEntityMapper fileEntityMapper;
+
+ @Scheduled(cron ="0 0/5 * * * ?")
+ public void executeCronJob() {
+ List allDeleteFilePath = fileEntityMapper.findAllDeleteFilePath();
+ for (String filePath : allDeleteFilePath) {
+ File file = new File(filePath);
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/entity/FileEntity.java b/src/main/java/com/dx/easychat/easychatting/entity/FileEntity.java
new file mode 100644
index 0000000..0cdc7f2
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/entity/FileEntity.java
@@ -0,0 +1,38 @@
+package com.dx.easychat.easychatting.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.extern.log4j.Log4j2;
+
+import java.util.Date;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Log4j2
+@TableName("db_file")
+public class FileEntity {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ private String uuid;
+
+ private String fileName;
+
+ private String fileType;
+
+ private String fileMimeType;
+
+ private String filePath;
+
+ private Integer isDelete;
+
+ private Date uploadTime;
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/entity/Message.java b/src/main/java/com/dx/easychat/easychatting/entity/Message.java
new file mode 100644
index 0000000..963324d
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/entity/Message.java
@@ -0,0 +1,56 @@
+package com.dx.easychat.easychatting.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 com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.extern.log4j.Log4j2;
+
+import java.util.Date;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ToString
+@Log4j2
+@TableName("db_message")
+public class Message {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ private String content;
+
+ private Date time;
+
+ private String type;
+
+ private String file;
+
+ private Integer isDelete;
+
+ @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ private String ip;
+
+ @TableField(exist = false)
+ private String sessionId;
+
+ @TableField(exist = false)
+ private String messageType;
+
+ @TableField(exist = false)
+ private String fileName;
+
+ @TableField(exist = false)
+ private String fileMimeType;
+
+ @TableField(exist = false)
+ private List fileEntityList;
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/entity/vo/request/SendOfferEntity.java b/src/main/java/com/dx/easychat/easychatting/entity/vo/request/SendOfferEntity.java
new file mode 100644
index 0000000..bbbb1a5
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/entity/vo/request/SendOfferEntity.java
@@ -0,0 +1,79 @@
+package com.dx.easychat.easychatting.entity.vo.request;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 前端请求的发送offer参数实体类
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SendOfferEntity {
+
+ /**
+ * 是否快速入职
+ */
+ private Integer isFastIn;
+
+ /**
+ * 是否快速入职
+ */
+ private Integer isUploadMedicalReport;
+
+ /**
+ * 是否短信通知
+ */
+ private Boolean isMessageNotice;
+
+ /**
+ * 短信内容
+ */
+ private String messageContent;
+
+ /**
+ * 是否邮件通知
+ */
+ private Boolean isEmailNotice;
+
+ /**
+ * 邮件标题
+ */
+ private String emailTitle;
+
+ /**
+ * 邮件内容
+ */
+ private String emailContent;
+
+ /**
+ * 选中的行ID 以逗号分隔
+ */
+ private String ids;
+
+ /**
+ * 入职须知(文件上传)
+ */
+ private List file;
+
+
+ @Override
+ public String toString() {
+ return "SendOfferEntity{" +
+ "isFastIn=" + isFastIn +
+ ", \nisUploadMedicalReport=" + isUploadMedicalReport +
+ ", \nisMessageNotice=" + isMessageNotice +
+ ", \nmessageContent='" + messageContent + '\'' +
+ ", \nisEmailNotice=" + isEmailNotice +
+ ", \nemailTitle='" + emailTitle + '\'' +
+ ", \nemailContent='" + emailContent + '\'' +
+ ", \nids='" + ids + '\'' +
+ ", \nfile=" + file +
+ '}';
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/filter/CorsCustomerFilter.java b/src/main/java/com/dx/easychat/easychatting/filter/CorsCustomerFilter.java
new file mode 100644
index 0000000..eae4ee7
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/filter/CorsCustomerFilter.java
@@ -0,0 +1,55 @@
+package com.dx.easychat.easychatting.filter;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpFilter;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+@Component
+@Order(-102)
+@Log4j2
+public class CorsCustomerFilter extends HttpFilter {
+
+ @Value("${spring.security.cors.origin:http://localhost:5173,http://127.0.0.1:5173}")
+ private String allowOrigin;
+
+ @Override
+ protected void doFilter(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+ response.addHeader("Access-Control-Allow-Origin",this.resolveOrigin(request));
+ response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS");
+ // response.addHeader("Access-Control-Allow-Headers","Authorization, Content-Type");
+ response.addHeader("Access-Control-Allow-Headers","*");
+ chain.doFilter(request, response);
+ }
+
+ private void addCorsHeader(HttpServletRequest request,
+ HttpServletResponse response) {
+ response.addHeader("Access-Control-Allow-Origin",allowOrigin);
+ response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS");
+ response.addHeader("Access-Control-Allow-Headers","Authorization, Content-Type");
+ }
+
+ /**
+ * 解析配置文件中的请求原始站点
+ * @param request 请求
+ * @return 解析得到的请求头值
+ */
+ private String resolveOrigin(HttpServletRequest request){
+ List list = Arrays.asList(allowOrigin.split(","));
+ String origin = request.getHeader("Origin");
+ if (list.isEmpty()) return "http://localhost:5173";
+ if ("*".equals(allowOrigin) || list.contains(origin)) return origin;
+ else return list.getFirst();
+ }
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/handler/WebSocketReceiveHandler.java b/src/main/java/com/dx/easychat/easychatting/handler/WebSocketReceiveHandler.java
new file mode 100644
index 0000000..7900799
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/handler/WebSocketReceiveHandler.java
@@ -0,0 +1,147 @@
+package com.dx.easychat.easychatting.handler;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dx.easychat.easychatting.entity.FileEntity;
+import com.dx.easychat.easychatting.entity.Message;
+import com.dx.easychat.easychatting.service.FileEntityService;
+import com.dx.easychat.easychatting.service.impl.MessageServiceImpl;
+import jakarta.annotation.Resource;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.*;
+import org.springframework.web.socket.handler.TextWebSocketHandler;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Log4j2
+@Component
+public class WebSocketReceiveHandler extends TextWebSocketHandler{
+
+ @Resource
+ private MessageServiceImpl messageService;
+
+ @Resource
+ private FileEntityService fileEntityService;
+
+ public static ConcurrentHashMap SessionsPool = new ConcurrentHashMap<>();
+
+ @Override
+ public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+ log.info("建立ws链接: id={}", session.getId());
+ SessionsPool.put(session.getId(), session);
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("id", session.getId());
+ jsonObject.put("messageType", "heartbeat");
+ jsonObject.put("status", true);
+ jsonObject.put("onlineNumber", SessionsPool.size());
+ session.sendMessage(new TextMessage(jsonObject.toJSONString()));
+ super.afterConnectionEstablished(session);
+ }
+
+ @Override
+ protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+ String payload = message.getPayload();
+ InetSocketAddress remoteAddress = session.getRemoteAddress();
+ log.info("接收到消息:id={},message={},ip={}", session.getId(), payload, remoteAddress);
+ boolean valid = JSON.isValid(payload);
+ if (valid) {
+ Message messageEntity = JSONObject.parseObject(payload, Message.class);
+ log.info("转换实体类:{}", messageEntity);
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("id", session.getId());
+ jsonObject.put("messageType", "heartbeat");
+ jsonObject.put("status", true);
+ jsonObject.put("onlineNumber", SessionsPool.size());
+ if (StringUtils.isNoneEmpty(messageEntity.getSessionId()) && SessionsPool.containsKey(session.getId())) {
+ switch (messageEntity.getMessageType()) {
+ case "delete":
+ messageService.updateById(messageEntity);
+ if ("file".equals(messageEntity.getType())){
+ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
+ lambdaQueryWrapper.eq(FileEntity::getUuid, messageEntity.getFile());
+ FileEntity fileEntity = fileEntityService.getOne(lambdaQueryWrapper);
+ if (fileEntity != null) {
+ File file = new File(fileEntity.getFilePath());
+ if (file.exists()) {
+ file.delete();
+ }
+ fileEntityService.removeById(fileEntity.getId());
+ }
+ }
+ break;
+ case "heartbeat":
+ session.sendMessage(new TextMessage(jsonObject.toJSONString()));
+ break;
+ case "send":
+ Message messageDto = new Message();
+ BeanUtils.copyProperties(messageEntity, messageDto);
+ messageDto.setIp(Objects.requireNonNull(session.getRemoteAddress()).getAddress().getHostAddress());
+ messageService.save(messageDto);
+ if ("file".equals(messageEntity.getType())){
+ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
+ lambdaQueryWrapper.eq(FileEntity::getUuid, messageEntity.getFile());
+ FileEntity fileEntity = fileEntityService.getOne(lambdaQueryWrapper);
+ String fileMimeType = fileEntity.getFileMimeType();
+ messageEntity.setFileMimeType(fileMimeType);
+ messageEntity.setFileName(fileEntity.getFileName());
+ }
+ messageEntity.setMessageType("receive");
+ SessionsPool.forEach((key, value) -> {
+ try {
+ value.sendMessage(new TextMessage(JSONObject.toJSONString(messageEntity)));
+ } catch (IOException e) {
+ log.info("广播消息:{}", e.getMessage());
+ }
+ });
+ break;
+ default:
+ log.error("未知类型数据");
+ }
+ }else {
+ log.error("请求sessionID不存在,重新获取session");
+ jsonObject.put("status", false);
+ jsonObject.put("message", "请求sessionID不存在,重新下发session");
+ session.sendMessage(new TextMessage(jsonObject.toJSONString()));
+ }
+ }else {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("code", -1);
+ jsonObject.put("message", "请求错误");
+ jsonObject.put("time", System.currentTimeMillis());
+ session.sendMessage(new TextMessage(jsonObject.toJSONString()));
+ }
+ super.handleTextMessage(session, message);
+ }
+
+ @Override
+ protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
+ log.info("接收到二进制消息::id={},message={}", session.getId(), message.getPayload());
+ super.handleBinaryMessage(session, message);
+ }
+
+ @Override
+ public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+ log.error("出现异常:id={},message={}", session.getId(), exception.getMessage());
+ super.handleTransportError(session, exception);
+ }
+
+ @Override
+ public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+ String sessionId = session.getId();
+ log.info("断开链接:id={},status={}", sessionId, status);
+ WebSocketSession remove = SessionsPool.remove(sessionId);
+ if (remove != null) {
+ remove.close();
+ }
+ super.afterConnectionClosed(session, status);
+ }
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/mapper/FileEntityMapper.java b/src/main/java/com/dx/easychat/easychatting/mapper/FileEntityMapper.java
new file mode 100644
index 0000000..fa589d0
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/mapper/FileEntityMapper.java
@@ -0,0 +1,16 @@
+package com.dx.easychat.easychatting.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.dx.easychat.easychatting.entity.FileEntity;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+@Mapper
+public interface FileEntityMapper extends BaseMapper {
+
+ @Select("SELECT file_path FROM db_message t1 LEFT JOIN db_file t2 on t1.file = t2.uuid WHERE type = 'file' AND t1.is_delete = 1")
+ List findAllDeleteFilePath();
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/mapper/MessageMapper.java b/src/main/java/com/dx/easychat/easychatting/mapper/MessageMapper.java
new file mode 100644
index 0000000..c360929
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/mapper/MessageMapper.java
@@ -0,0 +1,9 @@
+package com.dx.easychat.easychatting.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.dx.easychat.easychatting.entity.Message;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MessageMapper extends BaseMapper {
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/service/FileEntityService.java b/src/main/java/com/dx/easychat/easychatting/service/FileEntityService.java
new file mode 100644
index 0000000..9e3499a
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/service/FileEntityService.java
@@ -0,0 +1,7 @@
+package com.dx.easychat.easychatting.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dx.easychat.easychatting.entity.FileEntity;
+
+public interface FileEntityService extends IService {
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/service/MessageService.java b/src/main/java/com/dx/easychat/easychatting/service/MessageService.java
new file mode 100644
index 0000000..eec8da1
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/service/MessageService.java
@@ -0,0 +1,7 @@
+package com.dx.easychat.easychatting.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.dx.easychat.easychatting.entity.Message;
+
+public interface MessageService extends IService {
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/service/impl/FileEntityServiceImpl.java b/src/main/java/com/dx/easychat/easychatting/service/impl/FileEntityServiceImpl.java
new file mode 100644
index 0000000..20c6508
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/service/impl/FileEntityServiceImpl.java
@@ -0,0 +1,12 @@
+package com.dx.easychat.easychatting.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dx.easychat.easychatting.entity.FileEntity;
+import com.dx.easychat.easychatting.mapper.FileEntityMapper;
+import com.dx.easychat.easychatting.service.FileEntityService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FileEntityServiceImpl extends ServiceImpl implements FileEntityService {
+
+}
diff --git a/src/main/java/com/dx/easychat/easychatting/service/impl/MessageServiceImpl.java b/src/main/java/com/dx/easychat/easychatting/service/impl/MessageServiceImpl.java
new file mode 100644
index 0000000..6f92bdc
--- /dev/null
+++ b/src/main/java/com/dx/easychat/easychatting/service/impl/MessageServiceImpl.java
@@ -0,0 +1,12 @@
+package com.dx.easychat.easychatting.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.dx.easychat.easychatting.entity.Message;
+import com.dx.easychat.easychatting.mapper.MessageMapper;
+import com.dx.easychat.easychatting.service.MessageService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MessageServiceImpl extends ServiceImpl implements MessageService {
+
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..6c28edc
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,31 @@
+spring:
+ servlet:
+ multipart:
+ enabled: true
+ max-file-size: 20MB
+ max-request-size: 20MB
+ security:
+ filter:
+ order: -100
+ cors:
+ origin: http://127.0.0.1:5173,http://localhost:5173
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://127.0.0.1:3306/project
+ username: root
+ password: XXdove521..
+ customer:
+ config:
+ file-path: /Users/xx/Dev/file/
+
+
+mybatis-plus:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ call-setters-on-nulls: false
+logging:
+ file:
+ path: ./
+ name: spring.log
+ level:
+ com.dx.easychat.easychatting.service: info
\ No newline at end of file
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..48a47b5
--- /dev/null
+++ b/src/main/resources/application-prod.yml
@@ -0,0 +1,30 @@
+spring:
+ servlet:
+ multipart:
+ enabled: true
+ max-file-size: 20MB
+ max-request-size: 20MB
+ security:
+ filter:
+ order: -100
+ cors:
+ origin: http://127.0.0.1:5173,http://localhost:5173
+ datasource:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ # 生产环境
+ url: jdbc:mysql://127.0.0.1:3306/project
+ username: xiaoxu
+ password: xxdove521
+ customer:
+ config:
+ file-path: /opt/easychatting/file_temp
+mybatis-plus:
+ configuration:
+ log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ call-setters-on-nulls: false
+logging:
+ file:
+ path: ./
+ name: spring.log
+server:
+ port: 8020
\ No newline at end of file
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..686b110
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+spring:
+ profiles:
+ active: 'dev'
\ No newline at end of file
diff --git a/src/test/java/com/dx/easychat/easychatting/EasyChattingApplicationTests.java b/src/test/java/com/dx/easychat/easychatting/EasyChattingApplicationTests.java
new file mode 100644
index 0000000..b405b0e
--- /dev/null
+++ b/src/test/java/com/dx/easychat/easychatting/EasyChattingApplicationTests.java
@@ -0,0 +1,13 @@
+package com.dx.easychat.easychatting;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class EasyChattingApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}