Prechádzať zdrojové kódy

change the way of configuration

sunyj 8 rokov pred
rodič
commit
0b9d7712e8

+ 165 - 50
report/src/main/java/com/uas/report/SpecialProperties.java

@@ -1,127 +1,242 @@
 package com.uas.report;
 
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Configuration;
+import com.alibaba.fastjson.JSONObject;
+import com.uas.report.annotation.DynamicValue;
+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.util.Map;
+import java.util.Properties;
+import java.util.Set;
 
 /**
- * 不同环境下的配置信息(来自spring cloud)
- * 
+ * 不同环境下的配置信息(来自自定义的配置文件
+ *
  * @author sunyj
  * @since 2017年1月10日 下午3:32:30
  */
-@Configuration
+@Component
 public class SpecialProperties {
 
-	/**
+    /**
+     * 配置文件名称
+     */
+    private static final String PROPERTY_FILE_NAME = "report.properties";
+
+    /**
+     * 记录配置文件最后修改时间
+     */
+    private long propertyFileLastModified;
+
+    private Logger logger = LoggerFactory.getLogger(getClass());
+
+    /**
 	 * 本地资源根路径
 	 */
-	@Value("${localBaseDir}")
+	@DynamicValue("localBaseDir")
 	private String localBaseDir;
 
 	/**
 	 * 本地资源图片路径
 	 */
-	@Value("${localImagesDir}")
+	@DynamicValue("localImagesDir")
 	private String localImagesDir;
 
 	/**
 	 * 本地资源jrxml模板路径
 	 */
-	@Value("${localJrxmlDir}")
+	@DynamicValue("localJrxmlDir")
 	private String localJrxmlDir;
 
 	/**
 	 * 标准账套(存放标准模板)
 	 */
-	@Value("${standardMaster}")
+	@DynamicValue("standardMaster")
 	private String standardMaster;
 
 	/**
 	 * 本地是否拥有标准模板
 	 */
-	@Value("${hasStandardJrxmls}")
+	@DynamicValue("hasStandardJrxmls")
 	private boolean hasStandardJrxmls;
 
 	/**
 	 * 标准模板地址
 	 */
-	@Value("${standardJrxmlsUrl}")
+	@DynamicValue("standardJrxmlsUrl")
 	private String standardJrxmlsUrl;
 
 	/**
 	 * 主账套与其子帐套是否共用模板
 	 */
-	@Value("${shareJrxmlsWithSubMaster}")
+	@DynamicValue("shareJrxmlsWithSubMaster")
 	private boolean shareJrxmlsWithSubMaster;
 
 	/**
 	 * 数据源配置信息
 	 */
-	@Value("${datasource}")
+	@DynamicValue("datasource")
 	private String dataSourceInformation;
 
-	public String getLocalBaseDir() {
+    public SpecialProperties() {
+        mayLoad();
+    }
+
+    /**
+     * 加载配置
+     */
+    private void mayLoad() {
+        try {
+            File propertyFile = new File(PROPERTY_FILE_NAME);
+            if (!propertyFile.exists()) {
+                // 复制类路径下默认的配置文件
+                File defaultPropertyFile = ResourceUtils.getFile(PROPERTY_FILE_NAME);
+                if (defaultPropertyFile == null) {
+                    throw new FileNotFoundException("配置文件不存在:" + PROPERTY_FILE_NAME);
+                }
+                FileUtils.copy(defaultPropertyFile, propertyFile);
+            }
+            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));
+
+            // 通过反射注入配置
+            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);
+                }
+                properties.setProperty(expression, value.toString());
+            }
+            properties.store(new FileOutputStream(new File(PROPERTY_FILE_NAME)), "report properties");
+        } catch (IOException e) {
+            throw new IllegalStateException("配置保存失败", e);
+        }
+    }
+
+    public String getLocalBaseDir() {
+        mayLoad();
 		return localBaseDir;
 	}
 
-	public void setLocalBaseDir(String localBaseDir) {
-		this.localBaseDir = localBaseDir;
-	}
-
 	public String getLocalImagesDir() {
+        mayLoad();
 		return localImagesDir;
 	}
 
-	public void setLocalImagesDir(String localImagesDir) {
-		this.localImagesDir = localImagesDir;
-	}
-
 	public String getLocalJrxmlDir() {
+        mayLoad();
 		return localJrxmlDir;
 	}
 
-	public void setLocalJrxmlDir(String localJrxmlDir) {
-		this.localJrxmlDir = localJrxmlDir;
-	}
-
 	public String getStandardMaster() {
+        mayLoad();
 		return standardMaster;
 	}
 
-	public void setStandardMaster(String standardMaster) {
-		this.standardMaster = standardMaster;
-	}
-
-	public boolean hasStandardJrxmls() {
+	public boolean getHasStandardJrxmls() {
+        mayLoad();
 		return hasStandardJrxmls;
 	}
 
-	public void setHasStandardJrxmls(boolean hasStandardJrxmls) {
-		this.hasStandardJrxmls = hasStandardJrxmls;
-	}
-
 	public String getStandardJrxmlsUrl() {
+        mayLoad();
 		return standardJrxmlsUrl;
 	}
 
-	public void setStandardJrxmlsUrl(String standardJrxmlsUrl) {
-		this.standardJrxmlsUrl = standardJrxmlsUrl;
-	}
-
-	public boolean shareJrxmlsWithSubMaster() {
+	public boolean getShareJrxmlsWithSubMaster() {
+        mayLoad();
 		return shareJrxmlsWithSubMaster;
 	}
 
-	public void setShareJrxmlsWithSubMaster(boolean shareJrxmlsWithSubMaster) {
-		this.shareJrxmlsWithSubMaster = shareJrxmlsWithSubMaster;
-	}
-
 	public String getDataSourceInformation() {
+        mayLoad();
 		return dataSourceInformation;
 	}
-
-	public void setDataSourceInformation(String dataSourceInformation) {
-		this.dataSourceInformation = dataSourceInformation;
-	}
-
 }

+ 22 - 0
report/src/main/java/com/uas/report/annotation/DynamicValue.java

@@ -0,0 +1,22 @@
+package com.uas.report.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation at the field level that indicates a default value expression for the affected argument.
+ *
+ * @author sunyj
+ * @since 2017/12/20 9:16
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DynamicValue {
+
+    /**
+     * The actual value expression: e.g. "#{systemProperties.myProp}".
+     */
+    String value() default "";
+}

+ 36 - 0
report/src/main/java/com/uas/report/controller/PropertiesController.java

@@ -0,0 +1,36 @@
+package com.uas.report.controller;
+
+import com.uas.report.SpecialProperties;
+import org.apache.catalina.servlet4preview.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * 配置修改
+ *
+ * @author sunyj
+ * @since 2017/12/20 14:47
+ */
+@Controller
+@RequestMapping("/properties")
+public class PropertiesController {
+
+    @Autowired
+    private SpecialProperties specialProperties;
+
+    @RequestMapping("/get")
+    @ResponseBody
+    public SpecialProperties get(HttpServletRequest request) {
+        return specialProperties;
+    }
+
+    @RequestMapping("/update")
+    @ResponseBody
+    public boolean update(@RequestParam String json, HttpServletRequest request) {
+        specialProperties.update(json);
+        return true;
+    }
+}

+ 3 - 3
report/src/main/java/com/uas/report/service/impl/FileServiceImpl.java

@@ -74,7 +74,7 @@ public class FileServiceImpl implements FileService {
 		byte[] data = null;
 		String stantardJrxmlsUrl = String.format(specialProperties.getStandardJrxmlsUrl(), sourceUserName);
 		// 如果本机提供标准模板下载,直接从本地获取数据
-		if (specialProperties.hasStandardJrxmls()) {
+		if (specialProperties.getHasStandardJrxmls()) {
 			data = getStandardJrxmls(sourceUserName);
 		}
 		// 本机没有标准模板,则先下载标准模板数据
@@ -197,7 +197,7 @@ public class FileServiceImpl implements FileService {
 		if (StringUtils.isEmpty(userName)) {
 			throw new IllegalArgumentException("未传入当前账套名称!");
 		}
-		if (!specialProperties.hasStandardJrxmls()) {
+		if (!specialProperties.getHasStandardJrxmls()) {
 			throw new IllegalStateException("没有" + userName + "标准模板!");
 		}
 		try {
@@ -213,7 +213,7 @@ public class FileServiceImpl implements FileService {
 		if (StringUtils.isEmpty(userName)) {
 			throw new IllegalArgumentException("未传入当前账套名称!");
 		}
-		if (!specialProperties.hasStandardJrxmls()) {
+		if (!specialProperties.getHasStandardJrxmls()) {
 			throw new IllegalStateException("没有" + userName + "标准模板!");
 		}
 		downloadZip(specialProperties.getStandardMaster() + "/" + userName, response);

+ 1 - 1
report/src/main/java/com/uas/report/service/impl/PrintServiceImpl.java

@@ -602,7 +602,7 @@ public class PrintServiceImpl implements PrintService {
 			}
 		} else {
 			// 如果主账套与子账套共用模板
-			if (specialProperties.shareJrxmlsWithSubMaster()) {
+			if (specialProperties.getShareJrxmlsWithSubMaster()) {
 				Master master = MasterManager.getMaster(userName);
 				if (master != null) {
 					// 获取账套的主账套

+ 44 - 0
report/src/main/java/com/uas/report/util/ObjectUtils.java

@@ -1,8 +1,10 @@
 package com.uas.report.util;
 
 import com.alibaba.fastjson.JSONArray;
+
 import java.io.*;
 import java.lang.reflect.Field;
+import java.lang.reflect.Type;
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -299,4 +301,46 @@ public class ObjectUtils {
 		}
 		return fields;
 	}
+
+    /**
+     * 通过反射为指定的字段赋值
+     *
+     * @param object 对象
+     * @param field  字段
+     * @param value  值
+     * @throws IllegalAccessException
+     */
+    public static void setValue(Object object, Field field, Object value) throws IllegalAccessException {
+        if (object == null || field == null) {
+            throw new IllegalArgumentException("object 或 field 为空");
+        }
+        if (value != null) {
+            Type type = field.getGenericType();
+            if (type.toString().equals("class java.lang.String")) {
+            } else if (type.toString().equals("class java.lang.Long") || type.toString().equals("long")) {
+                value = Long.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Integer") || type.toString().equals("int")) {
+                value = Integer.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Short") || type.toString().equals("short")) {
+                value = Short.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Double") || type.toString().equals("double")) {
+                value = Double.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Float") || type.toString().equals("float")) {
+                value = Float.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Byte") || type.toString().equals("byte")) {
+                value = Byte.valueOf(value.toString());
+            } else if (type.toString().equals("class java.lang.Boolean") || type.toString().equals("boolean")) {
+                value = Boolean.valueOf(value.toString());
+            } else {
+                throw new IllegalArgumentException("不支持的类型:type=" + type + ", value=" + value);
+            }
+        }
+        if (!field.isAccessible()) {
+            field.setAccessible(true);
+            field.set(object, value);
+            field.setAccessible(false);
+        } else {
+            field.set(object, value);
+        }
+    }
 }

+ 9 - 0
report/src/main/resources/report.properties

@@ -0,0 +1,9 @@
+localBaseDir=/home/uas/data/reports
+localImagesDir=/Picture
+localJrxmlDir=/jrxml
+standardMaster=STANDARD_MASTER
+hasStandardJrxmls=false
+standardJrxmlsUrl=http://print.ubtob.com/report/file/standardJrxmls?userName=%s&onlyData=1
+shareJrxmlsWithSubMaster=false
+
+datasource={"UAS":{"driverClassName":"oracle.jdbc.driver.OracleDriver","url":"jdbc:oracle:thin:@127.0.0.1:1521:orcl","username":"UAS","password":"select!#%*(","initialSize":1,"minIdle":0,"maxActive":20,"maxWait":60000,"timeBetweenEvictionRunsMillis":60000,"minEvictableIdleTimeMillis":300000,"validationQuery":"SELECT 1 FROM DUAL","testWhileIdle":true,"testOnBorrow":true,"testOnReturn":false,"removeAbandoned":true,"removeAbandonedTimeout":120,"logAbandoned":true,"timeBetweenLogStatsMillis":600000,"poolPreparedStatements":true,"maxPoolPreparedStatementPerConnectionSize":20,"filters":"stat,slf4j","connectionProperties":"druid.stat.mergeSql=false;druid.stat.slowSqlMillis=5000"}}

+ 5 - 0
report/src/main/webapp/WEB-INF/views/console.html

@@ -96,6 +96,11 @@
 					<li><a target="_blank">print?userName=B2B/10005740&profile=test&reportName=PURCLIST&whereCondition=where rownum<30</a></li>
 					<li><a target="_blank">fileUpload?userName=B2B/1111</a></li>
 				</ol>
+                <strong><li class="title2">配置</li></strong>
+                <ol>
+                    <li><a target="_blank">properties/get</a></li>
+                    <li><a target="_blank">properties/update?json={"hasStandardJrxmls": false}</a></li>
+                </ol>
 			</ol>
 
 			<h2>5.定时任务</h2>