001// ______________________________________________________ 002// Generated by codegen - https://gitee.com/l0km/codegen 003// template: decorator/spring.controller.class.vm 004// ______________________________________________________ 005/** 006 * decorator pattern 装饰者模式代理{@link FeatureSe}接口<br> 007 * 将{@link FeatureSe}实例封装为一个spring controler<br> 008 * 计算机生成代码(generated by automated tools DecoratorGenerator @author guyadong)<br> 009 * @author guyadong 010 * 011 */ 012package net.gdface.sdk.fse; 013import java.util.ServiceLoader; 014import java.io.PrintWriter; 015import java.io.StringWriter; 016import java.util.Iterator; 017import java.util.Objects; 018 019import org.slf4j.Logger; 020import org.slf4j.LoggerFactory; 021import org.springframework.web.bind.annotation.*; 022import io.swagger.annotations.*; 023 024/** 025 * 特征码内存搜索引擎(feature search engine)接口<br> 026 * 提供高速的人脸特征相似度比对搜索/排序,支持多线程并行搜索,适用于百万级以上人脸库的快速搜索。<br> 027 * 1.使用 {@link #addFeature(byte[], byte[], String)}方法将特征添加到搜索引擎<br> 028 * 2.使用 {@link #searchCode(byte[], double, int)}在内存中搜索与指定特征相似的的特征返回搜索结果 029 * @author guyadong 030 */ 031@RestController 032@Api(value="FeatureSe",tags={"FeatureSe Controller"}) 033public class FeatureSeSpringController { 034 private static final Logger logger = LoggerFactory.getLogger(FeatureSeSpringController.class); 035 private static InstanceSupplier instanceSupplier = getInstanceSupplier(); 036 private final ResponseFactory responseFactory = loadResponseFactory(); 037 /** 038 * SPI(Service Provider Interface)机制加载 {@link InstanceSupplier}实例,没有找到则返回{@code null}, 039 * 返回{@link InstanceSupplier}提供的{@link FeatureSe}实例 040 * @return 返回{@link FeatureSe}实例 041 */ 042 private static final InstanceSupplier getInstanceSupplier() { 043 /* SPI(Service Provider Interface)机制加载 {@link InstanceSupplier}实例,没有找到则抛出异常 */ 044 ServiceLoader<InstanceSupplier> providers = ServiceLoader.load(InstanceSupplier.class); 045 Iterator<InstanceSupplier> itor = providers.iterator(); 046 return itor.hasNext() ? itor.next() : null; 047 } 048 /** 049 * @param instanceSupplier 要设置的 instanceSupplier 050 */ 051 public static void setInstanceSupplier(InstanceSupplier instanceSupplier) { 052 FeatureSeSpringController.instanceSupplier = instanceSupplier; 053 } 054 /** 055 * SPI(Service Provider Interface)加载{@link ResponseFactory}接口实例, 056 * 没有找到则返回{@link DefaultResponseFactory}实例 057 * @return 返回{@link ResponseFactory}实例 058 */ 059 private static final ResponseFactory loadResponseFactory() { 060 ServiceLoader<ResponseFactory> providers = ServiceLoader.load(ResponseFactory.class); 061 Iterator<ResponseFactory> itor = providers.iterator(); 062 return itor.hasNext() ? itor.next() : new DefaultResponseFactory(); 063 } 064 public FeatureSeSpringController() { 065 } 066 067 /** 068 * @return 返回被装饰的{@link FeatureSe}实例 069 */ 070 protected FeatureSe delegate() { 071 return Objects.requireNonNull( 072 instanceSupplier == null ? null : instanceSupplier.instanceOfFeatureSe(), 073 "FeatureSe instance is null" ); 074 } 075 // port-1 076 /** 077 * 添加一条特征码到内存表<br> 078 * @param featureId 特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID 079 * @param feature 特征码字节数组,为{@code null}时返回false 080 * @param imgMD5 特征所属图的MD5(32字节HEX字符串),可为null 081 * @return 添加成功返回true, 否则返回false 082 */ 083 @ResponseBody 084 @RequestMapping(value = "/FeatureSe/addFeatureToFse", method = RequestMethod.POST) 085 @ApiOperation(value = "添加一条特征码到内存表<br>", notes = "添加一条特征码到内存表<br>",httpMethod="POST") 086 public Response addFeature( @RequestBody AddFeatureToFseArgs args) 087 { 088 Response response = responseFactory.newFeatureSeResponse(); 089 try{ 090 response.onComplete(delegate().addFeature(args.featureId,args.feature,args.imgMD5)); 091 } 092 catch(Exception e){ 093 logger.error(e.getMessage(),e); 094 response.onError(e); 095 } 096 return response; 097 } 098 // port-2 099 /** 100 * 添加一条特征码到内存表<br> 101 * @param featureId 特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID 102 * @param feature 特征码字节数组,为{@code null}时返回false 103 * @param appid 应用id,由调用者定义,可为null 104 * @return 添加成功返回true, 否则返回false 105 */ 106 @ResponseBody 107 @RequestMapping(value = "/FeatureSe/addFeatureToFseWithAppId", method = RequestMethod.POST) 108 @ApiOperation(value = "添加一条特征码到内存表<br>", notes = "添加一条特征码到内存表<br>",httpMethod="POST") 109 public Response addFeature( @RequestBody AddFeatureToFseWithAppIdArgs args) 110 { 111 Response response = responseFactory.newFeatureSeResponse(); 112 try{ 113 response.onComplete(delegate().addFeature(args.featureId,args.feature,args.appid)); 114 } 115 catch(Exception e){ 116 logger.error(e.getMessage(),e); 117 response.onError(e); 118 } 119 return response; 120 } 121 // port-3 122 /** 123 * 删除内存表中所有特征数据 124 */ 125 @ResponseBody 126 @RequestMapping(value = "/FeatureSe/clearAllOfFse", method = RequestMethod.POST) 127 @ApiOperation(value = "删除内存表中所有特征数据", notes = "删除内存表中所有特征数据",httpMethod="POST") 128 public Response clearAll() 129 { 130 Response response = responseFactory.newFeatureSeResponse(); 131 try{ 132 delegate().clearAll(); 133 response.onComplete(); 134 } 135 catch(Exception e){ 136 logger.error(e.getMessage(),e); 137 response.onError(e); 138 } 139 return response; 140 } 141 // port-4 142 /** 143 * 根据特征码ID在表中查找指定的记录 144 * @param featureId 特征码ID,MD5校验码(16 bytes) 145 * @return 返回指定的特征记录,没有找到则返回{@code null},{@code featureId}为{@code null}或空返回{@code null} 146 */ 147 @ResponseBody 148 @RequestMapping(value = "/FeatureSe/getFeatureFromFse", method = RequestMethod.POST) 149 @ApiOperation(value = "根据特征码ID在表中查找指定的记录", notes = "根据特征码ID在表中查找指定的记录",httpMethod="POST") 150 public Response getFeature( @RequestBody GetFeatureFromFseArgs args) 151 { 152 Response response = responseFactory.newFeatureSeResponse(); 153 try{ 154 response.onComplete(delegate().getFeature(args.featureId)); 155 } 156 catch(Exception e){ 157 logger.error(e.getMessage(),e); 158 response.onError(e); 159 } 160 return response; 161 } 162 // port-5 163 /** 164 * 根据特征码ID在表中查找指定的记录 165 * @param featureId 特征码ID,MD5校验码(32字节HEX字符串) 166 * @return 返回指定的特征记录,没有找到则返回{@code null},{@code featureId}为{@code null}或空返回{@code null} 167 */ 168 @ResponseBody 169 @RequestMapping(value = "/FeatureSe/getFeatureByHexFromFse", method = RequestMethod.POST) 170 @ApiOperation(value = "根据特征码ID在表中查找指定的记录", notes = "根据特征码ID在表中查找指定的记录",httpMethod="POST") 171 public Response getFeatureByHex( @RequestBody GetFeatureByHexFromFseArgs args) 172 { 173 Response response = responseFactory.newFeatureSeResponse(); 174 try{ 175 response.onComplete(delegate().getFeatureByHex(args.featureId)); 176 } 177 catch(Exception e){ 178 logger.error(e.getMessage(),e); 179 response.onError(e); 180 } 181 return response; 182 } 183 // port-6 184 /** 185 * 根据特征码ID中表中删除指定的记录 186 * @param featureId 特征码ID,MD5校验码(16 bytes) 187 * @return 成功删除则返回true,否则返回false 188 */ 189 @ResponseBody 190 @RequestMapping(value = "/FeatureSe/removeFeatureFromFse", method = RequestMethod.POST) 191 @ApiOperation(value = "根据特征码ID中表中删除指定的记录", notes = "根据特征码ID中表中删除指定的记录",httpMethod="POST") 192 public Response removeFeature( @RequestBody RemoveFeatureFromFseArgs args) 193 { 194 Response response = responseFactory.newFeatureSeResponse(); 195 try{ 196 response.onComplete(delegate().removeFeature(args.featureId)); 197 } 198 catch(Exception e){ 199 logger.error(e.getMessage(),e); 200 response.onError(e); 201 } 202 return response; 203 } 204 // port-7 205 /** 206 * 根据特征码ID中表中删除指定的记录 207 * @param featureId 特征码ID,MD5校验码(32字节HEX字符串) 208 * @return 成功删除则返回true,否则返回false 209 */ 210 @ResponseBody 211 @RequestMapping(value = "/FeatureSe/removeFeatureByHexFromFse", method = RequestMethod.POST) 212 @ApiOperation(value = "根据特征码ID中表中删除指定的记录", notes = "根据特征码ID中表中删除指定的记录",httpMethod="POST") 213 public Response removeFeatureByHex( @RequestBody RemoveFeatureByHexFromFseArgs args) 214 { 215 Response response = responseFactory.newFeatureSeResponse(); 216 try{ 217 response.onComplete(delegate().removeFeatureByHex(args.featureId)); 218 } 219 catch(Exception e){ 220 logger.error(e.getMessage(),e); 221 response.onError(e); 222 } 223 return response; 224 } 225 // port-8 226 /** 227 * 在内存表中根据比对相似度进行特征码搜索 228 * @param code 要比对的特征码 229 * @param sim 相似度阀值 230 * @param rows 最大返回的记录数 231 * @return 返回包含相似度(降序)的结果数组,如果没有查到匹配的记录则返回空数组 232 */ 233 @ResponseBody 234 @RequestMapping(value = "/FeatureSe/searchCodeFromFse", method = RequestMethod.POST) 235 @ApiOperation(value = "在内存表中根据比对相似度进行特征码搜索", notes = "在内存表中根据比对相似度进行特征码搜索",httpMethod="POST") 236 public Response searchCode( @RequestBody SearchCodeFromFseArgs args) 237 { 238 Response response = responseFactory.newFeatureSeResponse(); 239 try{ 240 response.onComplete(delegate().searchCode(args.code,args.sim,args.rows)); 241 } 242 catch(Exception e){ 243 logger.error(e.getMessage(),e); 244 response.onError(e); 245 } 246 return response; 247 } 248 // port-9 249 /** 250 * @return 内存表中元素个数 251 */ 252 @ResponseBody 253 @RequestMapping(value = "/FeatureSe/sizeOfFse", method = RequestMethod.POST) 254 @ApiOperation(value = "", notes = "",httpMethod="POST") 255 public Response size() 256 { 257 Response response = responseFactory.newFeatureSeResponse(); 258 try{ 259 response.onComplete(delegate().size()); 260 } 261 catch(Exception e){ 262 logger.error(e.getMessage(),e); 263 response.onError(e); 264 } 265 return response; 266 } 267 /** 268 * argClass-1<br> 269 * wrap arguments for method {@link #addFeature(AddFeatureToFseArgs)} 270 */ 271 public static class AddFeatureToFseArgs{ 272 @ApiModelProperty(value ="特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID" ,required=true ,dataType="byte[]") 273 public byte[] featureId; 274 @ApiModelProperty(value ="特征码字节数组,为{@code null}时返回false" ,required=true ,dataType="byte[]") 275 public byte[] feature; 276 @ApiModelProperty(value ="特征所属图的MD5(32字节HEX字符串),可为null" ,required=true ,dataType="String") 277 public String imgMD5; 278 } 279 /** 280 * argClass-2<br> 281 * wrap arguments for method {@link #addFeature(AddFeatureToFseWithAppIdArgs)} 282 */ 283 public static class AddFeatureToFseWithAppIdArgs{ 284 @ApiModelProperty(value ="特征码ID(MD5校验码),为null时,native library会自动计算MD5作为特征码ID" ,required=true ,dataType="byte[]") 285 public byte[] featureId; 286 @ApiModelProperty(value ="特征码字节数组,为{@code null}时返回false" ,required=true ,dataType="byte[]") 287 public byte[] feature; 288 @ApiModelProperty(value ="应用id,由调用者定义,可为null" ,required=true ,dataType="long") 289 public long appid; 290 } 291 /** 292 * argClass-4<br> 293 * wrap arguments for method {@link #getFeature(GetFeatureFromFseArgs)} 294 */ 295 public static class GetFeatureFromFseArgs{ 296 @ApiModelProperty(value ="特征码ID,MD5校验码(16 bytes)" ,required=true ,dataType="byte[]") 297 public byte[] featureId; 298 } 299 /** 300 * argClass-5<br> 301 * wrap arguments for method {@link #getFeatureByHex(GetFeatureByHexFromFseArgs)} 302 */ 303 public static class GetFeatureByHexFromFseArgs{ 304 @ApiModelProperty(value ="特征码ID,MD5校验码(32字节HEX字符串)" ,required=true ,dataType="String") 305 public String featureId; 306 } 307 /** 308 * argClass-6<br> 309 * wrap arguments for method {@link #removeFeature(RemoveFeatureFromFseArgs)} 310 */ 311 public static class RemoveFeatureFromFseArgs{ 312 @ApiModelProperty(value ="特征码ID,MD5校验码(16 bytes)" ,required=true ,dataType="byte[]") 313 public byte[] featureId; 314 } 315 /** 316 * argClass-7<br> 317 * wrap arguments for method {@link #removeFeatureByHex(RemoveFeatureByHexFromFseArgs)} 318 */ 319 public static class RemoveFeatureByHexFromFseArgs{ 320 @ApiModelProperty(value ="特征码ID,MD5校验码(32字节HEX字符串)" ,required=true ,dataType="String") 321 public String featureId; 322 } 323 /** 324 * argClass-8<br> 325 * wrap arguments for method {@link #searchCode(SearchCodeFromFseArgs)} 326 */ 327 public static class SearchCodeFromFseArgs{ 328 @ApiModelProperty(value ="要比对的特征码" ,required=true ,dataType="byte[]") 329 public byte[] code; 330 @ApiModelProperty(value ="相似度阀值" ,required=true ,dataType="double") 331 public double sim; 332 @ApiModelProperty(value ="最大返回的记录数" ,required=true ,dataType="int") 333 public int rows; 334 } 335 /** 336 * 获取{@link FeatureSe}实例的接口, 337 * 用于应用层SPI方式提供{@link FeatureSe}实例 338 * @author guyadong 339 * 340 */ 341 public static interface InstanceSupplier{ 342 FeatureSe instanceOfFeatureSe(); 343 } 344 /** 345 * web响应数据接口 346 * @author guyadong 347 * 348 */ 349 public static interface Response{ 350 /** 351 * 接口方法调用成功 352 * @param result 调用返回值 353 */ 354 void onComplete(Object result); 355 /** 356 * 接口方法调用成功,调用方法返回类型为void 357 */ 358 void onComplete(); 359 /** 360 * 接口方法调用抛出异常 361 * @param e 异常 362 */ 363 void onError(Exception e); 364 } 365 /** 366 * 获取{@link Response}接口实例的工厂类接口 367 * @author guyadong 368 * 369 */ 370 public static interface ResponseFactory{ 371 /** 372 * @return 返回新的{@link Response}接口实例 373 */ 374 Response newFeatureSeResponse(); 375 } 376 /** 377 * {@link Response}默认实现 378 * @author guyadong 379 * 380 */ 381 public static class DefaultResponse implements Response{ 382 private static boolean outStrackTrace = false; 383 private boolean success; 384 /** RPC调用的返回值 */ 385 private Object result; 386 /** 异常信息 */ 387 private String errorMessage; 388 /** 异常堆栈信息 */ 389 private String stackTrace; 390 @Override 391 public void onComplete(Object result) { 392 this.success = true; 393 this.result = result; 394 } 395 @Override 396 public void onComplete() { 397 onComplete(null); 398 } 399 @Override 400 public void onError(Exception e) { 401 success = false; 402 errorMessage = e.getMessage(); 403 if(errorMessage == null){ 404 errorMessage = e.getClass().getSimpleName(); 405 } 406 if(outStrackTrace){ 407 StringWriter writer = new StringWriter(); 408 e.printStackTrace(new PrintWriter(writer)); 409 stackTrace = writer.toString(); 410 } 411 } 412 413 public boolean isSuccess() { 414 return success; 415 } 416 417 public void setSuccess(boolean success) { 418 this.success = success; 419 } 420 421 public Object getResult() { 422 return result; 423 } 424 425 public void setResult(Object result) { 426 this.result = result; 427 } 428 429 public String getErrorMessage() { 430 return errorMessage; 431 } 432 433 public void setErrorMessage(String errorMessage) { 434 this.errorMessage = errorMessage; 435 } 436 437 public String getStackTrace() { 438 return stackTrace; 439 } 440 441 public void setStackTrace(String stackTrace) { 442 this.stackTrace = stackTrace; 443 } 444 445 @Override 446 public String toString() { 447 StringBuilder builder = new StringBuilder(); 448 builder.append("DefaultResponse [success="); 449 builder.append(success); 450 builder.append(", "); 451 if (result != null) { 452 builder.append("result="); 453 builder.append(result); 454 builder.append(", "); 455 } 456 if (errorMessage != null) { 457 builder.append("errorMessage="); 458 builder.append(errorMessage); 459 builder.append(", "); 460 } 461 if (stackTrace != null) { 462 builder.append("stackTrace="); 463 builder.append(stackTrace); 464 } 465 builder.append("]"); 466 return builder.toString(); 467 } 468 /** 469 * 开启输出堆栈信息(默认为不开启)<br> 470 * 开发时为了调试需要获取详细的异常堆栈信息可以开启 471 * @param outStrackTrace 要设置的 outStrackTrace 472 */ 473 public static void enableStrackTrace() { 474 outStrackTrace = true; 475 } 476 } 477 /** 478 * {@link ResponseFactory}接口默认实现 479 * @author guyadong 480 * 481 */ 482 public static class DefaultResponseFactory implements ResponseFactory{ 483 484 @Override 485 public Response newFeatureSeResponse() { 486 return new DefaultResponse(); 487 } 488 } 489 public static String DESCRIPTION = "特征码内存搜索引擎(feature search engine)接口<br>\n" 490+" 提供高速的人脸特征相似度比对搜索/排序,支持多线程并行搜索,适用于百万级以上人脸库的快速搜索。<br>\n" 491+" 1.使用 {@link #addFeature(byte[], byte[], String)}方法将特征添加到搜索引擎<br>\n" 492+" 2.使用 {@link #searchCode(byte[], double, int)}在内存中搜索与指定特征相似的的特征返回搜索结果"; 493}