Commit d67a2815 by lpx

Merge branch 'master' of http://119.28.51.83/hewei/Jumeirah into dev/lanpingxiong

parents 21bc59b1 4ae65440
...@@ -49,3 +49,4 @@ logs ...@@ -49,3 +49,4 @@ logs
*/.rebel.xml.bak */.rebel.xml.bak
*/rebel.xml */rebel.xml
/common/src/main/resources/rebel.xml /common/src/main/resources/rebel.xml
/customer-service/target/
package com.jumeirah.api.app.controller; package com.jumeirah.api.app.controller;
import com.jumeirah.api.app.entity.param.DeviceTokenParam;
import com.jumeirah.api.app.service.AppUserApiService; import com.jumeirah.api.app.service.AppUserApiService;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.param.app.AppSmsRegisterParam; import com.jumeirah.common.param.app.AppSmsRegisterParam;
import com.jumeirah.common.param.app.AppUserInfoParam; import com.jumeirah.common.param.app.AppUserInfoParam;
import com.jumeirah.common.param.app.AppUserPhoneUpdateParam; import com.jumeirah.common.param.app.AppUserPhoneUpdateParam;
import com.jumeirah.common.param.app.DeviceTokenParam;
import com.jumeirah.common.service.AppUserService; import com.jumeirah.common.service.AppUserService;
import com.jumeirah.common.vo.app.LoginAppUserTokenVo; import com.jumeirah.common.vo.app.LoginAppUserTokenVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -13,18 +13,14 @@ import io.geekidea.springbootplus.framework.common.controller.BaseController; ...@@ -13,18 +13,14 @@ import io.geekidea.springbootplus.framework.common.controller.BaseController;
import io.geekidea.springbootplus.framework.log.annotation.Module; import io.geekidea.springbootplus.framework.log.annotation.Module;
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.geekidea.springbootplus.framework.shiro.jwt.JwtToken; import io.geekidea.springbootplus.framework.shiro.util.JwtTokenUtil;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
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.apache.shiro.SecurityUtils;
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.PostMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* APP用户 控制器 * APP用户 控制器
...@@ -51,17 +47,9 @@ public class AppUserController extends BaseController { ...@@ -51,17 +47,9 @@ public class AppUserController extends BaseController {
@PostMapping("/iosDeviceToken") @PostMapping("/iosDeviceToken")
@OperationLog(name = "ios-添加或修改推送token", type = OperationLogType.ADD) @OperationLog(name = "ios-添加或修改推送token", type = OperationLogType.ADD)
@ApiOperation(value = "ios-添加或修改推送token", notes = "添加和修改都调用此接口", response = ApiResult.class) @ApiOperation(value = "ios-添加或修改推送token", notes = "添加和修改都调用此接口", response = ApiResult.class)
public ApiResult<Boolean> addIosAppDeviceToken(@RequestBody DeviceTokenParam deviceToken) throws Exception { public ApiResult<Boolean> addIosAppDeviceToken(@RequestBody DeviceTokenParam deviceTokenParam) throws Exception {
AppUser appUser = new AppUser(); boolean flag = appUserService.updateDeviceToken(deviceTokenParam, 2);
appUser.setDeviceToken(deviceToken.getDeviceToken());
appUser.setDeviceType(2);
JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
appUser.setId(jwtToken.getUserId());
boolean flag = appUserService.updateAppUser(appUser);
return ApiResult.result(flag); return ApiResult.result(flag);
} }
...@@ -71,20 +59,13 @@ public class AppUserController extends BaseController { ...@@ -71,20 +59,13 @@ public class AppUserController extends BaseController {
@PostMapping("/androidDeviceToken") @PostMapping("/androidDeviceToken")
@OperationLog(name = "android-添加或修改推送token", type = OperationLogType.ADD) @OperationLog(name = "android-添加或修改推送token", type = OperationLogType.ADD)
@ApiOperation(value = "android-添加或修改推送token", notes = "添加和修改都调用此接口", response = ApiResult.class) @ApiOperation(value = "android-添加或修改推送token", notes = "添加和修改都调用此接口", response = ApiResult.class)
public ApiResult<Boolean> addAppDeviceToken(@RequestBody DeviceTokenParam deviceToken) throws Exception { public ApiResult<Boolean> addAppDeviceToken(@RequestBody DeviceTokenParam deviceTokenParam) throws Exception {
AppUser appUser = new AppUser();
appUser.setDeviceToken(deviceToken.getDeviceToken());
appUser.setDeviceType(1);
JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
appUser.setId(jwtToken.getUserId()); boolean flag = appUserService.updateDeviceToken(deviceTokenParam, 1);
boolean flag = appUserService.updateAppUser(appUser);
return ApiResult.result(flag); return ApiResult.result(flag);
} }
/** /**
* 补充或修改APP用户信息 * 补充或修改APP用户信息
*/ */
...@@ -174,5 +155,11 @@ public class AppUserController extends BaseController { ...@@ -174,5 +155,11 @@ public class AppUserController extends BaseController {
return appUserApiService.register(appSmsRegisterParam, language); return appUserApiService.register(appSmsRegisterParam, language);
} }
@GetMapping("/userInfo")
@ApiOperation(value = "根据token获取userInfo", notes = "客服模块调用")
public AppUser getUserInfo() {
return appUserApiService.getUserInfo(Long.valueOf(JwtUtil.getUsername(JwtTokenUtil.getToken())));
}
} }
package com.jumeirah.api.app.controller; package com.jumeirah.api.app.controller;
import com.jumeirah.api.app.entity.param.FeedbackAddParam;
import com.jumeirah.common.entity.Feedback; import com.jumeirah.common.entity.Feedback;
import com.jumeirah.common.service.FeedbackService; import com.jumeirah.common.service.FeedbackService;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -40,10 +41,13 @@ public class FeedbackController extends BaseController { ...@@ -40,10 +41,13 @@ public class FeedbackController extends BaseController {
@PostMapping("/add") @PostMapping("/add")
@OperationLog(name = "添加意见反馈", type = OperationLogType.ADD) @OperationLog(name = "添加意见反馈", type = OperationLogType.ADD)
@ApiOperation(value = "添加意见反馈") @ApiOperation(value = "添加意见反馈")
public ApiResult<Boolean> addFeedback(@Validated(Add.class) @RequestBody Feedback feedback) throws Exception { public ApiResult<Boolean> addFeedback(@Validated(Add.class) @RequestBody FeedbackAddParam feedbackAddParam) throws Exception {
JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal(); JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
Feedback feedback = new Feedback();
feedback.setUserId(jwtToken.getUserId()); feedback.setUserId(jwtToken.getUserId());
feedback.setContent(feedbackAddParam.getContent());
boolean flag = feedbackService.saveFeedback(feedback); boolean flag = feedbackService.saveFeedback(feedback);
return ApiResult.result(flag); return ApiResult.result(flag);
} }
......
package com.jumeirah.api.app.entity.param;
import io.geekidea.springbootplus.framework.common.entity.BaseEntity;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 意见反馈
*
* @author giao
* @since 2020-10-26
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "FeedbackAddParam")
public class FeedbackAddParam extends BaseEntity {
private static final long serialVersionUID = 1L;
private String content;
}
package com.jumeirah.api.app.service; package com.jumeirah.api.app.service;
import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.param.app.AppSmsRegisterParam; import com.jumeirah.common.param.app.AppSmsRegisterParam;
import com.jumeirah.common.param.app.AppUserInfoParam; import com.jumeirah.common.param.app.AppUserInfoParam;
import com.jumeirah.common.vo.app.LoginAppUserTokenVo; import com.jumeirah.common.vo.app.LoginAppUserTokenVo;
...@@ -9,6 +10,7 @@ public interface AppUserApiService { ...@@ -9,6 +10,7 @@ public interface AppUserApiService {
/** /**
* 注册 * 注册
*
* @param loginParam * @param loginParam
* @param language * @param language
* @return * @return
...@@ -19,13 +21,23 @@ public interface AppUserApiService { ...@@ -19,13 +21,23 @@ public interface AppUserApiService {
/** /**
* 修改或补充用户信息 * 修改或补充用户信息
*
* @param appUserInfoParam * @param appUserInfoParam
* @return * @return
* @throws Exception * @throws Exception
*/ */
boolean updateAppUser(AppUserInfoParam appUserInfoParam) throws Exception; boolean updateAppUser(AppUserInfoParam appUserInfoParam) throws Exception;
ApiResult<Boolean> updatePhone(String phoneArea, String phone,String code) throws Exception; ApiResult<Boolean> updatePhone(String phoneArea, String phone, String code) throws Exception;
/**
* 获取用户信息
*
* @param userId
* @return
*/
AppUser getUserInfo(Long userId);
} }
package com.jumeirah.api.app.service.impl; package com.jumeirah.api.app.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jumeirah.api.app.service.AppSmsService; import com.jumeirah.api.app.service.AppSmsService;
import com.jumeirah.api.app.service.AppUserApiService; import com.jumeirah.api.app.service.AppUserApiService;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
...@@ -53,6 +54,11 @@ public class AppUserApiServiceImpl implements AppUserApiService { ...@@ -53,6 +54,11 @@ public class AppUserApiServiceImpl implements AppUserApiService {
} }
@Override @Override
public AppUser getUserInfo(Long userId) {
return appUserService.getOne(new QueryWrapper<AppUser>().lambda().eq(AppUser::getId, userId));
}
@Override
public ApiResult<LoginAppUserTokenVo> register(AppSmsRegisterParam loginParam, String language) throws Exception { public ApiResult<LoginAppUserTokenVo> register(AppSmsRegisterParam loginParam, String language) throws Exception {
// 校验验证码 // 校验验证码
boolean equalsRegisterCode = appSmsService.equalsRegisterCode(loginParam.getPhoneArea(), loginParam.getPhone(), loginParam.getSmsCode()); boolean equalsRegisterCode = appSmsService.equalsRegisterCode(loginParam.getPhoneArea(), loginParam.getPhone(), loginParam.getSmsCode());
......
...@@ -16,12 +16,9 @@ import io.swagger.annotations.ApiOperation; ...@@ -16,12 +16,9 @@ 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.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import java.util.List;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* 航空公司商家表 控制器 * 航空公司商家表 控制器
...@@ -93,5 +90,15 @@ public class MerchantForSysController extends BaseController { ...@@ -93,5 +90,15 @@ public class MerchantForSysController extends BaseController {
return ApiResult.ok(paging); return ApiResult.ok(paging);
} }
/**
* 航空公司商家表
*/
@GetMapping("/getList")
@OperationLog(name = "航空公司商家列表", type = OperationLogType.LIST)
@ApiOperation(value = "航空公司商家列表")
public ApiResult<List<Merchant>> getMerchantList() {
return ApiResult.ok(merchantService.getMerchantList());
}
} }
...@@ -35,6 +35,18 @@ ...@@ -35,6 +35,18 @@
<groupId>io.geekidea.springbootplus</groupId> <groupId>io.geekidea.springbootplus</groupId>
<artifactId>framework</artifactId> <artifactId>framework</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.5</version>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
package com.jumeirah.api.app.entity.param; package com.jumeirah.common.param.app;
import lombok.Data; import lombok.Data;
......
package com.jumeirah.common.push;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.HashSet;
public abstract class AndroidNotification extends UmengNotification {
// Keys can be set in the payload level
protected static final HashSet<String> PAYLOAD_KEYS = new HashSet<String>(Arrays.asList("display_type"));
// Keys can be set in the body level
protected static final HashSet<String> BODY_KEYS = new HashSet<String>(Arrays.asList("ticker", "title", "text", "builder_id", "icon", "largeIcon", "img", "play_vibrate", "play_lights", "play_sound",
"sound", "after_open", "url", "activity", "custom"));
// Set key/value in the rootJson, for the keys can be set please see ROOT_KEYS, PAYLOAD_KEYS,
// BODY_KEYS and POLICY_KEYS.
@Override
public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
if (ROOT_KEYS.contains(key)) {
// This key should be in the root level
rootJson.put(key, value);
} else if (PAYLOAD_KEYS.contains(key)) {
// This key should be in the payload level
JSONObject payloadJson = null;
if (rootJson.has("payload")) {
payloadJson = rootJson.getJSONObject("payload");
} else {
payloadJson = new JSONObject();
rootJson.put("payload", payloadJson);
}
payloadJson.put(key, value);
} else if (BODY_KEYS.contains(key)) {
// This key should be in the body level
JSONObject bodyJson = null;
JSONObject payloadJson = null;
// 'body' is under 'payload', so build a payload if it doesn't exist
if (rootJson.has("payload")) {
payloadJson = rootJson.getJSONObject("payload");
} else {
payloadJson = new JSONObject();
rootJson.put("payload", payloadJson);
}
// Get body JSONObject, generate one if not existed
if (payloadJson.has("body")) {
bodyJson = payloadJson.getJSONObject("body");
} else {
bodyJson = new JSONObject();
payloadJson.put("body", bodyJson);
}
bodyJson.put(key, value);
} else if (POLICY_KEYS.contains(key)) {
// This key should be in the body level
JSONObject policyJson = null;
if (rootJson.has("policy")) {
policyJson = rootJson.getJSONObject("policy");
} else {
policyJson = new JSONObject();
rootJson.put("policy", policyJson);
}
policyJson.put(key, value);
} else {
if (key == "payload" || key == "body" || key == "policy" || key == "extra") {
throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
} else {
throw new Exception("Unknown key: " + key);
}
}
return true;
}
// Set extra key/value for Android notification
public boolean setExtraField(String key, String value) throws Exception {
JSONObject payloadJson = null;
JSONObject extraJson = null;
if (rootJson.has("payload")) {
payloadJson = rootJson.getJSONObject("payload");
} else {
payloadJson = new JSONObject();
rootJson.put("payload", payloadJson);
}
if (payloadJson.has("extra")) {
extraJson = payloadJson.getJSONObject("extra");
} else {
extraJson = new JSONObject();
payloadJson.put("extra", extraJson);
}
extraJson.put(key, value);
return true;
}
//
public void setDisplayType(DisplayType d) throws Exception {
setPredefinedKeyValue("display_type", d.getValue());
}
///通知栏提示文字
public void setTicker(String ticker) throws Exception {
setPredefinedKeyValue("ticker", ticker);
}
///通知标题
public void setTitle(String title) throws Exception {
setPredefinedKeyValue("title", title);
}
///通知文字描述
public void setText(String text) throws Exception {
setPredefinedKeyValue("text", text);
}
///用于标识该通知采用的样式。使用该参数时, 必须在SDK里面实现自定义通知栏样式。
public void setBuilderId(Integer builder_id) throws Exception {
setPredefinedKeyValue("builder_id", builder_id);
}
///状态栏图标ID, R.drawable.[smallIcon],如果没有, 默认使用应用图标。
public void setIcon(String icon) throws Exception {
setPredefinedKeyValue("icon", icon);
}
///通知栏拉开后左侧图标ID
public void setLargeIcon(String largeIcon) throws Exception {
setPredefinedKeyValue("largeIcon", largeIcon);
}
///通知栏大图标的URL链接。该字段的优先级大于largeIcon。该字段要求以http或者https开头。
public void setImg(String img) throws Exception {
setPredefinedKeyValue("img", img);
}
///收到通知是否震动,默认为"true"
public void setPlayVibrate(Boolean play_vibrate) throws Exception {
setPredefinedKeyValue("play_vibrate", play_vibrate.toString());
}
///收到通知是否闪灯,默认为"true"
public void setPlayLights(Boolean play_lights) throws Exception {
setPredefinedKeyValue("play_lights", play_lights.toString());
}
///收到通知是否发出声音,默认为"true"
public void setPlaySound(Boolean play_sound) throws Exception {
setPredefinedKeyValue("play_sound", play_sound.toString());
}
///通知声音,R.raw.[sound]. 如果该字段为空,采用SDK默认的声音
public void setSound(String sound) throws Exception {
setPredefinedKeyValue("sound", sound);
}
///收到通知后播放指定的声音文件
public void setPlaySound(String sound) throws Exception {
setPlaySound(true);
setSound(sound);
}
///点击"通知"的后续行为,默认为打开app。
public void goAppAfterOpen() throws Exception {
setAfterOpenAction(AfterOpenAction.go_app);
}
public void goUrlAfterOpen(String url) throws Exception {
setAfterOpenAction(AfterOpenAction.go_url);
setUrl(url);
}
public void goActivityAfterOpen(String activity) throws Exception {
setAfterOpenAction(AfterOpenAction.go_activity);
setActivity(activity);
}
public void goCustomAfterOpen(String custom) throws Exception {
setAfterOpenAction(AfterOpenAction.go_custom);
setCustomField(custom);
}
public void goCustomAfterOpen(JSONObject custom) throws Exception {
setAfterOpenAction(AfterOpenAction.go_custom);
setCustomField(custom);
}
///点击"通知"的后续行为,默认为打开app。原始接口
public void setAfterOpenAction(AfterOpenAction action) throws Exception {
setPredefinedKeyValue("after_open", action.toString());
}
public void setUrl(String url) throws Exception {
setPredefinedKeyValue("url", url);
}
public void setActivity(String activity) throws Exception {
setPredefinedKeyValue("activity", activity);
}
///can be a string of json
public void setCustomField(String custom) throws Exception {
setPredefinedKeyValue("custom", custom);
}
public void setCustomField(JSONObject custom) throws Exception {
setPredefinedKeyValue("custom", custom);
}
public enum DisplayType {
NOTIFICATION {
public String getValue() {
return "notification";
}
},///通知:消息送达到用户设备后,由友盟SDK接管处理并在通知栏上显示通知内容。
MESSAGE {
public String getValue() {
return "message";
}
};///消息:消息送达到用户设备后,消息内容透传给应用自身进行解析处理。
public abstract String getValue();
}
public enum AfterOpenAction {
go_app,//打开应用
go_url,//跳转到URL
go_activity,//打开特定的activity
go_custom//用户自定义内容。
}
}
package com.jumeirah.common.push;
public class App {
}
package com.jumeirah.common.push;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.HashSet;
public abstract class IOSNotification extends UmengNotification {
// Keys can be set in the aps level
protected static final HashSet<String> APS_KEYS = new HashSet<String>(Arrays.asList("alert", "badge", "sound", "content-available"));
@Override
public boolean setPredefinedKeyValue(String key, Object value) throws Exception {
if (ROOT_KEYS.contains(key)) {
// This key should be in the root level
rootJson.put(key, value);
} else if (APS_KEYS.contains(key)) {
// This key should be in the aps level
JSONObject apsJson = null;
JSONObject payloadJson = null;
if (rootJson.has("payload")) {
payloadJson = rootJson.getJSONObject("payload");
} else {
payloadJson = new JSONObject();
rootJson.put("payload", payloadJson);
}
if (payloadJson.has("aps")) {
apsJson = payloadJson.getJSONObject("aps");
} else {
apsJson = new JSONObject();
payloadJson.put("aps", apsJson);
}
apsJson.put(key, value);
} else if (POLICY_KEYS.contains(key)) {
// This key should be in the body level
JSONObject policyJson = null;
if (rootJson.has("policy")) {
policyJson = rootJson.getJSONObject("policy");
} else {
policyJson = new JSONObject();
rootJson.put("policy", policyJson);
}
policyJson.put(key, value);
} else {
if (key == "payload" || key == "aps" || key == "policy") {
throw new Exception("You don't need to set value for " + key + " , just set values for the sub keys in it.");
} else {
throw new Exception("Unknownd key: " + key);
}
}
return true;
}
// Set customized key/value for IOS notification
public boolean setCustomizedField(String key, String value) throws Exception {
//rootJson.put(key, value);
JSONObject payloadJson = null;
if (rootJson.has("payload")) {
payloadJson = rootJson.getJSONObject("payload");
} else {
payloadJson = new JSONObject();
rootJson.put("payload", payloadJson);
}
payloadJson.put(key, value);
return true;
}
public void setAlert(String token) throws Exception {
setPredefinedKeyValue("alert", token);
}
public void setAlert(String title, String subtitle, String body) throws Exception {
JSONObject object = new JSONObject();
object.put("title", title);
object.put("subtitle", subtitle);
object.put("body", body);
setPredefinedKeyValue("alert", object);
}
public void setBadge(Integer badge) throws Exception {
setPredefinedKeyValue("badge", badge);
}
public void setSound(String sound) throws Exception {
setPredefinedKeyValue("sound", sound);
}
public void setContentAvailable(Integer contentAvailable) throws Exception {
setPredefinedKeyValue("content-available", contentAvailable);
}
}
package com.jumeirah.common.push;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class PushClient {
// The host
protected static final String host = "http://msg.umeng.com";
// The upload path
protected static final String uploadPath = "/upload";
// The post path
protected static final String postPath = "/api/send";
// The user agent
protected final String USER_AGENT = "Mozilla/5.0";
// This object is used for sending the post request to Umeng
protected HttpClient client = new DefaultHttpClient();
public boolean send(UmengNotification msg) throws Exception {
String timestamp = Integer.toString((int) (System.currentTimeMillis() / 1000));
msg.setPredefinedKeyValue("timestamp", timestamp);
String url = host + postPath;
String postBody = msg.getPostBody();
String sign = DigestUtils.md5Hex(("POST" + url + postBody + msg.getAppMasterSecret()).getBytes(StandardCharsets.UTF_8));
url = url + "?sign=" + sign;
HttpPost post = new HttpPost(url);
post.setHeader("User-Agent", USER_AGENT);
StringEntity se = new StringEntity(postBody, "UTF-8");
post.setEntity(se);
// Send the post request and get the response
HttpResponse response = client.execute(post);
int status = response.getStatusLine().getStatusCode();
System.out.println("Response Code : " + status);
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
if (status == 200) {
System.out.println("Notification sent successfully.");
} else {
System.out.println("Failed to send the notification!");
}
return true;
}
// Upload file with device_tokens to Umeng
public String uploadContents(String appkey, String appMasterSecret, String contents) throws Exception {
// Construct the json string
JSONObject uploadJson = new JSONObject();
uploadJson.put("appkey", appkey);
String timestamp = Integer.toString((int) (System.currentTimeMillis() / 1000));
uploadJson.put("timestamp", timestamp);
uploadJson.put("content", contents);
// Construct the request
String url = host + uploadPath;
String postBody = uploadJson.toString();
String sign = DigestUtils.md5Hex(("POST" + url + postBody + appMasterSecret).getBytes(StandardCharsets.UTF_8));
url = url + "?sign=" + sign;
HttpPost post = new HttpPost(url);
post.setHeader("User-Agent", USER_AGENT);
StringEntity se = new StringEntity(postBody, "UTF-8");
post.setEntity(se);
// Send the post request and get the response
HttpResponse response = client.execute(post);
System.out.println("Response Code : " + response.getStatusLine().getStatusCode());
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
// Decode response string and get file_id from it
JSONObject respJson = new JSONObject(result.toString());
String ret = respJson.getString("ret");
if (!ret.equals("SUCCESS")) {
throw new Exception("Failed to upload file");
}
JSONObject data = respJson.getJSONObject("data");
String fileId = data.getString("file_id");
// Set file_id into rootJson using setPredefinedKeyValue
return fileId;
}
}
package com.jumeirah.common.push;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.HashSet;
public abstract class UmengNotification {
// Keys can be set in the root level
protected static final HashSet<String> ROOT_KEYS = new HashSet<String>(Arrays.asList("appkey", "timestamp", "type", "device_tokens", "alias", "alias_type", "file_id",
"filter", "production_mode", "feedback", "description", "thirdparty_id", "mipush", "mi_activity", "channel_properties"));
// Keys can be set in the policy level
protected static final HashSet<String> POLICY_KEYS = new HashSet<String>(Arrays.asList("start_time", "expire_time", "max_send_num"));
// This JSONObject is used for constructing the whole request string.
protected final JSONObject rootJson = new JSONObject();
// The app master secret
protected String appMasterSecret;
// Set predefined keys in the rootJson, for extra keys(Android) or customized keys(IOS) please
// refer to corresponding methods in the subclass.
public abstract boolean setPredefinedKeyValue(String key, Object value) throws Exception;
public String getPostBody() {
return rootJson.toString();
}
protected final String getAppMasterSecret() {
return appMasterSecret;
}
public void setAppMasterSecret(String secret) {
appMasterSecret = secret;
}
protected void setProductionMode(Boolean prod) throws Exception {
setPredefinedKeyValue("production_mode", prod.toString());
}
///正式模式
public void setProductionMode() throws Exception {
setProductionMode(true);
}
///测试模式
public void setTestMode() throws Exception {
setProductionMode(false);
}
///发送消息描述,建议填写。
public void setDescription(String description) throws Exception {
setPredefinedKeyValue("description", description);
}
///定时发送时间,若不填写表示立即发送。格式: "YYYY-MM-DD hh:mm:ss"。
public void setStartTime(String startTime) throws Exception {
setPredefinedKeyValue("start_time", startTime);
}
///消息过期时间,格式: "YYYY-MM-DD hh:mm:ss"。
public void setExpireTime(String expireTime) throws Exception {
setPredefinedKeyValue("expire_time", expireTime);
}
///发送限速,每秒发送的最大条数。
public void setMaxSendNum(Integer num) throws Exception {
setPredefinedKeyValue("max_send_num", num);
}
//厂商弹窗activity
public void setChannelActivity(String activity) throws Exception {
setPredefinedKeyValue("mipush", "true");
setPredefinedKeyValue("mi_activity", activity);
}
//厂商属性配置
public void setChannelProperties(String xiaoMiChannelId) throws Exception {
JSONObject object = new JSONObject();
object.put("xiaomi_channel_id", xiaoMiChannelId);
setPredefinedKeyValue("channel_properties", object);
}
}
package com.jumeirah.common.push.android;
import com.jumeirah.common.push.AndroidNotification;
public class AndroidBroadcast extends AndroidNotification {
public AndroidBroadcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "broadcast");
}
}
package com.jumeirah.common.push.android;
import com.jumeirah.common.push.AndroidNotification;
public class AndroidCustomizedcast extends AndroidNotification {
public AndroidCustomizedcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "customizedcast");
}
public void setAlias(String alias, String aliasType) throws Exception {
setPredefinedKeyValue("alias", alias);
setPredefinedKeyValue("alias_type", aliasType);
}
public void setFileId(String fileId, String aliasType) throws Exception {
setPredefinedKeyValue("file_id", fileId);
setPredefinedKeyValue("alias_type", aliasType);
}
}
package com.jumeirah.common.push.android;
import com.jumeirah.common.push.AndroidNotification;
public class AndroidFilecast extends AndroidNotification {
public AndroidFilecast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "filecast");
}
public void setFileId(String fileId) throws Exception {
setPredefinedKeyValue("file_id", fileId);
}
}
\ No newline at end of file
package com.jumeirah.common.push.android;
import com.jumeirah.common.push.AndroidNotification;
import org.json.JSONObject;
public class AndroidGroupcast extends AndroidNotification {
public AndroidGroupcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "groupcast");
}
public void setFilter(JSONObject filter) throws Exception {
setPredefinedKeyValue("filter", filter);
}
}
package com.jumeirah.common.push.android;
import com.jumeirah.common.push.AndroidNotification;
public class AndroidUnicast extends AndroidNotification {
public AndroidUnicast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "unicast");
}
public void setDeviceToken(String token) throws Exception {
setPredefinedKeyValue("device_tokens", token);
}
}
\ No newline at end of file
package com.jumeirah.common.push.ios;
import com.jumeirah.common.push.IOSNotification;
public class IOSBroadcast extends IOSNotification {
public IOSBroadcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "broadcast");
}
}
package com.jumeirah.common.push.ios;
import com.jumeirah.common.push.IOSNotification;
public class IOSCustomizedcast extends IOSNotification {
public IOSCustomizedcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "customizedcast");
}
public void setAlias(String alias, String aliasType) throws Exception {
setPredefinedKeyValue("alias", alias);
setPredefinedKeyValue("alias_type", aliasType);
}
public void setFileId(String fileId, String aliasType) throws Exception {
setPredefinedKeyValue("file_id", fileId);
setPredefinedKeyValue("alias_type", aliasType);
}
}
package com.jumeirah.common.push.ios;
import com.jumeirah.common.push.IOSNotification;
public class IOSFilecast extends IOSNotification {
public IOSFilecast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "filecast");
}
public void setFileId(String fileId) throws Exception {
setPredefinedKeyValue("file_id", fileId);
}
}
package com.jumeirah.common.push.ios;
import com.jumeirah.common.push.IOSNotification;
import org.json.JSONObject;
public class IOSGroupcast extends IOSNotification {
public IOSGroupcast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "groupcast");
}
public void setFilter(JSONObject filter) throws Exception {
setPredefinedKeyValue("filter", filter);
}
}
package com.jumeirah.common.push.ios;
import com.jumeirah.common.push.IOSNotification;
public class IOSUnicast extends IOSNotification {
public IOSUnicast(String appkey, String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "unicast");
}
public void setDeviceToken(String token) throws Exception {
setPredefinedKeyValue("device_tokens", token);
}
}
...@@ -3,6 +3,7 @@ package com.jumeirah.common.service; ...@@ -3,6 +3,7 @@ package com.jumeirah.common.service;
import com.jumeirah.common.entity.AppUser; import com.jumeirah.common.entity.AppUser;
import com.jumeirah.common.param.AppUserPageParam; import com.jumeirah.common.param.AppUserPageParam;
import com.jumeirah.common.param.app.AppSmsRegisterParam; import com.jumeirah.common.param.app.AppSmsRegisterParam;
import com.jumeirah.common.param.app.DeviceTokenParam;
import com.jumeirah.common.vo.AppUserQueryVo; import com.jumeirah.common.vo.AppUserQueryVo;
import com.jumeirah.common.vo.app.LoginAppUserTokenVo; import com.jumeirah.common.vo.app.LoginAppUserTokenVo;
import io.geekidea.springbootplus.framework.common.api.ApiResult; import io.geekidea.springbootplus.framework.common.api.ApiResult;
...@@ -63,6 +64,16 @@ public interface AppUserService extends BaseService<AppUser> { ...@@ -63,6 +64,16 @@ public interface AppUserService extends BaseService<AppUser> {
boolean updateAppUser(AppUser appUser) throws Exception; boolean updateAppUser(AppUser appUser) throws Exception;
/** /**
* 添加或修改推送token
*
* @param deviceTokenParam
* @param deviceType
* @return
* @throws Exception
*/
boolean updateDeviceToken(DeviceTokenParam deviceTokenParam, int deviceType) throws Exception;
/**
* 删除 * 删除
* *
* @param id * @param id
......
...@@ -6,6 +6,8 @@ import com.jumeirah.common.vo.MerchantQueryVo; ...@@ -6,6 +6,8 @@ import com.jumeirah.common.vo.MerchantQueryVo;
import io.geekidea.springbootplus.framework.common.service.BaseService; import io.geekidea.springbootplus.framework.common.service.BaseService;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
import java.util.List;
/** /**
* 航空公司商家表 服务类 * 航空公司商家表 服务类
* *
...@@ -59,4 +61,11 @@ public interface MerchantService extends BaseService<Merchant> { ...@@ -59,4 +61,11 @@ public interface MerchantService extends BaseService<Merchant> {
*/ */
Paging<MerchantQueryVo> getMerchantPageList(MerchantPageParam merchantPageParam) throws Exception; Paging<MerchantQueryVo> getMerchantPageList(MerchantPageParam merchantPageParam) throws Exception;
/**
* 获取全部商户
*
* @return
*/
List<Merchant> getMerchantList();
} }
...@@ -9,6 +9,7 @@ import com.jumeirah.common.enums.StateEnum; ...@@ -9,6 +9,7 @@ import com.jumeirah.common.enums.StateEnum;
import com.jumeirah.common.mapper.AppUserMapper; import com.jumeirah.common.mapper.AppUserMapper;
import com.jumeirah.common.param.AppUserPageParam; import com.jumeirah.common.param.AppUserPageParam;
import com.jumeirah.common.param.app.AppSmsRegisterParam; import com.jumeirah.common.param.app.AppSmsRegisterParam;
import com.jumeirah.common.param.app.DeviceTokenParam;
import com.jumeirah.common.service.AppUserService; import com.jumeirah.common.service.AppUserService;
import com.jumeirah.common.vo.AppUserQueryVo; import com.jumeirah.common.vo.AppUserQueryVo;
import com.jumeirah.common.vo.app.LoginAppUserTokenVo; import com.jumeirah.common.vo.app.LoginAppUserTokenVo;
...@@ -161,6 +162,23 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser> ...@@ -161,6 +162,23 @@ public class AppUserServiceImpl extends BaseServiceImpl<AppUserMapper, AppUser>
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@Override @Override
public boolean updateDeviceToken(DeviceTokenParam deviceTokenParam, int deviceType) throws Exception {
AppUser appUser = new AppUser();
appUser.setDeviceToken(deviceTokenParam.getDeviceToken());
appUser.setDeviceType(deviceType);
JwtToken jwtToken = (JwtToken) SecurityUtils.getSubject().getPrincipal();
appUser.setId(jwtToken.getUserId());
// 重置redis中的token
return this.updateAppUser(appUser);
}
@Transactional(rollbackFor = Exception.class)
@Override
public boolean deleteAppUser(Long id) throws Exception { public boolean deleteAppUser(Long id) throws Exception {
return super.removeById(id); return super.removeById(id);
} }
......
package com.jumeirah.common.service.impl; package com.jumeirah.common.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;
...@@ -16,6 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -16,6 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/** /**
* 航空公司商家表 服务实现类 * 航空公司商家表 服务实现类
* *
...@@ -59,4 +62,14 @@ public class MerchantServiceImpl extends BaseServiceImpl<MerchantMapper, Merchan ...@@ -59,4 +62,14 @@ public class MerchantServiceImpl extends BaseServiceImpl<MerchantMapper, Merchan
return new Paging<MerchantQueryVo>(iPage); return new Paging<MerchantQueryVo>(iPage);
} }
@Override
public List<Merchant> getMerchantList() {
return baseMapper.selectList(new QueryWrapper<Merchant>().lambda()
.eq(Merchant::getState, 1)
.eq(Merchant::getDeleted, 0)
.eq(Merchant::getAuditRegisterStatus, 1)
.orderByDesc(Merchant::getCreateTime));
}
} }
...@@ -14,6 +14,7 @@ import com.jumeirah.common.param.MerchantLoginParam; ...@@ -14,6 +14,7 @@ import com.jumeirah.common.param.MerchantLoginParam;
import com.jumeirah.common.param.MerchantUpdatePwdParam; import com.jumeirah.common.param.MerchantUpdatePwdParam;
import com.jumeirah.common.param.MerchantUserPageParam; import com.jumeirah.common.param.MerchantUserPageParam;
import com.jumeirah.common.service.MerchantPermissionService; import com.jumeirah.common.service.MerchantPermissionService;
import com.jumeirah.common.service.MerchantService;
import com.jumeirah.common.service.MerchantUserPermissionService; import com.jumeirah.common.service.MerchantUserPermissionService;
import com.jumeirah.common.service.MerchantUserService; import com.jumeirah.common.service.MerchantUserService;
import com.jumeirah.common.vo.LoginMerUserTokenVo; import com.jumeirah.common.vo.LoginMerUserTokenVo;
...@@ -207,10 +208,15 @@ public class MerchantUserServiceImpl extends BaseServiceImpl<MerchantUserMapper, ...@@ -207,10 +208,15 @@ public class MerchantUserServiceImpl extends BaseServiceImpl<MerchantUserMapper,
loginSysUserTokenVo.setToken(token); loginSysUserTokenVo.setToken(token);
loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo); loginSysUserTokenVo.setLoginSysUserVo(loginSysUserVo);
loginSysUserTokenVo.setIsAdmin(merchantUser.getIsAdmin()); loginSysUserTokenVo.setIsAdmin(merchantUser.getIsAdmin());
loginSysUserTokenVo.setMerchantId(merchantUser.getMcId());
loginSysUserTokenVo.setMerchantName(merchantService.getMerchantById(merchantUser.getMcId()).getName());
return ApiResult.ok(loginSysUserTokenVo); return ApiResult.ok(loginSysUserTokenVo);
} }
@Autowired
private MerchantService merchantService;
@Override @Override
public ApiResult<Boolean> updatePwd(MerchantUpdatePwdParam merchantUpdatePwdParam) throws Exception { public ApiResult<Boolean> updatePwd(MerchantUpdatePwdParam merchantUpdatePwdParam) throws Exception {
......
...@@ -40,6 +40,12 @@ public class LoginMerUserTokenVo implements LoginToken { ...@@ -40,6 +40,12 @@ public class LoginMerUserTokenVo implements LoginToken {
@ApiModelProperty("是否为管理员,0:普通,1:超级管理员") @ApiModelProperty("是否为管理员,0:普通,1:超级管理员")
private Integer isAdmin; private Integer isAdmin;
@ApiModelProperty("商户ID")
private Long merchantId;
@ApiModelProperty("商户name")
private String merchantName;
/** /**
* 登录用户对象 * 登录用户对象
*/ */
......
...@@ -47,6 +47,16 @@ ...@@ -47,6 +47,16 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId> <artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional> <optional>true</optional>
...@@ -115,7 +125,6 @@ ...@@ -115,7 +125,6 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
......
package com.ym.im.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* @Description 请求跨域的问题
* @Author hewei hwei1233@163.com
* @Date 2019-07-12
*/
@Configuration
public class MvcConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
// 原始请求的域名
corsConfiguration.addAllowedOrigin("*");
// 添加请求头字段Cache-Control, Expires, Content-Type等
corsConfiguration.addAllowedHeader("*");
// 服务器支持的所有跨域请求的方法('GET'、'POST')等
corsConfiguration.addAllowedMethod("*");
corsConfiguration.setAllowCredentials(true);
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//设置过滤条件
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
...@@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; ...@@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ym.im.entity.MsgBody; import com.ym.im.entity.MsgBody;
import com.ym.im.entity.Session; import com.ym.im.entity.Session;
import com.ym.im.entity.enums.ResultStatus; import com.ym.im.entity.enums.ResultStatus;
import com.ym.im.entity.model.SessionInfo; import com.ym.im.entity.SessionInfo;
import com.ym.im.service.SessionListService; import com.ym.im.service.SessionListService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
......
package com.ym.im.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* APP用户
*
* @author wei
* @since 2020-09-23
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "AppUser对象")
@AllArgsConstructor
@NoArgsConstructor
public class AppUser implements Serializable {
@ApiModelProperty("主键")
private Long id;
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("姓")
private String surname;
@ApiModelProperty("名")
private String name;
@ApiModelProperty("公司名")
private String companyName;
@ApiModelProperty("微信号")
private String wechat;
@ApiModelProperty("出生日期")
private String dateOfBirth;
@ApiModelProperty("昵称")
private String nickname;
@ApiModelProperty("密码")
private String password;
@ApiModelProperty("盐值")
private String salt;
@ApiModelProperty("手机号码")
private String phone;
@ApiModelProperty("手机区号")
private String phoneArea;
@ApiModelProperty("性别,0:女,1:男,默认1")
private Integer gender;
@ApiModelProperty("设备类型,1:安卓,2:ios")
private Integer deviceType;
@ApiModelProperty("头像")
private String head;
@ApiModelProperty("推送token")
private String deviceToken;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("状态,0:禁用,1:启用,2:锁定")
private Integer state;
@ApiModelProperty("部门id")
private Long departmentId;
@ApiModelProperty("角色id")
private Long roleId;
@ApiModelProperty("逻辑删除,0:未删除,1:已删除")
private Integer deleted;
@ApiModelProperty("版本")
private Integer version;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("修改时间")
private Date updateTime;
}
package com.ym.im.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author JJww
*/
@Data
@Accessors(chain = true)
public class DeviceTokenParam implements Serializable {
private String deviceToken;
@ApiModelProperty("设备类型,1:安卓,2:ios")
private Integer deviceType;
}
...@@ -64,6 +64,7 @@ public class JwtTokenRedisVo implements Serializable { ...@@ -64,6 +64,7 @@ public class JwtTokenRedisVo implements Serializable {
* 登录token * 登录token
*/ */
private String token; private String token;
/** /**
* 创建时间 * 创建时间
*/ */
......
...@@ -50,7 +50,7 @@ public class PullChatRecord implements Serializable { ...@@ -50,7 +50,7 @@ public class PullChatRecord implements Serializable {
private Integer pageSize = 20; private Integer pageSize = 20;
@ApiModelProperty(value = "总条数") @ApiModelProperty(value = "总条数")
private Long total; private Integer total;
@ApiModelProperty(value = "总页数") @ApiModelProperty(value = "总页数")
private Integer pages; private Integer pages;
......
package com.ym.im.entity.model; package com.ym.im.entity;
import com.ym.im.entity.Session; import com.ym.im.entity.Session;
import lombok.Data; import lombok.Data;
...@@ -15,4 +15,6 @@ public class SessionInfo extends Session { ...@@ -15,4 +15,6 @@ public class SessionInfo extends Session {
private Long recordId; private Long recordId;
private String latestRecord; private String latestRecord;
private Integer msgType;
} }
...@@ -4,6 +4,7 @@ import com.ym.im.entity.base.BaseSocketInfo; ...@@ -4,6 +4,7 @@ import com.ym.im.entity.base.BaseSocketInfo;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import java.util.HashSet; import java.util.HashSet;
...@@ -16,6 +17,7 @@ import java.util.Set; ...@@ -16,6 +17,7 @@ import java.util.Set;
*/ */
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class StaffSocketInfo extends BaseSocketInfo { public class StaffSocketInfo extends BaseSocketInfo {
...@@ -33,8 +35,6 @@ public class StaffSocketInfo extends BaseSocketInfo { ...@@ -33,8 +35,6 @@ public class StaffSocketInfo extends BaseSocketInfo {
this.userIds = userIds; this.userIds = userIds;
} }
public StaffSocketInfo() {
}
public StaffSocketInfo(Long staffId, Set<Long> userIds) { public StaffSocketInfo(Long staffId, Set<Long> userIds) {
this.staffId = staffId; this.staffId = staffId;
......
package com.ym.im.entity; package com.ym.im.entity;
import com.ym.im.entity.base.BaseSocketInfo; import com.ym.im.entity.base.BaseSocketInfo;
import com.ym.im.entity.model.PushToken;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
...@@ -19,15 +18,15 @@ import java.util.Set; ...@@ -19,15 +18,15 @@ import java.util.Set;
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
public class UserSocketInfo extends BaseSocketInfo { public class UserSocketInfo extends BaseSocketInfo {
private Long userId; private String col;
private Map<Long, Long> staffIds = new HashMap<>(); private Long userId;
private Set<Long> sessionList; private Set<Long> sessionList;
private PushToken pushToken; private DeviceTokenParam deviceTokenParam;
private String col; private Map<Long, Long> staffIds = new HashMap<>();
public Long getStaffId(Long merchantId) { public Long getStaffId(Long merchantId) {
return staffIds.get(merchantId); return staffIds.get(merchantId);
......
package com.ym.im.entity.model;
import lombok.Data;
/**
* @author xjx
* @Description
* @date 2019/11/18
*/
@Data
public class PushToken {
private String pushToken;
private String pushType;
}
...@@ -25,6 +25,9 @@ public class SingleChatFactory { ...@@ -25,6 +25,9 @@ public class SingleChatFactory {
* @return * @return
*/ */
public ChatService getService(String type) { public ChatService getService(String type) {
if (type == null) {
return null;
}
switch (RoleEnum.get(type)) { switch (RoleEnum.get(type)) {
case APP: case APP:
return userSingleChatServiceImpl; return userSingleChatServiceImpl;
......
package com.ym.im.handler; package com.ym.im.handler;
import com.ym.im.entity.base.ChannelAttributeKey; import com.ym.im.entity.base.ChannelAttributeKey;
import com.ym.im.exception.HttpException;
import com.ym.im.factory.SingleChatFactory; import com.ym.im.factory.SingleChatFactory;
import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
...@@ -21,21 +22,18 @@ public abstract class BaseHandler<T> extends SimpleChannelInboundHandler<T> { ...@@ -21,21 +22,18 @@ public abstract class BaseHandler<T> extends SimpleChannelInboundHandler<T> {
@Override @Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception { public void channelInactive(ChannelHandlerContext ctx) throws Exception {
try { final String roleType = ctx.channel().attr(ChannelAttributeKey.ROLE_TYPE).get();
singleChatFactory.getService(ctx.channel().attr(ChannelAttributeKey.ROLE_TYPE).get()).offline(ctx); if (roleType != null) {
} catch (Exception e) { singleChatFactory.getService(roleType).offline(ctx);
e.printStackTrace();
} }
} }
@Override @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
try { if (cause instanceof HttpException) {
singleChatFactory.getService(ctx.channel().attr(ChannelAttributeKey.ROLE_TYPE).get()).offline(ctx); return;
} catch (Exception e) {
e.printStackTrace();
} }
singleChatFactory.getService(ctx.channel().attr(ChannelAttributeKey.ROLE_TYPE).get()).offline(ctx);
} }
} }
...@@ -12,6 +12,7 @@ import io.netty.channel.ChannelHandler; ...@@ -12,6 +12,7 @@ import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.QueryStringDecoder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -36,27 +37,23 @@ import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; ...@@ -36,27 +37,23 @@ import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
@ChannelHandler.Sharable @ChannelHandler.Sharable
public class WebSocketHandshakerHandler extends BaseHandler<FullHttpRequest> { public class WebSocketHandshakerHandler extends BaseHandler<FullHttpRequest> {
@Resource(name = "myRedisTemplate")
private RedisTemplate redisTemplate;
@Autowired @Autowired
private ChannelGroupHandler channelGroup; private ChannelGroupHandler channelGroup;
@Autowired @Autowired
private SingleChatFactory singleChatFactory; private SingleChatFactory singleChatFactory;
@Resource(name = "myRedisTemplate") public static final String LOGIN_TOKEN = "login:token:%s";
private RedisTemplate redisTemplate;
public static final String AUTHORIZATION = "Authorization"; public static final String AUTHORIZATION = "Authorization";
/**
* 登录用户token信息key
* login:token:tokenMd5
*/
public static final String LOGIN_TOKEN = "login:token:%s";
@Override @Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception { protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
final String token = fullHttpRequest.headers().get(AUTHORIZATION); final String token = new QueryStringDecoder(fullHttpRequest.uri()).parameters().get(AUTHORIZATION).get(0);
Optional.ofNullable(token).orElseThrow(() -> new HttpException(ctx, fullHttpRequest, new DefaultFullHttpResponse(HTTP_1_1, UNAUTHORIZED))); Optional.ofNullable(token).orElseThrow(() -> new HttpException(ctx, fullHttpRequest, new DefaultFullHttpResponse(HTTP_1_1, UNAUTHORIZED)));
final JwtTokenRedisVo tokenInfoForRedis = this.getTokenInfoForRedis(token); final JwtTokenRedisVo tokenInfoForRedis = this.getTokenInfoForRedis(token);
Optional.ofNullable(tokenInfoForRedis).orElseThrow(() -> new HttpException(ctx, fullHttpRequest, new DefaultFullHttpResponse(HTTP_1_1, UNAUTHORIZED))); Optional.ofNullable(tokenInfoForRedis).orElseThrow(() -> new HttpException(ctx, fullHttpRequest, new DefaultFullHttpResponse(HTTP_1_1, UNAUTHORIZED)));
......
...@@ -22,7 +22,7 @@ public interface ChatRecordService { ...@@ -22,7 +22,7 @@ public interface ChatRecordService {
/** /**
* 聊天记录表数量 * 聊天记录表数量
*/ */
int NUMBER_OF_TABLE = 32; int NUMBER_OF_TABLE = 16;
@Validated({ChatRecordSaveGroup.class}) @Validated({ChatRecordSaveGroup.class})
int insert(ChatRecord chatRecord); int insert(ChatRecord chatRecord);
......
...@@ -7,6 +7,7 @@ import io.netty.channel.ChannelHandlerContext; ...@@ -7,6 +7,7 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
/** /**
* @author: JJww * @author: JJww
...@@ -20,7 +21,7 @@ public interface ChatService { ...@@ -20,7 +21,7 @@ public interface ChatService {
* @param ctx * @param ctx
* @return * @return
*/ */
void init(ChannelHandlerContext ctx); void init(ChannelHandlerContext ctx) throws IOException;
/** /**
......
...@@ -3,7 +3,7 @@ package com.ym.im.service; ...@@ -3,7 +3,7 @@ package com.ym.im.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.ym.im.entity.MsgBody; import com.ym.im.entity.MsgBody;
import com.ym.im.entity.Session; import com.ym.im.entity.Session;
import com.ym.im.entity.model.SessionInfo; import com.ym.im.entity.SessionInfo;
import java.util.List; import java.util.List;
......
...@@ -65,7 +65,7 @@ public class ChatRecordServiceImpl extends ServiceImpl<ChatRecordMapper, ChatRec ...@@ -65,7 +65,7 @@ public class ChatRecordServiceImpl extends ServiceImpl<ChatRecordMapper, ChatRec
final PageInfo<ChatRecord> pageInfo = new PageInfo<>(chatRecords); final PageInfo<ChatRecord> pageInfo = new PageInfo<>(chatRecords);
pull.setChatRecords(chatRecords); pull.setChatRecords(chatRecords);
pull.setPages(pageInfo.getPages()); pull.setPages(pageInfo.getPages());
pull.setTotal(pageInfo.getTotal()); pull.setTotal((int) pageInfo.getTotal());
return new MsgBody<PullChatRecord>().setCode(ResultStatus.SUCCESS.getCode()).setData(pull); return new MsgBody<PullChatRecord>().setCode(ResultStatus.SUCCESS.getCode()).setData(pull);
} }
......
...@@ -6,7 +6,7 @@ import com.ym.im.entity.ChatRecord; ...@@ -6,7 +6,7 @@ import com.ym.im.entity.ChatRecord;
import com.ym.im.entity.MsgBody; import com.ym.im.entity.MsgBody;
import com.ym.im.entity.Session; import com.ym.im.entity.Session;
import com.ym.im.entity.enums.ResultStatus; import com.ym.im.entity.enums.ResultStatus;
import com.ym.im.entity.model.SessionInfo; import com.ym.im.entity.SessionInfo;
import com.ym.im.mapper.SessionListMapper; import com.ym.im.mapper.SessionListMapper;
import com.ym.im.service.ChatRecordService; import com.ym.im.service.ChatRecordService;
import com.ym.im.service.SessionListService; import com.ym.im.service.SessionListService;
...@@ -34,8 +34,9 @@ public class SessionListServiceImpl extends ServiceImpl<SessionListMapper, Sessi ...@@ -34,8 +34,9 @@ public class SessionListServiceImpl extends ServiceImpl<SessionListMapper, Sessi
final List<SessionInfo> sessions = new ArrayList<>(); final List<SessionInfo> sessions = new ArrayList<>();
baseMapper.selectList(new QueryWrapper<Session>().lambda().eq(Session::getUserId, userId)).forEach(session -> { baseMapper.selectList(new QueryWrapper<Session>().lambda().eq(Session::getUserId, userId)).forEach(session -> {
final ChatRecord latestMsg = chatRecordService.getLatestMsg(userId, session.getMerchantId()); final ChatRecord latestMsg = chatRecordService.getLatestMsg(userId, session.getMerchantId());
final SessionInfo sessionModel = new SessionInfo().setLatestRecord(latestMsg.getMsgInfo()).setRecordId(latestMsg.getId()); final SessionInfo sessionModel = new SessionInfo().setLatestRecord(latestMsg.getMsgInfo()).setMsgType(latestMsg.getMsgType()).setRecordId(latestMsg.getId());
BeanUtils.copyProperties(session, sessionModel); BeanUtils.copyProperties(session, sessionModel);
sessionModel.setModifyTime(latestMsg.getCreateTime());//最后一条信息创建时间为呼叫列表更新时间
sessions.add(sessionModel); sessions.add(sessionModel);
}); });
return new MsgBody<List<SessionInfo>>().setCode(ResultStatus.SUCCESS.getCode()).setData(sessions); return new MsgBody<List<SessionInfo>>().setCode(ResultStatus.SUCCESS.getCode()).setData(sessions);
......
...@@ -28,11 +28,11 @@ public class StaffServiceImpl implements StaffService { ...@@ -28,11 +28,11 @@ public class StaffServiceImpl implements StaffService {
@Override @Override
public StaffSocketInfo getIdleStaff(Long merchantId, Long userId) { public StaffSocketInfo getIdleStaff(Long merchantId, Long userId) {
final Map<Long, StaffSocketInfo> socketInfoMap = channelGroup.STAFF_GROUP.get(merchantId); // final LinkedHashMap<Long, StaffSocketInfo> socketInfoMap = channelGroup.STAFF_GROUP.get(merchantId);
if (socketInfoMap == null) { // if (socketInfoMap == null || socketInfoMap.size() == 0) {
return null; // return null;
} // }
final LinkedHashMap<Long, StaffSocketInfo> collect = socketInfoMap final LinkedHashMap<Long, StaffSocketInfo> collect = channelGroup.STAFF_GROUP.get(merchantId)
.entrySet() .entrySet()
.stream() .stream()
.sorted(comparingByValue(new Comparator<StaffSocketInfo>() { .sorted(comparingByValue(new Comparator<StaffSocketInfo>() {
...@@ -81,7 +81,7 @@ public class StaffServiceImpl implements StaffService { ...@@ -81,7 +81,7 @@ public class StaffServiceImpl implements StaffService {
userSocketInfo.writeAndFlush(msgBody); userSocketInfo.writeAndFlush(msgBody);
//通知新客服 //通知新客服
staffSocketInfo.writeAndFlush(msgBody); staffSocketInfo.writeAndFlush(msgBody);
return new MsgBody<>().setData(ResultStatus.SUCCESS.getCode()); return new MsgBody<>().setCode(ResultStatus.SUCCESS.getCode());
} }
......
...@@ -86,7 +86,7 @@ public class StaffSingleChatServiceImpl implements ChatService { ...@@ -86,7 +86,7 @@ public class StaffSingleChatServiceImpl implements ChatService {
if (userIds.size() != 0) { if (userIds.size() != 0) {
final String userListKey = NettyConstant.STAFF_USERIDS_KEY + staffId; final String userListKey = NettyConstant.STAFF_USERIDS_KEY + staffId;
redisTemplate.delete(userListKey); redisTemplate.delete(userListKey);
redisTemplate.opsForSet().add(userListKey, userIds.toArray(new Long[userIds.size()])); redisTemplate.opsForSet().add(userListKey, userIds.toArray());
queue.staffOfflineQueue(new StaffSocketInfo(staffId, userIds)); //NioSocketChannel无法序列化 所以new StaffSocketInfo queue.staffOfflineQueue(new StaffSocketInfo(staffId, userIds)); //NioSocketChannel无法序列化 所以new StaffSocketInfo
} }
channelGroup.removeMerchantStaff(staffId); channelGroup.removeMerchantStaff(staffId);
......
...@@ -9,6 +9,7 @@ import com.ym.im.entity.base.NettyConstant; ...@@ -9,6 +9,7 @@ import com.ym.im.entity.base.NettyConstant;
import com.ym.im.entity.model.IdModel; import com.ym.im.entity.model.IdModel;
import com.ym.im.handler.ChannelGroupHandler; import com.ym.im.handler.ChannelGroupHandler;
import com.ym.im.service.*; import com.ym.im.service.*;
import com.ym.im.util.HttpClientUtils;
import com.ym.im.util.JsonUtils; import com.ym.im.util.JsonUtils;
import com.ym.im.validation.group.ChatRecordReceiveGroup; import com.ym.im.validation.group.ChatRecordReceiveGroup;
import com.ym.im.validation.group.ChatRecordSaveGroup; import com.ym.im.validation.group.ChatRecordSaveGroup;
...@@ -24,6 +25,7 @@ import org.springframework.validation.annotation.Validated; ...@@ -24,6 +25,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -56,21 +58,26 @@ public class UserSingleChatServiceImpl implements ChatService { ...@@ -56,21 +58,26 @@ public class UserSingleChatServiceImpl implements ChatService {
@Autowired @Autowired
private SessionListService sessiontListService; private SessionListService sessiontListService;
private static final String USER_INFO_URL = "http://192.168.1.237:8889/api/app/user/userInfo";
@Override @Override
public void init(ChannelHandlerContext ctx) { public void init(ChannelHandlerContext ctx) throws IOException {
final Long userId = ctx.channel().attr(ChannelAttributeKey.ROLE_ID).get(); final Long userId = ctx.channel().attr(ChannelAttributeKey.ROLE_ID).get();
UserSocketInfo userSocketInfo = new UserSocketInfo(); final String token = ctx.channel().attr(ChannelAttributeKey.TOKEN_INFO).get();
final UserSocketInfo userSocketInfo = new UserSocketInfo();
userSocketInfo.setUserId(userId); userSocketInfo.setUserId(userId);
userSocketInfo.setChannel((NioSocketChannel) ctx.channel()); userSocketInfo.setChannel((NioSocketChannel) ctx.channel());
userSocketInfo.setCol(ctx.channel().attr(ChannelAttributeKey.COL_INFO).get()); userSocketInfo.setCol(ctx.channel().attr(ChannelAttributeKey.COL_INFO).get());
userSocketInfo.setToken(ctx.channel().attr(ChannelAttributeKey.TOKEN_INFO).get()); userSocketInfo.setToken(token);
userSocketInfo.setPushToken(null);
userSocketInfo.setSessionList(this.getSessionList(userId)); userSocketInfo.setSessionList(this.getSessionList(userId));
Map<String, String> headers = new HashMap<>();
headers.put("token", token);
final AppUser appUser = JsonUtils.json2Obj(HttpClientUtils.doGet(USER_INFO_URL, null, headers), AppUser.class);//获取deviceToken
userSocketInfo.setDeviceTokenParam(new DeviceTokenParam().setDeviceToken(appUser.getDeviceToken()).setDeviceType(appUser.getDeviceType()));
channelGroup.USER_GROUP.put(userId, userSocketInfo); channelGroup.USER_GROUP.put(userId, userSocketInfo);
this.restoreBindingRelationship(userId); //恢复历史绑定关系 this.restoreBindingRelationship(userId); //恢复历史绑定关系
this.broadcastUserOnline(userId); //通知客服 用户上线 this.broadcastUserOnline(userId); //通知客服 用户上线
log.info("用户: " + userId + " 上线"); log.info("用户: " + userId + " 上线");
} }
...@@ -112,7 +119,7 @@ public class UserSingleChatServiceImpl implements ChatService { ...@@ -112,7 +119,7 @@ public class UserSingleChatServiceImpl implements ChatService {
// 服务用户的客服不在线 // 服务用户的客服不在线
if (staffSocketInfo == null) { if (staffSocketInfo == null) {
// Redis是否存在当前客服服务用户Set对象(TTL=60秒) // Redis是否存在当前客服服务用户Set对象(TTL=60秒)
Set members = redisTemplate.opsForSet().members(NettyConstant.STAFF_USERIDS_KEY + staffId); Set<Long> members = redisTemplate.opsForSet().members(NettyConstant.STAFF_USERIDS_KEY + staffId);
// 客服下线超过60秒,当前客服服务用户Set对象已过期,重新分配客服 // 客服下线超过60秒,当前客服服务用户Set对象已过期,重新分配客服
// 过期后set对象不会为空而是大小为0 // 过期后set对象不会为空而是大小为0
if (members.size() == 0) { if (members.size() == 0) {
...@@ -196,9 +203,9 @@ public class UserSingleChatServiceImpl implements ChatService { ...@@ -196,9 +203,9 @@ public class UserSingleChatServiceImpl implements ChatService {
*/ */
private void restoreBindingRelationship(Long userId) { private void restoreBindingRelationship(Long userId) {
if (redisTemplate.opsForHash().hasKey(NettyConstant.IM_USERS, userId)) { if (redisTemplate.opsForHash().hasKey(NettyConstant.IM_USERS, userId)) {
final HashMap staffs = (HashMap) redisTemplate.opsForHash().get(NettyConstant.IM_USERS, userId); final Map staffs = (HashMap<Long, Long>) redisTemplate.opsForHash().get(NettyConstant.IM_USERS, userId);
staffs.values().forEach(staffId -> { staffs.forEach((mid, staffId) -> {
final StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(Long.valueOf(staffId.toString())); final StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(Long.valueOf(mid.toString()), Long.valueOf(staffId.toString()));
if (staffSocketInfo != null) { if (staffSocketInfo != null) {
staffSocketInfo.getUserIds().add(userId); staffSocketInfo.getUserIds().add(userId);
} }
...@@ -214,11 +221,15 @@ public class UserSingleChatServiceImpl implements ChatService { ...@@ -214,11 +221,15 @@ public class UserSingleChatServiceImpl implements ChatService {
* @param userId * @param userId
*/ */
private void broadcastUserOnline(Long userId) { private void broadcastUserOnline(Long userId) {
channelGroup.USER_GROUP.get(userId).getStaffIds().forEach((merchantId, staffId) -> { final Map staffIds = channelGroup.USER_GROUP.get(userId).getStaffIds();
channelGroup.STAFF_GROUP.get(merchantId).values().forEach(staffSocketInfo -> { staffIds.forEach((merchantId, staffId) -> {
staffSocketInfo.getUserIds().remove(userId); final Map<Long, StaffSocketInfo> staffSocketInfoMap = channelGroup.STAFF_GROUP.get(Long.valueOf(merchantId.toString()));
staffSocketInfo.writeAndFlush(new MsgBody<>().setCode(MsgBody.USERS_ONLINE).setData(new IdModel().setStaffId(staffId).setUserId(userId))); if (staffSocketInfoMap != null) {
}); staffSocketInfoMap.values().forEach(staffSocketInfo -> {
staffSocketInfo.getUserIds().remove(userId);
staffSocketInfo.writeAndFlush(new MsgBody<>().setCode(MsgBody.USERS_ONLINE).setData(new IdModel().setStaffId(Long.valueOf(staffId.toString())).setUserId(userId)));
});
}
}); });
} }
......
package com.ym.im.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MimeTypeUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author 陈俊雄
* @since 2020/5/14
**/
@Slf4j
public abstract class HttpClientUtils {
private static final int TIMEOUT = 60;
private static final String UTF_8 = "UTF-8";
private static final BasicHeader BASIC_HEADER = new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-uriencoded; charset=utf-8");
public static final Map<String, String> JSON_HEADER = new HashMap<String, String>() {
{
put(HttpHeaders.CONTENT_TYPE, MimeTypeUtils.APPLICATION_JSON_VALUE);
}
};
/**
* 获取HttpClient
*
* @return CloseableHttpClient
*/
public static CloseableHttpClient getHttpClient() {
return HttpClients.createDefault();
}
public static void test() {
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", new SSLConnectionSocketFactory(SSLContexts.createSystemDefault()))
.build();
PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry);
HttpClients.custom().setConnectionManager(connManager);
}
/**
* 执行Post请求
*
* @param uri uri
* @param params 请求参数
* @return 请求结果
*/
public static String doPostForm(String uri, Map<String, String> params) {
return doPostForm(uri, params, null);
}
/**
* 执行Post请求
*
* @param uri uri
* @param params 请求参数
* @param headers 请求头信息
* @return 请求结果
*/
public static String doPostForm(String uri, Map<String, String> params, Map<String, String> headers) {
HttpPost httpPost = new HttpPost(uri);
setEntity(params, httpPost);
return send(getHttpClient(), httpPost, headers);
}
public static String doPostJson(String uri, String jsonString) {
return doPostJson(getHttpClient(), uri, jsonString, JSON_HEADER, UTF_8);
}
public static String doPostJson(String uri, String jsonString, Map<String, String> headers) {
HttpPost httpPost = new HttpPost(uri);
StringEntity stringEntity = new StringEntity(jsonString, UTF_8);
headers.forEach((k, v) -> stringEntity.setContentType(v));
httpPost.setEntity(stringEntity);
return send(getHttpClient(), httpPost, headers);
}
public static String doPostJson(CloseableHttpClient httpClient, String uri, String jsonString) {
return doPostJson(httpClient, uri, jsonString, JSON_HEADER, UTF_8);
}
public static String doPostJson(CloseableHttpClient httpClient, String uri, String jsonString, String encoding) {
return doPostJson(httpClient, uri, jsonString, JSON_HEADER, encoding);
}
public static String doPostJson(CloseableHttpClient httpClient, String uri, String jsonString, Map<String, String> headers, String encoding) {
HttpPost httpPost = new HttpPost(uri);
StringEntity stringEntity = new StringEntity(jsonString, encoding);
headers.forEach((k, v) -> stringEntity.setContentType(v));
httpPost.setEntity(stringEntity);
return send(httpClient, httpPost, headers);
}
/**
* 设置请求参数
*
* @param params 请求参数
* @param method Http请求
*/
private static void setEntity(Map<String, String> params, HttpEntityEnclosingRequestBase method) {
// 设置请求参数
if (params != null) {
List<NameValuePair> nameValuePairList = new ArrayList<>();
params.forEach((k, v) -> nameValuePairList.add(new BasicNameValuePair(k, v)));
try {
method.setEntity(new UrlEncodedFormEntity(nameValuePairList, UTF_8));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
/**
* 发送请求
*
* @param httpClient httpClient
* @param request request
* @param headers 请求头
* @return 请求字符串结果
*/
private static String send(CloseableHttpClient httpClient, HttpRequestBase request, Map<String, String> headers) {
// 设置请求头
if (!CollectionUtils.isEmpty(headers)) {
headers.forEach(request::setHeader);
} else {
request.setHeader(BASIC_HEADER);
}
// 设置超时时间
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(TIMEOUT * 1000)
.setConnectionRequestTimeout(TIMEOUT * 1000)
.setSocketTimeout(TIMEOUT * 1000).build();
request.setConfig(config);
// 获取请求返回消息
String result = null;
try {
// 执行请求
CloseableHttpResponse response = httpClient.execute(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
log.warn("Response status code:" + response.getStatusLine().getStatusCode());
}
// 获取请求返回消息
result = EntityUtils.toString(response.getEntity(), UTF_8);
response.close();
httpClient.close();
} catch (IOException e) {
log.error("Http client error:" + e.getMessage());
}
// 返回请求参数
return result;
}
public static String doGet(String uri) {
return doGet(uri, null, null);
}
public static String doGet(String uri, Map<String, Object> params) {
return doGet(uri, params, null);
}
public static String doGet(String uri, Map<String, Object> params, Map<String, String> headers) {
try {
final URIBuilder uriBuilder = new URIBuilder(new URI(uri));
uriBuilder.setCharset(StandardCharsets.UTF_8);
if (params != null && params.size() > 0) {
params.forEach((k, v) -> uriBuilder.addParameter(k, v.toString()));
}
final HttpGet httpGet = new HttpGet(uriBuilder.build());
return send(getHttpClient(), httpGet, headers);
} catch (URISyntaxException e) {
log.error("Uri解析错误:" + e.getMessage());
return null;
}
}
/**
* 发送multipart表单
*
* @param uri 请求路径
* @param params 表单体
* @param header 请求头
* @return resp
*/
public static String multipartUpload(String uri, Map<String, ContentBody> params, HashMap<String, String> header) {
final HttpPost httpPost = new HttpPost(uri);
// 设置请求体
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
params.forEach(builder::addPart);
final HttpEntity entity = builder.build();
httpPost.setEntity(entity);
// 执行请求
return send(getHttpClient(), httpPost, header);
}
}
...@@ -16,10 +16,11 @@ spring: ...@@ -16,10 +16,11 @@ spring:
max-wait: 60000 max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000 time-between-eviction-runs-millis: 60000
url: jdbc:mysql://127.0.0.1/customer_service?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai url: jdbc:mysql://127.0.0.1/customer_service?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
username: root username: root
password: 101020 password: 101020
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
connectionInitSqls: set names utf8mb4
jackson: jackson:
default-property-inclusion: non_null default-property-inclusion: non_null
rabbitmq: rabbitmq:
......
...@@ -16,10 +16,12 @@ spring: ...@@ -16,10 +16,12 @@ spring:
max-wait: 60000 max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000 time-between-eviction-runs-millis: 60000
url: jdbc:mysql://172.31.33.14:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai url: jdbc:mysql://172.31.33.14:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
username: root username: root
password: Yum123456 password: Yum123456
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
connectionInitSqls: set names utf8mb4
jackson: jackson:
default-property-inclusion: non_null default-property-inclusion: non_null
rabbitmq: rabbitmq:
......
...@@ -16,10 +16,12 @@ spring: ...@@ -16,10 +16,12 @@ spring:
max-wait: 60000 max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000 time-between-eviction-runs-millis: 60000
url: jdbc:mysql://192.168.1.237:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai url: jdbc:mysql://192.168.1.237:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
username: root username: root
password: 123456 password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver
connectionInitSqls: set names utf8mb4
jackson: jackson:
default-property-inclusion: non_null default-property-inclusion: non_null
rabbitmq: rabbitmq:
......
---
#开发环境
spring:
datasource:
# 数据库连接池配置
druid:
# 初始化时建立物理连接的个数
initial-size: 5
# 最大连接池数量
max-active: 10
# 用来检测连接是否有效的sql语句
validation-query: SELECT 1 FROM DUAL
# 最小连接池数量
min-idle: 5
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000
url: jdbc:mysql://47.99.47.225:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: temple123456
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
default-property-inclusion: non_null
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: admin
delay-queue-name: delay.ack.dev
staff-offline-Queue-Name: staff.offline.dev
exchange-name: delay.exchange.dev
listener:
simple:
default-requeue-rejected: false
redis:
database: 5
host: 127.0.0.1
password:
port: 6379
# (重要!)设置mvc默认语言为zh_CN,默认语言必须为static.i18n目录下有的语言配置文件,否则跟随服务器语言
mvc:
locale: zh_CN
devtools:
restart:
log-condition-evaluation-delta: false
---
#生产环境
spring:
datasource:
# 数据库连接池配置
druid:
# 初始化时建立物理连接的个数
initial-size: 5
# 最大连接池数量
max-active: 10
# 用来检测连接是否有效的sql语句
validation-query: SELECT 1 FROM DUAL
# 最小连接池数量
min-idle: 5
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000
url: jdbc:mysql://172.31.33.14:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: Yum123456
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
default-property-inclusion: non_null
rabbitmq:
host: 172.31.33.14
port: 5672
username: admin
password: Yum123456
delay-queue-name: delay.ack
staff-offline-Queue-Name: staff.offline
exchange-name: delayAck
listener:
simple:
default-requeue-rejected: false
redis:
database: 5
host: 172.31.33.14
password: Yum123456
port: 6379
# (重要!)设置mvc默认语言为zh_CN,默认语言必须为static.i18n目录下有的语言配置文件,否则跟随服务器语言
mvc:
locale: zh_CN
devtools:
restart:
log-condition-evaluation-delta: false
#日志配置
logging:
file: logs/${spring.application.name}.log
eureka:
client:
service-url:
defaultZone: http://172.31.41.108:20000/eureka/
instance:
prefer-ip-address: true
\ No newline at end of file
---
#开发环境
spring:
datasource:
# 数据库连接池配置
druid:
# 初始化时建立物理连接的个数
initial-size: 5
# 最大连接池数量
max-active: 10
# 用来检测连接是否有效的sql语句
validation-query: SELECT 1 FROM DUAL
# 最小连接池数量
min-idle: 5
# 获取连接时最大等待时间,单位毫秒
max-wait: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000
url: jdbc:mysql://192.168.1.237:3306/pathfinder_im?useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
jackson:
default-property-inclusion: non_null
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: admin
delay-queue-name: delay.ack.dev
staff-offline-Queue-Name: staff.offline.dev
exchange-name: delay.exchange.dev
listener:
simple:
default-requeue-rejected: false
redis:
database: 5
host: 127.0.0.1
password:
port: 6379
# (重要!)设置mvc默认语言为zh_CN,默认语言必须为static.i18n目录下有的语言配置文件,否则跟随服务器语言
mvc:
locale: zh_CN
devtools:
restart:
log-condition-evaluation-delta: false
spring:
profiles:
active: dev
application:
name: customer-service
# 404抛出异常
mvc:
throw-exception-if-no-handler-found: true
resources:
add-mappings: false
server:
port: 20002
# 关闭tomcat自带/error页面
error:
whitelabel:
enabled: false
netty:
port: 9095
#日志配置
logging:
level:
root: info
com.ym.im.mapper: debug
pagehelper:
helper-dialect: mysql
reasonable: true
support-methods-arguments: ture
params: count=contSql
<?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.ym.im.mapper.ChatRecordMapper">
<resultMap id="BaseResultMap" type="com.ym.im.entity.ChatRecord">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="user_id" jdbcType="BIGINT" property="userId"/>
<result column="staff_id" jdbcType="BIGINT" property="staffId"/>
<result column="msg_type" jdbcType="TINYINT" property="msgType"/>
<result column="msg_info" jdbcType="VARCHAR" property="msgInfo"/>
<result column="send_receive" jdbcType="TINYINT" property="sendReceive"/>
<result column="scope" jdbcType="TINYINT" property="scope"/>
<result column="send_time" jdbcType="TIMESTAMP" property="sendTime"/>
<result column="receive_time" jdbcType="TIMESTAMP" property="receiveTime"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="modify_time" jdbcType="TIMESTAMP" property="modifyTime"/>
</resultMap>
<sql id="Base_Column_List">
id, user_id, staff_id, msg_type, msg_info, send_receive, scope, send_time, receive_time, create_time, modify_time
</sql>
<insert id="insert">
INSERT INTO chat_record_${index} (<include refid="Base_Column_List"/>)
VALUES (
#{chat.id},
#{chat.userId},
#{chat.staffId},
#{chat.msgType},
#{chat.msgInfo},
#{chat.sendReceive},
#{chat.scope},
#{chat.sendTime},
#{chat.receiveTime},
#{chat.createTime},
#{chat.modifyTime})
</insert>
<insert id="insertSelective">
INSERT INTO chat_record_${index}
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="chat.id != null">
id,
</if>
<if test="chat.userId != null">
user_id,
</if>
<if test="chat.staffId != null">
staff_id,
</if>
<if test="chat.msgType != null">
msg_type,
</if>
<if test="chat.msgInfo != null">
msg_info,
</if>
<if test="chat.sendReceive != null">
send_receive,
</if>
<if test="chat.scope != null">
scope,
</if>
<if test="chat.sendTime != null">
send_time,
</if>
<if test="chat.receiveTime != null">
receive_time,
</if>
<if test="chat.createTime != null">
create_time,
</if>
<if test="chat.modifyTime != null">
modify_time,
</if>
</trim>
<trim prefix="VALUES (" suffix=")" suffixOverrides=",">
<if test="chat.id != null">
#{chat.id},
</if>
<if test="chat.userId != null">
#{chat.userId},
</if>
<if test="chat.staffId != null">
#{chat.staffId},
</if>
<if test="chat.msgType != null">
#{chat.msgType},
</if>
<if test="chat.msgInfo != null">
#{chat.msgInfo},
</if>
<if test="chat.sendReceive != null">
#{chat.sendReceive},
</if>
<if test="chat.scope != null">
#{chat.scope},
</if>
<if test="chat.sendTime != null">
#{chat.sendTime},
</if>
<if test="chat.receiveTime != null">
#{chat.receiveTime},
</if>
<if test="chat.createTime != null">
#{chat.createTime},
</if>
<if test="chat.modifyTime != null">
#{chat.modifyTime},
</if>
</trim>
</insert>
<update id="updateById">
UPDATE chat_record_${index}
SET user_id = #{chat.userId},
staff_id = #{chat.staffId},
msg_type = #{chat.msgType},
msg_info = #{chat.msgInfo},
send_receive = #{chat.sendReceive},
scope = #{chat.scope},
send_time = #{chat.sendTime},
receive_time = #{chat.receiveTime},
create_time = #{chat.createTime},
modify_time = #{chat.modifyTime}
WHERE id = #{chat.id}
</update>
<update id="updateByIdSelective">
UPDATE chat_record_${index}
<set>
<if test="chat.id != null">
#{chat.id}
</if>
<if test="chat.userId != null">
#{chat.userId}
</if>
<if test="chat.staffId != null">
#{chat.staffId}
</if>
<if test="chat.msgType != null">
#{chat.msgType}
</if>
<if test="chat.msgInfo != null">
#{chat.msgInfo}
</if>
<if test="chat.sendReceive != null">
#{chat.sendReceive}
</if>
<if test="chat.scope != null">
#{chat.scope}
</if>
<if test="chat.sendTime != null">
#{chat.sendTime}
</if>
<if test="chat.receiveTime != null">
#{chat.receiveTime}
</if>
<if test="chat.createTime != null">
#{chat.createTime}
</if>
<if test="chat.modifyTime != null">
#{chat.modifyTime}
</if>
</set>
</update>
<update id="updateBatchReceiveTimeById">
UPDATE chat_record_${index}
<set>
receive_time =
<foreach collection="chats" item="chat" index="index" separator=" " open="CASE" close="END">
WHEN id = #{chat.id} THEN #{chat.receiveTime}
</foreach>
</set>
WHERE id IN
<foreach collection="chats" item="chat" index="index" separator="," open="(" close=")">
#{chat.id}
</foreach>
</update>
<update id="updateReceiveTime">
UPDATE chat_record_${index}
<set>
receive_time = #{chat.receiveTime},
modify_time = #{chat.modifyTime}
</set>
WHERE id = #{chat.id}
</update>
<select id="selectById" resultType="com.ym.im.entity.ChatRecord">
SELECT
<include refid="Base_Column_List"/>
FROM chat_record_${index} WHERE id = #{id}
</select>
<select id="getChatRecord" resultType="com.ym.im.entity.ChatRecord">
SELECT
<include refid="Base_Column_List"/>
FROM chat_record_${index}
<trim prefix="WHERE" suffixOverrides="AND">
<if test="pull.userId != null">
user_id = #{pull.userId} AND
</if>
<if test="pull.direction == 'forward' and pull.chatRecordId != null">
--id小于传入id
id &lt; #{pull.chatRecordId}
</if>
<if test="pull.direction == 'backward' and pull.chatRecordId != null">
--id大于传入id
id &gt; #{pull.chatRecordId}
</if>
</trim>
</select>
</mapper>
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