MessagePushTravel/pom.xml
New file @@ -0,0 +1,83 @@ <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.sinata</groupId> <artifactId>message</artifactId> <version>1.0.0</version> <name>message</name> <description>message-push project for Spring Boot</description> <packaging>jar</packaging> <properties> <java.version>1.8</java.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- netty --> <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.27.Final</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.25</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> MessagePushTravel/src/main/java/com/sinata/push/MessagePushApplication.java
New file @@ -0,0 +1,19 @@ package com.sinata.push; import com.sinata.push.util.applets.NettyServer0; import com.sinata.push.util.echo.NettyServer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MessagePushApplication { public static void main(String[] args) { SpringApplication.run(MessagePushApplication.class, args); NettyServer nettyServer = new NettyServer(); nettyServer.bind(); NettyServer0 nettyServer0 = new NettyServer0(); nettyServer0.bind(); } } MessagePushTravel/src/main/java/com/sinata/push/controller/NettyController.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/controller/NettyController.java @@ -1,11 +1,11 @@ package com.sinata.zuul.controller; package com.sinata.push.controller; import com.alibaba.fastjson.JSON; import com.sinata.zuul.util.ResultUtil; import com.sinata.zuul.util.applets.NettyWebSocketController; import com.sinata.zuul.util.echo.NettyChannelMap; import com.sinata.zuul.util.echo.NettyServerController; import com.sinata.push.util.ResultUtil; import com.sinata.push.util.applets.NettyWebSocketController; import com.sinata.push.util.echo.NettyChannelMap; import com.sinata.push.util.echo.NettyServerController; import io.netty.channel.ChannelHandlerContext; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; MessagePushTravel/src/main/java/com/sinata/push/util/NettyStartListener.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/NettyStartListener.java @@ -1,7 +1,4 @@ package com.sinata.zuul.util; import com.sinata.zuul.util.applets.NettyServer0; import com.sinata.zuul.util.echo.NettyServer; package com.sinata.push.util; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; @@ -19,11 +16,11 @@ Thread thread = new Thread(new Runnable() { @Override public void run() { NettyServer nettyServer = new NettyServer(); nettyServer.bind(); NettyServer0 nettyServer0 = new NettyServer0(); nettyServer0.bind(); // NettyServer nettyServer = new NettyServer(); // nettyServer.bind(); // // NettyServer0 nettyServer0 = new NettyServer0(); // nettyServer0.bind(); } }); thread.start(); MessagePushTravel/src/main/java/com/sinata/push/util/ResultUtil.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/ResultUtil.java @@ -1,13 +1,10 @@ package com.sinata.zuul.util; package com.sinata.push.util; import com.alibaba.fastjson.JSONObject; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; /** * 定义统一返回对象 */ @ApiModel(value = "统一返回结果集") public class ResultUtil<T> { public static final Integer SUCCESS = 200; @@ -26,13 +23,10 @@ public static final String SIGN = "SIGN_INVALID"; @ApiModelProperty(name = "code", value = "业务状态码 200:成功,300:参数错误,400:运行异常,500:其他异常, 600:token无效,需重新登录,700:签名无效") private Integer code;//备用状态码 @ApiModelProperty(name = "msg", value = "返回结果说明") private String msg;//返回说明 @ApiModelProperty(name = "data", value = "返回结果值") private T data;//返回数据 MessagePushTravel/src/main/java/com/sinata/push/util/SinataUtil.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/SinataUtil.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util; package com.sinata.push.util; import java.io.UnsupportedEncodingException; import java.text.DecimalFormat; MessagePushTravel/src/main/java/com/sinata/push/util/SpringUtil.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/SpringUtil.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util; package com.sinata.push.util; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; MessagePushTravel/src/main/java/com/sinata/push/util/StringUtil.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/StringUtil.java @@ -1,6 +1,6 @@ package com.sinata.zuul.util; package com.sinata.push.util; import org.apache.commons.lang.StringUtils; public class StringUtil { @@ -65,37 +65,6 @@ } /** * 过滤掉字符串中的表情 * @param source * @return */ public static String filterEmoji(String source) { if (StringUtils.isBlank(source)) { return source; } StringBuilder buf = null; int len = source.length(); for (int i = 0; i < len; i++) { char codePoint = source.charAt(i); if (isEmojiCharacter(codePoint)) { if (buf == null) { buf = new StringBuilder(source.length()); } buf.append(codePoint); } } if (buf == null) { return source; } else { if (buf.length() == len) { buf = null; return source; } else { return buf.toString(); } } } /** MessagePushTravel/src/main/java/com/sinata/push/util/URLUtil.java
New file @@ -0,0 +1,12 @@ package com.sinata.push.util; /** * @author zhibing.pu * @Date 2025/6/22 0:33 */ public interface URLUtil { /** * 业务网关接口地址 */ String zuul = "http://172.21.35.45:80"; } MessagePushTravel/src/main/java/com/sinata/push/util/applets/CacheType.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/CacheType.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; /** * 缓存消息类型 MessagePushTravel/src/main/java/com/sinata/push/util/applets/ChildChannelHandler.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/ChildChannelHandler.java @@ -1,26 +1,37 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.ssl.ClientAuth; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import io.netty.handler.stream.ChunkedWriteHandler; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import java.io.File; public class ChildChannelHandler extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { // String path = "D:\\Program Files\\Apache Software Foundation\\Tomcat 8.5-80\\cert\\6855055_zhentonggongsi.com.pfx"; // String path = "/usr/local/server/apache-tomcat-80/conf/cert/6064978_okyueche.com.pfx"; // String path = "C:\\app\\cert\\tomcat\\www.gzjwzc.com.pfx"; // SSLContext sslContext = createSSLContext.createSSLContext("PKCS12" // , path, "jBOjj2fR"); // SSLEngine 此类允许使用ssl安全套接层协议进行安全通信 // , path, "79uc9bsd"); // SSLEngine engine = sslContext.createSSLEngine(); // engine.setUseClientMode(false); // socketChannel.pipeline().addLast("ssl", new SslHandler(engine)); File path = new File("/root/server/app/cert/qytzt.cn.key"); File path1 = new File("/root/server/app/cert/qytzt.cn.pem"); SslContext sslContext = SslContextBuilder.forServer(path, path1, null).clientAuth(ClientAuth.NONE).build(); //SSLEngine 此类允许使用ssl安全套接层协议进行安全通信 SSLEngine engine = sslContext.newEngine(socketChannel.alloc()); engine.setUseClientMode(false); socketChannel.pipeline().addLast("ssl", new SslHandler(engine)); // 设置30秒没有读到数据,则触发一个READER_IDLE事件。 // pipeline.addLast(new IdleStateHandler(30, 0, 0)); MessagePushTravel/src/main/java/com/sinata/push/util/applets/ClientPingMessage.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/ClientPingMessage.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import java.io.Serializable; MessagePushTravel/src/main/java/com/sinata/push/util/applets/Global.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/Global.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; MessagePushTravel/src/main/java/com/sinata/push/util/applets/NettyServer0.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/NettyServer0.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; @@ -64,7 +64,7 @@ // ChildChannelHandler 对出入的数据进行的业务操作,其继承ChannelInitializer b.childHandler(new ChildChannelHandler()); System.out.println("服务端开启等待客户端连接 ... ..."); Channel ch = b.bind(5300).sync().channel(); Channel ch = b.bind(8888).sync().channel(); ch.closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); MessagePushTravel/src/main/java/com/sinata/push/util/applets/NettyWebSocketController.java
New file @@ -0,0 +1,198 @@ package com.sinata.push.util.applets; import com.alibaba.fastjson.JSONObject; import com.sinata.push.util.SinataUtil; import com.sinata.push.util.SpringUtil; import com.sinata.push.util.StringUtil; import com.sinata.push.util.echo.Method; import com.sinata.push.util.echo.NettyChannelMap; import com.sinata.push.util.echo.NettyMsg; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.HashMap; import java.util.Hashtable; import java.util.Timer; import java.util.TimerTask; public class NettyWebSocketController { public static Hashtable<String, Hashtable<ChannelHandlerContext, String>> map = new Hashtable<String, Hashtable<ChannelHandlerContext,String>>(); private RedisTemplate<String, String> redisTemplate = SpringUtil.getObject(StringRedisTemplate.class); public static Hashtable<String,String> table; static{ if(table == null){ table = new Hashtable<>(); } } public static boolean isdebug = false; public static int i = 0; /** * 判断客户端要执行什么操作 * * @param ctx * @param msg * @author TaoNingBo */ public void JudgeOperation(ChannelHandlerContext ctx, String msg) { try { // 验证即时通讯命令是否正确有效 if(SinataUtil.isEmpty(msg)) { return; } String msgStr = msg.toString(); if(msgStr.indexOf("{") == -1 || msgStr.indexOf("}") == -1 || msgStr.indexOf("code") == -1 || msgStr.indexOf("msg") == -1 || msgStr.indexOf("data") == -1 || msgStr.indexOf("method") == -1) { return; } if(isdebug) { // System.out.println("<<<--receive-->>>111" + msg); } // 获取socket信息,保存相应的socket JSONObject jsonMsg = JSONObject.parseObject(msg.toString()); int code = jsonMsg.getIntValue("code"); String message = jsonMsg.getString("msg"); String method = jsonMsg.getString("method"); if(code != 200 || !message.equals("SUCCESS")) { return; } JSONObject jsonCon = JSONObject.parseObject(jsonMsg.get("data").toString()); // ############################### 心跳 ############################ // 心跳 if(method.equals(Method.ping)){ String token = jsonCon.getString("token"); String userId1 = jsonCon.getString("userId"); if(StringUtil.isNotEmpty(userId1)){ //确保账号在单个设备上登录 if(StringUtil.isNotEmpty(token)){ String token_ = (String)redisTemplate.opsForValue().get("USER_" + userId1);//获取缓存中最新的数据 if(StringUtil.isNotEmpty(token_) && !token.equals(token_)){//不在同一设备上登录,向其他设备发送数据 ChannelHandlerContext context = NettyChannelMap.getData("Applets" + userId1); JSONObject msg_ = new JSONObject(); msg_.put("code", 200); msg_.put("msg", "SUCCESS"); msg_.put("method", "OFFLINE"); msg_.put("data", new Object()); this.sendMsgToClient(context, msg_.toJSONString()); TimerTask timerTask = new TimerTask() { @Override public void run() { NettyChannelMap.remove(context); } }; Timer timer = new Timer(); timer.schedule(timerTask, 3000); timer.cancel(); } if(StringUtil.isEmpty(token_)){//确保登录的时候存储token失败的情况 redisTemplate.opsForValue().set("USER_" + userId1, token); } } //存储业务使用的通道 if(null != ctx && ctx.channel().isActive()) { NettyChannelMap.update("Applets" + userId1, ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); } } } } catch (Exception e) { if(isdebug) { NettyWebSocketController.sendMsgToClient(ctx, "__error__" + msg.toString()); } e.printStackTrace(); } } /** * 向客户端发送消息 * * @param ctx * @param msg * @author TaoNingBo */ public static void sendMsgToClient(ChannelHandlerContext ctx, String msg) { // System.out.println(ctx.channel().isActive()); if (ctx != null && ctx.channel().isActive()) { ByteBuf buffer = Unpooled.copiedBuffer((msg).getBytes()); ChannelFuture sync; try { sync = ctx.channel().writeAndFlush(new TextWebSocketFrame(msg)).sync(); if(!sync.isSuccess()){ boolean b = true; for (int i = 0; i < 10; i++) { ctx.wait(3000); sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); if(sync.isSuccess()){ b = false; break; } System.err.println("小程序-》推送不成功,将继续推送"+msg); } if(b){ NettyChannelMap.remove(ctx); } } } catch (Exception e) { System.err.println("小程序-》推送发生异常,记录:"+msg); NettyChannelMap.remove(ctx); } if(isdebug) { System.err.println("小程序-》 <<<--send-->>>" + msg) ; } }else{ System.err.println("小程序-》推送失败,长连接不存在"); NettyChannelMap.remove(ctx); } } // **链接断开 将推送消息记录 public static void sendMsgToClient(String cacheType, Integer id,String msg) { ChannelHandlerContext ctx = NettyChannelMap.getData(cacheType + id); if (ctx != null) { ChannelFuture sync; try { sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync(); if(!sync.isSuccess()){ for (int i = 0; i < 10; i++) { sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync();; if(!sync.isSuccess()){ sync = ctx.channel().write(new TextWebSocketFrame(msg)).sync();; System.err.println("推送不成功,将继续推送"+msg); if(i == 9){ table.put(cacheType+id, msg); ctx.close(); System.err.println("推送发生异常,记录:"+msg); } }else{ break; } } } } catch (Exception e) { table.put(cacheType+id, msg); System.err.println("推送发生异常,记录:"+msg); } if(isdebug) { System.err.println("<<<--send-->>>" + msg); } }else{ table.put(cacheType+id, msg); System.err.println("链接断开,记录:id="+cacheType+id+",消息:"+msg); } } } MessagePushTravel/src/main/java/com/sinata/push/util/applets/WebSocketHandler.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/WebSocketHandler.java @@ -1,9 +1,9 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import com.alibaba.fastjson.JSONObject; import com.sinata.zuul.util.echo.Method; import com.sinata.zuul.util.echo.NettyChannelMap; import com.sinata.zuul.util.echo.NettyMsg; import com.sinata.push.util.echo.Method; import com.sinata.push.util.echo.NettyChannelMap; import com.sinata.push.util.echo.NettyMsg; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; @@ -23,7 +23,7 @@ //用于websocket握手的处理类 private WebSocketServerHandshaker handshaker; private static final String WEB_SOCKET_URL = "ws://localhost:9090/websocket"; private static final String WEB_SOCKET_URL = "wss://localhost:8808/websocket"; MessagePushTravel/src/main/java/com/sinata/push/util/applets/createSSLContext.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/applets/createSSLContext.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.applets; package com.sinata.push.util.applets; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; MessagePushTravel/src/main/java/com/sinata/push/util/echo/DiscardServerHandler.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/DiscardServerHandler.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; @@ -104,7 +104,7 @@ // System.err.println(insocket.getAddress() + ": Disconnect connection......"); } NettyChannelMap.remove(ctx); // System.err.println("清除通道" + ctx); System.err.println("清除通道" + ctx); // super.channelInactive(ctx); } MessagePushTravel/src/main/java/com/sinata/push/util/echo/Method.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/Method.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; /** * 即时通讯【通讯类型类】 @@ -14,9 +14,6 @@ /** 心跳【接收】 */ public final static String ping = "PING"; /** 心跳【响应】 */ public final static String pong = "PONG"; /** 司机上传位置 */ public static final String location = "LOCATION"; MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyChannelMap.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/NettyChannelMap.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import io.netty.channel.ChannelHandlerContext; @@ -91,18 +91,6 @@ } public static synchronized void remove_(ChannelHandlerContext value) { Set<String> strings = ctxMap.keySet(); for(String key : strings){ ChannelHandlerContext channelHandlerContext = ctxMap.get(key); String s = channelHandlerContext.channel().remoteAddress().toString(); String s1 = value.channel().remoteAddress().toString(); if(s.equals(s1)){ channelHandlerContext.close();//关闭通道 ctxMap.remove(key); } } } /** @@ -125,9 +113,4 @@ map.put(key, value); } public static synchronized void update_(String key, ChannelHandlerContext value) { ctxMap.put(key, value); } } MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyMsg.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/NettyMsg.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyServer.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/NettyServer.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; @@ -50,7 +50,7 @@ /** * 获取即时通讯启动端口 */ private Integer nettyPort = 5200; private Integer nettyPort = 9999; @Override public void run() { EventLoopGroup bossGroup = new NioEventLoopGroup(); @@ -61,7 +61,7 @@ bootstrap.channel(NioServerSocketChannel.class); bootstrap.option(ChannelOption.SO_BACKLOG, 1024); // 通过TCP_NODELAY禁用NAGLE,使消息立即发出去,不用等待到一定的数据量才发出去 bootstrap.option(ChannelOption.TCP_NODELAY, true); bootstrap.childOption(ChannelOption.TCP_NODELAY, true); // 保持长连接状态 bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); bootstrap.childHandler(new ServerInit() { MessagePushTravel/src/main/java/com/sinata/push/util/echo/NettyServerController.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/NettyServerController.java @@ -1,20 +1,28 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.sinata.zuul.util.*; import com.sinata.push.util.*; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.client.RestTemplate; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.TimeUnit; /** @@ -29,11 +37,9 @@ public static Hashtable<String,String> table; private RedisUtil redisUtil = SpringUtil.getObject(RedisUtil.class); private RedisTemplate<String, String> redisTemplate = SpringUtil.getObject(StringRedisTemplate.class); private GDMapGeocodingUtil gdMapGeocodingUtil = SpringUtil.getObject(GDMapGeocodingUtil.class); private RestTemplate internalRestTemplate = SpringUtil.getObject(RestTemplate.class); private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); @@ -85,11 +91,6 @@ } JSONObject jsonCon = JSONObject.parseObject(jsonMsg.get("data").toString()); if(null != ctx && ctx.channel().isActive()){ jsonMsg.put("method", Method.pong); sendMsgToClient(ctx, jsonMsg.toJSONString()); } //心跳 if(method.equals(Method.ping)) { Integer type = jsonCon.getInteger("type"); @@ -98,62 +99,74 @@ String device = jsonCon.getString("device"); String version = jsonCon.getString("version"); if(StringUtil.isNotEmpty(userId1)){ String fluid_control = redisTemplate.opsForValue().get("fluid_control_" + userId1 + "_" + type); if(!StringUtils.hasLength(fluid_control)){ redisTemplate.opsForValue().set("fluid_control_" + userId1 + "_" + type, System.currentTimeMillis() + ""); }else{ long l = System.currentTimeMillis() - Long.valueOf(fluid_control); if(l >= 10000){ redisTemplate.opsForValue().set("fluid_control_" + userId1 + "_" + type, System.currentTimeMillis() + ""); }else{ String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); return; } } //判断用户或者司机长连接 //判断用户或者司机长连接 if(type==1){ //确保账号在单个设备上登录 if(StringUtil.isNotEmpty(token)){ String token_ = redisUtil.getValue("USER_APP_"+ userId1);//获取缓存中最新的数据 String token_ = (String)redisTemplate.opsForValue().get("USER_" + userId1);//获取缓存中最新的数据 if(StringUtil.isNotEmpty(token_) && !token.equals(token_)){//不在同一设备上登录,向其他设备发送数据 JSONObject msg_ = new JSONObject(); ChannelHandlerContext context = NettyChannelMap.getData("USER" + userId1); JSONObject msg_ = new JSONObject(); msg_.put("code", 200); msg_.put("msg", "SUCCESS"); msg_.put("method", "OFFLINE"); msg_.put("data", new Object()); this.sendMsgToClient(ctx, msg_.toJSONString());//给当前通道发送消息 this.sendMsgToClient(context, msg_.toJSONString());//给当前通道发送消息 TimerTask timerTask = new TimerTask() { @Override public void run() { NettyChannelMap.remove_(ctx); NettyChannelMap.remove(ctx); NettyChannelMap.remove(context); } }; Timer timer = new Timer(); timer.schedule(timerTask, 3000); timer.cancel(); }else{ NettyChannelMap.update_(token.substring(0, 23), ctx); NettyChannelMap.update("USER" + userId1, ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); } } if(StringUtil.isEmpty(token_)){//确保登录的时候存储token失败的情况 redisUtil.setStrValue("USER_APP_" + userId1, token); redisTemplate.opsForValue().set("USER_" + userId1, token); } } //存储通讯通道 if(null != ctx && ctx.channel().isActive()){ System.err.println("开始存储用户通道:" + sdf.format(new Date()) + "----" + userId1); NettyChannelMap.update("USER" + userId1, ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); } }else{ //添加司机在线 HttpHeaders headers = new HttpHeaders(); // 以表单的方式提交 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); //将请求头部和参数合成一个请求 MultiValueMap<String, Object> params = new LinkedMultiValueMap<>(); params.add("driverId", userId1); params.add("device", (null != device && device.equals("carDevice")) ? "2" : "1"); params.add("version", version); HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers); String w = internalRestTemplate.postForObject("http://driver-server/base/driverOnline/addDriverOnline",requestEntity , String.class); JSONObject jsonObject = JSON.parseObject(w, JSONObject.class); Map<String, Object> params = new HashMap<>(); params.put("driverId", userId1); HttpRequest post = HttpUtil.createPost(URLUtil.zuul + "/driver-server/base/driverOnline/addDriverOnline"); post.contentType(MediaType.APPLICATION_FORM_URLENCODED.getType()); post.form(params); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ System.err.println("调用driver-server添加司机在线数据出错了"); } JSONObject jsonObject = JSON.parseObject(execute.body(), JSONObject.class); if(jsonObject.getIntValue("code") != 200){ System.err.println("调用driver-server添加司机在线数据出错了"); } //TODO 存储最后一次上传的时间(用于保证车载端断电后1小时自动下班) if(StringUtil.isNotEmpty(device) && device.equals("carDevice")){ redisUtil.setStrValue("DEVICE_" + userId1, String.valueOf(System.currentTimeMillis())); redisTemplate.opsForValue().set("DEVICE_" + userId1, String.valueOf(System.currentTimeMillis())); String token_ = redisUtil.getValue("DRIVER_" + userId1);//缓存中拿最新数据 String token_ = (String)redisTemplate.opsForValue().get("DRIVER_" + userId1);//缓存中拿最新数据 if(StringUtil.isNotEmpty(token_) && !token_.equals(token)){ //如果是车载端登录,则将其它端都强迫下线 JSONObject msg_ = new JSONObject(); @@ -165,63 +178,50 @@ TimerTask timerTask = new TimerTask() { @Override public void run() { NettyChannelMap.remove_(ctx); NettyChannelMap.remove(ctx); } }; Timer timer = new Timer(); timer.schedule(timerTask, 3000); timer.cancel(); }else{ // System.err.println("开始存储司机通道" + userId1); NettyChannelMap.update("DRIVER" + userId1, ctx); NettyChannelMap.update_(token.substring(0, 23), ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); } if(StringUtil.isEmpty(token_)){//确保登录的时候存储token失败的情况 redisUtil.setStrValue("DRIVER_" + userId1, token); redisTemplate.opsForValue().set("DRIVER_" + userId1, token); } } //确保账号在单个设备上登录 String value = redisUtil.getValue("DEVICE_" + userId1); String value = (String)redisTemplate.opsForValue().get("DEVICE_" + userId1); if(StringUtil.isNotEmpty(token) && StringUtil.isEmpty(value)){//APP端登录的操作 String token_ = redisUtil.getValue("DRIVER_" + userId1);//缓存中拿最新数据 String token_ = (String)redisTemplate.opsForValue().get("DRIVER_" + userId1);//缓存中拿最新数据 if(StringUtil.isNotEmpty(token_) && !token.equals(token_)){//不在同一设备上登录,向当前设备发送数据 JSONObject msg_ = new JSONObject(); ChannelHandlerContext context = NettyChannelMap.getData("DRIVER" + userId1); JSONObject msg_ = new JSONObject(); msg_.put("code", 200); msg_.put("msg", "SUCCESS"); msg_.put("method", "OFFLINE"); msg_.put("data", new Object()); this.sendMsgToClient(ctx, msg_.toJSONString());//给当前通道发送消息 this.sendMsgToClient(context, msg_.toJSONString());//给当前通道发送消息 TimerTask timerTask = new TimerTask() { @Override public void run() { NettyChannelMap.remove_(ctx); NettyChannelMap.remove(ctx); NettyChannelMap.remove(context); } }; Timer timer = new Timer(); timer.schedule(timerTask, 3000); timer.cancel(); }else{ // System.err.println("开始存储司机通道" + userId1); NettyChannelMap.update("DRIVER" + userId1, ctx); NettyChannelMap.update_(token.substring(0, 23), ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); } } if(StringUtil.isEmpty(token_)){//确保登录的时候存储token失败的情况 redisUtil.setStrValue("DRIVER_" + userId1, token); redisTemplate.opsForValue().set("DRIVER_" + userId1, token); } } //存储通讯通道 if(null != ctx && ctx.channel().isActive()){ // System.err.println("开始存储司机通道" + userId1); System.err.println("开始存储司机通道:" + sdf.format(new Date()) + "----" + userId1); NettyChannelMap.update("DRIVER" + userId1, ctx); String s = NettyMsg.setMsg(Method.ok, new HashMap<String, Object>()); ctx.writeAndFlush(Unpooled.copiedBuffer((s).getBytes())); @@ -232,35 +232,49 @@ //司机上传位置 if(method.equals(Method.location)){ Integer driverId = jsonCon.getInteger("driverId"); String fluid_control = (String)redisTemplate.opsForValue().get("location_" + driverId); if(!StringUtils.hasLength(fluid_control)){ redisTemplate.opsForValue().set("location_" + driverId, System.currentTimeMillis() + ""); }else{ long l = System.currentTimeMillis() - Long.valueOf(fluid_control); if(l < 5000){ return; } redisTemplate.opsForValue().set("location_" + driverId, System.currentTimeMillis() + ""); } Integer orderId = jsonCon.getInteger("orderId"); Integer orderType = jsonCon.getInteger("orderType"); Double lon = jsonCon.getDouble("lon"); Double lat = jsonCon.getDouble("lat"); Double computeAzimuth = jsonCon.getDouble("computeAzimuth"); Double altitude = jsonCon.getDouble("altitude"); System.out.println("司机上传位置:" + sdf.format(new Date()) + "----" + driverId); if(SinataUtil.isNotEmpty(driverId)){ if(null != lon && 0 != lon && null != lat && 0 != lat){ if(null != orderId && 0 != driverId && null != orderType && 0 != orderType){//开始存入数据库 HttpHeaders headers = new HttpHeaders(); // 以表单的方式提交 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); //将请求头部和参数合成一个请求 MultiValueMap<String, Object> params = new LinkedMultiValueMap<>(); params.add("orderType", String.valueOf(orderType)); params.add("orderId", String.valueOf(orderId)); params.add("driverId", String.valueOf(driverId)); params.add("lon", String.valueOf(lon)); params.add("lat", String.valueOf(lat)); params.add("directionAngle", String.valueOf(computeAzimuth)); params.add("altitude", String.valueOf(altitude)); HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers); String s = internalRestTemplate.postForObject("http://driver-server/base/savePosition",requestEntity , String.class); JSONObject jsonObject = JSON.parseObject(s, JSONObject.class); Map<String, Object> params = new HashMap<>(); params.put("orderType", String.valueOf(orderType)); params.put("orderId", String.valueOf(orderId)); params.put("driverId", String.valueOf(driverId)); params.put("lon", String.valueOf(lon)); params.put("lat", String.valueOf(lat)); params.put("directionAngle", String.valueOf(computeAzimuth)); params.put("altitude", String.valueOf(altitude)); HttpRequest post = HttpUtil.createPost(URLUtil.zuul + "/driver-server/base/savePosition"); post.contentType(MediaType.APPLICATION_FORM_URLENCODED.getType()); post.form(params); HttpResponse execute = post.execute(); if(200 != execute.getStatus()){ System.err.println("调用driver-server存储位置数据出错了"); } JSONObject jsonObject = JSON.parseObject(execute.body(), JSONObject.class); if(jsonObject.getIntValue("code") != 200){ System.err.println("调用driver-server存储位置数据出错了"); } } redisUtil.setStrValue("DRIVER" + driverId, lon + "," + lat, 300);//实时位置存入redis中 System.out.println("id:" + driverId + "---lon" + lon + "---lat" + lat); redisTemplate.opsForValue().set("DRIVER" + driverId, lon + "," + lat, 300, TimeUnit.SECONDS);//实时位置存入redis中 }else{ NettyServerController.sendMsgToClient(ctx, "__error__" + msg.toString()); } MessagePushTravel/src/main/java/com/sinata/push/util/echo/ServerInit.java
File was renamed from ZuulQYTTravel/src/main/java/com/sinata/zuul/util/echo/ServerInit.java @@ -1,4 +1,4 @@ package com.sinata.zuul.util.echo; package com.sinata.push.util.echo; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; MessagePushTravel/src/main/resources/application.yml
New file @@ -0,0 +1,39 @@ server: port: 6000 spring: profiles: active: prod application: name: message #服务名称 servlet: multipart: max-request-size: 100MB max-file-size: 100MB data: redis: host: 172.21.35.151 database: 0 password: SC_cache@20#25 time-out: 1000 # 集群节点 cluster: nodes: 172.21.35.151:6512,172.21.35.152:6512,172.21.35.153:6512,172.21.35.151:6513,172.21.35.152:6513,172.21.35.153:6513 # 重定向最大次数 max-redirects: 3 lettuce: cluster: refresh: # 集群拓扑自适应刷新 adaptive: true # 集群拓扑刷新周期 毫秒 period: 3000 pool: # 最大链接数量 max-active: 100 # 最大阻塞时间 负数没有限制 max-wait: -1 # 最大空闲链接 max-idle: 10 # 最小空闲链接 min-idle: 0 MessagePushTravel/src/main/resources/logback.xml
New file @@ -0,0 +1,222 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,比如: 如果设置为WARN,则低于WARN的信息都不会输出 --> <!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true --> <!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 --> <!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="true" scanPeriod="10 seconds"> <contextName>logback</contextName> <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 --> <property name="log.path" value="/root/server/app/logs"/> <!--0. 日志格式和颜色渲染 --> <!-- 彩色日志依赖的渲染类 --> <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /> <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /> <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /> <!-- 彩色日志格式 --> <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/> <!--1. 输出到控制台--> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息--> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>debug</level> </filter> <encoder> <Pattern>${CONSOLE_LOG_PATTERN}</Pattern> <!-- 设置字符集 --> <charset>UTF-8</charset> </encoder> </appender> <!--2. 输出到文档--> <!-- 2.1 level为 DEBUG 日志,时间滚动输出 --> <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/debug.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 日志归档 --> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录debug级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>debug</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.2 level为 INFO 日志,时间滚动输出 --> <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/info.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 每天日志归档路径以及格式 --> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/info-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录info级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>info</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.3 level为 WARN 日志,时间滚动输出 --> <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/warn.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录warn级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>warn</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.4 level为 ERROR 日志,时间滚动输出 --> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/error.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/error-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档只记录ERROR级别的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <!-- 2.5 所有 除了DEBUG级别的其它高于DEBUG的 日志,记录到一个文件 --> <appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 正在记录的日志文档的路径及文档名 --> <file>${log.path}/all.log</file> <!--日志文档输出格式--> <encoder> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> <charset>UTF-8</charset> <!-- 此处设置字符集 --> </encoder> <!-- 日志记录器的滚动策略,按日期,按大小记录 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log.path}/%d{yyyy-MM-dd}/all-%d{yyyy-MM-dd}.%i.log</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> <!--日志文档保留天数--> <maxHistory>15</maxHistory> </rollingPolicy> <!-- 此日志文档记录除了DEBUG级别的其它高于DEBUG的 --> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>DEBUG</level> <onMatch>DENY</onMatch> <onMismatch>ACCEPT</onMismatch> </filter> </appender> <!-- <logger>用来设置某一个包或者具体的某一个类的日志打印级别、 以及指定<appender>。<logger>仅有一个name属性, 一个可选的level和一个可选的addtivity属性。 name:用来指定受此logger约束的某一个包或者具体的某一个类。 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。 如果未设置此属性,那么当前logger将会继承上级的级别。 addtivity:是否向上级logger传递打印信息。默认是true。 <logger name="org.springframework.web" level="info"/> <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/> --> <!-- root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性 level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF, 不能设置为INHERITED或者同义词NULL。默认是DEBUG 可以包含零个或多个元素,标识这个appender将会添加到这个logger。 --> <!-- 4 最终的策略: 基本策略(root级) + 根据profile在启动时, logger标签中定制化package日志级别(优先级高于上面的root级)--> <springProfile name="dev"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> <logger name="com.stylefeng.guns.modular.system.dao" level="debug"/> </springProfile> <springProfile name="test"> <root level="info"> <appender-ref ref="CONSOLE" /> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> </springProfile> <springProfile name="prod"> <root level="info"> <!-- 生产环境最好不配置console写文件 --> <appender-ref ref="DEBUG_FILE" /> <appender-ref ref="INFO_FILE" /> <appender-ref ref="WARN_FILE" /> <appender-ref ref="ERROR_FILE" /> <appender-ref ref="ALL_FILE" /> </root> </springProfile> </configuration> MessagePushTravel/src/main/resources/static/tXQaRbVjpJ.txt