This commit is contained in:
oneao committed 2025-10-14 17:30:21 +08:00
1 parent 35951777b0
commit 63f1d4d1dc
39 files changed
+880 -133

No files matched your search

@@ -24,6 +24,7 @@ public class AuthController {
response.put("message", "Missing parameters");
return response;
}
UserInfo userInfo = UserRepository.getUserPasswordById(orgId, userId);
if (userInfo != null && userInfo.getPassword().equals(password)) {
String token = JwtUtil.generateToken(userId, orgId);
@@ -33,6 +34,7 @@ public class AuthController {
} else {
response.put("message", "Invalid credentials");
}
return response;
}
@@ -19,10 +19,7 @@ public class ColumnConfigController {
*/
@GetMapping("/api/columns")
public Result<?> getColumnConfig(@RequestParam String tableName, HttpServletRequest request) {
try {
String orgId = UserContext.getOrgId();
System.out.println("api/columns:"+orgId);
List<Map<String, Object>> data = JsonUtils.queryColumnConfig(orgId, tableName);
@@ -32,10 +29,8 @@ public class ColumnConfigController {
}
}
@GetMapping("/api/columnsEdit")
public Result<?> getColumnEditConfig(@RequestParam String tableName, HttpServletRequest request) {
try {
String orgId = UserContext.getOrgId();
List<Map<String, Object>> data = JsonUtils.queryColumnEditConfig(orgId, tableName);
@@ -8,7 +8,7 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("http://localhost:5173", "http://localhost:8089","http://localhost:5174") // 前端地址
.allowedOriginPatterns("*") // 前端地址
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
@@ -3,11 +3,15 @@ package com.link.api.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.link.im.manager.UserChannelManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.sql.*;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
public class PaginationUtils {
@@ -470,5 +474,5 @@ public class PaginationUtils {
}
}
}
}
@@ -0,0 +1,43 @@
package com.link.im.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.link.api.util.DruidDataSourceManager;
import com.link.api.util.PaginationUtils;
import com.link.api.util.Result;
import com.link.api.util.UserContext;
import com.link.im.manager.UserChannelManager;
import com.link.im.utils.DbUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
@CrossOrigin
public class CompanyController {
@GetMapping("/api/loadCompanyList")
public Result<?> getCompanyList(){
try {
String orgId = UserContext.getOrgId();
String sql = "select b_id,b_name from b_user where b_canuse = '1' ";
List<Map<String, Object>> maps = DbUtils.queryForList(orgId, sql);
for (Map<String, Object> map : maps) {
String bId = map.get("b_id").toString();
map.put("_online",UserChannelManager.isOnline(bId));
}
return Result.ok("成功",maps);
} catch (Exception e) {
return Result.fail("公司列表查询异常:" + e.getMessage());
}
}
}
@@ -0,0 +1,72 @@
package com.link.im.handler;
import com.link.api.util.UserContext;
import com.link.im.manager.UserChannelManager;
import com.link.im.manager.WriteManager;
import com.link.im.model.ImRequest;
import com.link.im.model.ImResponse;
import com.link.im.utils.CommonUtils;
import com.link.im.utils.DbUtils;
import io.netty.channel.ChannelHandlerContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@Component
public class ImMessageProcessor {
public void process(ChannelHandlerContext ctx, ImRequest request) {
String type = request.getType();
if (type == null) {
WriteManager.writeToChannel(ctx.channel(), "消息类型不能为空");
return;
}
switch (type) {
case "ping":
handlePing(ctx);
break;
case "login":
handleLogin(ctx, request);
break;
default:
WriteManager.writeToChannel(ctx.channel(), "未知的消息类型: " + type);
break;
}
}
private void handlePing(ChannelHandlerContext ctx) {
WriteManager.writeToChannel(ctx.channel(), ImResponse.success("pong",null));
}
private void handleLogin(ChannelHandlerContext ctx,ImRequest request){
String fromUserid = request.getFrom();
UserChannelManager.addUser(fromUserid,ctx.channel());
String orgId = request.getOrgId();
System.out.println(orgId);
// 1.通知给好友
String sql1 = "select b_frienduser_Id from IM_Friends where b_user_id = '" + fromUserid +"'";
try {
List<Map<String, Object>> maps = DbUtils.queryForList(orgId, sql1);
for (Map<String, Object> map : maps) {
String bFrienduserId = map.get("b_frienduser_Id").toString();
if (CommonUtils.isNotEmpty(bFrienduserId)) {
boolean friendOnline = UserChannelManager.isOnline(bFrienduserId);
if(friendOnline){
}
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
// 2.通知给群组
// 3.通知给全部(测试用,先留,后面会删)
}
}
@@ -5,6 +5,8 @@ import com.link.im.manager.GroupManager;
import com.link.im.manager.UserChannelManager;
import com.link.im.manager.WriteManager;
import com.link.im.model.ImMessage;
import com.link.im.model.ImRequest;
import com.link.im.model.ImResponse;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
@@ -17,6 +19,7 @@ import org.slf4j.LoggerFactory;
public class ImWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static final Logger logger = LoggerFactory.getLogger(ImWebSocketHandler.class);
private static final ObjectMapper MAPPER = new ObjectMapper();
private final ImMessageProcessor imMessageProcessor = new ImMessageProcessor();
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
@@ -35,14 +38,15 @@ public class ImWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocke
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
String text = msg.text();
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
try {
ImMessage imMessage = MAPPER.readValue(text, ImMessage.class);
System.out.println(imMessage);
System.out.println(msg.text());
ImRequest request = MAPPER.readValue(msg.text(), ImRequest.class);
imMessageProcessor.process(ctx,request);
} catch (Exception e) {
WriteManager.writeToChannel(ctx.channel(),"JSON格式错误");
logger.error("channelRead0数据处理失败", e);
WriteManager.writeToChannel(ctx.channel(),ImResponse.error("error",e.toString()));
}
}
@@ -1,8 +1,6 @@
package com.link.im.manager;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,20 +12,45 @@ public class UserChannelManager {
private static final ConcurrentHashMap<String, Channel> userChannelMap = new ConcurrentHashMap<>();
/**
* 添加用户与Channel绑定
* 添加用户与Channel绑定,如果已有绑定,先移除旧的
*/
public static void addUser(String userId, Channel channel) {
if (userId != null && channel != null) {
userChannelMap.put(userId, channel);
if (userId == null || channel == null) return;
// 如果已有旧的 channel,先移除
Channel oldChannel = userChannelMap.put(userId, channel);
if (oldChannel != null && oldChannel != channel) {
try {
if (oldChannel.isActive()) {
oldChannel.close();
}
logger.info("用户 {} 已有旧 channel,被替换: oldChannelId={}, newChannelId={}",
userId, oldChannel.id().asShortText(), channel.id().asShortText());
} catch (Exception e) {
logger.error("关闭旧 channel 异常: userId={}", userId, e);
}
}
logger.info("用户上线: userId={}, channelId={}", userId, channel.id().asShortText());
}
/**
* 移除用户绑定
*/
public static void removeUserById(String userId) {
if (userId != null) {
userChannelMap.remove(userId);
if (userId == null) return;
Channel removed = userChannelMap.remove(userId);
if (removed != null) {
try {
if (removed.isActive()) {
removed.close();
}
} catch (Exception e) {
logger.error("关闭 channel 异常: userId={}", userId, e);
}
logger.info("用户下线: userId={}, channelId={}", userId, removed.id().asShortText());
}
}
@@ -60,5 +83,4 @@ public class UserChannelManager {
Channel ch = userChannelMap.get(userId);
return ch != null && ch.isActive();
}
}
@@ -24,6 +24,18 @@ public class ImMessage {
return type;
}
@Override
public String toString() {
return "ImMessage{" +
"type='" + type + '\'' +
", msg='" + msg + '\'' +
", from='" + from + '\'' +
", to='" + to + '\'' +
", content='" + content + '\'' +
", timestamp=" + timestamp +
'}';
}
public void setType(String type) {
this.type = type;
}
@@ -0,0 +1,82 @@
package com.link.im.model;
public class ImRequest {
private String type;
private String from;
private String to;
private String content;
private String orgId;
private long timestamp;
// 无参构造
public ImRequest() {}
// 全参构造
public ImRequest(String type, String from, String to, String content, long timestamp,String orgId) {
this.type = type;
this.from = from;
this.to = to;
this.content = content;
this.timestamp = timestamp;
this.orgId = orgId;
}
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
@Override
public String toString() {
return "ImRequest{" +
"type='" + type + '\'' +
", from='" + from + '\'' +
", to='" + to + '\'' +
", content='" + content + '\'' +
", timestamp=" + timestamp +
'}';
}
}
@@ -0,0 +1,89 @@
package com.link.im.model;
public class ImResponse {
private String type;
private int code;
private String message;
private long timestamp;
private Object data;
// 无参构造
public ImResponse() {}
// 全参构造
public ImResponse(String type, int code, String message, long timestamp, Object data) {
this.type = type;
this.code = code;
this.message = message;
this.timestamp = timestamp;
this.data = data;
}
public static ImResponse success(String type, Object data) {
return new ImResponse(type, 200, "success", System.currentTimeMillis(), data);
}
public static ImResponse success(String type, String message, Object data) {
return new ImResponse(type, 200, message, System.currentTimeMillis(), data);
}
public static ImResponse error(String type, String message) {
return new ImResponse(type, 500, message, System.currentTimeMillis(), null);
}
public static ImResponse error(String type, int code, String message) {
return new ImResponse(type, code, message, System.currentTimeMillis(), null);
}
// Getter & Setter
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
@Override
public String toString() {
return "ImResponse{" +
"type='" + type + '\'' +
", code=" + code +
", message='" + message + '\'' +
", timestamp=" + timestamp +
", data=" + data +
'}';
}
}
@@ -0,0 +1,21 @@
package com.link.im.utils;
public class CommonUtils {
/**
* 判断字符串是否为空(null 或 "")
* @param str 待判断的字符串
* @return true 如果字符串为 null 或 空串
*/
public static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
/**
* 判断字符串是否非空(不是 null 且不为空串)
* @param str 待判断的字符串
* @return true 如果字符串非空
*/
public static boolean isNotEmpty(String str) {
return !isEmpty(str);
}
}
@@ -0,0 +1,41 @@
package com.link.im.utils;
import com.link.api.util.DruidDataSourceManager;
import java.sql.*;
import java.util.*;
public class DbUtils {
/**
* 根据 SQL 查询数据
*
* @param orgCode 数据源组织编码
* @param sql 查询 SQL
* @return List<Map<String,Object>>,每一行作为 Map
*/
public static List<Map<String, Object>> queryForList(String orgCode, String sql) throws SQLException {
List<Map<String, Object>> resultList = new ArrayList<>();
try (Connection conn = DruidDataSourceManager.getConnection(orgCode);
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery()) {
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> rowMap = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnLabel(i);
Object value = rs.getObject(i);
rowMap.put(columnName, value);
}
resultList.add(rowMap);
}
}
return resultList;
}
}
@@ -1,4 +1,4 @@
url=jdbc:sqlserver://127.0.0.1:1433;databaseName=G3HY2025
url=jdbc:sqlserver://192.168.1.189:1433;databaseName=G3-Link;encrypt=false
username=sa
password=g3soft
driver=com.microsoft.sqlserver.jdbc.SQLServerDriver