netty-确定客户端和服务端编解码工具
This commit is contained in:
11
api/pom.xml
11
api/pom.xml
@@ -18,20 +18,15 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.10.Final</version>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>netty-model</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>6.0.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -39,8 +39,8 @@ public class MemberLessonTickerOrderTask {
|
||||
/**
|
||||
* 每30秒执行一次订单查看
|
||||
*/
|
||||
@Scheduled(fixedDelay = 30000)
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
// @Scheduled(fixedDelay = 30000)
|
||||
// @Transactional(rollbackFor = Exception.class)
|
||||
public void execute(){
|
||||
// 查询所有未支付订单
|
||||
List<MemberLessonTicket> memberLessonTickets = memberLessonTicketService.findOrders();
|
||||
|
||||
@@ -27,8 +27,6 @@ public class Constant {
|
||||
*/
|
||||
public static AttributeKey<ChannelParam> CHANNEL_PARAM = AttributeKey.newInstance("CHANNEL_PARAM");
|
||||
|
||||
public final static String DELIMITER_WORD = "$_$";
|
||||
|
||||
public final static String SPIT_WORD = "#";
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package com.sv.netty.controller;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
import com.sv.entity.Venue;
|
||||
import com.sv.netty.config.Constant;
|
||||
import com.sv.netty.netty.message.MessageDTO;
|
||||
import com.sv.netty.netty.message.MessageType;
|
||||
import com.sv.netty.netty.service.MessageService;
|
||||
import com.sv.service.api.QRCodeService;
|
||||
import com.ydd.framework.core.common.dto.ResponseDTO;
|
||||
import com.ydd.framework.core.controller.BaseApiController;
|
||||
import com.ydd.framework.core.exception.ServiceException;
|
||||
import io.netty.channel.Channel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -20,56 +16,54 @@ import javax.annotation.Resource;
|
||||
/**
|
||||
* 小程序二维码进场Controller
|
||||
*/
|
||||
//@RestController
|
||||
@RestController
|
||||
public class QREnterController extends BaseApiController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(QREnterController.class);
|
||||
// @Resource
|
||||
@Resource
|
||||
private QRCodeService qrCodeService;
|
||||
// @Resource
|
||||
@Resource
|
||||
private MessageService messageService;
|
||||
/**
|
||||
* 进场指令发布
|
||||
*/
|
||||
// @RequestMapping(value = "/qrCode/enter", method = RequestMethod.GET)
|
||||
// public ResponseDTO enter(@RequestParam("deviceId") String deviceId) {
|
||||
// Integer memberId = getMemberIdByAccessToken();
|
||||
// Integer venueId = getVenueId(deviceId);
|
||||
// String deviceName = getDeviceName(deviceId);
|
||||
// DeviceType enterOrOut = getEnterOrOut(deviceId);
|
||||
// Venue venue = qrCodeService.initEnter(venueId, deviceName,enterOrOut,memberId);
|
||||
// qrCodeService.unBindMember(venueId, deviceName, enterOrOut);
|
||||
// if (venue!=null){
|
||||
// if (DeviceType.OUT == enterOrOut){
|
||||
// // 出场
|
||||
// messageService.outVenue(deviceName,venueId,memberId,venue);
|
||||
// }else{
|
||||
// // 进场
|
||||
// messageService.enterVenue(deviceName,venueId,memberId,venue);
|
||||
// }
|
||||
// }
|
||||
// return ResponseDTO.ok();
|
||||
// }
|
||||
@RequestMapping(value = "/qrCode/enter", method = RequestMethod.GET)
|
||||
public ResponseDTO enter(@RequestParam("deviceId") String deviceId) {
|
||||
Integer memberId = getMemberIdByAccessToken();
|
||||
Integer venueId = getVenueId(deviceId);
|
||||
String deviceName = getDeviceName(deviceId);
|
||||
Venue venue = qrCodeService.initEnter(venueId, deviceName,memberId);
|
||||
qrCodeService.unBindMember(venueId, deviceName);
|
||||
if (venue!=null){
|
||||
if (true){
|
||||
// 出场
|
||||
messageService.outVenue(deviceName,venueId,memberId,venue);
|
||||
}else{
|
||||
// 进场
|
||||
messageService.enterVenue(deviceName,venueId,memberId,venue);
|
||||
}
|
||||
}
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫码结果页初始化
|
||||
* 需要进场的场馆信息
|
||||
*/
|
||||
// @RequestMapping(value = "/qrCode/init", method = RequestMethod.GET)
|
||||
// public ResponseDTO initEnter(@RequestParam("deviceId")String deviceId) {
|
||||
// try {
|
||||
// Integer memberId = getMemberIdByAccessToken();
|
||||
// Integer venueId = getVenueId(deviceId);
|
||||
// String deviceName = getDeviceName(deviceId);
|
||||
// DeviceType enterOrOut = getEnterOrOut(deviceId);
|
||||
// Venue venue = qrCodeService.initEnter(venueId, deviceName, enterOrOut,memberId);
|
||||
// qrCodeService.bindMember(venueId, deviceName, enterOrOut,memberId);
|
||||
// messageService.sendLoading(deviceName, venueId, enterOrOut, memberId);
|
||||
// return ResponseDTO.ok().addAttribute("venueInit", venue);
|
||||
// }catch(ServiceException e){
|
||||
// return ResponseDTO.ok().addAttribute("InitError",e.getMessage());
|
||||
// }
|
||||
// }
|
||||
@RequestMapping(value = "/qrCode/init", method = RequestMethod.GET)
|
||||
public ResponseDTO initEnter(@RequestParam("deviceId")String deviceId) {
|
||||
try {
|
||||
Integer memberId = getMemberIdByAccessToken();
|
||||
Integer venueId = getVenueId(deviceId);
|
||||
String deviceName = getDeviceName(deviceId);
|
||||
Venue venue = qrCodeService.initEnter(venueId, deviceName,memberId);
|
||||
qrCodeService.bindMember(venueId, deviceName,memberId);
|
||||
messageService.sendLoading(deviceName, venueId, memberId);
|
||||
return ResponseDTO.ok().addAttribute("venueInit", venue);
|
||||
}catch(ServiceException e){
|
||||
return ResponseDTO.ok().addAttribute("InitError",e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -77,58 +71,41 @@ public class QREnterController extends BaseApiController {
|
||||
* @param deviceId
|
||||
* @return
|
||||
*/
|
||||
// private Integer getVenueId(String deviceId){
|
||||
// String venueId = "0";
|
||||
// if (deviceId!=null && deviceId.contains(Constant.SPIT_WORD)){
|
||||
// venueId = deviceId.split(Constant.SPIT_WORD)[1];
|
||||
// }
|
||||
// try {
|
||||
// return Integer.parseInt(venueId);
|
||||
// }catch (Exception e){
|
||||
// return 0;
|
||||
// }
|
||||
// }
|
||||
private Integer getVenueId(String deviceId){
|
||||
String venueId = "0";
|
||||
if (deviceId!=null && deviceId.contains(Constant.SPIT_WORD)){
|
||||
venueId = deviceId.split(Constant.SPIT_WORD)[1];
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(venueId);
|
||||
}catch (Exception e){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字符串获取设备号
|
||||
* @param deviceId
|
||||
* @return
|
||||
*/
|
||||
// private String getDeviceName(String deviceId){
|
||||
// if (deviceId!=null){
|
||||
// return deviceId.split(Constant.SPIT_WORD)[0];
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 根据字符串获取门禁类型
|
||||
* @param deviceId
|
||||
* @return
|
||||
*/
|
||||
// private DeviceType getEnterOrOut(String deviceId){
|
||||
// DeviceType returnType = DeviceType.ENTER;
|
||||
// if (deviceId!=null && deviceId.contains(Constant.SPIT_WORD)){
|
||||
// String temp = deviceId.split(Constant.SPIT_WORD)[1];
|
||||
// if (temp!=null && temp.contains(Constant.SPIT_WORD)){
|
||||
// returnType = DeviceType.valueOf(temp.split(Constant.SPIT_WORD)[1]);
|
||||
// }
|
||||
// }
|
||||
// return returnType;
|
||||
// }
|
||||
private String getDeviceName(String deviceId){
|
||||
if (deviceId!=null){
|
||||
return deviceId.split(Constant.SPIT_WORD)[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验客户端读取能力
|
||||
* @return
|
||||
*/
|
||||
// @RequestMapping("/checkAlive")
|
||||
// public ResponseDTO checkAlive(@RequestParam String id) {
|
||||
// Integer venueId = getVenueId(id);
|
||||
// String deviceName = getDeviceName(id);
|
||||
// DeviceType enterOrOut = getEnterOrOut(id);
|
||||
// logger.info("验证设备"+ id + "通讯情况");
|
||||
// messageService.testLoad(deviceName,venueId,enterOrOut);
|
||||
// return ResponseDTO.ok();
|
||||
// }
|
||||
@RequestMapping("/checkAlive")
|
||||
public ResponseDTO checkAlive(@RequestParam String id) {
|
||||
Integer venueId = getVenueId(id);
|
||||
String deviceName = getDeviceName(id);
|
||||
logger.info("验证设备"+ id + "通讯情况");
|
||||
messageService.testLoad(deviceName,venueId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -74,9 +75,7 @@ public class BootService {
|
||||
bossGroup = new NioEventLoopGroup();
|
||||
channelOptions = Maps.newHashMap();
|
||||
try {
|
||||
// channelOptions.put(ChannelOption.SO_KEEPALIVE,keepalive);
|
||||
channelOptions.put(ChannelOption.SO_BACKLOG,backlog);
|
||||
// channelOptions.put(ChannelOption.TCP_NODELAY,TCP_NODELAY);
|
||||
channelOptions.put(ChannelOption.SO_REUSEADDR,reuseaddr);
|
||||
bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 设置服务器的通道是NIOServerSocketChannel
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.sv.netty.netty;
|
||||
|
||||
import com.sv.netty.config.Constant;
|
||||
import com.sv.netty.utils.JsonUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义消息编码器
|
||||
*
|
||||
* @Author peakren
|
||||
* @Date 07/05/2017 10:43 PM
|
||||
*/
|
||||
public class MessageEncoder extends MessageToByteEncoder {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(MessageEncoder.class);
|
||||
|
||||
Charset charset = Charset.forName("UTF-8");
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
|
||||
String message = JsonUtils.encode(msg);
|
||||
logger.info("send message content:" + msg);
|
||||
message = message + Constant.DELIMITER_WORD;
|
||||
byte[] content = message.getBytes(charset.name());
|
||||
out.writeBytes(content); //发送消息内容
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sv.netty.netty;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
import com.sv.netty.config.Constant;
|
||||
import com.sv.netty.config.SpringContextHolder;
|
||||
import com.sv.netty.netty.message.ChannelParam;
|
||||
@@ -48,13 +47,13 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
*/
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
|
||||
System.err.println("发送的数据========" + msg);
|
||||
String clientIp = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getClientIp();
|
||||
try {
|
||||
HeartBeat hb = JsonUtils.decode(msg,HeartBeat.class);
|
||||
logger.info("客户端" + hb.getDeviceName() + "&" + hb.getVenueId() + "【" + clientIp + "】上报心跳...");
|
||||
logger.info("客户端【" + clientIp + "】上报心跳...");
|
||||
ctx.channel().attr(Constant.CHANNEL_PARAM).get().setVenueId(hb.getVenueId());
|
||||
ctx.channel().attr(Constant.CHANNEL_PARAM).get().setDeviceName(hb.getDeviceName());
|
||||
ctx.channel().attr(Constant.CHANNEL_PARAM).get().setDeviceType(DeviceType.valueOf(hb.getDeviceType()));
|
||||
messageService.online(clientIp,ctx.channel(), hb);
|
||||
} catch (Exception e) {
|
||||
logger.error("[" + clientIp + "] host unknown error",e);
|
||||
@@ -85,8 +84,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
logger.error("Client ip [" + clientIP + "] has inactive");
|
||||
Integer venueId = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getVenueId();
|
||||
String deviceName = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceName();
|
||||
DeviceType deviceType = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceType();
|
||||
messageService.Offline(deviceName,venueId,deviceType);
|
||||
messageService.Offline(deviceName,venueId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,10 +97,10 @@ public class ServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
logger.error("ServerHandler exceptionCaught",cause);
|
||||
Channel channel = ctx.channel();
|
||||
Integer venueId = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getVenueId();
|
||||
String deviceName = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceName();
|
||||
DeviceType deviceType = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceType();
|
||||
messageService.Offline(deviceName,venueId,deviceType);
|
||||
// Integer venueId = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getVenueId();
|
||||
// String deviceName = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceName();
|
||||
// DeviceType deviceType = ctx.channel().attr(Constant.CHANNEL_PARAM).get().getDeviceType();
|
||||
// messageService.Offline(deviceName,venueId,deviceType);
|
||||
if(channel.isActive()) {
|
||||
// 错误产生,关闭连接
|
||||
ctx.close();
|
||||
|
||||
@@ -6,7 +6,9 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.handler.timeout.ReadTimeoutHandler;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -29,10 +31,10 @@ public class ServerProtocolInitializer extends ChannelInitializer<SocketChannel>
|
||||
// 超时设置(如果客户端频繁有人操作,则不会报心跳,这样就会触发超时,关闭链接)
|
||||
// pipeline.addLast(new ReadTimeoutHandler(READ_TIMEOUT));
|
||||
// 通过指定的长度来标识整包的信息,这样就可以自动的处理粘包和半包的问题
|
||||
pipeline.addLast(new DelimiterBasedFrameDecoder(2048,
|
||||
Unpooled.wrappedBuffer(Constant.DELIMITER_WORD.getBytes())));
|
||||
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
pipeline.addLast(new StringDecoder());
|
||||
pipeline.addLast(new MessageEncoder());
|
||||
pipeline.addLast(new StringEncoder());
|
||||
// pipeline.addLast(new MessageEncoder());
|
||||
// 心跳检测机制,通过调用触发下一个handler userEventTriggered 方法
|
||||
pipeline.addLast(new IdleStateHandler(IDLE_TIME, IDLE_TIME,IDLE_TIME));
|
||||
pipeline.addLast(new ServerHandler());
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.sv.netty.netty.message;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
|
||||
/**
|
||||
* 会话中存储的客户端对象
|
||||
*
|
||||
@@ -25,12 +23,6 @@ public class ChannelParam {
|
||||
*/
|
||||
private Integer venueId;
|
||||
|
||||
/**
|
||||
* 设备进场出场类型
|
||||
* @param clientIP
|
||||
*/
|
||||
private DeviceType deviceType;
|
||||
|
||||
public ChannelParam(String clientIP) {
|
||||
this.clientIp = clientIP;
|
||||
}
|
||||
@@ -58,12 +50,4 @@ public class ChannelParam {
|
||||
public void setVenueId(Integer venueId) {
|
||||
this.venueId = venueId;
|
||||
}
|
||||
|
||||
public DeviceType getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(DeviceType deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ public class HeartBeat implements Serializable {
|
||||
|
||||
private String deviceName; //设备号
|
||||
|
||||
private String deviceType; //出入标志
|
||||
|
||||
public Integer getVenueId() {
|
||||
return venueId;
|
||||
}
|
||||
@@ -32,11 +30,4 @@ public class HeartBeat implements Serializable {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sv.netty.netty.service;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
import com.sv.entity.Venue;
|
||||
import com.sv.netty.netty.message.HeartBeat;
|
||||
import io.netty.channel.Channel;
|
||||
@@ -29,7 +28,7 @@ public interface MessageService {
|
||||
* @param deviceName
|
||||
* @param venueId
|
||||
*/
|
||||
void Offline(String deviceName, Integer venueId,DeviceType deviceType);
|
||||
void Offline(String deviceName, Integer venueId);
|
||||
|
||||
/**
|
||||
* 统计目前的链接数
|
||||
@@ -37,7 +36,7 @@ public interface MessageService {
|
||||
*/
|
||||
Set<String> countConnection();
|
||||
|
||||
boolean sendLoading(String deviceName, Integer venueId,DeviceType deviceType, Integer memberId);
|
||||
boolean sendLoading(String deviceName, Integer venueId, Integer memberId);
|
||||
|
||||
/**
|
||||
* 出场
|
||||
@@ -57,5 +56,5 @@ public interface MessageService {
|
||||
*/
|
||||
void enterVenue(String deviceName, Integer venueId, Integer memberId, Venue venue);
|
||||
|
||||
void testLoad(String deviceName, Integer venueId,DeviceType deviceType);
|
||||
void testLoad(String deviceName, Integer venueId);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sv.netty.netty.service.impl;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
import com.sv.entity.Member;
|
||||
import com.sv.entity.MemberEnterVenueLog;
|
||||
import com.sv.entity.Venue;
|
||||
@@ -10,6 +9,7 @@ import com.sv.netty.netty.message.HeartBeat;
|
||||
import com.sv.netty.netty.message.MessageDTO;
|
||||
import com.sv.netty.netty.message.MessageType;
|
||||
import com.sv.netty.netty.service.MessageService;
|
||||
import com.sv.netty.utils.JsonUtils;
|
||||
import com.sv.service.api.MemberEnterVenueLogService;
|
||||
import com.sv.service.api.MemberService;
|
||||
import com.sv.service.api.VenueService;
|
||||
@@ -52,7 +52,7 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
// @Resource
|
||||
private MemberService memberService;
|
||||
|
||||
// @Resource
|
||||
@Resource
|
||||
private VenueService venueService;
|
||||
|
||||
// @Resource
|
||||
@@ -78,16 +78,16 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
*/
|
||||
@Override
|
||||
public void online(String clientId, Channel channel, HeartBeat heartBeat) {
|
||||
DeviceType deviceType = DeviceType.valueOf(heartBeat.getDeviceType());
|
||||
logger.error("=========" + JsonUtils.encode(heartBeat) + clientId);
|
||||
// 处理心跳信息
|
||||
if (!contains(heartBeat.getDeviceName(),heartBeat.getVenueId(),deviceType)){
|
||||
if (!contains(heartBeat.getDeviceName(),heartBeat.getVenueId())){
|
||||
// 此处存储客户端的channel 信息key 为 deviceId + venueId
|
||||
Venue thisVenue = venueService.findById(heartBeat.getVenueId());
|
||||
if (thisVenue == null ){
|
||||
logger.error("this client choose venue Error! venueId == " + heartBeat.getVenueId());
|
||||
} else {
|
||||
deviceService.online(heartBeat.getDeviceName(),heartBeat.getVenueId(),deviceType,thisVenue.getType(),clientId);
|
||||
putChannelType(heartBeat.getDeviceName(),heartBeat.getVenueId(),deviceType,channel);
|
||||
deviceService.online(heartBeat.getDeviceName(),heartBeat.getVenueId(),thisVenue.getType(),clientId);
|
||||
putChannelType(heartBeat.getDeviceName(),heartBeat.getVenueId(),channel);
|
||||
MessageDTO messageDTO = new MessageDTO(MessageType.LINK,"欢迎扫码进场!");
|
||||
channel.writeAndFlush(messageDTO);
|
||||
}
|
||||
@@ -100,10 +100,10 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
* @param venueId
|
||||
*/
|
||||
@Override
|
||||
public void Offline(String deviceName, Integer venueId,DeviceType deviceType) {
|
||||
public void Offline(String deviceName, Integer venueId) {
|
||||
if (deviceName != null && venueId != null){
|
||||
removeChannelType(deviceName,venueId,deviceType);
|
||||
deviceService.offline(deviceName,venueId,deviceType);
|
||||
removeChannelType(deviceName,venueId);
|
||||
deviceService.offline(deviceName,venueId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,12 +113,12 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean sendLoading(String deviceName, Integer venueId,DeviceType deviceType, Integer memberId) {
|
||||
public boolean sendLoading(String deviceName, Integer venueId,Integer memberId) {
|
||||
Member thisMember = memberService.findByMember(memberId);
|
||||
if (thisMember!=null){
|
||||
String nickname = thisMember.getNickname();
|
||||
MessageDTO messageDTO = new MessageDTO(MessageType.LOAD,"欢迎光临!" + nickname + ",请您60s内操作进场。");
|
||||
Channel currentChannel = getCurrentChannel(deviceName, venueId, deviceType);
|
||||
Channel currentChannel = getCurrentChannel(deviceName, venueId);
|
||||
sendMessage(currentChannel,messageDTO);
|
||||
return true;
|
||||
}
|
||||
@@ -130,15 +130,15 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public void testLoad(String deviceName, Integer venueId,DeviceType deviceType) {
|
||||
Channel currentChannel = getCurrentChannel(deviceName, venueId, deviceType);
|
||||
currentChannel.writeAndFlush("Test Links" + deviceName + venueId + deviceType);
|
||||
public void testLoad(String deviceName, Integer venueId) {
|
||||
Channel currentChannel = getCurrentChannel(deviceName, venueId);
|
||||
currentChannel.writeAndFlush("Test Links" + deviceName + venueId);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void outVenue(String deviceName, Integer venueId, Integer memberId, Venue venue) {
|
||||
Channel channel = getCurrentChannel(deviceName,venueId,DeviceType.OUT);
|
||||
Channel channel = getCurrentChannel(deviceName,venueId);
|
||||
Member member = memberService.findByMember(memberId);
|
||||
if (member != null) {
|
||||
//出场 不用判断直接出
|
||||
@@ -181,7 +181,7 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
@Override
|
||||
public void enterVenue(String deviceName, Integer venueId, Integer memberId, Venue venue) {
|
||||
Member member = memberService.findByMember(memberId);
|
||||
Channel channel = getCurrentChannel(deviceName, venueId, DeviceType.ENTER);
|
||||
Channel channel = getCurrentChannel(deviceName, venueId);
|
||||
// 校验入场时间是否正常
|
||||
if (checkInterval(member,venueId)) {
|
||||
if(venueService.qrCodeEnterVenue(memberId,deviceName,venueId,venue)){
|
||||
@@ -208,7 +208,7 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
MemberEnterVenueLog enterVenueLog = memberEnterVenueLogService.findMemberLastLogNoType(member.getId(), venueId);
|
||||
if (enterVenueLog != null) {
|
||||
//有记录 查看 最后一次是否是出场
|
||||
if (enterVenueLog.getType().intValue() == DeviceType.OUT.getCode()) {
|
||||
if (true) {// TODO
|
||||
return true;
|
||||
} else {
|
||||
//是进场
|
||||
@@ -272,32 +272,32 @@ public class AppMessageHandlerAdapter implements MessageService {
|
||||
/**
|
||||
* 缓存通道
|
||||
*/
|
||||
public void putChannelType(String deviceName, Integer venueId, DeviceType deviceType, Channel channel) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD + deviceType;
|
||||
public void putChannelType(String deviceName, Integer venueId, Channel channel) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId;
|
||||
links.put(clientId, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前通道
|
||||
*/
|
||||
public Channel getCurrentChannel(String deviceName, Integer venueId, DeviceType deviceType){
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD + deviceType;
|
||||
public Channel getCurrentChannel(String deviceName, Integer venueId){
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD;
|
||||
return links.get(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通道
|
||||
*/
|
||||
public boolean contains(String deviceName, Integer venueId, DeviceType deviceType) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD + deviceType;
|
||||
public boolean contains(String deviceName, Integer venueId) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD;
|
||||
return links.containsKey(clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除通道
|
||||
*/
|
||||
public void removeChannelType(String deviceName, Integer venueId, DeviceType deviceType) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId + Constant.SPIT_WORD + deviceType;
|
||||
public void removeChannelType(String deviceName, Integer venueId) {
|
||||
String clientId = deviceName + Constant.SPIT_WORD + venueId ;
|
||||
links.remove(clientId);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.sv.netty.utils;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* USER: douya
|
||||
* DATE: 2017-08-28
|
||||
*/
|
||||
public class CommonUtils {
|
||||
|
||||
|
||||
|
||||
public static byte[] intToBytes2(int n){
|
||||
byte[] b = new byte[4];
|
||||
|
||||
for(int i = 0;i < 4;i++)
|
||||
{
|
||||
b[i]=(byte)(n>>(24-i*8));
|
||||
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换成16进制字符串
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String bytesToHexString(byte[] src){
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (src == null || src.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
int v = src[i] & 0xFF;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
stringBuilder.append(0);
|
||||
}
|
||||
stringBuilder.append(hv);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* byte数组转换成16进制字符数组
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String[] bytesToHexStrings(byte[] src){
|
||||
if (src == null || src.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
String[] str = new String[src.length];
|
||||
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
int v = src[i] & 0xFF;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
str[i] = "0";
|
||||
}
|
||||
str[i] = hv;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] arg){
|
||||
String message = "{\"cmd\":\"text_message\",\"content\":\"开心开心\",\"member_count\":0,\"system\":0,\"vmc_no\":\"322af403825a\"";
|
||||
byte[] bodys = message.getBytes(Charset.forName("UTF-8"));
|
||||
String magic = bytesToHexString("doll".getBytes(Charset.forName("UTF-8")));
|
||||
String length = bytesToHexString(intToBytes2(bodys.length+8));
|
||||
System.out.println(magic+length+bytesToHexString(bodys));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2005-2009 springside.org.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
*
|
||||
* $Id: EncodeUtils.java 984 2010-03-21 13:02:44Z calvinxiu $
|
||||
*/
|
||||
package com.sv.netty.utils;
|
||||
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
/**
|
||||
* 各种格式的编码加码工具类.
|
||||
*
|
||||
* 集成Commons-Codec,Commons-Lang及JDK提供的编解码方法.
|
||||
*
|
||||
* @author ranfi
|
||||
*/
|
||||
public class EncodeUtils {
|
||||
|
||||
private static final String DEFAULT_URL_ENCODING = "UTF-8";
|
||||
private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
|
||||
|
||||
/**
|
||||
* Hex编码.
|
||||
*/
|
||||
public static String encodeHex(byte[] input) {
|
||||
return Hex.encodeHexString(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex解码.
|
||||
*/
|
||||
public static byte[] decodeHex(String input) {
|
||||
try {
|
||||
return Hex.decodeHex(input.toCharArray());
|
||||
} catch (DecoderException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64编码.
|
||||
*/
|
||||
public static String encodeBase64(byte[] input) {
|
||||
return Base64.encodeBase64String(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
|
||||
*/
|
||||
public static String encodeUrlSafeBase64(byte[] input) {
|
||||
return Base64.encodeBase64URLSafeString(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64解码.
|
||||
*/
|
||||
public static byte[] decodeBase64(String input) {
|
||||
return Base64.decodeBase64(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base62编码。
|
||||
*/
|
||||
public static String encodeBase62(byte[] input) {
|
||||
char[] chars = new char[input.length];
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
chars[i] = BASE62[(input[i] & 0xFF) % BASE62.length];
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2005-2012 springside.org.cn
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
*/
|
||||
package com.sv.netty.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.util.JSONPObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
|
||||
* <p>
|
||||
* 封装不同的输出风格, 使用不同的builder函数创建实例.
|
||||
*
|
||||
* @author calvin
|
||||
*/
|
||||
public class JsonMapper {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
|
||||
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
public JsonMapper() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public JsonMapper(Include include) {
|
||||
mapper = new ObjectMapper();
|
||||
// 设置输出时包含属性的风格
|
||||
if (include != null) {
|
||||
mapper.setSerializationInclusion(include);
|
||||
}
|
||||
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
|
||||
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
|
||||
*/
|
||||
public static JsonMapper nonEmptyMapper() {
|
||||
return new JsonMapper(Include.NON_EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
|
||||
*/
|
||||
public static JsonMapper nonDefaultMapper() {
|
||||
return new JsonMapper(Include.NON_DEFAULT);
|
||||
}
|
||||
|
||||
public static JsonMapper nonNullMapper() {
|
||||
return new JsonMapper(Include.NON_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
|
||||
*/
|
||||
public String toJson(Object object) {
|
||||
|
||||
try {
|
||||
return mapper.writeValueAsString(object);
|
||||
} catch (IOException e) {
|
||||
logger.warn("write to json string error:" + object, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化POJO或简单Collection如List<String>.
|
||||
* <p>
|
||||
* 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
|
||||
* <p>
|
||||
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
|
||||
*
|
||||
* @see #fromJson(String, JavaType)
|
||||
*/
|
||||
public <T> T fromJson(String jsonString, Class<T> clazz) {
|
||||
if (StringUtils.isEmpty(jsonString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return mapper.readValue(jsonString, clazz);
|
||||
} catch (IOException e) {
|
||||
logger.warn("parse json string error:" + jsonString, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化复杂Collection如List<Bean>,
|
||||
* 先使用createCollectionType()或contructMapType()构造类型, 然后调用本函数.
|
||||
*
|
||||
* @see #createCollectionType(Class, Class...)
|
||||
*/
|
||||
public <T> T fromJson(String jsonString, JavaType javaType) {
|
||||
if (StringUtils.isEmpty(jsonString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) mapper.readValue(jsonString, javaType);
|
||||
} catch (IOException e) {
|
||||
logger.warn("parse json string error:" + jsonString, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造Collection类型.
|
||||
*/
|
||||
public JavaType contructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
|
||||
return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造Map类型.
|
||||
*/
|
||||
public JavaType contructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
|
||||
return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* map 转 bean
|
||||
*
|
||||
* @param map
|
||||
* @param beanClass
|
||||
* @return
|
||||
*/
|
||||
public <T> T convertMapToBean(Map<String, ?> map, Class<T> beanClass) {
|
||||
try {
|
||||
return mapper.convertValue(map, beanClass);
|
||||
} catch (Exception e) {
|
||||
logger.warn("convertMapToBean error! ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* map 转 bean
|
||||
*
|
||||
* @param bean
|
||||
* @param objectClass
|
||||
* @return
|
||||
*/
|
||||
public <T> T convertBeanToOther(Object bean, Class<T> objectClass) {
|
||||
try {
|
||||
return mapper.convertValue(bean, objectClass);
|
||||
} catch (Exception e) {
|
||||
logger.warn("convertMapToBean error! ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当JSON里只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
|
||||
*/
|
||||
public void update(String jsonString, Object object) {
|
||||
try {
|
||||
mapper.readerForUpdating(object).readValue(jsonString);
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 輸出JSONP格式數據.
|
||||
*/
|
||||
public String toJsonP(String functionName, Object object) {
|
||||
return toJson(new JSONPObject(functionName, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定是否使用Enum的toString函數來讀寫Enum, 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
|
||||
* 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
|
||||
*/
|
||||
public void enableEnumUseToString() {
|
||||
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
|
||||
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出Mapper做进一步的设置或使用其他序列化API.
|
||||
*/
|
||||
public ObjectMapper getMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package com.sv.netty.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerationException;
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* USER: douya
|
||||
* DATE: 2017-11-01
|
||||
*/
|
||||
public class JsonUtils {
|
||||
|
||||
|
||||
/**
|
||||
* Logger for this class
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);
|
||||
|
||||
private final static ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
static {
|
||||
objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
|
||||
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
|
||||
objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
|
||||
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
private JsonUtils() {
|
||||
}
|
||||
|
||||
public static String encode(Object obj) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(obj);
|
||||
} catch (JsonGenerationException e) {
|
||||
logger.error("encode(Object)", e); //$NON-NLS-1$
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error("encode(Object)", e); //$NON-NLS-1$
|
||||
} catch (IOException e) {
|
||||
logger.error("encode(Object)", e); //$NON-NLS-1$
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json string反序列化成对象
|
||||
*
|
||||
* @param json
|
||||
* @param valueType
|
||||
* @return
|
||||
*/
|
||||
public static <T> T decode(String json, Class<T> valueType) {
|
||||
try {
|
||||
return objectMapper.readValue(json, valueType);
|
||||
} catch (JsonParseException e) {
|
||||
logger.error("decode(String, Class<T>)", e);
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error("decode(String, Class<T>)", e);
|
||||
} catch (IOException e) {
|
||||
logger.error("decode(String, Class<T>)", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json array反序列化为对象
|
||||
*
|
||||
* @param json
|
||||
* @param typeReference
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T decode(String json, TypeReference<T> typeReference) {
|
||||
try {
|
||||
return (T) objectMapper.readValue(json, typeReference);
|
||||
} catch (JsonParseException e) {
|
||||
logger.error("decode(String, JsonTypeReference<T>)", e);
|
||||
} catch (JsonMappingException e) {
|
||||
logger.error("decode(String, JsonTypeReference<T>)", e);
|
||||
} catch (IOException e) {
|
||||
logger.error("decode(String, JsonTypeReference<T>)", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package com.enums;
|
||||
|
||||
/**
|
||||
* 设备属性,控制入场还是控制出场
|
||||
*/
|
||||
public enum DeviceType {
|
||||
|
||||
ENTER(0,"进场"),
|
||||
OUT(1,"出场");
|
||||
private int code;
|
||||
private String name;
|
||||
|
||||
DeviceType(int code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.sv.entity;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
@@ -38,8 +36,6 @@ public class Device implements Serializable {
|
||||
|
||||
private Integer venueType;
|
||||
|
||||
private DeviceType deviceType;
|
||||
|
||||
private Integer bindMember;
|
||||
|
||||
private Date bindTime;
|
||||
@@ -249,14 +245,6 @@ public class Device implements Serializable {
|
||||
this.venueType = venueType;
|
||||
}
|
||||
|
||||
public DeviceType getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(DeviceType deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
|
||||
public Integer getBindMember() {
|
||||
return bindMember;
|
||||
}
|
||||
|
||||
@@ -13,13 +13,8 @@
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.10.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>netty-model</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package com.sv.netty;
|
||||
|
||||
import com.sv.netty.message.HeartBeat;
|
||||
import com.sv.netty.message.MessageType;
|
||||
import com.sv.netty.message.VenueMessage;
|
||||
import com.sv.netty.utils.EncodeMsg;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* 通讯服务器请求处理
|
||||
*
|
||||
@@ -16,77 +18,82 @@ import io.netty.handler.timeout.IdleStateEvent;
|
||||
* @date 05/12/2017 10:27 PM
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class ClientHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private final static String TAG = "ClientHandler";
|
||||
|
||||
private boolean hasRead = false;
|
||||
|
||||
@Override
|
||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelRegistered(ctx);
|
||||
// ClientTcpSession.getInstance().setContext(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
//服务器连上以后立即模拟心跳返回
|
||||
ctx.writeAndFlush(getHbMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
ClientThread.getInstance().clearFuture();
|
||||
ClientThread.getInstance().restart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
super.channelRead(ctx, msg);
|
||||
// Message message = JsonMapper.fromJson(msg.toString(), Message.class);
|
||||
// MessageService.getInstance().execute(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
System.err.println("错了Error");
|
||||
System.err.println("Error");
|
||||
// GlobalConfig.isConnected = false;
|
||||
ctx.close();
|
||||
}
|
||||
public class ClientHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
/**
|
||||
* 获取心跳返回消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private VenueMessage getHbMessage() {
|
||||
HeartBeat hb = new HeartBeat();
|
||||
// hb.setVersionCode(AppUtil.getVersionCode(StartApplication.getAppContext()));
|
||||
VenueMessage message = new VenueMessage();
|
||||
message.setMessageType(MessageType.HB);
|
||||
// message.setDeviceId(DeviceIdUtil.generateDeviceId(mContext));
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 心跳处理
|
||||
*
|
||||
* 当通道就绪就会触发
|
||||
* @param ctx
|
||||
* @param evt
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当通道失效就会触发
|
||||
* @param ctx
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当通道有读取事件时触发
|
||||
* @param ctx
|
||||
* @param msg
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
|
||||
System.out.println("接收服务器响应msg:[" + msg + "]");
|
||||
// MessageDTO message = JsonMapper.fromJson(msg, MessageDTO.class);
|
||||
// MessageService.getInstance().execute(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 心跳
|
||||
* @param ctx
|
||||
* @param evt
|
||||
*/
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws UnknownHostException {
|
||||
if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
if (event.state() == IdleState.ALL_IDLE) {
|
||||
ctx.writeAndFlush(getHbMessage());
|
||||
ctx.write(EncodeMsg.INSTANCE.encode(getHbMessage()));
|
||||
ctx.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装心跳请求包
|
||||
* @throws Exception
|
||||
*/
|
||||
private HeartBeat getHbMessage() {
|
||||
HeartBeat hb = new HeartBeat();
|
||||
hb.setDeviceName("dsadasdasd");
|
||||
hb.setVenueId(123);
|
||||
return hb;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理异常
|
||||
* @param ctx
|
||||
* @param cause
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
System.out.println("ClientHandler exceptionCaught");
|
||||
cause.printStackTrace();
|
||||
Channel channel = ctx.channel();
|
||||
if(channel.isActive()) {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
package com.sv.netty;
|
||||
|
||||
import com.sv.netty.config.Constant;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
import io.netty.handler.codec.Delimiters;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
|
||||
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final static int TIME_HEART_BEAT = 20;
|
||||
private final static int TIME_HEART_BEAT = 5;
|
||||
|
||||
public ClientThread.ReConnectHandler reConnectHandler;
|
||||
public ClientHandler dmClientHandler;
|
||||
@@ -28,10 +27,10 @@ public class ClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast("reconnect", reConnectHandler);
|
||||
pipeline.addLast("idleStateHandler", new IdleStateHandler(TIME_HEART_BEAT, TIME_HEART_BEAT, TIME_HEART_BEAT));
|
||||
pipeline.addLast(new MessageEncoder());
|
||||
pipeline.addFirst(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 4, 4, 0, 0));
|
||||
pipeline.addLast(new MessageDecoder());
|
||||
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
|
||||
pipeline.addLast(new StringDecoder());
|
||||
pipeline.addLast(new StringEncoder());
|
||||
pipeline.addLast(new IdleStateHandler(TIME_HEART_BEAT, TIME_HEART_BEAT,TIME_HEART_BEAT));
|
||||
pipeline.addLast(dmClientHandler);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.sv.netty;
|
||||
|
||||
import com.sv.netty.config.Constant;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -51,6 +52,7 @@ public class ClientThread extends Thread{
|
||||
bootstrap = new Bootstrap();
|
||||
bootstrap.group(workerGroup);
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
bootstrap.handler(new LoggingHandler());
|
||||
bootstrap.option(ChannelOption.TCP_NODELAY, true);
|
||||
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
@@ -114,7 +116,7 @@ public class ClientThread extends Thread{
|
||||
public void run() {
|
||||
doConnect();
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}, 2, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.sv.netty;
|
||||
|
||||
import com.sv.netty.config.Constant;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by hehelt on 16/2/26.
|
||||
* <p/>
|
||||
* 解码器
|
||||
*/
|
||||
public class MessageDecoder extends ByteToMessageDecoder {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (in.capacity() >= Constant.LENGTH_INDEX) {
|
||||
int magicWord = in.readInt();
|
||||
if (magicWord == Constant.MAGIC_WORD) {
|
||||
int length = in.readInt();
|
||||
byte[] msg = new byte[length];
|
||||
in.readBytes(msg);
|
||||
String message = new String(msg, "utf-8");
|
||||
out.add(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析从服务器接受的消息
|
||||
*
|
||||
* @param buf
|
||||
* @return
|
||||
*/
|
||||
private String getMessage(ByteBuf buf) {
|
||||
byte[] con = new byte[buf.readableBytes()];
|
||||
buf.readBytes(con);
|
||||
try {
|
||||
return new String(con, "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.sv.netty;
|
||||
|
||||
import com.sv.netty.config.Constant;
|
||||
import com.sv.netty.message.VenueMessage;
|
||||
import com.sv.utils.JsonMapper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
/**
|
||||
* 自定义编码器, 1个字节固定头+4个字节长度+内容
|
||||
*/
|
||||
public class MessageEncoder extends MessageToByteEncoder<VenueMessage> {
|
||||
|
||||
private String charset = "utf-8";
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, VenueMessage message, ByteBuf out) throws Exception {
|
||||
out.writeInt(Constant.MAGIC_WORD);
|
||||
String msg = JsonMapper.toJson(message);
|
||||
out.writeInt(msg.getBytes(charset).length);
|
||||
out.writeBytes(msg.getBytes(charset));
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.sv.netty.config;
|
||||
|
||||
public interface Constant {
|
||||
|
||||
String DELIMITER_WORD = "$_$";
|
||||
|
||||
int MAGIC_WORD = 0x9DDD;
|
||||
int LENGTH_INDEX = 4;
|
||||
|
||||
String SERVER_IP = "120.27.209.4";
|
||||
Integer SERVER_PORT = 56791;
|
||||
Integer VENUE_ID = 39;
|
||||
String DEVICE_NAME = "SN2020382013";
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2005-2012 springside.org.cn
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
*/
|
||||
package com.sv.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.util.JSONPObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 简单封装Jackson,实现JSON String<->Java Object的Mapper.
|
||||
* <p>
|
||||
* 封装不同的输出风格, 使用不同的builder函数创建实例.
|
||||
*
|
||||
* @author calvin
|
||||
*/
|
||||
public class JsonMapper {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(JsonMapper.class);
|
||||
|
||||
private static ObjectMapper mapper;
|
||||
|
||||
public JsonMapper() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public JsonMapper(Include include) {
|
||||
mapper = new ObjectMapper();
|
||||
// 设置输出时包含属性的风格
|
||||
if (include != null) {
|
||||
mapper.setSerializationInclusion(include);
|
||||
}
|
||||
// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
|
||||
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建只输出非Null且非Empty(如List.isEmpty)的属性到Json字符串的Mapper,建议在外部接口中使用.
|
||||
*/
|
||||
public static JsonMapper nonEmptyMapper() {
|
||||
return new JsonMapper(Include.NON_EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建只输出初始值被改变的属性到Json字符串的Mapper, 最节约的存储方式,建议在内部接口中使用。
|
||||
*/
|
||||
public static JsonMapper nonDefaultMapper() {
|
||||
return new JsonMapper(Include.NON_DEFAULT);
|
||||
}
|
||||
|
||||
public static JsonMapper nonNullMapper() {
|
||||
return new JsonMapper(Include.NON_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
|
||||
*/
|
||||
public static String toJson(Object object) {
|
||||
|
||||
try {
|
||||
return mapper.writeValueAsString(object);
|
||||
} catch (IOException e) {
|
||||
logger.warn("write to json string error:" + object, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化POJO或简单Collection如List<String>.
|
||||
* <p>
|
||||
* 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
|
||||
* <p>
|
||||
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
|
||||
*
|
||||
* @see #fromJson(String, JavaType)
|
||||
*/
|
||||
public static <T> T fromJson(String jsonString, Class<T> clazz) {
|
||||
if (StringUtils.isEmpty(jsonString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return mapper.readValue(jsonString, clazz);
|
||||
} catch (IOException e) {
|
||||
logger.warn("parse json string error:" + jsonString, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化复杂Collection如List<Bean>,
|
||||
* 先使用createCollectionType()或contructMapType()构造类型, 然后调用本函数.
|
||||
*
|
||||
* @see #createCollectionType(Class, Class...)
|
||||
*/
|
||||
public <T> T fromJson(String jsonString, JavaType javaType) {
|
||||
if (StringUtils.isEmpty(jsonString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return (T) mapper.readValue(jsonString, javaType);
|
||||
} catch (IOException e) {
|
||||
logger.warn("parse json string error:" + jsonString, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造Collection类型.
|
||||
*/
|
||||
public JavaType contructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass) {
|
||||
return mapper.getTypeFactory().constructCollectionType(collectionClass, elementClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造Map类型.
|
||||
*/
|
||||
public JavaType contructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass) {
|
||||
return mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* map 转 bean
|
||||
*
|
||||
* @param map
|
||||
* @param beanClass
|
||||
* @return
|
||||
*/
|
||||
public <T> T convertMapToBean(Map<String, ?> map, Class<T> beanClass) {
|
||||
try {
|
||||
return mapper.convertValue(map, beanClass);
|
||||
} catch (Exception e) {
|
||||
logger.warn("convertMapToBean error! ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* map 转 bean
|
||||
*
|
||||
* @param bean
|
||||
* @param objectClass
|
||||
* @return
|
||||
*/
|
||||
public <T> T convertBeanToOther(Object bean, Class<T> objectClass) {
|
||||
try {
|
||||
return mapper.convertValue(bean, objectClass);
|
||||
} catch (Exception e) {
|
||||
logger.warn("convertMapToBean error! ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当JSON里只含有Bean的部分屬性時,更新一個已存在Bean,只覆蓋該部分的屬性.
|
||||
*/
|
||||
public void update(String jsonString, Object object) {
|
||||
try {
|
||||
mapper.readerForUpdating(object).readValue(jsonString);
|
||||
} catch (JsonProcessingException e) {
|
||||
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
|
||||
} catch (IOException e) {
|
||||
logger.warn("update json string:" + jsonString + " to object:" + object + " error.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 輸出JSONP格式數據.
|
||||
*/
|
||||
public String toJsonP(String functionName, Object object) {
|
||||
return toJson(new JSONPObject(functionName, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* 設定是否使用Enum的toString函數來讀寫Enum, 為False時時使用Enum的name()函數來讀寫Enum, 默認為False.
|
||||
* 注意本函數一定要在Mapper創建後, 所有的讀寫動作之前調用.
|
||||
*/
|
||||
public void enableEnumUseToString() {
|
||||
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
|
||||
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取出Mapper做进一步的设置或使用其他序列化API.
|
||||
*/
|
||||
public ObjectMapper getMapper() {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package test.netty.nio.net;
|
||||
|
||||
import test.netty.nio.net.client.ClientThread;
|
||||
|
||||
/**
|
||||
* 开启一个客户端,
|
||||
*/
|
||||
public class ClientTest {
|
||||
public static void main(String[] args) {
|
||||
ClientThread instance = ClientThread.getInstance();
|
||||
instance.start();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
import test.netty.nio.net.dto.HeartBeat;
|
||||
import test.netty.nio.net.dto.Message;
|
||||
|
||||
/**
|
||||
* 通讯服务器请求处理
|
||||
*
|
||||
* @author peakren
|
||||
* @date 05/12/2017 10:27 PM
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class ClientHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private final static String TAG = "ClientHandler";
|
||||
|
||||
private boolean hasRead = false;
|
||||
|
||||
@Override
|
||||
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelRegistered(ctx);
|
||||
// ClientTcpSession.getInstance().setContext(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelActive(ctx);
|
||||
//服务器连上以后立即模拟心跳返回
|
||||
ctx.writeAndFlush(getHbMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
// GlobalConfig.isConnected =false;
|
||||
ClientThread.getInstance().clearFuture();
|
||||
ClientThread.getInstance().restart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
super.channelRead(ctx, msg);
|
||||
// Message message = JsonMapper.fromJson(msg.toString(), Message.class);
|
||||
// MessageService.getInstance().execute(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
// GlobalConfig.isConnected = false;
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取心跳返回消息
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Message getHbMessage() {
|
||||
HeartBeat hb = new HeartBeat();
|
||||
// hb.setVersionCode(AppUtil.getVersionCode(StartApplication.getAppContext()));
|
||||
Message message = new Message();
|
||||
message.setCmdId(Cmd.HB.id);
|
||||
// message.setDeviceId(DeviceIdUtil.generateDeviceId(mContext));
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 心跳处理
|
||||
*
|
||||
* @param ctx
|
||||
* @param evt
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
||||
if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
|
||||
IdleStateEvent event = (IdleStateEvent) evt;
|
||||
if (event.state() == IdleState.ALL_IDLE) {
|
||||
ctx.writeAndFlush(getHbMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
|
||||
|
||||
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final static int TIME_HEART_BEAT = 20;
|
||||
|
||||
public ClientThread.ReConnectHandler reConnectHandler;
|
||||
public ClientHandler dmClientHandler;
|
||||
|
||||
public ClientInitializer(ClientThread.ReConnectHandler handler) {
|
||||
reConnectHandler = handler;
|
||||
}
|
||||
|
||||
public ClientInitializer(ClientThread.ReConnectHandler handler, ClientHandler dmClientHandler) {
|
||||
reConnectHandler = handler;
|
||||
this.dmClientHandler = dmClientHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast("reconnect", reConnectHandler);
|
||||
pipeline.addLast("idleStateHandler", new IdleStateHandler(TIME_HEART_BEAT, TIME_HEART_BEAT, TIME_HEART_BEAT));
|
||||
pipeline.addLast(new MessageEncoder());
|
||||
pipeline.addFirst(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 4, 4, 0, 0));
|
||||
pipeline.addLast(new MessageDecoder());
|
||||
pipeline.addLast(dmClientHandler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
/**
|
||||
* 客户端通讯
|
||||
*
|
||||
* @author peakren
|
||||
* @date 07/12/2017 10:12 PM
|
||||
*/
|
||||
public class ClientThread extends Thread{
|
||||
|
||||
private static ClientThread instance;
|
||||
|
||||
private volatile EventLoopGroup workerGroup;
|
||||
private volatile Bootstrap bootstrap;
|
||||
private volatile boolean closed = false;
|
||||
private String remoteHost;
|
||||
private int remotePort;
|
||||
|
||||
private ChannelFuture future;
|
||||
|
||||
|
||||
public static ClientThread getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (ClientThread.class) {
|
||||
if (instance == null) {
|
||||
instance = new ClientThread("127.0.0.1", 56791);
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ClientThread(String remoteHost, int remotePort) {
|
||||
this.remoteHost = remoteHost;
|
||||
this.remotePort = remotePort;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
||||
closed = false;
|
||||
workerGroup = new NioEventLoopGroup();
|
||||
bootstrap = new Bootstrap();
|
||||
bootstrap.group(workerGroup);
|
||||
bootstrap.channel(NioSocketChannel.class);
|
||||
bootstrap.option(ChannelOption.TCP_NODELAY, true);
|
||||
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
|
||||
ReConnectHandler reConnectHandler = new ReConnectHandler();
|
||||
ClientHandler dmClientHandler = new ClientHandler();
|
||||
ClientInitializer channelInitializer = new ClientInitializer(reConnectHandler, dmClientHandler);
|
||||
|
||||
bootstrap.handler(channelInitializer);
|
||||
doConnect();
|
||||
}
|
||||
|
||||
public void clearFuture(){
|
||||
future = null;
|
||||
}
|
||||
|
||||
public void doConnect() {
|
||||
System.out.println("现在开始链接了");
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
System.out.println("连接 = " + remoteHost + " " + remotePort);
|
||||
future = bootstrap.connect(new InetSocketAddress(remoteHost, remotePort));
|
||||
future.addListener(new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture f) throws Exception {
|
||||
f.channel().eventLoop().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!f.isSuccess()) {
|
||||
doConnect();
|
||||
System.out.println("等待连接");
|
||||
} else {
|
||||
System.out.println("已连接");
|
||||
}
|
||||
}
|
||||
}, 2, TimeUnit.SECONDS);
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void close() {
|
||||
closed = true;
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
|
||||
public void restart() {
|
||||
close();
|
||||
run();
|
||||
}
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ReConnectHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
System.out.println("inactive");
|
||||
ctx.channel().eventLoop().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doConnect();
|
||||
}
|
||||
}, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
/**
|
||||
* 消息协议指令定义
|
||||
*
|
||||
* @Author peakren
|
||||
* @Date 08/12/2017 11:51 AM
|
||||
*/
|
||||
public enum Cmd {
|
||||
|
||||
|
||||
HB("hb", "心跳"),
|
||||
|
||||
FACEID("faceid", "人脸识别"),
|
||||
|
||||
FACEID_RESPONSE("faceid_response_upload", "识别结果"),
|
||||
|
||||
RECEV_FACE_IMAGE("recev_face_image", "接收人脸照片"),
|
||||
|
||||
RECEV_FACE_IMAGE_R("recev_face_image_r", "返回上传图片结果"),
|
||||
|
||||
OPEN_DOOR("open_door", "开门禁");
|
||||
|
||||
|
||||
public String id;
|
||||
|
||||
public String text;
|
||||
|
||||
Cmd(String id, String text) {
|
||||
this.id = id;
|
||||
this.text = text;
|
||||
|
||||
}
|
||||
|
||||
public static Cmd getCmd(String id) {
|
||||
for (Cmd cmd : Cmd.values()) {
|
||||
if (cmd.id.equalsIgnoreCase(id)) {
|
||||
return cmd;
|
||||
}
|
||||
}
|
||||
return Cmd.HB;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
|
||||
/**
|
||||
* 自定义解码器,解决粘包和分包问题
|
||||
*
|
||||
* @author peakren
|
||||
* @date 07/12/2017 10:03 PM
|
||||
*/
|
||||
public class CustomDecoder extends LengthFieldBasedFrameDecoder {
|
||||
|
||||
public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
|
||||
super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
|
||||
}
|
||||
|
||||
public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
|
||||
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
|
||||
}
|
||||
|
||||
public CustomDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
|
||||
super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
|
||||
}
|
||||
|
||||
public CustomDecoder(ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, boolean failFast) {
|
||||
super(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, failFast);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
|
||||
return super.decode(ctx, in);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
/**
|
||||
* Created by hehelt on 16/2/26.
|
||||
*/
|
||||
public class DataConfig {
|
||||
|
||||
public static final int MAGIC_WORD = 0x9DDD;
|
||||
public static final int MAGIC_WORD_INDEX = 0;
|
||||
public static final int LENGTH_INDEX = 4;
|
||||
public static final int DATA_INDEX = 8;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by hehelt on 16/2/26.
|
||||
* <p/>
|
||||
* 解码器
|
||||
*/
|
||||
public class MessageDecoder extends ByteToMessageDecoder {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
||||
if (in.capacity() >= DataConfig.LENGTH_INDEX) {
|
||||
int magicWord = in.readInt();
|
||||
if (magicWord == DataConfig.MAGIC_WORD) {
|
||||
int length = in.readInt();
|
||||
byte[] msg = new byte[length];
|
||||
in.readBytes(msg);
|
||||
String message = new String(msg, "utf-8");
|
||||
out.add(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析从服务器接受的消息
|
||||
*
|
||||
* @param buf
|
||||
* @return
|
||||
*/
|
||||
private String getMessage(ByteBuf buf) {
|
||||
|
||||
byte[] con = new byte[buf.readableBytes()];
|
||||
buf.readBytes(con);
|
||||
try {
|
||||
return new String(con, "utf-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package test.netty.nio.net.client;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import test.netty.nio.net.dto.JsonMapper;
|
||||
import test.netty.nio.net.dto.Message;
|
||||
|
||||
/**
|
||||
* 自定义编码器, 1个字节固定头+4个字节长度+内容
|
||||
*/
|
||||
public class MessageEncoder extends MessageToByteEncoder<Message> {
|
||||
|
||||
private String charset = "utf-8";
|
||||
private final static String TAG = "MessageEncoder";
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Message message, ByteBuf out) throws Exception {
|
||||
out.writeInt(DataConfig.MAGIC_WORD);
|
||||
String msg = JsonMapper.toJson(message);
|
||||
out.writeInt(msg.getBytes(charset).length);
|
||||
out.writeBytes(msg.getBytes(charset));
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
public class AddFaceResponse {
|
||||
|
||||
/**
|
||||
* code : 0
|
||||
* data : {"company_id":1,"id":4,"origin_url":"/static/upload/origin/2018-08-09/v2_1ea4b7847d1ea56b773aec99441af52dcbf9ca7d.jpg","quality":0.992649,"subject_id":null,"url":"/static/upload/photo/2018-08-09/v2_fa9dcfd045ff5232aa446f5645cbb031eef7ac74.jpg","version":7}
|
||||
* page : {}
|
||||
*/
|
||||
|
||||
@Expose
|
||||
private int code;
|
||||
|
||||
@Expose
|
||||
private DataBean data;
|
||||
|
||||
@Expose
|
||||
private PageBean page;
|
||||
|
||||
@Expose
|
||||
private String desc;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public DataBean getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(DataBean data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public PageBean getPage() {
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(PageBean page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static class DataBean {
|
||||
/**
|
||||
* company_id : 1
|
||||
* id : 4
|
||||
* origin_url : /static/upload/origin/2018-08-09/v2_1ea4b7847d1ea56b773aec99441af52dcbf9ca7d.jpg
|
||||
* quality : 0.992649
|
||||
* subject_id : null
|
||||
* url : /static/upload/photo/2018-08-09/v2_fa9dcfd045ff5232aa446f5645cbb031eef7ac74.jpg
|
||||
* version : 7
|
||||
*/
|
||||
|
||||
@Expose
|
||||
private int company_id;
|
||||
@Expose
|
||||
private int id;
|
||||
@Expose
|
||||
private String origin_url;
|
||||
@Expose
|
||||
private double quality;
|
||||
@Expose
|
||||
private Object subject_id;
|
||||
@Expose
|
||||
private String url;
|
||||
@Expose
|
||||
private int version;
|
||||
|
||||
public int getCompany_id() {
|
||||
return company_id;
|
||||
}
|
||||
|
||||
public void setCompany_id(int company_id) {
|
||||
this.company_id = company_id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getOrigin_url() {
|
||||
return origin_url;
|
||||
}
|
||||
|
||||
public void setOrigin_url(String origin_url) {
|
||||
this.origin_url = origin_url;
|
||||
}
|
||||
|
||||
public double getQuality() {
|
||||
return quality;
|
||||
}
|
||||
|
||||
public void setQuality(double quality) {
|
||||
this.quality = quality;
|
||||
}
|
||||
|
||||
public Object getSubject_id() {
|
||||
return subject_id;
|
||||
}
|
||||
|
||||
public void setSubject_id(Object subject_id) {
|
||||
this.subject_id = subject_id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PageBean {
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Created by peakren on 19/01/2018.
|
||||
*/
|
||||
|
||||
public class BaseDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3139438146199448677L;
|
||||
|
||||
@Expose
|
||||
private String cmdId; //指令
|
||||
|
||||
@Expose
|
||||
private String deviceId; //设备ID
|
||||
|
||||
/**
|
||||
* 客户端IP
|
||||
*/
|
||||
@Expose
|
||||
private String clientIp;
|
||||
|
||||
/**
|
||||
* 状态码 0正常 1错误
|
||||
*/
|
||||
@Expose
|
||||
private int errorCode = 0;
|
||||
|
||||
/**
|
||||
* 错误返回信息
|
||||
*/
|
||||
@Expose
|
||||
private String errorMsg;
|
||||
|
||||
|
||||
public String getCmdId() {
|
||||
return cmdId;
|
||||
}
|
||||
|
||||
public void setCmdId(String cmdId) {
|
||||
this.cmdId = cmdId;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(String deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端IP,获取的内网IP
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getClientIp() {
|
||||
return clientIp;
|
||||
}
|
||||
|
||||
public void setClientIp(String clientIp) {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public int getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode(int errorCode) {
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getErrorMsg() {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
public void setErrorMsg(String errorMsg) {
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* 会员基本信息
|
||||
* MemberDto.java
|
||||
*
|
||||
* @author peakren
|
||||
* @date 2018/12/20 8:39 PM
|
||||
*/
|
||||
public class FaceImageDto implements Serializable {
|
||||
|
||||
|
||||
@Expose
|
||||
private Integer faceId;
|
||||
|
||||
@Expose
|
||||
private Integer memberId;
|
||||
|
||||
|
||||
@Expose
|
||||
private String faceImage;
|
||||
|
||||
|
||||
public Integer getFaceId() {
|
||||
return faceId;
|
||||
}
|
||||
|
||||
public void setFaceId(Integer faceId) {
|
||||
this.faceId = faceId;
|
||||
}
|
||||
|
||||
public Integer getMemberId() {
|
||||
return memberId;
|
||||
}
|
||||
|
||||
public void setMemberId(Integer memberId) {
|
||||
this.memberId = memberId;
|
||||
}
|
||||
|
||||
public String getFaceImage() {
|
||||
return faceImage;
|
||||
}
|
||||
|
||||
public void setFaceImage(String faceImage) {
|
||||
this.faceImage = faceImage;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,44 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 客户端心跳数据包
|
||||
* HeartBeat.java
|
||||
*
|
||||
* @author peakren
|
||||
* @date 07/12/2017 10:23 PM
|
||||
*/
|
||||
public class HeartBeat implements Serializable {
|
||||
|
||||
@Expose
|
||||
private String versionCode; //客户端版本号
|
||||
|
||||
@Expose
|
||||
private String apkUrl; //升级的软件下载地址
|
||||
|
||||
|
||||
public String getVersionCode() {
|
||||
return versionCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端版本号
|
||||
*
|
||||
* @param versionCode
|
||||
*/
|
||||
public void setVersionCode(String versionCode) {
|
||||
this.versionCode = versionCode;
|
||||
}
|
||||
|
||||
public String getApkUrl() {
|
||||
return apkUrl;
|
||||
}
|
||||
|
||||
public void setApkUrl(String apkUrl) {
|
||||
this.apkUrl = apkUrl;
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by ranfi on 12/9/14.
|
||||
*/
|
||||
public class JsonMapper {
|
||||
|
||||
private final static Gson gson;
|
||||
|
||||
static {
|
||||
GsonBuilder builder = new GsonBuilder();
|
||||
builder.setDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
builder.excludeFieldsWithoutExposeAnnotation();
|
||||
gson = builder.create();
|
||||
}
|
||||
|
||||
private JsonMapper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Object可以是POJO,也可以是Collection或数组。 如果对象为Null, 返回"null". 如果集合为空集合, 返回"[]".
|
||||
*
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static String toJson(Object obj) {
|
||||
return gson.toJson(obj);
|
||||
}
|
||||
|
||||
|
||||
public static String toJson(Object obj, Type type) {
|
||||
return gson.toJson(obj, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 反序列化POJO或简单Collection如List<String>.
|
||||
* <p/>
|
||||
* 如果JSON字符串为Null或"null"字符串, 返回Null. 如果JSON字符串为"[]", 返回空集合.
|
||||
* <p/>
|
||||
* 如需反序列化复杂Collection如List<MyBean>, 请使用fromJson(String, JavaType)
|
||||
*/
|
||||
public static <T> T fromJson(String jsonValue, Class<T> clazz) {
|
||||
return gson.fromJson(jsonValue, clazz);
|
||||
}
|
||||
|
||||
public static <T> T fromJson(String jsonValue, Type type) {
|
||||
return gson.fromJson(jsonValue, type);
|
||||
}
|
||||
|
||||
public static <T> List<T> fromJson(String jsonValue) {
|
||||
return gson.fromJson(jsonValue, new TypeToken<List<T>>() {
|
||||
}.getType());
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
/**
|
||||
* 会员基本信息
|
||||
* MemberDto.java
|
||||
*
|
||||
* @author peakren
|
||||
* @date 2018/12/20 8:39 PM
|
||||
*/
|
||||
public class MemberDto implements Serializable {
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
@Expose
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
@Expose
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@Expose
|
||||
private String mobile;
|
||||
|
||||
/**
|
||||
* 余额
|
||||
*/
|
||||
@Expose
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 场地名称
|
||||
*/
|
||||
@Expose
|
||||
private String placeName;
|
||||
|
||||
/**
|
||||
* 会员卡名称
|
||||
*/
|
||||
@Expose
|
||||
private String cardName;
|
||||
|
||||
@Expose
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 1成功进场 0不允许进场
|
||||
*/
|
||||
@Expose
|
||||
private int code;
|
||||
|
||||
@Expose
|
||||
private BigDecimal placePrice;
|
||||
|
||||
@Expose
|
||||
private boolean first;
|
||||
|
||||
public BigDecimal getPlacePrice() {
|
||||
return placePrice;
|
||||
}
|
||||
|
||||
public void setPlacePrice(BigDecimal placePrice) {
|
||||
this.placePrice = placePrice;
|
||||
}
|
||||
|
||||
public boolean isFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public void setFirst(boolean first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return avatar;
|
||||
}
|
||||
|
||||
public void setAvatar(String avatar) {
|
||||
this.avatar = avatar;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public String getPlaceName() {
|
||||
return placeName;
|
||||
}
|
||||
|
||||
public void setPlaceName(String placeName) {
|
||||
this.placeName = placeName;
|
||||
}
|
||||
|
||||
public String getCardName() {
|
||||
return cardName;
|
||||
}
|
||||
|
||||
public void setCardName(String cardName) {
|
||||
this.cardName = cardName;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package test.netty.nio.net.dto;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
/**
|
||||
* <pre>上位机与通讯服务器的数据协议格式</pre>
|
||||
*
|
||||
* @author peakren
|
||||
* @date 07/12/2017 9:57 PM
|
||||
*/
|
||||
public class Message extends BaseDto {
|
||||
|
||||
private static final long serialVersionUID = -7944124768291562453L;
|
||||
|
||||
/**
|
||||
* 消息内容
|
||||
*/
|
||||
@Expose
|
||||
private MemberDto result;
|
||||
|
||||
|
||||
@Expose
|
||||
private FaceImageDto faceImage;
|
||||
|
||||
/**
|
||||
* 机器识别返回字符串
|
||||
*/
|
||||
@Expose
|
||||
private String content;
|
||||
|
||||
|
||||
public int getDoor() {
|
||||
return door;
|
||||
}
|
||||
|
||||
public void setDoor(int door) {
|
||||
this.door = door;
|
||||
}
|
||||
|
||||
@Expose
|
||||
private int door;
|
||||
|
||||
|
||||
public MemberDto getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(MemberDto result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public FaceImageDto getFaceImage() {
|
||||
return faceImage;
|
||||
}
|
||||
|
||||
public void setFaceImage(FaceImageDto faceImage) {
|
||||
this.faceImage = faceImage;
|
||||
}
|
||||
|
||||
}
|
||||
15
pom.xml
15
pom.xml
@@ -26,15 +26,21 @@
|
||||
<version>${smartvenue.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>smartvenue</artifactId>
|
||||
<groupId>sv-api</groupId>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>sv-api</artifactId>
|
||||
<version>${smartvenue.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<artifactId>smartvenue</artifactId>
|
||||
<groupId>netty-client</groupId>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>netty-client</artifactId>
|
||||
<version>${smartvenue.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>netty-model</artifactId>
|
||||
<version>${smartvenue.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>smartvenue</groupId>
|
||||
<artifactId>sv-oms</artifactId>
|
||||
@@ -98,6 +104,7 @@
|
||||
<module>oms</module>
|
||||
<module>service</module>
|
||||
<module>netty-client</module>
|
||||
<module>netty-model</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.sv.mapper;
|
||||
import com.common.DeviceDTO;
|
||||
import com.enums.DeviceType;
|
||||
import com.sv.entity.Device;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -67,34 +66,33 @@ public interface DeviceMapper {
|
||||
/**
|
||||
* 更新设备状态为 0 - 未连接
|
||||
*/
|
||||
void offline(@Param("venueId") Integer venueId,@Param("deviceName") String deviceName,@Param("deviceType")DeviceType deviceType);
|
||||
void offline(@Param("venueId") Integer venueId,@Param("deviceName") String deviceName);
|
||||
|
||||
/**
|
||||
* 更新设备状态为 2 - 连接成功
|
||||
*/
|
||||
void online(@Param("venueId") Integer venueId, @Param("deviceName") String deviceName, @Param("deviceType")DeviceType deviceType);
|
||||
void online(@Param("venueId") Integer venueId, @Param("deviceName") String deviceName);
|
||||
|
||||
|
||||
Integer checkDevice(@Param("deviceName") String deviceName,@Param("venueId") Integer venueId, @Param("deviceType") DeviceType deviceType);
|
||||
Integer checkDevice(@Param("deviceName") String deviceName,@Param("venueId") Integer venueId);
|
||||
|
||||
/**
|
||||
* 根据记录找设备
|
||||
* @param deviceName
|
||||
* @param venueId
|
||||
* @param deviceType
|
||||
* @return
|
||||
*/
|
||||
Device findByDevice(@Param("deviceName") String deviceName,@Param("venueId") Integer venueId,@Param("deviceType") DeviceType deviceType);
|
||||
Device findByDevice(@Param("deviceName") String deviceName,@Param("venueId") Integer venueId);
|
||||
|
||||
/**
|
||||
* 设备绑定正在扫码的用户
|
||||
*/
|
||||
void bindMember(@Param("bindMember") Integer bindMember,@Param("venueId") Integer venueId,@Param("deviceName") String deviceName,@Param("deviceType")DeviceType deviceType);
|
||||
void bindMember(@Param("bindMember") Integer bindMember,@Param("venueId") Integer venueId,@Param("deviceName") String deviceName);
|
||||
|
||||
/**
|
||||
* 更新设备状态为 2 - 连接成功
|
||||
*/
|
||||
void unBindMember(@Param("venueId") Integer venueId, @Param("deviceName") String deviceName, @Param("deviceType")DeviceType deviceType);
|
||||
void unBindMember(@Param("venueId") Integer venueId, @Param("deviceName") String deviceName);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.sv.service.api;
|
||||
|
||||
import com.enums.DeviceType;
|
||||
import com.enums.VenueTypeEnum;
|
||||
import com.sv.entity.Device;
|
||||
import com.sv.entity.Venue;
|
||||
import com.sv.mapper.DeviceMapper;
|
||||
import com.sv.mapper.VenueMapper;
|
||||
import com.sv.service.api.util.DateUtilCard;
|
||||
import com.ydd.framework.core.exception.ServiceException;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -20,22 +18,22 @@ import java.util.Date;
|
||||
/**
|
||||
* 小程序扫二维码处理
|
||||
*/
|
||||
//@Service("qrCodeService")
|
||||
//@Transactional(readOnly = true)
|
||||
@Service("qrCodeService")
|
||||
@Transactional(readOnly = true)
|
||||
public class QRCodeService {
|
||||
private final Logger logger = LoggerFactory.getLogger(ProtocolService.class);
|
||||
|
||||
// @Resource
|
||||
@Resource
|
||||
private VenueMapper venueMapper;
|
||||
// @Resource
|
||||
@Resource
|
||||
private DeviceMapper deviceMapper;
|
||||
|
||||
public Venue initEnter(Integer venueId,String deviceName,DeviceType deviceType,Integer memberId) throws ServiceException{
|
||||
Integer integer = deviceMapper.checkDevice(deviceName, venueId,deviceType);
|
||||
public Venue initEnter(Integer venueId,String deviceName,Integer memberId) throws ServiceException{
|
||||
Integer integer = deviceMapper.checkDevice(deviceName, venueId);
|
||||
if (integer != 1){
|
||||
throw new ServiceException(com.sv.exception.api.ExceptionCodeTemplate.DEVICE_ERROR);
|
||||
}
|
||||
Device device = deviceMapper.findByDevice(deviceName, venueId, deviceType);
|
||||
Device device = deviceMapper.findByDevice(deviceName, venueId);
|
||||
if (device == null){
|
||||
throw new ServiceException(com.sv.exception.api.ExceptionCodeTemplate.DEVICE_ERROR);
|
||||
}else {
|
||||
@@ -64,13 +62,13 @@ public class QRCodeService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void bindMember(Integer venueId,String deviceName,DeviceType deviceType,Integer memberId){
|
||||
deviceMapper.bindMember(memberId, venueId, deviceName, deviceType);
|
||||
public void bindMember(Integer venueId,String deviceName,Integer memberId){
|
||||
deviceMapper.bindMember(memberId, venueId, deviceName);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void unBindMember(Integer venueId,String deviceName,DeviceType deviceType){
|
||||
deviceMapper.unBindMember(venueId, deviceName, deviceType);
|
||||
public void unBindMember(Integer venueId,String deviceName){
|
||||
deviceMapper.unBindMember(venueId, deviceName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ public class VenueService extends BaseServiceImpl {
|
||||
@Transactional
|
||||
public synchronized boolean qrCodeEnterVenue(Integer memberId, String deviceName,Integer venueId,Venue venue) {
|
||||
synchronized (("enter" + memberId).intern()) {
|
||||
Device device = deviceService.findByDevice(deviceName,venueId, DeviceType.ENTER);
|
||||
Device device = deviceService.findByDevice(deviceName,venueId);
|
||||
// 查询当前时间内,场馆对应的价格(健身房没有价格)
|
||||
if (venue.getStatus().intValue() == 1) {
|
||||
logger.info(venue.getName() + "被禁用,入场失败");
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.sv.service.oms;
|
||||
|
||||
import com.common.DeviceDTO;
|
||||
import com.enums.DeviceStatusEnum;
|
||||
import com.enums.DeviceType;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.sv.entity.Device;
|
||||
import com.sv.exception.oms.OmsException;
|
||||
@@ -135,25 +134,24 @@ public class DeviceService extends BaseServiceImpl {
|
||||
* 设备连接断开
|
||||
*/
|
||||
@Transactional
|
||||
public void offline(String deviceName, Integer venueId,DeviceType deviceType){
|
||||
deviceMapper.offline(venueId,deviceName,deviceType);
|
||||
public void offline(String deviceName, Integer venueId){
|
||||
deviceMapper.offline(venueId,deviceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新的设备注册的逻辑
|
||||
*/
|
||||
@Transactional
|
||||
public void online(String deviceName,Integer venueId,DeviceType deviceType,Integer venueType,String deviceIp){
|
||||
public void online(String deviceName,Integer venueId,Integer venueType,String deviceIp){
|
||||
Device device = new Device();
|
||||
device.setVenueId(venueId);
|
||||
device.setVenueType(venueType);
|
||||
device.setName(deviceName);
|
||||
device.setStatus(DeviceStatusEnum.ONLINE.value);
|
||||
device.setStream(deviceIp);
|
||||
device.setDeviceType(deviceType);
|
||||
if(deviceMapper.checkDevice(deviceName,venueId,deviceType) > 0){
|
||||
if(deviceMapper.checkDevice(deviceName,venueId) > 0){
|
||||
logger.info(deviceName + venueId + "设备已存在");
|
||||
deviceMapper.online(venueId, deviceName,deviceType);
|
||||
deviceMapper.online(venueId, deviceName);
|
||||
}else {
|
||||
logger.info("落地客户端信息clientId = " + deviceIp + "&deviceName = " + deviceName + "&venueId = " + venueId);
|
||||
deviceMapper.insert(device);
|
||||
@@ -192,8 +190,8 @@ public class DeviceService extends BaseServiceImpl {
|
||||
/**
|
||||
* find by DeviceName
|
||||
*/
|
||||
public Device findByDevice(String deviceName, Integer venueId, DeviceType deviceType){
|
||||
return deviceMapper.findByDevice(deviceName,venueId,deviceType);
|
||||
public Device findByDevice(String deviceName, Integer venueId){
|
||||
return deviceMapper.findByDevice(deviceName,venueId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user