ソースを参照

添加日志存储与查询功能
登录接口返回用户详细信息

648540858 4 年 前
コミット
61f5950b4f

+ 13 - 1
sql/mysql.sql

@@ -74,7 +74,19 @@ create table device_alarm
     alarmType         varchar(50)
 );
 
-
+create table log
+(
+    id                int auto_increment
+        primary key,
+    name        varchar(50)     not null,
+    type        varchar(50)     not null,
+    uri         varchar(200)    not null,
+    address     varchar(50)     not null,
+    result      varchar(50)     not null,
+    timing      bigint          not null,
+    username    varchar(50)     not null,
+    createTime  varchar(50)     not null
+);
 
 create table device_mobile_position
 (

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@@ -4,6 +4,7 @@ import java.util.logging.LogManager;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
 import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.scheduling.annotation.EnableScheduling;
 import springfox.documentation.oas.annotations.EnableOpenApi;
@@ -11,6 +12,7 @@ import springfox.documentation.oas.annotations.EnableOpenApi;
 /**
  *
  */
+@ServletComponentScan("com.genersoft.iot.vmp.conf")
 @SpringBootApplication
 @EnableScheduling
 @EnableOpenApi

+ 172 - 0
src/main/java/com/genersoft/iot/vmp/common/ApiSaveConstant.java

@@ -0,0 +1,172 @@
+package com.genersoft.iot.vmp.common;
+
+public class ApiSaveConstant {
+
+    public static String getVal(String key) {
+        String[] keyItemArray = key.split("/");
+        if (keyItemArray.length <= 1 || !"api".equals(keyItemArray[1])) {
+            return null;
+        }
+        if (keyItemArray.length >= 4) {
+            switch (keyItemArray[2]) {
+                case "alarm":
+                    if ("delete".equals(keyItemArray[3])) {
+                        return "删除报警";
+                    }
+                    break;
+                case "device":
+                    switch (keyItemArray[3]) {
+                        case "config":
+                            if (keyItemArray.length >= 5 && "basicParam".equals(keyItemArray[4])) {
+                                return "[设备配置] 基本配置设置命令";
+                            }
+                            break;
+                        case "control":
+                            switch (keyItemArray[4]) {
+                                case "teleboot":
+                                    return "[设备控制] 远程启动";
+                                case "record":
+                                    return "[设备控制] 录像控制";
+                                case "guard":
+                                    return "[设备控制] 布防/撤防命令";
+                                case "reset_alarm":
+                                    return "[设备控制] 报警复位";
+                                case "i_frame":
+                                    return "[设备控制] 强制关键帧";
+                                case "home_position":
+                                    return "[设备控制] 看守位控制";
+                            }
+                            break;
+                            case "query":
+                                if (keyItemArray.length <= 5) return null;
+                                switch (keyItemArray[4]) {
+                                    case "devices":
+                                        if (keyItemArray.length < 7) return null;
+                                        switch (keyItemArray[6]) {
+                                            case "sync":
+                                                return "[设备查询] 同步设备通道";
+                                            case "delete":
+                                                return "[设备查询] 移除设备";
+                                        }
+                                        break;
+                                    case "channel":
+                                        return "[设备查询] 更新通道信息";
+                                    case "transport":
+                                        return "[设备查询] 修改数据流传输模式";
+                                }
+                                break;
+                            }
+                case "gbStream":
+                    switch (keyItemArray[3]) {
+                        case "del":
+                            return "移除通道与国标的关联";
+                        case "add":
+                            return "添加通道与国标的关联";
+                    }
+                    break;
+                case "media":
+                    break;
+                case "position":
+                    if ("subscribe".equals(keyItemArray[3])) {
+                        return "订阅位置信息";
+                    }
+                    break;
+                case "platform":
+                    switch (keyItemArray[3]) {
+                        case "save":
+                            return "添加上级平台";
+                        case "delete":
+                            return "移除上级平台";
+                        case "update_channel_for_gb":
+                            return "向上级平台添加国标通道";
+                        case "del_channel_for_gb":
+                            return "从上级平台移除国标通道";
+                    }
+                    break;
+                case "platform_gb_stream":
+                    break;
+                case "play":
+                    switch (keyItemArray[3]) {
+                        case "start":
+                            return "开始点播";
+                        case "stop":
+                            return "停止点播";
+                        case "convert":
+                            return "转码";
+                        case "convertStop":
+                            return "结束转码";
+                        case "broadcast":
+                            return "语音广播";
+                    }
+                    break;
+                case "download":
+                    switch (keyItemArray[3]) {
+                        case "start":
+                            return "开始历史媒体下载";
+                        case "stop":
+                            return "停止历史媒体下载";
+                    }
+                    break;
+                case "playback":
+                    switch (keyItemArray[3]) {
+                        case "start":
+                            return "开始视频回放";
+                        case "stop":
+                            return "停止视频回放";
+                    }
+                    break;
+                case "ptz":
+                    switch (keyItemArray[3]) {
+                        case "control":
+                            return "云台控制";
+                        case "front_end_command":
+                            return "通用前端控制命令";
+                    }
+                    break;
+                case "gb_record":
+                    break;
+                case "onvif":
+                    break;
+                case "server":
+                    if ("restart".equals(keyItemArray[3])) {
+                        return "重启流媒体服务";
+                    }
+                    break;
+                case "proxy":
+                    switch (keyItemArray[3]) {
+                        case "save":
+                            return "保存代理";
+                        case "del":
+                            return "移除代理";
+                        case "start":
+                            return "启用代理";
+                        case "stop":
+                            return "停用代理";
+                    }
+                    break;
+                case "push":
+                    switch (keyItemArray[3]) {
+                        case "save_to_gb":
+                            return "将推流添加到国标";
+                        case "remove_form_gb":
+                            return "将推流移出到国标";
+                    }
+                    break;
+                case "user":
+                    switch (keyItemArray[3]) {
+                        case "login":
+                            return "登录";
+                        case "changePassword":
+                            return "修改密码";
+                        case "add":
+                            return "添加用户";
+                        case "delete":
+                            return "删除用户";
+                    }
+                    break;
+            }
+        }
+        return null;
+    }
+}
+

+ 114 - 0
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java

@@ -0,0 +1,114 @@
+package com.genersoft.iot.vmp.conf;
+
+import com.genersoft.iot.vmp.common.ApiSaveConstant;
+import com.genersoft.iot.vmp.conf.security.SecurityUtils;
+import com.genersoft.iot.vmp.service.ILogService;
+import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+
+@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/api/*", asyncSupported=true)
+public class ApiAccessFilter extends OncePerRequestFilter {
+
+    private final static Logger logger = LoggerFactory.getLogger(ApiAccessFilter.class);
+
+    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    @Autowired
+    private UserSetup userSetup;
+
+    @Autowired
+    private ILogService logService;
+
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
+        String username = null;
+        if (SecurityUtils.getUserInfo() == null) {
+            username = servletRequest.getParameter("username");
+        }else {
+            username = SecurityUtils.getUserInfo().getUsername();
+        }
+        long start = System.currentTimeMillis(); // 请求进入时间
+        String uriName = ApiSaveConstant.getVal(servletRequest.getRequestURI());
+
+        filterChain.doFilter(servletRequest, servletResponse);
+
+        if (uriName != null && userSetup.getLogInDatebase()) {
+
+            LogDto logDto = new LogDto();
+            logDto.setName(uriName);
+            logDto.setUsername(username);
+            logDto.setAddress(servletRequest.getRemoteAddr());
+            logDto.setResult(HttpStatus.valueOf(servletResponse.getStatus()).toString());
+            logDto.setTiming(System.currentTimeMillis() - start);
+            logDto.setType(servletRequest.getMethod());
+            logDto.setUri(servletRequest.getRequestURI());
+            logDto.setCreateTime(format.format(System.currentTimeMillis()));
+            logService.add(logDto);
+//            logger.warn("[Api Access]  [{}] [{}] [{}] [{}] [{}] {}ms",
+//                    uriName, servletRequest.getMethod(), servletRequest.getRequestURI(), servletRequest.getRemoteAddr(), HttpStatus.valueOf(servletResponse.getStatus()),
+//                    System.currentTimeMillis() - start);
+
+        }
+    }
+
+    /**
+     * 获取IP地址
+     *
+     * @param request 请求
+     * @return request发起客户端的IP地址
+     */
+    private String getIP(HttpServletRequest request) {
+        if (request == null) {
+            return "0.0.0.0";
+        }
+
+        String Xip = request.getHeader("X-Real-IP");
+        String XFor = request.getHeader("X-Forwarded-For");
+
+        String UNKNOWN_IP = "unknown";
+        if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            //多次反向代理后会有多个ip值,第一个ip才是真实ip
+            int index = XFor.indexOf(",");
+            if (index != -1) {
+                return XFor.substring(0, index);
+            } else {
+                return XFor;
+            }
+        }
+
+        XFor = Xip;
+        if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            return XFor;
+        }
+
+        if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            XFor = request.getHeader("Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            XFor = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            XFor = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
+            XFor = request.getRemoteAddr();
+        }
+        return XFor;
+    }
+}

+ 10 - 0
src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java

@@ -25,6 +25,8 @@ public class UserSetup {
 
     private Boolean recordPushLive = Boolean.FALSE;
 
+    private Boolean logInDatebase = Boolean.TRUE;
+
     private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
 
     public Boolean getSavePositionHistory() {
@@ -94,4 +96,12 @@ public class UserSetup {
     public void setInterfaceAuthenticationExcludes(List<String> interfaceAuthenticationExcludes) {
         this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes;
     }
+
+    public Boolean getLogInDatebase() {
+        return logInDatebase;
+    }
+
+    public void setLogInDatebase(Boolean logInDatebase) {
+        this.logInDatebase = logInDatebase;
+    }
 }

+ 1 - 1
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java

@@ -48,7 +48,7 @@ public class SecurityUtils {
         Authentication authentication = getAuthentication();
         if(authentication!=null){
             Object principal = authentication.getPrincipal();
-            if(principal!=null){
+            if(principal!=null && !"anonymousUser".equals(principal)){
                 LoginUser user = (LoginUser) authentication.getPrincipal();
                 return user;
             }

+ 34 - 0
src/main/java/com/genersoft/iot/vmp/service/ILogService.java

@@ -0,0 +1,34 @@
+package com.genersoft.iot.vmp.service;
+
+import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
+import com.github.pagehelper.PageInfo;
+
+/**
+ * 系统日志
+ */
+public interface ILogService {
+
+    /**
+     * 查询日志
+     * @param page 当前页
+     * @param count 每页数量
+     * @param query 搜索内容
+     * @param type 类型
+     * @param startTime 开始时间
+     * @param endTime 结束时间
+     * @return 日志列表
+     */
+    PageInfo<LogDto> getAll(int page, int count, String query, String type, String startTime, String endTime);
+
+    /**
+     * 添加日志
+     * @param logDto 日志
+     */
+    void add(LogDto logDto);
+
+    /**
+     * 清空
+     */
+    int clear();
+
+}

+ 36 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java

@@ -0,0 +1,36 @@
+package com.genersoft.iot.vmp.service.impl;
+
+import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+import com.genersoft.iot.vmp.service.ILogService;
+import com.genersoft.iot.vmp.storager.dao.LogMapper;
+import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class LogServiceImpl implements ILogService {
+
+    @Autowired
+    private LogMapper logMapper;
+
+    @Override
+    public PageInfo<LogDto> getAll(int page, int count, String query, String type, String startTime, String endTime) {
+        PageHelper.startPage(page, count);
+        List<LogDto> all = logMapper.query(query, type, startTime, endTime);
+        return new PageInfo<>(all);
+    }
+
+    @Override
+    public void add(LogDto logDto) {
+        logMapper.add(logDto);
+    }
+
+    @Override
+    public int clear() {
+        return logMapper.clear();
+    }
+}

+ 4 - 2
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java

@@ -342,12 +342,14 @@ public class MediaServerServiceImpl implements IMediaServerService, CommandLineR
 
         if (redisUtil.zSize(key)  == null || redisUtil.zSize(key) == 0) {
             logger.info("获取负载最低的节点时无在线节点");
+            return null;
         }
 
         // 获取分数最低的,及并发最低的
         Set<Object> objects = redisUtil.ZRange(key, 0, -1);
-        ArrayList<Object> MediaServerObjectS = new ArrayList<>(objects);
-        String mediaServerId = (String)MediaServerObjectS.get(0);
+        ArrayList<Object> mediaServerObjectS = new ArrayList<>(objects);
+
+        String mediaServerId = (String)mediaServerObjectS.get(0);
         return getOne(mediaServerId);
     }
 

+ 39 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java

@@ -0,0 +1,39 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
+import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 用于存储设服务的日志
+ */
+@Mapper
+@Repository
+public interface LogMapper {
+
+    @Insert("insert into log ( name, type, uri, address, result, timing, username, createTime) " +
+            "values ('${name}', '${type}', '${uri}', '${address}', '${result}', ${timing}, '${username}', '${createTime}')")
+    int add(LogDto logDto);
+
+
+    @Select(value = {"<script>" +
+            " SELECT * FROM log " +
+            " WHERE 1=1 " +
+            " <if test=\"query != null\"> AND (name LIKE '%${query}%')</if> " +
+            " <if test=\"type != null\" >  AND type = '${type}'</if>" +
+            " <if test=\"startTime != null\" >  AND createTime &gt;= '${startTime}' </if>" +
+            " <if test=\"endTime != null\" >  AND createTime &lt;= '${endTime}' </if>" +
+            " ORDER BY createTime DESC " +
+            " </script>"})
+    List<LogDto> query(String query, String type, String startTime, String endTime);
+
+
+    @Delete("DELETE FROM log")
+    int clear();
+}

+ 86 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/LogDto.java

@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.storager.dao.dto;
+
+public class LogDto {
+
+    private int id;
+    private String name;
+    private String type;
+    private String uri;
+    private String address;
+    private String result;
+    private long timing;
+    private String username;
+    private String createTime;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        this.result = result;
+    }
+
+    public long getTiming() {
+        return timing;
+    }
+
+    public void setTiming(long timing) {
+        this.timing = timing;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+}

+ 93 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java

@@ -0,0 +1,93 @@
+package com.genersoft.iot.vmp.vmanager.log;
+
+import com.genersoft.iot.vmp.service.ILogService;
+import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
+import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+
+@Api(tags = "日志管理")
+@CrossOrigin
+@RestController
+@RequestMapping("/api/log")
+public class LogController {
+
+    @Autowired
+    private ILogService logService;
+
+    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     *  分页查询日志
+     *
+     * @param query 查询内容
+     * @param page 当前页
+     * @param count 每页查询数量
+     * @param type  类型
+     * @param startTime  开始时间
+     * @param endTime 结束时间
+     * @return
+     */
+    @ApiOperation("分页查询报警")
+    @GetMapping("/all")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name="query", value = "查询内容", dataTypeClass = String.class),
+            @ApiImplicitParam(name="page", value = "当前页", required = true ,dataTypeClass = Integer.class),
+            @ApiImplicitParam(name="count", value = "每页查询数量", required = true ,dataTypeClass = Integer.class),
+            @ApiImplicitParam(name="type", value = "类型" ,dataTypeClass = String.class),
+            @ApiImplicitParam(name="startTime", value = "查询内容" ,dataTypeClass = String.class),
+            @ApiImplicitParam(name="endTime", value = "查询内容" ,dataTypeClass = String.class),
+    })
+    public ResponseEntity<PageInfo<LogDto>> getAll(
+            @RequestParam int page,
+            @RequestParam int count,
+            @RequestParam(required = false)  String query,
+            @RequestParam(required = false) String type,
+            @RequestParam(required = false) String startTime,
+            @RequestParam(required = false) String endTime
+    ) {
+        if (StringUtils.isEmpty(query)) query = null;
+        if (StringUtils.isEmpty(startTime)) startTime = null;
+        if (StringUtils.isEmpty(endTime)) endTime = null;
+
+
+        try {
+            if (startTime != null)  format.parse(startTime);
+            if (endTime != null)  format.parse(endTime);
+        } catch (ParseException e) {
+            return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
+        }
+
+        PageInfo<LogDto> allLog = logService.getAll(page, count, query, type, startTime, endTime);
+        return new ResponseEntity<>(allLog, HttpStatus.OK);
+    }
+
+    /**
+     *  清空日志
+     *
+     */
+    @ApiOperation("清空日志")
+    @DeleteMapping("/clear")
+    @ApiImplicitParams({})
+    public ResponseEntity<WVPResult<String>> clear() {
+
+        int count = logService.clear();
+        WVPResult wvpResult = new WVPResult();
+        wvpResult.setCode(0);
+        wvpResult.setMsg("success");
+        wvpResult.setData(count);
+        return new ResponseEntity<WVPResult<String>>(wvpResult, HttpStatus.OK);
+    }
+
+}

+ 11 - 7
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java

@@ -17,9 +17,7 @@ import org.springframework.util.DigestUtils;
 import org.springframework.web.bind.annotation.*;
 
 import javax.security.sasl.AuthenticationException;
-import javax.xml.crypto.Data;
 import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.List;
 
 @Api(tags = "用户管理")
@@ -42,19 +40,25 @@ public class UserController {
             @ApiImplicitParam(name = "password", required = true, value = "密码(32位md5加密)", dataTypeClass = String.class),
     })
     @GetMapping("/login")
-    public String login(@RequestParam String username, @RequestParam String password){
-        LoginUser user;
+    public WVPResult<LoginUser> login(@RequestParam String username, @RequestParam String password){
+        LoginUser user = null;
+        WVPResult<LoginUser> result = new WVPResult<>();
         try {
             user = SecurityUtils.login(username, password, authenticationManager);
         } catch (AuthenticationException e) {
             e.printStackTrace();
-            return "fail";
+            result.setCode(-1);
+            result.setMsg("fail");
         }
         if (user != null) {
-            return "success";
+            result.setCode(0);
+            result.setMsg("success");
+            result.setData(user);
         }else {
-            return "fail";
+            result.setCode(-1);
+            result.setMsg("fail");
         }
+        return result;
     }
 
     @ApiOperation("修改密码")

+ 2 - 0
src/main/resources/all-application.yml

@@ -150,6 +150,8 @@ user-settings:
         - /api/v1/**
     # 推流直播是否录制
     record-push-live: true
+    # 是否将日志存储进数据库
+    logInDatebase: true
 
 # 在线文档: swagger-ui(生产环境建议关闭)
 swagger-ui:

BIN
src/main/resources/wvp.sqlite