|
|
@@ -0,0 +1,336 @@
|
|
|
+package com.uas.report;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.uas.report.annotation.DynamicValue;
|
|
|
+import com.uas.report.model.ExportType;
|
|
|
+import com.uas.report.util.FileUtils;
|
|
|
+import com.uas.report.util.ObjectUtils;
|
|
|
+import com.uas.report.util.ResourceUtils;
|
|
|
+import com.uas.report.util.StringUtils;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.lang.reflect.Field;
|
|
|
+import java.net.URL;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Properties;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 不同环境下的配置信息(来自自定义的配置文件)
|
|
|
+ *
|
|
|
+ * @author sunyj
|
|
|
+ * @since 2017年1月10日 下午3:32:30
|
|
|
+ */
|
|
|
+@Component
|
|
|
+public class DynamicProperties {
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置文件名称
|
|
|
+ */
|
|
|
+ private static final String PROPERTY_FILE_NAME = "report.properties";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录配置文件最后修改时间
|
|
|
+ */
|
|
|
+ private long propertyFileLastModified;
|
|
|
+
|
|
|
+ private Logger logger = LoggerFactory.getLogger(getClass());
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 本地资源根路径
|
|
|
+ */
|
|
|
+ @DynamicValue("localBaseDir")
|
|
|
+ private String localBaseDir;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 本地资源图片路径
|
|
|
+ */
|
|
|
+ @DynamicValue("localImagesDir")
|
|
|
+ private String localImagesDir;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 本地资源jrxml模板路径
|
|
|
+ */
|
|
|
+ @DynamicValue("localJrxmlDir")
|
|
|
+ private String localJrxmlDir;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 标准账套(存放标准模板)
|
|
|
+ */
|
|
|
+ @DynamicValue("standardMaster")
|
|
|
+ private String standardMaster;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 本地是否拥有标准模板
|
|
|
+ */
|
|
|
+ @DynamicValue("hasStandardJrxmls")
|
|
|
+ private Boolean hasStandardJrxmls;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 标准模板地址
|
|
|
+ */
|
|
|
+ @DynamicValue("standardJrxmlsUrl")
|
|
|
+ private String standardJrxmlsUrl;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 主账套与其子帐套是否共用模板
|
|
|
+ */
|
|
|
+ @DynamicValue("shareJrxmlsWithSubMaster")
|
|
|
+ private Boolean shareJrxmlsWithSubMaster;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 数据源配置信息
|
|
|
+ */
|
|
|
+ @DynamicValue("datasource")
|
|
|
+ private JSONObject dataSourceInformation;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * PC端支持打印的最大记录行数
|
|
|
+ */
|
|
|
+ @DynamicValue("max-record-size.pc")
|
|
|
+ private int maxRecordSizePc;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 手机端支持打印的最大记录行数
|
|
|
+ */
|
|
|
+ @DynamicValue("max-record-size.phone")
|
|
|
+ private int maxRecordSizePhone;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否使用 xlsx
|
|
|
+ */
|
|
|
+ @DynamicValue("use-xlsx")
|
|
|
+ private Boolean useXlsx;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 预览页面所显示的导出按钮
|
|
|
+ */
|
|
|
+ @DynamicValue("page.preview.show-export-buttons")
|
|
|
+ private List<ExportType> pagePreviewShowExportButtons;
|
|
|
+
|
|
|
+ public DynamicProperties() {
|
|
|
+ mayLoad();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加载配置
|
|
|
+ */
|
|
|
+ private void mayLoad() {
|
|
|
+ try {
|
|
|
+ File propertyFile = new File(PROPERTY_FILE_NAME);
|
|
|
+ if (!propertyFile.exists()) {
|
|
|
+ // 配置文件不存在时,加载旧的配置文件(以兼容旧的配置方式)
|
|
|
+ // TODO temporary codes
|
|
|
+ File oldPropertyFile = new File("application.properties");
|
|
|
+ if (oldPropertyFile.exists() && oldPropertyFile.isFile()) {
|
|
|
+ FileUtils.copy(oldPropertyFile, propertyFile);
|
|
|
+ } else {
|
|
|
+ // 复制类路径下默认的配置文件
|
|
|
+ File defaultPropertyFile = ResourceUtils.getFile(PROPERTY_FILE_NAME);
|
|
|
+ if (defaultPropertyFile == null) {
|
|
|
+ throw new FileNotFoundException("配置文件不存在:" + PROPERTY_FILE_NAME);
|
|
|
+ }
|
|
|
+ // 是否以 spring boot jar 形式运行
|
|
|
+ URL location = getClass().getProtectionDomain().getCodeSource().getLocation();
|
|
|
+ if (org.springframework.util.ResourceUtils.isJarURL(location)) {
|
|
|
+ // 以 spring boot jar 形式运行时,不能直接复制默认配置文件,需以输入流的方式读取默认配置
|
|
|
+ InputStream inputStream = getClass().getResourceAsStream("/" + PROPERTY_FILE_NAME);
|
|
|
+ byte[] data = new byte[inputStream.available()];
|
|
|
+ inputStream.read(data);
|
|
|
+ FileUtils.write(propertyFile.getPath(), data);
|
|
|
+ }else{
|
|
|
+ FileUtils.copy(defaultPropertyFile, propertyFile);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(propertyFile.isDirectory()){
|
|
|
+ throw new IOException("并非文件:" + PROPERTY_FILE_NAME);
|
|
|
+ }
|
|
|
+ long lastModified = propertyFile.lastModified();
|
|
|
+ // 如果配置文件有修改,就重新加载
|
|
|
+ if (propertyFileLastModified >= lastModified) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info("加载配置 " + PROPERTY_FILE_NAME + "...");
|
|
|
+ propertyFileLastModified = propertyFile.lastModified();
|
|
|
+ Properties properties = new Properties();
|
|
|
+ properties.load(new FileInputStream(propertyFile));
|
|
|
+
|
|
|
+ // TODO temporary codes
|
|
|
+ if(!properties.containsKey("max-record-size.pc")){
|
|
|
+ properties.put("max-record-size.pc", "100000");
|
|
|
+ properties.store(new FileOutputStream(propertyFile), "report properties updated on");
|
|
|
+ }
|
|
|
+ if(!properties.containsKey("max-record-size.phone")){
|
|
|
+ properties.put("max-record-size.phone", "10000");
|
|
|
+ properties.store(new FileOutputStream(propertyFile), "report properties updated on");
|
|
|
+ }
|
|
|
+ if(!properties.containsKey("use-xlsx")){
|
|
|
+ properties.put("use-xlsx", "false");
|
|
|
+ properties.store(new FileOutputStream(propertyFile), "report properties updated on");
|
|
|
+ }
|
|
|
+ if(!properties.containsKey("page.preview.show-export-buttons")){
|
|
|
+ properties.put("page.preview.show-export-buttons", "PDF, XLS, XLS_DATA");
|
|
|
+ properties.store(new FileOutputStream(propertyFile), "report properties updated on");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过反射注入配置
|
|
|
+ Field[] declaredFields = getClass().getDeclaredFields();
|
|
|
+ for (Field declaredField : declaredFields) {
|
|
|
+ DynamicValue dynamicValue = declaredField.getAnnotation(DynamicValue.class);
|
|
|
+ if (dynamicValue == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String expression = dynamicValue.value();
|
|
|
+ if (StringUtils.isEmpty(expression)) {
|
|
|
+ throw new IllegalStateException("配置项的表达式为空:" + declaredField.getName() + "=" + expression);
|
|
|
+ }
|
|
|
+ Object value = properties.get(expression);
|
|
|
+ if (ObjectUtils.isEmpty(value)) {
|
|
|
+ throw new IllegalArgumentException("配置项的值为空:" + expression + "=" + value);
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ ObjectUtils.setValue(this, declaredField, value);
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
+ throw new IllegalStateException("通过反射注入配置失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new IllegalStateException("配置加载失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新配置
|
|
|
+ *
|
|
|
+ * @param json json 格式的配置
|
|
|
+ */
|
|
|
+ public void update(String json) {
|
|
|
+ if (StringUtils.isEmpty(json)) {
|
|
|
+ throw new IllegalArgumentException("json 为空");
|
|
|
+ }
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(json);
|
|
|
+ // 更新 json 中指定的配置项
|
|
|
+ Set<Map.Entry<String, Object>> entrySet = jsonObject.entrySet();
|
|
|
+ for (Map.Entry<String, Object> entry : entrySet) {
|
|
|
+ String key = entry.getKey();
|
|
|
+ Object value = entry.getValue();
|
|
|
+ if (ObjectUtils.isEmpty(value)) {
|
|
|
+ throw new IllegalArgumentException("参数值为空:" + entry);
|
|
|
+ }
|
|
|
+ Field field;
|
|
|
+ try {
|
|
|
+ field = getClass().getDeclaredField(key);
|
|
|
+ ObjectUtils.setValue(this, field, value);
|
|
|
+ } catch (NoSuchFieldException e) {
|
|
|
+ throw new IllegalArgumentException("不支持配置项:" + key, e);
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
+ throw new IllegalStateException("通过反射修改配置失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ save();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 保存配置
|
|
|
+ */
|
|
|
+ private void save() {
|
|
|
+ try {
|
|
|
+ Properties properties = new Properties();
|
|
|
+ Field[] declaredFields = getClass().getDeclaredFields();
|
|
|
+ // 通过反射读取所有配置,写入本地文件
|
|
|
+ for (Field declaredField : declaredFields) {
|
|
|
+ DynamicValue dynamicValue = declaredField.getAnnotation(DynamicValue.class);
|
|
|
+ if (dynamicValue == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String expression = dynamicValue.value();
|
|
|
+ if (StringUtils.isEmpty(expression)) {
|
|
|
+ throw new IllegalStateException("配置项的表达式为空:" + declaredField.getName() + "=" + expression);
|
|
|
+ }
|
|
|
+ Object value = ObjectUtils.getValue(declaredField, this);
|
|
|
+ if (ObjectUtils.isEmpty(value)) {
|
|
|
+ throw new IllegalArgumentException("配置项的值为空:" + expression + "=" + value);
|
|
|
+ }
|
|
|
+ // List 直接 toString,结果中会带 '[]'
|
|
|
+ if (value instanceof List) {
|
|
|
+ List list = (List) value;
|
|
|
+ StringBuilder builder = new StringBuilder();
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ if (i != 0) {
|
|
|
+ builder.append(", ");
|
|
|
+ }
|
|
|
+ builder.append(list.get(i));
|
|
|
+ }
|
|
|
+ properties.setProperty(expression, builder.toString());
|
|
|
+ } else {
|
|
|
+ properties.setProperty(expression, value.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ properties.store(new FileOutputStream(new File(PROPERTY_FILE_NAME)), "report properties updated on");
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new IllegalStateException("配置保存失败", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getLocalBaseDir() {
|
|
|
+ mayLoad();
|
|
|
+ return localBaseDir;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getLocalImagesDir() {
|
|
|
+ mayLoad();
|
|
|
+ return localImagesDir;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getLocalJrxmlDir() {
|
|
|
+ mayLoad();
|
|
|
+ return localJrxmlDir;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getStandardMaster() {
|
|
|
+ mayLoad();
|
|
|
+ return standardMaster;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Boolean getHasStandardJrxmls() {
|
|
|
+ mayLoad();
|
|
|
+ return hasStandardJrxmls;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getStandardJrxmlsUrl() {
|
|
|
+ mayLoad();
|
|
|
+ return standardJrxmlsUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Boolean getShareJrxmlsWithSubMaster() {
|
|
|
+ mayLoad();
|
|
|
+ return shareJrxmlsWithSubMaster;
|
|
|
+ }
|
|
|
+
|
|
|
+ public JSONObject getDataSourceInformation() {
|
|
|
+ mayLoad();
|
|
|
+ return dataSourceInformation;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getMaxRecordSizePc() {
|
|
|
+ return maxRecordSizePc;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getMaxRecordSizePhone() {
|
|
|
+ return maxRecordSizePhone;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Boolean getUseXlsx() {
|
|
|
+ return useXlsx;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<ExportType> getPagePreviewShowExportButtons() {
|
|
|
+ return pagePreviewShowExportButtons;
|
|
|
+ }
|
|
|
+}
|