今天介绍的是封装泛微e9集成金蝶k3系统所需要的基础工具方法,具体使用参照之前章节。
工具类如下:
java
package weaver.interfaces.workflow.action;
import okhttp3.*;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 泛微OA对接ERP系统的通用工具类
* 核心能力:文件Base64编码、ERP鉴权Cookie获取、ERP接口调用、数据库操作、日期转换等
*/
public class ErpIntegrationUtil {
// 泛微日志工具
private static final BaseBean BASE_BEAN = new BaseBean();
// 全局OkHttpClient单例(复用连接池,避免资源泄漏)
private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时30s
.readTimeout(30, TimeUnit.SECONDS) // 读取超时30s
.writeTimeout(30, TimeUnit.SECONDS) // 写入超时30s
.build();
// 线程安全的日期格式化器(避免多线程并发问题)
private static final ThreadLocal<SimpleDateFormat> DATE_FORMATTER = ThreadLocal.withInitial(
() -> new SimpleDateFormat("yyyy-MM-dd")
);
/**
* 私有构造器:工具类禁止实例化
*/
private ErpIntegrationUtil() {
throw new UnsupportedOperationException("工具类禁止实例化");
}
/**
* 将文件内容编码为Base64字符串
* @param filePath 文件绝对路径(如D:\\泛微OA.cnf)
* @return Base64编码字符串 | null(文件不存在/读取失败)
*/
public static String encodeFileToBase64(String filePath) {
// 空路径直接返回null
if (filePath == null || filePath.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 文件路径为空,Base64编码失败");
return null;
}
try {
// 检查文件是否存在(避免Files.readAllBytes抛FileNotFoundException)
if (!Files.exists(Paths.get(filePath))) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 文件不存在:" + filePath);
return null;
}
// 读取文件字节并编码为Base64
byte[] fileBytes = Files.readAllBytes(Paths.get(filePath));
String base64Str = Base64.getEncoder().encodeToString(fileBytes);
BASE_BEAN.writeLog("[ErpIntegrationUtil] 文件Base64编码成功,路径:" + filePath);
return base64Str;
} catch (IOException e) {
// 泛微日志记录异常,便于排查
BASE_BEAN.writeLog("[ErpIntegrationUtil] 文件Base64编码失败,路径:" + filePath + ",异常:" + e.getMessage());
return null;
}
}
/**
* 获取ERP登录鉴权的Cookie列表,此案例中ERP采用传统的Session-Cookie鉴权模式
* @return List<String> Set-Cookie头列表 | null(请求失败/无Cookie)
*/
public static List<String> getErpAuthCookies() {
// 从泛微配置文件读取ERP登录参数(key在泛微配置文件ERP节点下)
String loginJson = BASE_BEAN.getPropValue("ERP", "cookieJson");
String loginUrl = BASE_BEAN.getPropValue("ERP", "url");
// 空值检查:配置项缺失直接返回
if (loginJson == null || loginJson.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP登录请求体(cookieJson)配置缺失");
return null;
}
if (loginUrl == null || loginUrl.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP登录地址(url)配置缺失");
return null;
}
// 构建登录请求
MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(jsonMediaType, loginJson);
Request loginRequest = new Request.Builder()
.url(loginUrl)
.post(requestBody)
.addHeader("Content-Type", "application/json")
.build();
// try-with-resources:自动关闭Response,避免资源泄漏
try (Response response = OK_HTTP_CLIENT.newCall(loginRequest).execute()) {
// 检查响应是否成功(200-299)
if (!response.isSuccessful()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP登录请求失败,状态码:" + response.code());
return null;
}
// 安全获取Set-Cookie头列表
List<String> setCookieList = response.headers().toMultimap().get("set-cookie");
BASE_BEAN.writeLog("[ErpIntegrationUtil] 获取ERP Cookie成功,数量:" + (setCookieList == null ? 0 : setCookieList.size()));
return setCookieList;
} catch (IOException e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 获取ERP Cookie异常:" + e.getMessage());
return null;
}
}
/**
* 携带鉴权Cookie调用ERP业务接口
* @param requestJson 接口请求体JSON字符串
* @param authCookies ERP鉴权Cookie列表(getErpAuthCookies返回)
* @param apiUrl ERP业务接口地址
* @return 接口响应体字符串 | 空字符串(请求失败/参数异常)
*/
public static String callErpApiWithCookies(String requestJson, List<String> authCookies, String apiUrl) {
// 空值检查:核心参数缺失直接返回
if (requestJson == null || requestJson.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP接口请求体为空");
return "";
}
if (authCookies == null || authCookies.isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP鉴权Cookie为空,接口调用失败");
return "";
}
if (apiUrl == null || apiUrl.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP接口地址为空");
return "";
}
try {
// 拼接Cookie头:多个Cookie用;分隔,仅保留键值对(去掉Path/HttpOnly等属性)
StringBuilder cookieHeader = new StringBuilder();
for (String cookie : authCookies) {
if (cookie == null || cookie.trim().isEmpty()) {
continue;
}
// 拆分Cookie键值对(如JSESSIONID=123; Path=/ → 取JSESSIONID=123)
String cookieKeyValue = cookie.split(";")[0].trim();
if (cookieHeader.length() > 0) {
cookieHeader.append("; ");
}
cookieHeader.append(cookieKeyValue);
}
// 构建接口请求
MediaType jsonMediaType = MediaType.parse("application/json; charset=utf-8");
RequestBody requestBody = RequestBody.create(jsonMediaType, requestJson);
Request apiRequest = new Request.Builder()
.url(apiUrl)
.post(requestBody)
.addHeader("Content-Type", "application/json")
.addHeader("Cookie", cookieHeader.toString())
.build();
// 执行请求并自动关闭响应
try (Response response = OK_HTTP_CLIENT.newCall(apiRequest).execute()) {
if (!response.isSuccessful()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP接口调用失败,状态码:" + response.code());
return "";
}
// 安全读取响应体(避免body为null)
String responseBody = response.body() != null ? response.body().string() : "";
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP接口调用成功,响应体:" + responseBody);
return responseBody;
}
} catch (IOException e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] ERP接口调用异常:" + e.getMessage());
return "";
}
}
/**
* 根据人员ID查询姓名
* @param userId 人员ID(泛微hrmresource表的id)
* @return 人员姓名 | 空字符串(查询失败/ID不存在)
*/
public static String getEmployeeNameById(String userId) {
// 空值检查
if (userId == null || userId.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 人员ID为空,查询姓名失败");
return "";
}
RecordSet recordSet = new RecordSet();
String sql;
sql = "select lastname from hrmresource where id=?";
try {
// 占位符执行SQL,避免注入
recordSet.executeQuery(sql, new Object[]{userId});
// 检查是否查询到数据
if (recordSet.next()) {
String lastName = recordSet.getString("lastname");
BASE_BEAN.writeLog("[ErpIntegrationUtil] 查询人员姓名成功,ID:" + userId + ",姓名:" + lastName);
return lastName == null ? "" : lastName;
} else {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 未查询到人员姓名,ID:" + userId);
return "";
}
} catch (Exception e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 查询人员姓名异常,ID:" + userId + ",异常:" + e.getMessage());
return "";
}
}
/**
* 根据人员ID查询工号
* @param userId 人员ID
* @return 工号 | 空字符串(查询失败/ID不存在)
*/
public static String getEmployeeWorkCodeById(String userId) {
if (userId == null || userId.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 人员ID为空,查询工号失败");
return "";
}
RecordSet recordSet = new RecordSet();
String sql = "select workcode from hrmresource where id=?";
try {
recordSet.executeQuery(sql, new Object[]{userId});
if (recordSet.next()) {
String workCode = recordSet.getString("workcode");
BASE_BEAN.writeLog("[ErpIntegrationUtil] 查询人员工号成功,ID:" + userId + ",工号:" + workCode);
return workCode == null ? "" : workCode;
} else {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 未查询到人员工号,ID:" + userId);
return "";
}
} catch (Exception e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 查询人员工号异常,ID:" + userId + ",异常:" + e.getMessage());
return "";
}
}
/**
* 日期字符串转换为秒级时间戳
* @param dateStr 日期字符串(格式:yyyy-MM-dd)
* @return 秒级时间戳 | null(转换失败)
*/
public static Long convertDateToTimestamp(String dateStr) {
// 空值检查(包含null和空字符串)
if (dateStr == null || dateStr.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 日期字符串为空,转换时间戳失败");
return 0L;
}
try {
// 线程安全的日期格式化器
Date date = DATE_FORMATTER.get().parse(dateStr.trim());
// 返回Long类型,避免int溢出(2038年问题)
Long timestamp = date.getTime() / 1000L;
BASE_BEAN.writeLog("[ErpIntegrationUtil] 日期转时间戳成功,日期:" + dateStr + ",时间戳:" + timestamp);
return timestamp;
} catch (ParseException e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 日期转时间戳异常,日期:" + dateStr + ",异常:" + e.getMessage());
return 0L;
}
}
/**
* 更新工作流表单主表的ERP返回编码
* @param tableName 表单主表名
* @param erpCode ERP返回的编码(如物料编码)
* @param requestId 工作流请求ID(泛微requestid)
* @return true-更新成功 | false-更新失败
*/
public static boolean updateErpCodeToBill(String tableName, String erpCode, String requestId) {
// 空值检查
if (tableName == null || tableName.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 表单表名为空,更新ERP编码失败");
return false;
}
if (requestId == null || requestId.trim().isEmpty()) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 工作流请求ID为空,更新ERP编码失败");
return false;
}
// 编码为空则设为空字符串(避免SQL拼接错误)
String code = erpCode == null ? "" : erpCode;
RecordSet recordSet = new RecordSet();
// 占位符SQL,避免注入风险
String updateSql = "update " + tableName + " set jkfhbm = ? where requestid = ?";
try {
// 执行更新并返回结果
boolean isSuccess = recordSet.executeUpdate(updateSql, new Object[]{code, requestId});
BASE_BEAN.writeLog("[ErpIntegrationUtil] 更新ERP编码" + (isSuccess ? "成功" : "失败") +
",表名:" + tableName + ",请求ID:" + requestId + ",编码:" + code);
return isSuccess;
} catch (Exception e) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 更新ERP编码异常,表名:" + tableName + ",异常:" + e.getMessage());
return false;
}
}
/**
* 物料类型编码转换为ERP对应的类型标识
* @param materialType 物料类型编码(0/1)
* @return ERP类型标识 | 空字符串(未知类型)
*/
public static String convertMaterialTypeToErpCode(String materialType) {
if (materialType == null) {
BASE_BEAN.writeLog("[ErpIntegrationUtil] 物料类型编码为空,转换失败");
return "";
}
String erpCode;
switch (materialType.trim()) {
case "0":
erpCode = "BD_Empinfo";
break;
case "1":
erpCode = "BD_Supplier";
break;
default:
erpCode = "";
BASE_BEAN.writeLog("[ErpIntegrationUtil] 未知物料类型编码:" + materialType);
break;
}
return erpCode;
}
}