package org.hsweb.web.service.impl.form;
import com.alibaba.fastjson.JSON;
import org.hsweb.commons.StringUtils;
import org.hsweb.concurrent.lock.annotation.LockName;
import org.hsweb.concurrent.lock.annotation.ReadLock;
import org.hsweb.concurrent.lock.annotation.WriteLock;
import org.hsweb.expands.office.excel.ExcelIO;
import org.hsweb.expands.office.excel.config.Header;
import org.hsweb.ezorm.core.*;
import org.hsweb.ezorm.rdb.RDBDatabase;
import org.hsweb.ezorm.rdb.RDBQuery;
import org.hsweb.ezorm.rdb.RDBTable;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.rdb.meta.builder.TableBuilder;
import org.hsweb.ezorm.rdb.meta.builder.simple.SimpleTableBuilder;
import org.hsweb.ezorm.rdb.meta.parser.TableMetaParser;
import org.hsweb.web.bean.common.DeleteParam;
import org.hsweb.web.bean.common.PagerResult;
import org.hsweb.web.bean.common.QueryParam;
import org.hsweb.web.bean.common.UpdateParam;
import org.hsweb.web.bean.po.GenericPo;
import org.hsweb.web.bean.po.form.Form;
import org.hsweb.web.bean.po.history.History;
import org.hsweb.web.core.authorize.ExpressionScopeBean;
import org.hsweb.web.core.exception.BusinessException;
import org.hsweb.web.core.exception.NotFoundException;
import org.hsweb.web.service.form.DynamicFormDataValidator;
import org.hsweb.web.service.form.DynamicFormService;
import org.hsweb.web.service.form.FormParser;
import org.hsweb.web.service.form.FormService;
import org.hsweb.web.service.history.HistoryService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.*;
/**
* Created by zhouhao on 16-4-14.
*/
@Service("dynamicFormService")
@Transactional(rollbackFor = Throwable.class)
public class DynamicFormServiceImpl implements DynamicFormService, ExpressionScopeBean {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired(required = false)
protected FormParser formParser;
@Autowired
protected RDBDatabase database;
@Resource
protected FormService formService;
@Resource
protected HistoryService historyService;
@Autowired(required = false)
protected List<DynamicFormDataValidator> dynamicFormDataValidator;
@Autowired(required = false)
protected Map<String, ExpressionScopeBean> expressionScopeBeanMap;
@Autowired(required = false)
protected TableMetaParser tableMetaParser;
protected void initDefaultField(RDBTableMetaData metaData) {
metaData.setDatabaseMetaData(database.getMeta());
TableBuilder builder = new SimpleTableBuilder(metaData, database, null);
builder.addColumn().name("u_id").varchar(32).primaryKey().comment("主键").commit();
metaData.setProperty("primaryKey", "u_id");
}
@Override
public RDBDatabase getDefaultDatabase() {
return database;
}
@Override
public RDBTableMetaData parseMeta(Form form) {
RDBTableMetaData metaData = formParser.parse(form);
initDefaultField(metaData);
return metaData;
}
@Override
@WriteLock
@LockName(value = "'form.lock.'+#form.name", isExpression = true)
public void deploy(Form form) throws SQLException {
RDBTableMetaData metaData = formParser.parse(form);
metaData.setProperty("version", form.getRevision());
initDefaultField(metaData);
RDBTableMetaData lastDeployMetaData;
if (tableMetaParser == null) {
History history = historyService.selectLastHistoryByType("form.deploy." + form.getName());
Form lastDeploy = JSON.parseObject(history.getChangeAfter(), Form.class);
lastDeployMetaData = formParser.parse(lastDeploy);
initDefaultField(lastDeployMetaData);
} else {
lastDeployMetaData = tableMetaParser.parse(form.getName());
}
//首次部署
if (lastDeployMetaData == null || lastDeployMetaData.getColumns().isEmpty()) {
try {
database.createTable(metaData);
} catch (Exception e) {
throw new BusinessException("发布失败:" + e.getMessage());
}
} else {
//向上发布
database.reloadTable(lastDeployMetaData);//先放入旧的结构
//更新结构
database.alterTable(metaData);
}
}
@Override
@WriteLock
@LockName(value = "'form.lock.'+#form.name", isExpression = true)
public void unDeploy(Form form) {
database.removeTable(form.getName());
}
public <T> RDBTable<T> getTableByName(String name) {
try {
RDBTable<T> table = database.getTable(name);
if (table == null) {
throw new NotFoundException("表单[" + name + "]不存在");
}
return table;
} catch (Exception e) {
throw new NotFoundException("表单[" + name + "]不存在");
}
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
@Transactional(readOnly = true)
public <T> PagerResult<T> selectPager(String name, QueryParam param) throws SQLException {
PagerResult<T> result = new PagerResult<>();
RDBTable<T> table = getTableByName(name);
RDBQuery<T> query = table.createQuery();
query.setParam(param);
int total = query.total();
result.setTotal(total);
if (total == 0) {
result.setData(new ArrayList<>());
} else {
//根据实际记录数量重新指定分页参数
param.rePaging(total);
result.setData(query.list(param.getPageIndex(), param.getPageSize()));
}
return result;
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
@Transactional(readOnly = true)
public <T> List<T> select(String name, QueryParam param) throws SQLException {
RDBTable<T> table = getTableByName(name);
RDBQuery<T> query = table.createQuery().setParam(param);
return query.list();
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
@Transactional(readOnly = true)
public int total(String name, QueryParam param) throws SQLException {
RDBTable table = getTableByName(name);
RDBQuery query = table.createQuery().setParam(param);
return query.total();
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public String insert(String name, Map<String, Object> data) throws SQLException {
RDBTable table = getTableByName(name);
String primaryKeyName = getPrimaryKeyName(name);
String pk = GenericPo.createUID();
data.put(primaryKeyName, pk);
Insert insert = table.createInsert().value(data);
insert.exec();
return pk;
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public List<String> insert(String name, List<Map<String, Object>> dataList) throws SQLException {
RDBTable table = getTableByName(name);
String primaryKeyName = getPrimaryKeyName(name);
List<String> idList = new ArrayList<>();
dataList.forEach(data -> {
String pk = GenericPo.createUID();
data.put(primaryKeyName, pk);
idList.add(pk);
});
table.createInsert().values(dataList).exec();
return idList;
}
@Override
public String saveOrUpdate(String name, Map<String, Object> data) throws SQLException {
String id = (String) data.get(getPrimaryKeyName(name));
if (id == null)
id = getRepeatDataId(name, data);
if (id != null) {
updateByPk(name, id, UpdateParam.build(data));
} else {
id = insert(name, data);
}
return id;
}
@Override
public String saveOrUpdate(String name, List<Map<String, Object>> map) throws SQLException {
StringBuilder builder = new StringBuilder();
for (Map<String, Object> objectMap : map) {
String id = saveOrUpdate(name, objectMap);
builder.append(id).append(",");
}
return builder.substring(0, builder.length());
}
protected String getRepeatDataId(String name, Map<String, Object> data) {
RDBTable table = getTableByName(name);
if (dynamicFormDataValidator != null) {
for (DynamicFormDataValidator validator : dynamicFormDataValidator) {
String id = validator.getRepeatDataId(table, data);
if (id != null) {
return id;
}
}
}
return null;
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public boolean deleteByPk(String name, String pk) throws SQLException {
String primaryKeyName = getPrimaryKeyName(name);
RDBTable table = getTableByName(name);
Delete delete = table.createDelete().where(primaryKeyName, pk);
return delete.exec() == 1;
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public int delete(String name, DeleteParam where) throws SQLException {
RDBTable table = getTableByName(name);
Delete delete = table.createDelete();
delete.setParam(where);
return delete.exec();
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public int updateByPk(String name, String pk, UpdateParam<Map<String, Object>> param) throws SQLException {
RDBTable table = getTableByName(name);
String pkName = getPrimaryKeyName(name);
Update update = table.createUpdate().setParam(param);
((Map) param.getData()).put(pkName, pk);
update.where(pkName, pk);
return update.exec();
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public int update(String name, UpdateParam<Map<String, Object>> param) throws SQLException {
RDBTable table = getTableByName(name);
Update update = table.createUpdate().setParam(param);
return update.exec();
}
@ReadLock
@LockName(value = "'form.lock.'+#tableName", isExpression = true)
public String getPrimaryKeyName(String tableName) {
RDBTable table = getTableByName(tableName);
return table.getMeta().getProperty("primaryKey", "u_id").toString();
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public <T> T selectByPk(String name, Object pk) throws SQLException {
Table<T> table = getTableByName(name);
Query<T> query = table.createQuery().where(getPrimaryKeyName(name), pk);
return query.single();
}
protected void putExcelHeader(String fieldPrefix, RDBColumnMetaData fieldMetaData, List<Header> headers) {
if (fieldMetaData == null) return;
PropertyWrapper valueWrapper = fieldMetaData.getProperty("export-excel", false);
if (fieldPrefix.length() > 0) fieldPrefix += ".";
if (valueWrapper.isTrue()) {
String title = fieldMetaData.getProperty("excel-header").getValue();
if (StringUtils.isNullOrEmpty(title)) {
title = fieldMetaData.getComment();
}
if (StringUtils.isNullOrEmpty(title)) {
title = fieldMetaData.getName();
}
String field = fieldMetaData.getName();
OptionConverter converter = fieldMetaData.getOptionConverter();
if (converter != null) {
field = converter.getFieldName();
}
headers.add(new Header(title, fieldPrefix + field));
}
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
@Transactional(readOnly = true)
public void exportExcel(String name, QueryParam param, OutputStream outputStream) throws Exception {
List<Object> dataList = select(name, param);
RDBTable table = getTableByName(name);
RDBTableMetaData metaData = table.getMeta();
List<Header> headers = new LinkedList<>();
Map<String, Object> sample = dataList.isEmpty() ? new HashMap<>() : (Map) dataList.get(0);
sample.forEach((key, value) -> {
if (value instanceof Map) {
((Map) value).forEach((k, v) -> {
String fieldName = key + "." + k;
RDBColumnMetaData field = metaData.findColumn(fieldName);
putExcelHeader(fieldName, field, headers);
});
} else {
RDBColumnMetaData field = metaData.findColumn(key);
putExcelHeader("", field, headers);
}
});
if (metaData.triggerIsSupport("export.excel")) {
Map<String, Object> var = new HashMap<>();
if (expressionScopeBeanMap != null)
var.putAll(expressionScopeBeanMap);
var.put("database", database);
var.put("table", table);
var.put("dataList", dataList);
var.put("headers", headers);
metaData.on("export.excel", var);
}
ExcelIO.write(outputStream, headers, dataList);
}
@Override
@ReadLock
@LockName(value = "'form.lock.'+#name", isExpression = true)
public Map<String, Object> importExcel(String name, InputStream inputStream) {
RDBTable<Map<String, Object>> table = getTableByName(name);
Map<String, Object> result = new HashMap<>();
long startTime = System.currentTimeMillis();
List<Map<String, Object>> excelData;
try {
excelData = ExcelIO.read2Map(inputStream);
} catch (Exception e) {
throw new BusinessException("解析excel失败,请确定文件格式正确!", e, 500);
}
List<Map<String, Object>> dataList = new LinkedList<>();
Map<String, String> headerMapper = new HashMap<>();
RDBTableMetaData metaData = table.getMeta();
metaData.getColumns().forEach(fieldMetaData -> {
PropertyWrapper valueWrapper = fieldMetaData.getProperty("importExcel", true);
if (valueWrapper.isTrue()) {
String title = fieldMetaData.getProperty("excel-header").getValue();
if (StringUtils.isNullOrEmpty(title)) {
title = fieldMetaData.getComment();
}
if (StringUtils.isNullOrEmpty(title)) {
title = fieldMetaData.getName();
}
String field = fieldMetaData.getName();
headerMapper.put(title, field);
}
});
if (metaData.triggerIsSupport("export.import.before")) {
Map<String, Object> var = new HashMap<>();
var.put("headerMapper", headerMapper);
var.put("excelData", excelData);
var.put("dataList", dataList);
var.put("database", database);
var.put("table", table);
if (expressionScopeBeanMap != null)
var.putAll(expressionScopeBeanMap);
metaData.on("export.import.before", var);
}
excelData.forEach(data -> {
Map<String, Object> newData = new HashMap<>();
data.forEach((k, v) -> {
String field = headerMapper.get(k);
if (field != null) {
newData.put(field, v);
} else {
newData.put(k, v);
}
});
dataList.add(newData);
});
List<Map<String, Object>> errorMessage = new LinkedList<>();
int index = 0, success = 0;
for (Map<String, Object> map : dataList) {
index++;
try {
if (metaData.triggerIsSupport("export.import.each")) {
Map<String, Object> var = new HashMap<>();
var.put("headerMapper", headerMapper);
var.put("excelData", excelData);
var.put("dataList", dataList);
var.put("data", map);
var.put("database", database);
var.put("table", table);
if (expressionScopeBeanMap != null)
var.putAll(expressionScopeBeanMap);
metaData.on("export.import.each", var);
}
saveOrUpdate(name, map);
success++;
} catch (Exception e) {
Map<String, Object> errorMsg = new HashMap<>();
errorMsg.put("index", index);
errorMsg.put("message", e.getMessage());
errorMessage.add(errorMsg);
}
}
long endTime = System.currentTimeMillis();
result.put("startTime", startTime);
result.put("endTime", endTime);
result.put("total", dataList.size());
result.put("success", success);
result.put("errorMessage", errorMessage);
return result;
}
}