【huTool】真的好用,面对接口开发之再来一弹

小公司的悲哀,维护项目和小需求不断。。

整理一下,算作纪念

需求:第三方需要接口传输图片流到特定的摄像头下
分析:

/**
 * 开发接口:
 *  1.接收主要:图片(小图,大图),时间,设备id -> Base64(小图,大图),时间戳,设备id
 *  2.调用平台登录,全部相机接口 -> 相机集合[相机id,相机唯一标识]
 *  3.遍历相机集合根据【设备id = 唯一标识】锁定入参:[相机id,Base64(小图,大图),时间戳]
 *  4.调用入库接口,传入入参
 *  5.异常处理,数据包装返回
 */

重点:

  1. 数据格式:multipart/form-data,区别以往的application/json,text/plain请求参数格式,需要传文件啦
  2. 涉及到大数据,缓存起来,缩减以后的响应时间
  3. 日志也要好好写啦,区别以往,增加logback.xml配置文件
  4. 全局异常要继续hold住啊

好了,咱们代码里详聊~
``首先,实体类

/**
 * Created by DQ on 2020/6/23/023.
 * 请求类
 */
@Data
public class RequestDTO {
    private String faceid;
    private String deviceid;
    private String devicename;
    private String locationid;
    private String locationname;
    private String lng;
    private String lat;
    private String identification;
    private String passtime;
    private MultipartFile facepic;
    private MultipartFile backgroudpic;
    private String rect;
}
/**
 * 响应类
 */
@Data
public class BaseResponse {
    // Y  错误码 0:成功 其它:失败
    protected Integer errcode;
    // Y 错误描述
    protected String errmsg;

    public BaseResponse() {
        this(ResponseEnum.SUCCESS);
    }

    public BaseResponse(ResponseEnum errorCode) {
        this.errcode = errorCode.getRtn();
        this.errmsg = errorCode.getMessage();
    }
    public BaseResponse(ResponseEnum errorCode, String message) {
        this.errcode = errorCode.getRtn();
        this.errmsg = message;
    }

    public boolean valid() {
        return 0 == this.errcode;
    }
}
/**
 * 响应状态码枚举类
 */
public enum ResponseEnum {

    SUCCESS(0, "OK"),
    SERVER_ERROR(1, "服务器异常,请稍后重试"),
    BAD_REQUEST_PARAMETER(-1, "图片参数错误"),
    NO_MATCH_DEVICEID(-1000, "deviceid与平台无匹配"),
    BAD_REQUEST(-2, "请求错误"),
    MEDIA_TYPE_NOT_SUPPORTED(-3, "请求的Content-Type错误"),
    METHOD_NOT_SUPPORTED(-4, "请求方法不支持"),
    ;
    private Integer rtn;
    private String message;

    ResponseEnum(Integer rtn, String message) {
        this.rtn = rtn;
        this.message = message;
    }

    public Integer getRtn() {
        return rtn;
    }

    public String getMessage() {
        return message;
    }
}
/**
 * Created by DQ on 2020/6/24/024.
 * 要被缓存的类
 */
@Data
public class Camera {
    private Integer id;
    //对应摄像头的唯一标识 外部deviceid 内部police_unit
    private String police_unit;

    public Camera(Integer id, String police_unit) {
        this.id = id;
        this.police_unit = police_unit;
    }

    public Camera() {
    }
}

重头戏来咯,controller和service

/**
 * Created by DQ on 2020/6/24/024.
 */
@RestController
@RequestMapping("/img")
@Api(value = "ImgFlow", tags = {"图片流入库Controller"})
public class ImgFlow {
    private static Logger logger = LoggerFactory.getLogger(ImgFlow.class);
    @Autowired
    FlowService flowService;

    @RequestMapping(value = "/flow", method = RequestMethod.POST)
    @ApiOperation(value = "图片流入库接口")
    public BaseResponse handleFileUpload(@RequestParam(value = "deviceid") String deviceid,
                                         @RequestParam(value = "passtime") String passtime,
                                         @RequestParam(value = "facepic") MultipartFile facepic,
                                         @RequestParam(value = "backgroudpic") MultipartFile backgroudpic,
                                         @RequestParam(value = "faceid", required = false) String faceid,
                                         @RequestParam(value = "devicename", required = false) String devicename,
                                         @RequestParam(value = "locationid", required = false) String locationid,
                                         @RequestParam(value = "locationname", required = false) String locationname,
                                         @RequestParam(value = "lng", required = false) Long lng,
                                         @RequestParam(value = "lat", required = false) Long lat,
                                         @RequestParam(value = "identification", required = false) String identification,
                                         @RequestParam(value = "rect", required = false) String rect
    ) throws IOException, InterruptedException {
        logger.info("deviceid:" + deviceid);
        logger.info("passtime:" + passtime);
        String faceFilename = facepic.getOriginalFilename();
        String backFilename = backgroudpic.getOriginalFilename();
        logger.info("facepic:" + faceFilename);
        logger.info("backgroudpic:" + backFilename);
        if(StrUtil.isBlank(faceFilename) || StrUtil.isBlank(backFilename)){
            return new BaseResponse(ResponseEnum.BAD_REQUEST_PARAMETER);
        }else {
            if(faceFilename.contains(".jpg") || faceFilename.contains(".png") || faceFilename.contains(".bmp")){
                if(backFilename.contains(".jpg") || backFilename.contains(".png") || backFilename.contains(".bmp")){
                    return flowService.FlowIt(deviceid, passtime, facepic, backgroudpic);
                }
                return new BaseResponse(ResponseEnum.BAD_REQUEST_PARAMETER);
            }
            return new BaseResponse(ResponseEnum.BAD_REQUEST_PARAMETER);
        }
    }
}
/**
 * Created by DQ on 2020/6/23/023.
 */
@Service
public class FlowService {
    private static Logger logger = LoggerFactory.getLogger(FlowService.class);
    @Autowired
    HttpUtils httpUtils;

    public BaseResponse FlowIt(String deviceid, String passtime, MultipartFile facepic, MultipartFile backgroudpic) throws InterruptedException {
        BaseResponse baseResponse = new BaseResponse();

        httpUtils.loginFp();

        ArrayList<Camera> cameras = httpUtils.getCameras();
        int j = 0;
        for (Camera camera : cameras) {
            if (deviceid.equals(camera.getPolice_unit())) {
                String body = JSONUtil.createObj()
                        .set("camera_id", camera.getId())
                        .set("face_image_content_base64", toBase64(facepic))
                        .set("picture_image_content_base64", toBase64(backgroudpic))
                        .set("timestamp", toTimeStamp(passtime)).toString();
                logger.info(body);
                baseResponse = httpUtils.flowImg(body);
            } else {
                j++;
            }
        }
        if (j == cameras.size()) {
            baseResponse = new BaseResponse(ResponseEnum.NO_MATCH_DEVICEID);
        }
        return baseResponse;
    }

    private String toBase64(MultipartFile someone) {
        return Base64.encode(tarnsToFile(someone));
    }
    private long toTimeStamp(String time) {
        DateTime parse = DateUtil.parse(time);
        return parse.getTime()/1000;
    }

    /*
    * MultipartFile -> File
    * */
    private File tarnsToFile(MultipartFile multipartFile){
        File file = null;
        try {
            file=File.createTempFile("tmp", null);
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (HttpException | IOException e) {
            e.printStackTrace();
        }
        return file;
    }
}

插个话,最近在看本书,《会说话的代码》,讲的是代码的规范方面,讲到注释只是辅助工具,好的代码不需要注释。正在往这方面努力

下面是util服务

/**
 * Created by DQ on 2020/6/23/023.
 */
@Service
public class HttpUtils {
    private static Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    private static String FP_IP =  getProps("fp.ip");
    private static String FP_PORT = getProps("fp.port");
    private static String loginName = getProps("fp.loginName");
    private static String loginPwd = getProps("fp.loginPwd");
    private static String loginUrl = getProps("fp.loginUrl");
    private static String flowUrl = getProps("mts.flowUrl");
    private static String asyncUrl = getProps("fp.asyncUrl");
    private static String cameraUrl = getProps("fp.cameraUrl");
    private static String cameraCache = getProps("cameraList.cache");
    private static String name = getProps("camera-device.name");

    public static Cache<String, String> lruCache = CacheUtil.newLRUCache(3);
    public static Cache<String, ArrayList<Camera>> listCache = CacheUtil.newLRUCache(2);

    /*
    * 入库接口
    * POST
    * */
    public BaseResponse flowImg(String body) {
        BaseResponse baseResponse = new BaseResponse();
        String fpUrl = formatFpUrl(flowUrl, FP_IP, "21100");
        HttpRequest request = HttpRequest.post(fpUrl)
                .body(body)
                .timeout(10000);
        HttpResponse execute = request.execute();
        JSONObject obj = JSONUtil.parseObj(execute.body());
        Integer rtn = obj.getInt("rtn");
        if (rtn != 0) {
            baseResponse.setErrcode(rtn);
            baseResponse.setErrmsg("入库失败");
        }
        return baseResponse;
    }

    /*
    * 登录接口
    * POST
    * */
    public void loginFp() {
        if (StrUtil.isBlank(FP_IP) || StrUtil.isBlank(FP_PORT) || StrUtil.isBlank(loginName)
                || StrUtil.isBlank(loginPwd) || StrUtil.isBlank(loginUrl) || StrUtil.isBlank(flowUrl)) {
            logger.error("有配置为空!");
        }
        if(StrUtil.isBlank(lruCache.get("cookie")) || StrUtil.isBlank(lruCache.get("cluster_id"))){
            String fpUrl = formatFpUrl(loginUrl, FP_IP, FP_PORT);
            String password = DigestUtil.md5Hex(loginPwd);
            HttpRequest req = HttpRequest.post(fpUrl)
                    .header("Content-Type", "application/json;charset=UTF-8")
                    .body(JSONUtil.createObj()
                            .set("name", loginName)
                            .set("password", password)
                            .toString())
                    .timeout(5000);
            HttpResponse execute = req.execute();
            JSONObject resp = JSONUtil.parseObj(execute.body());
            if (resp.getInt("rtn") == 0) {
                String session_id = resp.getStr("session_id");
                String cluster_id = session_id.substring(session_id.indexOf("@") + 1);
                String cookie = "session_id=" + session_id;
                //默认保存3分钟
                lruCache.put("cookie", cookie, 60 * 3 * 1000L);
                lruCache.put("cluster_id", cluster_id, 60 * 3 * 1000L);
            }
        }
    }

    /*
    * post获取result_id,并get获取到cameras
    * */
    public ArrayList<Camera> getCameras() throws InterruptedException {
        if(!listCache.containsKey("camera") || listCache.get("camera").isEmpty()){
            String fpUrl = formatFpUrl(asyncUrl, FP_IP, FP_PORT);
            ArrayList<Camera> list = new ArrayList<>();

            String cookie = lruCache.get("cookie");
            String cluster_id = lruCache.get("cluster_id");

            String resultId = postResultId(cookie, cluster_id, fpUrl);

            String url = fpUrl + "?result_id=" + resultId;

            String camerabody = getCamera(url, cookie);

            JSONObject parseObj = JSONUtil.parseObj(camerabody);

            JSONArray cluster_results = parseObj.getJSONArray("cluster_results");
            if (!cluster_results.isEmpty()) {
                JSONObject results = cluster_results.getJSONObject(0).getJSONObject("results");
                JSONArray cameras = results.getJSONArray("cameras");
                for (int i = 0; i < cameras.size(); i++) {
                    Camera camera = new Camera();
                    String POLICY_CODE;
                    JSONObject camerai = cameras.getJSONObject(i);
                    Integer id = camerai.getInt("id");
                    if(camerai.containsKey(name)){
                        POLICY_CODE= camerai.getStr(name);
                    }else {
                        POLICY_CODE = camerai.getJSONObject("meta").getStr(name);
                    }
                    camera.setId(id);
                    camera.setPolice_unit(POLICY_CODE);
                    list.add(camera);
                }
            }
            //默认缓存12小时
            listCache.put("camera", list, 60 * 60 * 12 * 1000L);
            return list;
        }
        logger.info(listCache.get("camera").toString());
        return listCache.get("camera");

    }

    private String postResultId(String cookie, String cluster_id, String fpUrl) {
        JSONObject request = JSONUtil.createObj()
                .set("cluster_id", cluster_id)
                .set("method", "GET")
                .set("payload", JSONUtil.createObj()
                        .set("clusterId", cluster_id))
                .set("url", "/website/face/camera-device");

        JSONArray requests = JSONUtil.createArray().put(request);

        String body = JSONUtil.createObj()
                .set("requests", requests)
                .toString();

        System.out.println(body);
        HttpRequest req = HttpRequest.post(fpUrl)
                .header("Content-Type", "application/json;charset=UTF-8")
                .header("Cookie", cookie)
                .body(body)
                .timeout(10000);
        HttpResponse execute = req.execute();
        JSONObject parseObj = JSONUtil.parseObj(execute.body());
        return parseObj.getStr("result_id");
    }
    /*
    * get平台获取Cameras
    * */
    private String getCamera(String url, String cookie) throws InterruptedException {
        HttpRequest request = HttpRequest.get(url)
                .header("Content-Type", "application/json;charset=UTF-8")
                .header("Cookie", cookie)
                .timeout(15000);
        Thread.sleep(3000L);
        return request.execute().body();
    }

    /*
    * url处理类
    * */
    private static String formatFpUrl(String url, String ip, String port) {
        if (StrUtil.isNotBlank(url)) {
            url = url.replace("[IP]", ip);
            url = url.replace("[PORT]", port);
        }
        return url;
    }
    /*
     * 读取配置类
     * */
    private static String getProps(String key){
        String path = System.getProperty("user.dir") + System.getProperty("file.separator") + "config.properties";
        if(!new File(path).exists()){
            logger.error("文件config.properties未找到!");
            return null;
        }
        return new Props(path).getProperty(key);
    }
}

在utils里有很多需要注意的地方,很多可能存在的异常,我并没有管,也没有trycatch,我觉得开发环境就是要大胆暴漏这些exceptions,好好测试,大不了我们下面全局处理一下嘛。。

/**
 * Created by DQ on 2020/6/23/023.
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 系统异常捕获处理
     */
    @ExceptionHandler(Exception.class)
//    @ResponseBody
    public BaseResponse exception(Exception e) {
        logger.error(e.getMessage(), e.getCause());
        //请求参数问题
        if (e instanceof HttpMessageNotReadableException) {
            return new BaseResponse(ResponseEnum.BAD_REQUEST);
        }
        //请求Content type不支持
        if (e instanceof HttpMediaTypeNotSupportedException) {
            return new BaseResponse(ResponseEnum.MEDIA_TYPE_NOT_SUPPORTED);
        }
        //请求方法不支持
        if (e instanceof HttpRequestMethodNotSupportedException) {
            return new BaseResponse(ResponseEnum.METHOD_NOT_SUPPORTED);
        }

        return new BaseResponse(ResponseEnum.SERVER_ERROR);
    }

}

好了,非常简单处理掉MultipartFile与File的转换,调用接口还是需要多练习,最近准备学习一下spring自带的restTemplent,听说这货集成了JDK 自带的 HttpURLConnection,Apache 的 HttpClient和OKHttp3,还是蛮厉害的~~
不是hutool的http请求库不好用,就是害怕高并发和大数据情况下不保险啊。。
我看公司项目里也有人用hutool,但是httpclient还是稳啊

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值