gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 开发博客
  • bug清单
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Kafka

分类归档Java

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  大数据开发
  • 分类归档: "Java"
bug清单, Java 1月 4,2021

SpringBoot 接口返回的 JSON 数据的时间与数据存储时间有误差

在做一个项目,接入数据存到数据库,在图层上展示今天、昨天的数据。但是发现展示的时间有误差。

 
使用MySQL57,(程序中打印的时间字段)查询出的时间字段总是和数据库存储的相差两个小时。
最后是通过修改数据库连接解决了这个问题。添加了下面这个属性。
&serverTimezone=Asia/Shanghai
接着又出现问题了。
默认情况下使用 @ResponseBody ,项目返回的JSON数据,返回对象会自动转为JSON格式,但是对象中的日期格式Date字段转换的时候相差了八小时,程序内打印时间没有问题,如果将 Date 改为 String 类型的话,也不会出现这种情况了。
所以问题应该出在返回结果格式化为JSON的这个过程中。
原因是spring转json的默认实现jackson中会根据时区去转换时间,而jackson的默认时区跟国内应该是相差8小时,所以在时间换算上自动减去了8小时。
可以通过jackson 的注解 @JsonFormat 解决问题
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8") private Date createTime; @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss" ,timezone = "GMT+8") private Date updateTime;
也可以在 SpringBoot 配置文件中统一配置,推荐使用这种方式:
  spring.jackson.date-format=yyyy-MM-dd HH:mm:ss   spring.jackson.time-zone=GTM+8
作者 east
bug清单, Java 1月 4,2021

springboot内嵌tomcat文件上传路径不存在bug解决

在线上环境容易出现一些开发环境没遇到的问题。就像这个问题,springboot内嵌tomcat,上传文件时会存放到tomcat临时文件目录(停止时删除/重启时新建),如:/tmp/tomcat.1046709481715876128.17301/work/Tomcat/localhost/cms

可知文件保存在/tmp目录下,/tmp目录在centos下会定时清理,大约10天未使用将会删除目录,(当tomcat未重启,但centos删除相应目录,tomcat获取相应目录却获取不到会报错)

 
解决方案:
一 配置multipartFile上传路径(推荐)
1.application.properties 文件中添加
spring.http.multipart.location=${tmp.file.path} 注意:tmp.file.path 如果不存在,spring会认为是相对路径,对应根路径是tomcat临时文件目录 2
2.配置相应bean
/** * 文件上传临时路径 */ @Bean MultipartConfigElement multipartConfigElement() { MultipartConfigFactory factory = new MultipartConfigFactory(); factory.setLocation("/data/ops/app/cms/cache"); return factor 246810121416
二 修改tomcat临时存放文件位置(不建议)
application.properties 文件中添加 (此方法会讲所有tomcat临时文件放在指定目录,新目录没有定时清理功能,不建议)
server.tomcat.basedir=/data/ops/app/cms/cache 2
三 修改centos定时清理功能(不建议)
vim /etc/cron.daily/tmpwatch
#! /bin/sh flags=-umc /usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \ -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \ -X '/tmp/hsperfdata_*' 10d /tmp \ -X '/tmp/tomcat.*' 10d /tmp /usr/sbin/tmpwatch "$flags" 30d /var/tmp for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do if [ -d "$d" ]; then /usr/sbin/tmpwatch "$flags" -f 30d "$d" fi done 24681012141618202224
其中添加一行
-X '/tmp/tomcat.*' 10d /tmp
作者 east
Java 1月 4,2021

springboot使用 @scheduled 多任务并发

springboot的@scheduled,并不是默认并发的,想给方法添加@Scheduled注解,实现两个定时任务。可是运行发现,两个task并没有并发执行,而是执行完一个task才会执行另外一个。

要 给类添加注解@EnableAsync,并给方法添加注解@Async。

 
@Component
@Configurable
@EnableScheduling
@EnableAsync
public class DemoTask {
@Async
@Scheduled(cron = "0/5 * *  * * ? ")
public void startSchedule() {
System.out.println("===========1=>");
try {
for(int i=1;i<=10;i++){
System.out.println("=1==>"+i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
 
@Async
@Scheduled(cron = "0/5 * *  * * ? ")
public void startSchedule2() {
for(int i=1;i<=10;i++){
System.out.println("=2==>"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

在这个类或启动类BootApplication添加@EnableScheduling标注

作者 east
bug清单, Java 1月 4,2021

Spring Boot Maven项目使用SystemPath引用线上部署遇到的问题

使用了第三方Jar包,最先考虑的是不使用Maven仓库,便于离线开发。首先采用了方案:

 <dependency>
        <groupId>com.tievd.third</groupId>
        <artifactId>arcvideo</artifactId>
        <version>1.0</version>
        <scope>system</scope>
        <systemPath>${basedir}/lib/face-api-1.0.jar</systemPath>
    </dependency>

但很多人讲到这里就没讲了,你会发现在IDE里会运行的非常好,一旦部署在线上环境,就会出现莫名其妙的问题。比如我遇到的不会抛异常,会一直卡在对象创建上。后来一直找不到问题出现在哪里,就改用了私服,发现问题解决,所以定位在问题肯定出现在打包上:第一步:确认解压之前的Jar包发现确实没有把第三方包打入进去第二步:在build节点加入一下语句使包正确的导入

   <resources>
            <resource>
                <directory>${project.basedir}/lib</directory>
                <targetPath>BOOT-INF/lib/</targetPath>
                        <includes>
                           <include>**/*.jar</include>
                        </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <targetPath>BOOT-INF/classes/</targetPath>
            </resource>
</resources>

  • 重新打包发现可以在线上环境正常部署了。
作者 east
Java 12月 7,2020

汉字转换位汉语拼音工具类

public final class Cn2Spell {

private Cn2Spell() {

}

/**
* 汉字转换位为语拼音首字母,英文字符不变
*
*
@param chines 汉字
*
@return 拼音
*/
public static String converterToFirstSpell(String chines) {
if (StringUtils.isBlank(chines)) {
return chines;
}
String pinyinName = "";
char[] nameChar = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
pinyinName += PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0].charAt(0);
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
pinyinName += nameChar[i];
}
}
return pinyinName.toUpperCase();
}

/**
* 汉字转换为汉语拼音,英文字符不变
*
*
@param chines 汉字
*
@return 拼音
*/
public static String converterToSpell(String chines) {
if (StringUtils.isBlank(chines)) {
return chines;
}
String pinyinName = "";
int index = 0;
char[] nameChar = chines.toCharArray();
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
for (int i = 0; i < nameChar.length; i++) {
if (nameChar[i] > 128) {
try {
if (index == 0 && i != 0) {
pinyinName += "_" + PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0];
} else {
pinyinName += PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0];
}
index++;
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
} else {
if (index > 0) {
pinyinName += "_" + nameChar[i];
index = 0;
} else {
pinyinName += nameChar[i];
}

}
}
return pinyinName.toUpperCase();
}

/**
* 判断是否有中文
*
*
@param str
*
@return
*/
public static boolean isChineseChar(String str) {
boolean temp = false;
// 即[\\u4e00-\\u9fa5]字符,因代码检查不通过,需如下处理
StringBuilder sb = new StringBuilder();
sb.append("[\\u").append("4e00-\\u").append("9fa5]");

Pattern p = Pattern.compile(sb.toString());
Matcher m = p.matcher(str);

if (m.find()) {
temp = true;
}
return temp;
}
}
作者 east
Java 12月 7,2020

中文转数字Java工具类


import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;


public final class CnNumericToArabicUtil {

/**
* 无参构造函数
*/
private CnNumericToArabicUtil() {
}

/**
* 中文数字数组
*/
private static final Character[] CN_NUMERIC = { '一', '二', '三', '四', '五', '六', '七', '八', '九', '壹', '贰', '叁', '肆',
'伍', '陆', '柒', '捌', '玖', '○', 'O', '零', '十', '百', '千', '拾', '佰', '仟', '万', '亿' };

private static Map<Character, Integer> cnNumeric = null;

static {
cnNumeric = new HashMap<Character, Integer>(40, 0.85f);
for (int j = 0; j < 9; j++) {
cnNumeric.put(CN_NUMERIC[j], j + 1);
}
for (int j = 9; j < 18; j++) {
cnNumeric.put(CN_NUMERIC[j], j - 8);
}
for (int j = 18; j < 21; j++) {
cnNumeric.put(CN_NUMERIC[j], 0);
}

cnNumeric.put(' ', 0);
cnNumeric.put('两', 2);
cnNumeric.put('十', 10);
cnNumeric.put('拾', 10);
cnNumeric.put('百', 100);
cnNumeric.put('佰', 100);
cnNumeric.put('千', 1000);
cnNumeric.put('仟', 1000);
cnNumeric.put('万', 10000);
cnNumeric.put('亿', 100000000);
}

/**
* 中文数字转换为阿拉伯数字<br>
* TODO 该方法不完善的地方为只能纯的中文数字或者纯的阿拉伯数字,如果互相掺杂,得到的结果不准确,后期再完善<br>
*
*
@param cn 中文数字
*
@return int
*/
public static int cnNumericToArabic(String cn) {

// 中文数字参数为空判断,为空时返回0
if (StringUtils.isEmpty(cn)) {
return 0;
}

cn = cn.trim();

// 阿拉伯数字,类型转换后,直接返回结果
if (NumberUtils.isNumber(cn)) {
return Integer.parseInt(cn);
}

if (cn.length() == 1) {
return isCnNumeric(cn.charAt(0));
}

cn = cn.replace('佰', '百').replace('仟', '千').replace('拾', '十').replace('零', ' ');

// 结果值
int val = 0;

// 根据中文单位,将中文数字转换为阿拉伯数字,得到结果数组
// 亿
String[] cnNumericToArabicByCnUnitResults = cnNumericToArabicByCnUnit(cn, '亿', 100000000);
cn = cnNumericToArabicByCnUnitResults[0];
val += Integer.parseInt(cnNumericToArabicByCnUnitResults[1]);

// 万
cnNumericToArabicByCnUnitResults = cnNumericToArabicByCnUnit(cn, '万', 10000);
cn = cnNumericToArabicByCnUnitResults[0];
val += Integer.parseInt(cnNumericToArabicByCnUnitResults[1]);

// 千
cnNumericToArabicByCnUnitResults = cnNumericToArabicByCnUnit(cn, '千', 1000);
cn = cnNumericToArabicByCnUnitResults[0];
val += Integer.parseInt(cnNumericToArabicByCnUnitResults[1]);

// 百
cnNumericToArabicByCnUnitResults = cnNumericToArabicByCnUnit(cn, '百', 100);
cn = cnNumericToArabicByCnUnitResults[0];
val += Integer.parseInt(cnNumericToArabicByCnUnitResults[1]);

// 十
int ten = -1;
ten = cn.lastIndexOf('十');
if (ten > -1) {
if (ten == 0) {
val += 1 * 10;
} else {
val += cnNumericToArabic(cn.substring(0, ten)) * 10;
}
if (ten < cn.length() - 1) {
cn = cn.substring(ten + 1, cn.length());
} else {
cn = "";
}
}

cn = cn.trim();
for (int j = 0; j < cn.length(); j++) {
val += isCnNumeric(cn.charAt(j));
}
return val;
}

/**
* 中文数字转阿拉伯数字<BR>
* 如果字符串中文数字表达不全或错误,则只会解析部分(例如三十二百五六返回32)
*
*
@param numStr 待转换的字符串
*
@param numArrays 阿拉伯数值数组
*
@return
*/
public static String cnNumericToArabic(String numStr, char[] numArrays) {

if (StringUtils.isEmpty(numStr)) {
return "";
}

StringBuffer strRs = new StringBuffer();
boolean isFirst = (null == numArrays || numArrays.length == 0);
numStr = filterStr(numStr);
Pattern pattern = Pattern.compile("^\\d+$");

if (pattern.matcher(numStr).find()) {
return numStr;
}
char[] args = numStr.toCharArray();
int index = 0;
for (int i = UNITS_2.length - 1; i > 0; i--) {
index = numStr.indexOf(UNITS_2[i]);

if (index > 0) {
if (null == numArrays || numArrays.length == 0) {
numArrays = new char[Arrays.binarySearch(UNITS_2, args[index]) * 4];
Arrays.fill(numArrays, '0');
}
cnNumericToArabic(numStr.substring(index), numArrays);
break;
}
}

try {
process(numStr, numArrays, strRs, isFirst, index);

} catch (Exception e) {
return "";
}
// 避免只有单位没数字 比如十三这个“十”单位前没数字,根据习惯默认为一
return strRs.toString().replaceAll("[十,百,千,万,亿]", "1");
}

/**
* 检查是否为中文字符
*
*
@param ch 中文字符
*
@return boolean true:是中文数字;false:不是中文数字
*/
private static int isCnNumeric(char ch) {
Integer i = cnNumeric.get(ch);
if (i == null) {
return 0;
}
return i.intValue();
}

/**
* 根据中文单位,将中文数字转换为阿拉伯数字
*
*
@param cn 中文数字
*
@param cnUnit 中文单位,如:亿、万、千、百、十
*
@param unitVal 单位值,如:亿-100000000
*
@return String[] 字符串数组,格式为:{处理后的中文数字、结果值}
*/
private static String[] cnNumericToArabicByCnUnit(String cn, char cnUnit, int unitVal) {
// 中文数字为空判断,当为空时直接返回空字符串和结果值为0的数组
if (StringUtils.isEmpty(cn)) {
return new String[] { "", "0" };
}

// 结果值
int val = 0;
// 中文单位所在位置
int unitPos = cn.lastIndexOf(cnUnit);
if (unitPos > -1) {
// 中文数字转换为阿拉伯数字
val += cnNumericToArabic(cn.substring(0, unitPos)) * unitVal;
if (unitPos < cn.length() - 1) {
cn = cn.substring(unitPos + 1, cn.length());
} else {
cn = "";
}

if (cn.length() == 1) {
int arbic = isCnNumeric(cn.charAt(0));
if (arbic <= 10) {
val += arbic * unitVal * 0.1;
}
cn = "";
}
}
return new String[] { cn, "" + val };
}

/** 中文数值 */
private static final Character[] CN_NUMBER_1 = { 'O', '一', '二', '三', '四', '五', '六', '七', '八', '九' };

/** 中文数值 */
private static final Character[] CN_NUMBER_2 = { '零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' };

/** 阿拉伯数值 */
private static final Character[] ARABIC_NUMBER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

/** 用于辅助定位单位 */
private static final String UNITS_1_STR = " 十百千";

/** 单位一 */
private static final Character[] UNITS_1 = { ' ', '十', '百', '千' };

/** 单位一的同义词 */
private static final Character[] UNITS_1_T = { ' ', '拾', '佰', '仟' };

/** 单位2 */
private static final Character[] UNITS_2 = { ' ', '万', '亿' };

/**
* 从字符串中提取满足当前可转换为阿拉伯数字的字符串
*
*
@param str 待转换的字符串
*
@return
*/
public static String getCnNumericStr(String str) {
StringBuffer regx = new StringBuffer("([");
for (Character c : CN_NUMBER_1) {
regx.append(c.charValue());
}
for (Character c : CN_NUMBER_2) {
regx.append(c.charValue());
}
for (Character c : ARABIC_NUMBER) {
regx.append(c.charValue());
}
for (Character c : UNITS_1) {
regx.append(String.valueOf(c.charValue()).trim());
}
for (Character c : UNITS_1_T) {
regx.append(String.valueOf(c.charValue()).trim());
}
for (Character c : UNITS_2) {
regx.append(String.valueOf(c.charValue()).trim());
}
regx.append("两Oo○");
regx.append("]+)");
Pattern pattern = Pattern.compile(regx.toString());
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
return matcher.group();
}
return "";
}

/**
* 从字符串中提取满足当前可转换为阿拉伯数字的字符串,并将转换后的中文数字用阿拉伯数字替换掉原来字符串中的数值,并且返回
*
*
@param str 待转换的字符串
*
@return
*/
public static String transCnNumericStr(String str) {
if (StringUtils.isEmpty(str)) {
return "";
}
StringBuffer regx = new StringBuffer("([");
for (Character c : CN_NUMBER_1) {
regx.append(c.charValue());
}
for (Character c : CN_NUMBER_2) {
regx.append(c.charValue());
}
for (Character c : ARABIC_NUMBER) {
regx.append(c.charValue());
}
for (Character c : UNITS_1) {
regx.append(String.valueOf(c.charValue()).trim());
}
for (Character c : UNITS_1_T) {
regx.append(String.valueOf(c.charValue()).trim());
}
for (Character c : UNITS_2) {
regx.append(String.valueOf(c.charValue()).trim());
}
regx.append("两Oo○");
regx.append("]+)");
Pattern pattern = Pattern.compile(regx.toString());

Matcher matcher = pattern.matcher(str);
String value = "";
if (matcher.find()) {
value = matcher.group();
}
return str.replaceFirst(regx.toString(), CnNumericToArabicUtil.cnNumericToArabic(value, null));
}

/**
* 进行解析处理
*
*
@param numStr 需要解析的数值字符串
*
@param numArrays 数值对应的数组
*
@param strRs 结果
*
@param isFirst 是否第一次遍历
*
@param index 分隔索引
*
@throws Exception
*/
private static void process(String numStr, char[] numArrays, StringBuffer strRs, boolean isFirst, int index)
throws Exception {
char[] args;

if (isFirst) {
firstParse(numStr, numArrays, strRs, index);
} else {
// 大于万
if (index > 0) {
args = numStr.substring(0, index).toCharArray();
numStr = numStr.substring(0, index);
} else {
args = numStr.toCharArray();
}
// 找到起始位置
int start = numArrays.length - Arrays.binarySearch(UNITS_2, args[0]) * 4;

for (int i = 1, j = 0; i < UNITS_1.length; i++) {
j = numStr.indexOf(UNITS_1[i]);
// 包含十, 百, 千单位
if (j > 0) {
numArrays[start + (3 - i)] = args[j - 1];

if (i == 1 && j + 1 < args.length) {
numArrays[start + (3 - i) + 1] = args[j + 1];
}
} else {
// 找上级(比如十没找到,则找百)
for (int ii = 1 + i; ii < UNITS_1.length; ii++) {
j = numStr.indexOf(UNITS_1[ii]);
// 找到上级
if (j > 0) {
numArrays[start + (3 - ii)] = args[j - 1];
break;
}
}
// 如果没有任何上级,且当前索引必须小于千,则按十-千填入数字
if (j < 0 && args.length - 1 - i >= 0 && i < 3) {
// 填入当前位置的数值
if (NumberUtils.isNumber(String.valueOf(args[args.length - 1 - i]))) {
numArrays[start + (3 - i)] = args[args.length - 1 - i];
}
// 填入当前位置后面的数值
if (NumberUtils.isNumber(String.valueOf(args[args.length - i]))) {
numArrays[start + (3 - i) + 1] = args[args.length - i];
}
}
}
}
}
}

/**
* 第一次解析
*
*
@param numStr 需要解析的数值字符串
*
@param numArrays 数值对应的数组
*
@param strRs 结果
*
@param index 为万级别的索引
*/
private static void firstParse(String numStr, char[] numArrays, StringBuffer strRs, int index) {
char[] args;
// 数值不超过5位
if (index <= 0) {
index = numStr.length();
}
args = numStr.substring(0, index).toCharArray();

if (null != args && args.length > 1) {
// 第二位为单位(十百千)
int k = UNITS_1_STR.indexOf(args[1]);
// 此位为单位(十百千),则创建此段空数组,准备填入数值
if (k > 0) {
char[] arrays = new char[k + 1];
// 默认为0
Arrays.fill(arrays, '0');
// 从十百千依次开始
for (int i = 1, j = 0; k > 0 && i < UNITS_1.length; i++, k--) {
j = numStr.substring(0, index).indexOf(UNITS_1[i]);
// 此字符串包含十百千,j的前一位肯定是数字
if (j > 0) {
// 在对应的数组位置填上其数值
arrays[arrays.length - 1 - i] = args[j - 1];
// i为1说明当前处于十位,则需要补全个位数
if (i == 1 && j + 1 < args.length) {
arrays[arrays.length - i] = args[j + 1];
}
// 没找到单位
} else {
// 找上级(比如十没找到,则找百)
for (int ii = 1 + i; ii < UNITS_1.length; ii++) {
j = numStr.substring(0, index).indexOf(UNITS_1[ii]);
// 找到上级
if (j > 0) {
// 如果上级索引位置后面还有数字个数大于等于理论上的数字减一,则填入当前索引位的最后一位
if ((args.length - j - 1) >= (ii - 1)) {
arrays[arrays.length - i] = args[args.length - i];
}
}

}
}
}

strRs.append(String.valueOf(arrays));

if (null != numArrays) {
strRs.append(String.valueOf(numArrays));
}
} else {
// 不规则的情况(单位前没数字) 十二、百三十
strRs.append(numStr.substring(0, index));
if (null != numArrays) {
strRs.append(String.valueOf(numArrays));
}
}
} else {
// 解析位只有1位,则判断其是否为单位属性
if (null != args && args.length == 1) {
int k = UNITS_1_STR.indexOf(args[0]);
if (k > 0) {
char[] arrays = new char[k + 1];
Arrays.fill(arrays, '0');
arrays[0] = '1';
strRs.append(String.valueOf(arrays));
}
}
// 如果不包含单位,则直接添加此数值
if (!UNITS_1_STR.contains(numStr.substring(0, index))) {
strRs.append(numStr.substring(0, index));
}

if (null != numArrays) {
strRs.append(String.valueOf(numArrays));
}
}
}

/**
* 将中文数值转换为阿拉伯数字
*
*
@param numStr 待过滤的字符串
*
@return
*/
private static String filterStr(String numStr) {
numStr = numStr.replace('O', ARABIC_NUMBER[0].charValue());
numStr = numStr.replace('○', ARABIC_NUMBER[0].charValue());
numStr = numStr.replace('两', ARABIC_NUMBER[2].charValue());
for (int i = 0; i < ARABIC_NUMBER.length; i++) {
numStr = numStr.replace(CN_NUMBER_1[i].charValue(), ARABIC_NUMBER[i].charValue());
numStr = numStr.replace(CN_NUMBER_2[i].charValue(), ARABIC_NUMBER[i].charValue());
}
for (int i = 1; i < UNITS_1.length; i++) {
numStr = numStr.replace(UNITS_1_T[i].charValue(), UNITS_1[i].charValue());
}
return numStr;
}
}
作者 east
Java 12月 7,2020

非spring容器下的配置工具类

1、按照spring boot的约定,配置文件名称默认是classpath根路径下的application.properties,并按其约定加载多个配置文件
2、按指定配置文件的路径及名称读取配置,一般是兼容旧工程没有按spring boot约定命名的配置文件 <br>
3、新增读取yml配置文件的功能,默认先读取properties文件,如果不存在再读取yml文件

public final class ConfigUtil {

    private static Logger log = LoggerFactory.getLogger(DataBaseUtil.class);

    /**
     * spring boot默认的配置文件名称
     */
    private static final String CONFIG_FILENAME = "application";

    private static final String DEFAULT_SUFFIX = ".properties";

    private static final String YML_SUFFIX = ".yml";

    /**
     * spring boot通过application.properties配置文件中的spring.profiles.active配置项值指定生效的配置文件名称<br>
     * 如spring.profiles.active=business,表示application-business.properties配置文件生效
     */
    private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

    /**
     * spring boot约定命名格式"application-{profile}.properties"来定义多个配置文件,其中{profile}是可变部分
     */
    private static final String SPRING_BOOT_PROFILE_TEMPLATE = "application-{profile}";

    /**
     * 属性对象集合,注意这里是线程安全的
     */
    private static Map<String, Properties> props = new ConcurrentHashMap<>();

    /** 私有的构造函数 */
    private ConfigUtil() {

    }

    /**
     * 加载指定配置文件中的配置
     * 
     * @param fileName
     * @return
     */
    private static Properties loadPropFromFile(String fileName) {
        Properties prop = new Properties();

        try {
            prop.load(ConfigUtil.class.getClassLoader().getResourceAsStream(fileName));
        } catch (IOException e) {
            e.printStackTrace();
            String error = "配置文件工具类加载配置文件" + fileName + "出现异常!";
            log.error(e.getMessage()+":===:"+error);
            throw new RuntimeException(error);
        }
        return prop;
    }

    /**
     * 将yml格式文件加载到Properties中
     * 
     * @param fileName 文件名
     * @return
     */
    private static Properties loadYmlFromFile(String fileName) {
        Properties prop = new Properties();
        LoaderOptions options = new LoaderOptions();
        // 是否允许读取重复key值,默认为true
        options.setAllowDuplicateKeys(false);
        Yaml yaml = new Yaml(options);

        // 加载yml文件流
        InputStream inStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileName);
        // 按照文件编码读取流
        Reader reader = new UnicodeReader(inStream);
        Iterable<Object> it = yaml.loadAll(reader);
        Map<String, Object> result = new LinkedHashMap<>();

        for (Object object : it) {
            // 构建map类型数据
            buildFlattenedMap(result, asMap(object), null);
        }
        prop.putAll(result);
        return prop;
    }

    /**
     * 递归转换map源数据,将递归的key值用"."拼接成最终目标map的key值,最终的value为目标map的value值
     * 
     * @param result
     * @param source
     * @param path
     */
    @SuppressWarnings("unchecked")
    private static void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, String path) {
        source.forEach((key, value) -> {

            if (hasText(path)) {
                if (key.startsWith("[")) {
                    key = path + key;
                } else {
                    // 分层读取key值,使用"."拼接
                    key = path + '.' + key;
                }
            }

            if (value instanceof String) {
                result.put(key, value);
            } else if (value instanceof Map) {
                // Need a compound key
                Map<String, Object> map = (Map<String, Object>) value;
                // 递归构造map
                buildFlattenedMap(result, map, key);
            } else if (value instanceof Collection) {
                // Need a compound key
                Collection<Object> collection = (Collection<Object>) value;

                if (collection.isEmpty()) {
                    result.put(key, "");
                } else {
                    int count = 0;
                    for (Object object : collection) {
                        buildFlattenedMap(result, Collections.singletonMap("[" + (count++) + "]", object), key);
                    }
                }
            } else {
                result.put(key, (value != null ? value : ""));
            }
        });
    }

    /**
     * 将object数据转换为Map
     * 
     * @param object
     * @return
     */
    @SuppressWarnings("unchecked")
    private static Map<String, Object> asMap(Object object) {
        // YAML can have numbers as keys
        Map<String, Object> result = new LinkedHashMap<>();

        if (!(object instanceof Map)) {
            // A document can be a text literal
            result.put("document", object);
            return result;
        }
        Map<Object, Object> map = (Map<Object, Object>) object;

        map.forEach((key, value) -> {

            if (value instanceof Map) {
                value = asMap(value);
            }

            if (key instanceof CharSequence) {
                result.put(key.toString(), value);
            } else {
                // It has to be a map key in this case
                result.put("[" + key.toString() + "]", value);
            }
        });
        return result;
    }

    // 判断字符串是否有值(不为空、不为null、必须包含字符串)
    private static boolean hasText(@Nullable String str) {
        return (str != null && !str.isEmpty() && containsText(str));
    }

    // 是否包含字符
    private static boolean containsText(CharSequence str) {
        int strLen = str.length();

        for (int i = 0; i < strLen; i++) {

            if (!Character.isWhitespace(str.charAt(i))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 根据属性key得到对应的属性值<br>
     * 配置文件按spring boot的约定的配置文件命名规则进行加载<br>
     * <font color=red>注意: 暂不支持yml文件属性读取</font>
     * 
     * @param key 键名称
     * @return
     */
    public static String getPropsValueByKey(String key) {
        // TODO 暂时不支持读取yml格式文件,yml文件支持map和list格式数据,需要另写方法支持
        if (!props.containsKey(CONFIG_FILENAME)) {
            Properties prop = new Properties();
            prop = getPropertiesByFileName(CONFIG_FILENAME);

            if (prop.get(SPRING_PROFILES_ACTIVE) != null) {
                // 依次读取指定的配置文件
                for (String partName : prop.get(SPRING_PROFILES_ACTIVE).toString().split(",")) {
                    prop.putAll(getPropertiesByFileName(SPRING_BOOT_PROFILE_TEMPLATE.replace("{profile}", partName)));
                }
            }
            props.put(CONFIG_FILENAME, prop);
        }
        Object obj = props.get(CONFIG_FILENAME).get(key);
        if (obj == null) {
            return null;
        } else {
            return obj.toString();
        }
    }

    /**
     * 根据配置文件名称和属性key得到对应的属性值.<br>
     * 一般用于非spring boot约定的配置文件名称,比如集成其它系统的功能时,有固定名称的配置文件,或兼容旧系统<br>
     * <font color=red>注意: 暂不支持yml文件属性读取</font>
     * 
     * @param configFileName 配置文件名称
     * @param key 属性key值
     * @return
     * 
     */
    public static String getPropsValueByKey(String configFileName, String key) {
        // TODO 暂时不支持读取yml格式文件,yml文件支持map和list格式数据,需要另写方法支持
        if (!props.containsKey(configFileName)) {
            props.put(configFileName, loadPropFromFile(configFileName));
        }
        return props.get(configFileName).getProperty(key);
    }

    /**
     * 根据文件名称获取Properties
     * 
     * @param fileName 文件名
     * @return
     */
    private static Properties getPropertiesByFileName(String fileName) {
        String fileFullName = fileName + DEFAULT_SUFFIX;
        InputStream inputStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileFullName);

        if (inputStream == null) {
            fileFullName = fileName + YML_SUFFIX;
            // 读取yml配置文件
            inputStream = ConfigUtil.class.getClassLoader().getResourceAsStream(fileFullName);
            return loadYmlFromFile(fileFullName);
        } else {
            // 读取properties文件
            return loadPropFromFile(fileFullName);
        }
    }

    public static String getBody(String bodyName,JSONObject jsonObject) {
        String body = (String) jsonObject.get(bodyName);
        String reqBody = body;
        String pattern = "\\$\\{.*?\\}";
        Pattern r = Pattern.compile(pattern);
        Matcher matcher = r.matcher(body);
        while (matcher.find()) {
            String substring = body.substring(matcher.start(), matcher.end());
            String s = getPropsValueByKey(substring.substring(2, substring.length() - 1));
            reqBody = reqBody.replace(substring, s);
        }
        return reqBody;
    }

}
作者 east
Java 12月 7,2020

Excel快速导入导出工具(仅提供excel2007以及更高版本的支持)

public class ExcelWriter {

/** 日志 */
private static Logger LOG = LoggerFactory.getLogger(ExcelWriter.class);

/** 原生HttpServletResponse对象 */
private HttpServletResponse response = null;

/**
* 用于导入excel的构造函数
*/
private ExcelWriter() {

}

/**
* 用于导出excel的构造函数 <br>
* List(Bean)格式
*
* @param clazz
* @param response
*/
private ExcelWriter(Class<?> clazz, HttpServletResponse response) {
// this.clazz == clazz;
this.response = response;
}

/**
* 用于导出excel的构造函数 <br>
* List(String[]) 格式
*
* @param response
*/
private ExcelWriter(HttpServletResponse response) {
this.response = response;
}

/**
* 用于浏览器导出excel的实例化
*
* @param clazz 实体Class对象
* @param response 原生HttpServletResponse对象
* @return ExcelUtils
*/
public static ExcelWriter exportInit(HttpServletResponse response) {
return new ExcelWriter(response);
}

/**
* 用于浏览器导出excel的实例化
*
* @param clazz 实体Class对象
* @param response 原生HttpServletResponse对象
* @return ExcelUtils
*/
public static ExcelWriter exportInit(Class<?> clazz, HttpServletResponse response) {
return new ExcelWriter(clazz, response);
}

/**
* 导出Excel,响应到浏览器下载(List<String[]>格式)
*
* @param headers 表头
* @param data 数据
* @param fileName 文件名称
* @param sheetName 工作表名
* @return
*/
public boolean writeExcel(List<String> headers, List<String[]> datas, String fileName, String sheetName) {
if (response == null) {
throw new IllegalArgumentException("请先使用exportInit(HttpServletResponse)初始化参数。");
}
long begin = System.currentTimeMillis();

if (ListUtils.isEmpty(datas)) {
LOG.error("没有检测到数据,不执行导出操作。");
return false;
}
int dataSize = datas.size();
LOG.info(String.format("即将导出excel数据 : %s条,请稍后...", dataSize));
try {
// 输出流
OutputStream outputStream = response.getOutputStream();
// 创建新的工作薄
SXSSFWorkbook wb = PoiUtils.newSXSSFWorkbook();
// 表头的样式
CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont();
// 对齐
cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
font.setBoldweight(Font.BOLDWEIGHT_NORMAL);
// 字体大小
font.setFontHeightInPoints((short) 12);
font.setFontName("宋体");
// 应用标题字体到标题样式
cellStyle.setFont(font);
// 设置单元格文本形式
DataFormat dataFormat = wb.createDataFormat();
cellStyle.setDataFormat(dataFormat.getFormat("@"));

// 表头的值
String headerValue = null;
// 单元格的值
String cellValue = null;
// 创建sheet
SXSSFSheet sheet = PoiUtils.newSXSSFSheet(wb, sheetName);
// 创建行表头
SXSSFRow headerRow = PoiUtils.newSXSSFRow(sheet, 0);
for (int i = 0, size = headers.size(); i < size; i++) {
headerValue = headers.get(i);
SXSSFCell cell = PoiUtils.newSXSSFCell(headerRow, i);
cell.setCellValue(headerValue);
cell.setCellStyle(cellStyle);
}

// 明细行数组
String[] bodys = null;
for (int i = 0; i < dataSize; i++) {
// 创建行数据
SXSSFRow bodyRow = PoiUtils.newSXSSFRow(sheet, i + 1);
bodys = datas.get(i);
for (int j = 0, len = bodys.length; j < len; j++) {
cellValue = bodys[j];
if (StringUtils.isBlank(cellValue)) {
// FIXME: 当值为""时,当前index的cell会失效,这里设置为null
cellValue = null;
}

// 创建列
SXSSFCell cell = PoiUtils.newSXSSFCell(bodyRow, j);
cell.setCellValue(cellValue);
cell.setCellType(SXSSFCell.CELL_TYPE_STRING);
}
}

writeByBrowser(response, fileName, wb, outputStream);
LOG.info(String.format("excel处理完成,共生成数据 : %s行,耗时 : %s seconds.", dataSize,
(System.currentTimeMillis() - begin) / 1000.0));
} catch (Exception e) {
LOG.error("导出excel失败 : " + e.getMessage(), e);
}
return true;
}

/**
* 响应到浏览器下载
*
* @param response
* @param fileName
* @param wb
* @param out
* @throws Exception
*/
private static void writeByBrowser(HttpServletResponse response, String fileName, SXSSFWorkbook wb,
OutputStream out) throws Exception {
// response对象不为空,响应到浏览器下载
if (response != null) {
response.setContentType(ConstantUtils.CONTENT_TYPE);
response.setCharacterEncoding("UTF-8");
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1") + ConstantUtils.XLSX_SUFFIX;
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
if (out == null) {
out = response.getOutputStream();
}
}
wb.write(out);
out.flush();
out.close();
}

/**
* 保存文件到本地
*
* @param headers 表头
* @param datas 转换好的数据
* @param filePath 路径
* @param sheetName 工作表名
* @param type 类型 0-转换成功 1-转换失败
*/
public static void saveByLocal(List<String> headers, List<String[]> datas, String filePath, int type) {
long begin = System.currentTimeMillis();

if (ListUtils.isEmpty(datas)) {
LOG.error("没有检测到数据,不执行导出操作。");
return;
}
int dataSize = datas.size();
LOG.info(String.format("即将保存excel数据 : %s条,请稍后...", dataSize));
// 输出流
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
fileOutputStream = new FileOutputStream(filePath);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
String sheetName = "";
if (type == 0) {
sheetName = PropertyUtils.getProperty("successConversion");
} else if (type == 1) {
sheetName = PropertyUtils.getProperty("failConversion");
}
// 创建新的工作薄
SXSSFWorkbook wb = PoiUtils.newSXSSFWorkbook();
// 表头的样式
CellStyle cellStyle = wb.createCellStyle();
Font font = wb.createFont();
// 对齐
cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
font.setBoldweight(Font.BOLDWEIGHT_NORMAL);
// 字体大小
font.setFontHeightInPoints((short) 12);
font.setFontName("宋体");
// 应用标题字体到标题样式
cellStyle.setFont(font);
// 设置单元格文本形式
DataFormat dataFormat = wb.createDataFormat();
cellStyle.setDataFormat(dataFormat.getFormat("@"));

// 表头的值
String headerValue = null;
// 单元格的值
String cellValue = null;
// 创建sheet
SXSSFSheet sheet = PoiUtils.newSXSSFSheet(wb, sheetName);
// 创建行表头
SXSSFRow headerRow = PoiUtils.newSXSSFRow(sheet, 0);
for (int i = 0, size = headers.size(); i < size; i++) {
headerValue = headers.get(i);
SXSSFCell cell = PoiUtils.newSXSSFCell(headerRow, i);
cell.setCellValue(headerValue);
cell.setCellStyle(cellStyle);
}

// 明细行数组
String[] bodys = null;
for (int i = 0; i < dataSize; i++) {
// 创建行数据
SXSSFRow bodyRow = PoiUtils.newSXSSFRow(sheet, i + 1);
bodys = datas.get(i);
for (int j = 0, len = bodys.length; j < len; j++) {
cellValue = bodys[j];
if (StringUtils.isBlank(cellValue)) {
// FIXME: 当值为""时,当前index的cell会失效,这里设置为null
cellValue = null;
}

// 创建列
SXSSFCell cell = PoiUtils.newSXSSFCell(bodyRow, j);
cell.setCellValue(cellValue);
cell.setCellType(SXSSFCell.CELL_TYPE_STRING);
}
}

wb.write(bufferedOutputStream);
LOG.info(String.format("excel处理完成,共生成数据 : %s行,耗时 : %s seconds.", dataSize,
(System.currentTimeMillis() - begin) / 1000.0));
} catch (Exception e) {
LOG.error("保存excel失败 : " + e.getMessage(), e);
} finally {
if (bufferedOutputStream != null) {
try {
bufferedOutputStream.close();
} catch (IOException e) {
LOG.error("文件流关闭异常");
}
}
}
}

}
作者 east
Java 12月 7,2020

GAT1400视图库没有视图库账户对接遇到的坑

没有视图库账号对接视图库,把DeviceId没有写自己的视图库账号,错误写成要对接的视图库账号,一直返回“用户名错误”。后来才知道,只要按照GAT1400标准,20位的视图库账号可以自己按照标准进行编写一个,然后让要对接的视图库厂商后台配置一下。

作者 east
Java 12月 7,2020

用AOP写的日志管理工具

 使用AOP,将日志记录,异常报告等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。 
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;

@Component
@Aspect
public class LogManageUtil {
private static Logger logger = LoggerFactory.getLogger(LogManageUtil.class);
private static final String serverName = "cloudsearch";
private static final Integer showRows = 5;

@Pointcut("execution(* com.funny.services.web..*.*(..))")
public void controllerLogProxy() {

}

@Before("controllerLogProxy()")
public void beforeLogInfo(JoinPoint joinPoint) {
Object[] params = joinPoint.getArgs();
String paramStr = "";
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if (i == 0){
logger.info(param.getClass().getSimpleName());
if(param.getClass().getSimpleName().equals("SessionRepositoryRequestWrapper")) {
paramStr = "该接口无参数";
}else{
paramStr += JSONObject.toJSONString(param);
}
}

else
paramStr += "," + JSONObject.toJSONString(param);
}
logger.info("service:[" + serverName + "] -- API:[" + getApiUrl() + "] 请求参数:" + paramStr);
}

@AfterReturning(pointcut = "controllerLogProxy()", returning = "result")
public void afterLogInfo(Object result) {
if (result instanceof ResultData) {
ResultData tmpRs = (ResultData) result;
ResultData rs = new ResultData();
BeanUtils.copyProperties(tmpRs, rs);
if (rs.getCode()==ResultStatus.SUCCESS_CODE) {
if (rs.getData() instanceof List) {
List<Object> list = (List) rs.getData();
List<Object> tmpList = new ArrayList<>();
if (list != null && (list.size() > showRows)) {
for (int i = 0; i < showRows; i++) {
tmpList.add(list.get(i));
}
Object more = "more...";
tmpList.add(more);
rs.setData(tmpList);
}
}
}
logger.info("service:[" + serverName + "] -- API:[" + getApiUrl() + "] 返回结果:" + JSONObject.toJSONString(rs));
}
}

public static String getApiUrl() {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
String url = request.getRequestURL().toString();
int startIndex = url.indexOf(serverName);
String ApiUrl = url.substring(startIndex + serverName.length(), url.length());
return ApiUrl;
}

public static void serviceErrorPrint(Exception e) {
logger.error("service:[" + serverName + "] -- API:[" + getApiUrl() + "] 错误信息:" + e.getMessage());
}


}
作者 east
Java 11月 17,2020

GAT1400的注册流程RFC2617认证

此图像的alt属性为空;文件名为image.png


Authorization 请求头字段

  • response: 客户端根据算法算出的摘要值
  • username: 要认证的用户名
  • realm: 认证域,可取任意标识值
  • uri: 请求的资源位置
  • qop: 保护质量
  • nonce: 服务器密码随机数
  • nc: 16进制请求认证计数器,第一次 00000001
  • algorithm: 默认MD5算法
  • cnonce: 客户端密码随机数

Request-Digest 摘要计算过程

若算法是:MD5 或者是未指定
则 A1= <username>:<realm>:<passwd>

若 qop 未定义或者 auth:
则 A2= <request-method>:<digest-uri-value>

若 qop 为 auth
      response=MD5(MD5(A1):<nonce>:<nc>:<cnonce>:<qop>:MD5(A2)) 
若 qop 没有定义
      response=MD5(MD5(A1):<nonce>:MD5(A2)) 
package com.finest.rfc2617;


import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.Validate;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Random;

/**
 * Http Digest
 * @author zhouzhixiang
 * @date 2019-05-14
 */
public class Digests {

    private static SecureRandom random = new SecureRandom();
    /**
     * 加密遵循RFC2671规范 将相关参数加密生成一个MD5字符串,并返回
     */
    public static String http_da_calc_HA1(String username, String realm, String password,
                                          String nonce, String nc, String cnonce, String qop,
                                          String method, String uri, String algorithm) {
        String HA1, HA2;
        if ("MD5-sess".equals(algorithm)) {
            HA1 = HA1_MD5_sess(username, realm, password, nonce, cnonce);
        } else {
            HA1 = HA1_MD5(username, realm, password);
        }
        byte[] md5Byte = md5(HA1.getBytes());
        HA1 = new String(Hex.encodeHex(md5Byte));

        md5Byte = md5(HA2(method, uri).getBytes());
        HA2 = new String(Hex.encodeHex(md5Byte));

        String original = HA1 + ":" + (nonce + ":" + nc + ":" + cnonce + ":" + qop) + ":" + HA2;

        md5Byte = md5(original.getBytes());
        return new String(Hex.encodeHex(md5Byte));

    }

    /**
     * algorithm值为MD5时规则
     */
    private static String HA1_MD5(String username, String realm, String password) {
        return username + ":" + realm + ":" + password;
    }

    /**
     * algorithm值为MD5-sess时规则
     */
    private static String HA1_MD5_sess(String username, String realm, String password, String nonce, String cnonce) {
        //      MD5(username:realm:password):nonce:cnonce

        String s = HA1_MD5(username, realm, password);
        byte[] md5Byte = md5(s.getBytes());
        String smd5 = new String(Hex.encodeHex(md5Byte));

        return smd5 + ":" + nonce + ":" + cnonce;
    }

    private static String HA2(String method, String uri) {
        return method + ":" + uri;
    }

    /**
     * 对输入字符串进行md5散列.
     */
    public static byte[] md5(byte[] input) {
        return digest(input, "MD5", null, 1);
    }

    /**
     * 对字符串进行散列, 支持md5与sha1算法.
     */
    private static byte[] digest(byte[] input, String algorithm, byte[] salt, int iterations) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);

            if (salt != null) {
                digest.update(salt);
            }

            byte[] result = digest.digest(input);

            for (int i = 1; i < iterations; i++) {
                digest.reset();
                result = digest.digest(result);
            }
            return result;
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 随机生成numBytes长度数组
     * @param numBytes
     * @return
     */
    public static byte[] generateSalt(int numBytes) {
        Validate.isTrue(numBytes > 0, "numBytes argument must be a positive integer (1 or larger)", (long)numBytes);
        byte[] bytes = new byte[numBytes];
        random.nextBytes(bytes);
        return bytes;
    }

    @Deprecated
    public static String generateSalt2(int length) {
        String val = "";
        Random random = new Random();
        //参数length,表示生成几位随机数
        for(int i = 0; i < length; i++) {
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            //输出字母还是数字
            if( "char".equalsIgnoreCase(charOrNum) ) {
                //输出是大写字母还是小写字母
                int temp = random.nextInt(2)%2 == 0 ? 65 : 97;
                val += (char)(random.nextInt(26) + temp);
            } else if( "num".equalsIgnoreCase(charOrNum) ) {
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val.toLowerCase();
    }


    //测试
    public static void main(String[] args) throws UnsupportedEncodingException {
        // String s = http_da_calc_HA1("povodo", "realm@easycwmp", "povodo",
        //                             "c10c9897f05a9aee2e2c5fdebf03bb5b0001b1ef", "00000001", "d5324153548c43d8", "auth",
        //                             "GET", "/", "MD5");
        // System.out.println("加密后response为:" + s);

        // String s = new String(generateSalt(8),"UTF-8");

        // System.out.println(s);
    }
}

package com.finest.rfc2617;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**

  • Http Digest Request contains POST、GET、PUT
  • @author zhouzhixiang
  • @date 2019-05-14
    */
    public class HttpRequestUtils { private static final Logger logger = LoggerFactory.getLogger(HttpRequestUtils.class); public static void main(String[] args) {
    // String url = “http://192.168.200.117:8087/v2/servers/defaultServer/vhosts/defaultVHost/applications/live/publishers”;
    // String url = “http://192.168.200.117:8087/v2/servers/defaultServer/vhosts/defaultVHost/applications/Relay/streamfiles/1234566/actions/connect?&vhost=defaultVHost&appType=live&appName=Relay&appInstance=definst&connectAppName=Relay&connectAppInstance=definst&streamFile=1234566.stream&mediaCasterType=liverepeater”;
    String param = “”;
    String username = “xxxxxx”;
    String password = “xxxxxx”;
    // String json = “{ \”password\”: \”plmo13579123\”, \”publisherName\”: \”4\”, \”serverName\”: \”defaultServer\”, \”description\”: \”\”, \”saveFieldList\”: [ \”\” ], \”version\”: \”v1.0\” }”;
    // String s = sendPost(url, param, username, password, json); // String s = sendPost(url, param, username, password, json); // -----------------GET-success------------------ String getUrl = "http://192.168.200.117:8087/v2/servers/_defaultServer_/vhosts/_defaultVHost_/applications"; // String s = sendGet(getUrl, param, username, password, null); // -----------------GET-success------------------ // -----------------PUT-success------------------ String putUrl = "http://192.168.200.117:8087/v2/servers/_defaultServer_/vhosts/_defaultVHost_/applications/Relay/streamfiles/6D07D7E7623B95889C33DC5901307461_0/actions/connect"; String putJson = "{ \"vhost\":\"_defaultVHost_\", \"mediaCasterType\":\"liverepeater\" }"; // String s = sendPUT(putUrl, param, username, password, putJson, null); // -----------------PUT-success------------------ // -----------------POST-success------------------ String postUrl = "http://192.168.200.117:8087/v2/servers/_defaultServer_/users"; String postJson = "{ \"password\": \"123456\", \"serverName\": \"_defaultServer_\", \"description\": \"\", \"groups\": [ \"\" ], \"saveFieldList\": [ \"\" ], \"userName\": \"test6\", \"version\": \"v1.0\" }"; // String s = sendPost(postUrl, param, username, password, postJson, null); // -----------------POST-success------------------ // -----------------POST-success------------------ String postUrl2 = "http://192.168.200.117:8087/v2/servers/_defaultServer_/publishers"; String postJson2 = "{ \"password\": \"1579655633@qq.com\", \"name\": \"test11\", \"serverName\": \"_defaultServer_\", \"description\": \"test\", \"saveFieldList\": [ \"\" ], \"version\": \"v1.0\" }"; // String s = sendPost(postUrl2, param, username, password, postJson2, null); // -----------------POST-success------------------ // -----------------DELETE-success------------------ String deleteUrl = "http://192.168.200.117:8087/v2/servers/_defaultServer_/users/test5"; // String deleteJson = "{ \"password\": \"1579655633@qq.com\", \"name\": \"test11\", \"serverName\": \"_defaultServer_\", \"description\": \"test\", \"saveFieldList\": [ \"\" ], \"version\": \"v1.0\" }"; String s = sendDelete(deleteUrl, param, username, password, null, null); // -----------------DELETE-success------------------ System.out.println(s); } static int nc = 0; //调用次数
    private static final String GET = “GET”;
    private static final String POST = “POST”;
    private static final String PUT = “PUT”;
    private static final String DELETE = “DELETE”; /**
    • 向指定URL发送DELETE方法的请求
    • @param url 发送请求的URL
    • @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    • @param username 验证所需的用户名
    • @param password 验证所需的密码
    • @param json 请求json字符串
    • @param type 返回xml和json格式数据,默认xml,传入json返回json数据
    • @return URL 所代表远程资源的响应结果
      */
      public static String sendDelete(String url, String param, String username, String password, String json, String type) { StringBuilder result = new StringBuilder();
      BufferedReader in = null;
      try {
      String wwwAuth = sendGet(url, param); //发起一次授权请求
      if (wwwAuth.startsWith(“WWW-Authenticate:”)) {
      wwwAuth = wwwAuth.replaceFirst(“WWW-Authenticate:”, “”);
      } else {
      return wwwAuth;
      }
      nc ++;
      String urlNameString = url + (StringUtils.isNotEmpty(param) ? “?” + param : “”);
      URL realUrl = new URL(urlNameString);
      // 打开和URL之间的连接
      HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection(); // 设置是否向connection输出,因为这个是post请求,参数要放在 // http正文内,因此需要设为true connection.setDoOutput(true); // Read from the connection. Defaultis true. connection.setDoInput(true); // 默认是 GET方式 connection.setRequestMethod(DELETE); // 设置通用的请求属性 setRequestProperty(connection, wwwAuth, realUrl, username, password, DELETE, type); if (!StringUtils.isEmpty(json)) { byte[] writebytes =json.getBytes(); connection.setRequestProperty("Content-Length",String.valueOf(writebytes.length)); OutputStream outwritestream = connection.getOutputStream(); outwritestream.write(json.getBytes()); outwritestream.flush(); outwritestream.close(); } if (connection.getResponseCode() == 200) { in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result.append(line); } } else { String errResult = formatResultInfo(connection, type); logger.info(errResult); return errResult; } nc = 0; } catch (Exception e) {
      nc = 0;
      throw new RuntimeException(e);
      } finally {
      try {
      if (in != null) in.close();
      } catch (Exception e2) {
      e2.printStackTrace();
      }
      }
      return result.toString();
      }
    /**
    • 向指定URL发送PUT方法的请求
    • @param url 发送请求的URL
    • @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    • @param username 验证所需的用户名
    • @param password 验证所需的密码
    • @param json 请求json字符串
    • @param type 返回xml和json格式数据,默认xml,传入json返回json数据
    • @return URL 所代表远程资源的响应结果
      */
      public static String sendPUT(String url, String param, String username, String password, String json, String type) { StringBuilder result = new StringBuilder();
      BufferedReader in = null;
      try {
      String wwwAuth = sendGet(url, param); //发起一次授权请求
      if (wwwAuth.startsWith(“WWW-Authenticate:”)) {
      wwwAuth = wwwAuth.replaceFirst(“WWW-Authenticate:”, “”);
      } else {
      return wwwAuth;
      }
      nc ++;
      String urlNameString = url + (StringUtils.isNotEmpty(param) ? “?” + param : “”);
      URL realUrl = new URL(urlNameString);
      // 打开和URL之间的连接
      HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection(); // 设置是否向connection输出,因为这个是post请求,参数要放在 // http正文内,因此需要设为true connection.setDoOutput(true); // Read from the connection. Defaultis true. connection.setDoInput(true); // 默认是 GET方式 connection.setRequestMethod(PUT); // Post 请求不能使用缓存 connection.setUseCaches(false); // 设置通用的请求属性 setRequestProperty(connection, wwwAuth,realUrl, username, password, PUT, type); if (!StringUtils.isEmpty(json)) { byte[] writebytes =json.getBytes(); connection.setRequestProperty("Content-Length",String.valueOf(writebytes.length)); OutputStream outwritestream = connection.getOutputStream(); outwritestream.write(json.getBytes()); outwritestream.flush(); outwritestream.close(); } if (connection.getResponseCode() == 200) { in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result.append(line); } } else { String errResult = formatResultInfo(connection, type); logger.info(errResult); return errResult; } nc = 0; } catch (Exception e) {
      nc = 0;
      throw new RuntimeException(e);
      } finally {
      try {
      if (in != null) in.close();
      } catch (Exception e2) {
      e2.printStackTrace();
      }
      }
      return result.toString();
      }
    /**
    • 向指定URL发送POST方法的请求
    • @param url 发送请求的URL
    • @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    • @param username 验证所需的用户名
    • @param password 验证所需的密码
    • @param json 请求json字符串
    • @param type 返回xml和json格式数据,默认xml,传入json返回json数据
    • @return URL 所代表远程资源的响应结果
      */
      public static String sendPost(String url, String param, String username, String password, String json, String type) { StringBuilder result = new StringBuilder();
      BufferedReader in = null;
      try {
      String wwwAuth = sendGet(url, param); //发起一次授权请求
      if (wwwAuth.startsWith(“WWW-Authenticate:”)) {
      wwwAuth = wwwAuth.replaceFirst(“WWW-Authenticate:”, “”);
      } else {
      return wwwAuth;
      }
      nc ++;
      String urlNameString = url + (StringUtils.isNotEmpty(param) ? “?” + param : “”);
      URL realUrl = new URL(urlNameString);
      // 打开和URL之间的连接
      HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection(); // 设置是否向connection输出,因为这个是post请求,参数要放在 // http正文内,因此需要设为true connection.setDoOutput(true); // Read from the connection. Defaultis true. connection.setDoInput(true); // 默认是 GET方式 connection.setRequestMethod(POST); // Post 请求不能使用缓存 connection.setUseCaches(false); // 设置通用的请求属性 setRequestProperty(connection, wwwAuth,realUrl, username, password, POST, type); if (!StringUtils.isEmpty(json)) { byte[] writebytes =json.getBytes(); connection.setRequestProperty("Content-Length",String.valueOf(writebytes.length)); OutputStream outwritestream = connection.getOutputStream(); outwritestream.write(json.getBytes()); outwritestream.flush(); outwritestream.close(); } if (connection.getResponseCode() == 200 || connection.getResponseCode() == 201) { in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result.append(line); } } else { String errResult = formatResultInfo(connection, type); logger.info(errResult); return errResult; } nc = 0; } catch (Exception e) {
      nc = 0;
      throw new RuntimeException(e);
      } finally {
      try {
      if (in != null) in.close();
      } catch (Exception e2) {
      e2.printStackTrace();
      }
      }
      return result.toString();
      }
    /**
    • 向指定URL发送GET方法的请求
    • @param url 发送请求的URL
    • @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    • @param username 验证所需的用户名
    • @param password 验证所需的密码
    • @param type 返回xml和json格式数据,默认xml,传入json返回json数据
    • @return URL 所代表远程资源的响应结果
      */
      public static String sendGet(String url, String param, String username, String password, String type) { StringBuilder result = new StringBuilder();
      BufferedReader in = null;
      try {
      String wwwAuth = sendGet(url, param); //发起一次授权请求
      if (wwwAuth.startsWith(“WWW-Authenticate:”)) {
      wwwAuth = wwwAuth.replaceFirst(“WWW-Authenticate:”, “”);
      } else {
      return wwwAuth;
      }
      nc ++;
      String urlNameString = url + (StringUtils.isNotEmpty(param) ? “?” + param : “”);
      URL realUrl = new URL(urlNameString);
      // 打开和URL之间的连接
      HttpURLConnection connection = (HttpURLConnection)realUrl.openConnection();
      // 设置通用的请求属性
      setRequestProperty(connection, wwwAuth,realUrl, username, password, GET, type);
      // 建立实际的连接
      // connection.connect();
      in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
      String line;
      while ((line = in.readLine()) != null) {
      result.append(line);
      }
      nc = 0;
      } catch (Exception e) {
      nc = 0;
      throw new RuntimeException(e);
      } finally {
      try {
      if (in != null) in.close();
      } catch (Exception e2) {
      e2.printStackTrace();
      }
      }
      return result.toString();
      }
    /**
    • 生成授权信息
    • @param authorization 上一次调用返回401的WWW-Authenticate数据
    • @param username 用户名
    • @param password 密码
    • @return 授权后的数据, 应放在http头的Authorization里
    • @throws IOException 异常
      */
      private static String getAuthorization(String authorization, String uri, String username, String password, String method) throws IOException { uri = StringUtils.isEmpty(uri) ? “/” : uri;
      // String temp = authorization.replaceFirst(“Digest”, “”).trim();
      String temp = authorization.replaceFirst(“Digest”, “”).trim().replace(“MD5″,”\”MD5\””);
      // String json = “{\”” + temp.replaceAll(“=”, “\”:”).replaceAll(“,”, “,\””) + “}”;
      String json = withdrawJson(authorization);
      // String json = “{ \”realm\”: \”Wowza\”, \” domain\”: \”/\”, \” nonce\”: \”MTU1NzgxMTU1NzQ4MDo2NzI3MWYxZTZkYjBiMjQ2ZGRjYTQ3ZjNiOTM2YjJjZA==\”, \” algorithm\”: \”MD5\”, \” qop\”: \”auth\” }”; JSONObject jsonObject = JSON.parseObject(json);
      // String cnonce = new String(Hex.encodeHex(Digests.generateSalt(8))); //客户端随机数
      String cnonce = Digests.generateSalt2(8);
      String ncstr = (“00000000” + nc).substring(Integer.toString(nc).length()); //认证的次数,第一次是1,第二次是2…
      // String algorithm = jsonObject.getString(“algorithm”);
      String algorithm = jsonObject.getString(“algorithm”);
      String qop = jsonObject.getString(“qop”);
      String nonce = jsonObject.getString(“nonce”);
      String realm = jsonObject.getString(“realm”); String response = Digests.http_da_calc_HA1(username, realm, password,
      nonce, ncstr, cnonce, qop,
      method, uri, algorithm); //组成响应authorization
      authorization = “Digest username=\”” + username + “\”,” + temp;
      authorization += “,uri=\”” + uri
      + “\”,nc=\”” + ncstr
      + “\”,cnonce=\”” + cnonce
      + “\”,response=\”” + response+”\””;
      return authorization;
      }
    /**
    • 将返回的Authrization信息转成json
    • @param authorization authorization info
    • @return 返回authrization json格式数据 如:String json = “{ \”realm\”: \”Wowza\”, \” domain\”: \”/\”, \” nonce\”: \”MTU1NzgxMTU1NzQ4MDo2NzI3MWYxZTZkYjBiMjQ2ZGRjYTQ3ZjNiOTM2YjJjZA==\”, \” algorithm\”: \”MD5\”, \” qop\”: \”auth\” }”;
      */
      private static String withdrawJson(String authorization) {
      String temp = authorization.replaceFirst(“Digest”, “”).trim().replaceAll(“\””,””);
      // String noncetemp = temp.substring(temp.indexOf(“nonce=”), temp.indexOf(“uri=”));
      // String json = “{\”” + temp.replaceAll(“=”, “\”:”).replaceAll(“,”, “,\””) + “}”;
      String[] split = temp.split(“,”);
      Map map = new HashMap<>();
      Arrays.asList(split).forEach(c -> {
      String c1 = c.replaceFirst(“=”,”:”);
      String[] split1 = c1.split(“:”);
      map.put(split1[0].trim(), split1[1].trim());
      });
      return JSONObject.toJSONString(map);
      }
    /**
    • 向指定URL发送GET方法的请求
    • @param url 发送请求的URL
    • @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
    • @return URL 所代表远程资源的响应结果
      */
      public static String sendGet(String url, String param) {
      StringBuilder result = new StringBuilder();
      BufferedReader in = null;
      try { String urlNameString = url + (StringUtils.isNotEmpty(param) ? "?" + param : ""); URL realUrl = new URL(urlNameString); // 打开和URL之间的连接 URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.connect(); //返回401时需再次用用户名和密码请求 //此情况返回服务器的 WWW-Authenticate 信息 if (((HttpURLConnection) connection).getResponseCode() == 401) { Map<String, List<String>> map = connection.getHeaderFields(); return "WWW-Authenticate:" + map.get("WWW-Authenticate").get(0); } in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result.append(line); } } catch (Exception e) {
      throw new RuntimeException(“get请求发送失败”,e);
      }
      // 使用finally块来关闭输入流
      finally {
      try {
      if (in != null) in.close();
      } catch (Exception e2) {
      e2.printStackTrace();
      }
      }
      return result.toString();
      }
    /**
    • HTTP set request property
      *
    • @param connection HttpConnection
    • @param wwwAuth 授权auth
    • @param realUrl 实际url
    • @param username 验证所需的用户名
    • @param password 验证所需的密码
    • @param method 请求方式
    • @param type 返回xml和json格式数据,默认xml,传入json返回json数据
      */
      private static void setRequestProperty(HttpURLConnection connection, String wwwAuth, URL realUrl, String username, String password, String method, String type)
      throws IOException { if (type != null && type.equals(“json”)) {
      // 返回json
      connection.setRequestProperty(“accept”, “application/json;charset=UTF-8”);
      connection.setRequestProperty(“Content-Type”,”application/json;charset=UTF-8″);
      connection.setRequestProperty(“connection”, “Keep-Alive”);
      connection.setRequestProperty(“user-agent”,
      “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)”);
      } else {
      // 返回xml
      if (!method.equals(GET)) {
      connection.setRequestProperty(“Content-Type”,”application/json;charset=UTF-8″);
      }
      connection.setRequestProperty(“accept”, “/“);
      connection.setRequestProperty(“connection”, “Keep-Alive”);
      // connection.setRequestProperty(“Cache-Control”, “no-cache”);
      connection.setRequestProperty(“user-agent”,
      “Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)”); }
      //授权信息
      String authentication = getAuthorization(wwwAuth, realUrl.getPath(), username, password, method);
      connection.setRequestProperty(“Authorization”, authentication);
      }
    /**
    • 格式化请求返回信息,支持json和xml格式
    • @param connection HttpConnection
    • @param type 指定返回数据格式,json、xml,默认xml
    • @return 返回数据
      */
      private static String formatResultInfo(HttpURLConnection connection, String type) throws IOException {
      String result = “”;
      if (type != null && type.equals(“json”)) {
      result = String.format(“{\”errCode\”:%s, \”message\”:%s}”,connection.getResponseCode(),connection.getResponseMessage());
      } else {
      result = String.format(” “
      + ” ” + ” %d” + ” %s” + ” “,connection.getResponseCode(),connection.getResponseMessage());
      }
      return result;
      }

}

作者 east
Java 11月 8,2020

GAT1400人脸相关接口

人脸相关接口

批量人脸新增

1.接口概览

URI /VIID/Faces
方法 查询字符串 消息体 返回结果
POST 无 <FaceList> <ResponseStatusList>
备注  

2.消息体特征参数

消息体结构参考C.9,字段定义参考A.9 。

3.返回消息

         结构参考C.25,字段定义参考A.26。

4.示例

URI /VIID/ Faces
请求方法 POST
请求头 参见请求参数
请求体 {     “FaceListObject”: {         “FaceObject”: [             {                 “FaceID”: “650100000011900000010220171219100515999830656599”,                 “InfoKind”: 1,                 “SourceID”: “66000000001190123456022017120110101000007”,                 “DeviceID”: “55000111221190000007”,                 “LeftTopX”: 1,                 “LeftTopY”: 1,                 “RightBtmX”: 1,                 “RightBtmY”: 1,                 “LocationMarkTime”: “19981230010000”,                 “FaceAppearTime”: “19981230010000”,                 “FaceDisAppearTime”: “19981230010000”,                 “IDType”: “111”,                 “IDNumber”: “1”,                 “Name”: “大华”,                 “UsedName”: “dahua”,                 “Alias”: “dahua”,                 “GenderCode”: “1”,                 “AgeUpLimit”: 10,                 “AgeLowerLimit”: 20,                 “EthicCode”: “01”,                 “NationalityCode”: “CHN”,                 “NativeCityCode”: “330108”,                 “ResidenceAdminDivision”: “330100”,                 “ChineseAccentCode”: “1”,                 “JobCategory”: “1”,                 “AccompanyNumber”: 1,                 “SkinColor”: “1”,                 “HairStyle”: “1”,                 “HairColor”: “1”,                 “FaceStyle”: “1”,                 “FacialFeature”: “1”,                 “PhysicalFeature”: “1”,                 “RespiratorColor”: “1”,                 “CapStyle”: “1”,                 “CapColor”: “1”,                 “GlassStyle”: “1”,                 “GlassColor”: “1”,                 “IsDriver”: 1,                 “IsForeigner”: 1,                 “PassportType”: “1”,                 “ImmigrantTypeCode”: “1”,                 “IsSuspectedTerrorist”: 1,                 “SuspectedTerroristNumber”: “1”,                 “IsCriminalInvolved”: 1,                 “CriminalInvolvedSpecilisationCode”: “1”,                 “BodySpeciallMark”: “1”,                 “CrimeMethod”: “1”,                 “CrimeCharacterCode”: “111”,                 “EscapedCriminalNumber”: “11111111111111111111111”,                 “IsDetainees”: 1,                 “DetentionHouseCode”: “111111111”,                 “DetaineesIdentity”: “1”,                 “DetaineesSpecialIdentity”: “1”,                 “MemberTypeCode”: “1”,                 “IsVictim”: 1,                 “VictimType”: “1”,                 “InjuredDegree”: “1”,                 “CorpseConditionCode”: “1”,                 “IsSuspiciousPerson”: 1,                 “Attitude”: 1,                 “Similaritydegree”: 1,                 “EyebrowStyle”: “1”,                 “NoseStyle”: “1”,                 “MustacheStyle”: “1”,                 “LipStyle”: “1”,                 “WrinklePouch”: “1”,                 “AcneStain”: “1”,                 “FreckleBirthmark”: “1”,                 “ScarDimple”: “1”,                 “OtherFeature”: “1”,                 “SubImageList”: {                     “SubImageInfoObject”: [                         {                             “ImageID”: “33020300001190000001022017122111111100001”,                             “EventSort”: 11,                             “DeviceID”: “33070299011190000253”,                             “StoragePath”: “http://10.33.6.108:9080/testx_108_20170908/a2421c4fde6d4a74ac923e8470d6e7fa.jpg”,                             “Type”: “01”,                             “FileFormat”: “Jpeg”,                             “ShotTime”: “20170825032455”,                             “Width”: 437,                             “Height”: 350                         }                     ]                 }             }         ]     } }
响应体 {     “ResponseStatusListObject”: {         “ResponseStatusObject”: [             {                 “RequestURL”: “http://localhost:8080/VIID/Faces”,                 “StatusCode”: 0,                 “StatusString”: “正常”,                 “Id”: “650100000011900000010220171219100515999830656599”,                 “LocalTime”: “20171222162927”             }         ]     } }

批量人脸查询

1.接口概览

URI /VIID/Faces
方法 查询字符串 消息体 返回结果
GET Face属性键-值对 无 < FaceList>
备注  

2.查询字符串

查询指令为Face属性键-值对,特征属性定义参考A.9 。

3.返回结果

结构参考C.9,字段定义参考A.9。

4.示例

URI /VIID/ Faces
请求方法 GET
请求头 参见请求参数
查询参数 ?FaceID =650100000011900000010220171219100515999830656599 &InfoKind=1 &IDType=111 &LocationMarkTime=19981230010000…
响应体 {     “FaceListObject”: {         “FaceObject”: [             {                 “FaceID”: “650100000011900000010220171219100515999830656489”,                 “InfoKind”: 1,                 “SourceID”: “66000000001190123456022017120110101000007”,                 “DeviceID”: “55000111221190000007”,                 “LeftTopX”: 1,                 “LeftTopY”: 1,                 “RightBtmX”: 1,                 “RightBtmY”: 1,                 “LocationMarkTime”: “19981230010000”,                 “FaceAppearTime”: “19981230010000”,                 “FaceDisAppearTime”: “19981230010000”,                 “IDType”: “111”,                 “IDNumber”: “1”,                 “Name”: “大华”,                 “UsedName”: “dahua”,                 “Alias”: “dahua”,                 “GenderCode”: “1”,                 “AgeUpLimit”: 10,                 “AgeLowerLimit”: 20,                 “EthicCode”: “1”,                 “NationalityCode”: “CHN”,                 “NativeCityCode”: “330108”,                 “ResidenceAdminDivision”: “330100”,                 “ChineseAccentCode”: “1”,                 “JobCategory”: “1”,                 “AccompanyNumber”: 1,                 “SkinColor”: “1”,                 “HairStyle”: “1”,                 “HairColor”: “1”,                 “FaceStyle”: “1”,                 “FacialFeature”: “1”,                 “PhysicalFeature”: “1”,                 “RespiratorColor”: “1”,                 “CapStyle”: “1”,                 “CapColor”: “1”,                 “GlassStyle”: “1”,                 “GlassColor”: “1”,                 “IsDriver”: 1,                 “IsForeigner”: 1,                 “PassportType”: “1”,                 “ImmigrantTypeCode”: “1”,                 “IsSuspectedTerrorist”: 1,                 “SuspectedTerroristNumber”: “1”,                 “IsCriminalInvolved”: 1,                 “CriminalInvolvedSpecilisationCode”: “1”,                 “BodySpeciallMark”: “1”,                 “CrimeMethod”: “1”,                 “CrimeCharacterCode”: “111”,                 “EscapedCriminalNumber”: “11111111111111111111111”,                 “IsDetainees”: 1,                 “DetentionHouseCode”: “111111111”,                 “DetaineesIdentity”: “1”,                 “DetaineesSpecialIdentity”: “1”,                 “MemberTypeCode”: “1”,                 “IsVictim”: 1,                 “VictimType”: “1”,                 “InjuredDegree”: “1”,                 “CorpseConditionCode”: “1”,                 “IsSuspiciousPerson”: 1,                 “Attitude”: 1,                 “Similaritydegree”: 1,                 “EyebrowStyle”: “1”,                 “NoseStyle”: “1”,                 “MustacheStyle”: “1”,                 “LipStyle”: “1”,                 “WrinklePouch”: “1”,                 “AcneStain”: “1”,                 “FreckleBirthmark”: “1”,                 “ScarDimple”: “1”,                 “OtherFeature”: “1”,                 “SubImageList”: {                     “SubImageInfoObject”: [                         {                             “ImageID”: “33020300001190000001022017122111111100001”,                             “EventSort”: 1,                             “DeviceID”: “33070299011190000253”,                             “StoragePath”: “http://172.26.8.236:11180/pictures//07314a17009347ab86d1d4a9b52abd1d.jpg”,                             “Type”: “11”,                             “FileFormat”: “Jpeg”,                             “ShotTime”: “20171221104550”,                             “Width”: 358,                             “Height”: 441                         }                     ]                 }             }         ]     } }

批量人脸修改

1.   接口概览

URI /VIID/Faces
方法 查询字符串 消息体 返回结果
PUT 无 <FaceList> <ResponseStatusList>
备注 消息体中FaceID必填,否则操作无效

2.消息体特征参数

消息体结构参考C.9,字段定义参考A.9 。

3.返回结果

         结构参考C.25,字段定义参考A.26。

4.示例

URI /VIID/Faces
请求方法 PUT
请求头 参见请求参数
请求体 {     “FaceListObject”: {         “FaceObject”: [             {                 “FaceID”: “650100000011900000010220171219100515999830656489”,                 “InfoKind”: 2,                 “LeftTopX”: 10,                 “LeftTopY”: 10,                 “RightBtmX”: 10,                 “RightBtmY”: 10,                 “NativeCityCode”: “330109”,                 “ResidenceAdminDivision”: “330101”,                 “ChineseAccentCode”: “2”,                 “JobCategory”: “2”,                 “AccompanyNumber”: 2,                 “SkinColor”: “2”,                 “HairStyle”: “2”,                 “HairColor”: “2”,                 “FaceStyle”: “2”,                 “FacialFeature”: “2”,                 “PhysicalFeature”: “2” …             }         ]     } }            
响应体 {     “ResponseStatusListObject”: {         “ResponseStatusObject”: [             {                 “RequestURL”: “http://localhost:8080/VIID/Faces”,                 “StatusCode”: 0,                 “StatusString”: “正常”,                 “Id”: “650100000011900000010220171219100515999830656489”,                 “LocalTime”: “20171223094319”             }         ]     } }

批量人脸删除

1.接口概览

URI /VIID/Faces
方法 请求参数 消息体 返回结果
DELETE 键为IDList,值为用英文半角分号”,”分隔的字符串 无 <ResponseStatusList>
备注  

2.请求参数

IDList=<FaceID >,< FaceID >。

3.返回结果

         结构参考C.25,字段定义参考A.26。

4.示例

URI /VIID/ Faces
请求方法 DELETE
请求头 参见请求参数
请求参数 ?IDList=650100000011900000010220171219100515999830656489,650100000011900000010220171219100515999830656490  
响应体 {     “ResponseStatusListObject”: {         “ResponseStatusObject”: [             {                 “RequestURL”: “http://localhost:8080/VIID/Faces”,                 “StatusCode”: 0,                 “StatusString”: “正常”,                 “Id”: “650100000011900000010220171219100515999830656489”,                 “LocalTime”: “20171223094319”             },             {                 “RequestURL”: “http://localhost:8080/VIID/Faces”,                 “StatusCode”: 0,                 “StatusString”: “正常”,                 “Id”: “650100000011900000010220171219100515999830656490”,                 “LocalTime”: “20171223094319”             }         ]     } }

单个人脸查询

1.接口概览

URI /VIID/Faces/<FaceID>
方法 请求参数 消息体 返回结果
GET 无 无 <Face>
备注  

2.   请求参数

无

3.返回结果

         结构参考C.9,字段定义参考A.9。

4.示例

URI /VIID/Faces/650100000011900000010220171219100515999830656489
请求方法 GET
请求头 参见请求参数
请求体 无
响应体 {     “FaceObject”: {         “FaceID”: “650100000011900000010220171219100515999830656489”,         “InfoKind”: 2,         “SourceID”: “66000000001190123456022017120110101000007”,         “DeviceID”: “55000111221190000007”,         “LeftTopX”: 10,         “LeftTopY”: 10,         “RightBtmX”: 10,         “RightBtmY”: 10,         “LocationMarkTime”: “19981230010000”,         “FaceAppearTime”: “19981230010000”,         “FaceDisAppearTime”: “19981230010000”,         “IDType”: “111”,         “IDNumber”: “1”,         “Name”: “大华”,         “UsedName”: “dahua”,         “Alias”: “dahua”,         “GenderCode”: “1”,         “AgeUpLimit”: 10,         “AgeLowerLimit”: 20,         “EthicCode”: “1”,         “NationalityCode”: “CHN”,         “NativeCityCode”: “330109”,         “ResidenceAdminDivision”: “330101”,         “ChineseAccentCode”: “2”,         “JobCategory”: “2”,         “AccompanyNumber”: 2,         “SkinColor”: “2”,         “HairStyle”: “2”,         “HairColor”: “2”,         “FaceStyle”: “2”,         “FacialFeature”: “2”,         “PhysicalFeature”: “2”,         “RespiratorColor”: “1”,         “CapStyle”: “1”,         “CapColor”: “1”,         “GlassStyle”: “1”,         “GlassColor”: “1”,         “IsDriver”: 1,         “IsForeigner”: 1,         “PassportType”: “1”,         “ImmigrantTypeCode”: “1”,         “IsSuspectedTerrorist”: 1,         “SuspectedTerroristNumber”: “1”,         “IsCriminalInvolved”: 1,         “CriminalInvolvedSpecilisationCode”: “1”,         “BodySpeciallMark”: “1”,         “CrimeMethod”: “1”,         “CrimeCharacterCode”: “111”,         “EscapedCriminalNumber”: “11111111111111111111111”,         “IsDetainees”: 1,         “DetentionHouseCode”: “111111111”,         “DetaineesIdentity”: “1”,         “DetaineesSpecialIdentity”: “1”,         “MemberTypeCode”: “1”,         “IsVictim”: 1,         “VictimType”: “1”,         “InjuredDegree”: “1”,         “CorpseConditionCode”: “1”,         “IsSuspiciousPerson”: 1,         “Attitude”: 1,         “Similaritydegree”: 1,         “EyebrowStyle”: “1”,         “NoseStyle”: “1”,         “MustacheStyle”: “1”,         “LipStyle”: “1”,         “WrinklePouch”: “1”,         “AcneStain”: “1”,         “FreckleBirthmark”: “1”,         “ScarDimple”: “1”,         “OtherFeature”: “1”,         “SubImageList”: {             “SubImageInfoObject”: [                 {                     “ImageID”: “33020300001190000001022017122111111100001”,                     “EventSort”: 4,                     “DeviceID”: “55220299011190000253”,                     “StoragePath”: “http://localhost:9080/testx_108_20170908/a2421c4fde6d4a74ac923e8470d6e7fa.jpg”,                     “Type”: “01”,                     “FileFormat”: “Jpeg”,                     “ShotTime”: “20170925032455”,                     “Width”: 437,                     “Height”: 350                 }             ]         }     } }

单个人脸修改

1.接口概览

URI /VIID/Faces/<FaceID>
方法 请求参数 消息体 返回结果
PUT  无 <Face> <ResponseStatus>
备注  

2.消息体特征参数

         结构参考C.9,字段定义参考A.9。

3.返回结果

         结构参考C.25,字段定义参考A.26。

4.示例

URI /VIID/Faces/650100000011900000010220171219100515999830656489
请求方法 PUT
请求头 参见请求参数
请求体 {     “FaceObject”: {         “FaceID”: “650100000011900000010220171219100515999830656489”,         “LeftTopX”: 10,         “LeftTopY”: 10,         “RightBtmX”: 10,         “RightBtmY”: 10 …     } }
响应体 {     “ResponseStatusObject”: {         “RequestURL”: “http://localhost:8080 /VIID/Faces/650100000011900000010220171219100515999830656589”,         “StatusCode”: 0,         “StatusString”: “正常”,         “Id”: “650100000011900000010220171219100515999830656589”,         “LocalTime”: “20171223135905”     } }

单个人脸删除

1.接口概览

URI /VIID/Faces/<FaceID>
方法 请求参数 消息体 返回结果
DELETE  无 无 <ResponseStatus>
备注  

2.请求参数

无

3.返回结果

         结构参考C.25,字段定义参考A.26。

4.示例

URI /VIID/Faces/650100000011900000010220171219100515999830656489
请求方法 DELETE
请求头 参见请求参数
请求体  
响应体 {     “ResponseStatusObject”: {         “RequestURL”: “http://localhost:8080 /VIID/Faces/650100000011900000010220171219100515999830656489”,         “StatusCode”: 0,         “StatusString”: “正常”,         “Id”: “650100000011900000010220171219100515999830656489”,         “LocalTime”: “20171223135905”     } }
作者 east

1 2 3 下一个

标签

flex布局 github mysql O2O UI控件 不含后台 交流 体育 共享经济 出行 单机类 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 旅游 日历 时钟 流量主 物流 用户系统 电商 画图 画布(canvas) 社交 签到 算命 联网 装修 解锁 评论 读书 读音 资讯 阅读 预订

官方QQ群

1群:74052405

薅羊毛交流群: 952493060

近期文章

  • android http请求带中文参数会乱码(url编码)
  • mysql主从复制
  • 修改my.ini导致启动不了服务
  • Android聊天输入框控件
  • Android直播间刷礼物动画控件
  • Android自定义交易密码框
  • Android记录文件日志工具类
  • Android常用图片操作工具类
  • Android倒计时工具类
  • Android压缩解压工具

文章归档

  • 2021年一月
  • 2020年十二月
  • 2020年十一月
  • 2020年十月
  • 2020年九月
  • 2020年八月
  • 2020年七月
  • 2020年六月
  • 2020年五月
  • 2020年四月
  • 2020年三月
  • 2020年二月
  • 2020年一月
  • 2019年七月
  • 2019年六月
  • 2019年五月
  • 2019年四月
  • 2019年三月
  • 2019年二月
  • 2019年一月
  • 2018年十二月
  • 2018年七月
  • 2018年六月

分类目录

  • Android (30)
  • bug清单 (26)
  • Fuchsia (15)
  • php (1)
  • python (2)
  • 人工智能 (1)
  • 大数据开发 (119)
    • Elasticsearch (6)
    • Flink (3)
    • Hadoop (11)
    • Hbase (8)
    • Hive (1)
    • Java (27)
    • Kafka (1)
    • solr (1)
    • Spark (42)
    • spring (8)
    • 数据仓库 (1)
    • 数据挖掘 (5)
    • 运维 (4)
  • 小游戏代码 (1)
  • 小程序代码 (111)
    • O2O (15)
    • UI控件 (3)
    • 互联网类 (17)
    • 企业类 (5)
    • 地图定位 (9)
    • 多媒体 (5)
    • 工具类 (19)
    • 电商类 (18)
    • 社交 (5)
    • 行业软件 (7)
    • 资讯读书 (7)
  • 开发博客 (5)
  • 数据库 (2)
  • 未分类 (6)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.