|
|
@@ -0,0 +1,292 @@
|
|
|
+package com.kingdee.eas.hr.emp.web.handler.wordtemplate.service.impl;
|
|
|
+
|
|
|
+import com.kingdee.bos.BOSException;
|
|
|
+import com.kingdee.bos.Context;
|
|
|
+import com.kingdee.eas.hr.base.SqlParam;
|
|
|
+import com.kingdee.eas.common.EASBizException;
|
|
|
+import com.kingdee.eas.hr.emp.web.handler.wordtemplate.service.ResumeWordTemplateService;
|
|
|
+import com.kingdee.jdbc.rowset.IRowSet;
|
|
|
+import com.kingdee.shr.baseconfig.StructureConfigColumnsInfo;
|
|
|
+import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
|
|
|
+import com.kingdee.util.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import java.sql.SQLException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 员工履历 Word 导出 — 服务层二开扩展。
|
|
|
+ * <p>
|
|
|
+ * 按 familyRelation.number(与本人关系基础资料编码 FNumber)升序排序。
|
|
|
+ * personFamily.relation.number 在 SQL 中会映射为 FRelationID(内码),不能用于按编码排序。
|
|
|
+ * </p>
|
|
|
+ */
|
|
|
+public class ResumeWordTemplateServiceImplEx extends ResumeWordTemplateServiceImpl {
|
|
|
+
|
|
|
+ private static final Logger LOGGER = LoggerFactory.getLogger(ResumeWordTemplateServiceImplEx.class);
|
|
|
+
|
|
|
+ /** Word / 结构配置中 PersonFamily 实体别名(匹配时忽略大小写) */
|
|
|
+ private static final String PERSON_FAMILY_ENTITY = "PERSONFAMILY";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与本人关系编码排序字段。
|
|
|
+ * SQL 中 personFamily.relation.number → PERSONFAMILY.FRelationID(UUID),不是编码;
|
|
|
+ * familyRelation.number → T_HR_BDRelation.FNumber(01/02/07777),与 Word 中 familyRelation.name 同源。
|
|
|
+ */
|
|
|
+ private static final String PERSON_FAMILY_SORT_FIELD = "familyRelation.number";
|
|
|
+
|
|
|
+ /** multiNotOne 内存排序临时键,不写入 Word */
|
|
|
+ private static final String ROW_SORT_VALUE = "__sortValue";
|
|
|
+
|
|
|
+ private static final int PERSON_FAMILY_ROW_LIMIT = 0;
|
|
|
+
|
|
|
+ private static volatile ResumeWordTemplateService INSTANCE;
|
|
|
+
|
|
|
+ public static ResumeWordTemplateService instance() {
|
|
|
+ if (INSTANCE == null) {
|
|
|
+ synchronized (ResumeWordTemplateServiceImplEx.class) {
|
|
|
+ if (INSTANCE == null) {
|
|
|
+ INSTANCE = new ResumeWordTemplateServiceImplEx();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return INSTANCE;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void rowHandle(
|
|
|
+ Context ctx,
|
|
|
+ SqlParam sqlParam,
|
|
|
+ Map<String, String> selectKeyToWordKeyMap,
|
|
|
+ Map<String, Object> resultMap,
|
|
|
+ Map<String, StructureConfigColumnsInfo> columnsInfoMap
|
|
|
+ ) throws EASBizException, BOSException, ShrWebBizException, SQLException {
|
|
|
+ if (containsPersonFamilyEntity(sqlParam)) {
|
|
|
+ LOGGER.info("ResumeWordTemplateServiceImplEx.rowHandle: apply PersonFamily sort before query, field="
|
|
|
+ + PERSON_FAMILY_SORT_FIELD);
|
|
|
+ preparePersonFamilySortBeforeQuery(sqlParam);
|
|
|
+ }
|
|
|
+ super.rowHandle(ctx, sqlParam, selectKeyToWordKeyMap, resultMap, columnsInfoMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void sorterHandler(Context ctx, SqlParam param) {
|
|
|
+ super.sorterHandler(ctx, param);
|
|
|
+ applyPersonFamilySorter(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void preparePersonFamilySortBeforeQuery(SqlParam param) {
|
|
|
+ applyPersonFamilySorter(param);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void multiNotOne(
|
|
|
+ IRowSet rowSet,
|
|
|
+ Context ctx,
|
|
|
+ SqlParam sqlParam,
|
|
|
+ Map<String, String> selectKeyToWordKeyMap,
|
|
|
+ Map<String, Object> resultMap,
|
|
|
+ Map<String, StructureConfigColumnsInfo> columnsInfoMap
|
|
|
+ ) throws SQLException {
|
|
|
+ List<Map<String, String>> rowList = new ArrayList<Map<String, String>>();
|
|
|
+ String entityKey = null;
|
|
|
+ String sortSelectKey = resolveSortSelectKey(selectKeyToWordKeyMap, PERSON_FAMILY_SORT_FIELD);
|
|
|
+ boolean personFamilyQuery = containsPersonFamilyEntity(sqlParam);
|
|
|
+ boolean sortInMemory = personFamilyQuery && sortSelectKey != null;
|
|
|
+
|
|
|
+ while (rowSet.next()) {
|
|
|
+ Map<String, String> rowData = new HashMap<String, String>();
|
|
|
+ for (Map.Entry<String, String> entry : selectKeyToWordKeyMap.entrySet()) {
|
|
|
+ String wordKey = entry.getValue();
|
|
|
+ Object dbValue = rowSet.getObject(entry.getKey());
|
|
|
+ String displayValue = dataTypeHandle(
|
|
|
+ ctx,
|
|
|
+ dbValue,
|
|
|
+ columnsInfoMap.get(wordKey)
|
|
|
+ );
|
|
|
+ if (!StringUtils.isEmpty(displayValue)) {
|
|
|
+ rowData.put(wordKey, displayValue);
|
|
|
+ }
|
|
|
+ if (StringUtils.isEmpty(entityKey)) {
|
|
|
+ int splitIndex = wordKey.indexOf('_');
|
|
|
+ if (splitIndex > 0) {
|
|
|
+ entityKey = wordKey.substring(0, splitIndex);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sortInMemory) {
|
|
|
+ rowData.put(ROW_SORT_VALUE, resolveRowSortValue(rowSet, sortSelectKey));
|
|
|
+ }
|
|
|
+ if (rowData.size() > 0) {
|
|
|
+ rowList.add(rowData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (containsPersonFamilyEntity(sqlParam) && sortInMemory) {
|
|
|
+ sortRowList(rowList);
|
|
|
+ logSortPreview(rowList);
|
|
|
+ for (Map<String, String> rowData : rowList) {
|
|
|
+ rowData.remove(ROW_SORT_VALUE);
|
|
|
+ }
|
|
|
+ } else if (personFamilyQuery) {
|
|
|
+ LOGGER.warn("ResumeWordTemplateServiceImplEx.multiNotOne: PersonFamily detected but sortSelectKey missing, "
|
|
|
+ + "entityKey=" + entityKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ applyPersonFamilyRowLimit(entityKey, rowList);
|
|
|
+
|
|
|
+ if (rowList.size() > 1) {
|
|
|
+ resultMap.put(entityKey, rowList);
|
|
|
+ } else if (rowList.size() == 1) {
|
|
|
+ resultMap.putAll(rowList.get(0));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void applyPersonFamilySorter(SqlParam param) {
|
|
|
+ if (!containsPersonFamilyEntity(param)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ param.setSortStr(PERSON_FAMILY_SORT_FIELD + " asc");
|
|
|
+ addSortFieldToSelectMapping(param.getSelectMapping(), PERSON_FAMILY_SORT_FIELD);
|
|
|
+ LOGGER.info("ResumeWordTemplateServiceImplEx: sortStr=" + param.getSortStr());
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean containsPersonFamilyEntity(SqlParam param) {
|
|
|
+ if (containsEntity(param.getInfoCtr(), PERSON_FAMILY_ENTITY)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ Map<String, String> selectMapping = param.getSelectMapping();
|
|
|
+ if (selectMapping == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ for (String key : selectMapping.keySet()) {
|
|
|
+ if (isPersonFamilyFieldKey(key)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isPersonFamilyFieldKey(String key) {
|
|
|
+ if (key == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return key.toUpperCase().startsWith(PERSON_FAMILY_ENTITY + ".");
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isPersonFamilyEntityKey(String entityKey) {
|
|
|
+ return entityKey != null && PERSON_FAMILY_ENTITY.equalsIgnoreCase(entityKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean containsEntity(Map infoCtr, String entityName) {
|
|
|
+ if (infoCtr == null || StringUtils.isEmpty(entityName)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (infoCtr.containsKey(entityName) || infoCtr.containsKey(entityName.toUpperCase())) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ for (Object key : infoCtr.keySet()) {
|
|
|
+ if (entityName.equalsIgnoreCase(String.valueOf(key))) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addSortFieldToSelectMapping(Map<String, String> selectMapping, String sortField) {
|
|
|
+ if (StringUtils.isEmpty(sortField) || selectMapping == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!containsKeyIgnoreCase(selectMapping, sortField)) {
|
|
|
+ selectMapping.put(sortField, sortField);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolveSortSelectKey(Map<String, String> selectKeyToWordKeyMap, String sortField) {
|
|
|
+ if (selectKeyToWordKeyMap == null || StringUtils.isEmpty(sortField)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ for (String key : selectKeyToWordKeyMap.keySet()) {
|
|
|
+ if (key != null && key.equalsIgnoreCase(sortField)) {
|
|
|
+ return key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String suffix = ".relation.number";
|
|
|
+ for (String key : selectKeyToWordKeyMap.keySet()) {
|
|
|
+ if (key != null && key.toUpperCase().endsWith(suffix.toUpperCase())) {
|
|
|
+ return key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (sortField != null && sortField.toUpperCase().endsWith(".NUMBER")) {
|
|
|
+ for (String key : selectKeyToWordKeyMap.keySet()) {
|
|
|
+ if (key != null && key.toUpperCase().endsWith(".NUMBER")) {
|
|
|
+ return key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String resolveRowSortValue(IRowSet rowSet, String sortSelectKey) throws SQLException {
|
|
|
+ if (!StringUtils.isEmpty(sortSelectKey)) {
|
|
|
+ Object value = rowSet.getObject(sortSelectKey);
|
|
|
+ if (value != null && !StringUtils.isEmpty(String.valueOf(value))) {
|
|
|
+ return String.valueOf(value).trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ private void logSortPreview(List<Map<String, String>> rowList) {
|
|
|
+ if (rowList == null || rowList.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ StringBuilder preview = new StringBuilder();
|
|
|
+ for (Map<String, String> row : rowList) {
|
|
|
+ if (preview.length() > 0) {
|
|
|
+ preview.append(" | ");
|
|
|
+ }
|
|
|
+ preview.append(row.get(ROW_SORT_VALUE));
|
|
|
+ }
|
|
|
+ LOGGER.info("ResumeWordTemplateServiceImplEx.multiNotOne: sorted by " + PERSON_FAMILY_SORT_FIELD
|
|
|
+ + ", sortValues=[" + preview + "], count=" + rowList.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sortRowList(List<Map<String, String>> rowList) {
|
|
|
+ if (rowList == null || rowList.size() <= 1) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Collections.sort(rowList, new Comparator<Map<String, String>>() {
|
|
|
+ @Override
|
|
|
+ public int compare(Map<String, String> left, Map<String, String> right) {
|
|
|
+ String leftValue = left.get(ROW_SORT_VALUE);
|
|
|
+ String rightValue = right.get(ROW_SORT_VALUE);
|
|
|
+ if (leftValue == null) {
|
|
|
+ leftValue = "";
|
|
|
+ }
|
|
|
+ if (rightValue == null) {
|
|
|
+ rightValue = "";
|
|
|
+ }
|
|
|
+ return leftValue.compareTo(rightValue);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void applyPersonFamilyRowLimit(String entityKey, List<Map<String, String>> rowList) {
|
|
|
+ if (PERSON_FAMILY_ROW_LIMIT <= 0 || rowList == null || rowList.isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!isPersonFamilyEntityKey(entityKey)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (rowList.size() > PERSON_FAMILY_ROW_LIMIT) {
|
|
|
+ rowList.subList(PERSON_FAMILY_ROW_LIMIT, rowList.size()).clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|