Commit 22172dc3 by hewei

Merge branch '1.3' into 'master'

1.3

See merge request !1
parents 2a2c9c5a e299ec07
...@@ -20,31 +20,27 @@ import io.geekidea.springbootplus.framework.util.PrintApplicationInfo; ...@@ -20,31 +20,27 @@ import io.geekidea.springbootplus.framework.util.PrintApplicationInfo;
import org.mybatis.spring.annotation.MapperScan; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
/** /**
* spring-boot-plus 项目启动入口 * 项目启动入口
*
* @author geekidea
* @since 2018-11-08
*/ */
@EnableAsync @EnableAsync
@EnableScheduling @EnableScheduling
@EnableTransactionManagement @EnableTransactionManagement
@EnableConfigurationProperties @EnableConfigurationProperties
@ServletComponentScan @ServletComponentScan
@ConfigurationPropertiesScan("com.wecloud.im.config") @EnableCaching
@MapperScan({"io.geekidea.springbootplus.**.mapper", "com.wecloud.**.mapper"}) @MapperScan({"io.geekidea.springbootplus.**.mapper", "com.wecloud.**.mapper"})
@SpringBootApplication(scanBasePackages = {"io.geekidea.springbootplus", "com.wecloud", "com.wecloud.im", "com.wecloud.im.config"}) @SpringBootApplication(scanBasePackages = {"io.geekidea.springbootplus", "com.wecloud"})
public class SpringBootPlusApplication { public class SpringBootPlusApplication {
public static void main(String[] args) { public static void main(String[] args) {
// 启动spring-boot-plus // 启动spring-boot-plus
ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args); ConfigurableApplicationContext context = SpringApplication.run(SpringBootPlusApplication.class, args);
...@@ -54,4 +50,5 @@ public class SpringBootPlusApplication { ...@@ -54,4 +50,5 @@ public class SpringBootPlusApplication {
PrintApplicationInfo.printTip(context); PrintApplicationInfo.printTip(context);
} }
} }
///*
// * Copyright 2019-2029 geekidea(https://github.com/geekidea)
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package io.geekidea.springbootplus.config;
//
//import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
//import com.alibaba.cloud.nacos.NacosServiceManager;
//import com.alibaba.cloud.nacos.discovery.NacosWatch;
//import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
//import com.wecloud.im.register.GetIpUtils;
//import org.springframework.beans.factory.ObjectProvider;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
//import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
//
//import javax.annotation.Resource;
//import java.text.SimpleDateFormat;
//import java.util.Date;
//import java.util.HashMap;
//import java.util.Map;
//
//
//@Configuration
//@EnableDiscoveryClient
//public class NacosConfig {
// @Value("${netty.port}")
// private String nettyPort;
// @Resource
// private GetIpUtils getIpUtils;
//
// @Bean
// @ConditionalOnMissingBean
// public NacosDiscoveryProperties nacosProperties() {
// return new NacosDiscoveryProperties();
// }
//
// @Bean
// @ConditionalOnMissingBean
// @ConditionalOnProperty(value = {"spring.cloud.nacos.discovery.watch.enabled"}, matchIfMissing = true)
// public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties, ObjectProvider<ThreadPoolTaskScheduler> taskScheduler) {
// Map<String, String> metadataMap = nacosDiscoveryProperties.getMetadata();
// if (metadataMap == null) {
// metadataMap = new HashMap<>();
// }
// String key = "ip.netty.public";
// metadataMap.put("startup.time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// String value = getIpUtils.getPublicIp() + ":" + nettyPort;
// metadataMap.put(key, value);
// // 设置心跳的周期,单位为秒,这里将心跳间隔设置为3秒:
// metadataMap.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL, "3000");
// // 设置心跳超时时间,单位为秒,这里将心跳超时时间设为6秒,
// // 即服务端6秒收不到客户端心跳,会将该客户端注册的实例设为不健康:
// metadataMap.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT, "6000");
// // 设置实例删除的超时时间,单位为秒,这里将实例删除超时时间设为9秒,
// // 即服务端9秒收不到客户端心跳,会将该客户端注册的实例删除:
// metadataMap.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT, "9000");
//
// nacosDiscoveryProperties.setMetadata(metadataMap);
// return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties, taskScheduler);
// }
//
//
//}
\ No newline at end of file
...@@ -207,7 +207,7 @@ public class ShiroConfig { ...@@ -207,7 +207,7 @@ public class ShiroConfig {
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 获取排除的路径 // 获取排除的路径
List<String[]> anonList = shiroProperties.getAnon(); List<String[]> anonList = shiroProperties.getAnon();
log.debug("anonList:{}", JSON.toJSONString(anonList)); log.info("anonList:{}", JSON.toJSONString(anonList));
if (CollectionUtils.isNotEmpty(anonList)) { if (CollectionUtils.isNotEmpty(anonList)) {
anonList.forEach(anonArray -> { anonList.forEach(anonArray -> {
if (ArrayUtils.isNotEmpty(anonArray)) { if (ArrayUtils.isNotEmpty(anonArray)) {
...@@ -222,7 +222,7 @@ public class ShiroConfig { ...@@ -222,7 +222,7 @@ public class ShiroConfig {
String definitions = shiroProperties.getFilterChainDefinitions(); String definitions = shiroProperties.getFilterChainDefinitions();
if (StringUtils.isNotBlank(definitions)) { if (StringUtils.isNotBlank(definitions)) {
Map<String, String> section = IniUtil.parseIni(definitions); Map<String, String> section = IniUtil.parseIni(definitions);
log.debug("definitions:{}", JSON.toJSONString(section)); log.info("definitions:{}", JSON.toJSONString(section));
for (Map.Entry<String, String> entry : section.entrySet()) { for (Map.Entry<String, String> entry : section.entrySet()) {
filterChainDefinitionMap.put(entry.getKey(), entry.getValue()); filterChainDefinitionMap.put(entry.getKey(), entry.getValue());
} }
...@@ -230,7 +230,7 @@ public class ShiroConfig { ...@@ -230,7 +230,7 @@ public class ShiroConfig {
// 获取自定义权限路径配置集合 // 获取自定义权限路径配置集合
List<ShiroPermissionProperties> permissionConfigs = shiroProperties.getPermission(); List<ShiroPermissionProperties> permissionConfigs = shiroProperties.getPermission();
log.debug("permissionConfigs:{}", JSON.toJSONString(permissionConfigs)); log.info("permissionConfigs:{}", JSON.toJSONString(permissionConfigs));
if (CollectionUtils.isNotEmpty(permissionConfigs)) { if (CollectionUtils.isNotEmpty(permissionConfigs)) {
for (ShiroPermissionProperties permissionConfig : permissionConfigs) { for (ShiroPermissionProperties permissionConfig : permissionConfigs) {
String url = permissionConfig.getUrl(); String url = permissionConfig.getUrl();
...@@ -261,7 +261,7 @@ public class ShiroConfig { ...@@ -261,7 +261,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/**", ANON); filterChainDefinitionMap.put("/**", ANON);
} }
log.debug("filterChainMap:{}", JSON.toJSONString(filterChainDefinitionMap)); log.info("filterChainMap:{}", JSON.toJSONString(filterChainDefinitionMap));
// 添加默认的filter // 添加默认的filter
Map<String, String> newFilterChainDefinitionMap = addDefaultFilterDefinition(filterChainDefinitionMap); Map<String, String> newFilterChainDefinitionMap = addDefaultFilterDefinition(filterChainDefinitionMap);
......
...@@ -46,7 +46,7 @@ public class SpringBootPlusCorsConfig { ...@@ -46,7 +46,7 @@ public class SpringBootPlusCorsConfig {
*/ */
@Bean @Bean
public FilterRegistrationBean corsFilter(SpringBootPlusCorsProperties corsProperties) { public FilterRegistrationBean corsFilter(SpringBootPlusCorsProperties corsProperties) {
log.debug("corsProperties:{}", corsProperties); log.info("corsProperties:{}", corsProperties);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration(); CorsConfiguration corsConfiguration = new CorsConfiguration();
// 跨域配置 // 跨域配置
......
...@@ -147,7 +147,7 @@ public class SpringBootPlusWebMvcConfig implements WebMvcConfigurer { ...@@ -147,7 +147,7 @@ public class SpringBootPlusWebMvcConfig implements WebMvcConfigurer {
filterConfig = springBootPlusProperties.getFilter(); filterConfig = springBootPlusProperties.getFilter();
interceptorConfig = springBootPlusProperties.getInterceptor(); interceptorConfig = springBootPlusProperties.getInterceptor();
// 打印SpringBootPlusProperties配置信息 // 打印SpringBootPlusProperties配置信息
log.debug("SpringBootPlusProperties:{}", JSON.toJSONString(springBootPlusProperties)); log.info("SpringBootPlusProperties:{}", JSON.toJSONString(springBootPlusProperties));
} }
@Override @Override
......
...@@ -244,7 +244,7 @@ public class Swagger2Config { ...@@ -244,7 +244,7 @@ public class Swagger2Config {
* @return * @return
*/ */
public String[] getBasePackages() { public String[] getBasePackages() {
log.debug("swaggerProperties = " + swaggerProperties); log.info("swaggerProperties = " + swaggerProperties);
String basePackage = swaggerProperties.getBasePackage(); String basePackage = swaggerProperties.getBasePackage();
if (StringUtils.isBlank(basePackage)) { if (StringUtils.isBlank(basePackage)) {
throw new SpringBootPlusConfigException("Swagger basePackage不能为空"); throw new SpringBootPlusConfigException("Swagger basePackage不能为空");
......
...@@ -27,7 +27,9 @@ public class FirebaseTest { ...@@ -27,7 +27,9 @@ public class FirebaseTest {
System.setProperty("socksProxyPort", "7891"); System.setProperty("socksProxyPort", "7891");
// String to = "ck_oO93kR42WlkmzBVjzcA:APA91bGTcXlFq9_AOvGOJSIB4Z38EOqhP3_6HQ18_XIn3othxSWTeRr_IaQn-75AB9FvD5CiTig03Y56VtZDEEihismai0OOMPyxB7R4ajaFrQszEQRbCBw3iUgaAyjK7e1RFeq22tRC"; // String to = "ck_oO93kR42WlkmzBVjzcA:APA91bGTcXlFq9_AOvGOJSIB4Z38EOqhP3_6HQ18_XIn3othxSWTeRr_IaQn-75AB9FvD5CiTig03Y56VtZDEEihismai0OOMPyxB7R4ajaFrQszEQRbCBw3iUgaAyjK7e1RFeq22tRC";
String to = "eLOQs869208Wq5_tQINUgl:APA91bEsiSt8_RBJYQ2bLDHJF4nuE6XS6bP-kdEAt463SpW2i0Q5wUcmma3ylszr698MUIkjkwV507EV7ao347pl0XwHTDgDM1kIL4WYfX28OznML2lefnYS7oMmlt5_uqvwDO1GWone"; // String to = "eLOQs869208Wq5_tQINUgl:APA91bEsiSt8_RBJYQ2bLDHJF4nuE6XS6bP-kdEAt463SpW2i0Q5wUcmma3ylszr698MUIkjkwV507EV7ao347pl0XwHTDgDM1kIL4WYfX28OznML2lefnYS7oMmlt5_uqvwDO1GWone";
String to = "cu7jc8tgd0Irh7VoMXGNz4:APA91bFnOP39EKSXUaTDqERlqyfLIovLPrGXA_U1pKLs5mJRPfbLPl6BvSlLUwsBAtprE0NoEeIiRwkTwN4RskUgh39IKSqcSJ14yXtEDIGMs8HqzaF4HrQqJ_zFFUX6S0r6WenUru_8";
String key = "AAAA7PNYwIg:APA91bG2PZlTpC9sxqeIxtKDJJGzGZlh1ca13_bR4c5qkv9pEvRxcDfgO8VQqV2g-7cCTZz3oDtpWAgcQ5TyMKGdlD7Zp3bEmFkpNYDJAIcshSbyW-BtjCbknT2R5px5THmEJrlTJuDi"; String key = "AAAA7PNYwIg:APA91bG2PZlTpC9sxqeIxtKDJJGzGZlh1ca13_bR4c5qkv9pEvRxcDfgO8VQqV2g-7cCTZz3oDtpWAgcQ5TyMKGdlD7Zp3bEmFkpNYDJAIcshSbyW-BtjCbknT2R5px5THmEJrlTJuDi";
String jsonStr = null; String jsonStr = null;
...@@ -60,7 +62,7 @@ public class FirebaseTest { ...@@ -60,7 +62,7 @@ public class FirebaseTest {
BufferedReader reader = new BufferedReader(in); BufferedReader reader = new BufferedReader(in);
String line = reader.readLine(); String line = reader.readLine();
log.debug(line); log.info(line);
wr.close(); wr.close();
reader.close(); reader.close();
......
///*
// * Copyright 2019-2029 geekidea(https://github.com/geekidea)
// *
// * Licensed under the Apache License, Version 2.0 (the "License");
// * you may not use this file except in compliance with the License.
// * You may obtain a copy of the License at
// *
// * http://www.apache.org/licenses/LICENSE-2.0
// *
// * Unless required by applicable law or agreed to in writing, software
// * distributed under the License is distributed on an "AS IS" BASIS,
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// * See the License for the specific language governing permissions and
// * limitations under the License.
// */
//
//package io.geekidea.springbootplus.test;
//
//import com.alibaba.nacos.api.exception.NacosException;
//import com.alibaba.nacos.api.naming.NamingFactory;
//import com.alibaba.nacos.api.naming.NamingService;
//import com.alibaba.nacos.api.naming.pojo.Instance;
//import com.wecloud.im.register.GetIpUtils;
//import io.geekidea.springbootplus.SpringBootPlusApplication;
//import org.junit.Test;
//import org.junit.runner.RunWith;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.boot.test.context.SpringBootTest;
//import org.springframework.test.context.junit4.SpringRunner;
//
//import java.util.Map;
//
///**
// * get ip
// **/
//@RunWith(SpringRunner.class)
//@SpringBootTest(classes = SpringBootPlusApplication.class)
//public class GetIpTest {
// @Autowired
// private GetIpUtils publicIpUtils;
//
// @Value("${spring.cloud.nacos.discovery.server-addr}")
// private String addr;
//
//
// @Test
// public void test() throws NacosException {
//
//// String s = publicIpUtils.getlanIp();
//// String publicIp = publicIpUtils.getPublicIp();
//// String s2 = publicIpUtils.getlanIp();
//// String publicIp2 = publicIpUtils.getPublicIp();
//
//// String serveAddr = System.getProperty("serveAddr");
// NamingService naming = NamingFactory.createNamingService(addr);
// Instance wecloudIm = naming.selectOneHealthyInstance("wecloud_im");
// Map<String, String> metadata = wecloudIm.getMetadata();
// String publicIp = metadata.get("ip.netty.public");
// System.out.println(wecloudIm);
//
//// naming.subscribe("ip.netty.public", event -> {
//// if (event instanceof NamingEvent) {
//// System.out.println(((NamingEvent) event).getServiceName());
//// System.out.println(((NamingEvent) event).getInstances());
//// }
//// });
//
//// while (true){
////
//// }
//
// }
//
//
//}
package io.geekidea.springbootplus.test;
import cn.hutool.core.codec.Base64;
import com.turo.pushy.apns.DeliveryPriority;
import com.turo.pushy.apns.PushType;
import com.wecloud.im.ws.sender.IosPush;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class IosApnsBase64Test {
public static void main(String[] args) throws IOException {
// apnsCertificatePath 证书
// * @param productFlag 环境
// * @param deviceToken 设备token
// * @param alertTitle 标题
// * @param alertBody 副标题
// * @param contentAvailable Boolean.FALSE
// * @param customProperty 自定义属性
// * @param badge 角标数量
// * @param priority DeliveryPriority.IMMEDIATE
// * @param pushType PushType.ALERT
// * @param topicBundleId undleId
// * @param sound rtc= "call.caf"; 否则为default
Map<String, Object> customProperty = new HashMap<String, Object>(10);
String apnsCertificatePath = "frogsell_push_dev.p12";
String deviceToken = "27c93ca84bbf17d9ff8eb05df0576ac49822db2ae1c02aa0afea83b5c3861276";
String alertTitle = "你好333";
String alertBody = "hi333";
int badge = 1;
String topicBundleId = "com.jdw.frogsell";
boolean contentAvailable = false;
InputStream certificate = IosPush.getApnsCertificate(apnsCertificatePath);
String encode = Base64.encode(certificate);
// 解码
byte[] decode = Base64.decode(encode);
InputStream inputStream2 = new ByteArrayInputStream(decode);
IosPush.push("123456", inputStream2, Boolean.FALSE, deviceToken, alertTitle, alertBody,
contentAvailable, customProperty, badge
, DeliveryPriority.IMMEDIATE, PushType.ALERT, topicBundleId,
"default");
}
// public static byte[] readInputStream(InputStream inputStream) throws IOException {
// byte[] buffer = new byte[1024];
// int len = 0;
// ByteArrayOutputStream bos = new ByteArrayOutputStream();
// while ((len = inputStream.read(buffer)) != -1) {
// bos.write(buffer, 0, len);
// }
// bos.close();
// return bos.toByteArray();
// }
// private static String inputToString(InputStream is) throws IOException {
// final int bufferSize = 1024;
// final char[] buffer = new char[bufferSize];
// final StringBuilder out = new StringBuilder();
// Reader in = new InputStreamReader(is, StandardCharsets.UTF_8);
// for (; ; ) {
// int rsz = in.read(buffer, 0, buffer.length);
// if (rsz < 0)
// break;
// out.append(buffer, 0, rsz);
// }
// return out.toString();
// }
}
package io.geekidea.springbootplus.test;
import com.turo.pushy.apns.DeliveryPriority;
import com.turo.pushy.apns.PushType;
import com.wecloud.im.ws.sender.IosPush;
import java.util.HashMap;
import java.util.Map;
public class IosApnsPushTest {
public static void main(String[] args) {
// * @param apnsCertificatePath 证书
// * @param productFlag 环境,测试=Boolean.FALSE,正式=Boolean.TRUE
// * @param deviceToken 设备token
// * @param alertTitle 标题
// * @param alertBody 副标题
// * @param contentAvailable Boolean.FALSE
// * @param customProperty 自定义属性
// * @param badge 角标数量
// * @param priority DeliveryPriority.IMMEDIATE
// * @param pushType PushType.ALERT
// * @param topicBundleId undleId
// * @param sound rtc= "call.caf"; 否则为default
Map<String, Object> customProperty = new HashMap<String, Object>(10);
String apnsCertificatePath = "frogsell_push_dev.p12";
String deviceToken = "27c93ca84bbf17d9ff8eb05df0576ac49822db2ae1c02aa0afea83b5c3861276";
String alertTitle = "你好22";
String alertBody = "hi";
int badge = 1;
String topicBundleId = "com.jdw.frogsell";
boolean contentAvailable = false;
IosPush.push(apnsCertificatePath, Boolean.FALSE, deviceToken, alertTitle, alertBody,
contentAvailable, customProperty, badge
, DeliveryPriority.IMMEDIATE, PushType.ALERT, topicBundleId,
"default");
}
}
...@@ -50,9 +50,7 @@ public class LoginTest { ...@@ -50,9 +50,7 @@ public class LoginTest {
private String getToken(String timestemp, String clientId, String appKey, String sign) throws Exception { private String getToken(String timestemp, String clientId, String appKey, String sign) throws Exception {
// 根据appKey从数据库查询密钥 // 根据appKey从数据库查询密钥
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOneByAppKey(appKey);
new QueryWrapper<ImApplication>().lambda().eq(ImApplication::getAppKey, appKey)
);
// 生成以数据库为准的签名 // 生成以数据库为准的签名
String mySign = new MD5().digestHex(timestemp + clientId + imApplication.getAppKey() + imApplication.getAppSecret()); String mySign = new MD5().digestHex(timestemp + clientId + imApplication.getAppKey() + imApplication.getAppSecret());
...@@ -96,11 +94,13 @@ public class LoginTest { ...@@ -96,11 +94,13 @@ public class LoginTest {
@Test @Test
public void test() throws Exception { public void test() throws Exception {
// 时间戳 // 时间戳
String timestamp = "1626665156369"; String timestamp = "1629274899016";
String clientId = "aaaaa1"; String clientId = "aaaaa2";
String sign = "a404fe25d383eb154b3b527f7213b35a";
String appKey = "QNtP3EjtLw26ekt0"; String appKey = "QNtP3EjtLw26ekt0";
String sign = "a0b128928849c44bb0b7ae82944770b5";
String token = getToken(timestamp, clientId, appKey, sign); String token = getToken(timestamp, clientId, appKey, sign);
System.out.println("token:" + token); System.out.println("token:\n" + token);
} }
} }
package io.geekidea.springbootplus.test;
import cn.hutool.core.codec.Base64;
import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.service.ImIosApnsService;
import com.wecloud.im.ws.sender.IosPush;
import io.geekidea.springbootplus.framework.shiro.util.SnowflakeUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.InputStream;
/**
* 生成apns字符串 并存入数据库
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class SaveApnsTest {
@Autowired
private ImIosApnsService imIosApnsService;
@Test
public void test() throws Exception {
String apnsCertificatePath = "frogsell_push.p12";
String topicBundleId = "com.jdw.frogsell";
String pwd = "123456";
InputStream certificate = IosPush.getApnsCertificate(apnsCertificatePath);
String encode = Base64.encode(certificate);
ImIosApns imIosApns = new ImIosApns();
imIosApns.setId(SnowflakeUtil.getId());
imIosApns.setFkAppId(0L);
imIosApns.setApnsFileValue(encode);
imIosApns.setEnv(1);
imIosApns.setBundleId(topicBundleId);
imIosApns.setPwd(pwd);
imIosApnsService.save(imIosApns);
}
}
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
<artifactId>common</artifactId> <artifactId>common</artifactId>
<name>common</name> <name>common</name>
<description>api服务模块</description> <description>应用服务模块</description>
<dependencies> <dependencies>
<dependency> <dependency>
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
<artifactId>framework</artifactId> <artifactId>framework</artifactId>
</dependency> </dependency>
<!-- <dependency>-->
<!-- <groupId>com.alibaba.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>-->
<!-- <version>2.2.5.RELEASE</version>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.google.firebase</groupId> <groupId>com.google.firebase</groupId>
...@@ -69,18 +74,6 @@ ...@@ -69,18 +74,6 @@
<!-- netty--> <!-- netty-->
<!-- 公众号(包括订阅号和服务号):weixin-java-mp -->
<!-- <dependency>-->
<!-- <groupId>com.github.binarywang</groupId>-->
<!-- <artifactId>weixin-java-mp</artifactId>-->
<!-- <version>4.0.0</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>com.github.binarywang</groupId>-->
<!-- <artifactId>weixin-java-pay</artifactId>-->
<!-- <version>4.0.0</version>-->
<!-- </dependency>-->
<!-- fastbootWeixin的核心依赖 --> <!-- fastbootWeixin的核心依赖 -->
...@@ -122,6 +115,14 @@ ...@@ -122,6 +115,14 @@
<!-- 友盟 end --> <!-- 友盟 end -->
<!-- https://mvnrepository.com/artifact/com.turo/pushy -->
<!-- apns推送-->
<dependency>
<groupId>com.turo</groupId>
<artifactId>pushy</artifactId>
<version>0.13.10</version>
</dependency>
<!-- wecloud短信 start--> <!-- wecloud短信 start-->
<dependency> <dependency>
...@@ -138,5 +139,34 @@ ...@@ -138,5 +139,34 @@
<!-- wecloud短信 end--> <!-- wecloud短信 end-->
</dependencies> </dependencies>
<!-- <build>-->
<!-- <resources>-->
<!-- <resource>-->
<!-- <directory>src/main/resources</directory>-->
<!-- <includes>-->
<!-- <include>**/*.p12</include>-->
<!-- </includes>-->
<!-- <filtering>false</filtering>-->
<!-- </resource>-->
<!-- </resources>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-resources-plugin</artifactId>-->
<!-- <configuration>-->
<!-- <encoding>UTF-8</encoding>-->
<!-- &lt;!&ndash; 过滤后缀为pem、pfx的证书文件 &ndash;&gt;-->
<!-- &lt;!&ndash; 打包编译是过滤掉这些证书文件,不再自动篡改&ndash;&gt;-->
<!-- <nonFilteredFileExtensions>-->
<!-- <nonFilteredFileExtension>p12</nonFilteredFileExtension>-->
<!-- <nonFilteredFileExtension>pem</nonFilteredFileExtension>-->
<!-- <nonFilteredFileExtension>pfx</nonFilteredFileExtension>-->
<!-- </nonFilteredFileExtensions>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- </build>-->
</project> </project>
\ No newline at end of file
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
// @OperationLog(name = "helloWorld") // @OperationLog(name = "helloWorld")
// @ApiOperation(value = "helloWorld", response = String.class) // @ApiOperation(value = "helloWorld", response = String.class)
// public ApiResult<String> helloWorld() throws IOException { // public ApiResult<String> helloWorld() throws IOException {
// log.debug("Hello World...app"); // log.info("Hello World...app");
// return ApiResult.ok("Hello World app"); // return ApiResult.ok("Hello World app");
// } // }
// //
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
// @OperationLog(name = "needRole") // @OperationLog(name = "needRole")
// @ApiOperation(value = "needRole", response = String.class) // @ApiOperation(value = "needRole", response = String.class)
// public ApiResult<String> needRole() throws IOException { // public ApiResult<String> needRole() throws IOException {
// log.debug("Hello World...app"); // log.info("Hello World...app");
// return ApiResult.ok("Hello World app"); // return ApiResult.ok("Hello World app");
// } // }
// //
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
// @ApiOperation(value = "needRoleAdmin", response = String.class) // @ApiOperation(value = "needRoleAdmin", response = String.class)
// @RequiresRoles("app:admin") // @RequiresRoles("app:admin")
// public ApiResult<String> needRoleAdmin() throws IOException { // public ApiResult<String> needRoleAdmin() throws IOException {
// log.debug("Hello World...app"); // log.info("Hello World...app");
// return ApiResult.ok("Hello World needRoleAdmin"); // return ApiResult.ok("Hello World needRoleAdmin");
// } // }
// //
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
// @ApiOperation(value = "needRoleAll", response = String.class) // @ApiOperation(value = "needRoleAll", response = String.class)
// @RequiresRoles("app:all") // @RequiresRoles("app:all")
// public ApiResult<String> needRoleAll() throws IOException { // public ApiResult<String> needRoleAll() throws IOException {
// log.debug("Hello World...app"); // log.info("Hello World...app");
// return ApiResult.ok("Hello World needRoleAll"); // return ApiResult.ok("Hello World needRoleAll");
// } // }
// //
......
package com.wecloud.im.controller; //package com.wecloud.im.controller;
//
import com.wecloud.im.entity.ImApplication; //import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.param.ImApplicationPageParam; //import com.wecloud.im.param.ImApplicationPageParam;
import com.wecloud.im.param.ImApplicationQueryVo; //import com.wecloud.im.param.ImApplicationQueryVo;
import com.wecloud.im.param.add.ImApplicationAdd; //import com.wecloud.im.param.add.ImApplicationAdd;
import com.wecloud.im.service.ImApplicationService; //import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.ws.utils.RSAGenerator; //import com.wecloud.im.ws.utils.RSAGenerator;
import io.geekidea.springbootplus.framework.common.api.ApiResult; //import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController; //import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.core.pagination.Paging; //import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.core.validator.groups.Add; //import io.geekidea.springbootplus.framework.core.validator.groups.Add;
import io.geekidea.springbootplus.framework.core.validator.groups.Update; //import io.geekidea.springbootplus.framework.core.validator.groups.Update;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog; //import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType; //import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
import io.swagger.annotations.Api; //import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; //import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; //import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; //import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; //import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated; //import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; //import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; //import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; //import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; //import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; //import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; //import org.springframework.web.bind.annotation.RestController;
//
/** ///**
* 第三方应用表 控制器 // * 第三方应用表 控制器
* // *
* @author wei // * @author wei
* @since 2021-04-27 // * @since 2021-04-27
*/ // */
@Slf4j //@Slf4j
@RestController //@RestController
@RequestMapping("/imApplication") //@RequestMapping("/imApplication")
@Api(value = "第三方应用表API", tags = {"第三方应用表"}) //@Api(value = "第三方应用表API", tags = {"第三方应用表"})
public class ImApplicationController extends BaseController { //public class ImApplicationController extends BaseController {
//
public static final String ADMIN_PWD = "si0132g9ad4gd6xv8x888wd6g86aga731h6pzc1pzc68b7eln96s2360j0sjkh028sj131h0gjb"; // public static final String ADMIN_PWD = "si0132g9ad4gd6xv8x888wd6g86aga731h6pzc1pzc68b7eln96s2360j0sjkh028sj131h0gjb";
//
@Autowired // @Autowired
private ImApplicationService imApplicationService; // private ImApplicationService imApplicationService;
//
/** // /**
* 添加第三方应用表 // * 添加第三方应用表
*/ // */
@PostMapping("/add") // @PostMapping("/add")
@OperationLog(name = "添加第三方应用表", type = OperationLogType.ADD) // @OperationLog(name = "添加第三方应用表", type = OperationLogType.ADD)
@ApiOperation(value = "添加第三方应用表") // @ApiOperation(value = "添加第三方应用表")
public ApiResult<Boolean> addImApplication(@Validated(Add.class) @RequestBody ImApplicationAdd imApplicationAdd) throws Exception { // public ApiResult<Boolean> addImApplication(@Validated(Add.class) @RequestBody ImApplicationAdd imApplicationAdd) throws Exception {
//
if (!imApplicationAdd.getAdminPwd().equals(ADMIN_PWD)) { // if (!imApplicationAdd.getAdminPwd().equals(ADMIN_PWD)) {
return ApiResult.fail(); // return ApiResult.fail();
} // }
//
ImApplication imApplication = new ImApplication(); // ImApplication imApplication = new ImApplication();
BeanUtils.copyProperties(imApplicationAdd, imApplication); // BeanUtils.copyProperties(imApplicationAdd, imApplication);
//
// 生成AppKey // // 生成AppKey
String appKey = RSAGenerator.getAppKey(); //定义变量接收 // String appKey = RSAGenerator.getAppKey(); //定义变量接收
// 生成appSecret // // 生成appSecret
String appSecret = RSAGenerator.getAppSecret(appKey); // String appSecret = RSAGenerator.getAppSecret(appKey);
//
imApplication.setAppKey(appKey); // imApplication.setAppKey(appKey);
imApplication.setAppSecret(appSecret); // imApplication.setAppSecret(appSecret);
//
boolean flag = imApplicationService.saveImApplication(imApplication); // boolean flag = imApplicationService.saveImApplication(imApplication);
return ApiResult.result(flag); // return ApiResult.result(flag);
} // }
//
/** // /**
* 修改第三方应用表 // * 修改第三方应用表
*/ // */
@PostMapping("/update") // @PostMapping("/update")
@OperationLog(name = "修改第三方应用表", type = OperationLogType.UPDATE) // @OperationLog(name = "修改第三方应用表", type = OperationLogType.UPDATE)
@ApiOperation(value = "修改第三方应用表") // @ApiOperation(value = "修改第三方应用表")
public ApiResult<Boolean> updateImApplication(@Validated(Update.class) @RequestBody ImApplicationAdd imApplicationAdd) throws Exception { // public ApiResult<Boolean> updateImApplication(@Validated(Update.class) @RequestBody ImApplicationAdd imApplicationAdd) throws Exception {
//
if (!imApplicationAdd.getAdminPwd().equals(ADMIN_PWD)) { // if (!imApplicationAdd.getAdminPwd().equals(ADMIN_PWD)) {
return ApiResult.fail(); // return ApiResult.fail();
} // }
//
ImApplication imApplication = new ImApplication(); // ImApplication imApplication = new ImApplication();
boolean flag = imApplicationService.updateImApplication(imApplication); // boolean flag = imApplicationService.updateImApplication(imApplication);
return ApiResult.result(flag); // return ApiResult.result(flag);
} // }
//
/** // /**
* 删除第三方应用表 // * 删除第三方应用表
*/ // */
@PostMapping("/delete") // @PostMapping("/delete")
@OperationLog(name = "删除第三方应用表", type = OperationLogType.DELETE) // @OperationLog(name = "删除第三方应用表", type = OperationLogType.DELETE)
@ApiOperation(value = "删除第三方应用表") // @ApiOperation(value = "删除第三方应用表")
public ApiResult<Boolean> deleteImApplication(@RequestParam("id") Long id, @RequestParam("pwd") String pwd) throws Exception { // public ApiResult<Boolean> deleteImApplication(@RequestParam("id") Long id, @RequestParam("pwd") String pwd) throws Exception {
//
if (!pwd.equals(ADMIN_PWD)) { // if (!pwd.equals(ADMIN_PWD)) {
return ApiResult.fail(); // return ApiResult.fail();
} // }
boolean flag = imApplicationService.deleteImApplication(id); // boolean flag = imApplicationService.deleteImApplication(id);
return ApiResult.result(flag); // return ApiResult.result(flag);
} // }
//
/** // /**
* 获取第三方应用表详情 // * 获取第三方应用表详情
*/ // */
@GetMapping("/info/") // @GetMapping("/info/")
@OperationLog(name = "第三方应用表详情", type = OperationLogType.INFO) // @OperationLog(name = "第三方应用表详情", type = OperationLogType.INFO)
@ApiOperation(value = "第三方应用表详情") // @ApiOperation(value = "第三方应用表详情")
public ApiResult<ImApplicationQueryVo> getImApplication(@RequestParam("id") Long id, @RequestParam("pwd") String pwd) throws Exception { // public ApiResult<ImApplicationQueryVo> getImApplication(@RequestParam("id") Long id, @RequestParam("pwd") String pwd) throws Exception {
//
if (!pwd.equals(ADMIN_PWD)) { // if (!pwd.equals(ADMIN_PWD)) {
return null; // return null;
} // }
//
ImApplicationQueryVo imApplicationQueryVo = imApplicationService.getImApplicationById(id); // ImApplicationQueryVo imApplicationQueryVo = imApplicationService.getImApplicationById(id);
return ApiResult.ok(imApplicationQueryVo); // return ApiResult.ok(imApplicationQueryVo);
} // }
//
/** // /**
* 第三方应用表分页列表 // * 第三方应用表分页列表
*/ // */
@PostMapping("/getPageList") // @PostMapping("/getPageList")
@OperationLog(name = "第三方应用表分页列表", type = OperationLogType.PAGE) // @OperationLog(name = "第三方应用表分页列表", type = OperationLogType.PAGE)
@ApiOperation(value = "第三方应用表分页列表") // @ApiOperation(value = "第三方应用表分页列表")
public ApiResult<Paging<ImApplicationQueryVo>> getImApplicationPageList(@Validated @RequestBody ImApplicationPageParam imApplicationPageParam) throws Exception { // public ApiResult<Paging<ImApplicationQueryVo>> getImApplicationPageList(@Validated @RequestBody ImApplicationPageParam imApplicationPageParam) throws Exception {
//
if (!imApplicationPageParam.getPwd().equals(ADMIN_PWD)) { // if (!imApplicationPageParam.getPwd().equals(ADMIN_PWD)) {
return null; // return null;
} // }
Paging<ImApplicationQueryVo> paging = imApplicationService.getImApplicationPageList(imApplicationPageParam); // Paging<ImApplicationQueryVo> paging = imApplicationService.getImApplicationPageList(imApplicationPageParam);
return ApiResult.ok(paging); // return ApiResult.ok(paging);
} // }
//
} //}
//
package com.wecloud.im.controller; package com.wecloud.im.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.param.GetOnlineStatusParam;
import com.wecloud.im.param.add.ImClientDeviceInfoAdd; import com.wecloud.im.param.add.ImClientDeviceInfoAdd;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService; import com.wecloud.im.service.ImClientService;
...@@ -10,8 +10,6 @@ import com.wecloud.im.ws.service.MangerChannelService; ...@@ -10,8 +10,6 @@ import com.wecloud.im.ws.service.MangerChannelService;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.controller.BaseController; import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.core.validator.groups.Add; import io.geekidea.springbootplus.framework.core.validator.groups.Add;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken; import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
...@@ -24,6 +22,9 @@ import org.springframework.web.bind.annotation.RequestBody; ...@@ -24,6 +22,9 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
/** /**
* 终端表 控制器 * 终端表 控制器
* *
...@@ -49,38 +50,57 @@ public class ImClientController extends BaseController { ...@@ -49,38 +50,57 @@ public class ImClientController extends BaseController {
* 添加或修改推送设备信息 * 添加或修改推送设备信息
*/ */
@PostMapping("/addDeviceInfo") @PostMapping("/addDeviceInfo")
@OperationLog(name = "添加或修改推送设备信息", type = OperationLogType.ADD)
@ApiOperation(value = "添加或修改推送设备信息(每次请求都会覆盖之前的数据)") @ApiOperation(value = "添加或修改推送设备信息(每次请求都会覆盖之前的数据)")
public ApiResult<Boolean> addDeviceInfo(@Validated(Add.class) @RequestBody ImClientDeviceInfoAdd imClientDevice) throws Exception { public ApiResult<Boolean> addDeviceInfo(@Validated(Add.class) @RequestBody ImClientDeviceInfoAdd imClientDevice) throws Exception {
boolean flag = imClientService.addDeviceInfo(imClientDevice); boolean flag = imClientService.updateDeviceInfo(imClientDevice);
return ApiResult.result(flag); return ApiResult.result(flag);
} }
/** /**
* 获取用户在线状态 * 获取用户在线状态(批量)
* *
* @return true:在线, false 不在线 * @return true:在线, false 不在线
*/ */
@PostMapping("/getOnlineStatus") @PostMapping("/onlineStatus")
@OperationLog(name = "获取用户在线状态", type = OperationLogType.ADD) @ApiOperation(value = "获取用户在线状态(批量)")
@ApiOperation(value = "获取用户在线状态") ApiResult<List<ImOnlineStatusVo>> getOnlineStatus(@RequestBody GetOnlineStatusParam getOnlineStatusParam) {
ApiResult<ImOnlineStatusVo> getOnlineStatus(String clientId) {
// shiro线程中获取当前token // shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken(); JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid // 根据appKey查询appid
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
new QueryWrapper<ImApplication>().lambda() ArrayList<ImOnlineStatusVo> imOnlineStatusVos = new ArrayList<ImOnlineStatusVo>();
.select(ImApplication::getId, ImApplication::getAppKey) for (String clientId : getOnlineStatusParam.getClientIds()) {
.eq(ImApplication::getAppKey, curentJwtToken.getAppKey())
);
boolean onlineStatus = mangerChannelService.getOnlineStatus(imApplication.getAppKey(), clientId); ImOnlineStatusVo imOnlineStatusVo = new ImOnlineStatusVo();
ImOnlineStatusVo imOnlineStatusVo = new ImOnlineStatusVo(); imOnlineStatusVo.setStatus(mangerChannelService.getOnlineStatus(imApplication.getAppKey(), clientId));
imOnlineStatusVo.setStatus(onlineStatus); imOnlineStatusVo.setClientId(clientId);
return ApiResult.ok(imOnlineStatusVo); imOnlineStatusVos.add(imOnlineStatusVo);
}
return ApiResult.ok(imOnlineStatusVos);
} }
//
// /**
// * 获取用户在线状态(批量)
// *
// * @return true:在线, false 不在线
// */
// @PostMapping("/getOnlineStatus")
// @OperationLog(name = "获取用户在线状态", type = OperationLogType.ADD)
// @ApiOperation(value = "获取用户在线状态")
// ApiResult<ImOnlineStatusVo> getOnlinesStatus(String clientId) {
// // shiro线程中获取当前token
// JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
//
// // 根据appKey查询appid
// ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
//
// boolean onlineStatus = mangerChannelService.getOnlineStatus(imApplication.getAppKey(), clientId);
// ImOnlineStatusVo imOnlineStatusVo = new ImOnlineStatusVo();
// imOnlineStatusVo.setStatus(onlineStatus);
// return ApiResult.ok(imOnlineStatusVo);
// }
// /** // /**
// * 添加终端表 // * 添加终端表
......
...@@ -39,8 +39,7 @@ public class ImConversationController extends BaseController { ...@@ -39,8 +39,7 @@ public class ImConversationController extends BaseController {
@PostMapping("/create") @PostMapping("/create")
@ApiOperation(value = "创建会话", notes = "后台可配置:两个客户端如果已经创建过会话,是否重复创建会话") @ApiOperation(value = "创建会话", notes = "后台可配置:两个客户端如果已经创建过会话,是否重复创建会话")
public ApiResult<ImConversationCreateVo> createImConversation(@RequestBody ImConversationCreate imConversationCreate) throws Exception { public ApiResult<ImConversationCreateVo> createImConversation(@RequestBody ImConversationCreate imConversationCreate) throws Exception {
ApiResult<ImConversationCreateVo> imConversation = imConversationService.createImConversation(imConversationCreate); return imConversationService.createImConversation(imConversationCreate);
return imConversation;
} }
/** /**
...@@ -54,13 +53,14 @@ public class ImConversationController extends BaseController { ...@@ -54,13 +53,14 @@ public class ImConversationController extends BaseController {
} }
/** /**
* 修改单向隐藏或显示会话 * 批量修改单向隐藏或显示会话
*/ */
@PostMapping("/displayUpdate") @PostMapping("/displayUpdate")
@ApiOperation(value = "修改单向隐藏或显示会话", notes = "拉取会话列表不展示已隐藏状态的会话,云端聊天记录不删除;假设有A和B两个用户,A删会话,B还能发; 如果B发了消息,A这边要重新把会话显示出来,并能显示之前的聊天记录") @ApiOperation(value = "批量修改单向隐藏或显示会话", notes = "拉取会话列表不展示已隐藏状态的会话,云端聊天记录不删除;假设有A和B两个用户,A删会话,B还能发; 如果B发了消息,A这边要重新把会话显示出来,并能显示之前的聊天记录")
public ApiResult<Boolean> updateDisplayConversation(@RequestBody ImConversationDisplayUpdate imConversationDisplayUpdate) throws Exception { public ApiResult<Boolean> updateDisplayConversation(@RequestBody ImConversationDisplayUpdate imConversationDisplayUpdate) throws Exception {
boolean flag = imConversationService.updateDisplayConversation(imConversationDisplayUpdate);
return ApiResult.result(flag); imConversationService.updateDisplayConversation(imConversationDisplayUpdate);
return ApiResult.result(true);
} }
// /** // /**
......
...@@ -9,6 +9,7 @@ import io.swagger.annotations.Api; ...@@ -9,6 +9,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
...@@ -34,7 +35,7 @@ public class ImInboxController extends BaseController { ...@@ -34,7 +35,7 @@ public class ImInboxController extends BaseController {
*/ */
@PostMapping("/msgReceivedUpdate") @PostMapping("/msgReceivedUpdate")
@ApiOperation(value = "消息修改为已接收状态") @ApiOperation(value = "消息修改为已接收状态")
public ApiResult<Boolean> updateImMsgReceived(@RequestBody ImMsgReceivedStatusUpdate imMsgReceivedUpdate) throws Exception { public ApiResult<Boolean> updateImMsgReceived(@RequestBody @Validated ImMsgReceivedStatusUpdate imMsgReceivedUpdate) throws Exception {
return imInboxService.updateImMsgReceived(imMsgReceivedUpdate); return imInboxService.updateImMsgReceived(imMsgReceivedUpdate);
} }
......
//package com.wecloud.im.controller;
//
//import com.wecloud.im.service.ImIosApnsService;
//import io.geekidea.springbootplus.framework.common.controller.BaseController;
//import io.swagger.annotations.Api;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.web.bind.annotation.RequestMapping;
//import org.springframework.web.bind.annotation.RestController;
//
///**
// * apns配置表 控制器
// *
// * @author wei
// * @since 2021-09-18
// */
//@Slf4j
//@RestController
//@RequestMapping("/imIosApns")
//@Api(value = "apns配置表API", tags = {"apns配置表"})
//public class ImIosApnsController extends BaseController {
//
// @Autowired
// private ImIosApnsService imIosApnsService;
////
//// /**
//// * 添加apns配置表
//// */
//// @PostMapping("/add")
//// @OperationLog(name = "添加apns配置表", type = OperationLogType.ADD)
//// @ApiOperation(value = "添加apns配置表")
//// public ApiResult<Boolean> addImIosApns(@Validated(Add.class) @RequestBody ImIosApns imIosApns) throws Exception {
//// boolean flag = imIosApnsService.saveImIosApns(imIosApns);
//// return ApiResult.result(flag);
//// }
////
//// /**
//// * 修改apns配置表
//// */
//// @PostMapping("/update")
//// @OperationLog(name = "修改apns配置表", type = OperationLogType.UPDATE)
//// @ApiOperation(value = "修改apns配置表")
//// public ApiResult<Boolean> updateImIosApns(@Validated(Update.class) @RequestBody ImIosApns imIosApns) throws Exception {
//// boolean flag = imIosApnsService.updateImIosApns(imIosApns);
//// return ApiResult.result(flag);
//// }
////
//// /**
//// * 删除apns配置表
//// */
//// @PostMapping("/delete/{id}")
//// @OperationLog(name = "删除apns配置表", type = OperationLogType.DELETE)
//// @ApiOperation(value = "删除apns配置表")
//// public ApiResult<Boolean> deleteImIosApns(@PathVariable("id") Long id) throws Exception {
//// boolean flag = imIosApnsService.deleteImIosApns(id);
//// return ApiResult.result(flag);
//// }
////
//// /**
//// * 获取apns配置表详情
//// */
//// @GetMapping("/info/{id}")
//// @OperationLog(name = "apns配置表详情", type = OperationLogType.INFO)
//// @ApiOperation(value = "apns配置表详情")
//// public ApiResult<ImIosApnsQueryVo> getImIosApns(@PathVariable("id") Long id) throws Exception {
//// ImIosApnsQueryVo imIosApnsQueryVo = imIosApnsService.getImIosApnsById(id);
//// return ApiResult.ok(imIosApnsQueryVo);
//// }
//
//// /**
//// * apns配置表分页列表
//// */
//// @PostMapping("/getPageList")
//// @OperationLog(name = "apns配置表分页列表", type = OperationLogType.PAGE)
//// @ApiOperation(value = "apns配置表分页列表")
//// public ApiResult<Paging<ImIosApnsQueryVo>>getImIosApnsPageList(@Validated @RequestBody ImIosApnsPageParam imIosApnsPageParam)throws Exception{
//// Paging<ImIosApnsQueryVo> paging = imIosApnsService.getImIosApnsPageList(imIosApnsPageParam);
//// return ApiResult.ok(paging);
//// }
////
//}
//
package com.wecloud.im.controller;
import cn.hutool.crypto.digest.MD5;
import com.wecloud.im.param.GetSignParam;
import com.wecloud.im.service.ImClientLoginService;
import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* sign 控制器
*
* @author wei
* @since 2021-04-27
*/
@Slf4j
@RestController
@RequestMapping("/signDemo")
@Api(value = "sign API", tags = {"获取sign(Demo)"})
public class SignController extends BaseController {
@Autowired
private ImClientLoginService imClientLoginService;
/**
* 根据客户方生成签名字符串 验证通过则下发token
*/
@GetMapping("/get")
@ApiOperation(value = "获取sign(仅测试使用)", notes = "生成签名")
public String verify(@RequestBody GetSignParam getSignParam) throws Exception {
return new MD5().digestHex(getSignParam.getTimestamp() + getSignParam.getClientId() + getSignParam.getAppKey() + getSignParam.getAppSecret());
}
}
...@@ -62,4 +62,7 @@ public class ImApplication extends BaseEntity { ...@@ -62,4 +62,7 @@ public class ImApplication extends BaseEntity {
@ApiModelProperty("是否允许创建重复会话 0不允许 1允许") @ApiModelProperty("是否允许创建重复会话 0不允许 1允许")
private Integer repeatSessionStatus; private Integer repeatSessionStatus;
@ApiModelProperty("创建会话时对比扩展字段 0不 1是")
private Integer contrastExtendedFieldStatus;
} }
...@@ -33,6 +33,9 @@ public class ImClient extends BaseEntity { ...@@ -33,6 +33,9 @@ public class ImClient extends BaseEntity {
@ApiModelProperty("创建时间") @ApiModelProperty("创建时间")
private Date createTime; private Date createTime;
@ApiModelProperty("最后离线时间")
private Date lastOfflineTime;
@ApiModelProperty("修改时间") @ApiModelProperty("修改时间")
private Date updateTime; private Date updateTime;
......
...@@ -51,7 +51,7 @@ public class ImConversation extends BaseEntity { ...@@ -51,7 +51,7 @@ public class ImConversation extends BaseEntity {
private String name; private String name;
@ApiModelProperty("可选 自定义属性,供开发者扩展使用。") @ApiModelProperty("可选 自定义属性,供开发者扩展使用。")
private Object attributes; private String attributes;
@ApiModelProperty("可选 对话类型标志,是否是系统对话,后面会说明。") @ApiModelProperty("可选 对话类型标志,是否是系统对话,后面会说明。")
private Boolean system; private Boolean system;
......
package com.wecloud.im.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* apns配置表
*
* @author wei
* @since 2021-09-18
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "ImIosApns对象")
public class ImIosApns extends BaseEntity {
private static final long serialVersionUID = 1L;
@NotNull(message = "id不能为空")
@ApiModelProperty("id")
@TableId(value = "id", type = IdType.INPUT)
private Long id;
@NotNull(message = "应用appid不能为空")
@ApiModelProperty("应用appid")
private Long fkAppId;
@ApiModelProperty("Base64(apns.p12)")
private String apnsFileValue;
@ApiModelProperty("环境,正式1,测试0")
private Integer env;
@ApiModelProperty("bundle_id")
private String bundleId;
@ApiModelProperty("证书密码")
private String pwd;
}
...@@ -46,7 +46,7 @@ public class DownloadInterceptor extends HandlerInterceptorAdapter { ...@@ -46,7 +46,7 @@ public class DownloadInterceptor extends HandlerInterceptorAdapter {
// 访问全路径 // 访问全路径
String fullUrl = request.getRequestURL().toString(); String fullUrl = request.getRequestURL().toString();
// 下载拦截器,业务处理代码 // 下载拦截器,业务处理代码
log.debug("DownloadInterceptor..."); log.info("DownloadInterceptor...");
// 访问token,如果需要,可以设置参数,进行鉴权 // 访问token,如果需要,可以设置参数,进行鉴权
// String token = request.getParameter(JwtTokenUtil.getTokenName()); // String token = request.getParameter(JwtTokenUtil.getTokenName());
return true; return true;
......
...@@ -46,7 +46,7 @@ public class ResourceInterceptor extends HandlerInterceptorAdapter { ...@@ -46,7 +46,7 @@ public class ResourceInterceptor extends HandlerInterceptorAdapter {
// 访问全路径 // 访问全路径
String fullUrl = request.getRequestURL().toString(); String fullUrl = request.getRequestURL().toString();
// 资源拦截器,业务处理代码 // 资源拦截器,业务处理代码
log.debug("ResourceInterceptor..."); log.info("ResourceInterceptor...");
// 访问token,如果需要,可以设置参数,进行鉴权 // 访问token,如果需要,可以设置参数,进行鉴权
// String token = request.getParameter(JwtTokenUtil.getTokenName()); // String token = request.getParameter(JwtTokenUtil.getTokenName());
return true; return true;
......
...@@ -47,7 +47,7 @@ public class UploadInterceptor extends HandlerInterceptorAdapter { ...@@ -47,7 +47,7 @@ public class UploadInterceptor extends HandlerInterceptorAdapter {
// 访问全路径 // 访问全路径
String fullUrl = request.getRequestURL().toString(); String fullUrl = request.getRequestURL().toString();
// 上传拦截器,业务处理代码 // 上传拦截器,业务处理代码
log.debug("UploadInterceptor..."); log.info("UploadInterceptor...");
// 访问token,如果需要,可以设置参数,进行鉴权 // 访问token,如果需要,可以设置参数,进行鉴权
// String token = request.getParameter(JwtTokenUtil.getTokenName()); // String token = request.getParameter(JwtTokenUtil.getTokenName());
return true; return true;
......
package com.wecloud.im.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.param.ImIosApnsPageParam;
import com.wecloud.im.param.ImIosApnsQueryVo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.io.Serializable;
/**
* apns配置表 Mapper 接口
*
* @author wei
* @since 2021-09-18
*/
@Repository
public interface ImIosApnsMapper extends BaseMapper<ImIosApns> {
/**
* 根据ID获取查询对象
*
* @param id
* @return
*/
ImIosApnsQueryVo getImIosApnsById(Serializable id);
/**
* 获取分页对象
*
* @param page
* @param imIosApnsPageParam
* @return
*/
IPage<ImIosApnsQueryVo> getImIosApnsPageList(@Param("page") Page page, @Param("param") ImIosApnsPageParam imIosApnsPageParam);
}
...@@ -62,7 +62,7 @@ public class ChannelInboundHandler extends ChannelInboundHandlerAdapter { ...@@ -62,7 +62,7 @@ public class ChannelInboundHandler extends ChannelInboundHandlerAdapter {
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) throws Exception {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("连接的客户端地址:{}", ctx.channel().remoteAddress()); logger.info("连接的客户端地址:{}", ctx.channel().remoteAddress());
} }
ctx.writeAndFlush("客户端" + InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! "); ctx.writeAndFlush("客户端" + InetAddress.getLocalHost().getHostName() + "成功与服务端建立连接! ");
super.channelActive(ctx); super.channelActive(ctx);
......
...@@ -14,21 +14,21 @@ import org.springframework.stereotype.Component; ...@@ -14,21 +14,21 @@ import org.springframework.stereotype.Component;
@Slf4j @Slf4j
public class NettyStart { public class NettyStart {
private final NettyChannelInitializer nettyChannelInitializer; private final NettyChannelInitializer nettyChannelInitializer;
private static final EventLoopGroup boss = new NioEventLoopGroup(1); private static final EventLoopGroup BOSS = new NioEventLoopGroup(1);
private static final EventLoopGroup work = new NioEventLoopGroup(); private static final EventLoopGroup WORK = new NioEventLoopGroup();
private static final ServerBootstrap serverBootstrap = new ServerBootstrap(); private static final ServerBootstrap SERVER_BOOTSTRAP = new ServerBootstrap();
static { static {
serverBootstrap.group(boss, work); SERVER_BOOTSTRAP.group(BOSS, WORK);
//Netty4使用对象池,重用缓冲区 //Netty4使用对象池,重用缓冲区
serverBootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); SERVER_BOOTSTRAP.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
serverBootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT); SERVER_BOOTSTRAP.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
//设置 心跳保活 socket 的参数选项 keepAlive //设置 心跳保活 socket 的参数选项 keepAlive
serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); SERVER_BOOTSTRAP.childOption(ChannelOption.SO_KEEPALIVE, true);
// 设置不延迟发送TCP_NODELAY=true // 设置不延迟发送TCP_NODELAY=true
serverBootstrap.childOption(ChannelOption.TCP_NODELAY, true); SERVER_BOOTSTRAP.childOption(ChannelOption.TCP_NODELAY, true);
// // 初始化服务端可连接队列 // // 初始化服务端可连接队列
// serverBootstrap.option(ChannelOption.SO_BACKLOG, 1000); // serverBootstrap.option(ChannelOption.SO_BACKLOG, 1000);
...@@ -39,7 +39,7 @@ public class NettyStart { ...@@ -39,7 +39,7 @@ public class NettyStart {
// serverBootstrap.option(ChannelOption.SO_SNDBUF, 256 * 1024); // serverBootstrap.option(ChannelOption.SO_SNDBUF, 256 * 1024);
// 配置io模型为nio非阻塞 // 配置io模型为nio非阻塞
serverBootstrap.channel(NioServerSocketChannel.class); SERVER_BOOTSTRAP.channel(NioServerSocketChannel.class);
} }
...@@ -58,16 +58,16 @@ public class NettyStart { ...@@ -58,16 +58,16 @@ public class NettyStart {
try { try {
//设置过滤器 //设置过滤器
serverBootstrap.childHandler(nettyChannelInitializer); SERVER_BOOTSTRAP.childHandler(nettyChannelInitializer);
// 服务器绑定端口监听 // 服务器绑定端口监听
ChannelFuture f = serverBootstrap.bind(port).sync(); ChannelFuture f = SERVER_BOOTSTRAP.bind(port).sync();
f.channel().closeFuture().sync(); f.channel().closeFuture().sync();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
//关闭EventLoopGroup,释放掉所有资源包括创建的线程 //关闭EventLoopGroup,释放掉所有资源包括创建的线程
boss.shutdownGracefully(); BOSS.shutdownGracefully();
work.shutdownGracefully(); WORK.shutdownGracefully();
} }
} }
......
...@@ -42,9 +42,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -42,9 +42,9 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
* io密集型任务配置尽可能多的线程数量 * io密集型任务配置尽可能多的线程数量
*/ */
private final static ExecutorService TASK_THREAD_POOL_EXECUTOR = private final static ExecutorService TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 10, WsConstants.CPU_PROCESSORS * 20, new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 5, WsConstants.CPU_PROCESSORS * 50,
3L, TimeUnit.MILLISECONDS, 3L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(2048), NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy()); new LinkedBlockingQueue<Runnable>(1), NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy());
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) { protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
...@@ -68,67 +68,59 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram ...@@ -68,67 +68,59 @@ public class WsReadHandler extends SimpleChannelInboundHandler<TextWebSocketFram
} }
private void execute(ChannelHandlerContext ctx, String data) { private void execute(ChannelHandlerContext ctx, String data) {
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx); String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get();
// String clientId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get();
// log.debug("appWS收到" + userIdByChannel + ":" + data + ",channelId:" + ctx.channel().id().asLongText()); try {
log.debug("WS收到:" + data); readWsData.convertModel(data, ctx, appKey, clientId);
} catch (Exception e) {
log.error("系统繁忙data:" + data + ",appKey:" + appKey + ",clientId:" + clientId +
",channelId:" + ctx.channel().id().asShortText(), e);
}
readWsData.convertModel(data, ctx);
} }
/** // /**
* 检测到异常 // * 检测到异常
* // *
* @param ctx // * @param ctx
* @param cause // * @param cause
* @throws Exception // * @throws Exception
*/ // */
@Override // @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.debug("检测到异常exceptionCaught", cause); // String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
// log.info("uid:" + userIdByChannel + ",ws异常,channelId:" + ctx.channel().id().asShortText(), cause);
// //排除当客户端意外关闭的情况,不是发送指定指令通知服务器退出,就会产生此错误。 // }
// if (ctx.channel().isActive()) {
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx);
// log.error("uid:" + userIdByChannel + ",ws异常,channelId:" + ctx.channel().id().asLongText(), cause);
// }
}
@Override @Override
public void handlerAdded(ChannelHandlerContext ctx) { public void handlerAdded(ChannelHandlerContext ctx) {
String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
String userIdByChannel = mangerChannelService.getUserIdByChannel(ctx); log.info("连接WS成功handlerAdded,uid:" + userIdByChannel + "," + ",channelId:" + ctx.channel().id().asShortText());
log.debug("uid:" + userIdByChannel + "," + ",channelId:" + ctx.channel().id().asLongText());
log.debug("连接WS成功handlerAdded");
} }
/** // /**
* 客户端不活跃 // * 客户端不活跃
* // *
* @param ctx // * @param ctx
* @throws Exception // * @throws Exception
*/ // */
@Override // @Override
public void channelInactive(ChannelHandlerContext ctx) { // public void channelInactive(ChannelHandlerContext ctx) {
log.debug("客户端不活跃channelInactive"); // String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
// log.info("uid:" + userIdByChannel + "," + "channelInactive" + ",channelId:" + ctx.channel().id().asShortText());
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx); // }
// log.debug("uid:" + userIdByChannel + "," + "不活跃" + ",channelId:" + ctx.channel().id().asLongText());
// mangerChannelService.remove(ctx);
}
/** /**
* 移除时触发, 不活跃的情况下会移除,会再次触发该事件 * 移除时触发, 不活跃的情况下会移除,会再次触发该事件
*/ */
@Override @Override
public void handlerRemoved(ChannelHandlerContext ctx) { public void handlerRemoved(ChannelHandlerContext ctx) {
String userIdByChannel = mangerChannelService.getInfoByChannel(ctx);
log.debug("handlerRemoved"); log.info("uid:" + userIdByChannel + "," + "handlerRemoved" + ",channelId:" + ctx.channel().id().asShortText());
// 关掉连接
// Long userIdByChannel = appUserChannelsService.getUserIdByChannel(ctx); ctx.close();
// log.debug("uid:" + userIdByChannel + "," + "handlerRemoved" + ",channelId:" + ctx.channel().id().asLongText());
} }
} }
...@@ -64,7 +64,7 @@ public class NettyApiRequest { ...@@ -64,7 +64,7 @@ public class NettyApiRequest {
String body = FullHttpRequestUtils.getBody(httpRequest); String body = FullHttpRequestUtils.getBody(httpRequest);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("httpRequest:\n" + httpRequest.toString() + "\n" + body); log.info("httpRequest:\n" + httpRequest.toString() + "\n" + body);
} }
if (path.contains(WsConstants.WS_URL)) { if (path.contains(WsConstants.WS_URL)) {
......
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* sign
*
* @author wei
* @since 2021-04-29
*/
@Data
@ApiModel(value = "GetOnlineStatusParam")
public class GetOnlineStatusParam {
private static final long serialVersionUID = 1L;
@ApiModelProperty("客户端ID")
List<String> clientIds;
}
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* sign
*
* @author wei
* @since 2021-04-29
*/
@Data
@ApiModel(value = "GetSignParam")
public class GetSignParam {
private static final long serialVersionUID = 1L;
@ApiModelProperty("时间戳")
private String timestamp;
@ApiModelProperty("client客户端id")
private String clientId;
@ApiModelProperty("appKey")
private String appKey;
@ApiModelProperty("密钥")
private String appSecret;
}
package com.wecloud.im.param;
import io.geekidea.springbootplus.framework.core.pagination.BasePageOrderParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <pre>
* apns配置表 分页参数对象
* </pre>
*
* @author wei
* @date 2021-09-18
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "apns配置表分页参数")
public class ImIosApnsPageParam extends BasePageOrderParam {
private static final long serialVersionUID = 1L;
}
package com.wecloud.im.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* apns配置表 查询结果对象
* </pre>
*
* @author wei
* @date 2021-09-18
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "ImIosApnsQueryVo对象")
public class ImIosApnsQueryVo implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("id")
private Long id;
@ApiModelProperty("应用appid")
private Long fkAppId;
@ApiModelProperty("Base64(apns.p12)")
private String apnsFileValue;
@ApiModelProperty("环境,正式1,测试0")
private Integer env;
@ApiModelProperty("bundle_id")
private String bundleId;
@ApiModelProperty("证书密码")
private String pwd;
}
\ No newline at end of file
...@@ -7,6 +7,7 @@ import lombok.Data; ...@@ -7,6 +7,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
/** /**
...@@ -22,9 +23,10 @@ import java.util.List; ...@@ -22,9 +23,10 @@ import java.util.List;
public class ImMsgReceivedStatusUpdate extends BaseEntity { public class ImMsgReceivedStatusUpdate extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ApiModelProperty("消息id数组,可以传入单个或多个, 如接收离线消息列表时可以批量修改 则传入多个") @ApiModelProperty(value = "消息id数组,可以传入单个或多个, 如接收离线消息列表时可以批量修改 则传入多个", required = true)
@NotEmpty(message = "msgIds==null")
private List<Long> msgIds; private List<Long> msgIds;
@ApiModelProperty("是否同时修改为已读状态") @ApiModelProperty(value = "是否同时修改为已读状态", required = false)
private Boolean readStatus; private Boolean readStatus = false;
} }
...@@ -7,6 +7,8 @@ import lombok.Data; ...@@ -7,6 +7,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.util.List;
/** /**
* 修改是否单向隐藏会话 * 修改是否单向隐藏会话
* *
...@@ -21,7 +23,7 @@ public class ImConversationDisplayUpdate extends BaseEntity { ...@@ -21,7 +23,7 @@ public class ImConversationDisplayUpdate extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "会话id", required = true) @ApiModelProperty(value = "会话id", required = true)
private Long conversationId; private List<Long> conversationIds;
@ApiModelProperty(value = "显示状态 1显示 0不显示", required = true) @ApiModelProperty(value = "显示状态 1显示 0不显示", required = true)
private Integer displayStatus; private Integer displayStatus;
......
...@@ -85,7 +85,7 @@ public class PushClient { ...@@ -85,7 +85,7 @@ public class PushClient {
// Decode response string and get file_id from it // Decode response string and get file_id from it
JSONObject respJson = new JSONObject(result.toString()); JSONObject respJson = new JSONObject(result.toString());
String ret = respJson.getString("ret"); String ret = respJson.getString("ret");
if (!ret.equals("SUCCESS")) { if (!"SUCCESS".equals(ret)) {
throw new Exception("Failed to upload file"); throw new Exception("Failed to upload file");
} }
JSONObject data = respJson.getJSONObject("data"); JSONObject data = respJson.getJSONObject("data");
......
package com.wecloud.im.register;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
/**
* 获取公网ip
*/
@Component
@Slf4j
public class GetIpUtils {
private static final String LOCAL = "local";
private static final String AWS = "aws";
private static final String HUAWEI_CLOUD = "huawei";
/**
* 内网ip
*/
private static String lAN_IP = null;
/**
* 公网ip
*/
private static String PUBLIC_IP = null;
/**
* 服务器运营商local,aws,huawei
*/
@Value("${load-blance.server-type}")
private String SERVER_TYPE;
/**
* 内网ip
*
* @return
*/
public String getlanIp() {
if (lAN_IP == null) {
lAN_IP = getLocalIpAddress();
}
return lAN_IP;
}
/**
* 公网ip
*/
public String getPublicIp() {
if (PUBLIC_IP == null) {
switch (SERVER_TYPE) {
case LOCAL:
PUBLIC_IP = getlanIp();
break;
case AWS:
PUBLIC_IP = HttpUtil.get("http://instance-data/latest/meta-data/public-ipv4", 30);
break;
case HUAWEI_CLOUD:
PUBLIC_IP = HttpUtil.get("http://169.254.169.254/latest/meta-data/public-ipv4", 30);
break;
}
}
return PUBLIC_IP;
}
/**
* 判断是否为虚拟mac地址
*
* @param mac
* @return
*/
private static boolean isVmMac(byte[] mac) {
if (null == mac) {
return false;
}
/*
* 排除无效的mac地址
*/
byte[][] INVALID_MACS = {
{0x00, 0x05, 0x69}, // VMWare
{0x00, 0x1C, 0x14}, // VMWare
{0x00, 0x0C, 0x29}, // VMWare
{0x00, 0x50, 0x56}, // VMWare
{0x08, 0x00, 0x27}, // Virtualbox
{0x0A, 0x00, 0x27}, // Virtualbox
{0x00, 0x03, (byte) 0xFF}, // Virtual-PC
{0x00, 0x15, 0x5D} // Hyper-V
};
for (byte[] invalid : INVALID_MACS) {
if (invalid[0] == mac[0] && invalid[1] == mac[1] && invalid[2] == mac[2]) {
return true;
}
}
return false;
}
/**
* 获取本机地址
*/
private static String getLocalIpAddress() {
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface ni = networkInterfaces.nextElement();
/*
排除docker虚拟网卡
*/
String docker0 = "docker0";
if (ni.getName().equals(docker0)) {
continue;
}
if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) {
continue;
}
if (isVmMac(ni.getHardwareAddress())) {
continue;
}
Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (inetAddress.isLinkLocalAddress()) {
continue;
}
return inetAddress.getHostAddress();
}
}
} catch (SocketException e) {
log.info("获取本机IP地址失败。" + e);
}
return StringUtils.EMPTY;
}
}
...@@ -14,6 +14,15 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging; ...@@ -14,6 +14,15 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging;
*/ */
public interface ImApplicationService extends BaseService<ImApplication> { public interface ImApplicationService extends BaseService<ImApplication> {
/**
* 根据appKey查询application
*
* @param appKey
* @return
*/
ImApplication getOneByAppKey(String appKey);
/** /**
* 保存 * 保存
* *
......
...@@ -30,7 +30,7 @@ public interface ImClientService extends BaseService<ImClient> { ...@@ -30,7 +30,7 @@ public interface ImClientService extends BaseService<ImClient> {
* @param imClientDevice * @param imClientDevice
* @return * @return
*/ */
boolean addDeviceInfo(ImClientDeviceInfoAdd imClientDevice); boolean updateDeviceInfo(ImClientDeviceInfoAdd imClientDevice);
/** /**
* 修改 * 修改
...@@ -76,4 +76,8 @@ public interface ImClientService extends BaseService<ImClient> { ...@@ -76,4 +76,8 @@ public interface ImClientService extends BaseService<ImClient> {
*/ */
ImClient getCurentClient(); ImClient getCurentClient();
ImClient getCacheImClient(Long applicationId, String clientId);
void deleteCacheImClient(Long applicationId, String clientId);
} }
package com.wecloud.im.service; package com.wecloud.im.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.wecloud.im.entity.ImConversation; import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.param.ImConversationPageParam; import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryVo; import com.wecloud.im.param.ImConversationQueryVo;
...@@ -37,7 +38,7 @@ public interface ImConversationService extends BaseService<ImConversation> { ...@@ -37,7 +38,7 @@ public interface ImConversationService extends BaseService<ImConversation> {
* @param imConversationCreate * @param imConversationCreate
* @return * @return
*/ */
ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate); ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) throws JsonProcessingException;
/** /**
* 修改 * 修改
...@@ -49,7 +50,7 @@ public interface ImConversationService extends BaseService<ImConversation> { ...@@ -49,7 +50,7 @@ public interface ImConversationService extends BaseService<ImConversation> {
boolean updateImConversation(ImConversation imConversation) throws Exception; boolean updateImConversation(ImConversation imConversation) throws Exception;
/** /**
* 是否单向隐藏会话","云端聊天记录不删除;假设有A和B两个用户,A删会话,B还能发; 如果B发了消息,A这边要重新把会话显示出来,并能显示之前的聊天记录" * 修改为 是否单向隐藏会话","云端聊天记录不删除;假设有A和B两个用户,A删会话,B还能发; 如果B发了消息,A这边要重新把会话显示出来,并能显示之前的聊天记录"
* *
* @return * @return
* @throws Exception * @throws Exception
......
...@@ -2,13 +2,10 @@ package com.wecloud.im.service; ...@@ -2,13 +2,10 @@ package com.wecloud.im.service;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.wecloud.im.entity.ImInbox; import com.wecloud.im.entity.ImInbox;
import com.wecloud.im.param.ImInboxPageParam;
import com.wecloud.im.param.ImInboxQueryVo;
import com.wecloud.im.param.ImMsgReadStatusUpdate; import com.wecloud.im.param.ImMsgReadStatusUpdate;
import com.wecloud.im.param.ImMsgReceivedStatusUpdate; import com.wecloud.im.param.ImMsgReceivedStatusUpdate;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.BaseService; import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
/** /**
* 消息收件箱表 服务类 * 消息收件箱表 服务类
...@@ -18,50 +15,50 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging; ...@@ -18,50 +15,50 @@ import io.geekidea.springbootplus.framework.core.pagination.Paging;
*/ */
public interface ImInboxService extends BaseService<ImInbox> { public interface ImInboxService extends BaseService<ImInbox> {
/** // /**
* 保存 // * 保存
* // *
* @param imInbox // * @param imInbox
* @return // * @return
* @throws Exception // * @throws Exception
*/ // */
boolean saveImInbox(ImInbox imInbox) throws Exception; // boolean saveImInbox(ImInbox imInbox) throws Exception;
//
/** // /**
* 修改 // * 修改
* // *
* @param imInbox // * @param imInbox
* @return // * @return
* @throws Exception // * @throws Exception
*/ // */
boolean updateImInbox(ImInbox imInbox) throws Exception; // boolean updateImInbox(ImInbox imInbox) throws Exception;
//
/** // /**
* 删除 // * 删除
* // *
* @param id // * @param id
* @return // * @return
* @throws Exception // * @throws Exception
*/ // */
boolean deleteImInbox(Long id) throws Exception; // boolean deleteImInbox(Long id) throws Exception;
//
/** // /**
* 根据ID获取查询对象 // * 根据ID获取查询对象
* // *
* @param id // * @param id
* @return // * @return
* @throws Exception // * @throws Exception
*/ // */
ImInboxQueryVo getImInboxById(Long id) throws Exception; // ImInboxQueryVo getImInboxById(Long id) throws Exception;
//
/** // /**
* 获取分页对象 // * 获取分页对象
* // *
* @param imInboxPageParam // * @param imInboxPageParam
* @return // * @return
* @throws Exception // * @throws Exception
*/ // */
Paging<ImInboxQueryVo> getImInboxPageList(ImInboxPageParam imInboxPageParam) throws Exception; // Paging<ImInboxQueryVo> getImInboxPageList(ImInboxPageParam imInboxPageParam) throws Exception;
/** /**
......
package com.wecloud.im.service;
import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.param.ImIosApnsQueryVo;
import io.geekidea.springbootplus.framework.common.service.BaseService;
/**
* apns配置表 服务类
*
* @author wei
* @since 2021-09-18
*/
public interface ImIosApnsService extends BaseService<ImIosApns> {
/**
* 保存
*
* @param imIosApns
* @return
* @throws Exception
*/
boolean saveImIosApns(ImIosApns imIosApns) throws Exception;
/**
* 修改
*
* @param imIosApns
* @return
* @throws Exception
*/
boolean updateImIosApns(ImIosApns imIosApns) throws Exception;
/**
* 删除
*
* @param id
* @return
* @throws Exception
*/
boolean deleteImIosApns(Long id) throws Exception;
/**
* 根据ID获取查询对象
*
* @param id
* @return
* @throws Exception
*/
ImIosApnsQueryVo getImIosApnsById(Long id) throws Exception;
ImIosApns getImIosApnsByAppId(Long appId);
/**
* 获取分页对象
*
* @param imIosApnsPageParam
* @return
* @throws Exception
*/
// Paging<ImIosApnsQueryVo> getImIosApnsPageList(ImIosApnsPageParam imIosApnsPageParam) throws Exception;
}
...@@ -37,6 +37,50 @@ public interface ImMessageService extends BaseService<ImMessage> { ...@@ -37,6 +37,50 @@ public interface ImMessageService extends BaseService<ImMessage> {
ApiResult<Boolean> updateMsgById(ImMsgUpdate imMsgUpdate); ApiResult<Boolean> updateMsgById(ImMsgUpdate imMsgUpdate);
/** /**
* 查询某个会话历史消息分页列表
*
* @param imHistoryMessagePageParam
* @return
* @throws Exception
*/
Paging<OfflineMsgDto> getHistoryMsgConversationId(ImHistoryMessagePageParam imHistoryMessagePageParam) throws Exception;
/**
* 查询用户所有离线消息
*
* @return
* @throws Exception
*/
List<ImMessageOfflineListVo> getOfflineList() throws Exception;
/**
* 根据客户端id与会话id 查询离线消息
*
* @param clientId
* @param conversationId
* @return
*/
List<OfflineMsgDto> getOfflineListByClientAndConversation(Long clientId, Long conversationId);
/**
* 查询会话的最后一条消息
*
* @param conversationId
* @return
*/
OfflineMsgDto getLastMsgByConversationId(Long conversationId);
/**
* 查询会话接收的最后一条消息
*
* @param clientId
* @param conversationId
* @return
*/
OfflineMsgDto getReceivedLastMsgByConversationId(Long clientId, Long conversationId);
/**
* 保存 * 保存
* *
* @param imMessage * @param imMessage
...@@ -80,53 +124,4 @@ public interface ImMessageService extends BaseService<ImMessage> { ...@@ -80,53 +124,4 @@ public interface ImMessageService extends BaseService<ImMessage> {
// * @throws Exception // * @throws Exception
// */ // */
// Paging<ImMessageQueryVo> getImMessagePageList(ImMessagePageParam imMessagePageParam) throws Exception; // Paging<ImMessageQueryVo> getImMessagePageList(ImMessagePageParam imMessagePageParam) throws Exception;
/**
* 查询某个会话历史消息分页列表
*
* @param imHistoryMessagePageParam
* @return
* @throws Exception
*/
Paging<OfflineMsgDto> getHistoryMsgConversationId(ImHistoryMessagePageParam imHistoryMessagePageParam) throws Exception;
/**
* 查询用户所有离线消息
*
* @return
* @throws Exception
*/
List<ImMessageOfflineListVo> getOfflineList() throws Exception;
/**
* 根据客户端id与会话id 查询离线消息
*
* @param clientId
* @param conversationId
* @return
*/
List<OfflineMsgDto> getOfflineListByClientAndConversation(Long clientId, Long conversationId);
/**
* 查询会话接收的最后一条消息
*
* @param clientId
* @param conversationId
* @return
*/
OfflineMsgDto getReceivedLastMsgByConversationId(Long clientId, Long conversationId);
/**
* 查询会话的最后一条消息
*
* @param conversationId
* @return
*/
OfflineMsgDto getLastMsgByConversationId(Long conversationId);
} }
package com.wecloud.im.service.impl; package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem; import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
...@@ -13,6 +14,8 @@ import io.geekidea.springbootplus.framework.core.pagination.PageInfo; ...@@ -13,6 +14,8 @@ import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -24,11 +27,22 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -24,11 +27,22 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
@Slf4j @Slf4j
@Service @Service
@CacheConfig(cacheNames = "applic")
public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMapper, ImApplication> implements ImApplicationService { public class ImApplicationServiceImpl extends BaseServiceImpl<ImApplicationMapper, ImApplication> implements ImApplicationService {
@Autowired @Autowired
private ImApplicationMapper imApplicationMapper; private ImApplicationMapper imApplicationMapper;
@Override
@Cacheable(key = "#p0")
public ImApplication getOneByAppKey(String appKey) {
ImApplication imApplication = this.getOne(
new QueryWrapper<ImApplication>().lambda()
.eq(ImApplication::getAppKey, appKey)
);
return imApplication;
}
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public boolean saveImApplication(ImApplication imApplication) throws Exception { public boolean saveImApplication(ImApplication imApplication) throws Exception {
......
...@@ -59,12 +59,10 @@ public class ImClientLoginServiceImpl implements ImClientLoginService { ...@@ -59,12 +59,10 @@ public class ImClientLoginServiceImpl implements ImClientLoginService {
public ApiResult<TokenVo> verifySign(ImTokenVerify imTokenVerify) { public ApiResult<TokenVo> verifySign(ImTokenVerify imTokenVerify) {
// 根据appKey从数据库查询密钥 // 根据appKey从数据库查询密钥
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOneByAppKey(imTokenVerify.getAppKey());
new QueryWrapper<ImApplication>().lambda().eq(ImApplication::getAppKey, imTokenVerify.getAppKey())
);
if (imApplication == null) { if (imApplication == null) {
log.error("imApplication == null,getAppKey:" + imTokenVerify.getAppKey()); log.info("imApplication == null,getAppKey:" + imTokenVerify.getAppKey());
return ApiResult.result(ApiCode.FAIL, null); return ApiResult.result(ApiCode.FAIL, null);
} }
...@@ -73,10 +71,8 @@ public class ImClientLoginServiceImpl implements ImClientLoginService { ...@@ -73,10 +71,8 @@ public class ImClientLoginServiceImpl implements ImClientLoginService {
String mySign = new MD5().digestHex(imTokenVerify.getTimestamp() + imTokenVerify.getClientId() + imApplication.getAppKey() + secret); String mySign = new MD5().digestHex(imTokenVerify.getTimestamp() + imTokenVerify.getClientId() + imApplication.getAppKey() + secret);
// 验证签名 // 验证签名
if (mySign.equals(imTokenVerify.getSign())) { if (!mySign.equals(imTokenVerify.getSign())) {
log.debug("sign一致" + mySign); log.info("sign不一致" + mySign);
} else {
log.debug("sign不一致" + mySign);
return ApiResult.result(ApiCode.FAIL, null); return ApiResult.result(ApiCode.FAIL, null);
} }
...@@ -88,7 +84,7 @@ public class ImClientLoginServiceImpl implements ImClientLoginService { ...@@ -88,7 +84,7 @@ public class ImClientLoginServiceImpl implements ImClientLoginService {
.eq(ImClient::getClientId, imTokenVerify.getClientId())); .eq(ImClient::getClientId, imTokenVerify.getClientId()));
if (imClient == null) { if (imClient == null) {
log.debug("client不存在,先走注册流程"); log.info("client不存在,先走注册流程");
imClient = new ImClient(); imClient = new ImClient();
imClient.setId(new Snowflake(1L, 1L).nextId()); imClient.setId(new Snowflake(1L, 1L).nextId());
...@@ -103,8 +99,7 @@ public class ImClientLoginServiceImpl implements ImClientLoginService { ...@@ -103,8 +99,7 @@ public class ImClientLoginServiceImpl implements ImClientLoginService {
// 保存redis // 保存redis
// redisTemplate.opsForValue().set("client:" + imApplication.getAppKey() + ":" + imTokenVerify.getClientId(), generateToken); // redisTemplate.opsForValue().set("client:" + imApplication.getAppKey() + ":" + imTokenVerify.getClientId(), generateToken);
JwtToken jwtToken = new JwtToken() JwtToken jwtToken = JwtToken.build(generateToken, secret, jwtProperties.getExpireSecond(), imClient.getClientId(), imTokenVerify.getAppKey());
.build(generateToken, secret, jwtProperties.getExpireSecond(), imClient.getClientId(), imTokenVerify.getAppKey());
appLoginRedisService.cacheLoginInfo(jwtToken); appLoginRedisService.cacheLoginInfo(jwtToken);
......
...@@ -20,6 +20,9 @@ import io.geekidea.springbootplus.framework.shiro.util.JwtUtil; ...@@ -20,6 +20,9 @@ import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -31,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -31,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional;
*/ */
@Slf4j @Slf4j
@Service @Service
@CacheConfig(cacheNames = "client")
public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClient> implements ImClientService { public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClient> implements ImClientService {
@Autowired @Autowired
...@@ -46,18 +50,22 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -46,18 +50,22 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean addDeviceInfo(ImClientDeviceInfoAdd imClientDevice) { public boolean updateDeviceInfo(ImClientDeviceInfoAdd imClientDevice) {
ImClient client = getCurentClient(); ImClient client = getCurentClient();
ImClient clientNew = new ImClient(); ImClient clientNew = new ImClient();
BeanUtils.copyProperties(imClientDevice, clientNew); BeanUtils.copyProperties(imClientDevice, clientNew);
clientNew.setId(client.getId()); clientNew.setId(client.getId());
return this.saveOrUpdate(clientNew);
// 清楚缓存
deleteCacheImClient(client.getFkAppid(), client.getClientId());
// 修改
return this.updateImClient(clientNew);
} }
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public boolean updateImClient(ImClient imClient) throws Exception { public boolean updateImClient(ImClient imClient) {
return super.updateById(imClient); return super.updateById(imClient);
} }
...@@ -76,7 +84,7 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -76,7 +84,7 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
public Paging<ImClientQueryVo> getImClientPageList(ImClientPageParam imClientPageParam) throws Exception { public Paging<ImClientQueryVo> getImClientPageList(ImClientPageParam imClientPageParam) throws Exception {
Page<ImClientQueryVo> page = new PageInfo<>(imClientPageParam, OrderItem.desc(getLambdaColumn(ImClient::getCreateTime))); Page<ImClientQueryVo> page = new PageInfo<>(imClientPageParam, OrderItem.desc(getLambdaColumn(ImClient::getCreateTime)));
IPage<ImClientQueryVo> iPage = imClientMapper.getImClientPageList(page, imClientPageParam); IPage<ImClientQueryVo> iPage = imClientMapper.getImClientPageList(page, imClientPageParam);
return new Paging<ImClientQueryVo>(iPage); return new Paging<>(iPage);
} }
@Override @Override
...@@ -84,17 +92,22 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien ...@@ -84,17 +92,22 @@ public class ImClientServiceImpl extends BaseServiceImpl<ImClientMapper, ImClien
// shiro线程中获取当前token // shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken(); JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid // 根据appKey查询appid
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
new QueryWrapper<ImApplication>().lambda() return getCacheImClient(imApplication.getId(), curentJwtToken.getClientId());
.select(ImApplication::getId) }
.eq(ImApplication::getAppKey, curentJwtToken.getAppKey())
);
@Override
@Cacheable(key = "#p0+#p1")
public ImClient getCacheImClient(Long applicationId, String clientId) {
return this.getOne(new QueryWrapper<ImClient>().lambda() return this.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId()) .eq(ImClient::getFkAppid, applicationId)
.eq(ImClient::getClientId, curentJwtToken.getClientId())); .eq(ImClient::getClientId, clientId));
}
@Override
@CacheEvict(key = "#p0+#p1")
public void deleteCacheImClient(Long applicationId, String clientId) {
} }
} }
...@@ -78,17 +78,17 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap ...@@ -78,17 +78,17 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) { public ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) throws JsonProcessingException {
ImClient client = imClientService.getCurentClient(); ImClient createClient = imClientService.getCurentClient();
// 成员不存在,不能创建会话 // 成员不存在,不能创建会话
for (String id : imConversationCreate.getClientIds()) { for (String id : imConversationCreate.getClientIds()) {
ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient imClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.select(ImClient::getId) .select(ImClient::getId)
.eq(ImClient::getFkAppid, client.getFkAppid()) .eq(ImClient::getFkAppid, createClient.getFkAppid())
.eq(ImClient::getClientId, id)); .eq(ImClient::getClientId, id));
if (client2 == null) { if (imClient == null) {
log.info("成员不存在,不能创建会话 client2 == null"); log.info("成员不存在,不能创建会话 client2 == null");
return ApiResult.result(ApiCode.CLIENT_NOT_FOUNT, null); return ApiResult.result(ApiCode.CLIENT_NOT_FOUNT, null);
} }
...@@ -96,69 +96,93 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap ...@@ -96,69 +96,93 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap
// shiro线程中获取当前token // shiro线程中获取当前token
JwtToken curentJwtToken = JwtUtil.getCurentJwtToken(); JwtToken curentJwtToken = JwtUtil.getCurentJwtToken();
// 根据appKey查询appid // 根据appKey查询application
ImApplication imApplication = imApplicationService.getOne( ImApplication imApplication = imApplicationService.getOneByAppKey(curentJwtToken.getAppKey());
new QueryWrapper<ImApplication>().lambda()
.eq(ImApplication::getAppKey, curentJwtToken.getAppKey()) // 该应用 是否允许创建重复会话 0不允许 1允许
); if (imApplication.getRepeatSessionStatus() != null && imApplication.getRepeatSessionStatus() == 0) {
// 该应用 是否允许重复创建会话
if (imApplication.getRepeatSessionStatus() == 0) {
// 判断是否已经存在会话 // 判断是否已经存在会话
// 两个用户如果已经创建过会话,不能重复创建会话 // size() == 1 为单聊不允许重复创建 两个用户如果已经创建过会话,不能重复创建会话
// size() == 1 为单聊的时候不允许重复创建
if (imConversationCreate.getClientIds().size() == 1) { if (imConversationCreate.getClientIds().size() == 1) {
ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, client.getFkAppid()) .eq(ImClient::getFkAppid, createClient.getFkAppid())
.eq(ImClient::getClientId, imConversationCreate.getClientIds().get(0))); .eq(ImClient::getClientId, imConversationCreate.getClientIds().get(0)));
// 是否存在重复会话 // 是否存在重复会话
Integer repetitionConversation = getRepetitionConversation(client.getId(), client2.getId()); Integer repetitionConversation = getRepetitionConversation(createClient.getId(), client2.getId());
if (repetitionConversation != 0) { if (repetitionConversation != 0) {
log.debug("repetitionConversation != 0"); log.info("repetitionConversation != 0");
// 返回已存在的会话id // 返回已存在的会话id
ImConversation repetitionConversationInfo = imConversationMapper.getRepetitionConversationInfo(client.getId(), client2.getId()); ImConversation repetitionConversationInfo = imConversationMapper.getRepetitionConversationInfo(createClient.getId(), client2.getId());
ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo(); ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo();
imConversationCreateVo.setId(repetitionConversationInfo.getId()); imConversationCreateVo.setId(repetitionConversationInfo.getId());
return ApiResult.ok(imConversationCreateVo); return ApiResult.ok(imConversationCreateVo);
} }
} }
} else {
//创建重复会话时对比扩展字段 0不 1是
if (imApplication.getContrastExtendedFieldStatus() == 1) {
// 被邀请client
ImClient inviteClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, createClient.getFkAppid())
.eq(ImClient::getClientId, imConversationCreate.getClientIds().get(0)));
// 是否存在重复会话
Integer repetitionConversation = getRepetitionConversation(createClient.getId(), inviteClient.getId());
if (repetitionConversation != 0) {
ImConversation repetitionConversationInfo = imConversationMapper.getRepetitionConversationInfo(createClient.getId(), inviteClient.getId());
log.info("出现Conversation重复");
JsonMapper jsonMapper = new JsonMapper();
HashMap dbAttributesMap = jsonMapper.readValue(repetitionConversationInfo.getAttributes(), HashMap.class);
log.info("DBAttributes:" + repetitionConversationInfo.getAttributes());
log.info("RequestAttributes:" + jsonMapper.writeValueAsString(imConversationCreate.getAttributes()));
if (dbAttributesMap.equals(imConversationCreate.getAttributes())) {
log.info("出现Attributes重复");
ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo();
imConversationCreateVo.setId(repetitionConversationInfo.getId());
// 为重复
return ApiResult.ok(imConversationCreateVo);
}
}
}
} }
// 会话id // 会话id
Long imConversationId = SnowflakeUtil.getId(); Long imConversationId = SnowflakeUtil.getId();
// 创建者 // 创建者
Long creator = client.getId(); Long creator = createClient.getId();
// 创建会话 // 创建会话
ImConversation imConversation = new ImConversation(); ImConversation imConversation = new ImConversation();
imConversation.setId(imConversationId); imConversation.setId(imConversationId);
imConversation.setCreateTime(new Date()); imConversation.setCreateTime(new Date());
imConversation.setLastMessage(null); imConversation.setLastMessage(null);
imConversation.setFkAppid(client.getFkAppid()); imConversation.setFkAppid(createClient.getFkAppid());
imConversation.setCreator(creator); imConversation.setCreator(creator);
imConversation.setName(imConversationCreate.getName()); imConversation.setName(imConversationCreate.getName());
JsonMapper jsonMapper = new JsonMapper();
try {
String writeValueAsString = jsonMapper.writeValueAsString(imConversationCreate.getAttributes());
imConversation.setAttributes(writeValueAsString);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
imConversation.setSystem(false); imConversation.setSystem(false);
JsonMapper jsonMapper = new JsonMapper();
// 拓展数据
String writeValueAsString = jsonMapper.writeValueAsString(imConversationCreate.getAttributes());
imConversation.setAttributes(writeValueAsString);
imConversationService.save(imConversation); imConversationService.save(imConversation);
// 将自己添加到会话 // 将创建者自己添加到会话
Long imConversationMembersId = SnowflakeUtil.getId(); Long imConversationMembersId = SnowflakeUtil.getId();
ImConversationMembers imConversationMembers = new ImConversationMembers(); ImConversationMembers imConversationMembers = new ImConversationMembers();
imConversationMembers.setId(imConversationMembersId); imConversationMembers.setId(imConversationMembersId);
imConversationMembers.setCreateTime(new Date()); imConversationMembers.setCreateTime(new Date());
imConversationMembers.setFkAppid(client.getFkAppid()); imConversationMembers.setFkAppid(createClient.getFkAppid());
imConversationMembers.setFkConversationId(imConversationId); imConversationMembers.setFkConversationId(imConversationId);
imConversationMembers.setFkClientId(creator); imConversationMembers.setFkClientId(creator);
imConversationMembersService.save(imConversationMembers); imConversationMembersService.save(imConversationMembers);
...@@ -166,13 +190,13 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap ...@@ -166,13 +190,13 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap
// 将他人添加到会话 // 将他人添加到会话
for (String id : imConversationCreate.getClientIds()) { for (String id : imConversationCreate.getClientIds()) {
ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, client.getFkAppid()) .eq(ImClient::getFkAppid, createClient.getFkAppid())
.eq(ImClient::getClientId, id)); .eq(ImClient::getClientId, id));
Long imConversationMembersId2 = SnowflakeUtil.getId(); Long imConversationMembersId2 = SnowflakeUtil.getId();
ImConversationMembers imConversationMembers2 = new ImConversationMembers(); ImConversationMembers imConversationMembers2 = new ImConversationMembers();
imConversationMembers2.setId(imConversationMembersId2); imConversationMembers2.setId(imConversationMembersId2);
imConversationMembers2.setCreateTime(new Date()); imConversationMembers2.setCreateTime(new Date());
imConversationMembers2.setFkAppid(client.getFkAppid()); imConversationMembers2.setFkAppid(createClient.getFkAppid());
imConversationMembers2.setFkConversationId(imConversationId); imConversationMembers2.setFkConversationId(imConversationId);
imConversationMembers2.setFkClientId(client2.getId()); imConversationMembers2.setFkClientId(client2.getId());
imConversationMembersService.save(imConversationMembers2); imConversationMembersService.save(imConversationMembers2);
...@@ -201,15 +225,16 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap ...@@ -201,15 +225,16 @@ public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMap
@Override @Override
public boolean updateDisplayConversation(ImConversationDisplayUpdate imConversationDisplayUpdate) throws Exception { public boolean updateDisplayConversation(ImConversationDisplayUpdate imConversationDisplayUpdate) throws Exception {
ImClient curentClient = imClientService.getCurentClient(); ImClient curentClient = imClientService.getCurentClient();
for (Long id : imConversationDisplayUpdate.getConversationIds()) {
// 修改为删除隐藏状态 // 修改为删除隐藏状态
boolean update = imConversationMembersService.update(new UpdateWrapper<ImConversationMembers>() boolean update = imConversationMembersService.update(new UpdateWrapper<ImConversationMembers>()
.set("display_status", imConversationDisplayUpdate.getDisplayStatus()) .set("display_status", imConversationDisplayUpdate.getDisplayStatus())
.eq("fk_client_id", curentClient.getId()) .eq("fk_client_id", curentClient.getId())
.eq("fk_conversation_id", imConversationDisplayUpdate.getConversationId()) .eq("fk_conversation_id", id)
.eq("fk_appid", curentClient.getFkAppid()) .eq("fk_appid", curentClient.getFkAppid())
); );
return update; }
return true;
} }
@Override @Override
......
package com.wecloud.im.service.impl; package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversationMembers; import com.wecloud.im.entity.ImConversationMembers;
...@@ -10,8 +7,6 @@ import com.wecloud.im.entity.ImInbox; ...@@ -10,8 +7,6 @@ import com.wecloud.im.entity.ImInbox;
import com.wecloud.im.entity.ImMessage; import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.entity.ImMessageOnlineSend; import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.mapper.ImInboxMapper; import com.wecloud.im.mapper.ImInboxMapper;
import com.wecloud.im.param.ImInboxPageParam;
import com.wecloud.im.param.ImInboxQueryVo;
import com.wecloud.im.param.ImMsgReadStatusUpdate; import com.wecloud.im.param.ImMsgReadStatusUpdate;
import com.wecloud.im.param.ImMsgReceivedStatusUpdate; import com.wecloud.im.param.ImMsgReceivedStatusUpdate;
import com.wecloud.im.service.ImApplicationService; import com.wecloud.im.service.ImApplicationService;
...@@ -24,8 +19,6 @@ import com.wecloud.im.ws.service.WriteDataService; ...@@ -24,8 +19,6 @@ import com.wecloud.im.ws.service.WriteDataService;
import io.geekidea.springbootplus.framework.common.api.ApiCode; import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl; import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -63,35 +56,35 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -63,35 +56,35 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
private ImApplicationService imApplicationService; private ImApplicationService imApplicationService;
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class)
@Override // @Override
public boolean saveImInbox(ImInbox imInbox) throws Exception { // public boolean saveImInbox(ImInbox imInbox) throws Exception {
return super.save(imInbox); // return super.save(imInbox);
} // }
//
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class)
@Override // @Override
public boolean updateImInbox(ImInbox imInbox) throws Exception { // public boolean updateImInbox(ImInbox imInbox) throws Exception {
return super.updateById(imInbox); // return super.updateById(imInbox);
} // }
//
@Transactional(rollbackFor = Exception.class) // @Transactional(rollbackFor = Exception.class)
@Override // @Override
public boolean deleteImInbox(Long id) throws Exception { // public boolean deleteImInbox(Long id) throws Exception {
return super.removeById(id); // return super.removeById(id);
} // }
//
@Override // @Override
public ImInboxQueryVo getImInboxById(Long id) throws Exception { // public ImInboxQueryVo getImInboxById(Long id) throws Exception {
return imInboxMapper.getImInboxById(id); // return imInboxMapper.getImInboxById(id);
} // }
//
@Override // @Override
public Paging<ImInboxQueryVo> getImInboxPageList(ImInboxPageParam imInboxPageParam) throws Exception { // public Paging<ImInboxQueryVo> getImInboxPageList(ImInboxPageParam imInboxPageParam) throws Exception {
Page<ImInboxQueryVo> page = new PageInfo<>(imInboxPageParam, OrderItem.desc(getLambdaColumn(ImInbox::getCreateTime))); // Page<ImInboxQueryVo> page = new PageInfo<>(imInboxPageParam, OrderItem.desc(getLambdaColumn(ImInbox::getCreateTime)));
IPage<ImInboxQueryVo> iPage = imInboxMapper.getImInboxPageList(page, imInboxPageParam); // IPage<ImInboxQueryVo> iPage = imInboxMapper.getImInboxPageList(page, imInboxPageParam);
return new Paging<ImInboxQueryVo>(iPage); // return new Paging<ImInboxQueryVo>(iPage);
} // }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
...@@ -155,12 +148,12 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -155,12 +148,12 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
private void sendMsgStatus(ImClient curentClient, ImApplication application, HashMap<String, String> stringStringHashMap, List<Long> msgIds) { private void sendMsgStatus(ImClient curentClient, ImApplication application, HashMap<String, String> stringStringHashMap, List<Long> msgIds) {
// 遍历消息id集合 // 遍历消息id集合
for (Long MsgId : msgIds) { for (Long msgId : msgIds) {
// 查询该消息 // 查询该消息
ImMessage imMessageDb = imMessageService.getById(MsgId); ImMessage imMessageDb = imMessageService.getById(msgId);
// 根据消息id查询该会话所有成员 // 根据会话id查询该会话所有成员
List<ImConversationMembers> membersList = imConversationMembersService.list( List<ImConversationMembers> membersList = imConversationMembersService.list(
new QueryWrapper<ImConversationMembers>().lambda() new QueryWrapper<ImConversationMembers>().lambda()
.eq(ImConversationMembers::getFkConversationId, imMessageDb.getFkConversationId()) .eq(ImConversationMembers::getFkConversationId, imMessageDb.getFkConversationId())
...@@ -172,7 +165,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -172,7 +165,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
// 消息实体 // 消息实体
ImMessage imMessage = new ImMessage(); ImMessage imMessage = new ImMessage();
imMessage.setId(MsgId); imMessage.setId(msgId);
imMessage.setCreateTime(new Date()); imMessage.setCreateTime(new Date());
imMessage.setFkAppid(curentClient.getFkAppid()); imMessage.setFkAppid(curentClient.getFkAppid());
imMessage.setSender(curentClient.getId()); imMessage.setSender(curentClient.getId());
...@@ -191,7 +184,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> ...@@ -191,7 +184,7 @@ public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox>
imMessageOnlineSend.setConversationId(conversationMember.getFkConversationId()); imMessageOnlineSend.setConversationId(conversationMember.getFkConversationId());
// 查询接收方 // 查询接收方
ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, curentClient.getId()) .eq(ImClient::getFkAppid, curentClient.getFkAppid())
.eq(ImClient::getId, conversationMember.getFkClientId())); .eq(ImClient::getId, conversationMember.getFkClientId()));
if (imClientReceiver == null) { if (imClientReceiver == null) {
continue; continue;
......
package com.wecloud.im.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.mapper.ImIosApnsMapper;
import com.wecloud.im.param.ImIosApnsQueryVo;
import com.wecloud.im.service.ImIosApnsService;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* apns配置表 服务实现类
*
* @author wei
* @since 2021-09-18
*/
@Slf4j
@Service
@CacheConfig(cacheNames = "apns")
public class ImIosApnsServiceImpl extends BaseServiceImpl<ImIosApnsMapper, ImIosApns> implements ImIosApnsService {
@Autowired
private ImIosApnsMapper imIosApnsMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveImIosApns(ImIosApns imIosApns) throws Exception {
return super.save(imIosApns);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean updateImIosApns(ImIosApns imIosApns) throws Exception {
return super.updateById(imIosApns);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean deleteImIosApns(Long id) throws Exception {
return super.removeById(id);
}
@Override
public ImIosApnsQueryVo getImIosApnsById(Long id) throws Exception {
return imIosApnsMapper.getImIosApnsById(id);
}
@Override
@Cacheable(key = "#p0")
public ImIosApns getImIosApnsByAppId(Long appId) {
return this.getOne(new QueryWrapper<ImIosApns>().lambda().eq(
ImIosApns::getFkAppId, appId
));
}
// @Override
// public Paging<ImIosApnsQueryVo> getImIosApnsPageList(ImIosApnsPageParam imIosApnsPageParam) throws Exception {
// Page<ImIosApnsQueryVo> page;
// IPage<ImIosApnsQueryVo> iPage = imIosApnsMapper.getImIosApnsPageList(page, imIosApnsPageParam);
// return new Paging<ImIosApnsQueryVo>(iPage);
// }
}
...@@ -103,8 +103,7 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes ...@@ -103,8 +103,7 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes
return ApiResult.fail(); return ApiResult.fail();
} }
boolean isOK = this.updateById(imMessage); if (this.updateById(imMessage)) {
if (isOK) {
return ApiResult.ok(); return ApiResult.ok();
} else { } else {
return ApiResult.fail(); return ApiResult.fail();
...@@ -168,13 +167,16 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes ...@@ -168,13 +167,16 @@ public class ImMessageServiceImpl extends BaseServiceImpl<ImMessageMapper, ImMes
// 获取加入的所有会话 // 获取加入的所有会话
List<ImConversation> myImConversationList = imConversationService.getMyImConversationList(); List<ImConversation> myImConversationList = imConversationService.getMyImConversationList();
// 遍历会话列表, 查询每个会话列表的离线消息 // 遍历会话列表, 查询每个会话列表的离线消息
for (ImConversation imConversation : myImConversationList) { for (ImConversation imConversation : myImConversationList) {
//根据客户端id与会话id 查询离线消息 //根据客户端id与会话id 查询离线消息
List<OfflineMsgDto> offlineListByClientAndConversation = getOfflineListByClientAndConversation(client.getId(), imConversation.getId()); List<OfflineMsgDto> offlineListByClientAndConversation = this.getOfflineListByClientAndConversation(client.getId(), imConversation.getId());
// 房间消息为空则不添加
if (offlineListByClientAndConversation.isEmpty()) {
continue;
}
ImMessageOfflineListVo imMessageOfflineListVo = new ImMessageOfflineListVo(); ImMessageOfflineListVo imMessageOfflineListVo = new ImMessageOfflineListVo();
imMessageOfflineListVo.setMsgList(offlineListByClientAndConversation); imMessageOfflineListVo.setMsgList(offlineListByClientAndConversation);
imMessageOfflineListVo.setConversationId(imConversation.getId()); imMessageOfflineListVo.setConversationId(imConversation.getId());
......
...@@ -21,4 +21,6 @@ public class ImOnlineStatusVo extends BaseEntity { ...@@ -21,4 +21,6 @@ public class ImOnlineStatusVo extends BaseEntity {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ApiModelProperty("true:在线, false 不在线") @ApiModelProperty("true:在线, false 不在线")
private Boolean status; private Boolean status;
private String clientId;
} }
...@@ -42,4 +42,20 @@ public class OfflineMsgDto implements Serializable { ...@@ -42,4 +42,20 @@ public class OfflineMsgDto implements Serializable {
@ApiModelProperty("at他人,传入客户端id数组") @ApiModelProperty("at他人,传入客户端id数组")
private String at; private String at;
@ApiModelProperty("未读人数统计,全部人已读为0")
private Integer notReadCount;
@ApiModelProperty("未接收人数统计,全部人已接收为0")
private Integer notReceiverCount;
// @ApiModelProperty("读取时间")
// private Date readTime;
//
// @ApiModelProperty("接收时间")
// private Date receiverTime;
// @ApiModelProperty("0未接收; 1已接收")
// private Integer receiverMsgStatus;
} }
...@@ -68,7 +68,7 @@ public class UserCache { ...@@ -68,7 +68,7 @@ public class UserCache {
// 获取机器内网ip // 获取机器内网ip
static { static {
lAN_IP = getLocalIpAddress(); lAN_IP = getLocalIpAddress();
log.debug("lAN_IP:" + lAN_IP); log.info("lAN_IP:" + lAN_IP);
} }
/** /**
...@@ -124,7 +124,7 @@ public class UserCache { ...@@ -124,7 +124,7 @@ public class UserCache {
} }
} }
} catch (SocketException e) { } catch (SocketException e) {
log.debug("获取本机IP地址失败。" + e); log.info("获取本机IP地址失败。" + e);
} }
...@@ -138,7 +138,7 @@ public class UserCache { ...@@ -138,7 +138,7 @@ public class UserCache {
* @param id * @param id
*/ */
public void online(String id) { public void online(String id) {
log.debug("ws用户上线保存redis连接ip:" + lAN_IP, ",uid:" ); log.info("ws用户上线保存redis连接ip:" + lAN_IP, ",uid:");
// redisUtils.hset(KEY_BASE + id, PRIVATE_IP_KEY, lAN_IP); // redisUtils.hset(KEY_BASE + id, PRIVATE_IP_KEY, lAN_IP);
// redisUtils.hset(KEY_BASE + id, ONLINE_STATUS_KEY, String.valueOf(ONLINE)); // redisUtils.hset(KEY_BASE + id, ONLINE_STATUS_KEY, String.valueOf(ONLINE));
} }
...@@ -149,7 +149,7 @@ public class UserCache { ...@@ -149,7 +149,7 @@ public class UserCache {
* @param id * @param id
*/ */
public void offline(String id) { public void offline(String id) {
log.debug("ws用户离线删除redis key,uid:" + id); log.info("ws用户离线删除redis key,uid:" + id);
// redisUtils.kdel(KEY_BASE + id); // redisUtils.kdel(KEY_BASE + id);
} }
......
package com.wecloud.im.ws.model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class FileHelperOfflineModel implements Serializable {
private String messageId;
@ApiModelProperty(value = "消息内容")
private String content;
@ApiModelProperty(value = "消息类型 text, audio, image, file, video, location")
private String type;
@ApiModelProperty(value = "资源id")
private String sourceId;
@ApiModelProperty(value = "时长(s)")
private Integer duration;
@ApiModelProperty(value = "位置信息")
private String locationInfo;
@ApiModelProperty(value = "图片/视频尺寸相关信息")
private String measureInfo;
@ApiModelProperty(value = "消息回执id")
private String backId;
@ApiModelProperty(value = "文件名")
private String fileName;
@ApiModelProperty(value = "文件大小")
private String fileSize;
@ApiModelProperty(value = "消息渠道 singleChat, groupChat,systemNotice,syncMySend")
private String route;
@ApiModelProperty(value = "时间戳")
private Date timestamp;
}
...@@ -20,12 +20,12 @@ public class ResponseModel<T> implements Serializable { ...@@ -20,12 +20,12 @@ public class ResponseModel<T> implements Serializable {
public static final Integer ONLINE_EVENT_MSG = 3; public static final Integer ONLINE_EVENT_MSG = 3;
/** /**
* 下发在线消息 * 下发在线基本类型消息
*/ */
public static final Integer ONLINE_MSG = 2; public static final Integer ONLINE_MSG = 2;
/** /**
* 响应数据 * 响应数据类型
*/ */
public static final Integer RES = 1; public static final Integer RES = 1;
......
package com.wecloud.im.ws.model.request;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Description 推送model
* @Author hewei hwei1233@163.com
* @Date 2019-12-05
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PushModel implements Serializable {
/**
* 标题
*/
private String title;
/**
* 子标题
*/
private String subTitle;
}
package com.wecloud.im.ws.receive; package com.wecloud.im.ws.receive;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.json.JsonMapper;
import com.wecloud.im.ws.enums.WsRequestCmdEnum; import com.wecloud.im.ws.enums.WsRequestCmdEnum;
import com.wecloud.im.ws.model.request.ReceiveModel; import com.wecloud.im.ws.model.request.ReceiveModel;
import com.wecloud.im.ws.service.MangerChannelService;
import com.wecloud.im.ws.service.WriteDataService; import com.wecloud.im.ws.service.WriteDataService;
import com.wecloud.im.ws.strategy.AbstractReceiveStrategy; import com.wecloud.im.ws.strategy.AbstractReceiveStrategy;
import com.wecloud.im.ws.strategy.ReceiveStrategyContext; import com.wecloud.im.ws.strategy.ReceiveStrategyContext;
import io.geekidea.springbootplus.framework.common.exception.BusinessException;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -40,42 +39,26 @@ public class ReadWsData { ...@@ -40,42 +39,26 @@ public class ReadWsData {
* @param data * @param data
* @throws Exception * @throws Exception
*/ */
public void convertModel(String data, ChannelHandlerContext ctx) { public void convertModel(String data, ChannelHandlerContext ctx, String appKey, String clientId) throws Exception {
String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get();
String clientId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get();
log.info("appWS收到data:" + data + "\nappKey+clientId:" + appKey + ":" + clientId +
",channelId:" + ctx.channel().id().asShortText());
if (PING.equals(data)) { if (PING.equals(data)) {
log.debug("收到心跳:" + clientId); log.info("收到心跳clientId:" + clientId);
return; return;
} }
String language = ctx.channel().attr(MangerChannelService.LANGUAGE).get(); // 解析json
// ReceiveModel requestModel = JSON.parseObject(data, ReceiveModel.class);
JsonMapper jsonMapper = new JsonMapper(); JsonMapper jsonMapper = new JsonMapper();
ReceiveModel receiveModel = jsonMapper.readValue(data, ReceiveModel.class);
ReceiveModel receiveModel = null;
try {
receiveModel = jsonMapper.readValue(data, ReceiveModel.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
if (null == receiveModel || null == receiveModel.getCmd()) { if (null == receiveModel || null == receiveModel.getCmd()) {
return; throw new BusinessException("null == receiveModel || null == receiveModel.getCmd()");
} }
try { WsRequestCmdEnum wsRequestUriPathEnum = WsRequestCmdEnum.getByCode(receiveModel.getCmd());
WsRequestCmdEnum wsRequestUriPathEnum = WsRequestCmdEnum.getByCode(receiveModel.getCmd()); // 使用策略模式, 根据不同类型请求调用不同实现类
// 使用策略模式, 根据不同类型请求调用不同实现类 AbstractReceiveStrategy receiveStrategy = receiveStrategyContext.getStrategy(wsRequestUriPathEnum);
AbstractReceiveStrategy receiveStrategy = receiveStrategyContext.getStrategy(wsRequestUriPathEnum); receiveStrategy.process(receiveModel, ctx, data, appKey, clientId);
receiveStrategy.process(receiveModel, language, ctx, data);
} catch (Exception e) {
log.error("系统繁忙:" + data + ",appKey:" + appKey + ",clientId:" + clientId, e);
// writeDataService.nullDataSuccess(requestModel, ResultStatus.SYS_BUSY, userId, language);
}
} }
......
package com.wecloud.im.ws.sender;
import com.turo.pushy.apns.ApnsClient;
import com.turo.pushy.apns.ApnsClientBuilder;
import com.turo.pushy.apns.DeliveryPriority;
import com.turo.pushy.apns.PushNotificationResponse;
import com.turo.pushy.apns.PushType;
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
import com.turo.pushy.apns.util.TokenUtil;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* @Description 基于APNs最新HTTP/2接口实现iOS的高性能消息推送pushy(服务端篇)
* 通过Semaphore来进行流控,防止缓存过大,内存不足;
* 通过CountDownLatch来标记消息是否发送完成;
* 使用AtomicLong完成匿名内部类operationComplete方法中的计数;
* 使用Netty的Future对象进行消息推送结果的判断。
*/
public class IosPush {
// private static Map<String, String> APNS_CACHE = new HashMap<>();
private static final Logger logger = LoggerFactory.getLogger(IosPush.class);
/**
* Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。
*/
private static final Semaphore SEMAPHORE = new Semaphore(10000);
// private static ApnsClient apnsClient = null;
//
// public static ApnsClient getLocalAPNSConnect() {
// if (apnsClient == null) {
// try {
// EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
// apnsClient = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
// .setClientCredentials(new File("G:/java/push_file/xt_aillo_test_apns.p12"), "123456")
// .setConcurrentConnections(4).setEventLoopGroup(eventLoopGroup).build();
// } catch (Exception e) {
// logger.error("ios get pushy apns client failed!");
// e.printStackTrace();
// }
// }
// return apnsClient;
// }
// public static void push(String apnsCertificatePath, Boolean productFlag, final String deviceToken, String alertTitle, String alertBody,
// int badge, String topicBundleId,
// String sound) {
// }
/**
* @param inputStream 证书输入流
* @param productFlag 环境,测试=Boolean.FALSE,正式=Boolean.TRUE
* @param deviceToken 设备token
* @param alertTitle 标题
* @param alertBody 副标题
* @param contentAvailable Boolean.FALSE
* @param customProperty 自定义属性
* @param badge 角标数量
* @param priority DeliveryPriority.IMMEDIATE
* @param pushType PushType.ALERT
* @param topicBundleId undleId
* @param sound rtc= "call.caf"; 否则为default
*/
public static void push(String certificatePassword, InputStream inputStream, Boolean productFlag, final String deviceToken, String alertTitle, String alertBody,
boolean contentAvailable, Map<String, Object> customProperty,
int badge, DeliveryPriority priority, PushType pushType, String topicBundleId,
String sound) {
if (deviceToken == null || "".equals(deviceToken)) {
logger.error("deviceToken=null");
return;
}
long startTime = System.currentTimeMillis();
//每次完成一个任务(不一定需要线程走完),latch减1,直到所有的任务都完成,就可以执行下一阶段任务,可提高性能
final CountDownLatch latch = new CountDownLatch(1);
//线程安全的计数器
final AtomicLong successCnt = new AtomicLong(0);
ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
if (alertTitle != null) {
payloadBuilder.setAlertTitle(alertTitle);
}
if (alertBody != null) {
payloadBuilder.setAlertBody(alertBody);
}
payloadBuilder.setMutableContent(true);
//如果badge小于0,则不推送这个右上角的角标,主要用于消息盒子新增或者已读时,更新此状态
if (badge > 0) {
payloadBuilder.setBadgeNumber(badge);
}
if (!StringUtils.isEmpty(sound)) {
payloadBuilder.setSound(sound);
}
//将所有的附加参数全部放进去
if (customProperty != null) {
for (Map.Entry<String, Object> map : customProperty.entrySet()) {
payloadBuilder.addCustomProperty(map.getKey(), map.getValue());
}
}
payloadBuilder.setContentAvailable(contentAvailable);
String payload = payloadBuilder.buildWithDefaultMaximumLength();
final String token = TokenUtil.sanitizeTokenString(deviceToken);
SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, topicBundleId, payload, new Date(), priority, pushType);
try {
//从信号量中获取一个允许机会
SEMAPHORE.acquire();
} catch (Exception e) {
//线程太多了,没有多余的信号量可以获取了
logger.error("ios push get semaphore failed, deviceToken:{}", deviceToken);
logger.error("ios push get semaphore failed", e);
}
logger.debug("token={},payload={}", token, payload);
ApnsClient apnsClient = getAPNSConnect(inputStream, productFlag, certificatePassword);
final Future<PushNotificationResponse<SimpleApnsPushNotification>> future = apnsClient.sendNotification(pushNotification);
future.addListener((GenericFutureListener<Future<PushNotificationResponse>>) pushNotificationResponseFuture -> {
if (future.isSuccess()) {
final PushNotificationResponse<SimpleApnsPushNotification> response = future.getNow();
if (response.isAccepted()) {
logger.debug("success token{}", token);
successCnt.incrementAndGet();
} else {
Date invalidTime = response.getTokenInvalidationTimestamp();
logger.error("Notification rejected by the APNs gateway: " + response.getRejectionReason() + ",payload:" + payload +
"\n,deviceToken:" + deviceToken
, ",alertBody:" + alertBody + ",sanitizeTokenString:" + token);
if (invalidTime != null) {
logger.error("\t…and the token is invalid as of " + response.getTokenInvalidationTimestamp());
}
}
} else {
logger.error("send notification device token={} is failed {} ", token, future.cause().getMessage());
}
latch.countDown();
//释放允许,将占有的信号量归还
SEMAPHORE.release();
});
try {
latch.await(20, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.error("ios push latch await failed!", e);
}
long endPushTime = System.currentTimeMillis();
logger.debug("pushMessage success. [成功{}个,耗时{}ms]", successCnt.get(), endPushTime - startTime);
}
/**
* @param apnsCertificatePath 证书
* @param productFlag 环境
* @param deviceToken 设备token
* @param alertTitle 标题
* @param alertBody 副标题
* @param contentAvailable Boolean.FALSE
* @param customProperty 自定义属性
* @param badge 角标数量
* @param priority DeliveryPriority.IMMEDIATE
* @param pushType PushType.ALERT
* @param topicBundleId undleId
* @param sound rtc= "call.caf"; 否则为default
*/
public static void push(String apnsCertificatePath, Boolean productFlag, final String deviceToken, String alertTitle, String alertBody,
boolean contentAvailable, Map<String, Object> customProperty,
int badge, DeliveryPriority priority, PushType pushType, String topicBundleId,
String sound) {
String certificatePassword = "123456";
if (deviceToken == null || "".equals(deviceToken)) {
logger.error("deviceToken=null");
return;
}
long startTime = System.currentTimeMillis();
//每次完成一个任务(不一定需要线程走完),latch减1,直到所有的任务都完成,就可以执行下一阶段任务,可提高性能
final CountDownLatch latch = new CountDownLatch(1);
//线程安全的计数器
final AtomicLong successCnt = new AtomicLong(0);
ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
if (alertTitle != null) {
payloadBuilder.setAlertTitle(alertTitle);
}
if (alertBody != null) {
payloadBuilder.setAlertBody(alertBody);
}
payloadBuilder.setMutableContent(true);
//如果badge小于0,则不推送这个右上角的角标,主要用于消息盒子新增或者已读时,更新此状态
if (badge > 0) {
payloadBuilder.setBadgeNumber(badge);
}
if (!StringUtils.isEmpty(sound)) {
payloadBuilder.setSound(sound);
}
//将所有的附加参数全部放进去
if (customProperty != null) {
for (Map.Entry<String, Object> map : customProperty.entrySet()) {
payloadBuilder.addCustomProperty(map.getKey(), map.getValue());
}
}
payloadBuilder.setContentAvailable(contentAvailable);
String payload = payloadBuilder.buildWithDefaultMaximumLength();
final String token = TokenUtil.sanitizeTokenString(deviceToken);
SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, topicBundleId, payload, new Date(), priority, pushType);
try {
//从信号量中获取一个允许机会
SEMAPHORE.acquire();
} catch (Exception e) {
//线程太多了,没有多余的信号量可以获取了
logger.error("ios push get semaphore failed, deviceToken:{}", deviceToken);
logger.error("ios push get semaphore failed", e);
}
logger.debug("token={},payload={}", token, payload);
ApnsClient apnsClient = getAPNSConnect(apnsCertificatePath, productFlag, certificatePassword);
final Future<PushNotificationResponse<SimpleApnsPushNotification>> future = apnsClient.sendNotification(pushNotification);
future.addListener((GenericFutureListener<Future<PushNotificationResponse>>) pushNotificationResponseFuture -> {
if (future.isSuccess()) {
final PushNotificationResponse<SimpleApnsPushNotification> response = future.getNow();
if (response.isAccepted()) {
logger.debug("success token{}", token);
successCnt.incrementAndGet();
} else {
Date invalidTime = response.getTokenInvalidationTimestamp();
logger.error("Notification rejected by the APNs gateway: " + response.getRejectionReason() + ",payload:" + payload +
"\n,deviceToken:" + deviceToken
, ",alertBody:" + alertBody + ",sanitizeTokenString:" + token);
if (invalidTime != null) {
logger.error("\t…and the token is invalid as of " + response.getTokenInvalidationTimestamp());
}
}
} else {
logger.error("send notification device token={} is failed {} ", token, future.cause().getMessage());
}
latch.countDown();
//释放允许,将占有的信号量归还
SEMAPHORE.release();
});
try {
latch.await(20, TimeUnit.SECONDS);
} catch (InterruptedException e) {
logger.error("ios push latch await failed!", e);
}
long endPushTime = System.currentTimeMillis();
logger.debug("pushMessage success. [成功{}个,耗时{}ms]", successCnt.get(), endPushTime - startTime);
}
// public static void main(String[] args) {
// Map<String, Object> customProperty = new HashMap<String, Object>(5);
// //alert
// push(getLocalAPNSConnect(), "edb79e259a9523894da68328bca050c4e22f8188e45bcd6f15a5498cf1f0ab12", "123", "789",
// false, customProperty, 0, DeliveryPriority.IMMEDIATE, PushType.ALERT, "com.xteng.ailloTest", null);
// // 静默
// push(getLocalAPNSConnect(), "edb79e259a9523894da68328bca050c4e22f8188e45bcd6f15a5498cf1f0ab12", null, null,
// true, customProperty, 0, DeliveryPriority.CONSERVE_POWER, PushType.BACKGROUND, "com.xteng.ailloTest", null);
// }
/**
* 获取apns推送连接
*
* @param inputStream 证书文件
* @param productFlag 环境: true=正式, false测试
* @param certificatePassword ios证书通用密码
* @return
*/
public static ApnsClient getAPNSConnect(InputStream inputStream, Boolean productFlag, String certificatePassword) {
ApnsClient apnsXTClient = null;
try {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
String environmentHost = productFlag ? ApnsClientBuilder.PRODUCTION_APNS_HOST : ApnsClientBuilder.DEVELOPMENT_APNS_HOST;
apnsXTClient = new ApnsClientBuilder().setApnsServer(environmentHost)
.setClientCredentials(inputStream, certificatePassword)
.setConcurrentConnections(4).setEventLoopGroup(eventLoopGroup).build();
} catch (Exception e) {
logger.error("ios get push apns client failed!", e);
}
return apnsXTClient;
}
/**
* 获取apns推送连接
*
* @param apnsCertificatePath 证书文件
* @param productFlag 环境: true=正式, false测试
* @param certificatePassword ios证书通用密码
* @return
*/
public static ApnsClient getAPNSConnect(String apnsCertificatePath, Boolean productFlag, String certificatePassword) {
ApnsClient apnsXTClient = null;
try {
EventLoopGroup eventLoopGroup = new NioEventLoopGroup(4);
String environmentHost = productFlag ? ApnsClientBuilder.PRODUCTION_APNS_HOST : ApnsClientBuilder.DEVELOPMENT_APNS_HOST;
InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(apnsCertificatePath);
apnsXTClient = new ApnsClientBuilder().setApnsServer(environmentHost)
.setClientCredentials(resourceAsStream, certificatePassword)
.setConcurrentConnections(4).setEventLoopGroup(eventLoopGroup).build();
} catch (Exception e) {
logger.error("ios get push apns client failed!", e);
}
return apnsXTClient;
}
public static InputStream getApnsCertificate(String apnsCertificatePath) {
return ClassLoader.getSystemClassLoader().getResourceAsStream(apnsCertificatePath);
}
}
package com.wecloud.im.ws.sender; package com.wecloud.im.ws.sender;
import cn.hutool.core.codec.Base64;
import com.turo.pushy.apns.DeliveryPriority;
import com.turo.pushy.apns.PushType;
import com.wecloud.im.entity.ImApplication; import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient; import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImMessage; import com.wecloud.im.entity.ImIosApns;
import com.wecloud.im.push.PushUtils; import com.wecloud.im.push.PushUtils;
import com.wecloud.im.service.ImIosApnsService;
import com.wecloud.im.ws.model.request.PushModel;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/** /**
* 异步系统推送 * 异步系统推送
...@@ -23,32 +32,47 @@ import java.net.URL; ...@@ -23,32 +32,47 @@ import java.net.URL;
@Slf4j @Slf4j
public class PushTask { public class PushTask {
@Autowired
private ImIosApnsService imIosApnsService;
/** /**
* 谷歌推送地址 * 谷歌推送地址
*/ */
private static final String API_URL_FCM = "https://fcm.googleapis.com/fcm/send"; private static final String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
//您收到一条新消息 /**
* 您收到一条新消息
*/
private static final String PUSH_TITLE = "You have received a new message"; private static final String PUSH_TITLE = "You have received a new message";
//点击查看 /**
* 点击查看
*/
private static final String PUSH_BODY = "Click to view"; private static final String PUSH_BODY = "Click to view";
/** /**
* 异步系统推送 * 异步系统推送
* *
* @param imClientReceiver * @param imClientReceiver
* @param imClientSender
* @param imMessage
*/ */
@Async @Async
public void push(ImClient imClientReceiver, ImClient imClientSender, ImMessage imMessage, ImApplication imApplication) { public void push(HashMap<String, String> pushMap, ImClient imClientReceiver, ImApplication imApplication) {
log.debug("push " + imClientReceiver.getClientId()); log.info("push:" + imClientReceiver.getClientId());
PushModel pushModel = new PushModel();
if (pushMap.isEmpty()) {
pushModel.setTitle(PUSH_TITLE);
pushModel.setSubTitle(PUSH_BODY);
} else {
pushModel.setTitle(pushMap.get("title"));
pushModel.setSubTitle(pushMap.get("subTitle"));
}
// 校验参数 // 校验参数
if (imClientReceiver.getValid() == null || imClientReceiver.getDeviceToken() == null || imClientReceiver.getDeviceType() == null) { if (imClientReceiver.getValid() == null || imClientReceiver.getDeviceToken() == null || imClientReceiver.getDeviceType() == null) {
log.debug("push参数错误"); log.info("push参数错误");
return; return;
} }
// 设备不想收到推送提醒, 1想, 0不想 // 设备不想收到推送提醒, 1想, 0不想
...@@ -58,27 +82,25 @@ public class PushTask { ...@@ -58,27 +82,25 @@ public class PushTask {
// 设备类型1:ios; 2:android // 设备类型1:ios; 2:android
if (imClientReceiver.getDeviceType() == 1) { if (imClientReceiver.getDeviceType() == 1) {
ios(imClientReceiver, imApplication); ios(pushModel, imClientReceiver, imApplication);
} else { } else {
android(imClientReceiver, imApplication, imMessage); android(pushModel, imClientReceiver, imApplication);
} }
} }
private void android(ImClient imClientReceiver, ImApplication imApplication, ImMessage imMessage) { private void android(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
// 安卓推送通道,友盟:1;firebase:2; 信鸽3 // 安卓推送通道,友盟:1;firebase:2; 信鸽3
if (imApplication.getAndroidPushChannel() == 1) { if (imApplication.getAndroidPushChannel() == 1) {
log.debug("友盟"); log.info("友盟");
// 友盟推送 // 友盟推送
PushUtils pushUtils = new PushUtils(imApplication.getUmengKey(), imApplication.getUmengSecret()); PushUtils pushUtils = new PushUtils(imApplication.getUmengKey(), imApplication.getUmengSecret());
// 安卓 单推 // 安卓 单推
String deviceTokenIOS = imClientReceiver.getDeviceToken(); String deviceTokenIOS = imClientReceiver.getDeviceToken();
String titleIOS = PUSH_TITLE;
String subtitle = "";
try { try {
pushUtils.sendIOSUnicast(deviceTokenIOS, titleIOS, subtitle, PUSH_BODY); pushUtils.sendIOSUnicast(deviceTokenIOS, pushModel.getTitle(), pushModel.getSubTitle(), PUSH_BODY);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
...@@ -86,63 +108,24 @@ public class PushTask { ...@@ -86,63 +108,24 @@ public class PushTask {
} else if (imApplication.getAndroidPushChannel() == 2) { } else if (imApplication.getAndroidPushChannel() == 2) {
//firebase:2 //firebase:2
log.debug("firebase"); log.info("android_firebase");
String jsonStr = null; firebase(pushModel, imClientReceiver, imApplication);
try {
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setConnectTimeout(10000);
conn.setRequestMethod("POST");
//不设置默认发送文本格式。设置就是json
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + imApplication.getFirebaseSecret());
JSONObject json = new JSONObject();
//推送到哪台客户端机器
json.put("to", imClientReceiver.getDeviceToken());
JSONObject info = new JSONObject();
info.put("title", PUSH_TITLE);
info.put("body", PUSH_BODY);
//数据消息data 通知消息 notification
json.put("notification", info);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
jsonStr = json.toString();
wr.write(jsonStr);
wr.flush();
InputStream inputStream = conn.getInputStream();
InputStreamReader in = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(in);
String line = reader.readLine();
log.debug(line);
wr.close();
reader.close();
} catch (Exception e) {
log.error("FCM push failure: " + jsonStr, e);
}
} else if (imApplication.getAndroidPushChannel() == 3) { } else if (imApplication.getAndroidPushChannel() == 3) {
// 信鸽3 // 信鸽3
log.debug("信鸽3"); log.info("信鸽3");
} else { } else {
log.debug("没有找到推送类型"); log.info("没有找到推送类型");
return;
} }
} }
private void ios(ImClient imClientReceiver, ImApplication imApplication) { private void ios(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
// ios推送通道,友盟:1;firebase:2; apns原生:3 // ios推送通道,友盟:1;firebase:2; apns原生:3
if (imApplication.getIosPushChannel() == 1) { if (imApplication.getIosPushChannel() == 1) {
log.debug("友盟"); log.info("友盟");
// 友盟推送 // 友盟推送
PushUtils pushUtils = new PushUtils(imApplication.getUmengKey(), imApplication.getUmengSecret()); PushUtils pushUtils = new PushUtils(imApplication.getUmengKey(), imApplication.getUmengSecret());
...@@ -150,9 +133,9 @@ public class PushTask { ...@@ -150,9 +133,9 @@ public class PushTask {
// 安卓单推 // 安卓单推
String deviceToken = imClientReceiver.getDeviceToken(); String deviceToken = imClientReceiver.getDeviceToken();
String unicastText = "Android unicast text"; String unicastText = "Android unicast text";
String unicastTicker = PUSH_BODY; String unicastTicker = pushModel.getSubTitle();
try { try {
pushUtils.sendAndroidUnicast(deviceToken, unicastText, unicastTicker, PUSH_TITLE); pushUtils.sendAndroidUnicast(deviceToken, unicastText, unicastTicker, pushModel.getTitle());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
...@@ -160,57 +143,92 @@ public class PushTask { ...@@ -160,57 +143,92 @@ public class PushTask {
} else if (imApplication.getIosPushChannel() == 2) { } else if (imApplication.getIosPushChannel() == 2) {
//firebase:2 //firebase:2
log.debug("firebase"); log.info("firebase");
String jsonStr = null; firebase(pushModel, imClientReceiver, imApplication);
try {
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setConnectTimeout(10000);
conn.setRequestMethod("POST");
//不设置默认发送文本格式。设置就是json
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + imApplication.getFirebaseSecret());
JSONObject json = new JSONObject();
//推送到哪台客户端机器
json.put("to", imClientReceiver.getDeviceToken());
JSONObject info = new JSONObject();
info.put("title", PUSH_TITLE);
info.put("body", PUSH_BODY);
//数据消息data 通知消息 notification
json.put("notification", info);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
jsonStr = json.toString();
wr.write(jsonStr);
wr.flush();
InputStream inputStream = conn.getInputStream();
InputStreamReader in = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(in);
String line = reader.readLine();
log.debug(line);
wr.close();
reader.close();
} catch (Exception e) {
log.error("FCM push failure: " + jsonStr, e);
}
} else if (imApplication.getIosPushChannel() == 3) { } else if (imApplication.getIosPushChannel() == 3) {
// apns原生:3 // apns原生:3
log.debug("apns原生");
log.info("apns原生");
apnsPush(pushModel, imClientReceiver, imApplication);
} else { } else {
log.debug("没有找到推送类型"); log.info("没有找到推送类型");
return; }
}
public void firebase(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
String jsonStr = null;
try {
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setConnectTimeout(10000);
conn.setRequestMethod("POST");
//不设置默认发送文本格式。设置就是json
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Authorization", "key=" + imApplication.getFirebaseSecret());
JSONObject json = new JSONObject();
//推送到哪台客户端机器
json.put("to", imClientReceiver.getDeviceToken());
JSONObject info = new JSONObject();
info.put("title", pushModel.getTitle());
info.put("body", pushModel.getSubTitle());
//数据消息data 通知消息 notification
json.put("notification", info);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
jsonStr = json.toString();
wr.write(jsonStr);
wr.flush();
InputStream inputStream = conn.getInputStream();
InputStreamReader in = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(in);
String line = reader.readLine();
log.info(line);
wr.close();
reader.close();
} catch (Exception e) {
log.error("FCM push failure: " + jsonStr, e);
}
}
private void apnsPush(PushModel pushModel, ImClient imClientReceiver, ImApplication imApplication) {
// 查询apns证书
ImIosApns apns = imIosApnsService.getImIosApnsByAppId(imApplication.getId());
Map<String, Object> customProperty = new HashMap<String, Object>(1);
String deviceToken = imClientReceiver.getDeviceToken();
String alertTitle = pushModel.getTitle();
String alertBody = pushModel.getSubTitle();
int badge = 1;
String topicBundleId = apns.getBundleId();
String certificatePassword = apns.getPwd();
boolean contentAvailable = false;
String sound = "default";
// 解码
byte[] decode = Base64.decode(apns.getApnsFileValue());
InputStream inputStream2 = new ByteArrayInputStream(decode);
// productFlag 环境,测试=Boolean.FALSE,正式=Boolean.TRUE
Boolean productFlag = Boolean.FALSE;
// 正式1,测试0
if (apns.getEnv() == 1) {
productFlag = Boolean.TRUE;
} }
IosPush.push(certificatePassword, inputStream2, productFlag, deviceToken, alertTitle, alertBody,
contentAvailable, customProperty, badge
, DeliveryPriority.IMMEDIATE, PushType.ALERT, topicBundleId,
sound);
} }
} }
...@@ -24,25 +24,25 @@ public interface MangerChannelService { ...@@ -24,25 +24,25 @@ public interface MangerChannelService {
/** /**
* CLIENT_ID,是客户端的字符串id * CLIENT_ID,是客户端的字符串id
*/ */
AttributeKey<String> CLIENT_ID = AttributeKey.valueOf("CLIENTID"); AttributeKey<String> CLIENT_ID = AttributeKey.valueOf("ci");
/** /**
* 是app的字符串id * 是app的字符串id
*/ */
AttributeKey<String> APP_KEY = AttributeKey.valueOf("APPKEY"); AttributeKey<String> APP_KEY = AttributeKey.valueOf("ak");
/** /**
* LANGUAGE * LANGUAGE
*/ */
AttributeKey<String> LANGUAGE = AttributeKey.valueOf("language"); AttributeKey<String> LANGUAGE = AttributeKey.valueOf("lan");
/** /**
* APP_VERSION * APP_VERSION
*/ */
AttributeKey<String> APP_VERSION = AttributeKey.valueOf("appVersion"); // AttributeKey<String> APP_VERSION = AttributeKey.valueOf("appVersion");
AttributeKey<String> TOKEN = AttributeKey.valueOf("TOKEN"); // AttributeKey<String> TOKEN = AttributeKey.valueOf("TOKEN");
AttributeKey<String> DEVICEID = AttributeKey.valueOf("DEVICEID"); // AttributeKey<String> DEVICEID = AttributeKey.valueOf("DEVICEID");
AttributeKey<String> PLATFORM = AttributeKey.valueOf("PLATFORM"); // AttributeKey<String> PLATFORM = AttributeKey.valueOf("PLATFORM");
/** /**
* 根据userID获取channel * 根据userID获取channel
...@@ -65,12 +65,12 @@ public interface MangerChannelService { ...@@ -65,12 +65,12 @@ public interface MangerChannelService {
void remove(ChannelHandlerContext channelHandlerContext); void remove(ChannelHandlerContext channelHandlerContext);
/** /**
* 根据channel返回userId * 根据channel返回客户端key和id
* *
* @param channelHandlerContext * @param channelHandlerContext
* @return * @return
*/ */
String getUserIdByChannel(ChannelHandlerContext channelHandlerContext); String getInfoByChannel(ChannelHandlerContext channelHandlerContext);
/** /**
* 下发数据 * 下发数据
......
...@@ -59,6 +59,13 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -59,6 +59,13 @@ public class MangerChannelServiceImpl implements MangerChannelService {
@Override @Override
public void put(String appKey, String clientId, NioSocketChannel channel) { public void put(String appKey, String clientId, NioSocketChannel channel) {
// 断掉旧链接
NioSocketChannel nioSocketChannel = get(appKey, clientId);
if (null != nioSocketChannel) {
log.info("put新连接关掉旧链接:" + appKey + "," + clientId + ",\nchannelId:" + nioSocketChannel.id().asLongText());
nioSocketChannel.close();
}
// AppHashValueModel appHashValueModel = new AppHashValueModel(); // AppHashValueModel appHashValueModel = new AppHashValueModel();
// appHashValueModel.setOnlineStatus(UserCache.ONLINE); // appHashValueModel.setOnlineStatus(UserCache.ONLINE);
// userCache.online(userId); // userCache.online(userId);
...@@ -78,20 +85,18 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -78,20 +85,18 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// !channel.isWritable() 通道是否可写数据 // !channel.isWritable() 通道是否可写数据
*/ */
if (channel != null && !channel.isActive() && !channel.isOpen()) { if (channel != null && !channel.isActive() && !channel.isOpen()) {
String userId = String.valueOf(this.getUserIdByChannel(channelHandlerContext)); String userId = String.valueOf(this.getInfoByChannel(channelHandlerContext));
userCache.offline(userId); userCache.offline(userId);
log.info("不活跃remove,uid:" + userId);
log.debug("不活跃remove,uid:" + userId);
MangerChannelService.CHANNEL_MAP.remove(userId); MangerChannelService.CHANNEL_MAP.remove(userId);
channelHandlerContext.channel().close(); channelHandlerContext.channel().close();
} }
} }
@Override @Override
public String getUserIdByChannel(ChannelHandlerContext channelHandlerContext) { public String getInfoByChannel(ChannelHandlerContext channelHandlerContext) {
return channelHandlerContext.channel().attr(MangerChannelService.CLIENT_ID).get(); return "APP_KEY:" + channelHandlerContext.channel().attr(MangerChannelService.APP_KEY).get()
// return 1L; + ",CLIENT_ID:" + channelHandlerContext.channel().attr(MangerChannelService.CLIENT_ID).get();
} }
// @Override // @Override
...@@ -118,13 +123,13 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -118,13 +123,13 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// NioSocketChannel nioSocketChannel = get(String.valueOf(userId)); // NioSocketChannel nioSocketChannel = get(String.valueOf(userId));
// if (null == nioSocketChannel) { // if (null == nioSocketChannel) {
// userCache.offline(String.valueOf(userId)); // userCache.offline(String.valueOf(userId));
// log.debug("rpc-writeData连接为空:" + userId + "," + msg); // log.info("rpc-writeData连接为空:" + userId + "," + msg);
// return false; // return false;
// } // }
// //
// // 判断连接是否断开 // // 判断连接是否断开
// if (nioSocketChannel.isShutdown()) { // if (nioSocketChannel.isShutdown()) {
// log.debug("rpc-writeData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); // log.info("rpc-writeData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
// return false; // return false;
// } // }
// //
...@@ -163,19 +168,19 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -163,19 +168,19 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// //
// NioSocketChannel nioSocketChannel = get(String.valueOf(userId)); // NioSocketChannel nioSocketChannel = get(String.valueOf(userId));
// if (null == nioSocketChannel) { // if (null == nioSocketChannel) {
// log.debug("rpc-kickWriteData连接为空:" + userId + "," + msg); // log.info("rpc-kickWriteData连接为空:" + userId + "," + msg);
// return false; // return false;
// } // }
// //
// // 判断连接是否断开 // // 判断连接是否断开
// if (nioSocketChannel.isShutdown()) { // if (nioSocketChannel.isShutdown()) {
// log.debug("rpc-kickWriteData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); // log.info("rpc-kickWriteData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
// nioSocketChannel.close(); // nioSocketChannel.close();
// return false; // return false;
// } // }
// //
// if (log.isDebugEnabled()) { // if (log.isDebugEnabled()) {
// log.debug("rpc-kickWriteData:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); // log.info("rpc-kickWriteData:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
// } // }
// //
// ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg)); // ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg));
...@@ -183,7 +188,7 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -183,7 +188,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// //执行后回调的方法 // //执行后回调的方法
// (ChannelFutureListener) channelFuture1 -> { // (ChannelFutureListener) channelFuture1 -> {
// if (log.isDebugEnabled()) { // if (log.isDebugEnabled()) {
// log.debug("rpc-netty踢人线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess() // log.info("rpc-netty踢人线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess()
// + ";\nkickWriteData:" + userId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText()); // + ";\nkickWriteData:" + userId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText());
// } // }
// }); // });
...@@ -208,7 +213,7 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -208,7 +213,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// Future<Boolean> future = THREAD_POOL_RPC_WRITE_EXECUTOR.submit(() -> { // Future<Boolean> future = THREAD_POOL_RPC_WRITE_EXECUTOR.submit(() -> {
// NioSocketChannel nioSocketChannel = get(String.valueOf(userId)); // NioSocketChannel nioSocketChannel = get(String.valueOf(userId));
// if (null == nioSocketChannel) { // if (null == nioSocketChannel) {
// log.debug("rpc-closeOldChannel连接为空:" + userId); // log.info("rpc-closeOldChannel连接为空:" + userId);
// return false; // return false;
// } // }
// // 关闭 // // 关闭
...@@ -232,18 +237,18 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -232,18 +237,18 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// NioSocketChannel nioSocketChannel = get(String.valueOf(userId)); // NioSocketChannel nioSocketChannel = get(String.valueOf(userId));
// if (null == nioSocketChannel) { // if (null == nioSocketChannel) {
// userCache.offline(String.valueOf(userId)); // userCache.offline(String.valueOf(userId));
// log.debug("writeData连接为空:" + userId + "," + msg); // log.info("writeData连接为空:" + userId + "," + msg);
// return false; // return false;
// } // }
// //
// // 判断连接是否断开 // // 判断连接是否断开
// if (nioSocketChannel.isShutdown()) { // if (nioSocketChannel.isShutdown()) {
// log.debug("writeData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); // log.info("writeData连接断开:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
// return false; // return false;
// } // }
// //
// if (log.isDebugEnabled()) { // if (log.isDebugEnabled()) {
// log.debug("writeData:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); // log.info("writeData:" + userId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
// } // }
// //
// ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg)); // ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg));
...@@ -251,7 +256,7 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -251,7 +256,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
// //执行后回调的方法 // //执行后回调的方法
// (ChannelFutureListener) channelFuture1 -> { // (ChannelFutureListener) channelFuture1 -> {
// if (log.isDebugEnabled()) { // if (log.isDebugEnabled()) {
// log.debug("netty线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess() // log.info("netty线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess()
// + ";\nwriteData:" + userId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText()); // + ";\nwriteData:" + userId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText());
// } // }
// }); // });
...@@ -284,14 +289,14 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -284,14 +289,14 @@ public class MangerChannelServiceImpl implements MangerChannelService {
if (null == nioSocketChannel) { if (null == nioSocketChannel) {
// userCache.offline(toAppKey + toClientId); // userCache.offline(toAppKey + toClientId);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("writeData 不存在 连接为空:" + toAppKey + toClientId); log.info("writeData 不存在 连接为空:" + toAppKey + toClientId);
} }
return false; return false;
} }
// 判断连接是否断开 // 判断连接是否断开
if (nioSocketChannel.isShutdown()) { if (nioSocketChannel.isShutdown()) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("writeData连接断开:" + toAppKey + toClientId + "channelId:" + nioSocketChannel.id().asLongText()); log.info("writeData连接断开:" + toAppKey + toClientId + "channelId:" + nioSocketChannel.id().asLongText());
} }
return false; return false;
} }
...@@ -306,20 +311,20 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -306,20 +311,20 @@ public class MangerChannelServiceImpl implements MangerChannelService {
if (null == nioSocketChannel) { if (null == nioSocketChannel) {
// userCache.offline(toAppKey + toClientId); // userCache.offline(toAppKey + toClientId);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("writeData连接为空:" + toAppKey + toClientId + "," + msg); log.info("writeData连接为空:" + toAppKey + toClientId + "," + msg);
} }
return false; return false;
} }
// 判断连接是否断开 // 判断连接是否断开
if (nioSocketChannel.isShutdown()) { if (nioSocketChannel.isShutdown()) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("writeData连接断开:" + toAppKey + toClientId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); log.info("writeData连接断开:" + toAppKey + toClientId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
} }
return false; return false;
} }
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("writeData:" + toAppKey + "," + toClientId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText()); log.info("writeData:" + toAppKey + "," + toClientId + "," + msg + ",\nchannelId:" + nioSocketChannel.id().asLongText());
} }
ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg)); ChannelFuture channelFuture = nioSocketChannel.writeAndFlush(new TextWebSocketFrame(msg));
...@@ -327,7 +332,7 @@ public class MangerChannelServiceImpl implements MangerChannelService { ...@@ -327,7 +332,7 @@ public class MangerChannelServiceImpl implements MangerChannelService {
//执行后回调的方法 //执行后回调的方法
(ChannelFutureListener) channelFuture1 -> { (ChannelFutureListener) channelFuture1 -> {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("netty线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess() log.info("netty线程异步执行结果:" + channelFuture1.isDone() + ",业务执行结果:" + channelFuture1.isSuccess()
+ ";\nwriteData:" + toAppKey + toClientId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText()); + ";\nwriteData:" + toAppKey + toClientId + "," + msg + ",channelId:" + nioSocketChannel.id().asLongText());
} }
}); });
......
...@@ -36,7 +36,7 @@ public class WriteDataServiceImpl implements WriteDataService { ...@@ -36,7 +36,7 @@ public class WriteDataServiceImpl implements WriteDataService {
* io密集型任务配置尽可能多的线程数量 * io密集型任务配置尽可能多的线程数量
*/ */
private final static ExecutorService WRITE_TASK_THREAD_POOL_EXECUTOR = private final static ExecutorService WRITE_TASK_THREAD_POOL_EXECUTOR =
new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 10, WsConstants.CPU_PROCESSORS * 500, new ThreadPoolExecutor(WsConstants.CPU_PROCESSORS * 2, WsConstants.CPU_PROCESSORS * 3,
1L, TimeUnit.MILLISECONDS, 1L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(), WRITE_NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy()); new LinkedBlockingQueue<Runnable>(), WRITE_NAMED_THREAD_FACTORY, new ThreadPoolExecutor.CallerRunsPolicy());
......
package com.wecloud.im.ws.strategy; package com.wecloud.im.ws.strategy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.wecloud.im.ws.model.request.ReceiveModel; import com.wecloud.im.ws.model.request.ReceiveModel;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
...@@ -16,8 +17,7 @@ public abstract class AbstractReceiveStrategy { ...@@ -16,8 +17,7 @@ public abstract class AbstractReceiveStrategy {
* 处理业务流程 * 处理业务流程
* *
* @param requestModel * @param requestModel
* @param language
* @throws Exception * @throws Exception
*/ */
abstract public void process(ReceiveModel requestModel, String language, ChannelHandlerContext ctx, String data); abstract public void process(ReceiveModel requestModel, ChannelHandlerContext ctx, String data, String appKey, String clientId) throws JsonProcessingException;
} }
...@@ -20,7 +20,6 @@ import com.wecloud.im.ws.enums.WsRequestCmdEnum; ...@@ -20,7 +20,6 @@ import com.wecloud.im.ws.enums.WsRequestCmdEnum;
import com.wecloud.im.ws.model.ResponseModel; import com.wecloud.im.ws.model.ResponseModel;
import com.wecloud.im.ws.model.request.ReceiveModel; import com.wecloud.im.ws.model.request.ReceiveModel;
import com.wecloud.im.ws.sender.PushTask; import com.wecloud.im.ws.sender.PushTask;
import com.wecloud.im.ws.service.MangerChannelService;
import com.wecloud.im.ws.service.WriteDataService; import com.wecloud.im.ws.service.WriteDataService;
import com.wecloud.im.ws.strategy.AbstractReceiveStrategy; import com.wecloud.im.ws.strategy.AbstractReceiveStrategy;
import io.geekidea.springbootplus.framework.common.api.ApiCode; import io.geekidea.springbootplus.framework.common.api.ApiCode;
...@@ -37,13 +36,19 @@ import java.util.HashMap; ...@@ -37,13 +36,19 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
/** /**
* @Description 处理app单聊消息 * @Description 处理app数据消息
*/ */
@ReceiveTypeAnnotation(type = WsRequestCmdEnum.DATA) @ReceiveTypeAnnotation(type = WsRequestCmdEnum.DATA)
@Service @Service
@Slf4j @Slf4j
public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy { public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy {
private static final String TO_CONVERSATION_KEY = "toConversation";
private static final String PUSH_KEY = "push";
private static final String MSG_ID = "msgId";
private static final JsonMapper JSON_MAPPER = new JsonMapper();
@Autowired @Autowired
private ImClientBlacklistService imClientBlacklistService; private ImClientBlacklistService imClientBlacklistService;
...@@ -69,110 +74,76 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -69,110 +74,76 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy {
private PushTask pushTask; private PushTask pushTask;
@Override @Override
public void process(ReceiveModel receiveModel, String language, ChannelHandlerContext ctx, String data) { public void process(ReceiveModel receiveModel, ChannelHandlerContext ctx, String data, String appKey, String clientId) throws JsonProcessingException {
String appKey = ctx.channel().attr(MangerChannelService.APP_KEY).get(); // String language = ctx.channel().attr(MangerChannelService.LANGUAGE).get();
String clientUniId = ctx.channel().attr(MangerChannelService.CLIENT_ID).get();
// 查询imApplication // 查询imApplication
ImApplication imApplication = imApplicationService.getOne(new QueryWrapper<ImApplication>().lambda() ImApplication imApplication = imApplicationService.getOneByAppKey(appKey);
.eq(ImApplication::getAppKey, appKey));
if (imApplication == null) { if (imApplication == null) {
log.error("imApplication为空"); log.info("imApplication为空");
return; return;
} }
// 查询发送者client // 查询发送者client
ImClient imClientSender = imClientService.getOne(new QueryWrapper<ImClient>().lambda() ImClient imClientSender = getClientSender(clientId, imApplication);
.eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getClientId, clientUniId));
if (imClientSender == null) { if (imClientSender == null) {
log.error("imClientSender为空");
return; return;
} }
JsonMapper jsonMapper = new JsonMapper();
// 获取会话id // 获取会话id
Long toConversationId = Long.valueOf(receiveModel.getData().get("toConversation").toString()); if (receiveModel.getData().get(TO_CONVERSATION_KEY) == null) {
receiveModel.getData().remove("toConversation"); return;
// 生成消息id
long messageId = SnowflakeUtil.getId();
String content = null;
try {
content = jsonMapper.writeValueAsString(receiveModel.getData());
} catch (JsonProcessingException e) {
e.printStackTrace();
} }
Long toConversationId = Long.valueOf(receiveModel.getData().get(TO_CONVERSATION_KEY).toString());
// 查询该会话所有成员 // 查询该会话所有成员
List<ImConversationMembers> membersList = imConversationMembersService.list( List<ImConversationMembers> membersList = imConversationMembersService.list(
new QueryWrapper<ImConversationMembers>().lambda() new QueryWrapper<ImConversationMembers>().lambda()
.eq(ImConversationMembers::getFkConversationId, toConversationId) .eq(ImConversationMembers::getFkConversationId, toConversationId)
.notIn(ImConversationMembers::getFkClientId, imClientSender.getId()) .notIn(ImConversationMembers::getFkClientId, imClientSender.getId())
); );
if (membersList.isEmpty()) { if (membersList.isEmpty()) {
log.error("membersList为空,toConversationId:" + toConversationId); log.info("membersList为空,toConversationId:" + toConversationId);
return; return;
} }
receiveModel.getData().remove(TO_CONVERSATION_KEY);
// 获取自定义推送字段
HashMap<String, String> pushMap = null;
if (receiveModel.getData().get(PUSH_KEY) != null) {
pushMap = (HashMap<String, String>) receiveModel.getData().get(PUSH_KEY);
receiveModel.getData().remove(PUSH_KEY);
}
String content = null;
try {
content = JSON_MAPPER.writeValueAsString(receiveModel.getData());
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// 判断为单聊 // 判断为单聊
if (membersList.size() == 1) { if (membersList.size() == 1) {
// 判断是否被拉黑 // 拉黑逻辑
boolean beBlack = imClientBlacklistService.isBeBlack(membersList.get(0).getFkClientId(), imClientSender.getId()); if (black(receiveModel, appKey, clientId, imClientSender, membersList)) {
if (beBlack) {
log.debug("被对方拉黑了");
// 响应发送方
ResponseModel<HashMap<String, Long>> responseModel = new ResponseModel<>();
ApiResult<Boolean> result = ApiResult.result(ApiCode.IS_BE_BLACK);
responseModel.setCmd(ResponseModel.RES);
responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage());
responseModel.setReqId(receiveModel.getReqId());
writeDataService.write(responseModel, appKey, clientUniId);
return;
}
// 是否把对方拉黑
boolean black = imClientBlacklistService.isBeBlack(imClientSender.getId(), membersList.get(0).getFkClientId());
if (black) {
log.debug("你把对方拉黑了");
// 响应发送方
ResponseModel<HashMap<String, Long>> responseModel = new ResponseModel<>();
ApiResult<Boolean> result = ApiResult.result(ApiCode.IS_TO_BLACK);
responseModel.setCmd(ResponseModel.RES);
responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage());
responseModel.setReqId(receiveModel.getReqId());
writeDataService.write(responseModel, appKey, clientUniId);
return; return;
} }
} }
// 生成消息id
// 保存消息 long messageId = SnowflakeUtil.getId();
ImMessage imMessage = new ImMessage(); // 保存消息至消息表
imMessage.setId(messageId); ImMessage imMessage = saveImMessage(imApplication, imClientSender, toConversationId, messageId, content);
imMessage.setCreateTime(new Date());
imMessage.setFkAppid(imApplication.getId());
imMessage.setSender(imClientSender.getId());
imMessage.setContent(content);
imMessage.setWithdraw(false);
imMessage.setEvent(false);
imMessage.setSystem(false);
imMessage.setSendStatus(2);
imMessage.setFkConversationId(toConversationId);
imMessageService.save(imMessage);
// 封装响应的实体 // 封装响应的实体
ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend(); ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();
BeanUtils.copyProperties(imMessage, imMessageOnlineSend); BeanUtils.copyProperties(imMessage, imMessageOnlineSend);
imMessageOnlineSend.setMsgId(imMessage.getId()); imMessageOnlineSend.setMsgId(imMessage.getId());
imMessageOnlineSend.setSender(clientUniId); imMessageOnlineSend.setSender(clientId);
imMessageOnlineSend.setContent(receiveModel.getData()); imMessageOnlineSend.setContent(receiveModel.getData());
imMessageOnlineSend.setConversationId(toConversationId); imMessageOnlineSend.setConversationId(toConversationId);
...@@ -196,7 +167,7 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -196,7 +167,7 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy {
.eq(ImClient::getFkAppid, imApplication.getId()) .eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getId, conversationMembers.getFkClientId())); .eq(ImClient::getId, conversationMembers.getFkClientId()));
if (imClientReceiver == null) { if (imClientReceiver == null) {
return; continue;
} }
// 向接收方推送 // 向接收方推送
...@@ -210,7 +181,7 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -210,7 +181,7 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy {
writeDataService.write(responseModel, appKey, imClientReceiver.getClientId()); writeDataService.write(responseModel, appKey, imClientReceiver.getClientId());
// 异步推送系统通知消息 // 异步推送系统通知消息
pushTask.push(imClientReceiver, imClientSender, imMessage, imApplication); pushTask.push(pushMap, imClientReceiver, imApplication);
} }
// 响应发送方消息id等信息 // 响应发送方消息id等信息
...@@ -219,14 +190,73 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy { ...@@ -219,14 +190,73 @@ public class ImConcreteReceiveStrategy extends AbstractReceiveStrategy {
responseModel.setCmd(ResponseModel.RES); responseModel.setCmd(ResponseModel.RES);
responseModel.setCode(result.getCode()); responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage()); responseModel.setMsg(result.getMessage());
HashMap<String, Long> stringHashMap = new HashMap<>(3);
HashMap<String, Long> stringHashMap = new HashMap<>(); stringHashMap.put(MSG_ID, messageId);
stringHashMap.put("msgId", messageId);
responseModel.setData(stringHashMap); responseModel.setData(stringHashMap);
responseModel.setReqId(receiveModel.getReqId()); responseModel.setReqId(receiveModel.getReqId());
writeDataService.write(responseModel, appKey, clientUniId); // 响应发送方
writeDataService.write(responseModel, appKey, clientId);
}
private ImClient getClientSender(String clientUniId, ImApplication imApplication) {
ImClient imClientSender = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
.eq(ImClient::getFkAppid, imApplication.getId())
.eq(ImClient::getClientId, clientUniId));
if (imClientSender == null) {
log.info("imClientSender为空");
return null;
}
return imClientSender;
}
private ImMessage saveImMessage(ImApplication imApplication, ImClient imClientSender, Long toConversationId, long messageId, String content) {
ImMessage imMessage = new ImMessage();
imMessage.setId(messageId);
imMessage.setCreateTime(new Date());
imMessage.setFkAppid(imApplication.getId());
imMessage.setSender(imClientSender.getId());
imMessage.setContent(content);
imMessage.setWithdraw(false);
imMessage.setEvent(false);
imMessage.setSystem(false);
imMessage.setSendStatus(2);
imMessage.setFkConversationId(toConversationId);
imMessageService.save(imMessage);
return imMessage;
}
private boolean black(ReceiveModel receiveModel, String appKey, String clientUniId, ImClient imClientSender, List<ImConversationMembers> membersList) {
// 判断是否被拉黑
boolean beBlack = imClientBlacklistService.isBeBlack(membersList.get(0).getFkClientId(), imClientSender.getId());
if (beBlack) {
log.info("被对方拉黑了");
// 响应发送方
ResponseModel<HashMap<String, Long>> responseModel = new ResponseModel<>();
ApiResult<Boolean> result = ApiResult.result(ApiCode.IS_BE_BLACK);
responseModel.setCmd(ResponseModel.RES);
responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage());
responseModel.setReqId(receiveModel.getReqId());
writeDataService.write(responseModel, appKey, clientUniId);
return true;
}
// 是否把对方拉黑
boolean black = imClientBlacklistService.isBeBlack(imClientSender.getId(), membersList.get(0).getFkClientId());
if (black) {
log.info("你把对方拉黑了");
// 响应发送方
ResponseModel<HashMap<String, Long>> responseModel = new ResponseModel<>();
ApiResult<Boolean> result = ApiResult.result(ApiCode.IS_TO_BLACK);
responseModel.setCmd(ResponseModel.RES);
responseModel.setCode(result.getCode());
responseModel.setMsg(result.getMessage());
responseModel.setReqId(receiveModel.getReqId());
writeDataService.write(responseModel, appKey, clientUniId);
return true;
}
return false;
} }
......
...@@ -6,7 +6,7 @@ import java.security.Key; ...@@ -6,7 +6,7 @@ import java.security.Key;
public class EncrypDES { public class EncrypDES {
// 字符串默认键值 // 字符串默认键值
private static final String strDefaultKey = "inventec2020@#$%^&"; private static final String STR_DEFAULT_KEY = "inventec2020@#$%^&";
//加密工具 //加密工具
...@@ -19,7 +19,7 @@ public class EncrypDES { ...@@ -19,7 +19,7 @@ public class EncrypDES {
* 默认构造方法,使用默认密钥 * 默认构造方法,使用默认密钥
*/ */
public EncrypDES() throws Exception { public EncrypDES() throws Exception {
this(strDefaultKey); this(STR_DEFAULT_KEY);
} }
/** /**
......
...@@ -79,7 +79,7 @@ public class FullHttpRequestUtils { ...@@ -79,7 +79,7 @@ public class FullHttpRequestUtils {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, copiedBuffer(context, CharsetUtil.UTF_8)); FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, copiedBuffer(context, CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8"); response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=utf-8");
logger.debug("response:\n" + response.toString() + "\ncontext:" + context); logger.info("response:\n" + response.toString() + "\ncontext:" + context);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
} }
} }
...@@ -6,7 +6,7 @@ public class RSAGenerator { ...@@ -6,7 +6,7 @@ public class RSAGenerator {
private final static String[] chars = new String[]{"a", "b", "c", "d", "e", "f", private final static String[] CHARS = new String[]{"a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
...@@ -21,7 +21,7 @@ public class RSAGenerator { ...@@ -21,7 +21,7 @@ public class RSAGenerator {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
String str = uuid.substring(i * 2, i * 2 + 2); String str = uuid.substring(i * 2, i * 2 + 2);
int x = Integer.parseInt(str, 16); int x = Integer.parseInt(str, 16);
shortBuffer.append(chars[x % 0x3E]); shortBuffer.append(CHARS[x % 0x3E]);
} }
return shortBuffer.toString(); return shortBuffer.toString();
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id id
, create_time, update_time, app_key, app_secret, app_name, ios_push_channel, android_push_channel,umeng_key,umeng_secret,firebase_secret,repeat_session_status , create_time, update_time, app_key, app_secret, app_name, ios_push_channel, android_push_channel,umeng_key,umeng_secret,firebase_secret,repeat_session_status,contrast_extended_field_status
</sql> </sql>
......
...@@ -24,20 +24,20 @@ ...@@ -24,20 +24,20 @@
SELECT imConversation.id, SELECT imConversation.id,
imConversation.create_time, imConversation.create_time,
imConversation.`name`, imConversation.`name`,
imConversation.attributes as attribute, imConversation.attributes as attribute,
imConversation.system, imConversation.system,
im_client.client_id AS creator, im_client.client_id AS creator,
(SELECT COUNT(im_inbox.id) (SELECT COUNT(im_inbox.id)
FROM im_inbox FROM im_inbox
WHERE im_inbox.fk_conversation_id = imConversation.id WHERE im_inbox.fk_conversation_id = imConversation.id
AND im_inbox.receiver = #{clientId} AND im_inbox.receiver = #{clientId}
AND im_inbox.receiver_msg_status = 0) AS msg_not_read_count, AND im_inbox.read_msg_status = 0) AS msg_not_read_count,
( (
SELECT GROUP_CONCAT(im_client.client_id) SELECT GROUP_CONCAT(im_client.client_id)
FROM im_conversation_members AS im_conversation_members FROM im_conversation_members AS im_conversation_members
INNER JOIN im_client AS im_client ON im_client.id = im_conversation_members.fk_client_id INNER JOIN im_client AS im_client ON im_client.id = im_conversation_members.fk_client_id
WHERE im_conversation_members.fk_conversation_id = imConversation.id WHERE im_conversation_members.fk_conversation_id = imConversation.id
) AS members ) AS members
FROM im_conversation_members AS imConversationMembers FROM im_conversation_members AS imConversationMembers
INNER JOIN im_conversation AS imConversation INNER JOIN im_conversation AS imConversation
ON imConversation.id = imConversationMembers.fk_conversation_id ON imConversation.id = imConversationMembers.fk_conversation_id
...@@ -79,10 +79,8 @@ ...@@ -79,10 +79,8 @@
FROM im_conversation_members FROM im_conversation_members
WHERE im_conversation_members.fk_client_id = #{clientId2}) AS im_conversation_members2 WHERE im_conversation_members.fk_client_id = #{clientId2}) AS im_conversation_members2
ON im_conversation_members.fk_conversation_id = im_conversation_members2.fk_conversation_id ON im_conversation_members.fk_conversation_id = im_conversation_members2.fk_conversation_id
INNER JOIN im_conversation ON im_conversation.id = im_conversation_members.fk_conversation_id INNER JOIN im_conversation ON im_conversation.id = im_conversation_members.fk_conversation_id
WHERE im_conversation_members.fk_client_id = #{clientId1} LIMIT 1
WHERE im_conversation_members.fk_client_id = #{clientId1}
</select> </select>
</mapper> </mapper>
...@@ -24,7 +24,8 @@ ...@@ -24,7 +24,8 @@
UPDATE im_inbox UPDATE im_inbox
SET `im_inbox`.`update_time` = NOW(), SET `im_inbox`.`update_time` = NOW(),
`im_inbox`.`read_msg_status` = 1, `im_inbox`.`read_msg_status` = 1,
`im_inbox`.`receiver_time` = NOW() `im_inbox`.`receiver_time` = NOW(),
`im_inbox`.`read_time` = NOW()
WHERE WHERE
im_inbox.receiver = #{clientId} im_inbox.receiver = #{clientId}
AND im_inbox.fk_msg_id IN AND im_inbox.fk_msg_id IN
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wecloud.im.mapper.ImIosApnsMapper">
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id
, fk_app_id, apns_file_value, env, bundle_id, pwd
</sql>
<select id="getImIosApnsById" resultType="com.wecloud.im.param.ImIosApnsQueryVo">
select
<include refid="Base_Column_List"/>
from im_ios_apns where id = #{id}
</select>
<select id="getImIosApnsPageList" parameterType="com.wecloud.im.param.ImIosApnsPageParam"
resultType="com.wecloud.im.param.ImIosApnsQueryVo">
select
<include refid="Base_Column_List"/>
from im_ios_apns
</select>
</mapper>
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
from im_message from im_message
</select> </select>
<select id="getOfflineListByClientAndConversation" resultType="com.wecloud.im.vo.OfflineMsgDto"> <select id="getOfflineListByClientAndConversation" resultType="com.wecloud.im.vo.OfflineMsgDto">
SELECT im_message.id AS msgId, SELECT im_message.id AS msgId,
im_message.create_time, im_message.create_time,
im_message.withdraw_time, im_message.withdraw_time,
...@@ -33,15 +32,19 @@ ...@@ -33,15 +32,19 @@
im_message.system, im_message.system,
im_message.`at`, im_message.`at`,
im_message.send_status, im_message.send_status,
im_message.fk_conversation_id im_message.fk_conversation_id,
(SELECT COUNT(id) FROM im_inbox WHERE fk_msg_id = msgId AND read_msg_status = 0) AS not_read_count,
(SELECT COUNT(id)
FROM im_inbox
WHERE fk_msg_id = msgId
AND receiver_msg_status = 0) AS not_receiver_count
FROM im_inbox FROM im_inbox
INNER JOIN im_message im_message ON im_message.id = im_inbox.fk_msg_id INNER JOIN im_message im_message ON im_message.id = im_inbox.fk_msg_id
INNER JOIN `im_client` ON `im_client`.id = `im_message`.sender INNER JOIN `im_client` ON `im_client`.id = `im_message`.sender
WHERE im_inbox.fk_conversation_id = #{conversationId} WHERE im_inbox.fk_conversation_id = #{conversationId}
AND im_inbox.receiver = #{clientId} AND im_inbox.receiver = #{clientId}
AND im_inbox.receiver_msg_status = 0
AND im_inbox.read_msg = 0
</select> </select>
<select id="getHistoryMsgConversationId" resultType="com.wecloud.im.vo.OfflineMsgDto"> <select id="getHistoryMsgConversationId" resultType="com.wecloud.im.vo.OfflineMsgDto">
SELECT im_message.id AS msgId, SELECT im_message.id AS msgId,
...@@ -55,7 +58,12 @@ ...@@ -55,7 +58,12 @@
im_message.system, im_message.system,
im_message.`at`, im_message.`at`,
im_message.send_status, im_message.send_status,
im_message.fk_conversation_id im_message.fk_conversation_id,
(SELECT COUNT(id) FROM im_inbox WHERE fk_msg_id = msgId AND read_msg_status = 0) AS not_read_count,
(SELECT COUNT(id)
FROM im_inbox
WHERE fk_msg_id = msgId
AND receiver_msg_status = 0) AS not_receiver_count
FROM `im_message` FROM `im_message`
INNER JOIN `im_client` ON `im_client`.id = `im_message`.sender INNER JOIN `im_client` ON `im_client`.id = `im_message`.sender
WHERE fk_conversation_id = #{param.conversationId} WHERE fk_conversation_id = #{param.conversationId}
......
...@@ -42,7 +42,7 @@ public class SpringBootPlusStaticProperties { ...@@ -42,7 +42,7 @@ public class SpringBootPlusStaticProperties {
@PostConstruct @PostConstruct
public void init() { public void init() {
INFO_PROJECT_VERSION = this.infoProjectVersion; INFO_PROJECT_VERSION = this.infoProjectVersion;
log.debug("INFO_PROJECT_VERSION:" + INFO_PROJECT_VERSION); log.info("INFO_PROJECT_VERSION:" + INFO_PROJECT_VERSION);
} }
} }
...@@ -26,8 +26,17 @@ spring: ...@@ -26,8 +26,17 @@ spring:
password: password:
port: 6379 port: 6379
cloud:
nacos:
discovery:
server-addr: localhost:8848
# 打印SQL语句和结果集,本地开发环境可开启,线上注释掉 # 打印SQL语句和结果集,本地开发环境可开启,线上注释掉
mybatis-plus: mybatis-plus:
configuration: configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 服务器负载均衡配置
load-blance:
# 服务器运营商local,aws,huawei
server-type: local
...@@ -14,23 +14,46 @@ spring-boot-plus: ...@@ -14,23 +14,46 @@ spring-boot-plus:
request-log-format: false request-log-format: false
response-log-format: false response-log-format: false
spring: spring:
# upay
# datasource:
# url: jdbc:mysql://172.31.38.183:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
# username: web
# password: 74DXJwJE7wYehHr5VFJbc2w8
# # Redis配置
# redis:
# database: 0
# host: 172.31.38.183
# password: qZ8yzTz8chSZE1ZbbRbK
# port: 6379
# 飞蛙
datasource: datasource:
url: jdbc:mysql://172.31.38.183:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: web username: web
password: 74DXJwJE7wYehHr5VFJbc2w8 password: axT8knPN5hAP
# Redis配置
redis: redis:
database: 0 database: 0
host: 172.31.38.183 host: 127.0.0.1
password: qZ8yzTz8chSZE1ZbbRbK password: JH86uc53r8Ca
port: 6379 port: 6379
cloud:
nacos:
discovery:
server-addr: localhost:8848
# knife4j配置 # knife4j配置
knife4j: knife4j:
enable: ${spring-boot-plus.swagger.enable} enable: ${spring-boot-plus.swagger.enable}
basic: basic:
enable: true enable: true
username: 321wecloudAdmin123 username: 321wecloudAdmin123
password: hj12ad2f123H22skd3123sk2h password: hj12ad2f123H22skd3123sk2h
\ No newline at end of file
# 服务器负载均衡配置
load-blance:
# 服务器运营商local,aws,huawei
server-type: aws
...@@ -2,7 +2,7 @@ spring-boot-plus: ...@@ -2,7 +2,7 @@ spring-boot-plus:
# 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false # 是否启用ansi控制台输出有颜色的字体,local环境建议开启,服务器环境设置为false
enable-ansi: false enable-ansi: false
# 当前环境服务IP地址 # 当前环境服务IP地址
server-ip: 172.31.32.111 server-ip: 127.0.0.1
# 文件上传下载配置 # 文件上传下载配置
upload-path: /opt/upload/ upload-path: /opt/upload/
# AOP配置 # AOP配置
...@@ -16,19 +16,27 @@ spring-boot-plus: ...@@ -16,19 +16,27 @@ spring-boot-plus:
spring: spring:
datasource: datasource:
url: jdbc:mysql://172.31.32.111:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true url: jdbc:mysql://127.0.0.1:3306/wecloud_im?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: web username: web
password: axT8knPN5hAP password: axT8knPN5hAP
# Redis配置 # Redis配置
redis: redis:
database: 0 database: 0
host: 172.31.32.111 host: 127.0.0.1
password: JH86uc53r8Ca password: JH86uc53r8Ca
port: 6379 port: 6379
cloud:
nacos:
discovery:
server-addr: localhost:8848
# 打印SQL语句和结果集,本地开发环境可开启,线上注释掉 # 打印SQL语句和结果集,本地开发环境可开启,线上注释掉
mybatis-plus: mybatis-plus:
configuration: configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 服务器负载均衡配置
load-blance:
# 服务器运营商local,aws,huawei
server-type: aws
\ No newline at end of file
...@@ -197,6 +197,7 @@ spring-boot-plus: ...@@ -197,6 +197,7 @@ spring-boot-plus:
- /,/index.html - /,/index.html
# 应用相关 # 应用相关
- /imApplication/** - /imApplication/**
- /signDemo/get
# 多行字符串权限配置 # 多行字符串权限配置
filter-chain-definitions: | filter-chain-definitions: |
......
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
<!-- 解决SpringBootAdmin错误日志问题 --> <!-- 解决SpringBootAdmin错误日志问题 -->
<logger name="org.apache.catalina.connector.CoyoteAdapter" level="OFF"/> <logger name="org.apache.catalina.connector.CoyoteAdapter" level="OFF"/>
<root level="DEBUG"> <root level="INFO">
<appender-ref ref="CONSOLE"/> <appender-ref ref="CONSOLE"/>
<appender-ref ref="ASYNC_FILE"/> <appender-ref ref="ASYNC_FILE"/>
<appender-ref ref="ASYNC_ERROR_FILE"/> <appender-ref ref="ASYNC_ERROR_FILE"/>
......
#! /bin/shell
# sudo 超级权限启动, 否则无法创建log日志文件夹报错
# 停止服务
ps aux|grep bootstrap-2.0|awk '{print $2}'|xargs kill -9
#/data0/java_projects_jenkins/
# 启动新jar,
nohup java -jar bootstrap-2.0.jar &>/dev/null &
echo "success"
...@@ -63,7 +63,7 @@ public class EnumController { ...@@ -63,7 +63,7 @@ public class EnumController {
@GetMapping("/enum") @GetMapping("/enum")
public ApiResult<Map<String, Map<Integer, EnumVo<? extends BaseEnum>>>> enumList() { public ApiResult<Map<String, Map<Integer, EnumVo<? extends BaseEnum>>>> enumList() {
log.debug("enumList..."); log.info("enumList...");
return ApiResult.ok(BaseEnumUtil.getEnumMap()); return ApiResult.ok(BaseEnumUtil.getEnumMap());
} }
...@@ -76,7 +76,7 @@ public class EnumController { ...@@ -76,7 +76,7 @@ public class EnumController {
enumPackages.addAll(FRAMEWORK_ENUM_PACKAGES); enumPackages.addAll(FRAMEWORK_ENUM_PACKAGES);
// 获取BaseEnum接口的所有实现 // 获取BaseEnum接口的所有实现
log.debug("enumPackages:" + enumPackages); log.info("enumPackages:" + enumPackages);
Reflections reflections = new Reflections(enumPackages); Reflections reflections = new Reflections(enumPackages);
Set<Class<? extends BaseEnum>> set = reflections.getSubTypesOf(BaseEnum.class); Set<Class<? extends BaseEnum>> set = reflections.getSubTypesOf(BaseEnum.class);
if (CollectionUtils.isEmpty(set)) { if (CollectionUtils.isEmpty(set)) {
...@@ -98,7 +98,7 @@ public class EnumController { ...@@ -98,7 +98,7 @@ public class EnumController {
// 设置map // 设置map
BaseEnumUtil.getEnumMap().put(clazz.getName(), enumVoMap); BaseEnumUtil.getEnumMap().put(clazz.getName(), enumVoMap);
} }
log.debug("enumMap:{}", BaseEnumUtil.getEnumMap()); log.info("enumMap:{}", BaseEnumUtil.getEnumMap());
} catch (Exception e) { } catch (Exception e) {
log.error("获取BaseEnum枚举map异常", e); log.error("获取BaseEnum枚举map异常", e);
} }
......
...@@ -171,13 +171,13 @@ public abstract class BaseLogAop { ...@@ -171,13 +171,13 @@ public abstract class BaseLogAop {
requestIdType = logAopConfig.getRequestIdType(); requestIdType = logAopConfig.getRequestIdType();
operationLogConfig = springBootPlusAopProperties.getOperationLog(); operationLogConfig = springBootPlusAopProperties.getOperationLog();
loginLogConfig = springBootPlusAopProperties.getLoginLog(); loginLogConfig = springBootPlusAopProperties.getLoginLog();
log.debug("logAopConfig = " + logAopConfig); log.info("logAopConfig = " + logAopConfig);
log.debug("logPrintType = " + logPrintType); log.info("logPrintType = " + logPrintType);
log.debug("enableRequestId = " + enableRequestId); log.info("enableRequestId = " + enableRequestId);
log.debug("requestIdType = " + requestIdType); log.info("requestIdType = " + requestIdType);
log.debug("operationLogConfig = " + operationLogConfig); log.info("operationLogConfig = " + operationLogConfig);
log.debug("loginLogConfig = " + loginLogConfig); log.info("loginLogConfig = " + loginLogConfig);
log.debug("contextPath = " + contextPath); log.info("contextPath = " + contextPath);
} }
/** /**
......
...@@ -114,7 +114,7 @@ public class JwtFilter extends AuthenticatingFilter { ...@@ -114,7 +114,7 @@ public class JwtFilter extends AuthenticatingFilter {
@Override @Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
String url = WebUtils.toHttp(request).getRequestURI(); String url = WebUtils.toHttp(request).getRequestURI();
log.debug("isAccessAllowed url:{}", url); log.info("isAccessAllowed url:{}", url);
if (this.isLoginRequest(request, response)) { if (this.isLoginRequest(request, response)) {
return true; return true;
} }
...@@ -142,7 +142,7 @@ public class JwtFilter extends AuthenticatingFilter { ...@@ -142,7 +142,7 @@ public class JwtFilter extends AuthenticatingFilter {
@Override @Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
String url = WebUtils.toHttp(request).getRequestURI(); String url = WebUtils.toHttp(request).getRequestURI();
log.debug("鉴权成功,token:{},url:{}", token, url); log.info("鉴权成功,token:{},url:{}", token, url);
// 刷新token // 刷新token
JwtToken jwtToken = (JwtToken) token; JwtToken jwtToken = (JwtToken) token;
HttpServletResponse httpServletResponse = WebUtils.toHttp(response); HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
......
...@@ -59,7 +59,7 @@ public class JwtRealmAppUser extends AuthorizingRealm { ...@@ -59,7 +59,7 @@ public class JwtRealmAppUser extends AuthorizingRealm {
*/ */
@Override @Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
log.debug("doGetAuthorizationInfo principalCollection..."); log.info("doGetAuthorizationInfo principalCollection...");
// 设置角色/权限信息 // 设置角色/权限信息
JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal(); JwtToken jwtToken = (JwtToken) principalCollection.getPrimaryPrincipal();
...@@ -92,7 +92,7 @@ public class JwtRealmAppUser extends AuthorizingRealm { ...@@ -92,7 +92,7 @@ public class JwtRealmAppUser extends AuthorizingRealm {
*/ */
@Override @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
log.debug("doGetAuthenticationInfo authenticationToken..."); log.info("doGetAuthenticationInfo authenticationToken...");
// 校验token // 校验token
JwtToken jwtToken = (JwtToken) authenticationToken; JwtToken jwtToken = (JwtToken) authenticationToken;
if (jwtToken == null) { if (jwtToken == null) {
......
...@@ -105,7 +105,7 @@ public class ShiroLoginServiceImpl implements ShiroLoginService { ...@@ -105,7 +105,7 @@ public class ShiroLoginServiceImpl implements ShiroLoginService {
// JwtToken newJwtToken = JwtToken.build(newToken, username, jwtToken.getUserId(), salt, expireSecond, jwtToken.getType(), null); // JwtToken newJwtToken = JwtToken.build(newToken, username, jwtToken.getUserId(), salt, expireSecond, jwtToken.getType(), null);
// // 更新redis缓存 // // 更新redis缓存
// sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken); // sysLoginRedisService.refreshLoginInfo(token, username, newJwtToken);
// log.debug("刷新token成功,原token:{},新token:{}", token, newToken); // log.info("刷新token成功,原token:{},新token:{}", token, newToken);
// // 设置响应头 // // 设置响应头
// // 刷新token // // 刷新token
// httpServletResponse.setStatus(CommonConstant.JWT_REFRESH_TOKEN_CODE); // httpServletResponse.setStatus(CommonConstant.JWT_REFRESH_TOKEN_CODE);
......
...@@ -39,7 +39,7 @@ public class JwtTokenUtil { ...@@ -39,7 +39,7 @@ public class JwtTokenUtil {
public JwtTokenUtil(JwtProperties jwtProperties) { public JwtTokenUtil(JwtProperties jwtProperties) {
tokenName = jwtProperties.getTokenName(); tokenName = jwtProperties.getTokenName();
log.debug("tokenName:{}", tokenName); log.info("tokenName:{}", tokenName);
} }
/** /**
......
...@@ -79,13 +79,13 @@ public class JwtUtil { ...@@ -79,13 +79,13 @@ public class JwtUtil {
log.error("username不能为空"); log.error("username不能为空");
return null; return null;
} }
log.debug("clientId:{}", clientId); log.info("clientId:{}", clientId);
// // 如果盐值为空,则使用默认值:666666 // // 如果盐值为空,则使用默认值:666666
// if (StringUtils.isBlank(salt)) { // if (StringUtils.isBlank(salt)) {
// salt = jwtProperties.getSecret(); // salt = jwtProperties.getSecret();
// } // }
log.debug("salt:{}", salt); log.info("salt:{}", salt);
// 过期时间,单位:秒 // 过期时间,单位:秒
Long expireSecond; Long expireSecond;
...@@ -95,9 +95,9 @@ public class JwtUtil { ...@@ -95,9 +95,9 @@ public class JwtUtil {
} else { } else {
expireSecond = expireDuration.getSeconds(); expireSecond = expireDuration.getSeconds();
} }
log.debug("expireSecond:{}", expireSecond); log.info("expireSecond:{}", expireSecond);
Date expireDate = DateUtils.addSeconds(new Date(), expireSecond.intValue()); Date expireDate = DateUtils.addSeconds(new Date(), expireSecond.intValue());
log.debug("expireDate:{}", expireDate); log.info("expireDate:{}", expireDate);
// 生成token // 生成token
Algorithm algorithm = Algorithm.HMAC256(salt); Algorithm algorithm = Algorithm.HMAC256(salt);
......
...@@ -43,23 +43,23 @@ public class PrintApplicationInfo { ...@@ -43,23 +43,23 @@ public class PrintApplicationInfo {
tip.append("===========================================================================================\n"); tip.append("===========================================================================================\n");
tip.append(" \n"); tip.append(" \n");
tip.append(" !!!准备工作!!! \n"); tip.append(" !!!准备工作!!! \n");
tip.append(" 1.导入SQL初始化脚本:docs/db,根据不同数据库导入对应SQL脚本并修改链接等信息配置\n"); // tip.append(" 1.导入SQL初始化脚本:docs/db,根据不同数据库导入对应SQL脚本并修改链接等信息配置\n");
tip.append(" 2.启动Redis服务,必要条件\n"); // tip.append(" 2.启动Redis服务,必要条件\n");
tip.append(" 3.启动SpringBootAdmin Server,可选操作,admin模块中,启动SpringBootPlusAdminApplication\n"); // tip.append(" 3.启动SpringBootAdmin Server,可选操作,admin模块中,启动SpringBootPlusAdminApplication\n");
tip.append(" 4.根据项目需要,修改项目配置,请先查看官网配置文档:https://springboot.plus/config/\n"); // tip.append(" 4.根据项目需要,修改项目配置,请先查看官网配置文档:https://springboot.plus/config/\n");
tip.append(" 5.项目模块说明:\n"); // tip.append(" 5.项目模块说明:\n");
tip.append(" admin: SpringBootAdmin Server启动模块\n"); // tip.append(" admin: SpringBootAdmin Server启动模块\n");
tip.append(" bootstrap: 项目启动模块\n"); tip.append(" bootstrap: 项目启动模块\n");
tip.append(" config: 项目配置模块\n"); tip.append(" config: 项目配置模块\n");
tip.append(" distribution:项目打包模块,打包时,请先选中Maven Profiles中的release和对应环境\n"); // tip.append(" distribution:项目打包模块,打包时,请先选中Maven Profiles中的release和对应环境\n");
tip.append(" example: 业务自定义模块,自己的业务代码可在example下进行,也可以再创建模块\n"); // tip.append(" example: 业务自定义模块,自己的业务代码可在example下进行,也可以再创建模块\n");
tip.append(" framework: 项目核心框架模块\n"); tip.append(" framework: 项目核心框架模块\n");
tip.append(" generator: 代码生成模块,启动类:SpringBootPlusGenerator,请根据实际情况进行配置\n"); tip.append(" generator: 代码生成模块,启动类:SpringBootPlusGenerator,请根据实际情况进行配置\n");
tip.append(" scheduled: 任务调度模块\n"); // tip.append(" scheduled: 任务调度模块\n");
tip.append(" system: 系统管理模块\n"); // tip.append(" system: 系统管理模块\n");
tip.append(" 6.FAQ:https://springboot.plus/faq\n"); // tip.append(" 6.FAQ:https://springboot.plus/faq\n");
tip.append(" 7.如开发中遇到bug及问题,欢迎提交ISSUES:https://github.com/geekidea/spring-boot-plus/issues\n"); // tip.append(" 7.如开发中遇到bug及问题,欢迎提交ISSUES:https://github.com/geekidea/spring-boot-plus/issues\n");
tip.append(" 8.QQ:625301326,进群答案:springboot.plus\n"); // tip.append(" 8.QQ:625301326,进群答案:springboot.plus\n");
tip.append(" \n"); tip.append(" \n");
tip.append("===========================================================================================\n"); tip.append("===========================================================================================\n");
if ("dev".equals(profileActive)) { if ("dev".equals(profileActive)) {
...@@ -107,16 +107,16 @@ public class PrintApplicationInfo { ...@@ -107,16 +107,16 @@ public class PrintApplicationInfo {
String homeUrl = "http://" + serverIp + ":" + port + contextPath; String homeUrl = "http://" + serverIp + ":" + port + contextPath;
String swaggerUrl = "http://" + serverIp + ":" + port + contextPath + "/swagger-ui.html"; String swaggerUrl = "http://" + serverIp + ":" + port + contextPath + "/swagger-ui.html";
String knife4jUrl = "http://" + serverIp + ":" + port + contextPath + "/doc.html"; String knife4jUrl = "http://" + serverIp + ":" + port + contextPath + "/doc.html";
log.info("Admin: {}", springBootAdminServerUrl); // log.info("Admin: {}", springBootAdminServerUrl);
log.info("Home: {}", homeUrl); log.info("Home: {}", homeUrl);
log.info("Knife4j: {}", knife4jUrl); log.info("Knife4j: {}", knife4jUrl);
log.info("Swagger: {}", swaggerUrl); // log.info("Swagger: {}", swaggerUrl);
log.info("spring-boot-plus project start success..........."); log.info("spring-boot-plus project start success...........");
if ("dev".equals(profileActive)) { // if ("dev".equals(profileActive)) {
log.info("\n{}", AnsiUtil.getAnsi(Ansi.Color.BLUE, startSuccess)); // log.info("\n{}", AnsiUtil.getAnsi(Ansi.Color.BLUE, startSuccess));
} else { // } else {
log.info("\n{}", startSuccess); // log.info("\n{}", startSuccess);
} // }
} }
} }
...@@ -94,13 +94,13 @@ public final class UploadUtil { ...@@ -94,13 +94,13 @@ public final class UploadUtil {
public static void deleteQuietly(String uploadPath, String saveFileName) { public static void deleteQuietly(String uploadPath, String saveFileName) {
File saveDir = new File(uploadPath); File saveDir = new File(uploadPath);
File saveFile = new File(saveDir, saveFileName); File saveFile = new File(saveDir, saveFileName);
log.debug("删除文件:" + saveFile); log.info("删除文件:" + saveFile);
FileUtils.deleteQuietly(saveFile); FileUtils.deleteQuietly(saveFile);
} }
public static interface UploadFileNameHandle { public interface UploadFileNameHandle {
/** /**
* 回调处理接口 * 回调处理接口
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<version>2.0</version> <version>2.0</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>WC_IM</name> <name>WeCloud_IM</name>
<url>https://github.com/geekidea/spring-boot-plus</url> <url>https://github.com/geekidea/spring-boot-plus</url>
<properties> <properties>
...@@ -532,22 +532,22 @@ ...@@ -532,22 +532,22 @@
</profile> </profile>
</profiles> </profiles>
<repositories> <!-- <repositories>-->
<repository> <!-- <repository>-->
<id>aliyun</id> <!-- <id>aliyun</id>-->
<name>aliyun-maven</name> <!-- <name>aliyun-maven</name>-->
<url>http://maven.aliyun.com/nexus/content/groups/public/</url> <!-- <url>http://maven.aliyun.com/nexus/content/groups/public/</url>-->
</repository> <!-- </repository>-->
<repository> <!-- <repository>-->
<id>spring-milestones</id> <!-- <id>spring-milestones</id>-->
<name>Spring Milestones</name> <!-- <name>Spring Milestones</name>-->
<url>https://maven.aliyun.com/repository/spring</url> <!-- <url>https://maven.aliyun.com/repository/spring</url>-->
</repository> <!-- </repository>-->
<repository> <!-- <repository>-->
<id>central</id> <!-- <id>central</id>-->
<name>maven-central</name> <!-- <name>maven-central</name>-->
<url>http://central.maven.org/maven2/</url> <!-- <url>http://central.maven.org/maven2/</url>-->
</repository> <!-- </repository>-->
</repositories> <!-- </repositories>-->
</project> </project>
\ No newline at end of file
...@@ -33,7 +33,7 @@ public class HelloScheduled { ...@@ -33,7 +33,7 @@ public class HelloScheduled {
*/ */
@Scheduled(cron = "0 0 0/1 * * ? ") @Scheduled(cron = "0 0 0/1 * * ? ")
public void hello() throws Exception { public void hello() throws Exception {
log.debug("HelloScheduled..."); log.info("HelloScheduled...");
} }
} }
本地:
String appKey = "QNtP3EjtLw26ekt0";
String appSecret = "a5e619003868258e0f7c5b5821ea00fb6b2302faf2ab3737";
--
aaaaa1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJjbGllbnRJZCI6ImFhYWFhMSIsImlzcyI6IndlY2xvdWRfaW0iLCJhcHBLZXkiOiJRTnRQM0VqdEx3MjZla3QwIiwiZXhwIjoxNjc5MjU0MjAzLCJpYXQiOjE2MjkyNzUxOTUsImp0aSI6IjEwNTM0N2YxOGUyYzQ4MzY4ZmQ2OTZjM2Q5NWZhZWZiIn0.kD7eKKQdxOnE8pKGyvtup-xq-JV6GI2qhd6_oUBRl2A
--
aaaaa2
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3ZWIiLCJjbGllbnRJZCI6ImFhYWFhMiIsImlzcyI6IndlY2xvdWRfaW0iLCJhcHBLZXkiOiJRTnRQM0VqdEx3MjZla3QwIiwiZXhwIjoxNjc5MjU0MjQ3LCJpYXQiOjE2MjkyNzUyMzksImp0aSI6IjM5NjUwZjZiMzgwYTRkNjFhNzIxYzFmNzQyMjRhMjA1In0.39hQkadKFIXhXJbIfIvsMcLa5YccQF21kP9Wh13qACY
--
aaaaa3
--
-- 会话
1邀请2
1427910060675305472
--群聊发送文本-------
{
"reqId":"1231223123",
"cmd":1,
"data":{
"diyAbcd":"aaaa自已定2义字段的值",
"toConversation":1427910060675305472,
"type":-1,
"text":"发给12312123213这是一123个纯文本消息,发给12312123213这是一123个纯文本消息发给12312123213这是一123个纯文本消息",
"attrs":{
"a":"attrs 阿道夫123123是用来213存储用户自定义的一些键值对,ttrs 阿道夫123123是用来213存储用户自定义的一些键值对",
"b":"attrs 阿道夫123123是用来213存储用户自定义的一些键值对,ttrs 阿道夫123123是用来213存储用户自定义的一些键值对"
}
}
}
{
"reqId":"123123123",
"cmd":1,
"data":{
"push":{
"title":"收到一条新消息",
"subTitle":"发给12312123213这是一123个纯文本消息,发给12312123213这是一123个纯文本消息发给12312123213这是一123个纯文本消息"
},
"diyAbcd":"aaaa自已定义字段的值",
"toConversation":1427910060675305472,
"type":-1,
"text":"发给12312123213这是一123个纯文本消息,发给12312123213这是一123个纯文本消息发给12312123213这是一123个纯文本消息",
"attrs":{
"a":"attrs 阿道夫123123是用来213存储用户自定义的一些键值对,ttrs 阿道夫123123是用来213存储用户自定义的一些键值对",
"b":"attrs 阿道夫123123是用来213存储用户自定义的一些键值对,ttrs 阿道夫123123是用来213存储用户自定义的一些键值对"
}
}
}
## 集群配置
### AWS服务器内部获取公网IP地址 等元数据
curl http://instance-data/latest/meta-data/public-ipv4
### 华为
查询弹性云服务器的网络信息 Network data(OpenStack元数据API)
文档:https://support.huaweicloud.com/usermanual-ecs/ecs_03_0166.html
Linux操作系统:
curl http://169.254.169.254/latest/meta-data/public-ipv4
Windows操作系统:
Invoke-RestMethod http://169.254.169.254/latest/meta-data/public-ipv4
配置文件中配置当前服务器的运营商 可以从运营商处获取公网IP, 如果获取不到则走IP138等接口获取公网IP
服务器负载均衡配置
load-blance:
服务器配置 Local,AWS,AlibabaCloud,HuaweiCloud
server-type: Local
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment