Commit 550c8baf by lpx

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

parents 968c862b b21af718
package com.jumeirah.api.app.controller;
import com.jumeirah.common.entity.Merchant;
import com.jumeirah.common.service.MerchantService;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.log.annotation.OperationLog;
import io.geekidea.springbootplus.framework.log.enums.OperationLogType;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author: JJww
* @Date:2020/11/5
*/
@Slf4j
@RestController
@RequestMapping("/app/merchant")
@Api(value = "商户相关接口")
public class MerchantController {
@Autowired
private MerchantService merchantService;
/**
* 航空公司商家表
*/
@GetMapping("/list")
@OperationLog(name = "航空公司商家列表", type = OperationLogType.LIST)
@ApiOperation(value = "航空公司商家列表")
public ApiResult<List<Merchant>> getMerchantList() {
return ApiResult.ok(merchantService.getMerchantList());
}
}
...@@ -18,8 +18,6 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -18,8 +18,6 @@ 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.*; import org.springframework.web.bind.annotation.*;
import java.util.List;
/** /**
* 航空公司商家表 控制器 * 航空公司商家表 控制器
* *
...@@ -90,15 +88,6 @@ public class MerchantForSysController extends BaseController { ...@@ -90,15 +88,6 @@ 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());
}
} }
...@@ -83,4 +83,13 @@ public interface StrokeMapper extends BaseMapper<Stroke> { ...@@ -83,4 +83,13 @@ public interface StrokeMapper extends BaseMapper<Stroke> {
Page<StrokeQueryVo> page, @Param("param") McStrokePaymentPageParam mcStrokePaymentPageParam, Page<StrokeQueryVo> page, @Param("param") McStrokePaymentPageParam mcStrokePaymentPageParam,
@Param("mcId") Long mcId); @Param("mcId") Long mcId);
/**
* 查询行程明细
*
* @param id
* @return
*/
McStrokeQueryVo getStrokeInfo(@Param("mcId") Long mcId,@Param("id") Long id);
} }
...@@ -16,7 +16,6 @@ import com.jumeirah.common.vo.McStrokePaymentQueryVo; ...@@ -16,7 +16,6 @@ import com.jumeirah.common.vo.McStrokePaymentQueryVo;
import com.jumeirah.common.vo.McStrokeQueryVo; import com.jumeirah.common.vo.McStrokeQueryVo;
import com.jumeirah.common.vo.StrokeDetailVo; import com.jumeirah.common.vo.StrokeDetailVo;
import com.jumeirah.common.vo.StrokeQueryVo; import com.jumeirah.common.vo.StrokeQueryVo;
import com.rabbitmq.tools.json.JSONUtil;
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.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging; import io.geekidea.springbootplus.framework.core.pagination.Paging;
...@@ -48,7 +47,7 @@ public class StrokeServiceImpl extends BaseServiceImpl<StrokeMapper, Stroke> imp ...@@ -48,7 +47,7 @@ public class StrokeServiceImpl extends BaseServiceImpl<StrokeMapper, Stroke> imp
public boolean saveStroke(Stroke stroke) throws Exception { public boolean saveStroke(Stroke stroke) throws Exception {
final boolean save = super.save(stroke); final boolean save = super.save(stroke);
if (save) {//推送订单到客服系统 if (save) {//推送订单到客服系统
queue.pushOrder(JSON.toJSONString(stroke)); queue.pushOrder(JSON.toJSONString(baseMapper.getStrokeInfo(stroke.getMcId(), stroke.getId())));
} }
return save; return save;
} }
...@@ -126,5 +125,4 @@ public class StrokeServiceImpl extends BaseServiceImpl<StrokeMapper, Stroke> imp ...@@ -126,5 +125,4 @@ public class StrokeServiceImpl extends BaseServiceImpl<StrokeMapper, Stroke> imp
IPage<McStrokePaymentQueryVo> mcStrokePageList = strokeMapper.getPaymentPageList(page, mcStrokePaymentPageParam, jwtToken.getMcId()); IPage<McStrokePaymentQueryVo> mcStrokePageList = strokeMapper.getPaymentPageList(page, mcStrokePaymentPageParam, jwtToken.getMcId());
return new Paging<McStrokePaymentQueryVo>(mcStrokePageList); return new Paging<McStrokePaymentQueryVo>(mcStrokePageList);
} }
} }
...@@ -76,6 +76,11 @@ ...@@ -76,6 +76,11 @@
<select id="getStrokePageList" parameterType="com.jumeirah.common.param.StrokePageParam" <select id="getStrokePageList" parameterType="com.jumeirah.common.param.StrokePageParam"
resultType="com.jumeirah.common.vo.StrokeQueryVo"> resultType="com.jumeirah.common.vo.StrokeQueryVo">
select select
ctco.city_name_cn as city_outset_name,
ctco.airport_name_cn as outset_airport_name,
ctca.city_name_cn as city_arrive_name,
ctca.airport_name_cn as arrive_airport_name,
<include refid="Page_Column_List"/>
<choose> <choose>
<when test="language !='zh_CN'"> <when test="language !='zh_CN'">
ctco.city_name_en as city_outset_name, ctco.city_name_en as city_outset_name,
...@@ -111,6 +116,11 @@ ...@@ -111,6 +116,11 @@
<select id="getStrokePageListWithFinish" parameterType="com.jumeirah.common.param.StrokePageParam" <select id="getStrokePageListWithFinish" parameterType="com.jumeirah.common.param.StrokePageParam"
resultType="com.jumeirah.common.vo.StrokeQueryVo"> resultType="com.jumeirah.common.vo.StrokeQueryVo">
select select
ctco.city_name_cn as city_outset_name,
ctco.airport_name_cn as outset_airport_name,
ctca.city_name_cn as city_arrive_name,
ctca.airport_name_cn as arrive_airport_name,
<include refid="Page_Column_List"/>
<choose> <choose>
<when test="language !='zh_CN'"> <when test="language !='zh_CN'">
ctco.city_name_en as city_outset_name, ctco.city_name_en as city_outset_name,
...@@ -141,6 +151,14 @@ ...@@ -141,6 +151,14 @@
<select id="getMcStrokePageList" parameterType="com.jumeirah.common.param.McStrokePageParam" <select id="getMcStrokePageList" parameterType="com.jumeirah.common.param.McStrokePageParam"
resultType="com.jumeirah.common.vo.McStrokeQueryVo"> resultType="com.jumeirah.common.vo.McStrokeQueryVo">
SELECT SELECT
s.*,
ctco.city_name_cn as city_outset_name,
ctco.airport_name_cn as outset_airport_name,
ctca.city_name_cn as city_arrive_name,
ctca.airport_name_cn as arrive_airport_name,
CONCAT( au.surname, au.`name` ) AS applicant,
pt.name AS plain_type_name,
au.phone AS phone_number
s.id, s.id,
s.city_outset_id, s.city_outset_id,
s.deleted, s.deleted,
...@@ -185,6 +203,33 @@ ...@@ -185,6 +203,33 @@
pt.name AS plain_type_name, pt.name AS plain_type_name,
au.phone AS phone_number au.phone AS phone_number
FROM FROM
stroke s
LEFT JOIN app_user au ON au.id = s.user_id
LEFT JOIN plain_type pt ON pt.id = s.plain_type_id
INNER JOIN city_three_code ctco ON ctco.id = s.city_outset_id
INNER JOIN city_three_code ctca ON ctca.id = s.city_arrive_id
<where>
s.mc_id = #{mcId}
<if test="mcStrokePageParam.status != null and mcStrokePageParam.status != -1">
AND s.status = #{mcStrokePageParam.status}
</if>
<if test="mcStrokePageParam.type != null and mcStrokePageParam.type != -1">
AND s.type = #{mcStrokePageParam.type}
</if>
<if test="mcStrokePageParam.id != null and mcStrokePageParam.id != 0">
AND s.id = #{mcStrokePageParam.id}
</if>
<if test="mcStrokePageParam.startTime != null and mcStrokePageParam.startTime != ''">
AND s.create_time &gt;= #{mcStrokePageParam.startTime}
</if>
<if test="mcStrokePageParam.endTime != null and mcStrokePageParam.endTime != ''">
AND s.create_time &lt;= #{mcStrokePageParam.endTime}
</if>
<if test="mcStrokePageParam.applicant != null and mcStrokePageParam.applicant != ''">
AND CONCAT( au.surname, au.`name` ) LIKE CONCAT('%',#{mcStrokePageParam.applicant},'%')
</if>
</where>
ORDER BY s.create_time DESC
stroke s stroke s
LEFT JOIN app_user au ON au.id = s.user_id LEFT JOIN app_user au ON au.id = s.user_id
LEFT JOIN plain_type pt ON pt.id = s.plain_type_id LEFT JOIN plain_type pt ON pt.id = s.plain_type_id
...@@ -217,16 +262,16 @@ ...@@ -217,16 +262,16 @@
<select id="getPaymentPageList" parameterType="com.jumeirah.common.param.McStrokePaymentPageParam" <select id="getPaymentPageList" parameterType="com.jumeirah.common.param.McStrokePaymentPageParam"
resultType="com.jumeirah.common.vo.McStrokePaymentQueryVo"> resultType="com.jumeirah.common.vo.McStrokePaymentQueryVo">
SELECT SELECT
s.id, s.id,
s.type, s.type,
s.user_recharge_time, s.user_recharge_time,
s.payment_status, s.payment_status,
s.user_recharge_money, s.user_recharge_money,
s.payment_channel, s.payment_channel,
CONCAT( au.surname, au.`name` ) AS applicant, CONCAT( au.surname, au.`name` ) AS applicant,
au.phone AS phone_number au.phone AS phone_number
FROM FROM
stroke s stroke s
LEFT JOIN app_user au ON au.id = s.user_id LEFT JOIN app_user au ON au.id = s.user_id
<where> <where>
s.mc_id = #{mcId} s.mc_id = #{mcId}
...@@ -246,4 +291,57 @@ ...@@ -246,4 +291,57 @@
ORDER BY s.create_time DESC ORDER BY s.create_time DESC
</select> </select>
<select id="getStrokeInfo" resultType="com.jumeirah.common.vo.McStrokeQueryVo">
SELECT s.id,
s.city_outset_id,
s.deleted,
s.city_arrive_id,
s.people_num,
s.plain_type_id,
s.outset_time,
s.return_time,
s.type,
s.mc_id,
s.status,
s.create_time,
s.update_time,
s.goods_name,
s.goods_size,
s.goods_weight,
s.disease_name,
s.instruments,
s.medical_persons,
s.remarks,
s.money,
s.user_id,
s.arrive_plain_type_id,
s.back_outset_airport_name,
s.back_arrive_airport_name,
s.payment_status,
s.audit_status,
s.user_recharge_money,
s.user_recharge_bank,
s.user_recharge_name,
s.user_recharge_bank_number,
s.is_discount,
s.user_recharge_credentials_url,
ctco.city_name_cn as city_outset_name,
ctco.airport_name_cn as outset_airport_name,
ctca.city_name_cn as city_arrive_name,
ctca.airport_name_cn as arrive_airport_name,
CONCAT(au.surname, au.`name`) AS applicant,
pt.name AS plain_type_name,
au.phone AS phone_number
FROM stroke s
LEFT JOIN app_user au ON au.id = s.user_id
LEFT JOIN plain_type pt ON pt.id = s.plain_type_id
INNER JOIN city_three_code ctco ON ctco.id = s.city_outset_id
INNER JOIN city_three_code ctca ON ctca.id = s.city_arrive_id
where
s.id = #{id}
and s.mc_id = #{mcId}
</select>
</mapper> </mapper>
...@@ -121,6 +121,12 @@ ...@@ -121,6 +121,12 @@
<version>1.18.12</version> <version>1.18.12</version>
</dependency> </dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
......
...@@ -13,6 +13,7 @@ import java.io.Serializable; ...@@ -13,6 +13,7 @@ import java.io.Serializable;
@Accessors(chain = true) @Accessors(chain = true)
public class DeviceTokenParam implements Serializable { public class DeviceTokenParam implements Serializable {
@ApiModelProperty("推送Token")
private String deviceToken; private String deviceToken;
@ApiModelProperty("设备类型,1:安卓,2:ios") @ApiModelProperty("设备类型,1:安卓,2:ios")
private Integer deviceType; private Integer deviceType;
......
package com.ym.im.entity; package com.ym.im.entity;
import com.ym.im.validation.group.ChatRecordSaveGroup;
import com.ym.im.validation.group.ChatRecordSendGroup;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
import javax.validation.groups.Default;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
/** /**
* 行程表 * 行程表
...@@ -22,128 +14,18 @@ import java.util.Date; ...@@ -22,128 +14,18 @@ import java.util.Date;
@Data @Data
@Accessors(chain = true) @Accessors(chain = true)
public class Stroke implements Serializable { public class Stroke implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
private Long id; private Long id;
private String cityOutsetName;//起飞城市
@ApiModelProperty("出发城市id") private String cityArriveName;//到达城市
private Long cityOutsetId; private Long outsetTime;//起飞时间
private Long returnTime;//返程时间
@ApiModelProperty("逻辑删除,0:未删除,1:已删除") private int type;//行程类型 0-单程,1-往返行程,2-货运,3-医疗
private Integer deleted;
@ApiModelProperty("出发城市名称")
private String cityOutsetName;
@ApiModelProperty("到达城市id")
private Long cityArriveId;
@ApiModelProperty("到达城市名称")
private String cityArriveName;
@ApiModelProperty("人数")
private Integer peopleNum;
@ApiModelProperty("飞机型号ID")
private Long plainTypeId;
@ApiModelProperty("出发时间")
private Timestamp outsetTime;
@ApiModelProperty("返程时间")
private Timestamp returnTime;
@ApiModelProperty("行程类型,0-单程,1-往返行程,2-货运,3-医疗")
private Integer type;
@ApiModelProperty("状态,0-审核中,1-进行中,2-已完成,99-取消")
private Integer status;
@ApiModelProperty("创建时间")
private Timestamp createTime;
@ApiModelProperty("更新时间")
private Timestamp updateTime;
@ApiModelProperty("付款时间")
private Timestamp userRechargeTime;
@ApiModelProperty("货物名称")
private String goodsName;
@ApiModelProperty("货物体积(长*宽*高) 单位:CM,例如:100*102*120")
private String goodsSize;
@ApiModelProperty("货物重量,单位:吨")
private String goodsWeight;
@ApiModelProperty("病人疾病名称")
private String diseaseName;
@ApiModelProperty("病人病情诊断书")
private String medicalCertificateUrl;
@ApiModelProperty("配备器械(格式:1,2,3)逗号分隔")
private String instruments;
@ApiModelProperty("医护人员,0-医生,1-护士,2-护工(格式:0,1,2)逗号分隔")
private String medicalPersons;
@ApiModelProperty("备注")
private String remarks;
@ApiModelProperty("价格")
private BigDecimal money;
@ApiModelProperty("用户ID")
private Long userId; private Long userId;
@ApiModelProperty("出发机场名称")
private String outsetAirportName;
@ApiModelProperty("到达机场名称")
private String arriveAirportName;
@ApiModelProperty("返程飞机型号ID")
private Long arrivePlainTypeId;
@ApiModelProperty("返程出发机场名称")
private String backOutsetAirportName;
@ApiModelProperty("返程到达机场名称")
private String backArriveAirportName;
@ApiModelProperty("商家id")
private Long mcId; private Long mcId;
private String outsetAirportName;//出发机场名称
private String arriveAirportName;//到达机场名称
private String backOutsetAirportName;//返程出发机场名称
private String backArriveAirportName;//返程到达机场名称
private boolean isDiscount;//是否是优惠调机
@ApiModelProperty("用户选择机型")
private String choosePlainType;
@ApiModelProperty("付款状态,0-未付款,1-付款中,2-已付款,3-退款中,99-已退款")
private Integer paymentStatus;
@ApiModelProperty("审核状态,0审核中,1审核通过,2审核未通过")
private Integer auditStatus;
@ApiModelProperty("用户充值金额")
private BigDecimal userRechargeMoney;
@ApiModelProperty("用户充值银行名称")
private String userRechargeBank;
@ApiModelProperty("用户充值账户名")
private String userRechargeName;
@ApiModelProperty("用户充值卡号")
private String userRechargeBankNumber;
@ApiModelProperty("用户充值截图证据, 传入数组")
private String userRechargeCredentialsUrl;
@ApiModelProperty("是否是优惠调机,0-否,1-是")
private Boolean isDiscount;
@ApiModelProperty(value = "发送时间")
private Date sendTime;
} }
package com.ym.im.factory;
import com.ym.im.service.PushService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author: JJww
* @Date:2020/11/5
*/
@Component
public class PushFactory {
@Autowired
private PushService umengIosPushServiceImpl;
@Autowired
private PushService umengAndroidPushServiceImpl;
/**
* 创建对应实现类
*
* @param type
* @return
*/
public PushService getService(Integer type) {
switch (type) {
case 1:
return umengAndroidPushServiceImpl;
case 2:
return umengIosPushServiceImpl;
default:
return null;
}
}
}
...@@ -25,17 +25,15 @@ public class SingleChatFactory { ...@@ -25,17 +25,15 @@ 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;
case merchant: case merchant:
return staffSingleChatServiceImpl; return staffSingleChatServiceImpl;
default: default:
return null;
} }
return null;
} }
} }
......
package com.ym.im.mq; package com.ym.im.mq;
import com.ym.im.entity.MsgBody; import com.ym.im.entity.*;
import com.ym.im.entity.StaffSocketInfo;
import com.ym.im.entity.Stroke;
import com.ym.im.entity.UserSocketInfo;
import com.ym.im.entity.base.NettyConstant; 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.ChatService;
import com.ym.im.service.StaffService; import com.ym.im.service.StaffService;
import com.ym.im.util.JsonUtils; import com.ym.im.util.JsonUtils;
import lombok.SneakyThrows; import lombok.SneakyThrows;
...@@ -28,9 +26,6 @@ import java.util.Set; ...@@ -28,9 +26,6 @@ import java.util.Set;
@Component @Component
public class Receiver { public class Receiver {
@Autowired
private Queue queue;
@Resource(name = "myRedisTemplate") @Resource(name = "myRedisTemplate")
private RedisTemplate redisTemplate; private RedisTemplate redisTemplate;
...@@ -40,6 +35,9 @@ public class Receiver { ...@@ -40,6 +35,9 @@ public class Receiver {
@Autowired @Autowired
private ChannelGroupHandler channelGroup; private ChannelGroupHandler channelGroup;
@Autowired
private ChatService staffSingleChatServiceImpl;
@RabbitListener(queues = "#{staffOfflineQueue.name}") @RabbitListener(queues = "#{staffOfflineQueue.name}")
public void offlineHandler(StaffSocketInfo staffSocketInfo) { public void offlineHandler(StaffSocketInfo staffSocketInfo) {
...@@ -67,7 +65,7 @@ public class Receiver { ...@@ -67,7 +65,7 @@ public class Receiver {
/** /**
* 订单相关处理 * 订单相关处理
* *
* @param orderModel * @param json
*/ */
@SneakyThrows @SneakyThrows
@RabbitListener(queues = "#{orderQueue.name}") @RabbitListener(queues = "#{orderQueue.name}")
...@@ -80,9 +78,10 @@ public class Receiver { ...@@ -80,9 +78,10 @@ public class Receiver {
if (userSocketInfo == null) { if (userSocketInfo == null) {
return; return;
} }
stroke.setSendTime(new Date());
final MsgBody<Stroke> orderInfo = new MsgBody<Stroke>().setCode(MsgBody.ORDER).setData(stroke);
final StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(userSocketInfo.getStaffId(stroke.getMcId())) == null ? staffService.getIdleStaff(mcId, userId) : channelGroup.getMerchantStaff(userSocketInfo.getStaffId(stroke.getMcId())); final StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(userSocketInfo.getStaffId(stroke.getMcId())) == null ? staffService.getIdleStaff(mcId, userId) : channelGroup.getMerchantStaff(userSocketInfo.getStaffId(stroke.getMcId()));
final ChatRecord chatRecord = new ChatRecord().setMsgInfo(json).setUserId(userId).setSendTime(new Date()).setMsgType(MsgBody.ORDER);
final MsgBody<ChatRecord> orderInfo = new MsgBody<ChatRecord>().setCode(MsgBody.ORDER).setData(chatRecord);
staffSingleChatServiceImpl.save(staffSocketInfo.getStaffId(), orderInfo);
if (staffSocketInfo != null) { if (staffSocketInfo != null) {
staffSocketInfo.writeAndFlush(orderInfo); staffSocketInfo.writeAndFlush(orderInfo);
log.info("客服订单: " + "给客服(" + staffSocketInfo.getStaffId() + ")发送订单:" + json); log.info("客服订单: " + "给客服(" + staffSocketInfo.getStaffId() + ")发送订单:" + json);
......
package com.ym.im.push.umeng;
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 org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* @author JJww
*/
@Component
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.ym.im.push.umeng;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.HashSet;
@Component
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.ym.im.push.umeng.android;
import com.ym.im.push.umeng.UmengNotification;
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.ym.im.push.umeng.ios;
import com.ym.im.push.umeng.UmengNotification;
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);
}
}
...@@ -15,7 +15,21 @@ import javax.validation.constraints.NotNull; ...@@ -15,7 +15,21 @@ import javax.validation.constraints.NotNull;
**/ **/
public interface MsgBodyService { public interface MsgBodyService {
/**
* 消息流程处理器
*
* @param ctx
* @param msgBody
* @throws JsonProcessingException
*/
void msgBodyHandle(@NotNull ChannelHandlerContext ctx, @Valid MsgBody<ChatRecord> msgBody) throws JsonProcessingException; void msgBodyHandle(@NotNull ChannelHandlerContext ctx, @Valid MsgBody<ChatRecord> msgBody) throws JsonProcessingException;
/**
* 发送与回执
*
* @param channel
* @param msgBody
* @throws JsonProcessingException
*/
void sendAndAck(NioSocketChannel channel, MsgBody<ChatRecord> msgBody) throws JsonProcessingException; void sendAndAck(NioSocketChannel channel, MsgBody<ChatRecord> msgBody) throws JsonProcessingException;
} }
package com.ym.im.service;
/**
* @author: JJww
* @Date:2020/11/5
*/
public interface PushService {
/**
* 单播
*
* @param deviceToken
*/
void unicast(String deviceToken);
}
...@@ -2,13 +2,11 @@ package com.ym.im.service.impl; ...@@ -2,13 +2,11 @@ package com.ym.im.service.impl;
import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.ym.im.entity.ChatRecord; import com.ym.im.entity.*;
import com.ym.im.entity.MsgBody;
import com.ym.im.entity.StaffSocketInfo;
import com.ym.im.entity.UserSocketInfo;
import com.ym.im.entity.base.ChannelAttributeKey; import com.ym.im.entity.base.ChannelAttributeKey;
import com.ym.im.entity.base.NettyConstant; 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.factory.PushFactory;
import com.ym.im.handler.ChannelGroupHandler; import com.ym.im.handler.ChannelGroupHandler;
import com.ym.im.mq.Queue; import com.ym.im.mq.Queue;
import com.ym.im.service.ChatRecordService; import com.ym.im.service.ChatRecordService;
...@@ -18,6 +16,7 @@ import com.ym.im.util.JsonUtils; ...@@ -18,6 +16,7 @@ import com.ym.im.util.JsonUtils;
import com.ym.im.validation.group.*; import com.ym.im.validation.group.*;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.SneakyThrows;
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.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
...@@ -57,10 +56,8 @@ public class StaffSingleChatServiceImpl implements ChatService { ...@@ -57,10 +56,8 @@ public class StaffSingleChatServiceImpl implements ChatService {
@Autowired @Autowired
private ChannelGroupHandler channelGroup; private ChannelGroupHandler channelGroup;
@Autowired
// @Autowired private PushFactory pushFactory;
// private PushGatherService pushService;
@Override @Override
public void init(ChannelHandlerContext ctx) { public void init(ChannelHandlerContext ctx) {
...@@ -182,24 +179,15 @@ public class StaffSingleChatServiceImpl implements ChatService { ...@@ -182,24 +179,15 @@ public class StaffSingleChatServiceImpl implements ChatService {
* *
* @param userId * @param userId
*/ */
@SneakyThrows
private void pushNotifications(Long userId) { private void pushNotifications(Long userId) {
final UserSocketInfo userSocketInfo = channelGroup.USER_GROUP.get(userId);
if (userSocketInfo != null) {
final DeviceTokenParam deviceTokenParam = userSocketInfo.getDeviceTokenParam();
pushFactory.getService(deviceTokenParam.getDeviceType()).unicast(deviceTokenParam.getDeviceToken());
}
}
// String title = null;
// String content = null;
// final UserSocketInfo userSocketInfo = ChannelGroupService.USER_GROUP.get(userId);
// PushTokenAndTypeModel pushToken = userSocketInfo != null ? userSocketInfo.getPushToken() : feignClientUsersService.getPushToken(String.valueOf(userId)).getData();
// final String col = userSocketInfo == null ? LanguageEnum.zh.getKey() : userSocketInfo.getCol();
// if (LanguageEnum.zh.getKey().equals(col)) {
// title = PushTitleEnum.customerService.getName();
// content = PushContentEnum.sndmsg.getName();
// } else {
// title = PushTitleEnum.customerService.getNameEnglish();
// content = PushContentEnum.sndmsg.getNameEnglish();
// }
// Map customBoundary = new HashMap<>();
// customBoundary.put("pushType", PushTypeEnum.customerServicePush.getKey());
// pushService.pushTokenGather(pushToken.getPushToken(), pushToken.getPushType(), title, content, customBoundary);
} }
}
\ No newline at end of file
package com.ym.im.service.impl;
import com.ym.im.push.umeng.PushClient;
import com.ym.im.push.umeng.android.AndroidNotification;
import com.ym.im.service.PushService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author: JJww
* @Date:2020/11/5
*/
@Component
public class UmengAndroidPushServiceImpl extends AndroidNotification implements PushService {
@Autowired
private PushClient pushClient;
private static final String APP_KEY = "5f963f3ea1491772a2aef713";
private static final String APP_MASTER_SECRET = "ti5gomxtvmkgehmwgtbq9rtsfhy0khsi";
@PostConstruct
public void init() throws Exception {
setAppMasterSecret(APP_MASTER_SECRET);
setPredefinedKeyValue("appkey", APP_KEY);
}
@Override
@SneakyThrows
public void unicast(String deviceToken) {
this.setTitle("您有一条新信息");
this.setText("");
this.goAppAfterOpen();
this.setPredefinedKeyValue("device_tokens", deviceToken);
this.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
this.setProductionMode();
this.setExtraField("pushType", "1");//自定义字段 推送类型:客服消息
this.setPredefinedKeyValue("type", "unicast");//单播
pushClient.send(this);
}
}
package com.ym.im.service.impl;
import com.ym.im.push.umeng.PushClient;
import com.ym.im.push.umeng.ios.IOSNotification;
import com.ym.im.service.PushService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author: JJww
* @Date:2020/11/5
*/
@Component
public class UmengIosPushServiceImpl extends IOSNotification implements PushService {
@Autowired
private PushClient pushClient;
private static final String APP_KEY = "5f963f3ea1491772a2aef713";
private static final String APP_MASTER_SECRET = "ti5gomxtvmkgehmwgtbq9rtsfhy0khsi";
@PostConstruct
public void init() throws Exception {
setAppMasterSecret(APP_MASTER_SECRET);
setPredefinedKeyValue("appkey", APP_KEY);
}
@Override
@SneakyThrows
public void unicast(String deviceToken) {
this.setAlert("您有一条新信息");
this.setBadge(0);
this.setSound("default");
this.setProductionMode();
this.setPredefinedKeyValue("device_tokens", deviceToken);
this.setCustomizedField("pushType", "1");//自定义字段 推送类型:客服消息
this.setPredefinedKeyValue("type", "unicast");
pushClient.send(this);
}
}
...@@ -113,6 +113,7 @@ public class UserSingleChatServiceImpl implements ChatService { ...@@ -113,6 +113,7 @@ public class UserSingleChatServiceImpl implements ChatService {
if (staffId == null) { if (staffId == null) {
staffSocketInfo = staffService.getIdleStaff(merchantId, id); staffSocketInfo = staffService.getIdleStaff(merchantId, id);
if (staffSocketInfo == null) { if (staffSocketInfo == null) {
log.info("当前没有客服在线! ");
return null; return null;
} }
} else { } else {
......
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