Przeglądaj źródła

1.添加一个socket测试

slambb 3 lat temu
rodzic
commit
f23db17032

+ 8 - 0
src/main/java/com/YuyeTech/TPlat/TPlatApplication.java

@@ -238,4 +238,12 @@ class IndexController {
     public ModelAndView logging() {
         return new ModelAndView("logging.html", "port", port);
     }
+
+    /**
+     * 跳转App实时日志
+     */
+    @GetMapping("appLogging")
+    public ModelAndView appLogging() {
+        return new ModelAndView("appLogging.html", "port", port);
+    }
 }

+ 1 - 0
src/main/java/com/YuyeTech/TPlat/common/service/CommonService.java

@@ -22,6 +22,7 @@ public interface CommonService<V, E,T> {
 
     Result<List<V>> list(V entityVo);
 
+    List<V> listVo(V entityVo);
 
     Result<V> get(T id);
 

+ 7 - 0
src/main/java/com/YuyeTech/TPlat/common/service/CommonServiceImpl.java

@@ -96,6 +96,13 @@ public class CommonServiceImpl<V, E, T> implements CommonService<V, E, T> {
         return Result.of(entityModelList);
     }
 
+    @Override
+    public List<V> listVo(V entityVo) {
+        List<E> entityList = commonRepository.findAll(Example.of(CopyUtil.copy(entityVo, entityClass)));
+        List<V> entityModelList = CopyUtil.copyList(entityList, entityVoClass);
+        return entityModelList;
+    }
+
     @Override
     public Result<V> get(T id) {
         Optional<E> optionalE = commonRepository.findById(id);

+ 109 - 0
src/main/java/com/YuyeTech/TPlat/config/logback/AppLoggingWSServer.java

@@ -0,0 +1,109 @@
+package com.YuyeTech.TPlat.config.logback;
+
+
+import com.YuyeTech.TPlat.config.websocket.MyEndpointConfigure;
+import com.YuyeTech.TPlat.utils.ErrorUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.thymeleaf.util.StringUtils;
+
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * WebSocket获取实时日志并输出到Web页面
+ */
+@Slf4j
+@Component
+@ServerEndpoint(value = "/websocket/APPLog/{appId}", configurator = MyEndpointConfigure.class)
+public class AppLoggingWSServer {
+
+    @Value("${spring.application.name}")
+    private String applicationName;
+
+    /**
+     * 连接集合
+     */
+    private static Map<String, Session> appSessionMap = new ConcurrentHashMap<String, Session>();
+    private static Map<String, Session> serverSessionMap = new ConcurrentHashMap<String, Session>();
+
+    /**
+     * 定义一个服务器server id
+     */
+    private String serverId = "10000";
+
+    /**
+     * 连接建立成功调用的方法
+     */
+    @OnOpen
+    public void onOpen(@PathParam("appId") String appId, Session session) {
+        //添加到集合中
+        if(appId.equals(serverId)){
+            //定义服务器id = 10000
+            serverSessionMap.put(serverId,session);
+        }else{
+            appSessionMap.put(appId, session);
+        }
+    }
+
+    /**
+     * 连接关闭调用的方法
+     */
+    @OnClose
+    public void onClose(@PathParam("appId") String appId, Session session) {
+        //从集合中删除
+        if(appId.equals(serverId)){
+            //定义服务器id = 10000
+            serverSessionMap.remove(serverId,session);
+        }else{
+            appSessionMap.remove(appId);
+        }
+    }
+
+    /**
+     * 发生错误时调用
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        //输出到日志文件中
+        log.error(ErrorUtil.errorInfoToString(error));
+    }
+
+    /**
+     * 服务器接收到客户端消息时调用的方法
+     */
+    @OnMessage
+    public void onMessage(@PathParam("appId") String appId, String message) {
+        if(appId.equals(serverId)){
+            log.info("服务器"+appId+":"+ message);
+        }else{
+            //如果不是服务器发送的消息
+            log.info("客户端"+appId+":"+ message);
+            serverSessionMap.forEach((sessionId,session) -> send(session,message));
+        }
+    }
+
+    /**
+     * 封装一个send方法,发送消息到前端
+     */
+    private void send(Session session, String message) {
+        try {
+            session.getBasicRemote().sendText(message);
+        } catch (Exception e) {
+            //输出到日志文件中
+            log.error(ErrorUtil.errorInfoToString(e));
+        }
+    }
+}

+ 2 - 1
src/main/java/com/YuyeTech/TPlat/config/security/SecurityConfig.java

@@ -81,7 +81,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 "/reward/**",
                 "/oss/**",
                 "/user_info/**",
-                "/wxlogin/**"
+                "/wxlogin/**",
+                "/websocket/APPLog/**"
                 //,
                 //"/backstage_ble/**"
         );

+ 2 - 1
src/main/java/com/YuyeTech/TPlat/config/token/WebConfig.java

@@ -46,7 +46,8 @@ public class WebConfig {
                 "/oss/*",
                 "/user_info/*",
                 "/wxlogin/*",
-                "/tPlat/*");
+                "/tPlat/*",
+                "/websocket/APPLog/*");
         registration.setName("gameFilter");
         registration.setOrder(1);
         return registration;

+ 4 - 3
src/main/java/com/YuyeTech/TPlat/filter/gameFilter.java

@@ -100,14 +100,15 @@ public class gameFilter implements Filter {
                 path.indexOf("getCode") > -1 ||
                 path.indexOf("dontLogin") > -1 ||
                 path.indexOf("client_game") > -1 ||
-                path.indexOf("findAll")>-1
+                path.indexOf("findAll") > -1 ||
+                path.indexOf("APPLog") > -1
         ) {
             //登录情况直接放行
             filterChain.doFilter(servletRequest, response);
             return;
         }
 
-        log.info("token:"+token);
+        log.info("token:" + token);
         if (null == token || token.isEmpty()) {
             //没有token信息
             ResultVO resultVO = ResultVOUtil.error(ResultEnum.TOKEN_DOES_NOT_EXIST);
@@ -121,7 +122,7 @@ public class gameFilter implements Filter {
                  * token使用redis管理,实时控制登录,下线等操作
                  */
 //                String.format(RedisConstant.TOKEN_PREFIX, token)
-                String userId = redisSettingMap.getValue(RedisType.TOKEN,token);
+                String userId = redisSettingMap.getValue(RedisType.TOKEN, token);
                 //String userId = jwtTokenUtil.getUserIdFromToken(authToken);
                 //if (!jwtTokenUtil.validateToken(authToken, userId)) {
                 //    log.info("secret 不可靠,validateToken:{}", jwtTokenUtil.validateToken(authToken, userId));

+ 28 - 0
src/main/java/com/YuyeTech/TPlat/game/gameInfo/controller/GameInfoController.java

@@ -1,6 +1,7 @@
 package com.YuyeTech.TPlat.game.gameInfo.controller;
 
 import com.YuyeTech.TPlat.VO.ResultVO;
+import com.YuyeTech.TPlat.common.pojo.Result;
 import com.YuyeTech.TPlat.config.GameConfigTime;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameCategory;
 import com.YuyeTech.TPlat.form.GameInfoForm;
@@ -214,6 +215,7 @@ public class GameInfoController {
      * @return
      */
     @GetMapping("/list_from_category_platform")
+    @Deprecated
     public ResultVO getGameListFromCategoryAndPlatform(@RequestParam(value = "categoryType", required = false) Integer categoryType,
                                             @RequestParam(value = "userId", required = false) String userId,
                                             @RequestParam(value = "platform",required = false) Integer platform,
@@ -230,6 +232,32 @@ public class GameInfoController {
         return ResultVOUtil.success(gameDTOList);
     }
 
+    /**
+     * 主要根据tag返回
+     * @param userId
+     * @param platform
+     * @param categoryType
+     * @param tagId
+     * @param page
+     * @param size
+     * @return
+     */
+    @PostMapping("/listByTag")
+    public Result getGameByTag(@RequestParam(value = "userId", required = false) String userId,
+                               @RequestParam(value = "platform",required = false) Integer platform,
+                               @RequestParam(value = "categoryType", required = false) Integer categoryType,
+                               @RequestParam(value = "tagId", required = false) Integer tagId,
+                               @RequestParam(value = "page", defaultValue = "1") Integer page,
+                               @RequestParam(value = "size", defaultValue = "10") Integer size){
+
+        //查询对应游戏数据
+        PageRequest request = PageRequest.of(page - 1, size);
+        List<GameDTO> gameDTOList =  gameInfoService.findListByTag(userId,categoryType,platform,tagId,request);
+
+
+        return Result.of(gameDTOList);
+    }
+
     @GetMapping("/list_by_ranking_show")
     public ResultVO getGameListByRankingShow(@RequestParam(value = "userId", required = false) String userId,
                                             @RequestParam(value = "rankingShow", required = false) Integer rankingShow,

+ 5 - 1
src/main/java/com/YuyeTech/TPlat/game/gameInfo/repository/GameTagReferenceRepository.java

@@ -1,9 +1,11 @@
 package com.YuyeTech.TPlat.game.gameInfo.repository;
 
+import com.YuyeTech.TPlat.common.repository.CommonRepository;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameTagReference;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
 
 import java.util.List;
 
@@ -12,7 +14,9 @@ import java.util.List;
  * @author:slambb
  * @date:2020/1/16
  */
-public interface GameTagReferenceRepository extends JpaRepository<GameTagReference,Integer> {
+//extends JpaRepository<GameTagReference,Integer>
+@Repository
+public interface GameTagReferenceRepository  extends CommonRepository<GameTagReference,Integer> {
 
     Page<GameTagReference> findByGameId(String gameId, Pageable pageable);
 

+ 1 - 0
src/main/java/com/YuyeTech/TPlat/game/gameInfo/service/GameInfoService.java

@@ -27,6 +27,7 @@ public interface GameInfoService extends CommonService<GameInfoVo, GameInfo, Str
      */
     List<GameDTO> findListByTypeAndPlatform(String userId, Integer categoryType, Integer platform, String endTime, Pageable pageable);
 
+    List<GameDTO> findListByTag(String userId, Integer categoryType, Integer platform, Integer tagId, Pageable pageable);
 
     Page<GameInfo> findPage(String userId, Integer categoryType, Pageable pageable);
     /**

+ 62 - 5
src/main/java/com/YuyeTech/TPlat/game/gameInfo/service/GameInfoServiceImpl.java

@@ -7,6 +7,7 @@ import com.YuyeTech.TPlat.enums.PictureType;
 import com.YuyeTech.TPlat.exception.UserException;
 import com.YuyeTech.TPlat.game.gameInfo.repository.GamePicturesRepository;
 import com.YuyeTech.TPlat.game.gameInfo.vo.GameInfoVo;
+import com.YuyeTech.TPlat.game.gameInfo.vo.GameTagReferenceVo;
 import com.YuyeTech.TPlat.game.imageInfo.projo.Pictures;
 import com.YuyeTech.TPlat.game.imageInfo.repository.PicturesRepository;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameInfo;
@@ -157,6 +158,63 @@ public class GameInfoServiceImpl extends CommonServiceImpl<GameInfoVo, GameInfo,
         return gameDTOList;
     }
 
+
+    @Override
+    public List<GameDTO> findListByTag(String userId, Integer categoryType, Integer platform, Integer tagId, Pageable pageable) {
+        GameTagReferenceVo gameTagVo = new GameTagReferenceVo();
+        gameTagVo.setTagId(tagId);
+        List<GameTagReferenceVo> gameTagList = gameTagReferenceService.listVo(gameTagVo);
+        List<String> gameIdList = gameTagList.stream().map(GameTagReferenceVo::getGameId).collect(Collectors.toList());
+
+        //排序规则和分页
+        Specification<GameInfo> specification = new Specification<GameInfo>() {
+            @Override
+            public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
+                //增加筛选条件
+                Predicate predicate = cb.conjunction();
+                predicate.getExpressions().add(cb.equal(root.get("gameStatus").as(String.class), 1));
+
+                if (categoryType != 0) {
+                    predicate.getExpressions().add(cb.equal(root.get("gameType").as(String.class), categoryType));
+                }
+
+                Predicate p1 = cb.equal(root.get("platform").as(String.class), platform);
+                Predicate p2 = cb.equal(root.get("platform").as(String.class), 2);
+                predicate.getExpressions().add(cb.or(p1, p2));
+
+                //game ids  in
+                List<Predicate> list = com.google.common.collect.Lists.newArrayList();
+                if(null!=gameIdList&& gameIdList.size()>0){
+                    CriteriaBuilder.In<String> in = cb.in(root.get("gameId"));
+                    for (String id : gameIdList) {
+                        in.value(id);
+                    }
+                    list.add(in);
+                }
+                predicate.getExpressions().add(cb.and(list.toArray(new Predicate[list.size()])));
+
+                return predicate;
+            }
+        };
+
+        List<GameDTO> gameDTOList = gameInfoRepository.findAll(specification, pageable).stream().map(e -> new GameDTO(
+                e.getGameId(),
+                e.getGameName(),
+                aliyunOSSUtil.addDomainName(e.getGameIcon()),
+                e.getGameDescription(),
+                aliyunOSSUtil.addDomainName(e.getGamePicture()),
+                //获取收藏信息
+                favoritesService.findByUserIdAndFObjectId(userId, e.getGameId()),
+                e.getGameRankingId(),
+                e.getGameRankingShow().equals(1),
+                e.getCreateTime(),
+                gameTagReferenceService.findGameTagByGameId(e.getGameRankingId(), e.getGameId()),
+                e.getPlatform()
+        )).collect(Collectors.toList());
+
+        return gameDTOList;
+    }
+
     @Override
     public Page<GameInfo> findPage(String userId, Integer categoryType, Pageable pageable) {
         //假如是0的话,分页查询全部数据
@@ -196,7 +254,7 @@ public class GameInfoServiceImpl extends CommonServiceImpl<GameInfoVo, GameInfo,
     @Override
     public Map findByGameDetail(String gameId, Boolean addDomain) {
         //1.先查游戏基本数据
-        GameInfo gameInfo = findByGameId(gameId,addDomain);
+        GameInfo gameInfo = findByGameId(gameId, addDomain);
 
         //2.根据游戏id 在游戏图片 查询图片相关id(后续废弃这个操作)
         List<Integer> pictureIds = gamePicturesRepository.findByGameId(gameId).stream().map(
@@ -253,11 +311,10 @@ public class GameInfoServiceImpl extends CommonServiceImpl<GameInfoVo, GameInfo,
                 String urlPicture = aliyunOSSUtil.addDomainName(gamePicture);
                 gameInfo.setGamePicture(urlPicture);
             }
+            //清楚对象缓存,避免update到数据库
+            Session session = em.unwrap(Session.class);
+            session.evict(gameInfo);
         }
-        //清楚对象缓存,避免update到数据库
-        Session session = em.unwrap(Session.class);
-        session.evict(gameInfo);
-
         return gameInfo;
     }
 

+ 3 - 1
src/main/java/com/YuyeTech/TPlat/game/gameInfo/service/GameTagReferenceService.java

@@ -1,8 +1,10 @@
 package com.YuyeTech.TPlat.game.gameInfo.service;
 
+import com.YuyeTech.TPlat.common.service.CommonService;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameTagReference;
 import com.YuyeTech.TPlat.dto.GameTagDTO;
 import com.YuyeTech.TPlat.dto.PageInfoDTO;
+import com.YuyeTech.TPlat.game.gameInfo.vo.GameTagReferenceVo;
 import org.springframework.data.domain.Pageable;
 
 import java.util.List;
@@ -11,7 +13,7 @@ import java.util.List;
  * @author:slambb
  * @date:2020/6/24
  */
-public interface GameTagReferenceService {
+public interface GameTagReferenceService extends CommonService<GameTagReferenceVo, GameTagReference, Integer> {
 
     List<PageInfoDTO>  findByGameId(String gameId, Pageable pageable);
 

+ 4 - 4
src/main/java/com/YuyeTech/TPlat/game/gameInfo/service/GameTagReferenceServiceImpl.java

@@ -1,12 +1,13 @@
 package com.YuyeTech.TPlat.game.gameInfo.service;
 
+import com.YuyeTech.TPlat.common.service.CommonServiceImpl;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameTag;
 import com.YuyeTech.TPlat.game.gameInfo.projo.GameTagReference;
 import com.YuyeTech.TPlat.dto.GameTagDTO;
 import com.YuyeTech.TPlat.dto.PageInfoDTO;
 import com.YuyeTech.TPlat.game.gameInfo.repository.GameTagReferenceRepository;
 import com.YuyeTech.TPlat.game.gameInfo.repository.GameTagRepository;
-import com.YuyeTech.TPlat.game.gameInfo.service.GameTagReferenceService;
+import com.YuyeTech.TPlat.game.gameInfo.vo.GameTagReferenceVo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Pageable;
 import org.springframework.stereotype.Service;
@@ -22,7 +23,8 @@ import java.util.stream.Collectors;
  * @date:2020/6/24
  */
 @Service
-public class GameTagReferenceServiceImpl implements GameTagReferenceService {
+@Transactional
+public class GameTagReferenceServiceImpl extends CommonServiceImpl<GameTagReferenceVo, GameTagReference, Integer> implements GameTagReferenceService {
     @Autowired
     private GameTagReferenceRepository gameTagReferenceRepository;
 
@@ -61,13 +63,11 @@ public class GameTagReferenceServiceImpl implements GameTagReferenceService {
     }
 
     @Override
-    @Transactional
     public void saveGameTagReference(List<GameTagReference> gameTagReferenceList) {
         gameTagReferenceRepository.saveAll(gameTagReferenceList);
     }
 
     @Override
-    @Transactional
     public void deleteGameTagByGameId(String gameId) {
         gameTagReferenceRepository.deleteAllByGameId(gameId);
     }

+ 22 - 0
src/main/java/com/YuyeTech/TPlat/game/gameInfo/vo/GameTagReferenceVo.java

@@ -0,0 +1,22 @@
+package com.YuyeTech.TPlat.game.gameInfo.vo;
+
+import com.YuyeTech.TPlat.common.pojo.PageCondition;
+import lombok.Data;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import java.io.Serializable;
+
+/**
+ * @author:slambb
+ * @date:2022/08/17
+ */
+@Data
+public class GameTagReferenceVo extends PageCondition implements Serializable {
+    private Integer referenceId;
+    private Integer tagId;
+    private String gameId;
+    private Integer status;
+}

+ 4 - 3
src/main/java/com/YuyeTech/TPlat/game/userinfo/service/UserInfoServiceImpl.java

@@ -54,10 +54,11 @@ public class UserInfoServiceImpl extends CommonServiceImpl<UserInfoVo, UserInfo,
             //修改url,添加访问域名
             String url = aliyunOSSUtil.addDomainName(userInfo.getAvatarUrl());
             userInfo.setAvatarUrl(url);
+            //清楚对象缓存,避免update到数据库
+            Session session = em.unwrap(Session.class);
+            session.evict(userInfo);
         }
-        //清楚对象缓存,避免update到数据库
-        Session session = em.unwrap(Session.class);
-        session.evict(userInfo);
+
         return userInfo;
     }
 

+ 234 - 0
src/main/resources/static/appLogging.html

@@ -0,0 +1,234 @@
+<!DOCTYPE>
+<!--解决idea thymeleaf 表达式模板报红波浪线-->
+<!--suppress ALL -->
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8">
+    <title>实时日志</title>
+    <!-- 引入公用部分 -->
+    <script th:replace="common/head::static"></script>
+
+</head>
+<body>
+<!-- 标题 -->
+<h1 style="text-align: center;">app端实时日志</h1>
+
+<!-- 显示区 -->
+<div id="loggingText" contenteditable="true"
+     style="width:100%;height: 700px;background-color: ghostwhite; overflow: auto;"></div>
+
+<!-- 操作栏 -->
+<div style="text-align: center;">
+    <button onclick="$('#loggingText').text('')" style="color: green; height: 35px;">清屏</button>
+    <button onclick="$('#loggingText').animate({scrollTop:$('#loggingText')[0].scrollHeight});"
+            style="color: green; height: 35px;">滚动至底部
+    </button>
+    <button onclick="if(window.loggingAutoBottom){$(this).text('开启自动滚动');}else{$(this).text('关闭自动滚动');};window.loggingAutoBottom = !window.loggingAutoBottom"
+            style="color: green; height: 35px; ">开启自动滚动
+    </button>
+</div>
+
+<div id="echart-oAcc" style="height: 250px;"></div>
+<div id="echart-oGyro" style="height: 250px;"></div>
+</body>
+<!-- jQuery and bootstrtap js -->
+<script src="main-bundles/lib.vendor.bundle.js"></script>
+
+<!-- start plugin js file  -->
+<script src="main-bundles/echarts.bundle.js"></script>
+
+<!-- Start core js and page js -->
+<script src="js/core.js"></script>
+
+<!--<script src="js/chart/echart.js"></script>-->
+
+<script th:inline="javascript">
+    /**
+     * 表格
+     */
+    var testData = [];
+    var domOAcc = document.getElementById("echart-oAcc");
+    var domOGyro = document.getElementById("echart-oGyro");
+    var oAccTable = echarts.init(domOAcc);
+    var oGyroTable = echarts.init(domOGyro);
+    var option = {};
+    // var date = [];
+    // var data = [];
+    // let oAccXArray = [], oAccYArray = [], oAccZArray = [];
+    // let oGyroXArray = [], oGyroYArray = [], oGyroZArray = [];
+
+    $(window).on('resize', function () {
+        oAccTable.resize();
+        oGyroTable.resize();
+    });
+    /**
+     * websocket对象
+     * @type {Array[]}
+     */
+    let port = [[${port}]];//端口
+    let websocket = null;
+    //判断当前浏览器是否支持WebSocket
+    if ('WebSocket' in window) {
+        //动态获取域名或ip
+        let hostname = window.location.hostname;
+        port = window.location.port;
+        let _f = "wss://";
+        if (hostname.indexOf("192.168.0.108") > -1) {//暂时设置一个本地ip
+            _f = "ws://";
+        }
+        // websocket = new WebSocket(_f + hostname + ":" + port + ctx + "/websocket/APPLog/10000");
+        //
+        websocket = new WebSocket("wss://www.9527fun.cn:/api_dev/websocket/APPLog/10000");
+        console.log(_f + hostname + ":" + port + ctx + "/websocket/APPLog/10000");
+    } else {
+        console.error("不支持WebSocket");
+    }
+
+    //连接发生错误的回调方法
+    websocket.onerror = function (e) {
+        console.error("WebSocket连接发生错误");
+    };
+
+    //连接成功建立的回调方法
+    websocket.onopen = function () {
+        console.log("WebSocket连接成功")
+    };
+
+    //接收到消息的回调方法
+    websocket.onmessage = function (event) {
+        //追加
+        if (event.data) {
+            //日志内容
+            let $loggingText = $("#loggingText");
+            $loggingText.append(event.data);
+
+            testData.push.apply(testData,JSON.parse(event.data));
+            // console.log(testData);
+            //重置数据长度
+            let date = [];
+            let data = [];
+            let oAccXArray = [], oAccYArray = [], oAccZArray = [];
+            let oGyroXArray = [], oGyroYArray = [], oGyroZArray = [];
+            for (let i = 0; i < testData.length; i++) {
+                let temp = testData[i];
+                date.push(temp.index);
+                // data.push(temp.gyroValue);
+                oAccXArray.push(temp.acc.oAccX);
+                oAccYArray.push(temp.acc.oAccY);
+                oAccZArray.push(temp.acc.oAccZ);
+                oGyroXArray.push(temp.gyro.oGyroX);
+                oGyroYArray.push(temp.gyro.oGyroY);
+                oGyroZArray.push(temp.gyro.oGyroZ);
+            }
+            option = {
+                tooltip: {
+                    trigger: 'axis',
+                    position: function (pt) {
+                        return [pt[0], '10%'];
+                    }
+                },
+                grid: {
+                    left: '5%',
+                    right: '0%',
+                    top: '2%',
+                    bottom: '20%',
+                },
+                xAxis: {
+                    type: 'category',
+                    boundaryGap: false,
+                    data: date,
+                    axisLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLabel: {
+                        color: anchor.colors["gray-700"],
+                    }
+                },
+                yAxis: {
+                    type: 'value',
+                    boundaryGap: [0, '100%'],
+                    splitLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLabel: {
+                        color: anchor.colors["gray-700"],
+                    }
+                },
+                dataZoom: [{
+                    type: 'inside',
+                    start: 0,
+                    end: 10
+                }, {
+                    start: 0,
+                    end: 10,
+                    handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
+                    handleSize: '80%',
+                    handleStyle: {
+                        color: '#fff',
+                        shadowBlur: 3,
+                        shadowColor: 'rgba(0, 0, 0, 0.6)',
+                        shadowOffsetX: 2,
+                        shadowOffsetY: 2
+                    }
+                }]
+            };
+            if (option && typeof option === "object") {
+                option.series = [ {
+                    name: 'oAccX',
+                    type: 'line',
+                    data: oAccXArray
+                },
+                    {
+                        name: 'oAccY',
+                        type: 'line',
+                        data: oAccYArray
+                    },
+                    {
+                        name: 'oAccZ',
+                        type: 'line',
+                        data: oAccZArray
+                    }];
+                oAccTable.setOption(option, true);
+                option.series = [ {
+                    name: 'oGyroX',
+                    type: 'line',
+                    data: oGyroXArray
+                }
+                    ,
+                    {
+                        name: 'oGyroY',
+                        type: 'line',
+                        data: oGyroYArray
+                    },
+                    {
+                        name: 'oGyroZ',
+                        type: 'line',
+                        data: oGyroZArray
+                    }];
+                oGyroTable.setOption(option,true);
+            }
+            //是否开启自动底部
+            if (window.loggingAutoBottom) {
+                //滚动条自动到最底部
+                $loggingText.scrollTop($loggingText[0].scrollHeight);
+            }
+        }
+    }
+
+    //连接关闭的回调方法
+    websocket.onclose = function () {
+        console.log("WebSocket连接关闭")
+    };
+
+
+</script>
+</html>

+ 234 - 0
src/main/resources/templates/appLogging.html

@@ -0,0 +1,234 @@
+<!DOCTYPE>
+<!--解决idea thymeleaf 表达式模板报红波浪线-->
+<!--suppress ALL -->
+<html xmlns:th="http://www.thymeleaf.org">
+<head>
+    <meta charset="UTF-8">
+    <title>实时日志</title>
+    <!-- 引入公用部分 -->
+    <script th:replace="common/head::static"></script>
+
+</head>
+<body>
+<!-- 标题 -->
+<h1 style="text-align: center;">app端实时日志</h1>
+
+<!-- 显示区 -->
+<div id="loggingText" contenteditable="true"
+     style="width:100%;height: 700px;background-color: ghostwhite; overflow: auto;"></div>
+
+<!-- 操作栏 -->
+<div style="text-align: center;">
+    <button onclick="$('#loggingText').text('')" style="color: green; height: 35px;">清屏</button>
+    <button onclick="$('#loggingText').animate({scrollTop:$('#loggingText')[0].scrollHeight});"
+            style="color: green; height: 35px;">滚动至底部
+    </button>
+    <button onclick="if(window.loggingAutoBottom){$(this).text('开启自动滚动');}else{$(this).text('关闭自动滚动');};window.loggingAutoBottom = !window.loggingAutoBottom"
+            style="color: green; height: 35px; ">开启自动滚动
+    </button>
+</div>
+
+<div id="echart-oAcc" style="height: 250px;"></div>
+<div id="echart-oGyro" style="height: 250px;"></div>
+</body>
+<!-- jQuery and bootstrtap js -->
+<script src="main-bundles/lib.vendor.bundle.js"></script>
+
+<!-- start plugin js file  -->
+<script src="main-bundles/echarts.bundle.js"></script>
+
+<!-- Start core js and page js -->
+<script src="js/core.js"></script>
+
+<!--<script src="js/chart/echart.js"></script>-->
+
+<script th:inline="javascript">
+    /**
+     * 表格
+     */
+    var testData = [];
+    var domOAcc = document.getElementById("echart-oAcc");
+    var domOGyro = document.getElementById("echart-oGyro");
+    var oAccTable = echarts.init(domOAcc);
+    var oGyroTable = echarts.init(domOGyro);
+    var option = {};
+    // var date = [];
+    // var data = [];
+    // let oAccXArray = [], oAccYArray = [], oAccZArray = [];
+    // let oGyroXArray = [], oGyroYArray = [], oGyroZArray = [];
+
+    $(window).on('resize', function () {
+        oAccTable.resize();
+        oGyroTable.resize();
+    });
+    /**
+     * websocket对象
+     * @type {Array[]}
+     */
+    let port = [[${port}]];//端口
+    let websocket = null;
+    //判断当前浏览器是否支持WebSocket
+    if ('WebSocket' in window) {
+        //动态获取域名或ip
+        let hostname = window.location.hostname;
+        port = window.location.port;
+        let _f = "wss://";
+        if (hostname.indexOf("192.168.0.108") > -1) {//暂时设置一个本地ip
+            _f = "ws://";
+        }
+        // websocket = new WebSocket(_f + hostname + ":" + port + ctx + "/websocket/APPLog/10000");
+        //
+        websocket = new WebSocket("wss://www.9527fun.cn:/api_dev/websocket/APPLog/10000");
+        console.log(_f + hostname + ":" + port + ctx + "/websocket/APPLog/10000");
+    } else {
+        console.error("不支持WebSocket");
+    }
+
+    //连接发生错误的回调方法
+    websocket.onerror = function (e) {
+        console.error("WebSocket连接发生错误");
+    };
+
+    //连接成功建立的回调方法
+    websocket.onopen = function () {
+        console.log("WebSocket连接成功")
+    };
+
+    //接收到消息的回调方法
+    websocket.onmessage = function (event) {
+        //追加
+        if (event.data) {
+            //日志内容
+            let $loggingText = $("#loggingText");
+            $loggingText.append(event.data);
+
+            testData.push.apply(testData,JSON.parse(event.data));
+            // console.log(testData);
+            //重置数据长度
+            let date = [];
+            let data = [];
+            let oAccXArray = [], oAccYArray = [], oAccZArray = [];
+            let oGyroXArray = [], oGyroYArray = [], oGyroZArray = [];
+            for (let i = 0; i < testData.length; i++) {
+                let temp = testData[i];
+                date.push(temp.index);
+                // data.push(temp.gyroValue);
+                oAccXArray.push(temp.acc.oAccX);
+                oAccYArray.push(temp.acc.oAccY);
+                oAccZArray.push(temp.acc.oAccZ);
+                oGyroXArray.push(temp.gyro.oGyroX);
+                oGyroYArray.push(temp.gyro.oGyroY);
+                oGyroZArray.push(temp.gyro.oGyroZ);
+            }
+            option = {
+                tooltip: {
+                    trigger: 'axis',
+                    position: function (pt) {
+                        return [pt[0], '10%'];
+                    }
+                },
+                grid: {
+                    left: '5%',
+                    right: '0%',
+                    top: '2%',
+                    bottom: '20%',
+                },
+                xAxis: {
+                    type: 'category',
+                    boundaryGap: false,
+                    data: date,
+                    axisLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLabel: {
+                        color: anchor.colors["gray-700"],
+                    }
+                },
+                yAxis: {
+                    type: 'value',
+                    boundaryGap: [0, '100%'],
+                    splitLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLine: {
+                        lineStyle: {
+                            color: anchor.colors["gray-100"],
+                        }
+                    },
+                    axisLabel: {
+                        color: anchor.colors["gray-700"],
+                    }
+                },
+                dataZoom: [{
+                    type: 'inside',
+                    start: 0,
+                    end: 10
+                }, {
+                    start: 0,
+                    end: 10,
+                    handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
+                    handleSize: '80%',
+                    handleStyle: {
+                        color: '#fff',
+                        shadowBlur: 3,
+                        shadowColor: 'rgba(0, 0, 0, 0.6)',
+                        shadowOffsetX: 2,
+                        shadowOffsetY: 2
+                    }
+                }]
+            };
+            if (option && typeof option === "object") {
+                option.series = [ {
+                    name: 'oAccX',
+                    type: 'line',
+                    data: oAccXArray
+                },
+                    {
+                        name: 'oAccY',
+                        type: 'line',
+                        data: oAccYArray
+                    },
+                    {
+                        name: 'oAccZ',
+                        type: 'line',
+                        data: oAccZArray
+                    }];
+                oAccTable.setOption(option, true);
+                option.series = [ {
+                    name: 'oGyroX',
+                    type: 'line',
+                    data: oGyroXArray
+                }
+                    ,
+                    {
+                        name: 'oGyroY',
+                        type: 'line',
+                        data: oGyroYArray
+                    },
+                    {
+                        name: 'oGyroZ',
+                        type: 'line',
+                        data: oGyroZArray
+                    }];
+                oGyroTable.setOption(option,true);
+            }
+            //是否开启自动底部
+            if (window.loggingAutoBottom) {
+                //滚动条自动到最底部
+                $loggingText.scrollTop($loggingText[0].scrollHeight);
+            }
+        }
+    }
+
+    //连接关闭的回调方法
+    websocket.onclose = function () {
+        console.log("WebSocket连接关闭")
+    };
+
+
+</script>
+</html>

+ 6 - 2
src/main/resources/templates/logging.html

@@ -39,8 +39,12 @@
         //动态获取域名或ip
         let hostname = window.location.hostname;
         port = window.location.port;
-        websocket = new WebSocket("wss://"+hostname+":" + port + ctx + "/websocket/logging");
-        console.log("wss://"+hostname+":" + port + ctx + "/websocket/logging");
+        let _f = "wss://";
+        if (hostname.indexOf("192.168.0.108") > -1) {//暂时设置一个本地ip
+            _f = "ws://";
+        }
+        websocket = new WebSocket(_f + hostname + ":" + port + ctx + "/websocket/logging");
+        console.log(_f + hostname + ":" + port + ctx + "/websocket/logging");
     } else {
         console.error("不支持WebSocket");
     }