调用接口登录禅道_Java调用禅道api接口查询以及创建任务(傻瓜式复制粘贴--旗舰版禅道页面调用)

背景:系统需要调用禅道的接口进行工单的创建,并对工单进行附件上传等信息的操作。禅道接口为http接口,每次请求都需要带上zentaosid进行请求。

由于专业版禅道升级为旗舰版禅道版本变更,请求的URL有所变化,变化最大为常量类配置,如下(实体类在文章末尾):

1.配置常量类

/**
 * @ClassName ZenTaoConstants
 * @Description 禅道接口调用地址常量
 * @Author hyh
 * @Date 2022/6/29 8:56
 * @Version 1.0
 */
public class ZenTaoConstants {

    /**
     * http get请求
     */
    public static final String HTTP_GET_METHOD = "GET";

    /**
     * http post请求
     */
    public static final String HTTP_POST_METHOD = "POST";
    /**
     * 禅道服务网地址
     */
    public static final String ZENTAO_DOMAIN_URL = "https://task.zzvcom.com";

    /**
     * 获取禅道session
     */
    public static final String ZENTAO_GET_SESSION_URL = ZENTAO_DOMAIN_URL + "/api-getsessionid.json";

    /**
     * 禅道登录
     */
    public static final String ZENTAO_POST_LOGIN_URL = ZENTAO_DOMAIN_URL + "/user-login-account-password.json?account={0}&password={1}&zentaosid={2}";

    /**
     * 获取团队用户列表
     */
    public static final String ZENTAO_GET_USERLIST_URL =  ZENTAO_DOMAIN_URL + "/project-team-{0}.json?zentaosid={1}";

    /**
     * 创建禅道任务单
     */
    public static final String ZENTAO_POST_CREATE_ORDER_URL = ZENTAO_DOMAIN_URL + "/task-create-{0}-{1}.json?zentaosid={2}";

    /**
     * 给工单添加备注
     */
    public static final String ZENTAO_POST_ADD_ORDER_COMMENT_URL = ZENTAO_DOMAIN_URL + "/action-comment-task-{0}.json?zentaosid={1}";

    /**
     * 关闭工单,并添加备注
     */
    public static final String ZENTAO_POST_CLOSE_ORDER_URL = ZENTAO_DOMAIN_URL + "/task-close-{0}.json?zentaosid={1}";

    /**
     * 批量关闭工单
     */
    public static final String ZENTAO_GET_CLOSE_BATCH_ORDER_URL = ZENTAO_DOMAIN_URL + "&m=task&f=batchClose&skipTaskIdList={0}&zentaosid={1}";

    /**
     * 删除工单
     */
    public static final String ZENTAO_GET_DELETE_ORDER_URL = ZENTAO_DOMAIN_URL + "/task-delete-{0}-{1}.json?confirm=yes&zentaosid={2}";

    /**
     * 根据参数请求禅道搜索框
     */
    public static final String ZENTAO_POST_ORDER_SEARCH_URL = ZENTAO_DOMAIN_URL + "/search-buildQuery.json?zentaosid={0}";
    /**
     * 根据搜索框返回结果查询禅道搜索列表结果
     */
    public static final String ZENTAO_GET_ORDER_LIST_URL = "?zentaosid={0}";

    /**
     * 条件查询禅道任务模块信息
     */
    public static final String ZENTAO_GET_TASK_MODULE_LIST_URL = ZENTAO_DOMAIN_URL + "/tree-ajaxGetOptionMenu-{0}-task-0-0-json--0-.json?zentaosid={1}";

}

2.封装请求方法

/**
 * 禅道api
 *
 * @author wangshuxue
 * @date 2021/3/17
 */
public interface IZenTaoService {

    /**
     * @param
     * @return String
     * @description: 禅道登录
     * @author hyh
     * @date 2022/7/13 9:43
     */
    String loginZenTao() throws IOException;

    /**
     * 获取禅道用户信息
     *
     * @return List
     * @author hyh
     * @params []
     * @date 2022/7/13 9:43
     */
    List<ZenTaoUserVo> listZentaoUsers(String projectCode) throws IOException;

    /**
     * @param
     * @return String
     * @description: 获取禅道session,默认时间是24分钟
     * @author hyh
     * @date 2022/7/13 9:50
     */
    String getZenTaoSession();

    /**
     * @param acceptOrder
     * @return String
     * @description: 创建禅道任务单
     * @author hyh
     * @date 2022/7/13 9:53
     */
    String createOrder(MultipartFile[] files, AcceptOrder acceptOrder) throws IOException;

    /**
     * @param acceptOrderRemark
     * @return Boolean
     * @description: 给工单添加备注
     * @author hyh
     * @date 2022/7/13 14:10
     */
    Boolean addComment(AcceptOrderRemark acceptOrderRemark) throws IOException;

    /**
     * @param orderRemark
     * @return Boolean
     * @description: 关闭工单,并添加备注
     * @author hyh
     * @date 2022/7/13 13:34
     */
    Boolean closeOrder(AcceptOrderRemark orderRemark) throws IOException;

    /**
     * @param ids
     * @return Boolean
     * @description: 批量关闭工单
     * @author hyh
     * @date 2022/7/13 13:34
     */
    Boolean closeBatchOrder(String ids) throws IOException;

    /**
     * @param acceptOrder
     * @return Boolean
     * @description: 删除工单
     * @author hyh
     * @date 2022/7/13 13:34
     */
    Boolean delOrder(AcceptOrder acceptOrder) throws IOException;

    /**
     * @param order
     * @return String
     * @description: 根据参数请求禅道搜索框
     * @author hyh
     * @date 2022/8/16 14:17
     */
    String getZenTaoSearchLocalUrl(AcceptOrder order) throws IOException;

    /**
     * @param locateUrl
     * @return String
     * @description: 根据搜索框返回结果查询禅道搜索列表结果
     * @author hyh
     * @date 2022/8/16 14:17
     */
    String getZenTaoSearchList(String locateUrl) throws IOException;

    /**
     * 条件查询禅道任务模块信息
     *
     * @return List
     * @author hyh
     * @params []
     * @date 2022/7/13 9:43
     */
    List<ZenTaoTaskModuleVo> getZenTaoModuleList(String projectCode) throws IOException;
}

3.创建方法实现类 


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.vcom.pmfr.enums.ZenTaoOptionEnum;
import com.vcom.pmfr.enums.ZenTaoTaskStatusEnum;
import com.vcom.pmfr.exception.BaseException;
import com.vcom.pmfr.mapper.SDictDataMapper;
import com.vcom.pmfr.model.common.Constant;
import com.vcom.pmfr.model.common.ZenTaoConstants;
import com.vcom.pmfr.model.entity.AcceptOrder;
import com.vcom.pmfr.model.entity.AcceptOrderRemark;
import com.vcom.pmfr.model.entity.SDictData;
import com.vcom.pmfr.model.entity.SysUser;
import com.vcom.pmfr.model.zentao.ZenTaoClientVo;
import com.vcom.pmfr.model.zentao.ZenTaoTaskModuleVo;
import com.vcom.pmfr.model.zentao.ZenTaoUserVo;
import com.vcom.pmfr.service.IZenTaoService;
import com.vcom.pmfr.util.RedisUtil;
import com.vcom.pmfr.util.UserUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.SocketTimeoutException;
import java.text.MessageFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@Slf4j
@Service
public class ZenTaoServiceImpl implements IZenTaoService {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private UserUtil userUtil;

    private static final Long ZENTAO_SESSION_EXPIRE_TIME = 20 * 60L;

    //禅道客服运维管理账号
    @Value("${zentao.account}")
    private String ZEN_TAO_ADMIN_ACCOUNT;

    //禅道客服运维管理密码
    @Value("${zentao.password}")
    private String ZEN_TAO_ADMIN_PASSWORD;

    /**
     * 设置超时时间
     */
    private static final int CONNECT_TIMEOUT = 100;
    private static final int READ_TIMEOUT = 45;
    private static final int WRITE_TIMEOUT = 45;

    @Autowired
    private SDictDataMapper sDictDataMapper;

    //img Matcher 对象
    private static Pattern p_image = Pattern.compile("<img.*src\\s*=\\s*(.*?)[^>]*?>", Pattern.CASE_INSENSITIVE);
    //img src Matcher 对象
    private static Pattern r_image = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)");
    //禅道工单受理内容富文本内容图片存储位置
    private static final String ZEN_TAO_ACCEPTCONTEXT_IMGS_PATH = "/localfile/data/acceptContextImgs/";

    /**
     * 获取禅道用户信息
     *
     * @return com.vcom.vpms.model.dto.ResponseBean
     * @author wangshuxue
     * @params []
     * @date 2021/3/17
     */
    @Override
    public List<ZenTaoUserVo> listZentaoUsers(String projectCode) throws IOException {
        List<ZenTaoUserVo> jsonList = new ArrayList<ZenTaoUserVo>();
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接获取禅道用户地址参数
        String userUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_GET_USERLIST_URL, projectCode, zentaosid);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(userUrl);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_GETUSER.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            JSONObject data = jsonObject.getJSONObject("data");
            JSONObject resultArray = data.getJSONObject("teamMembers");
            if (CollectionUtils.isNotEmpty(resultArray)) {
                for (Map.Entry entry : resultArray.entrySet()) {
                    JSONObject obj = (JSONObject) entry.getValue();
                    ZenTaoUserVo vo = new ZenTaoUserVo();
                    vo.setId(Integer.parseInt(obj.getString("id")));
                    vo.setAccount(obj.getString("account"));
                    vo.setRealname(obj.getString("realname"));
                    jsonList.add(vo);
                }
            }
        }
        return jsonList;
    }

    /**
     * @param
     * @return String
     * @description: 获取禅道session,默认时间是24分钟
     * @author hyh
     * @date 2022/7/13 9:50
     */
    @Override
    public String getZenTaoSession() {
        String zentaosid = null;
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(ZenTaoConstants.ZENTAO_GET_SESSION_URL);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_SESSION.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            String tmp = StringEscapeUtils.unescapeEcmaScript(jsonObject.getString("data"));
            JSONObject object = JSONObject.parseObject(tmp);
            zentaosid = object.getString("sessionID");
            //将禅道sessionid放入缓存,设置平台20分钟失效,禅道24分钟失效
            redisUtil.set(getZenTaoKey(), zentaosid, ZENTAO_SESSION_EXPIRE_TIME);
        }
        return zentaosid;
    }

    /**
     * @param
     * @return String
     * @description: 禅道登录
     * @author hyh
     * @date 2022/7/13 9:43
     */
    @Override
    public String loginZenTao() throws IOException {
        //获取禅道session
        String zentaosid = getZentaoSid();
        //创建请求
        MediaType mediaType = MediaType.parse("text/plain");
        RequestBody body = RequestBody.create(mediaType, "");
        //获取用户禅道账户密码
        SysUser sysUser = getLoginUserInfo();
        //拼接登录地址参数
        String loginUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_POST_LOGIN_URL,
                StringUtils.isNotEmpty(sysUser.getChandaoAccount()) ? sysUser.getChandaoAccount() : ZEN_TAO_ADMIN_ACCOUNT,
                StringUtils.isNotEmpty(sysUser.getChandaoPassword()) ? sysUser.getChandaoPassword() : ZEN_TAO_ADMIN_PASSWORD, zentaosid);
        log.info(loginUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(loginUrl);
        zenTaoClientVo.setBody(body);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_POST_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_LOGIN.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        log.info("发起登录");
        if (ObjectUtils.isEmpty(jsonObject)) {
            log.info("禅道token未获取到");
            redisUtil.del(getZenTaoKey());
            throw new BaseException("禅道token未获取到");
        }
        if (jsonObject.containsKey("status") && "failed".equals(jsonObject.getString("status"))) {
            log.info("禅道token未获取到:" + jsonObject.getString("reason"));
            redisUtil.del(getZenTaoKey());
            throw new BaseException(jsonObject.getString("reason"));
        }
        log.info("登陆成功");
        return zentaosid;
    }

    /**
     * @param
     * @return String
     * @description: 创建禅道任务单
     * @author hyh
     * @date 2022/7/13 9:53
     */
    @Override
    public String createOrder(MultipartFile[] files, AcceptOrder acceptOrder) throws IOException {
        log.info("创建禅道工单,请求参数{}", acceptOrder.toString());
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //禅道任务id
        String id = null;
        //获取文件map
        Map<MultipartFile, String> multipartFilesMap = getFilesObject(files);
        //获取处理内容富文本中的图片,并传入禅道附件
        Map<File, String> fileMap = getAcceptContextImgs(acceptOrder.getAcceptContext());
        log.info("创建禅道工单,拼装请求参数");
        //拼装请求参数
        RequestBody body = packageCreateOrderObject(acceptOrder, multipartFilesMap, fileMap);
        //拼接创建工单地址参数
        String createUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_POST_CREATE_ORDER_URL, acceptOrder.getProjectCode(), acceptOrder.getTaskModule(), zentaosid);//项目id
        log.info(createUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(createUrl);
        zenTaoClientVo.setBody(body);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_POST_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_ADD.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        log.info("请求成功--" + jsonObject.toJSONString());
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            //超时处理
            if (jsonObject.containsKey("overTime") && jsonObject.getBoolean("overTime")) {
                //超时处理
                log.info("禅道sid:{},超时处理" + zentaosid);
                return "工单创建中";
            }
            //成功
            //判断是否有失败请求
            if ("fail".equals(jsonObject.getString("result"))) {
                String msg = "";
                JSONObject messageObj = jsonObject.getJSONObject("message");
                for (String key : messageObj.keySet()) {
                    log.error("错误值{},原因{}", key, messageObj.get(key).toString());
                    msg = messageObj.get(key).toString();
                }
                //删除缓存
                redisUtil.del(getZenTaoKey());
                throw new BaseException(msg);
            }
            id = jsonObject.getString("id");
        }
        log.info("禅道id=" + zentaosid);
        return id;
    }

    /**
     * @param
     * @return
     * @description: 给工单添加备注
     * @author hyh
     * @date 2022/7/13 14:10
     */
    @Override
    public Boolean addComment(AcceptOrderRemark acceptOrderRemark) throws IOException {
        Boolean isSuccess = false;
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("comment", acceptOrderRemark.getContext()).build();
        //拼接增加工单评论url
        String addCommentUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_POST_ADD_ORDER_COMMENT_URL, acceptOrderRemark.getSourceOrderNum(), zentaosid);
        log.info("添加工单备注:" + addCommentUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(addCommentUrl);
        zenTaoClientVo.setBody(body);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_POST_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_ADD_COMMENT.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            //成功
            isSuccess = true;
        }
        return isSuccess;
    }


    /**
     * @param
     * @return
     * @description: 关闭工单,并添加备注
     * @author hyh
     * @date 2022/7/13 13:34
     */
    @Override
    public Boolean closeOrder(AcceptOrderRemark orderRemark) throws IOException {
        Boolean isSuccess = false;
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接关闭工单地址参数
        String closeUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_POST_CLOSE_ORDER_URL, orderRemark.getSourceOrderNum(), zentaosid);
        log.info("关闭工单:" + closeUrl);
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM).addFormDataPart("comment", orderRemark.getContext())
//                .addFormDataPart("status", ZenTaoTaskStatusEnum.ZEN_TAO_TASK_STATUS_CLOSE.getCode())
//                .addFormDataPart("deadline", orderRemark.getDeadline()) //必传 预计结束日期
                .build();
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(closeUrl);
        zenTaoClientVo.setBody(body);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_POST_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_CLOSE.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            if ("fail".equals(jsonObject.getJSONObject("data").getString("result"))) {
                log.info("工单关闭失败,原因:", jsonObject.getJSONObject("data").getString("message"));
            } else {
                //成功
                isSuccess = true;
            }
        }
        return isSuccess;
    }

    /**
     * @param ids
     * @return
     * @description: 批量关闭工单
     * @author hyh
     * @date 2022/7/13 13:34
     */
    @Override
    public Boolean closeBatchOrder(String ids) throws IOException {
        Boolean isSuccess = false;
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接关闭工单地址参数
        String closeUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_GET_CLOSE_BATCH_ORDER_URL, ids, zentaosid);
        log.info("批量关闭工单:" + closeUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(closeUrl);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_BATCH_CLOSE.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            //成功
            isSuccess = true;
        }
        return isSuccess;
    }

    /**
     * @param
     * @return
     * @description: 删除工单
     * @author hyh
     * @date 2022/7/13 13:34
     */
    @Override
    public Boolean delOrder(AcceptOrder acceptOrder) throws IOException {
        Boolean isSuccess = false;
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接删除工单地址参数
        String delUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_GET_DELETE_ORDER_URL, acceptOrder.getProjectCode(), acceptOrder.getSourceOrderNum(), zentaosid);
        log.info("删除工单:" + delUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(delUrl);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_DEL.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            //成功
            isSuccess = true;
        }
        return isSuccess;
    }

    /**
     * @param order
     * @return String
     * @description: 根据参数请求禅道搜索框
     * @author hyh
     * @date 2022/8/16 14:17
     */
    @Override
    public String getZenTaoSearchLocalUrl(AcceptOrder order) throws IOException {
        String locateUrl = "";
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接 根据参数请求禅道搜索框 地址参数
        String searchUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_POST_ORDER_SEARCH_URL, zentaosid);
        log.info("根据参数请求禅道搜索框:" + searchUrl);
        RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart("field1", "name")//搜索参数 标题
                .addFormDataPart("operator1", "=")//搜索限制 include 包含 ,=等于
                .addFormDataPart("value1", order.getTaskName()) //搜索值
                .addFormDataPart("module", "workTask") //模块
                .addFormDataPart("actionURL", "/my-work-task-bySearch-myQueryID.json") //响应返回地址
                .build();
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(searchUrl);
        zenTaoClientVo.setBody(body);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_POST_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_SEARCH_TASK.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            String tmp = StringEscapeUtils.unescapeEcmaScript(jsonObject.getString("data"));
            JSONObject object = JSONObject.parseObject(tmp);
            //成功
            locateUrl = object.getString("locate");
        }
        return locateUrl;
    }

    /**
     * @param locateUrl
     * @return String
     * @description: 根据搜索框返回结果查询禅道搜索列表结果
     * @author hyh
     * @date 2022/8/16 14:17
     */
    @Override
    public String getZenTaoSearchList(String locateUrl) throws IOException {
        String id = "";
        if (StringUtils.isEmpty(locateUrl)) {
            return id;
        }
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接 根据搜索框返回结果查询禅道搜索列表结果 地址参数
        String searchListUrl = locateUrl + MessageFormat.format(ZenTaoConstants.ZENTAO_GET_ORDER_LIST_URL, zentaosid);
        log.info("根据搜索框返回结果查询禅道搜索列表结果:" + searchListUrl);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(searchListUrl);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_TASK_LIST.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            JSONObject data = jsonObject.getJSONObject("data");
            JSONObject taskObj = new JSONObject();
            Object object = JSON.parse(data.getString("tasks"));
            //专业版  只有符合条件可以查出来一条并且是JSONObject格式,若为空或多条则是JSONArray
            //旗舰版  符合条件查出来一条是JSONArray格式
            if (object instanceof JSONObject) {
                taskObj = (JSONObject) object;
            } else if (object instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) object;
                log.info(" jsonArray:" + jsonArray.toJSONString());
                if (CollectionUtils.isNotEmpty(jsonArray)) {
                    log.info(" 请求禅道用户任务列表返回的数据-jsonArray-开始");
                    for (int i = 0; i < jsonArray.size(); i++) {
                        taskObj = jsonArray.getJSONObject(i);
                    }
                    log.info(" 请求禅道用户任务列表返回的数据-jsonArray-结束,若不打印则转换失败");
                }
            }
            //成功
            if (ObjectUtils.isNotEmpty(taskObj)) {
                //将jsonObj转换成Map
                Map<String, Object> itemMap = JSONObject.toJavaObject(taskObj, Map.class);
                for (Object key : itemMap.keySet()) {
                    //判断map中任务的id
                    if("id".equals(key)){
                        id=itemMap.get(key).toString();
                        break;
                    }
                }
                log.info("执行根据任务名称查询禅道未同步的数据获取到的禅道任务数据:{}", JSON.toJSONString(itemMap));
            }
        }
        return id;
    }

    @Override
    public List<ZenTaoTaskModuleVo> getZenTaoModuleList(String projectCode) throws IOException {
        List<ZenTaoTaskModuleVo> jsonList = new ArrayList<ZenTaoTaskModuleVo>();
        //获取禅道session,每次刷新登录
        String zentaosid = loginZenTao();
        //拼接获取禅道用户地址参数
        //TODO 暂时修改为 "635".equals(acceptOrder.getProjectCode()) ? "1" : "627"
        String userUrl = MessageFormat.format(ZenTaoConstants.ZENTAO_GET_TASK_MODULE_LIST_URL, "635".equals(projectCode) ? "1" : "627", zentaosid);
        //拼装请求客户端参数
        ZenTaoClientVo zenTaoClientVo = new ZenTaoClientVo();
        zenTaoClientVo.setZenTaoUrl(userUrl);
        zenTaoClientVo.setBody(null);
        zenTaoClientVo.setMethodType(ZenTaoConstants.HTTP_GET_METHOD);
        zenTaoClientVo.setOption(ZenTaoOptionEnum.ZEN_TAO_OPTION_TASK_MODULE_LIST.getInfo());
        JSONObject jsonObject = packageZenTaoHttpClient(zenTaoClientVo);
        if (ObjectUtils.isNotEmpty(jsonObject)) {
            Iterator it = jsonObject.keySet().iterator();
            while (it.hasNext()) {
                String key = (String) it.next();// 获得key
                String value = jsonObject.getString(key);// 获得value
                ZenTaoTaskModuleVo taskModuleVo = new ZenTaoTaskModuleVo();
                taskModuleVo.setModuleCode(key).setModuleName(value);
                jsonList.add(taskModuleVo);
            }
        }
        return jsonList;
    }

    /**
     * @param
     * @return String zentaosid
     * @description: 获取zentaosid
     * @author hyh
     * @date 2022/7/13 17:24
     */
    private String getZentaoSid() throws IOException {
        String zentaosid = null;
        String zentaoKey = getZenTaoKey();
        //判断缓存值是否存在
        if (ObjectUtils.isEmpty(redisUtil.get(zentaoKey))) {
            zentaosid = getZenTaoSession();
        } else {
            zentaosid = redisUtil.get(zentaoKey).toString();
        }
        if (StringUtils.isEmpty(zentaosid)) {
            log.error("禅道获取zentaosid失败");
            throw new BaseException("禅道获取zentaosid失败");
        }
        return zentaosid;
    }

    /**
     * @param
     * @return
     * @description: 获取 ZenTaoKey
     * @author hyh
     * @date 2022/7/14 9:01
     */
    private String getZenTaoKey() {
        // 获取当前登录用户
        SysUser userCurrent = userUtil.getCurrentUser();
        if (ObjectUtils.isEmpty(userCurrent)) {
            log.error("获取当前登录用户失败");
            throw new BaseException("获取当前登录用户失败");
        }
        return Constant.PREFIX_ZENTAO_SESSION + userCurrent.getId();
    }

    /**
     * @param
     * @return
     * @description: 获取 登录人信息
     * @author hyh
     * @date 2022/7/14 9:01
     */
    private SysUser getLoginUserInfo() {
        // 获取当前登录用户
        SysUser userCurrent = userUtil.getCurrentUser();
        if (ObjectUtils.isEmpty(userCurrent)) {
            log.error("获取当前登录用户失败");
            throw new BaseException("获取当前登录用户失败");
        }
        return userCurrent;
    }

    /**
     * @param
     * @return
     * @description: 封装禅道创建工单请求体
     * @author hyh
     * @date 2022/7/14 9:17
     */
    private RequestBody packageCreateOrderObject(AcceptOrder acceptOrder, Map<MultipartFile, String> multipartFileMap, Map<File, String> fileMap) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        String status = "";
        //判断是否有处理结果,如果有结果直接关闭
        if (StringUtils.isNotEmpty(acceptOrder.getAcceptResult())) {
            status = ZenTaoTaskStatusEnum.ZEN_TAO_TASK_STATUS_CLOSE.getCode();
        } else {
            status = ZenTaoTaskStatusEnum.ZEN_TAO_TASK_STATUS_DOING.getCode();
        }
        //TODO 暂时修改为 "635".equals(acceptOrder.getProjectCode()) ? "1" : "627"
        builder.addFormDataPart("execution", "635".equals(acceptOrder.getProjectCode()) ? "1" : "627")                           //必传   项目id
                .addFormDataPart("type", getZnTaoDataByData("taskType", acceptOrder.getZenTaoType()))                                   //必传   任务类型
                .addFormDataPart("assignedTo[]", acceptOrder.getAssignedTo())                           //必传   指派给谁,必传
                .addFormDataPart("status", status)    //后台必传 任务状态
                .addFormDataPart("name", acceptOrder.getTaskName())                                     //必传   任务名称,
                .addFormDataPart("pri", getZnTaoDataByData("pri", acceptOrder.getPri()))                                           //必传   任务优先级,1-4,最高,较高,一般,最低
                .addFormDataPart("estimate", acceptOrder.getAssessTime().toString())                    //必传   预计工时
                .addFormDataPart("desc", stripHtml(acceptOrder.getAcceptContext()))                     //必传 任务描述
                .addFormDataPart("estStarted", acceptOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))                  //必传 预计开始日期
                .addFormDataPart("deadline", acceptOrder.getDeadline().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))                     //必传 预计结束日期
//                .addFormDataPart("story", "")                                                               //非必传 关联需求
//                .addFormDataPart("color", "")                                                               //非必传  标题颜色
                .addFormDataPart("module", acceptOrder.getTaskModule());                                //非必传  所属模块
        log.info("组装时的参数:execution:{},type:{},assignedTo:{},status:{},name:{},pri:{},estimate:{},desc:{},estStarted:{},deadline:{}",
                acceptOrder.getProjectCode(), getZnTaoDataByData("taskType", acceptOrder.getZenTaoType()), acceptOrder.getAssignedTo(), status,
                acceptOrder.getTaskName(), getZnTaoDataByData("pri", acceptOrder.getPri()),
                acceptOrder.getAssessTime().toString(), acceptOrder.getAcceptContext(), acceptOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")),
                acceptOrder.getDeadline().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        //添加文件
        if (CollectionUtils.isNotEmpty(multipartFileMap)) {
            for (Map.Entry<MultipartFile, String> entry : multipartFileMap.entrySet()) {
                builder.addFormDataPart("files[]", entry.getValue(), RequestBody.create(MediaType.parse("application/octet-stream"), multipartFileToFile(entry.getKey())))//非必传 附件
                        .addFormDataPart("labels[]", entry.getValue());               //非必传 附件名称;
            }
        }
        //处理内容富文本中的图片,并传入禅道附件
        if (CollectionUtils.isNotEmpty(fileMap)) {
            for (Map.Entry<File, String> entry : fileMap.entrySet()) {
                builder.addFormDataPart("files[]", entry.getValue(), RequestBody.create(MediaType.parse("application/octet-stream"), entry.getKey()))//非必传 附件
                        .addFormDataPart("labels[]", entry.getValue());
            }
        }
        RequestBody body = builder.build();
        return body;
    }

    /**
     * 去除富文本内容的html标签
     *
     * @param content
     * @return
     */
    public static String stripHtml(String content) {
        //定义style的正则表达式
        String regEx_style = "<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>";
        //开始转换
        content = content.replaceAll(regEx_style, "").replaceAll("<[a-zA-Z]+[1-9]?[^><]*>", "").replaceAll("</[a-zA-Z]+[1-9]?>", "").replaceAll("<!--[\\w\\W\\r\\n]*?-->", "");
        return content;
    }

    /**
     * @param type 字典类型 dataId 字典值id
     * @return String
     * @description: 根据字典类型字典值id获取所需字段
     * @author hyh
     * @date 2022/7/28 9:58
     */
    private String getZnTaoDataByData(String type, String dataId) {
        String code = "";
        SDictData data = sDictDataMapper.selectById(dataId);
        if (ObjectUtils.isNotEmpty(data)) {
            if ("pri".equals(type)) {
                code = data.getSort().toString();
            }
            if ("taskType".equals(type)) {
                code = data.getDataCode();
            }
        }
        return code;
    }

    /**
     * @param
     * @return
     * @description: 根据文件查询文件绝对地址和名称并返回
     * @author hyh
     * @date 2022/7/14 10:35
     */
    private Map<MultipartFile, String> getFilesObject(MultipartFile[] files) {
        Map<MultipartFile, String> map = new HashMap<>(1 << 4);
        if (files.length > 0) {
            for (MultipartFile file : files) {
                if (file.isEmpty()) {
                    throw new BaseException("文件不存在");
                }
                //文件名称
                String fileName = file.getOriginalFilename();
                //保存平台工单信息
                map.put(file, fileName);
            }
        }
        return map;
    }


    /**
     * MultipartFile 转 File
     *
     * @param multipartFile
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile multipartFile) {

        File file = null;
        //判断是否为null
        if (multipartFile.equals("") || multipartFile.getSize() <= 0) {
            return file;
        }
        //MultipartFile转换为File
        InputStream ins = null;
        OutputStream os = null;
        try {
            ins = multipartFile.getInputStream();
            file = new File(multipartFile.getOriginalFilename());
            os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (ins != null) {
                try {
                    ins.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file;
    }


    /**
     * @param zenTaoClientVo
     * @return
     * @description: 封装禅道请求客户端
     * @author hyh
     * @date 2022/7/20 17:25
     */
    public JSONObject packageZenTaoHttpClient(ZenTaoClientVo zenTaoClientVo) {
        Response response = null;
        JSONObject jsonObject = new JSONObject();
        try {
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
                    .build();
            MediaType mediaType = MediaType.parse("text/plain");
            //拼接增加工单评论url
            Request request = new Request.Builder()
                    .url(zenTaoClientVo.getZenTaoUrl())
                    .method(zenTaoClientVo.getMethodType(), zenTaoClientVo.getBody())
                    .build();
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                String res = response.body().string();
                log.info("操作:" + zenTaoClientVo.getOption() + ",请求客户端返回信息:{}", res);
                if (isJSON2(res)) {
                    jsonObject = JSONObject.parseObject(res);
                    log.info("如果是json,此时解析返回的数据:{}", jsonObject.toJSONString());
                } else {
                    jsonObject.put("flag", true);
                }
            }
        } catch (SocketTimeoutException e) {
            // 超时
            log.error("executeHttpRequest TimeOut, e: " + e);
            //超时处理
            jsonObject.put("overTime", true);
//            throw new BaseException("禅道" + zenTaoClientVo.getOption() + "超时");
        } catch (IOException e) {
            // 网络IO异常
            log.error("executeHttpRequest IOException, e: " + e);
            throw new BaseException("禅道" + zenTaoClientVo.getOption() + "网络IO异常");
        } catch (Exception e) {
            // 其他异常
            log.error("禅道" + zenTaoClientVo.getOption() + "失败");
            throw new BaseException("禅道" + zenTaoClientVo.getOption() + "失败");
        } finally {
            if (response != null) {
                // body 必须被关闭,否则会发生资源泄漏;
                response.body().close();
            }
        }
        return jsonObject;
    }

    /**
     * @param str
     * @return boolean
     * @description: 判断是否是json格式
     * @author hyh
     * @date 2022/7/21 15:21
     */
    public static boolean isJSON2(String str) {
        boolean result = false;
        try {
            Object obj = JSON.parse(str);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    /**
     * @param acceptContext 受理内容
     * @return Map<MultipartFile, String>
     * @description: 获取处理内容富文本中的图片,并传入禅道附件
     * @author hyh
     * @date 2022/8/5 9:12
     */
    public static Map<File, String> getAcceptContextImgs(String acceptContext) {
        Map<File, String> fileMap = new HashMap<>(1 << 4);
        String num = String.format("%04d", new Random().nextInt(10000));
        if (StringUtils.isNotEmpty(acceptContext)) {
            List<String> imgList = getImgStr(acceptContext);
            if (!org.springframework.util.CollectionUtils.isEmpty(imgList)) {
                for (int i = 0; i < imgList.size(); i++) {
                    if (imgList.get(i).contains("base64,")) {
                        String fileName = String.format("%s%s%s", num, i, ".jpg");
                        fileMap.put(base64ToFile(imgList.get(i).split("base64,")[1], fileName), fileName);
                    }
                }
            }
        }

        return fileMap;
    }

    //BASE64解码成File文件
    public static File base64ToFile(String base64, String fileName) {
        File file = null;
        //创建文件目录
        String filePath = ZEN_TAO_ACCEPTCONTEXT_IMGS_PATH;
        File dir = new File(filePath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }
        BufferedOutputStream bos = null;
        java.io.FileOutputStream fos = null;
        try {
            byte[] bytes = Base64.getDecoder().decode(base64);
            file = new File(filePath + "/" + fileName);
            fos = new java.io.FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
        } catch (Exception e) {
            log.error("禅道工单富文本图片存储失败0", e);
            throw new BaseException("禅道工单富文本图片存储失败");
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    log.error("禅道工单富文本图片存储失败1", e);
                    throw new BaseException("禅道工单富文本图片存储失败");
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("禅道工单富文本图片存储失败2", e);
                    throw new BaseException("禅道工单富文本图片存储失败");
                }
            }
        }
        return file;
    }

    /**
     * @return java.util.List<java.lang.String>
     * @Author shipj
     * @Description 提取富文本图片(img标签src属性)
     * @Date 20:49 2021-04-12
     * @Param [htmlStr]
     **/
    public static List<String> getImgStr(String htmlStr) {
        List<String> list = new ArrayList<>();
        Matcher m_image = p_image.matcher(htmlStr);
        while (m_image.find()) {
            // 得到<img />数据
            String img = m_image.group();
//            System.out.println(img);
            // 匹配<img>中的src数据
            Matcher m = r_image.matcher(img);
            while (m.find()) {
                list.add(m.group(1));
            }
        }
        return list;
    }

}

 实体类:

/**
 * @ClassName ZenTaoUserVo
 * @Description 禅道客户端请求 VO
 * @Version 1.0
 */
@Data
@Accessors(chain = true)
public class ZenTaoClientVo {

    /**
     * 请求体
     * */
    private RequestBody body;
    /**
     * 请求地址
     * */
    private String zenTaoUrl;
    /**
     * 方法类型
     * */
    private String methodType;
    /**
     * 操作类型
     * */
    private String option;
}

@Data
@Accessors(chain = true)
public class ZenTaoUserVo {

    /**
     * 用户id
     * */
    private Integer id;
    /**
     * 用户部门
     * */
//    private Integer dept;
    /**
     * 用户账户名称
     * */
    private String account;
    /**
     * 用户真实名称
     * */
    private String realname;
    /**
     * 用户角色
     * */
//    private String role;
    /**
     * 用户pinyin
     * */
//    private String pinyin;
    /**
     * 用户email
     * */
//    private String email;
}

4.傻瓜式调用

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值