获取钉钉打卡数据并导出Excel

本文介绍如何使用钉钉API获取用户信息和打卡记录,并利用EasyExcel将数据导出为Excel文件。涵盖钉钉API调用、EasyExcel配置及数据处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.taobao.top</groupId>
            <artifactId>taobao-sdk-java-auto</artifactId>
            <version>1.0.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/taobao-sdk-java-auto_1479188381469-20200512.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.taobao.top</groupId>
            <artifactId>taobao-sdk-java-auto-source</artifactId>
            <version>1.0.0</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/src/main/resources/lib/taobao-sdk-java-auto_1479188381469-20200512-source.jar</systemPath>
        </dependency>
 

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.HeadRowHeight;
import lombok.Data;

import java.io.Serializable;


/**
 * @author wongH
 * @date 2020/5/26 10:39
 * @Version 1.0
 */
@Data
@HeadRowHeight(value = 40)
public class ExcelModel  implements Serializable {

    @ExcelProperty(value = {"姓名"}, index = 0)
    private String name;

    @ExcelProperty(value = {"用户id"}, index = 1)
    private String userId;

    @ExcelProperty(value = {"考勤组"}, index = 2)
    private String groupId;

    @ExcelProperty(value = {"上下班"}, index = 3)
    private String checkType;

    @ExcelProperty(value = {"时间"}, index = 4)
    private String checkTime;

    @Override
    public boolean equals(Object o) {
        if (o instanceof ExcelModel) {
            ExcelModel excelModel = (ExcelModel) o;
            return this.name.equals(excelModel.name)
                    && this.userId.equals(excelModel.userId)
                    && this.groupId.equals(excelModel.groupId)
                    && this.checkType.equals(excelModel.checkType)
                    && this.checkTime.equals(excelModel.checkTime);
        }
        return super.equals(o);
    }
}

 

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * @author wongH
 * @date 2020/5/26 11:31
 * @Version 1.0
 */
@Slf4j
public class ExcelUtil {
    /**
     * 导出
     * @param response
     * @param data
     * @param fileName
     * @param sheetName
     * @param clazz
     * @throws Exception
     */
    public static void writeExcel(HttpServletResponse response, List<? extends Object> data,
                                  String fileName, String sheetName, Class clazz) throws Exception {
        //表头样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //内容样式
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //设置内容居中对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

        EasyExcel.write(getOutputStream(fileName, response), clazz)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet(sheetName)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(horizontalCellStyleStrategy)
                .doWrite(data);
    }
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
        fileName = URLEncoder.encode(fileName, "UTF-8");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        return response.getOutputStream();
    }
}



 

import com.alibaba.fastjson.JSONObject;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import fangrong.com.cn.conmmon.ExcelUtil;
import fangrong.com.cn.entity.ExcelModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

import static fangrong.com.cn.config.DingdingConfig.AccessToken;

@RequestMapping("/")
@RestController
@Slf4j
public class IndexController {

    @GetMapping("")
    public void getData(HttpServletResponse response) throws Exception {
        //获取部门用户id列表  后期可以改成 下面的getUserIdsPage()方法 查询全部在职的员工id
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getDeptMember");
        OapiUserGetDeptMemberRequest req = new OapiUserGetDeptMemberRequest();
        //需要查询的部门
        req.setDeptId("142921000");
        req.setHttpMethod("GET");
        OapiUserGetDeptMemberResponse rsp = client.execute(req, AccessToken);
        List<String> userIds = rsp.getUserIds();

        //获取用户打卡记录
        long i = 0L;
        List<ExcelModel> excelModels = new ArrayList<>();
        while (true) {
            //获取userIds 指定日期内的打卡记录
            DingTalkClient client1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/attendance/list");
            OapiAttendanceListRequest req1 = new OapiAttendanceListRequest();
            req1.setWorkDateFrom("2020-01-06 00:00:00");
            req1.setWorkDateTo("2020-01-11 00:00:00");
            //最大50个
            req1.setUserIdList(userIds);
            req1.setOffset(i);
            req1.setLimit(50L);
            log.warn(String.valueOf(i));
            OapiAttendanceListResponse rsp1 = client1.execute(req1, AccessToken);
            List<OapiAttendanceListResponse.Recordresult> recordresults = rsp1.getRecordresult();
            if (recordresults.isEmpty()) {
                break;
            }
            //打卡结果封装
            for (OapiAttendanceListResponse.Recordresult recordresult : recordresults) {
                String userId = recordresult.getUserId();
                //根据id获取用户详情
                JSONObject userInfo = getUserInfo(userId);
                String onDuty = recordresult.getCheckType().equals("OnDuty") ? "上班" : "下班";
                Date userCheckTime = recordresult.getUserCheckTime();
                LocalDateTime localDateTime = LocalDateTime.ofInstant(userCheckTime.toInstant(), ZoneId.systemDefault());
                DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                String checkTime = localDateTime.format(dtf);
                //封装数据ExcelModel
                ExcelModel excelModel = new ExcelModel();
                excelModel.setName(userInfo.getString("name"));
                excelModel.setUserId(userId);
                excelModel.setCheckType(onDuty);
                //获取考勤组名称
                excelModel.setGroupId(getAttendance(recordresult.getGroupId()));
                excelModel.setCheckTime(checkTime);
                if (!excelModels.contains(excelModel)) {
                    excelModels.add(excelModel);
                }
            }
            i += 50;
        }
        String fileName = "考勤";
        String sheetName = "考勤";
        try {
            ExcelUtil.writeExcel(response, excelModels, fileName, sheetName, ExcelModel.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 查询用户信息
     *
     * @param userId 用户id
     */
    public static JSONObject getUserInfo(String userId) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/get");
            OapiUserGetRequest req = new OapiUserGetRequest();
            req.setUserid(userId);
            req.setHttpMethod("GET");
            OapiUserGetResponse rsp = client.execute(req, AccessToken);
            return JSONObject.parseObject(rsp.getBody());
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询考勤组名称
     *
     * @param id 考勤组id
     */
    public static String getAttendance(Long id) {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/group/query");
        OapiAttendanceGroupQueryRequest req = new OapiAttendanceGroupQueryRequest();
        req.setOpUserId("manager01");
        req.setGroupId(id);
        try {
            OapiAttendanceGroupQueryResponse rsp = client.execute(req, AccessToken);
            return rsp.getResult().getName();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 查询全部在职用户Id
     *
     * @param status     在职员工子状态筛选,其他状态无效。2:试用期;3:正式;5:待离职;-1:无状态。
     * @param nextCursor 下一次调用需要传的分页值
     * @param set        调用这个方法的外部set集合 如 Set<String> set = new HashSet<>() ; 自动将全部id封装到这个set中
     */
    public static void getUserIdsPage(String status, Long nextCursor, Set<String> set) {
        JSONObject jsonObject = getUserIds(status, nextCursor);
        List<String> dataList = (List<String>) jsonObject.get("dataList");
        set.addAll(dataList);
        Long cursor = jsonObject.getLong("cursor");
        if (cursor != null) {
            getUserIdsPage(status, cursor, set);
        }
    }

    private static JSONObject getUserIds(String status, Long nextCursor) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob");
            OapiSmartworkHrmEmployeeQueryonjobRequest req = new OapiSmartworkHrmEmployeeQueryonjobRequest();
            req.setStatusList(status);
            req.setOffset(nextCursor);
            req.setSize(50L);
            OapiSmartworkHrmEmployeeQueryonjobResponse rsp = client.execute(req, AccessToken);
            List<String> dataList = rsp.getResult().getDataList();
            Long cursor = rsp.getResult().getNextCursor();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("dataList", dataList);
            jsonObject.put("cursor", cursor);
            return jsonObject;
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        getUserIdsPage("3", 0L, set);
        System.err.println("一共有===>" + set.size());
    }


}


<think>好的,我现在需要帮助用户解决如何通过钉钉API获取打卡数据的问题。首先,我得回忆一下钉钉API的相关文档和之前的引用内容。用户提供了三个引用,分别涉及Python、Java和PHP的实现,这可能意味着用户对具体编程语言不太限制,但需要通用的步骤指导。 首先,根据引用中的信息,获取钉钉API数据通常需要几个步骤:创建企业内部应用、获取访问凭证(access_token)、调用考勤打卡接口。我需要确认这些步骤是否仍然适用,但根据钉钉的文档,这些基本流程应该没变。 用户可能没有提到创建应用的部分,但这是必要的第一步。引用1提到需要corpid和corpsecret,这对应应用的AppKey和AppSecret。引用2和3也提到创建应用和权限申请,所以必须强调这一点。 接下来,获取access_token是关键步骤,每个API调用都需要它。引用1中的Python代码示例展示了如何获取token,用户可能需要类似的代码,但需要根据他们使用的语言调整。不过用户的问题更偏向于方法而不是具体代码,所以应该概括步骤。 然后,调用考勤打卡接口。引用2提到获取打卡结果和详情,需要用户ID,因此可能需要先获取部门用户列表。用户可能不知道需要哪些前置步骤,比如获取部门列表和用户ID,这点需要说明清楚。 权限问题也很重要,引用2提到如果没有权限会报错,需要去开发者后台添加接口权限。用户可能会遇到权限问题,所以必须提醒他们检查应用权限,申请考勤打卡API的权限。 最后,数据的处理,比如分页和存储,用户可能需要知道如何循环获取所有数据,但问题可能集中在获取数据的方法上,所以这部分可以简要提及。 现在需要将这些步骤组织成清晰的流程,确保用户能按顺序操作。同时生成相关问题,帮助用户深入解决可能遇到的问题,比如权限申请、数据处理等。</think>### 通过钉钉API获取打卡数据的步骤 #### 1. **创建企业内部应用** - 登录[钉钉开发者后台](https://open-dev.dingtalk.com) - 创建应用:填写应用名称、描述,选择「企业内部开发」类型 - 获取`AppKey`和`AppSecret`(用于后续获取访问凭证)[^2] #### 2. **添加API权限** - 在应用详情页进入「权限管理」 - 添加以下接口权限: - `考勤打卡数据」读取` - `通讯录部门信息」读取` - `成员信息」读取` - 提交后需企业管理员审批[^2] #### 3. **获取Access Token** - 调用接口:`https://oapi.dingtalk.com/gettoken` - 请求参数: ```python grant_type=client_credentials appkey=你的AppKey appsecret=你的AppSecret ``` - 返回示例: ```json {"access_token":"xxxx","expires_in":7200} ``` - 有效期2小时,需定时刷新[^1][^3] #### 4. **获取部门及用户ID** - 调用`获取部门列表`接口: ```python GET https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=xxx ``` - 调用`获取部门用户userid列表`接口: ```python POST https://oapi.dingtalk.com/topapi/user/listid?access_token=xxx {"dept_id":部门ID} ``` #### 5. **调用考勤打卡接口** - **获取打卡记录**接口: ```python POST https://oapi.dingtalk.com/attendance/list { "workDateFrom": "2023-01-01 00:00:00", "workDateTo": "2023-12-31 23:59:59", "userIdList": ["userid1","userid2"], "offset": 0, "limit": 50 } ``` - 注意分页参数`offset`和`limit`[^2][^3] #### 6. **处理返回数据** - 返回数据包含: ```json { "recordresult": [ {"checkType":"OnDuty","userCheckTime":时间戳}, {"checkType":"OffDuty","userCheckTime":时间戳} ] } ``` - 建议使用循环分页获取完整数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值