jiangping
2023-10-12 697775ce76037e4ec4a2f7de59395fc873070c71
修改
已添加7个文件
已修改15个文件
817 ■■■■■ 文件已修改
server/db/business.mqtt_log.permissions.sql 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/platform/src/main/java/com/doumee/api/MqttLogController.java 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/platform/src/main/java/com/doumee/api/business/LocksController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/constants/Constants.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/core/mqtt/service/MqttToolService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/MqttLogMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Locks.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/MqttLog.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/dao/business/model/Sites.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/BikesService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/DeviceService.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/LocksService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/MemberRidesService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/MqttLogService.java 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/DeviceSubscribeServiceImpl.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/LocksServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/MemberRidesServiceImpl.java 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/MqttLogServiceImpl.java 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/services/src/main/java/com/doumee/service/business/impl/SitesServiceImpl.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/自行车mqtt协议.md 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/db/business.mqtt_log.permissions.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:mqttlog:create', '新建系统行为操作记录表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:mqttlog:delete', '删除系统行为操作记录表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:mqttlog:update', '修改系统行为操作记录表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:mqttlog:query', '查询系统行为操作记录表', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
INSERT INTO `SYSTEM_PERMISSION`(`CODE`, `NAME`, `REMARK`, `FIXED`, `CREATE_USER`, `CREATE_TIME`, `UPDATE_USER`, `UPDATE_TIME`, `DELETED`) VALUES ('business:mqttlog:exportExcel', '导出系统行为操作记录表(Excel)', '', 0, 1, CURRENT_TIMESTAMP, NULL, NULL, 0);
server/platform/src/main/java/com/doumee/api/MqttLogController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
package com.doumee.api;
import com.doumee.api.BaseController;
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.PageWrap;
import com.doumee.core.model.PageData;
import com.doumee.dao.business.model.MqttLog;
import com.doumee.service.business.MqttLogService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/10/12 14:25
 */
@Api(tags = "系统行为操作记录表")
@RestController
@RequestMapping("/business/mqttLog")
public class MqttLogController extends BaseController {
    @Autowired
    private MqttLogService mqttLogService;
    @PreventRepeat
    @ApiOperation("新建")
    @PostMapping("/create")
    @RequiresPermissions("business:mqttlog:create")
    public ApiResponse create(@RequestBody MqttLog mqttLog) {
        return ApiResponse.success(mqttLogService.create(mqttLog));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @RequiresPermissions("business:mqttlog:delete")
    public ApiResponse deleteById(@PathVariable String id) {
        mqttLogService.deleteById(id);
        return ApiResponse.success(null);
    }
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @RequiresPermissions("business:mqttlog:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
        String [] idArray = ids.split(",");
        List<String> idList = new ArrayList<>();
        for (String id : idArray) {
            idList.add(id);
        }
        mqttLogService.deleteByIdInBatch(idList);
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @RequiresPermissions("business:mqttlog:update")
    public ApiResponse updateById(@RequestBody MqttLog mqttLog) {
        mqttLogService.updateById(mqttLog);
        return ApiResponse.success(null);
    }
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @RequiresPermissions("business:mqttlog:query")
    public ApiResponse<PageData<MqttLog>> findPage (@RequestBody PageWrap<MqttLog> pageWrap) {
        return ApiResponse.success(mqttLogService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @RequiresPermissions("business:mqttlog:exportExcel")
    public void exportExcel (@RequestBody PageWrap<MqttLog> pageWrap, HttpServletResponse response) {
        ExcelExporter.build(MqttLog.class).export(mqttLogService.findPage(pageWrap).getRecords(), "系统行为操作记录表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @RequiresPermissions("business:mqttlog:query")
    public ApiResponse findById(@PathVariable String id) {
        return ApiResponse.success(mqttLogService.findById(id));
    }
}
server/platform/src/main/java/com/doumee/api/business/LocksController.java
@@ -70,7 +70,7 @@
        return ApiResponse.success(null);
    }
    @ApiOperation("实时车位信息_分页查询")
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @RequiresPermissions("business:locks:query")
    public ApiResponse<PageData<Locks>> findPage(@RequestBody PageWrap<Locks> pageWrap) {
server/services/src/main/java/com/doumee/core/constants/Constants.java
@@ -32,10 +32,15 @@
    public static final String PROJECT_FILE = "PROJECT_FILE";
    public static String REDIS_DEBUG_STR="test_";
    public  interface MqttTopic{
        //开锁
        String openLock = "OPENLOCK";
        //关闭锁头
        String closeLock = "CLOSELOCK";
        //开锁(发布)
        String topic_index = "device/lock/";
        String openLock = "device/lock/+/unlock";
        //锁信息,在初始化、状态变更时会推送锁的完整状态(订阅)
        String lockInfo = "device/lock/+/info";
        //还车锁头(订阅)
        String closeLock = "device/lock/+/bike";
        //实时获取锁信息(发布)
        String getLockInfo = "device/lock/+/getInfo";
    }
    /**
@@ -47,6 +52,13 @@
        int all =2;
        int partful = 3;
  }
    public interface LockStatus{
      //  //状态,0闭合, 1打开,2运行中, 3异常
        int closed =0;
        int open =1;
        int running =2;
        int error= 3;
    }
    public interface goodsorderStatus{
        int waitPay =0;
        int pay =1;
server/services/src/main/java/com/doumee/core/mqtt/service/MqttToolService.java
@@ -36,16 +36,18 @@
     * @param message
     * @param topic
     */
    public  void pubMessage(String message,String topic){
    public  int pubMessage(String message,String topic){
        MqttMessage mess = new MqttMessage();
        mess.setQos(1);
        mess.setRetained(true);
        mess.setPayload(message.getBytes());
        try {
            MqttClientInit.getInstance(config,callBack).publish(topic, mess);
            return  1;
        } catch (Exception e) {
            //LOGGER.error(e.getLocalizedMessage());
        }
        return 0;
    }
    public static void main(String[] args) {
        MqttToolService client1 = new MqttToolService();
server/services/src/main/java/com/doumee/dao/business/MqttLogMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.doumee.dao.business;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.doumee.dao.business.model.MqttLog;
/**
 * @author æ±Ÿè¹„蹄
 * @date 2023/10/12 14:25
 */
public interface MqttLogMapper extends BaseMapper<MqttLog> {
}
server/services/src/main/java/com/doumee/dao/business/model/Locks.java
@@ -1,5 +1,6 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -58,8 +59,8 @@
    @ExcelColumn(name="编号")
    private String code;
    @ApiModelProperty(value = "状态 0正常 1异常", example = "1")
    @ExcelColumn(name="状态 0正常 1异常")
    @ApiModelProperty(value = "状态,0闭合, 1打开,2运行中, 3异常", example = "1")
    @ExcelColumn(name="状态,0闭合, 1打开,2运行中, 3异常")
    private Integer status;
    @ApiModelProperty(value = "站点编码(关联sites)")
@@ -69,5 +70,8 @@
    @ApiModelProperty(value = "当前锁定自行车编号")
    @ExcelColumn(name="当前锁定自行车编号")
    private String bikeCode;
    @ApiModelProperty(value = "当前锁定自行车编号")
    @TableField(select = false)
    private Sites sites;
}
server/services/src/main/java/com/doumee/dao/business/model/MqttLog.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
package com.doumee.dao.business.model;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.doumee.core.annotation.excel.ExcelColumn;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.Date;
/**
 * ç³»ç»Ÿè¡Œä¸ºæ“ä½œè®°å½•表
 * @author æ±Ÿè¹„蹄
 * @date 2023/10/12 14:25
 */
@Data
@ApiModel("系统行为操作记录表")
@TableName("`mqtt_log`")
public class MqttLog {
    @ApiModelProperty(value = "编码")
    @ExcelColumn(name="编码")
    private String id;
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "创建人")
    @ExcelColumn(name="创建人")
    private String creator;
    @ApiModelProperty(value = "编辑时间")
    @ExcelColumn(name="编辑时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
    @ApiModelProperty(value = "编辑人")
    @ExcelColumn(name="编辑人")
    private String editor;
    @ApiModelProperty(value = "是否已删除 0未删除 1已删除", example = "1")
    @ExcelColumn(name="是否已删除 0未删除 1已删除")
    @TableLogic
    private Integer isdeleted;
    @ApiModelProperty(value = "备注")
    @ExcelColumn(name="备注")
    private String info;
    @ApiModelProperty(value = "类型 0订阅 1发布", example = "1")
    @ExcelColumn(name="类型 0订阅 1发布")
    private Integer type;
    @ApiModelProperty(value = "客户端编码")
    @ExcelColumn(name="客户端编码")
    private String clientid;
    @ApiModelProperty(value = "服务器信息")
    @ExcelColumn(name="服务器信息")
    private String hostInfo;
    @ApiModelProperty(value = "主题")
    @ExcelColumn(name="主题")
    private String topic;
    @ApiModelProperty(value = "消息内容")
    @ExcelColumn(name="消息内容")
    private String msg;
    @ApiModelProperty(value = "结果 0成功 1失败", example = "1")
    @ExcelColumn(name="结果 0成功 1失败")
    private Integer result;
}
server/services/src/main/java/com/doumee/dao/business/model/Sites.java
@@ -78,6 +78,9 @@
    @ApiModelProperty(value = "在架车辆数")
    @TableField(exist = false)
    private Integer bikeCount;
    @ApiModelProperty(value = "在架车辆数")
    @TableField(exist = false)
    private Integer allLockNum;
    @ApiModelProperty(value = "满架率")
    @TableField(exist = false)
server/services/src/main/java/com/doumee/service/business/BikesService.java
@@ -96,4 +96,5 @@
    long count(Bikes bikes);
    PageData<Bikes> findJoinPage(PageWrap<Bikes> pageWrap);
}
server/services/src/main/java/com/doumee/service/business/DeviceService.java
@@ -1,6 +1,7 @@
package com.doumee.service.business;
import com.doumee.dao.business.model.Locks;
import com.doumee.dao.business.model.MqttLog;
/**
 * ä¸Žç¡¬ä»¶å¯¹æŽ¥æœåŠ¡
@@ -14,8 +15,10 @@
     * ä¸‹å‘开车开锁指令
     * @return String
     */
    boolean openLock(Locks locks);
    MqttLog openLock(Locks locks);
    void startSubcribe();
    MqttLog getLockInfo(Locks locks);
}
server/services/src/main/java/com/doumee/service/business/LocksService.java
@@ -94,4 +94,5 @@
     * @return long
     */
    long count(Locks locks);
}
server/services/src/main/java/com/doumee/service/business/MemberRidesService.java
@@ -2,6 +2,7 @@
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.Locks;
import com.doumee.dao.business.model.MemberRides;
import com.doumee.dao.business.web.request.MemberRidesQuery;
import com.doumee.dao.business.web.response.BikeLogDTO;
@@ -133,4 +134,8 @@
    void updateDuration(MemberRides memberRides);
    void forceBack(MemberRides memberRides);
    int mqttCloseBikeEvent(MemberRides bikes);
    int mqttLockInfoEvent(Locks locks);
}
server/services/src/main/java/com/doumee/service/business/MqttLogService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,97 @@
package com.doumee.service.business;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.business.model.MqttLog;
import java.util.List;
/**
 * ç³»ç»Ÿè¡Œä¸ºæ“ä½œè®°å½•表Service定义
 * @author æ±Ÿè¹„蹄
 * @date 2023/10/12 14:25
 */
public interface MqttLogService {
    /**
     * åˆ›å»º
     *
     * @param mqttLog å®žä½“对象
     * @return String
     */
    String create(MqttLog mqttLog);
    /**
     * ä¸»é”®åˆ é™¤
     *
     * @param id ä¸»é”®
     */
    void deleteById(String id);
    /**
     * åˆ é™¤
     *
     * @param mqttLog å®žä½“对象
     */
    void delete(MqttLog mqttLog);
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<String> ids);
    /**
     * ä¸»é”®æ›´æ–°
     *
     * @param mqttLog å®žä½“对象
     */
    void updateById(MqttLog mqttLog);
    /**
     * æ‰¹é‡ä¸»é”®æ›´æ–°
     *
     * @param mqttLogs å®žä½“集
     */
    void updateByIdInBatch(List<MqttLog> mqttLogs);
    /**
     * ä¸»é”®æŸ¥è¯¢
     *
     * @param id ä¸»é”®
     * @return MqttLog
     */
    MqttLog findById(String id);
    /**
     * æ¡ä»¶æŸ¥è¯¢å•条记录
     *
     * @param mqttLog å®žä½“对象
     * @return MqttLog
     */
    MqttLog findOne(MqttLog mqttLog);
    /**
     * æ¡ä»¶æŸ¥è¯¢
     *
     * @param mqttLog å®žä½“对象
     * @return List<MqttLog>
     */
    List<MqttLog> findList(MqttLog mqttLog);
    /**
     * åˆ†é¡µæŸ¥è¯¢
     *
     * @param pageWrap åˆ†é¡µå¯¹è±¡
     * @return PageData<MqttLog>
     */
    PageData<MqttLog> findPage(PageWrap<MqttLog> pageWrap);
    /**
     * æ¡ä»¶ç»Ÿè®¡
     *
     * @param mqttLog å®žä½“对象
     * @return long
     */
    long count(MqttLog mqttLog);
}
server/services/src/main/java/com/doumee/service/business/impl/DeviceServiceImpl.java
@@ -1,12 +1,17 @@
package com.doumee.service.business.impl;
import com.alibaba.fastjson.JSONObject;
import com.doumee.core.constants.Constants;
import com.doumee.core.mqtt.config.MqttConfig;
import com.doumee.core.mqtt.service.MqttToolService;
import com.doumee.dao.business.MqttLogMapper;
import com.doumee.dao.business.model.Locks;
import com.doumee.dao.business.model.MqttLog;
import com.doumee.service.business.DeviceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Date;
/**
 *  ä¸Žç¡¬ä»¶å¯¹æŽ¥æœåŠ¡
@@ -17,14 +22,54 @@
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private MqttToolService mqttToolService;
    @Autowired
    private MqttLogMapper mqttLogMapper;
    @Autowired
    private MqttConfig mqttConfig;
    @Override
    @PostConstruct
    public void startSubcribe() {
        mqttToolService.subscribe(new String[]{ Constants.MqttTopic.openLock, Constants.MqttTopic.closeLock});
    }
    /**
     * å‘起开锁指令
     * @param locks
     * @return
     */
    @Override
    public boolean openLock(Locks locks) {
        mqttToolService.pubMessage(locks.getName(), Constants.MqttTopic.openLock);
        return true;
    public MqttLog openLock(Locks locks) {
        String topic =  Constants.MqttTopic.openLock.replace("+", locks.getId());
        int result = mqttToolService.pubMessage("{}",topic);
        MqttLog mqttLog = createPushLog(topic,result,"请求开锁_"+locks.getId());
        return mqttLog;
    }
    /**
     * å®žæ—¶æŸ¥è¯¢é”ä¿¡æ¯
     * @param locks
     * @return
     */
    @Override
    public MqttLog getLockInfo(Locks locks) {
        String topic =  Constants.MqttTopic.getLockInfo.replace("+", locks.getId());
        int result = mqttToolService.pubMessage("{}",topic);
        MqttLog mqttLog = createPushLog(topic,result,"实时查询锁信息_"+locks.getId());
        return mqttLog;
    }
    private MqttLog createPushLog(String topic, int result,String info) {
        MqttLog log = new MqttLog();
        log.setId(Constants.getUUID());
        log.setCreateDate(new Date());
        log.setResult(result);
        log.setTopic(topic);
        log.setClientid(mqttConfig.getClientid());
        log.setHostInfo(mqttConfig.getHost());
        log.setInfo(JSONObject.toJSONString(mqttConfig));
        log.setType(Constants.ONE);
        log.setMsg("");
        log.setInfo(info);
        mqttLogMapper.insert(log);
        return  log;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/DeviceSubscribeServiceImpl.java
@@ -1,14 +1,23 @@
package com.doumee.service.business.impl;
import com.alibaba.fastjson.JSONObject;
import com.doumee.core.constants.Constants;
import com.doumee.core.exception.BusinessException;
import com.doumee.core.mqtt.config.MqttConfig;
import com.doumee.core.mqtt.service.MqttToolService;
import com.doumee.dao.business.MqttLogMapper;
import com.doumee.dao.business.model.Bikes;
import com.doumee.dao.business.model.Locks;
import com.doumee.service.business.DeviceService;
import com.doumee.service.business.DeviceSubcribeService;
import com.doumee.dao.business.model.MemberRides;
import com.doumee.dao.business.model.MqttLog;
import com.doumee.service.business.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Date;
/**
 *  ä¸Žç¡¬ä»¶å¯¹æŽ¥æœåŠ¡
@@ -16,10 +25,81 @@
 * @date 2023/10/09 18:06
 */
@Service
@Slf4j
public class DeviceSubscribeServiceImpl implements DeviceSubcribeService {
    @Autowired
    MemberRidesService memberRidesService;
    @Autowired
    private MqttLogMapper mqttLogMapper;
    @Autowired
    private MqttConfig mqttConfig;
    @Override
    public void listener(String param,String topic) {
        System.out.println("mqtt消息订阅==================="+param);
       log.info("mqtt消息订阅==================="+param);
        String info = Constants.MqttTopic.lockInfo.substring(Constants.MqttTopic.lockInfo.lastIndexOf("/")+1) ;
        String closeLock = Constants.MqttTopic.lockInfo.substring(Constants.MqttTopic.closeLock.lastIndexOf("/")+1) ;
        if(topic.indexOf(Constants.MqttTopic.topic_index)!=0
                || (!StringUtils.contains(topic, info)
                   &&!StringUtils.contains(topic,closeLock))){
            log.error("mqtt消息订阅===========无效数据========"+param);
            return;
        }
        String lockid =  getLockIdFromTopic(topic);
        if(StringUtils.isBlank(lockid)){
            //如果锁头编码为空
            log.error("mqtt消息订阅==============无效数据====="+param);
            return;
        }
        String logId =Constants.getUUID();
        String logInfo = "";
        int result =0;
        try {
            if(StringUtils.contains(topic, info)){
                //如果锁头信息上报
                Locks locks  = JSONObject.parseObject(param, Locks.class);
                locks.setId(lockid);
                locks.setInfo(logId);
                result = memberRidesService.mqttLockInfoEvent(locks);
                logInfo = "上报锁头信息";
                log.info("mqtt消息订阅=========锁信息==========成功");
            }
            if(StringUtils.contains(topic, closeLock)){
                //如果还车上报
                JSONObject pjson  = JSONObject.parseObject(param);
                String bikeCode = pjson.getString("bikeCode");
                MemberRides bikes = new MemberRides();
                bikes.setBikeCode(bikeCode);
                bikes.setBackLockId(lockid);
                bikes.setBackCommondId(logId);
                result = memberRidesService.mqttCloseBikeEvent(bikes);
                logInfo = "上报还车消息";
                log.info("mqtt消息订阅=========还车==========成功");
            }
        }catch (BusinessException e){
            result =1;
        }catch (Exception e){
            result =1;
        }
        createSubLog(topic,logId,result,param,logInfo);
    }
    private void createSubLog(String topic, String logId, int result,String param,String info) {
        MqttLog log = new MqttLog();
        log.setId(logId);
        log.setCreateDate(new Date());
        log.setResult(result);
        log.setTopic(topic);
        log.setClientid(mqttConfig.getClientid());
        log.setHostInfo(mqttConfig.getHost());
        log.setInfo(JSONObject.toJSONString(mqttConfig));
        log.setType(Constants.ZERO);
        log.setMsg(param);
        log.setInfo(info);
        mqttLogMapper.insert(log);
    }
    private String getLockIdFromTopic(String topic) {
        topic = topic.substring(0,topic.lastIndexOf("/"));
        String id =  topic.substring( topic.lastIndexOf("/")+1);
        return  id;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/GoodsorderServiceImpl.java
@@ -429,13 +429,13 @@
        BigDecimal closeMoney = new BigDecimal(0.00);
        int durationSum = 0;
        //取最高车型计算方案结算订单
        MemberRides topRides =null;
        for(MemberRides rides : memberRides){
            if ( isClose && Constants.MEMBER_RIDES_STATUS.BACK_CYCLING.getKey()!=(Constants.formatIntegerNum(rides.getStatus()))){
                throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"当前订单有未完成的骑行,无法强制结算");
            }
            durationSum += Constants.formatIntegerNum(rides.getDuration());//累计骑行(计费)时长
        }
        MemberRides topRides =memberRides.get(0);
        if(durationSum > 0 && topRides != null){
            int baseTime =Constants.formatIntegerNum(topRides.getBaseTime());
            closeMoney = Constants.formatDecimalNum(topRides.getBasePrice());
server/services/src/main/java/com/doumee/service/business/impl/LocksServiceImpl.java
@@ -10,6 +10,7 @@
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.doumee.service.business.SitesService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@@ -142,4 +143,6 @@
        QueryWrapper<Locks> wrapper = new QueryWrapper<>(locks);
        return locksMapper.selectCount(wrapper);
    }
}
server/services/src/main/java/com/doumee/service/business/impl/MemberRidesServiceImpl.java
@@ -13,9 +13,7 @@
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.DateUtil;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.ActionLogMapper;
import com.doumee.dao.business.LocksMapper;
import com.doumee.dao.business.MemberRidesMapper;
import com.doumee.dao.business.*;
import com.doumee.dao.business.join.MemberRidesJoinMapper;
import com.doumee.dao.business.model.*;
import com.doumee.dao.business.web.request.MemberRidesQuery;
@@ -59,6 +57,10 @@
    @Autowired
    private LocksMapper locksMapper;
    @Autowired
    private SitesMapper sitesMapper;
    @Autowired
    private BikesMapper bikesMapper;
    @Autowired
    private GoodsorderService goodsorderService;
@@ -366,8 +368,8 @@
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"存在骑行中车辆,无法扫码");
        };
        Locks locks = locksMapper.selectOne(new QueryWrapper<Locks>().eq("code",code).eq("isdeleted", Constants.ZERO).last("limit 1"));
        Boolean flag = deviceService.openLock(locks);
        if(!flag){
        MqttLog flag = deviceService.openLock(locks);
        if(flag.getResult() == 0){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"开锁失败");
        }
        //存储骑行记录
@@ -397,4 +399,139 @@
        return memberRidesDetailResponse;
    }
    /**
     * é”å¤´ä¿¡æ¯ä¸ŠæŠ¥
     * @param locks
     * @return
     */
    @Override
    public  int mqttLockInfoEvent(Locks locks){
        //判断检查处理站点锁头信息
        Locks model = dealLockAndSite(locks);
        //车辆记录
        Bikes bikes = dealBikesByParam(model);
        //状态,0闭合, 1打开,2运行中, 3异常
        if(model.getStatus() == Constants.LockStatus.open){
            //如果是开锁业务,判断是否有开锁中的信息
            if(StringUtils.isNotBlank(locks.getBikeCode())){
            }
            MemberRides memberRides = new MemberRides();
            memberRides.setBikeCode(model.getBikeCode());
        }
        return 0;
    }
    private Bikes dealBikesByParam(Locks model) {
        QueryWrapper<Bikes> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Bikes::getLockId, model.getId());
        wrapper.lambda().eq(Bikes::getSiteId, model.getSiteId());
        Bikes bikes = bikesMapper.selectOne(wrapper.last("last 1"));
        if(bikes != null ) {
            if (  StringUtils.equals(model.getBikeCode(), bikes.getCode())){
                //如果绑定车辆信息发生编号,更换绑定关系
                bikes.setCode(model.getBikeCode());
                bikes.setParamId(getBileTypeByCode(model.getBikeCode()));
                UpdateWrapper<Bikes> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().set(Bikes::getId, bikes.getId());
                //更新自行站点锁头绑定自行车信息
                bikesMapper.updateById(bikes);
            }
        }else{
            bikes = new Bikes();
            bikes.setId(Constants.getUUID());
            bikes.setIsdeleted(Constants.ZERO);
            bikes.setCreateDate(new Date());
            bikes.setSiteId(model.getSiteId());
            bikes.setLockId(model.getId());
            bikes.setCode(model.getBikeCode());
            bikes.setParamId(getBileTypeByCode(model.getBikeCode()));
            bikesMapper.insert(bikes);
        }
        return  bikes;
    }
    //TODO-----JP------------根据车辆code分析车辆类型,待确认方案-------------------
    private String getBileTypeByCode(String bikeCode) {
        return null;
    }
    private Locks dealLockAndSite(Locks locks) {
        Locks model =   locksMapper.selectById(locks.getId());
        Date date =new Date();
        //检查站点信息,不存在则新增
//        boolean newSite =false;
        Sites sites = sitesMapper.selectById(locks.getSiteId());
        if(sites == null){
            sites = new Sites();
            sites.setIsdeleted(Constants.ZERO);
            sites.setCode(locks.getSiteId());
            sites.setId(locks.getSiteId());
            sites.setCreateDate(date);
            sites.setStatus(Constants.ZERO);
            sites.setLockNum(1);
            //新增锁头
            sitesMapper.insert(sites);
//            newSite =true;
        }
        if(model == null){
            //如果锁头不存在,判断存储
            model = new Locks();
            model.setId(locks.getId());
            model.setSiteId(locks.getSiteId());
            model.setIsdeleted(Constants.ZERO);
            model.setCode(locks.getCode());
            model.setSiteId(locks.getSiteId());
            model.setBikeCode(locks.getBikeCode());
            model.setCreateDate(date);
            model.setStatus(locks.getStatus());
            locksMapper.insert(model);
         /*   UpdateWrapper<Sites> wrapper = new UpdateWrapper();
            wrapper.eq("id",sites.getId());
            wrapper.lambda().setSql("lock_num = COALESCE(lock_num,0)  + 1");
            wrapper.lambda().set(Sites::getEditDate,date);
            sitesMapper.update(null,wrapper);//累计锁头数量*/
        }else{
          /*  if(!StringUtils.equals(model.getId(),locks.getId())){
                //如果站点发生变化,原来的站点锁头数量-1
                UpdateWrapper<Sites> wrapper = new UpdateWrapper();
                wrapper.eq("id",model.getId());
                wrapper.lambda().setSql("lock_num = COALESCE(lock_num,0)  - 1");
                wrapper.lambda().set(Sites::getEditDate,date);
                sitesMapper.update(null,wrapper);//累计锁头数量
            }
            if(!newSite){
                //如果站点未发生变化, å¹¶ä¸”不是新站点,站点锁头+1
                UpdateWrapper<Sites> wrapper = new UpdateWrapper();
                wrapper.eq("id",model.getId());
                wrapper.lambda().setSql("lock_num = COALESCE(lock_num,0)  - 1");
                wrapper.lambda().set(Sites::getEditDate,date);
                sitesMapper.update(null,wrapper);//累计锁头数量
            }*/
            model.setSiteId(locks.getSiteId());
            model.setIsdeleted(Constants.ZERO);
            model.setCode(locks.getCode());
            model.setId(locks.getSiteId());
            model.setEditDate(date);
            model.setBikeCode(locks.getBikeCode());
            model.setStatus(locks.getStatus());
            locksMapper.update(null, new QueryWrapper<>(model));
        }
        model.setSites(sites);
        return  model;
    }
    @Override
    public  int mqttCloseBikeEvent(MemberRides bikes){
        return  0;
    }
}
server/services/src/main/java/com/doumee/service/business/impl/MqttLogServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,145 @@
package com.doumee.service.business.impl;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Utils;
import com.doumee.dao.business.MqttLogMapper;
import com.doumee.dao.business.model.MqttLog;
import com.doumee.service.business.MqttLogService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
 * ç³»ç»Ÿè¡Œä¸ºæ“ä½œè®°å½•表Service实现
 * @author æ±Ÿè¹„蹄
 * @date 2023/10/12 14:25
 */
@Service
public class MqttLogServiceImpl implements MqttLogService {
    @Autowired
    private MqttLogMapper mqttLogMapper;
    @Override
    public String create(MqttLog mqttLog) {
        mqttLogMapper.insert(mqttLog);
        return mqttLog.getId();
    }
    @Override
    public void deleteById(String id) {
        mqttLogMapper.deleteById(id);
    }
    @Override
    public void delete(MqttLog mqttLog) {
        UpdateWrapper<MqttLog> deleteWrapper = new UpdateWrapper<>(mqttLog);
        mqttLogMapper.delete(deleteWrapper);
    }
    @Override
    public void deleteByIdInBatch(List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
        mqttLogMapper.deleteBatchIds(ids);
    }
    @Override
    public void updateById(MqttLog mqttLog) {
        mqttLogMapper.updateById(mqttLog);
    }
    @Override
    public void updateByIdInBatch(List<MqttLog> mqttLogs) {
        if (CollectionUtils.isEmpty(mqttLogs)) {
            return;
        }
        for (MqttLog mqttLog: mqttLogs) {
            this.updateById(mqttLog);
        }
    }
    @Override
    public MqttLog findById(String id) {
        return mqttLogMapper.selectById(id);
    }
    @Override
    public MqttLog findOne(MqttLog mqttLog) {
        QueryWrapper<MqttLog> wrapper = new QueryWrapper<>(mqttLog);
        return mqttLogMapper.selectOne(wrapper);
    }
    @Override
    public List<MqttLog> findList(MqttLog mqttLog) {
        QueryWrapper<MqttLog> wrapper = new QueryWrapper<>(mqttLog);
        return mqttLogMapper.selectList(wrapper);
    }
    @Override
    public PageData<MqttLog> findPage(PageWrap<MqttLog> pageWrap) {
        IPage<MqttLog> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        QueryWrapper<MqttLog> queryWrapper = new QueryWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
        if (pageWrap.getModel().getId() != null) {
            queryWrapper.lambda().eq(MqttLog::getId, pageWrap.getModel().getId());
        }
        if (pageWrap.getModel().getCreateDate() != null) {
            queryWrapper.lambda().ge(MqttLog::getCreateDate, Utils.Date.getStart(pageWrap.getModel().getCreateDate()));
            queryWrapper.lambda().le(MqttLog::getCreateDate, Utils.Date.getEnd(pageWrap.getModel().getCreateDate()));
        }
        if (pageWrap.getModel().getCreator() != null) {
            queryWrapper.lambda().eq(MqttLog::getCreator, pageWrap.getModel().getCreator());
        }
        if (pageWrap.getModel().getEditDate() != null) {
            queryWrapper.lambda().ge(MqttLog::getEditDate, Utils.Date.getStart(pageWrap.getModel().getEditDate()));
            queryWrapper.lambda().le(MqttLog::getEditDate, Utils.Date.getEnd(pageWrap.getModel().getEditDate()));
        }
        if (pageWrap.getModel().getEditor() != null) {
            queryWrapper.lambda().eq(MqttLog::getEditor, pageWrap.getModel().getEditor());
        }
        if (pageWrap.getModel().getIsdeleted() != null) {
            queryWrapper.lambda().eq(MqttLog::getIsdeleted, pageWrap.getModel().getIsdeleted());
        }
        if (pageWrap.getModel().getInfo() != null) {
            queryWrapper.lambda().eq(MqttLog::getInfo, pageWrap.getModel().getInfo());
        }
        if (pageWrap.getModel().getType() != null) {
            queryWrapper.lambda().eq(MqttLog::getType, pageWrap.getModel().getType());
        }
        if (pageWrap.getModel().getClientid() != null) {
            queryWrapper.lambda().eq(MqttLog::getClientid, pageWrap.getModel().getClientid());
        }
        if (pageWrap.getModel().getTopic() != null) {
            queryWrapper.lambda().eq(MqttLog::getTopic, pageWrap.getModel().getTopic());
        }
        if (pageWrap.getModel().getMsg() != null) {
            queryWrapper.lambda().eq(MqttLog::getMsg, pageWrap.getModel().getMsg());
        }
        if (pageWrap.getModel().getResult() != null) {
            queryWrapper.lambda().eq(MqttLog::getResult, pageWrap.getModel().getResult());
        }
        for(PageWrap.SortData sortData: pageWrap.getSorts()) {
            if (sortData.getDirection().equalsIgnoreCase(PageWrap.DESC)) {
                queryWrapper.orderByDesc(sortData.getProperty());
            } else {
                queryWrapper.orderByAsc(sortData.getProperty());
            }
        }
        return PageData.from(mqttLogMapper.selectPage(page, queryWrapper));
    }
    @Override
    public long count(MqttLog mqttLog) {
        QueryWrapper<MqttLog> wrapper = new QueryWrapper<>(mqttLog);
        return mqttLogMapper.selectCount(wrapper);
    }
}
server/services/src/main/java/com/doumee/service/business/impl/SitesServiceImpl.java
@@ -205,8 +205,8 @@
        IPage<Sites> page = new Page<>(pageWrap.getPage(), pageWrap.getCapacity());
        QueryWrapper<Sites> queryWrapper = new QueryWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
//        queryWrapper.select("*,(select count(r.id) from locks r where r.site_id = sites.id) as localCount" +
        queryWrapper.select("*,(select count(r.bike_code) from locks r where r.site_id = sites.id and r.bike_code is null and r.bike_code !='' ) as bikeCount");
        queryWrapper.select("*,(select count(r.id) from locks r where r.site_id = sites.id) as all_lock_num" +
         ",(select count(r.bike_code) from locks r where r.site_id = sites.id and r.bike_code is null and r.bike_code !='' ) as bikeCount");
//        Page<SitesMonitorDTO> sitesMonitorDTO = sitesMapper.getSitesMonitorDTO(page, pageWrap.getModel().getCode(), pageWrap.getModel().getName());
        queryWrapper.lambda().like(StringUtils.isNotBlank(pageWrap.getModel().getCode()),Sites::getCode,pageWrap.getModel().getCode());
        queryWrapper.lambda().like(StringUtils.isNotBlank(pageWrap.getModel().getName()),Sites::getCode,pageWrap.getModel().getName());
@@ -215,7 +215,7 @@
        if (!CollectionUtils.isEmpty(sitesMonitorDTO.getRecords())){
            sitesMonitorDTO.getRecords().forEach(s->{
                s.setRate(new BigDecimal(s.getBikeCount()).divide(new BigDecimal(s.getLockNum()).setScale(2)));
                s.setRate(new BigDecimal(s.getBikeCount()).divide(new BigDecimal(s.getAllLockNum()).setScale(2)));
            });
        }
server/×ÔÐгµmqttЭÒé.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,43 @@
# è‡ªè¡Œè½¦ mqtt åè®®æ–‡æ¡£
## é€šä¿¡è§„范
- æ¯ä¸ªç«™ç‚¹ä¸€ä¸ª mqtt è¿žæŽ¥ï¼ŒclientId ä¸º SITE_站点编号
- ä¸€ä¸ªç«™ç‚¹ç”±éƒ¨ç½²åœ¨ä¸Šä½æœºä¸Šçš„软件通过can总线与多个锁通信,并与服务器通过mqtt做消息转发
## sub: device/lock/{id}/info
> **锁信息,在初始化、状态变更时会推送锁的完整状态**
- æ•°æ®
```json
{
    "siteId": "1015", // ç«™ç‚¹ç¼–号
    "code": "01", // é”ç¼–号
    "id": "123456789103", // é”å”¯ä¸€id,同主题{id}
    "status": 1, // çŠ¶æ€ï¼Œ0闭合, 1打开,2运行中, 3异常
    "bikeCode": "1234567890" // è‡ªè¡Œè½¦ic卡号,无车为空
}
```
## pub: device/lock/{id}/getInfo
> å®žæ—¶èŽ·å–é”ä¿¡æ¯
- æ•°æ®
```json
{}
```
## pub: device/lock/{id}/unlock
> å¼€é”ï¼ŒæˆåŠŸå¤±è´¥å¯å…³æ³¨info消息推送
- æ•°æ®
```json
{}
```
## sub: device/lock/{id}/bike
> è¿˜è½¦, è¿˜è½¦æˆåŠŸæ—¶ï¼ŒèŽ·å¾—æ‰€è¿˜è½¦è¾†ic卡号推送
- æ•°æ®
```json
{
    "bikeCode": "1234567890",
    "time": "2023-10-13 10:12:90" // ç«™ç‚¹ä¸Šä½æœºæ”¶åˆ°è¿˜è½¦æŒ‡ä»¤çš„æ—¶é—´ï¼Œä»…做参考,请以服务器时间为准
}
```