用spring-boot和netty做一个心跳程序,安卓端和服务端连接,服务端检查客户端是否在线,并且记录在线时间和离开时间,并保存到数据库中,现在调用service层的方法时,出现了java.lang.NullPointerException
,下面是部分代码:
@SpringBootApplication
public class App
{
public static void main(String[] args)
{
SpringApplication.run(App.class, args);
HeartbeatServer.start(8089);
}
}
public class HeartbeatServer
{
public static void start(int port)
{
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
try
{
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 10000).childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
public void initChannel(SocketChannel ch) throws Exception
{
ch.pipeline().addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())).addLast("decoder", new StringDecoder()).addLast("encoder", new StringEncoder()).addLast(new IdleStateHandler(60, 0, 0), // 心跳控制
new ServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(port).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} catch (InterruptedException e)
{
e.printStackTrace();
} finally
{
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
@Component
public class ServerHandler extends SimpleChannelInboundHandler<String>
{
private long comingTime;
private long leaveTime;
private Map<String, Integer> users = new HashMap<String, Integer>();
@Autowired
@Qualifier(CompanyAttendanceService.SERVICE_NAME)
private CompanyAttendanceService cs;
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception
{
comingTime = System.currentTimeMillis();
System.out.println(ctx.channel().remoteAddress() + "连接成功:" + comingTime);
ctx.fireChannelRegistered();
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String message) throws Exception
{
Channel incoming = ctx.channel();
Integer userId = users.get(ctx.channel().remoteAddress());
if (userId == null)
{
cs.updateLeaveTime(Integer.valueOf(message), comingTime);
}
users.put(incoming.localAddress().toString(), Integer.valueOf(message));
System.out.println("收到客户端" + "[" + incoming.remoteAddress() + "]" + "的消息:" + message);
incoming.writeAndFlush("[" + incoming.remoteAddress() + "]" + message + "\n");
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
Channel incoming = ctx.channel();
System.out.println(incoming.remoteAddress() + "在线");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
{
Channel incoming = ctx.channel();
System.out.println(incoming.remoteAddress() + "异常");
// 当出现异常就关闭连接
cause.printStackTrace();
ctx.close();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception
{
leaveTime = System.currentTimeMillis();
Channel incoming = ctx.channel();
int userId = users.get(incoming.localAddress().toString());
System.out.println(incoming.remoteAddress() + "掉线,userId:" + userId);
users.remove(incoming.localAddress().toString());
cs.updateOnlineTime(userId, leaveTime, comingTime);
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception
{
/* 心跳处理 */
if (evt instanceof IdleStateEvent)
{
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.READER_IDLE)
{
/* 读超时 */
System.out.println("READER_IDLE 读超时");
ctx.disconnect();
} else if (event.state() == IdleState.WRITER_IDLE)
{
/* 写超时 */
System.out.println("WRITER_IDLE 写超时");
} else if (event.state() == IdleState.ALL_IDLE)
{
/* 总超时 */
System.out.println("ALL_IDLE 总超时");
}
}
}
}
注意这几块代码:
你的原意是想通过
@Component
进行注入,但是你这里的
ServerHandler
是自己new
的,所以Spring就无能为力了所以你这里的
ServerHandler
应该通过Spring创建,交给Spring容器管理