first commit
This commit is contained in:
parent
e3f3176200
commit
28eaa63e19
52
.gitignore
vendored
52
.gitignore
vendored
@ -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/
|
||||
|
124
pom.xml
Normal file
124
pom.xml
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.1</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.dx.easychat</groupId>
|
||||
<artifactId>EasyChatting</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
<name>EasyChatting</name>
|
||||
<description>EasyChatting</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>21</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.51</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis-plus的依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>3.5.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- mybatis-plus代码生成工具的依赖 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-generator</artifactId>
|
||||
<version>3.5.7</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
|
||||
<dependency>
|
||||
<groupId>org.freemarker</groupId>
|
||||
<artifactId>freemarker</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.14.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<FileEntity> 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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Message> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(Message::getIsDelete, 0);
|
||||
List<Message> list = messageService.list(lambdaQueryWrapper);
|
||||
for (Message message : list) {
|
||||
if ("file".equals(message.getType())) {
|
||||
LambdaQueryWrapper<FileEntity> 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<Message> 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<Message> list = messageService.list(lambdaQueryWrapper);
|
||||
for (Message message : list) {
|
||||
if ("file".equals(message.getType())) {
|
||||
LambdaQueryWrapper<FileEntity> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(FileEntity::getUuid, message.getFile());
|
||||
List<FileEntity> fileEntityList = fileEntityService.list(queryWrapper);
|
||||
if (fileEntityList != null) {
|
||||
message.setFileEntityList(fileEntityList);
|
||||
}
|
||||
}
|
||||
}
|
||||
jsonObject.put("data", list);
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
}
|
@ -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<String> allDeleteFilePath = fileEntityMapper.findAllDeleteFilePath();
|
||||
for (String filePath : allDeleteFilePath) {
|
||||
File file = new File(filePath);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -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<FileEntity> fileEntityList;
|
||||
|
||||
}
|
@ -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<MultipartFile> 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 +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -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<String> 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();
|
||||
}
|
||||
}
|
@ -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<String, WebSocketSession> 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<FileEntity> 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<FileEntity> 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);
|
||||
}
|
||||
|
||||
}
|
@ -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<FileEntity> {
|
||||
|
||||
@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<String> findAllDeleteFilePath();
|
||||
|
||||
}
|
@ -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<Message> {
|
||||
}
|
@ -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<FileEntity> {
|
||||
}
|
@ -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<Message> {
|
||||
}
|
@ -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<FileEntityMapper, FileEntity> implements FileEntityService {
|
||||
|
||||
}
|
@ -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<MessageMapper, Message> implements MessageService {
|
||||
|
||||
}
|
31
src/main/resources/application-dev.yml
Normal file
31
src/main/resources/application-dev.yml
Normal file
@ -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
|
30
src/main/resources/application-prod.yml
Normal file
30
src/main/resources/application-prod.yml
Normal file
@ -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
|
3
src/main/resources/application.yml
Normal file
3
src/main/resources/application.yml
Normal file
@ -0,0 +1,3 @@
|
||||
spring:
|
||||
profiles:
|
||||
active: 'dev'
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user