Kaynağa Gözat

Merge branch 'dev' of http://192.168.1.220:10080/Amoy2/wlyy2.0 into dev

# Conflicts:
#	common/common-entity/sql记录
yeshijie 3 yıl önce
ebeveyn
işleme
2f00a85edd

+ 16 - 0
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/common/BaseController.java

@ -5,6 +5,9 @@ import com.yihu.jw.util.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@ -16,6 +19,19 @@ public class BaseController {
    private static Logger logger = LoggerFactory.getLogger("error_logger");
    /**
     * 获取request中body数据
     */
    public String getRequestBodyData(HttpServletRequest request) throws IOException {
        BufferedReader bufferReader = new BufferedReader(request.getReader());
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = bufferReader.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    }
    /**
     * 返回接口处理结果
     *

+ 2 - 71
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/endpoint/HvDeviceController.java

@ -3,9 +3,8 @@ package com.yihu.jw.care.endpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.jw.care.common.BaseController;
import com.yihu.jw.care.service.HvDeviceService;
import com.yihu.jw.care.util.DeviceDataPushLogUtil;
import com.yihu.jw.utils.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -17,10 +16,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
 * Created with IntelliJ IDEA.
@ -32,7 +27,7 @@ import java.util.Map;
@RestController
@RequestMapping("/hvdevice")
@Api(value = "海威设备相关服务", description = "海威设备相关服务")
public class HvDeviceController {
public class HvDeviceController extends BaseController{
    private static Logger logger = LoggerFactory.getLogger(HvDeviceController.class);
@ -87,68 +82,4 @@ public class HvDeviceController {
        }
    }
    /**
     * 获取request中body数据
     */
    public static String getRequestBodyData(HttpServletRequest request) throws IOException {
        BufferedReader bufferReader = new BufferedReader(request.getReader());
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = bufferReader.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    }
    /**
     * 返回接口处理结果
     *
     * @param code  结果码,成功为200
     * @param msg   结果提示信息
     * @return
     */
    public String error(int code, String msg) {
        try {
            Map<Object, Object> map = new HashMap<Object, Object>();
            ObjectMapper mapper = new ObjectMapper();
            map.put("status", code);
            map.put("msg", msg);
            map.put("success", false);
            return mapper.writeValueAsString(map);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 接口处理成功
     * @return
     */
    public String success() {
        try {
            Map<Object, Object> map = new HashMap<Object, Object>();
            ObjectMapper mapper = new ObjectMapper();
            map.put("status", 200);
            map.put("success", true);
            return mapper.writeValueAsString(map);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    public String write(int code, String msg) {
        try {
            Map<Object, Object> map = new HashMap<Object, Object>();
            ObjectMapper mapper = new ObjectMapper();
            map.put("status", code);
            map.put("msg", msg);
            map.put("success", true);
            return mapper.writeValueAsString(map);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

+ 126 - 0
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/endpoint/SiterwellDeviceController.java

@ -0,0 +1,126 @@
package com.yihu.jw.care.endpoint;
import com.yihu.jw.care.common.BaseController;
import com.yihu.jw.care.util.OnenetPushUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: yeshijie
 * @Date: 2021/9/6
 * @Description:
 */
@RestController
@RequestMapping("/siterwelldevice")
@Api(value = "onenet设备相关服务", description = "onenet设备相关服务")
public class SiterwellDeviceController extends BaseController{
    private static Logger logger = LoggerFactory.getLogger(SiterwellDeviceController.class);
    //用户自定义token和OneNet第三方平台配置里的token一致(配置http推送时使用)
    private static String token ="jkzl2021";
    /**
     * 功能描述:第三方平台数据接收。<p>
     *           <ul>注:
     *               <li>1.OneNet平台为了保证数据不丢失,有重发机制,如果重复数据对业务有影响,数据接收端需要对重复数据进行排除重复处理。</li>
     *               <li>2.OneNet每一次post数据请求后,等待客户端的响应都设有时限,在规定时限内没有收到响应会认为发送失败。
     *                    接收程序接收到数据时,尽量先缓存起来,再做业务逻辑处理。</li>
     *           </ul>
     * @param body 数据消息
     * @return 任意字符串。OneNet平台接收到http 200的响应,才会认为数据推送成功,否则会重发。
     */
    @RequestMapping(value = "/receive",method = RequestMethod.POST)
    public String receive(@RequestBody String body) throws Exception {
        logger.info("data receive:  body String --- " +body);
        /************************************************
         *  解析数据推送请求,非加密模式。
         *  如果是明文模式使用以下代码
         **************************************************/
        /*************明文模式  start****************/
        OnenetPushUtil.BodyObj obj = OnenetPushUtil.resolveBody(body, false);
//        logger.info("data receive:  body Object --- " +obj);
        if (obj != null){
            boolean dataRight = OnenetPushUtil.checkSignature(obj, token);
            if (dataRight){
                logger.info("data receive: content" + obj.toString());
            }else {
                logger.info("data receive: signature error");
            }
        }else {
            logger.info("data receive: body empty error");
        }
        /*************明文模式  end****************/
        /********************************************************
         *  解析数据推送请求,加密模式
         *
         *  如果是加密模式使用以下代码
         ********************************************************/
        /*************加密模式  start****************/
//        Util.BodyObj obj1 = Util.resolveBody(body, true);
//        logger.info("data receive:  body Object--- " +obj1);
//        if (obj1 != null){
//            boolean dataRight1 = Util.checkSignature(obj1, token);
//            if (dataRight1){
//                String msg = Util.decryptMsg(obj1, aeskey);
//                logger.info("data receive: content" + msg);
//            }else {
//                logger.info("data receive:  signature error " );
//            }
//        }else {
//            logger.info("data receive: body empty error" );
//        }
        /*************加密模式  end****************/
        return "ok";
    }
    /**
     * 功能说明: URL&Token验证接口。如果验证成功返回msg的值,否则返回其他值。
     * @param msg 验证消息
     * @param nonce 随机串
     * @param signature 签名
     * @return msg值
     */
    @RequestMapping(value = "/receive", method = RequestMethod.GET)
    public String check(@RequestParam(value = "msg") String msg,
                        @RequestParam(value = "nonce") String nonce,
                        @RequestParam(value = "signature") String signature) throws Exception {
        logger.info("url&token check: msg:{} nonce{} signature:{}",msg,nonce,signature);
        if (OnenetPushUtil.checkToken(msg,nonce,signature,token)){
            return msg;
        }else {
            return "error";
        }
    }
    @ApiOperation("触发器消息通知接收--废弃")
    @RequestMapping(value = "triggerMessage",method = {RequestMethod.POST,RequestMethod.GET})
    public String triggerMessage(
            HttpServletRequest request) {
        try {
            String str = getRequestBodyData(request);
            logger.info("======================:"+str);
            return success();
        } catch (Exception e) {
            e.printStackTrace();
            return error(-1,"Device data incoming failure");
        }
    }
}

+ 11 - 0
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/service/OnenetService.java

@ -0,0 +1,11 @@
package com.yihu.jw.care.service;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: yeshijie
 * @Date: 2021/9/6
 * @Description:
 */
public class OnenetService {
}

+ 91 - 7
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/util/OneNetUtil.java

@ -1,5 +1,7 @@
package com.yihu.jw.care.util;
import org.apache.commons.lang.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
@ -19,6 +21,8 @@ public class OneNetUtil {
    private static final String MasterAPIkey ="Da0iDvhQ5H8OD6phWq=tMubBcBw=";
    private static final String access_key  ="WikrY0Zy/BB308DZhplru4Mc65OijFqH35nMEh4xre0=";
    private static final String objId = "3200";
    private static final String resId = "5505";
    public static String assembleToken(String version, String resourceName, String expirationTime, String signatureMethod, String accessKey)
            throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
@ -70,14 +74,94 @@ public class OneNetUtil {
        SHA1, MD5, SHA256;
    }
    /**
     * 16进制的字符串表示转成字节数组
     *
     * @param hexString
     *            16进制格式的字符串
     * @return 转换后的字节数组
     **/
    public static byte[] toByteArray(String hexString) {
        if (StringUtils.isEmpty(hexString))
            throw new IllegalArgumentException("this hexString must not be empty");
        hexString = hexString.toLowerCase();
        final byte[] byteArray = new byte[hexString.length() / 2];
        int k = 0;
        for (int i = 0; i < byteArray.length; i++) {//因为是16进制,最多只会占用4位,转换成字节需要两个16进制的字符,高位在先
            byte high = (byte) (Character.digit(hexString.charAt(k), 16) & 0xff);
            byte low = (byte) (Character.digit(hexString.charAt(k + 1), 16) & 0xff);
            byteArray[i] = (byte) (high << 4 | low);
            k += 2;
        }
        return byteArray;
    }
    /**
     * 字节数组转成16进制表示格式的字符串
     *
     * @param byteArray
     *            需要转换的字节数组
     * @return 16进制表示格式的字符串
     **/
    public static String toHexString(byte[] byteArray) {
        if (byteArray == null || byteArray.length < 1)
            throw new IllegalArgumentException("this byteArray must not be null or empty");
        final StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            if ((byteArray[i] & 0xff) < 0x10)//0~F前面不零
                hexString.append("0");
            hexString.append(Integer.toHexString(0xFF & byteArray[i]));
        }
        return hexString.toString().toLowerCase();
    }
    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        String version = "2018-10-31";
        String resourceName = "mqs/A1EB10110CFA9E06D6209E40C4A6D7976";
        String expirationTime = System.currentTimeMillis() / 1000 + 100 * 24 * 60 * 60 + "";
        String signatureMethod = SignatureMethod.SHA1.name().toLowerCase();
        String accessKey = "KuF3NT/jUBJ62LNBB/A8XZA9CqS3Cu79B/ABmfA1UCw=";
        String token = assembleToken(version, resourceName, expirationTime, signatureMethod, accessKey);
        System.out.println("Authorization:" + token);
//        String version = "2018-10-31";
//        String resourceName = "mqs/A1EB10110CFA9E06D6209E40C4A6D7976";
//        String expirationTime = System.currentTimeMillis() / 1000 + 100 * 24 * 60 * 60 + "";
//        String signatureMethod = SignatureMethod.SHA1.name().toLowerCase();
//        String accessKey = "KuF3NT/jUBJ62LNBB/A8XZA9CqS3Cu79B/ABmfA1UCw=";
//        String token = assembleToken(version, resourceName, expirationTime, signatureMethod, accessKey);
//        System.out.println("Authorization:" + token);
        //001F0000161401000000000400005A1200000701C6FFADFFF900000E620245CA71
        String value = "001F0000161401000000000400005A1200000701C6FFADFFF900000E620245CA71";
        String value1 = "1401000000000400005A1200000701C6FFADFFF900000E620245CA71";
        System.out.println(Integer.parseInt("001F", 16));
        System.out.println(Integer.parseInt("00", 16));
        System.out.println(Integer.parseInt("0016", 16));
        System.out.println("1401");
        System.out.println("0000");//Public_Status
        System.out.println(Integer.parseInt("00", 16));//Gas_Status
        System.out.println(Integer.parseInt("00", 16));//Co_Status
        System.out.println(Integer.parseInt("04", 16));//Gas_Level
        System.out.println(Integer.parseInt("0000", 16));//Co_Level
        System.out.println(Integer.parseInt("5A", 16));//Battery_Level
//        byte[] lenth = toByteArray(value);
//        System.out.println(toHexString(lenth));
/*        长度:31
        命令:0
        流水号:22
        命令:0x1401
        公共状态:0000000000000000(二进制)0
        AC电源
        GAS传感器状态:00000000(二进制)0
        CO传感器状态:00000000(二进制)0
        GAS浓度百分比:4%
                CO浓度:0(ppm)
                电量百分比:90%
                CSQ:18
        ECL:0
        SNR:7
        PCI:454
        RSRP:-83
        RSRQ:-7
        频点:3682
        小区ID:38128241*/
    }
}

+ 176 - 0
svr/svr-cloud-device/src/main/java/com/yihu/jw/care/util/OnenetPushUtil.java

@ -0,0 +1,176 @@
package com.yihu.jw.care.util;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.*;
/**
 * Created with IntelliJ IDEA.
 *
 * @Author: yeshijie
 * @Date: 2021/9/6
 * @Description:
 */
public class OnenetPushUtil {
    private static Logger logger = LoggerFactory.getLogger(OnenetPushUtil.class);
    private static MessageDigest mdInst;
    static {
        try {
            mdInst = MessageDigest.getInstance("MD5");
            Security.addProvider(new BouncyCastleProvider());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    /**
     * 功能描述:在OneNet平台配置数据接收地址时,平台会发送URL&token验证请求<p>
     *          使用此功能函数验证token
     * @param msg 请求参数 <msg>的值
     * @param nonce 请求参数 <nonce>的值
     * @param signature 请求参数 <signature>的值
     * @param token OneNet平台配置页面token的值
     * @return token检验成功返回true;token校验失败返回false
     */
    public static boolean checkToken(String msg,String nonce,String signature, String token) throws UnsupportedEncodingException {
        byte[] paramB = new byte[token.length() + 8 + msg.length()];
        System.arraycopy(token.getBytes(), 0, paramB, 0, token.length());
        System.arraycopy(nonce.getBytes(), 0, paramB, token.length(), 8);
        System.arraycopy(msg.getBytes(), 0, paramB, token.length() + 8, msg.length());
        String sig =  com.sun.org.apache.xerces.internal.impl.dv.util.Base64.encode(mdInst.digest(paramB));
        logger.info("url&token validation: result {},  detail receive:{} calculate:{}", sig.equals(signature.replace(' ','+')),signature,sig);
        return sig.equals(signature.replace(' ','+'));
    }
    /**
     * 功能描述: 检查接收数据的信息摘要是否正确。<p>
     *          方法非线程安全。
     * @param obj 消息体对象
     * @param token OneNet平台配置页面token的值
     * @return
     */
    public static boolean checkSignature(BodyObj obj, String token)  {
        //计算接受到的消息的摘要
        //token长度 + 8B随机字符串长度 + 消息长度
        byte[] signature = new byte[token.length() + 8 + obj.getMsg().toString().length()];
        System.arraycopy(token.getBytes(), 0, signature, 0, token.length());
        System.arraycopy(obj.getNonce().getBytes(), 0, signature, token.length(), 8);
        System.arraycopy(obj.getMsg().toString().getBytes(), 0, signature, token.length() + 8, obj.getMsg().toString().length());
        String calSig = Base64.encodeBase64String(mdInst.digest(signature));
        logger.info("check signature: result:{}  receive sig:{},calculate sig: {}",calSig.equals(obj.getMsgSignature()),obj.getMsgSignature(),calSig);
        return calSig.equals(obj.getMsgSignature());
    }
    /**
     *  功能描述 解密消息
     * @param obj 消息体对象
     * @param encodeKey OneNet平台第三方平台配置页面为用户生成的AES的BASE64编码格式秘钥
     * @return
     * @throws NoSuchPaddingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws InvalidKeyException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     */
    public static String decryptMsg(BodyObj obj, String encodeKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        byte[] encMsg = Base64.decodeBase64(obj.getMsg().toString());
        byte[] aeskey = Base64.decodeBase64(encodeKey + "=");
        SecretKey secretKey = new SecretKeySpec(aeskey, 0, 32, "AES");
        Cipher cipher = null;
        cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(aeskey, 0, 16));
        byte[] allmsg = cipher.doFinal(encMsg);
        byte[] msgLenBytes = new byte[4];
        System.arraycopy(allmsg, 16, msgLenBytes, 0, 4);
        int msgLen = getMsgLen(msgLenBytes);
        byte[] msg = new byte[msgLen];
        System.arraycopy(allmsg, 20, msg, 0, msgLen);
        return new String(msg);
    }
    /**
     * 功能描述 解析数据推送请求,生成code>BodyObj</code>消息对象
     * @param body 数据推送请求body部分
     * @param encrypted 表征是否为加密消息
     * @return  生成的<code>BodyObj</code>消息对象
     */
    public static BodyObj resolveBody(String body, boolean encrypted) {
        JSONObject jsonMsg = new JSONObject(body);
        BodyObj obj = new BodyObj();
        obj.setNonce(jsonMsg.getString("nonce"));
        obj.setMsgSignature(jsonMsg.getString("msg_signature"));
        if (encrypted) {
            if (!jsonMsg.has("enc_msg")) {
                return null;
            }
            obj.setMsg(jsonMsg.getString("enc_msg"));
        } else {
            if (!jsonMsg.has("msg")) {
                return null;
            }
            obj.setMsg(jsonMsg.get("msg"));
        }
        return obj;
    }
    private static int getMsgLen(byte[] arrays) {
        int len = 0;
        len += (arrays[0] & 0xFF) << 24;
        len += (arrays[1] & 0xFF) << 16;
        len += (arrays[2] & 0xFF) << 8;
        len += (arrays[3] & 0xFF);
        return len;
    }
    public static class BodyObj {
        private Object msg;
        private String nonce;
        private String msgSignature;
        public Object getMsg() {
            return msg;
        }
        public void setMsg(Object msg) {
            this.msg = msg;
        }
        public String getNonce() {
            return nonce;
        }
        public void setNonce(String nonce) {
            this.nonce = nonce;
        }
        public String getMsgSignature() {
            return msgSignature;
        }
        public void setMsgSignature(String msgSignature) {
            this.msgSignature = msgSignature;
        }
        @Override
        public String toString(){
            return "{ \"msg\":"+this.msg+",\"nonce\":"+this.nonce+",\"signature\":"+this.msgSignature+"}";
        }
    }
}