roo00 6 anos atrás
pai
commit
ee45786202
100 arquivos alterados com 4758 adições e 1097 exclusões
  1. 17 0
      o2server/x_attendance_assemble_control/pom.xml
  2. 449 23
      o2server/x_attendance_assemble_control/src/main/webapp/jest/describe.js
  3. 9 8
      o2server/x_attendance_assemble_control/src/main/webapp/jest/index.html
  4. 7 6
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceAdmin.java
  5. 2 8
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceScheduleSetting.java
  6. 3 3
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticPersonForMonth.java
  7. 2 2
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticTopUnitForDay.java
  8. 6 5
      o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticUnitForMonth.java
  9. 127 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/container/EntityManagerContainer.java
  10. 1 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/entity/StorageType.java
  11. 13 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/Application.java
  12. 22 8
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/Applications.java
  13. 895 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/annotation/ApiBuilder.java
  14. 2 2
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/annotation/DescribeBuilder.java
  15. 12 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/build/CheckCore.java
  16. 1 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Collect.java
  17. 85 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Communicate.java
  18. 81 22
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java
  19. 3 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/DumpRestoreData.java
  20. 3 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/DumpRestoreStorage.java
  21. 21 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/LogLevel.java
  22. 21 60
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Messages.java
  23. 8 8
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Node.java
  24. 20 1
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Person.java
  25. 32 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ProcessPlatform.java
  26. 52 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/PushConfig.java
  27. 4 4
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/connection/CipherConnectionAction.java
  28. 0 2
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/gson/GsonPropertyObject.java
  29. 4 2
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/AbstractJaxrsAction.java
  30. 8 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/DescribeFilter.java
  31. 31 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WrapCount.java
  32. 116 10
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/logger/Audit.java
  33. 10 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/message/MessageConnector.java
  34. 24 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/message/PmsInnerMessage.java
  35. 3 2
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/scripting/Scripting.java
  36. 43 9
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/BaseTools.java
  37. 0 221
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/PasswordTools.java
  38. 10 2
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/StringTools.java
  39. 0 25
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_bbs_assemble_control.java
  40. 1 14
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_calendar_assemble_control.java
  41. 0 39
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_cms_assemble_control.java
  42. 0 6
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_component_assemble_control.java
  43. 0 11
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_file_assemble_control.java
  44. 0 7
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_general_assemble_control.java
  45. 13 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_jpush_assemble_control.java
  46. 10 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_jpush_core_entity.java
  47. 0 12
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_meeting_assemble_control.java
  48. 0 11
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_message_assemble_communicate.java
  49. 0 15
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_mind_assemble_control.java
  50. 0 32
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_okr_assemble_control.java
  51. 0 11
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_organization_assemble_authentication.java
  52. 0 14
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_organization_assemble_control.java
  53. 0 13
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_portal_assemble_designer.java
  54. 0 12
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_portal_assemble_surface.java
  55. 3 3
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_assemble_designer.java
  56. 4 50
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_assemble_surface.java
  57. 2 3
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_service_processing.java
  58. 0 36
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_query_assemble_surface.java
  59. 0 24
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_teamwork_assemble_control.java
  60. 17 0
      o2server/x_bbs_assemble_control/pom.xml
  61. 102 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/MessageFactory.java
  62. 15 3
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/ThisApplication.java
  63. 23 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/factory/BBSVoteRecordFactory.java
  64. 2 1
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/attachment/ActionAttachmentDelete.java
  65. 11 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/replyinfo/ActionSave.java
  66. 1 1
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/replyinfo/BaseAction.java
  67. 1 1
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/sectioninfo/ActionListSubSectionByMainSectionId.java
  68. 5 4
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/sectioninfo/ActionSave.java
  69. 10 19
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/subjectinfo/ActionSubjectSubmitVoteResult.java
  70. 129 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/MessageWo.java
  71. 187 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/QueueNewReplyNotify.java
  72. 156 0
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/QueueNewSubjectNotify.java
  73. 21 12
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/service/BBSSectionInfoService.java
  74. 42 17
      o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/service/BBSSubjectVoteService.java
  75. 449 23
      o2server/x_bbs_assemble_control/src/main/webapp/jest/describe.js
  76. 9 8
      o2server/x_bbs_assemble_control/src/main/webapp/jest/index.html
  77. 83 27
      o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSForumInfo.java
  78. 101 40
      o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSSectionInfo.java
  79. 10 0
      o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSVoteRecord.java
  80. 17 0
      o2server/x_calendar_assemble_control/pom.xml
  81. 4 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/AbstractFactory.java
  82. 10 5
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/Business.java
  83. 4 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/ThisApplication.java
  84. 104 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/factory/Calendar_EventCommentFactory.java
  85. 1 1
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/factory/Calendar_EventRepeatMasterFactory.java
  86. 18 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/ActionGet.java
  87. 2 2
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/ActionUpdateSingleEventWithId.java
  88. 6 11
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/BaseAction.java
  89. 103 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/schedule/CheckEventComment.java
  90. 92 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventCommentQueryService.java
  91. 66 0
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventCommentService.java
  92. 27 18
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventRepeatMasterService.java
  93. 4 4
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventRepeatMasterServiceAdv.java
  94. 59 4
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventService.java
  95. 110 19
      o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventServiceAdv.java
  96. 449 23
      o2server/x_calendar_assemble_control/src/main/webapp/jest/describe.js
  97. 9 8
      o2server/x_calendar_assemble_control/src/main/webapp/jest/index.html
  98. 11 38
      o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_Event.java
  99. 85 0
      o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_EventComment.java
  100. 23 56
      o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_EventRepeatMaster.java

+ 17 - 0
o2server/x_attendance_assemble_control/pom.xml

@@ -48,6 +48,23 @@
 							</arguments>
 						</configuration>
 					</execution>
+					<execution>
+						<id>apiBuilder</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>java</goal>
+						</goals>
+						<configuration>
+							<addOutputToClasspath>true</addOutputToClasspath>
+							<includePluginDependencies>true</includePluginDependencies>
+							<includeProjectDependencies>true</includeProjectDependencies>
+							<mainClass>com.x.base.core.project.annotation.ApiBuilder</mainClass>
+							<arguments>
+								<argument>${basedir}</argument>
+								<argument>${project.build.sourceDirectory}</argument>
+							</arguments>
+						</configuration>
+					</execution>
 					<execution>
 						<id>checkAssemble</id>
 						<phase>prepare-package</phase>

+ 449 - 23
o2server/x_attendance_assemble_control/src/main/webapp/jest/describe.js

@@ -157,7 +157,8 @@ Describe.writeOut = function(outs, json) {
 	}
 }
 
-Describe.createSample= function(m) {
+Describe.createSampleMootools = function(m) {
+	debugger;
 	var address = window.location.href;
 	address = address.substring(0,address.indexOf("/jest/"));
 	var address = address +"/"+ m.path;
@@ -179,7 +180,7 @@ Describe.createSample= function(m) {
 	
 	var strSample="";
 	if (m.contentType.indexOf('application/json') > -1) {
-		  strSample =  "var data = {};" + "\n";
+		        strSample =  "var data = {};" + "\n";
 			if (m.ins && m.ins.length > 0) {
 				$.each(m.ins, function(ii, i) {
 					switch (i.type) {
@@ -191,7 +192,12 @@ Describe.createSample= function(m) {
 								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
 							}
 						} else {
-							      strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+							     // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								 if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
 						}
 					}
 				});
@@ -200,18 +206,291 @@ Describe.createSample= function(m) {
 			} else if (m.useStringParameter) {
 				strSample += 'data = "参数";'+"\n";
 			}
+
+			strSample += " \n var mootoolsRequest = new Request({" + "\n";
+		    strSample += "        url:'"+address + "',\n";
+			strSample += "        method:'"+ m.type + "',\n";
+			strSample += "        dataType:'json',\n";
+		    strSample += "        headers : {'Content-Type':'application/json;charset=utf8','x-token':'实际的x-token'}" + ",\n";
+			if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+				strSample += "        data:JSON.stringify(data),\n";
+			}else{
+			  	strSample += "        data:data,\n";
+			}
+            strSample += "        onRequest: function(){ },"+ "\n";
+            strSample += "        onSuccess: function(responseText){},"+ "\n";
+            strSample += "        onFailure: function(){}"+ "\n";
+           strSample +="}).send();"+ "\n";
+	} else {
+		/*
+			strSample = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+							//formData.append(p.name, $('input[type=file]', '#formParameters')[0].files[0]);
+					strSample += 'formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					strSample += 'formData.append("'+p.name+'", "参数'+pi+'");' +  "\n";
+					}
+				});
+			}
 			
 			strSample += "$.ajax({" + "\n";
 			strSample += "type : '"+ m.type + "',\n";
-			strSample += "dataType : 'json'" + ",\n";
 			strSample += "url : '"+address + "',\n";
 			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : '"+m.contentType+ "',\n";
+			strSample += "contentType : false,\n";
+			strSample += "processData  : false,\n";
 			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
 			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : data"+"\n";
+			strSample += "data : formData"+"\n";
+			strSample += "});";	
+			*/
+	}
+
+	return  strSample;
+   }
+   
+Describe.createSampleJSO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+			if(parameter == ""){
+				parameter = "\"" + p.name + "\"" + ":" + '"替换参数'+pi +'"';
+			}else{
+				parameter = parameter +  ",\"" + p.name + "\"" + ":" + '替换参数'+pi +'"';
+			}
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			 var functionName = "do";
+			 strSample += "\n var root = \"" + uri + "\";" + "\n";
+			 strSample += " var options = { " + "\n";
+			 strSample += "                 " + functionName + ":{ //服务命名1,自定义"+ "\n";
+			 strSample += "                           \"uri\": \"/" + m.path + "\","+ "\n";;
+             strSample += "                           \"method\": \""+m.type+"\""+ "\n";
+			 strSample += "                      }"+ "\n";
+			 strSample += "     }" + "\n";
+			 strSample += "var action = new this.Action( root, options);" + "\n\n";
+			 strSample += "action.invoke({" + "\n";
+			 strSample += "        \"name\": \"" + functionName+ "\", //自定义的服务名" + "\n"; 
+			 strSample += "        \"parameter\": {" + parameter+ "},  //uri参数 " + "\n"; 
+             strSample += "        \"data\": data, //请求的正文, JsonObject " +  "\n"; 
+             strSample += "        \"success\": function(json){ //服务调用成功时的回调方法,json 是服务返回的数据" +  "\n"; 
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "        }.bind(this),"+ "\n"; 
+             strSample += "        \"failure\" : function(xhr){ //服务调用失败时的回调方法,xhr 为 XMLHttpRequest 对象" +  "\n";
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "     },"+ "\n"; 
+             strSample += "        \"async\" : true, //同步还是异步,默认为true" + "\n"; 
+             strSample += "        \"withCredentials\" : true, //是否允许跨域请求,默认为true" + "\n"; 
+             strSample += "        \"urlEncode\" : true //uri参数是否需要通过encodeURIComponent函数编码,默认为true" + "\n";
+             strSample += "});"			
+	} else {
+		
+	}
+	return  strSample;
+  }   
+   
+   
+   
+Describe.createSampleO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			
+			
+			if(m.type=="POST"){
+			   strSample += " \n var string = JSON.stringify(data);" + "\n";
+               strSample += " var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.postQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="GET"){
+               strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+                strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.getQuery( serviceRoot, path );"+ "\n";
+			}
+			if(m.type=="PUT"){
+			   strSample += " \n var string = JSON.stringify(data)"+ "\n";
+               strSample += " var applications = this.Action.applications"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address+ "\";"+ "\n"; ;
+               strSample += " var resp = applications.putQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="DELETE"){
+			   strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \" "+ uri + "\";"+ "\n";
+                 strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.deleteQuery( serviceRoot, path);"+ "\n";
+			}
+			
+               strSample += " var json = JSON.parse( resp.toString() );"+ "\n";
+			
+	} else {
+		
+	}
+	return  strSample;
+  }
+Describe.createSample= function(m) {
+	var address = window.location.href;
+	address = address.substring(0,address.indexOf("/jest/"));
+	var address = address +"/"+ m.path;
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+			if (m.ins && m.ins.length > 0) {
+				strSample =  "var data = {};" + "\n";
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += '   data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += '   data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+								if(i.isCollection){
+									strSample += '   data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += '   data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+														
+						
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += '    data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += '    data = "参数";'+"\n";
+			}
+			
+			strSample += "\n$.ajax({" + "\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        dataType : 'json'" + ",\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : '"+m.contentType+ "',\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			
+		   if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+			 strSample += "       data : JSON.stringify(data),\n";
+			}else{
+			  strSample += "      data : data"+"\n";
+			}
+			
 			strSample += "}).always(function(resultJson) {"+"\n";
-			strSample += "alert(JSON.stringify(resultJson, null, 4))" +"\n";
+			strSample += "        alert(JSON.stringify(resultJson, null, 4))" +"\n";
 			strSample += "});";
 			
 	} else {
@@ -227,28 +506,135 @@ Describe.createSample= function(m) {
 				});
 			}
 			strSample += "$.ajax({" + "\n";
-			strSample += "type : '"+ m.type + "',\n";
-			strSample += "url : '"+address + "',\n";
-			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : false,\n";
-			strSample += "processData  : false,\n";
-			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
-			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : formData"+"\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : false,\n";
+			strSample += "        processData  : false,\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			strSample += "        data : formData"+"\n";
 			strSample += "});";	
 	}
 
 	return  strSample;
    }
+Describe.createSampleCommon= function(m,className) {
+	 debugger;
+	var address = window.location.href;
+		address = address.substring(0,address.indexOf("/jest/"));
+	var root = address.substring(address.lastIndexOf("/")+1,address.length);
 
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+			$.each(m.pathParameters, function(pi, p) {
+				if(parameter == ""){
+					parameter =  p.name ;
+				}else{
+					parameter = parameter +  "," + p.name;
+				}
+			});
+		}
+	var query = "";
+		if (m.queryParameters && m.queryParameters.length > 0) {
+			$.each(m.queryParameters, function(pi, p) {
+				if (query == "") {
+					 query = "&" + p.name + '=' + '替换参数'+pi;
+				} else {
+					 query = query + "&"+ p.name + '=' + '替换参数'+pi;
+				}
+			});
+		}
+	var strSample="";
+	var body = "";
+	if (m.contentType.indexOf('application/json') > -1) {
+				if (m.ins && m.ins.length > 0) {
+					 body =  "var data = {};" + "\n";
+					$.each(m.ins, function(ii, i) {
+						switch (i.type) {
+						default:
+							if (i.isBaseType) {
+								if (i.isCollection) {
+									  body += '       data["'+i.name+'"] = ["参数1"];' + "\n";
+								} else {
+									  body += '       data["'+i.name+'"] = "参数";' + "\n";
+								}
+							} else {
+									if(i.isCollection){
+										body += '       data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+									}else{
+										body += '       data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+									}
+															
+							
+							}
+						}
+					});
+				} else if (m.useJsonElementParameter) {
+					body += '       data = {"参数1":"value1","参数2":"value2"};' +"\n";
+				} else if (m.useStringParameter) {
+					body += '       data = "参数";'+"\n";
+				}
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += body;	
+		 }	   
+	 }			
+	 strSample += "var action = this.Actions.load(\"" + root + "\");\n";
+	 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+	 if(parameter!=""){
+	   strSample += "      " + parameter  +",//uri的参数\n";
+	 }
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += "      data,//body请求参数\n";	
+		 }	   
+	 }
+	 strSample += "      function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+	 strSample += "         data = json.data; //为变量data赋值\n";
+	 strSample += "      }.bind(this),\n";
+	 strSample +=  "     function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+	 strSample +=  "        data = json.data; //为变量data赋值\n";
+	 strSample +=  "     }.bind(this),\n";
+	 strSample += "      false //同步执行 \n";
+	 strSample += "    );\n";
+				
+	}else{
+			var formData = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+					formData += '      formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					formData += '      formData.append("'+p.name+'", "参数值'+pi+'");' +  "\n";
+					}
+				});
+			}
+		 strSample += formData;
+		 strSample += "var action = this.Actions.get(\"" + root + "\");\n";
+		 //strSample += "action."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "      "+parameter  +",//uri的参数\n";
+		 strSample +=  "      formData"+",//from参数\n";
+		 strSample +=  "function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "false //同步执行 \n";
+		 strSample += ");\n"
+		} 
+   return  strSample ;		
+   }
 Describe.prototype = {
 	"load" : function() {
 		var str = '<ul>';
 		$.getJSON('../describe/describe.json?rd=' + Math.random(), function(json) {
 			$.each(json.jaxrs, function(ji, j) {
-				str += '<li xtype="menu" >' + j.name;
+				str += '<li xtype="menu" ' + 'style="margin-top: 30px;font-size:14px;font-weight:bold;"title="' +'" >' + j.name + ' <span style="font-style:italic">(' + j.description+ ')</span>';
 				$.each(j.methods, function(mi, m) {
-					str += '<ul><li xtype="li"><a id ="' + j.name + '_' + m.name + '" href="#">' + m.name + '</a></li></ul>';
+					str += '<ul><li xtype="li"  style="margin-top: 10px;margin-left:-24px;font-size:12px; font-weight:normal;line-height:18px" ><a id ="' + j.name + '_' + m.name + '" href="#"><b>' + m.name+'</b><br/><span style="color: #666666;">-'+ m.description + '</span>' + '</a></li></ul>';
 				});
 				str += '</li>'
 			});
@@ -262,7 +648,7 @@ Describe.prototype = {
 								var sample = "";
 								var txt = '<fieldset id="method"><legend>Method</legend>';
 								txt += '<table>';
-								txt += '<tr><td>name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
+								txt += '<tr><td style="width:100px;">name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
 								txt += '<tr><td>path:</td><td>' + m.path + '</td></tr>';
 								txt += '<tr><td>type:</td><td>' + m.type + '</td></tr>';
 								txt += '<tr><td>description:</td><td>' + m.description + '</td></tr>';
@@ -366,7 +752,7 @@ Describe.prototype = {
 									txt += '<fieldset id="outs"><legend>Out</legend>';
 									txt += '<table>';
 									$.each(m.outs, function(oi, o) {
-										txt += '<tr><td>' + o.name + '</td><td>' + o.type + '</td><td>' + (o.isCollection ? 'multi' : 'single') + '</td><td>' + o.description + '</td><td id="out_'
+										txt += '<tr><td style="width: 160px;">' + o.name + '</td><td style="width: 90px;">' + o.type + '</td><td style="width: 90px;">' + (o.isCollection ? 'multi' : 'single') + '</td><td style="width: 90px;">' + o.description + '</td><td id="out_'
 												+ o.name + '_out">&nbsp;</td></tr>';
 									});
 									txt += '</table>';
@@ -407,7 +793,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															//data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
 														}
 													}
 												});
@@ -431,7 +826,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
+														
 														}
 													}
 												});
@@ -493,7 +897,11 @@ Describe.prototype = {
 								})
 								
 								debugger;
-							 $('#Sample').html(Describe.createSample(m));
+							$('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;color: #1E7ACE;\">\n平台推荐脚本样例</span>\n\n"+ Describe.createSampleCommon(m,j.name)+ "</div><div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							
+							 /*
+							 $('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							 */
 							});
 				});
 			});
@@ -505,7 +913,13 @@ Describe.prototype = {
 						  }else{
 						     event.cancelBubble = true;
 						  }
-					    $(this).children().toggle();
+						$(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+					    //$(this).children().toggle();
 					});
 		  $("[xtype='li']").click( function(event) {
 			    if(event.stopPropagation){
@@ -514,6 +928,18 @@ Describe.prototype = {
 				     event.cancelBubble = true;
 				  }
 			})
+			$("[xtype='menu']").each(function(i){ 
+			if(i!=0){
+			  // $(this).children().toggle();
+			  $(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+			  }
+			}
+			);
 		});
 		
 	

+ 9 - 8
o2server/x_attendance_assemble_control/src/main/webapp/jest/index.html

@@ -99,7 +99,14 @@
 				
 				<div id="content"
 						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word;border-image: linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 100%, #ffffff);box-shadow: inset 15px 0 5px -16px #e7e7e7;background-image: -webkit-radial-gradient(right, #f2f2f2, #ffffff 100%);">&nbsp;</div>
-						
+				<fieldset>
+					<legend>
+						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
+					</legend>
+					<div id="result"
+						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
+				</fieldset>
+				
 			    <fieldset>
 					<legend>
 						Sample&nbsp;<a  id="btn_copy"  href="javascript:" data-clipboard-target="#Sample">copy</a>&nbsp;
@@ -109,13 +116,7 @@
 						</div>
 				</fieldset>		
 						
-				<fieldset>
-					<legend>
-						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
-					</legend>
-					<div id="result"
-						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
-				</fieldset>
+
 			</td>
 		</tr>
 	</table>

+ 7 - 6
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceAdmin.java

@@ -58,27 +58,28 @@ public class AttendanceAdmin extends SliceJpaObject {
 	 */
 	public static final String unitName_FIELDNAME = "unitName";
 	@FieldDescribe("组织名称")
-	@Column( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + unitName_FIELDNAME)
+	@Column(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ unitName_FIELDNAME)
 	@CheckPersist(allowEmpty = true)
 	private String unitName = "";
 
 	public static final String unitOu_FIELDNAME = "unitOu";
 	@FieldDescribe("组织编号")
-	@Column( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + unitOu_FIELDNAME)
-	@Index( name = TABLE + IndexNameMiddle + unitOu_FIELDNAME )
+	@Column(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + unitOu_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + unitOu_FIELDNAME)
 	@CheckPersist(allowEmpty = true)
 	private String unitOu = "";
 
 	public static final String adminName_FIELDNAME = "adminName";
 	@FieldDescribe("管理员姓名")
-	@Column( length = JpaObject.length_96B, name = ColumnNamePrefix + adminName_FIELDNAME)
-	@Index( name = TABLE + IndexNameMiddle + adminName_FIELDNAME )
+	@Column(length = JpaObject.length_96B, name = ColumnNamePrefix + adminName_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + adminName_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String adminName = "";
 
 	public static final String adminLevel_FIELDNAME = "adminLevel";
 	@FieldDescribe("管理级别:UNIT|TOPUNIT")
-	@Column( length = JpaObject.length_96B, name = ColumnNamePrefix + adminLevel_FIELDNAME)
+	@Column(length = JpaObject.length_96B, name = ColumnNamePrefix + adminLevel_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String adminLevel = "TOPUNIT";
 

+ 2 - 8
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/AttendanceScheduleSetting.java

@@ -1,27 +1,19 @@
 package com.x.attendance.entity;
 
-import java.util.Date;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.Id;
 import javax.persistence.Inheritance;
 import javax.persistence.InheritanceType;
-import javax.persistence.PrePersist;
-import javax.persistence.PreUpdate;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.openjpa.persistence.jdbc.Index;
-
 import com.x.base.core.entity.AbstractPersistenceProperties;
 import com.x.base.core.entity.JpaObject;
 import com.x.base.core.entity.SliceJpaObject;
 import com.x.base.core.entity.annotation.CheckPersist;
 import com.x.base.core.entity.annotation.ContainerEntity;
 import com.x.base.core.project.annotation.FieldDescribe;
-import com.x.base.core.project.tools.DateTools;
 
 @ContainerEntity
 @Entity
@@ -29,6 +21,8 @@ import com.x.base.core.project.tools.DateTools;
 		+ JpaObject.IndexNameMiddle + JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
 				JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }))
 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+//@Table(name = PersistenceProperties.AttendanceScheduleSetting.table)
+//@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
 public class AttendanceScheduleSetting extends SliceJpaObject {
 
 	private static final long serialVersionUID = 4555094494086574586L;

+ 3 - 3
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticPersonForMonth.java

@@ -44,12 +44,12 @@ public class StatisticPersonForMonth extends SliceJpaObject {
 
 	public void onPersist() throws Exception {
 		String employeeName = null;
-		if(  this.employeeName != null ) {
+		if (this.employeeName != null) {
 			employeeName = this.employeeName.split("@")[0];
-		}else {
+		} else {
 			employeeName = this.employeeName;
 		}
-		this.setSequence( StringUtils.join(this.statisticYear + this.statisticMonth, employeeName, this.getId()) );
+		this.setSequence(StringUtils.join(this.statisticYear + this.statisticMonth, employeeName, this.getId()));
 	}
 	/*
 	 * =============================================================================

+ 2 - 2
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticTopUnitForDay.java

@@ -44,9 +44,9 @@ public class StatisticTopUnitForDay extends SliceJpaObject {
 
 	public void onPersist() throws Exception {
 		String topUnitName = null;
-		if(  this.topUnitName != null ) {
+		if (this.topUnitName != null) {
 			topUnitName = this.topUnitName.split("@")[0];
-		}else {
+		} else {
 			topUnitName = this.topUnitName;
 		}
 		this.setSequence(StringUtils.join(this.statisticDate, topUnitName, this.getId()));

+ 6 - 5
o2server/x_attendance_core_entity/src/main/java/com/x/attendance/entity/StatisticUnitForMonth.java

@@ -63,17 +63,18 @@ public class StatisticUnitForMonth extends SliceJpaObject {
 	public void onPersist() throws Exception {
 		String topUnitName = null;
 		String unitName = null;
-		if(  this.topUnitName != null ) {
+		if (this.topUnitName != null) {
 			topUnitName = this.topUnitName.split("@")[0];
-		}else {
+		} else {
 			topUnitName = this.topUnitName;
 		}
-		if(  this.unitName != null ) {
+		if (this.unitName != null) {
 			unitName = this.unitName.split("@")[0];
-		}else {
+		} else {
 			unitName = this.unitName;
 		}
-		this.setSequence(StringUtils.join(this.statisticYear + this.statisticMonth, topUnitName, unitName, this.getId()));
+		this.setSequence(
+				StringUtils.join(this.statisticYear + this.statisticMonth, topUnitName, unitName, this.getId()));
 	}
 	/*
 	 * =============================================================================

+ 127 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/container/EntityManagerContainer.java

@@ -458,6 +458,36 @@ public class EntityManagerContainer extends EntityManagerContainerBasic {
 		return list;
 	}
 
+	public <T extends JpaObject, W extends Object> List<T> listEqualAndEqualAndIn(Class<T> cls, String firstAttribute,
+			Object firstValue, String secondAttribute, Object secondValue, String thirdAttribute,
+			Collection<W> thirdValues) throws Exception {
+		EntityManager em = this.get(cls);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<T> cq = cb.createQuery(cls);
+		Root<T> root = cq.from(cls);
+		Predicate p = cb.equal(root.get(firstAttribute), firstValue);
+		p = cb.and(p, cb.equal(root.get(secondAttribute), secondValue));
+		p = cb.and(p, cb.isMember(root.get(thirdAttribute), cb.literal(thirdValues)));
+		List<T> os = em.createQuery(cq.select(root).where(p)).getResultList();
+		List<T> list = new ArrayList<>(os);
+		return list;
+	}
+
+	public <T extends JpaObject, W extends Object> List<T> listEqualAndInAndNotEqual(Class<T> cls,
+			String firstAttribute, Object firstValue, String secondAttribute, Collection<W> secondValues,
+			String thirdAttribute, Object thirdValue) throws Exception {
+		EntityManager em = this.get(cls);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<T> cq = cb.createQuery(cls);
+		Root<T> root = cq.from(cls);
+		Predicate p = cb.equal(root.get(firstAttribute), firstValue);
+		p = cb.and(p, cb.isMember(root.get(secondAttribute), cb.literal(secondValues)));
+		p = cb.and(p, cb.notEqual(root.get(thirdAttribute), thirdValue));
+		List<T> os = em.createQuery(cq.select(root).where(p)).getResultList();
+		List<T> list = new ArrayList<>(os);
+		return list;
+	}
+
 	public <T extends JpaObject, W extends Object> List<T> listEqualAndGreaterThanOrEqualTo(Class<T> cls,
 			String attribute, Object value, String otherAttribute, Object otherValue) throws Exception {
 		EntityManager em = this.get(cls);
@@ -530,6 +560,15 @@ public class EntityManagerContainer extends EntityManagerContainerBasic {
 		return em.createQuery(cq).getSingleResult();
 	}
 
+	public <T extends JpaObject> Long count(Class<T> cls, Predicate predicate) throws Exception {
+		EntityManager em = this.get(cls);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
+		Root<T> root = cq.from(cls);
+		cq.select(cb.count(root)).where(predicate);
+		return em.createQuery(cq).getSingleResult();
+	}
+
 	public <T extends JpaObject> Long countNotEqual(Class<T> cls, String attribute, Object value) throws Exception {
 		EntityManager em = this.get(cls);
 		CriteriaBuilder cb = em.getCriteriaBuilder();
@@ -1445,6 +1484,94 @@ public class EntityManagerContainer extends EntityManagerContainerBasic {
 		return list;
 	}
 
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject> List<T> fetchDescPaging(Class<T> clz, Predicate predicate, Integer page, Integer count,
+			String orderAttribute) throws Exception {
+		List<T> os = fetchDescPaging(clz, JpaObject.singularAttributeField(clz, true, true), predicate, page, count,
+				orderAttribute);
+		return os;
+	}
+
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject, W extends GsonPropertyObject> List<W> fetchDescPaging(Class<T> clz,
+			WrapCopier<T, W> copier, Predicate predicate, Integer page, Integer count, String orderAttribute)
+			throws Exception {
+		List<T> os = fetchDescPaging(clz, copier.getCopyFields(), predicate, page, count, orderAttribute);
+		return copier.copy(os);
+	}
+
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject, W extends GsonPropertyObject> List<T> fetchDescPaging(Class<T> clz,
+			List<String> fetchAttributes, Predicate predicate, Integer page, Integer pageSize, String orderAttribute)
+			throws Exception {
+		List<T> list = new ArrayList<>();
+		int max = (pageSize == null || pageSize < 1 || pageSize > MAX_PAGESIZE) ? DEFAULT_PAGESIZE : pageSize;
+		int startPosition = (page == null || page < 1) ? 0 : (page - 1) * max;
+		List<String> fields = ListTools.trim(fetchAttributes, true, true, JpaObject.id_FIELDNAME);
+		EntityManager em = this.get(clz);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Tuple> cq = cb.createQuery(Tuple.class);
+		Root<T> root = cq.from(clz);
+		List<Selection<?>> selections = new ArrayList<>();
+		for (String str : fields) {
+			selections.add(root.get(str));
+		}
+		cq.multiselect(selections).where(predicate).orderBy(cb.desc(root.get(orderAttribute)));
+		T t = null;
+		for (Tuple o : em.createQuery(cq).setFirstResult(startPosition).setMaxResults(max).getResultList()) {
+			t = clz.newInstance();
+			for (int i = 0; i < fields.size(); i++) {
+				PropertyUtils.setProperty(t, fields.get(i), o.get(selections.get(i)));
+			}
+			list.add(t);
+		}
+		return list;
+	}
+
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject> List<T> fetchAscPaging(Class<T> clz, Predicate predicate, Integer page, Integer count,
+			String orderAttribute) throws Exception {
+		List<T> os = fetchAscPaging(clz, JpaObject.singularAttributeField(clz, true, true), predicate, page, count,
+				orderAttribute);
+		return os;
+	}
+
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject, W extends GsonPropertyObject> List<W> fetchAscPaging(Class<T> clz,
+			WrapCopier<T, W> copier, Predicate predicate, Integer page, Integer count, String orderAttribute)
+			throws Exception {
+		List<T> os = fetchAscPaging(clz, copier.getCopyFields(), predicate, page, count, orderAttribute);
+		return copier.copy(os);
+	}
+
+	/* 仅在单一数据库可用 */
+	public <T extends JpaObject, W extends GsonPropertyObject> List<T> fetchAscPaging(Class<T> clz,
+			List<String> fetchAttributes, Predicate predicate, Integer page, Integer pageSize, String orderAttribute)
+			throws Exception {
+		List<T> list = new ArrayList<>();
+		int max = (pageSize == null || pageSize < 1 || pageSize > MAX_PAGESIZE) ? DEFAULT_PAGESIZE : pageSize;
+		int startPosition = (page == null || page < 1) ? 0 : (page - 1) * max;
+		List<String> fields = ListTools.trim(fetchAttributes, true, true, JpaObject.id_FIELDNAME);
+		EntityManager em = this.get(clz);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Tuple> cq = cb.createQuery(Tuple.class);
+		Root<T> root = cq.from(clz);
+		List<Selection<?>> selections = new ArrayList<>();
+		for (String str : fields) {
+			selections.add(root.get(str));
+		}
+		cq.multiselect(selections).where(predicate).orderBy(cb.asc(root.get(orderAttribute)));
+		T t = null;
+		for (Tuple o : em.createQuery(cq).setFirstResult(startPosition).setMaxResults(max).getResultList()) {
+			t = clz.newInstance();
+			for (int i = 0; i < fields.size(); i++) {
+				PropertyUtils.setProperty(t, fields.get(i), o.get(selections.get(i)));
+			}
+			list.add(t);
+		}
+		return list;
+	}
+
 	/* 仅在单一数据库可用 */
 	public <T extends JpaObject, W extends GsonPropertyObject> List<W> fetchEqualDescPaging(Class<T> clz,
 			WrapCopier<T, W> copier, String equalAttribute, Object equalValue, Integer page, Integer count,

+ 1 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/entity/StorageType.java

@@ -1,6 +1,6 @@
 package com.x.base.core.entity;
 
 public enum StorageType {
-	file, processPlatform, mind, meeting, calendar, okr, cms, bbs, report, strategyDeploy, teamwork;
+	file, processPlatform, mind, meeting, calendar, okr, cms, bbs, report, strategyDeploy, teamwork, structure;
 	public static final int length = JpaObject.length_32B;
 }

+ 13 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/Application.java

@@ -49,7 +49,7 @@ public class Application extends GsonPropertyObject {
 		this.scheduleLocalRequestList = scheduleLocalRequestList;
 	}
 
-	public String getUrlRoot() {
+	public String getUrlJaxrsRoot() {
 		StringBuffer buffer = new StringBuffer();
 		if (BooleanUtils.isTrue(this.sslEnable)) {
 			buffer.append("https://").append(StringUtils.isNotEmpty(node) ? node : "127.0.0.1")
@@ -60,7 +60,19 @@ public class Application extends GsonPropertyObject {
 		}
 		buffer.append(contextPath + "/jaxrs/");
 		return buffer.toString();
+	}
 
+	public String getUrlDescribeApiJson() {
+		StringBuffer buffer = new StringBuffer();
+		if (BooleanUtils.isTrue(this.sslEnable)) {
+			buffer.append("https://").append(StringUtils.isNotEmpty(node) ? node : "127.0.0.1")
+					.append(port == 443 ? "" : (":" + port));
+		} else {
+			buffer.append("http://").append(StringUtils.isNotEmpty(node) ? node : "127.0.0.1")
+					.append(port == 80 ? "" : (":" + port));
+		}
+		buffer.append(contextPath + "/describe/api.json");
+		return buffer.toString();
 	}
 
 	public Integer getPort() {

+ 22 - 8
o2server/x_base_core_project/src/main/java/com/x/base/core/project/Applications.java

@@ -12,10 +12,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import com.x.base.core.project.connection.ActionResponse;
 import com.x.base.core.project.connection.CipherConnectionAction;
+import com.x.base.core.project.connection.HttpConnection;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.LoggerFactory;
 import com.x.base.core.project.tools.DefaultCharset;
@@ -81,7 +83,7 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 	}
 
 	public ActionResponse getQuery(Boolean xdebugger, Application application, String uri) throws Exception {
-		return CipherConnectionAction.get(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri));
+		return CipherConnectionAction.get(xdebugger, application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri));
 	}
 
 	public ActionResponse getQuery(String applicationName, String uri) throws Exception {
@@ -94,7 +96,7 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 			throw new Exception("getQuery can not find application with name:" + applicationName + ".");
 		}
 		Application application = this.randomWithWeight(name);
-		return CipherConnectionAction.get(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri));
+		return CipherConnectionAction.get(xdebugger, application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri));
 	}
 
 	public ActionResponse deleteQuery(Class<?> applicationClass, String uri) throws Exception {
@@ -110,7 +112,8 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 	}
 
 	public ActionResponse deleteQuery(Boolean xdebugger, Application application, String uri) throws Exception {
-		return CipherConnectionAction.delete(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri));
+		return CipherConnectionAction.delete(xdebugger,
+				application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri));
 	}
 
 	public ActionResponse deleteQuery(String applicationName, String uri) throws Exception {
@@ -123,7 +126,8 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 			throw new Exception("deleteQuery can not find application with name:" + applicationName + ".");
 		}
 		Application application = this.randomWithWeight(name);
-		return CipherConnectionAction.delete(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri));
+		return CipherConnectionAction.delete(xdebugger,
+				application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri));
 	}
 
 	public ActionResponse postQuery(Class<?> applicationClass, String uri, Object body) throws Exception {
@@ -141,7 +145,7 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 
 	public ActionResponse postQuery(Boolean xdebugger, Application application, String uri, Object body)
 			throws Exception {
-		return CipherConnectionAction.post(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri),
+		return CipherConnectionAction.post(xdebugger, application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri),
 				body);
 	}
 
@@ -156,7 +160,7 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 			throw new Exception("postQuery can not find application with name:" + applicationName + ".");
 		}
 		Application application = this.randomWithWeight(name);
-		return CipherConnectionAction.post(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri),
+		return CipherConnectionAction.post(xdebugger, application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri),
 				body);
 	}
 
@@ -176,7 +180,7 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 	public ActionResponse putQuery(Boolean xdebugger, Application application, String uri, Object body)
 			throws Exception {
 		return CipherConnectionAction.put(xdebugger,
-				StringTools.JoinUrl(application.getUrlRoot() + CipherConnectionAction.trim(uri)), body);
+				StringTools.JoinUrl(application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri)), body);
 	}
 
 	public ActionResponse putQuery(String applicationName, String uri, Object body) throws Exception {
@@ -190,7 +194,8 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 			throw new Exception("putQuery can not find application with name:" + applicationName + ".");
 		}
 		Application application = this.randomWithWeight(name);
-		return CipherConnectionAction.put(xdebugger, application.getUrlRoot() + CipherConnectionAction.trim(uri), body);
+		return CipherConnectionAction.put(xdebugger, application.getUrlJaxrsRoot() + CipherConnectionAction.trim(uri),
+				body);
 	}
 
 	public String findApplicationName(String name) throws Exception {
@@ -261,4 +266,13 @@ public class Applications extends ConcurrentHashMap<String, CopyOnWriteArrayList
 		this.updateTimestamp = updateTimestamp;
 	}
 
+	public String describeApi(String name) throws Exception {
+		String applicationName = this.findApplicationName(name);
+		if (StringUtils.isEmpty(applicationName)) {
+			throw new Exception("getDescribe can not find application with name:" + name + ".");
+		}
+		Application application = this.randomWithWeight(applicationName);
+		return HttpConnection.getAsString(application.getUrlDescribeApiJson(), null);
+	}
+
 }

+ 895 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/annotation/ApiBuilder.java

@@ -0,0 +1,895 @@
+package com.x.base.core.project.annotation;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.collections4.list.SetUniqueList;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.commons.lang3.reflect.MethodUtils;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.ApiBuilder.JaxrsApiMethod;
+import com.x.base.core.project.annotation.DescribeBuilder.JaxrsMethod;
+import com.x.base.core.project.bean.WrapCopier;
+import com.x.base.core.project.gson.XGsonBuilder;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.DefaultCharset;
+import com.x.base.core.project.tools.ListTools;
+
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ClassInfo;
+import io.github.classgraph.ScanResult;
+
+public class ApiBuilder {
+
+	private static Logger logger = LoggerFactory.getLogger(ApiBuilder.class);
+
+	public static void main(String[] args) throws IOException {
+		//System.out.println("ApiBuilder......");
+		File basedir = new File(args[0]);
+		File sourcedir = new File(args[1]);
+		
+		File dir = new File(basedir, "src/main/webapp/describe");
+
+		FileUtils.forceMkdir(dir);
+
+		ApiBuilder builder = new ApiBuilder();
+
+		builder.scan(dir);
+
+		FileUtils.copyDirectory(sourcedir, new File(dir, "sources"));
+
+	}
+
+	private void scan(File dir) {
+		try {
+			List<JaxrsClass> jaxrsClasses = new ArrayList<>();
+			List<Class<?>> classes = this.scanJaxrsClass();
+			for (Class<?> clz : classes) {
+				if (StandardJaxrsAction.class.isAssignableFrom(clz)) {
+					jaxrsClasses.add(this.jaxrsClass(clz));
+				}
+			}
+			
+			
+			LinkedHashMap<String, List<?>> map = new LinkedHashMap<>();
+			jaxrsClasses = jaxrsClasses.stream().sorted(Comparator.comparing(JaxrsClass::getName))
+					.collect(Collectors.toList());
+			map.put("jaxrs", jaxrsClasses);
+			File file = new File(dir, "api.json");
+			FileUtils.writeStringToFile(file, XGsonBuilder.toJson(map), DefaultCharset.charset);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	private List<Class<?>> scanJaxrsClass() throws Exception {
+		try (ScanResult scanResult = new ClassGraph().disableJarScanning().enableAnnotationInfo().scan()) {
+			SetUniqueList<Class<?>> classes = SetUniqueList.setUniqueList(new ArrayList<Class<?>>());
+			for (ClassInfo info : scanResult.getClassesWithAnnotation(ApplicationPath.class.getName())) {
+				Class<?> applicationPathClass = ClassUtils.getClass(info.getName());
+				for (Class<?> o : (Set<Class<?>>) MethodUtils.invokeMethod(applicationPathClass.newInstance(),
+						"getClasses")) {
+					Path path = o.getAnnotation(Path.class);
+					JaxrsDescribe jaxrsDescribe = o.getAnnotation(JaxrsDescribe.class);
+					if (null != path && null != jaxrsDescribe) {
+						classes.add(o);
+					}
+				}
+			}
+			return classes;
+		}
+	}
+
+	private JaxrsClass jaxrsClass(Class<?> clz) throws Exception {
+		logger.print("describe class:{}.", clz.getName());
+		JaxrsDescribe jaxrsDescribe = clz.getAnnotation(JaxrsDescribe.class);
+		JaxrsClass jaxrsClass = new JaxrsClass();
+		//jaxrsClass.setClassName(clz.getName());
+		jaxrsClass.setName(clz.getSimpleName());
+		//jaxrsClass.setDescription(jaxrsDescribe.value());
+		for (Method method : clz.getMethods()) {
+			JaxrsMethodDescribe jaxrsMethodDescribe = method.getAnnotation(JaxrsMethodDescribe.class);
+			if (null != jaxrsMethodDescribe) {
+				/*
+				Map<String, JaxrsApiMethod> map = new HashMap<String,JaxrsApiMethod>();
+				map.put(method.getName(), this.jaxrsApiMethod(clz, method));
+				jaxrsClass.getMethods().add(map);
+				*/
+				jaxrsClass.getMethods().add(this.jaxrsApiMethod(clz, method));
+			}
+		}
+		
+		//jaxrsClass.setMethods(this.getSortData("name",jaxrsClass.getMethods()));
+		
+		return jaxrsClass;
+		
+	}
+   
+
+   private List<Map<String, JaxrsApiMethod>> getSortData(String indicator, List<Map<String, JaxrsApiMethod>> data) {
+        class MapSort implements Comparator<Map<String, JaxrsApiMethod>> {
+            private String keyName = "";
+            private MapSort(String keyName) {
+                this.keyName = keyName;
+            }
+            public int compare(Map<String, JaxrsApiMethod> mp1, Map<String, JaxrsApiMethod> mp2) {
+            	 System.out.println("this.keyName=" + mp1.keySet().toArray()[0]);
+                 String d1 = mp1.keySet().toArray()[0].toString();
+                 String d2 = mp2.keySet().toArray()[0].toString();
+                return d2.compareTo(d1);
+            }
+        }
+        MapSort mapSort = new MapSort(indicator);
+        Collections.sort(data, mapSort);
+        return data;
+    }
+
+	private JaxrsApiMethod jaxrsApiMethod(Class<?> clz, Method method) throws Exception {
+		JaxrsMethodDescribe jaxrsMethodDescribe = method.getAnnotation(JaxrsMethodDescribe.class);
+		JaxrsApiMethod jaxrsMethod = new JaxrsApiMethod();
+		jaxrsMethod.setName(method.getName());
+		//jaxrsMethod.setDescription(jaxrsMethodDescribe.value());
+		Class<?> actionClass = jaxrsMethodDescribe.action();
+		//jaxrsMethod.setClassName(actionClass.getName());
+		if (null != method.getAnnotation(GET.class)) {
+			jaxrsMethod.setMethod("GET");
+		} else if (null != method.getAnnotation(POST.class)) {
+			jaxrsMethod.setMethod("POST");
+		} else if (null != method.getAnnotation(PUT.class)) {
+			jaxrsMethod.setMethod("PUT");
+		} else if (null != method.getAnnotation(DELETE.class)) {
+			jaxrsMethod.setMethod("DELETE");
+		} else if (null != method.getAnnotation(OPTIONS.class)) {
+			jaxrsMethod.setMethod("OPTIONS");
+		} else if (null != method.getAnnotation(HEAD.class)) {
+			jaxrsMethod.setMethod("HEAD");
+		}
+		
+		if (!jaxrsMethod.getMethod().equalsIgnoreCase("GET")) {
+			Consumes consumes = method.getAnnotation(Consumes.class);
+			if (null != consumes) {
+				if(consumes.value()[0].equals("multipart/form-data")) {
+				   jaxrsMethod.setEnctype("formData");
+				}else {
+					jaxrsMethod.setEnctype(consumes.value()[0]);
+				}
+			} else {
+				//jaxrsMethod.setEnctype(MediaType.APPLICATION_JSON);
+			}
+		}
+		
+		
+		Path path = method.getAnnotation(Path.class);
+		if (null == path) {
+			jaxrsMethod.setUri("jaxrs/" + clz.getAnnotation(Path.class).value());
+		} else {
+			jaxrsMethod.setUri("jaxrs/" + clz.getAnnotation(Path.class).value() + "/" + path.value());
+		}
+
+		return jaxrsMethod;
+	}
+	
+	private JaxrsMethod jaxrsMethod(Class<?> clz, Method method) throws Exception {
+		JaxrsMethodDescribe jaxrsMethodDescribe = method.getAnnotation(JaxrsMethodDescribe.class);
+		
+		
+		JaxrsMethod jaxrsMethod = new JaxrsMethod();
+		jaxrsMethod.setName(method.getName());
+		jaxrsMethod.setDescription(jaxrsMethodDescribe.value());
+		Class<?> actionClass = jaxrsMethodDescribe.action();
+		jaxrsMethod.setClassName(actionClass.getName());
+		if (null != method.getAnnotation(GET.class)) {
+			jaxrsMethod.setType("GET");
+		} else if (null != method.getAnnotation(POST.class)) {
+			jaxrsMethod.setType("POST");
+		} else if (null != method.getAnnotation(PUT.class)) {
+			jaxrsMethod.setType("PUT");
+		} else if (null != method.getAnnotation(DELETE.class)) {
+			jaxrsMethod.setType("DELETE");
+		} else if (null != method.getAnnotation(OPTIONS.class)) {
+			jaxrsMethod.setType("OPTIONS");
+		} else if (null != method.getAnnotation(HEAD.class)) {
+			jaxrsMethod.setType("HEAD");
+		}
+		Class<?> woClass = this.getWoClass(actionClass);
+		if (null != woClass) {
+			jaxrsMethod.setOuts(this.jaxrsOutField(woClass));
+		}
+		Class<?> wiClass = this.getWiClass(actionClass);
+		if (null != wiClass) {
+			jaxrsMethod.setIns(this.jaxrsInField(wiClass));
+		} else {
+			if (StringUtils.equals("POST", jaxrsMethod.getType()) || StringUtils.equals("PUT", jaxrsMethod.getType())) {
+				/** 如果没有定义Wi对象,那么有可能使用的是jsonElement对象 */
+				if (ArrayUtils.contains(method.getParameterTypes(), JsonElement.class)) {
+					jaxrsMethod.setUseJsonElementParameter(true);
+				} else {
+					jaxrsMethod.setUseStringParameter(true);
+				}
+			}
+		}
+		Consumes consumes = method.getAnnotation(Consumes.class);
+		if (null != consumes) {
+			jaxrsMethod.setContentType(consumes.value()[0]);
+		} else {
+			jaxrsMethod.setContentType(MediaType.APPLICATION_JSON);
+		}
+		Produces produces = method.getAnnotation(Produces.class);
+		if (null != produces) {
+			jaxrsMethod.setResultContentType(produces.value()[0]);
+			jaxrsMethod.setResultContentType(produces.value()[0]);
+		}
+		Path path = method.getAnnotation(Path.class);
+		if (null == path) {
+			jaxrsMethod.setPath("jaxrs/" + clz.getAnnotation(Path.class).value());
+		} else {
+			jaxrsMethod.setPath("jaxrs/" + clz.getAnnotation(Path.class).value() + "/" + path.value());
+		}
+		for (Parameter o : method.getParameters()) {
+			FormDataParam formDataParam = o.getAnnotation(FormDataParam.class);
+			FormParam formParam = o.getAnnotation(FormParam.class);
+			PathParam pathParam = o.getAnnotation(PathParam.class);
+			QueryParam queryParam = o.getAnnotation(QueryParam.class);
+			if (null != formDataParam) {
+				jaxrsMethod.getFormParameters().add(this.jaxrsFormDataParameter(clz, method, o));
+			} else if (null != formParam) {
+				jaxrsMethod.getFormParameters().add(this.jaxrsFormParameter(clz, method, o));
+			} else if (null != queryParam) {
+				jaxrsMethod.getQueryParameters().add(this.jaxrsQueryParameter(clz, method, o));
+			} else if (null != pathParam) {
+				jaxrsMethod.getPathParameters().add(this.jaxrsPathParameter(clz, method, o));
+			}
+		}
+		jaxrsMethod.setFormParameters(jaxrsMethod.getFormParameters().stream().filter(Objects::nonNull)
+				.sorted(Comparator.comparing(JaxrsFormParameter::getName, Comparator.nullsLast(String::compareTo)))
+				.collect(Collectors.toList()));
+		jaxrsMethod.setQueryParameters(jaxrsMethod.getQueryParameters().stream().filter(Objects::nonNull)
+				.sorted(Comparator.comparing(JaxrsQueryParameter::getName, Comparator.nullsLast(String::compareTo)))
+				.collect(Collectors.toList()));
+		jaxrsMethod.setPathParameters(jaxrsMethod.getPathParameters().stream().filter(Objects::nonNull)
+				.sorted(Comparator.comparing(JaxrsPathParameter::getName, Comparator.nullsLast(String::compareTo)))
+				.collect(Collectors.toList()));
+		return jaxrsMethod;
+	}
+
+	private JaxrsFormParameter jaxrsFormDataParameter(Class<?> clz, Method method, Parameter parameter) {
+		JaxrsParameterDescribe jaxrsParameterDescribe = parameter.getAnnotation(JaxrsParameterDescribe.class);
+		FormDataParam formDataParam = parameter.getAnnotation(FormDataParam.class);
+		if (StringUtils.equalsIgnoreCase("file", formDataParam.value())) {
+			if (parameter.getType() == FormDataContentDisposition.class) {
+				/** 单独处理附件 */
+				JaxrsFormParameter o = new JaxrsFormParameter();
+				o.setType("File");
+				o.setName(formDataParam.value());
+				if (null != jaxrsParameterDescribe) {
+					o.setDescription(jaxrsParameterDescribe.value());
+				} else {
+					logger.print("类: {}, 方法: {} ,未设置参数 {} 的JaxrsParameterDescribe.", clz.getName(), method.getName(),
+							formDataParam.value());
+					o.setDescription("");
+				}
+				return o;
+			}
+		} else {
+			JaxrsFormParameter o = new JaxrsFormParameter();
+			o.setType(this.simpleType(parameter.getType().toString()));
+			o.setName(formDataParam.value());
+			if (null != jaxrsParameterDescribe) {
+				o.setDescription(jaxrsParameterDescribe.value());
+			} else {
+				logger.print("类: {}, 方法: {} ,未设置参数 {} 的JaxrsParameterDescribe.", clz.getName(), method.getName(),
+						formDataParam.value());
+				o.setDescription("");
+			}
+			return o;
+		}
+		return null;
+	}
+
+	private JaxrsFormParameter jaxrsFormParameter(Class<?> clz, Method method, Parameter parameter) {
+		JaxrsParameterDescribe jaxrsParameterDescribe = parameter.getAnnotation(JaxrsParameterDescribe.class);
+		FormParam formParam = parameter.getAnnotation(FormParam.class);
+		JaxrsFormParameter o = new JaxrsFormParameter();
+		o.setType(this.simpleType(parameter.getType().toString()));
+		o.setName(formParam.value());
+		if (null != jaxrsParameterDescribe) {
+			o.setDescription(jaxrsParameterDescribe.value());
+		} else {
+			logger.print("类: {}, 方法: {} ,未设置参数 {} 的JaxrsParameterDescribe.", clz.getName(), method.getName(),
+					formParam.value());
+			o.setDescription("");
+		}
+		return o;
+	}
+
+	private JaxrsQueryParameter jaxrsQueryParameter(Class<?> clz, Method method, Parameter parameter) {
+		JaxrsParameterDescribe jaxrsParameterDescribe = parameter.getAnnotation(JaxrsParameterDescribe.class);
+		QueryParam queryParam = parameter.getAnnotation(QueryParam.class);
+		JaxrsQueryParameter o = new JaxrsQueryParameter();
+		if (null != jaxrsParameterDescribe) {
+			o.setDescription(jaxrsParameterDescribe.value());
+		} else {
+			logger.print("类: {}, 方法: {} ,未设置参数 {} 的JaxrsParameterDescribe.", clz.getName(), method.getName(),
+					queryParam.value());
+			o.setDescription("");
+		}
+		o.setName(queryParam.value());
+		o.setType(this.simpleType(parameter.getType().getName()));
+		return o;
+	}
+
+	private JaxrsPathParameter jaxrsPathParameter(Class<?> clz, Method method, Parameter parameter) throws Exception {
+		JaxrsParameterDescribe jaxrsParameterDescribe = parameter.getAnnotation(JaxrsParameterDescribe.class);
+		PathParam pathParam = parameter.getAnnotation(PathParam.class);
+		JaxrsPathParameter o = new JaxrsPathParameter();
+		o.setName(pathParam.value());
+		if (null != jaxrsParameterDescribe) {
+			o.setDescription(jaxrsParameterDescribe.value());
+		} else {
+			logger.print("类: {}, 方法: {} ,未设置参数 {} 的JaxrsParameterDescribe.", clz.getName(), method.getName(),
+					pathParam.value());
+			o.setDescription("");
+		}
+		o.setType(this.getJaxrsParameterType(parameter));
+		return o;
+	}
+
+	private Class<?> getWiClass(Class<?> actionClass) {
+		for (Class<?> c : actionClass.getDeclaredClasses()) {
+			if (StringUtils.equals(c.getSimpleName(), "Wi")) {
+				return c;
+			}
+		}
+		return null;
+	}
+
+	private Class<?> getWoClass(Class<?> actionClass) {
+		for (Class<?> c : actionClass.getDeclaredClasses()) {
+			if (StringUtils.equals(c.getSimpleName(), "Wo")) {
+				return c;
+			}
+		}
+		return null;
+	}
+
+	private List<JaxrsField> jaxrsInField(Class<?> clz) throws Exception {
+		List<JaxrsField> list = new ArrayList<>();
+		List<Field> fields = FieldUtils.getAllFieldsList(clz);
+		List<String> copierCopyFields = this.listCopierCopyFields(clz);
+		if (ListTools.isNotEmpty(copierCopyFields)) {
+			List<Field> os = new ArrayList<>();
+			for (Field o : fields) {
+				FieldDescribe fieldDescribe = o.getAnnotation(FieldDescribe.class);
+				if ((null != fieldDescribe)
+						&& (copierCopyFields.contains(o.getName()) || this.inWiNotInEntity(o.getName(), clz))) {
+					os.add(o);
+				}
+				fields = os;
+			}
+		}
+		for (Field o : fields) {
+			FieldDescribe fieldDescribe = o.getAnnotation(FieldDescribe.class);
+			if (null != fieldDescribe) {
+				JaxrsField jaxrsField = new JaxrsField();
+				jaxrsField.setName(o.getName());
+				jaxrsField.setDescription(fieldDescribe.value());
+				jaxrsField.setType(this.getJaxrsFieldType(o));
+				jaxrsField.setIsBaseType(false);
+				if (Collection.class.isAssignableFrom(o.getType())) {
+					jaxrsField.setIsCollection(true);
+					if (StringUtils.containsAny(jaxrsField.getType(), "<String>", "<Boolean>", "<Date>", "<Integer>",
+							"<Double>", "<Long>", "<Float>")) {
+						jaxrsField.setIsBaseType(true);
+					}
+				} else {
+					// O2LEE,String[]未被判断为collection导致组织的JSON格式不符合wrapIn要求
+					if (StringUtils.equalsAnyIgnoreCase("String[]", jaxrsField.getType())) {
+						jaxrsField.setIsCollection(true);
+					} else {
+						jaxrsField.setIsCollection(false);
+					}
+					if (StringUtils.startsWithAny(jaxrsField.getType(), "String", "Boolean", "Date", "Integer",
+							"Double", "Long", "Float")) {
+						jaxrsField.setIsBaseType(true);
+					}
+				}
+				list.add(jaxrsField);
+			}
+		}
+		return list;
+	}
+
+	private List<JaxrsField> jaxrsOutField(Class<?> clz) throws Exception {
+		List<JaxrsField> list = new ArrayList<>();
+		List<Field> fields = FieldUtils.getAllFieldsList(clz);
+		List<String> copierEraseFields = this.listCopierEraseFields(clz);
+		if (ListTools.isNotEmpty(copierEraseFields)) {
+			List<Field> os = new ArrayList<>();
+			for (Field o : fields) {
+				FieldDescribe fieldDescribe = o.getAnnotation(FieldDescribe.class);
+				if ((null != fieldDescribe) && (!copierEraseFields.contains(o.getName()))) {
+					os.add(o);
+				}
+			}
+			fields = os;
+		}
+		for (Field o : fields) {
+			FieldDescribe fieldDescribe = o.getAnnotation(FieldDescribe.class);
+			if (null != fieldDescribe) {
+				JaxrsField jaxrsField = new JaxrsField();
+				jaxrsField.setName(o.getName());
+				jaxrsField.setDescription(fieldDescribe.value());
+				jaxrsField.setType(this.getJaxrsFieldType(o));
+				if (Collection.class.isAssignableFrom(o.getType())) {
+					jaxrsField.setIsCollection(true);
+				} else {
+					jaxrsField.setIsCollection(false);
+				}
+				list.add(jaxrsField);
+			}
+		}
+		return list;
+	}
+
+	private String getJaxrsFieldType(Field o) {
+		String value = o.getGenericType().getTypeName();
+		return this.simpleType(value);
+	}
+
+	private String getJaxrsParameterType(Parameter o) {
+		String value = o.getType().getTypeName();
+		return this.simpleType(value);
+	}
+
+	private String simpleType(String value) {
+		value = value.replaceAll(" ", "");
+		String[] ss = value.split("[,|<|>]");
+		for (String s : ss) {
+			String[] ns = s.split("[.|\\$]");
+			value = value.replace(s, ns[ns.length - 1]);
+		}
+		return value;
+	}
+
+	private List<String> listCopierEraseFields(Class<?> clz) {
+		try {
+			Object o = FieldUtils.readStaticField(clz, "copier", true);
+			WrapCopier copier = (WrapCopier) o;
+			return copier.getEraseFields();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	private List<String> listCopierCopyFields(Class<?> clz) {
+		try {
+			Object o = FieldUtils.readStaticField(clz, "copier", true);
+			WrapCopier copier = (WrapCopier) o;
+			return copier.getCopyFields();
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	/** 判断字段是否在Wi中但是没有在Entity类中说明是Wi新增字段,需要进行描述 */
+	private Boolean inWiNotInEntity(String field, Class<?> clz) {
+		try {
+			Object o = FieldUtils.readStaticField(clz, "copier", true);
+			WrapCopier copier = (WrapCopier) o;
+			if ((null != FieldUtils.getField(copier.getOrigClass(), field, true))
+					&& (null == FieldUtils.getField(copier.getDestClass(), field, true))) {
+				return true;
+			}
+			return false;
+		} catch (Exception e) {
+			return null;
+		}
+	}
+
+	public class JaxrsClass {
+
+		private String name;
+		private List<JaxrsApiMethod> methods = new ArrayList<>();
+	
+		public List<JaxrsApiMethod> getMethods() {
+			return methods;
+		}
+
+		public void setMethods(List<JaxrsApiMethod> methods) {
+			this.methods = methods;
+		}
+     
+		public String getName() {
+			return name;
+		}
+  /*
+		private List<Map<String,JaxrsApiMethod>> methods = new ArrayList<Map<String,JaxrsApiMethod>>();
+		public List<Map<String, JaxrsApiMethod>> getMethods() {
+			return methods;
+		}
+
+		public void setMethods(List<Map<String, JaxrsApiMethod>> methods) {
+			this.methods = methods;
+		}
+  */
+		public void setName(String name) {
+			this.name = name;
+		}
+	}
+	
+    public class JaxrsApiMethod{
+		//private List<JaxsApiMethodProperty> name = new ArrayList<>();
+    	private String name;
+		private String uri;
+		private String method;
+		private String enctype;
+		
+	
+		public String getName() {
+			return name;
+		}
+		public void setName(String name) {
+			this.name = name;
+		}
+		public String getUri() {
+			return uri;
+		}
+		public void setUri(String uri) {
+			this.uri = uri;
+		}
+		public String getMethod() {
+			return method;
+		}
+		public void setMethod(String method) {
+			this.method = method;
+		}
+		public String getEnctype() {
+			return enctype;
+		}
+		public void setEnctype(String enctype) {
+			this.enctype = enctype;
+		}
+
+    }
+    public class JaxsApiMethodProperty{
+    	private String name;
+		private String uri;
+		private String method;
+		private String enctype;
+		
+		public String getUri() {
+			return uri;
+		}
+		public void setUri(String uri) {
+			this.uri = uri;
+		}
+		public String getMethod() {
+			return method;
+		}
+		public void setMethod(String method) {
+			this.method = method;
+		}
+		public String getEnctype() {
+			return enctype;
+		}
+		public void setEnctype(String enctype) {
+			this.enctype = enctype;
+		}
+    	
+    }
+	public class JaxrsMethod {
+		private String name;
+		private String className;
+		private String description;
+		private String type;
+		private String path;
+		private String contentType;
+		private String resultContentType;
+		private Boolean useJsonElementParameter = false;
+		private Boolean useStringParameter = false;
+		private List<JaxrsPathParameter> pathParameters = new ArrayList<>();
+		private List<JaxrsFormParameter> formParameters = new ArrayList<>();
+		private List<JaxrsQueryParameter> queryParameters = new ArrayList<>();
+		private List<JaxrsField> ins = new ArrayList<>();
+		private List<JaxrsField> outs = new ArrayList<>();
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+		public String getPath() {
+			return path;
+		}
+
+		public void setPath(String path) {
+			this.path = path;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public List<JaxrsField> getIns() {
+			return ins;
+		}
+
+		public void setIns(List<JaxrsField> ins) {
+			this.ins = ins;
+		}
+
+		public List<JaxrsField> getOuts() {
+			return outs;
+		}
+
+		public void setOuts(List<JaxrsField> outs) {
+			this.outs = outs;
+		}
+
+		public String getContentType() {
+			return contentType;
+		}
+
+		public void setContentType(String contentType) {
+			this.contentType = contentType;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getClassName() {
+			return className;
+		}
+
+		public void setClassName(String className) {
+			this.className = className;
+		}
+
+		public List<JaxrsPathParameter> getPathParameters() {
+			return pathParameters;
+		}
+
+		public void setPathParameters(List<JaxrsPathParameter> pathParameters) {
+			this.pathParameters = pathParameters;
+		}
+
+		public List<JaxrsFormParameter> getFormParameters() {
+			return formParameters;
+		}
+
+		public void setFormParameters(List<JaxrsFormParameter> formParameters) {
+			this.formParameters = formParameters;
+		}
+
+		public List<JaxrsQueryParameter> getQueryParameters() {
+			return queryParameters;
+		}
+
+		public void setQueryParameters(List<JaxrsQueryParameter> queryParameters) {
+			this.queryParameters = queryParameters;
+		}
+
+		public Boolean getUseJsonElementParameter() {
+			return useJsonElementParameter;
+		}
+
+		public void setUseJsonElementParameter(Boolean useJsonElementParameter) {
+			this.useJsonElementParameter = useJsonElementParameter;
+		}
+
+		public String getResultContentType() {
+			return resultContentType;
+		}
+
+		public void setResultContentType(String resultContentType) {
+			this.resultContentType = resultContentType;
+		}
+
+		public Boolean getUseStringParameter() {
+			return useStringParameter;
+		}
+
+		public void setUseStringParameter(Boolean useStringParameter) {
+			this.useStringParameter = useStringParameter;
+		}
+
+	}
+
+	public class JaxrsField {
+
+		private String name;
+		private String type;
+		private Boolean isCollection;
+		private String description;
+		private Boolean isBaseType;
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+		public Boolean getIsCollection() {
+			return isCollection;
+		}
+
+		public void setIsCollection(Boolean isCollection) {
+			this.isCollection = isCollection;
+		}
+
+		public Boolean getIsBaseType() {
+			return isBaseType;
+		}
+
+		public void setIsBaseType(Boolean isBaseType) {
+			this.isBaseType = isBaseType;
+		}
+
+	}
+
+	public class JaxrsPathParameter {
+
+		private String name;
+		private String type;
+		private String description;
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+	}
+
+	public class JaxrsFormParameter {
+
+		private String name;
+		private String type;
+		private String description;
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+	}
+
+	public class JaxrsQueryParameter {
+
+		private String name;
+		private String type;
+		private String description;
+
+		public String getName() {
+			return name;
+		}
+
+		public void setName(String name) {
+			this.name = name;
+		}
+
+		public String getDescription() {
+			return description;
+		}
+
+		public void setDescription(String description) {
+			this.description = description;
+		}
+
+		public String getType() {
+			return type;
+		}
+
+		public void setType(String type) {
+			this.type = type;
+		}
+
+	}
+
+}

+ 2 - 2
o2server/x_base_core_project/src/main/java/com/x/base/core/project/annotation/DescribeBuilder.java

@@ -60,7 +60,7 @@ public class DescribeBuilder {
 
 		File basedir = new File(args[0]);
 
-		File sourcedir = new File(args[1]);
+		File sourcesdir = new File(args[1]);
 
 		File dir = new File(basedir, "src/main/webapp/describe");
 
@@ -70,7 +70,7 @@ public class DescribeBuilder {
 
 		builder.scan(dir);
 
-		FileUtils.copyDirectory(sourcedir, new File(dir, "sources"));
+		FileUtils.copyDirectory(sourcesdir, new File(dir, "sources"));
 
 	}
 

+ 12 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/build/CheckCore.java

@@ -13,6 +13,7 @@ import javax.persistence.Lob;
 import javax.persistence.Table;
 import javax.persistence.UniqueConstraint;
 
+import org.apache.commons.lang3.BooleanUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.openjpa.persistence.jdbc.ContainerTable;
@@ -22,7 +23,6 @@ import com.x.base.core.entity.JpaObject;
 import com.x.base.core.entity.annotation.ContainerEntity;
 import com.x.base.core.project.annotation.FieldDescribe;
 import com.x.base.core.project.annotation.Module;
-import com.x.base.core.project.tools.MainTools;
 
 import io.github.classgraph.ClassGraph;
 import io.github.classgraph.ClassInfo;
@@ -234,4 +234,15 @@ public class CheckCore {
 			}
 		}
 	}
+
+	@Test
+	public static void checkIdUnique(List<Class<?>> classes) throws Exception {
+		for (Class<?> cls : classes) {
+			Field idField = FieldUtils.getField(cls, JpaObject.id_FIELDNAME, true);
+			Column column = idField.getAnnotation(Column.class);
+			if (BooleanUtils.isNotTrue(column.unique())) {
+				System.err.println(String.format("checkIdUnique error: class: %s.", cls.getName()));
+			}
+		}
+	}
 }

+ 1 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Collect.java

@@ -26,7 +26,7 @@ public class Collect extends ConfigObject {
 	private static String Default_title = "企业办公平台";
 	private static String Default_footer = "www.o2oa.net";
 	private static String Default_name = "www.o2oa.net";
-	private static String Default_appUrl = "http://www.pgyer.com/ZhiHe_android";
+	private static String Default_appUrl = "https://sample.o2oa.net/app/download.html";
 	private static String Default_server = "collect.o2oa.net";
 	private static Integer Default_port = 20080;
 

+ 85 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Communicate.java

@@ -0,0 +1,85 @@
+package com.x.base.core.project.config;
+
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.CronExpression;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+
+public class Communicate extends ConfigObject {
+
+	public static final Boolean DEFAULT_WEBSOCKETENABLE = true;
+
+	public Communicate() {
+		this.webSocketEnable = DEFAULT_WEBSOCKETENABLE;
+	}
+
+	public static Communicate defaultInstance() {
+		return new Communicate();
+	}
+
+	@FieldDescribe("是否启用webSocket推送消息.")
+	private Boolean webSocketEnable;
+
+	public Boolean webSocketEnable() {
+		return BooleanUtils.isTrue(webSocketEnable);
+	}
+
+	@FieldDescribe("清理设置.")
+	private Clean clean;
+
+	public Clean clean() {
+		return this.clean == null ? new Clean() : this.clean;
+	}
+
+	public static class Clean extends ConfigObject {
+
+		public static Clean defaultInstance() {
+			Clean o = new Clean();
+			return o;
+		}
+
+		public final static Boolean DEFAULT_ENABLE = true;
+
+		public final static Integer DEFAULT_KEEP = 7;
+
+		public final static String DEFAULT_CRON = "30 30 6 * * ?";
+
+		@FieldDescribe("是否启用")
+		private Boolean enable = DEFAULT_ENABLE;
+
+		@FieldDescribe("定时cron表达式")
+		private String cron = DEFAULT_CRON;
+
+		@FieldDescribe("消息保留天数")
+		private Integer keep = DEFAULT_KEEP;
+
+		public Integer getKeep() {
+			if ((null == this.keep) || (this.keep < 1)) {
+				return DEFAULT_KEEP;
+			} else {
+				return this.keep;
+			}
+		}
+
+		public String getCron() {
+			if (StringUtils.isNotEmpty(this.cron) && CronExpression.isValidExpression(this.cron)) {
+				return this.cron;
+			} else {
+				return DEFAULT_CRON;
+			}
+		}
+
+		public Boolean getEnable() {
+			return BooleanUtils.isTrue(this.enable);
+		}
+
+		public void setCron(String cron) {
+			this.cron = cron;
+		}
+
+		public void setEnable(Boolean enable) {
+			this.enable = enable;
+		}
+	}
+}

+ 81 - 22
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java

@@ -63,7 +63,10 @@ public class Config {
 	public static final String PATH_CONFIG_BINDLOGO = "config/bindLogo.png";
 	public static final String PATH_CONFIG_SLICE = "config/slice.json";
 	public static final String PATH_COMMONS_INITIALSCRIPTTEXT = "commons/initialScriptText.js";
+	public static final String PATH_COMMONS_INITIALSERVICESCRIPTTEXT = "commons/initialServiceScriptText.js";
 	public static final String PATH_COMMONS_MOOTOOLSSCRIPTTEXT = "commons/mooToolsScriptText.js";
+	public static final String PATH_CONFIG_JPUSH = "config/jpushConfig.json";
+	public static final String PATH_CONFIG_COMMUNICATE = "config/communicate.json";
 
 	public static final String DIR_COMMONS = "commons";
 	public static final String DIR_COMMONS_TESS4J_TESSDATA = "commons/tess4j/tessdata";
@@ -112,6 +115,8 @@ public class Config {
 
 	public static final String RESOURCE_AUDITLOGPRINTSTREAM = "auditLogPrintStream";
 
+	public static final String SCRIPTING_ENGINE_NAME = "JavaScript";
+
 	// public static final String RESOUCE_CONFIG = "config";
 
 	public static final String RESOURCE_NODE_PREFIX = "node/";
@@ -482,7 +487,7 @@ public class Config {
 					if (null != files && files.length > 0) {
 						for (File o : files) {
 							String name = StringUtils.substringBetween(o.getName(), "node_", ".json");
-							Node node = BaseTools.readObject(DIR_CONFIG + "/" + o.getName(), Node.class);
+							Node node = BaseTools.readConfigObject(DIR_CONFIG + "/" + o.getName(), Node.class);
 							if (StringUtils.isNotEmpty(name) && BooleanUtils.isTrue(node.getEnable())) {
 								nodes.put(name, node);
 							}
@@ -492,7 +497,7 @@ public class Config {
 						nodes.put(node(), o);
 					}
 					/* 20191009兼容centerServer */
-					CenterServer c = BaseTools.readObject(PATH_CONFIG_CENTERSERVER, CenterServer.class);
+					CenterServer c = BaseTools.readConfigObject(PATH_CONFIG_CENTERSERVER, CenterServer.class);
 					if (null != c) {
 						for (Node n : nodes.values()) {
 							n.setCenter(c);
@@ -512,7 +517,7 @@ public class Config {
 		if (null == instance().token) {
 			synchronized (Config.class) {
 				if (null == instance().token) {
-					Token o = BaseTools.readObject(PATH_CONFIG_TOKEN, Token.class);
+					Token o = BaseTools.readConfigObject(PATH_CONFIG_TOKEN, Token.class);
 					if (null == o) {
 						o = Token.defaultInstance();
 					}
@@ -529,7 +534,7 @@ public class Config {
 		if (null == instance().externalDataSources) {
 			synchronized (Config.class) {
 				if (null == instance().externalDataSources) {
-					ExternalDataSources obj = BaseTools.readObject(PATH_CONFIG_EXTERNALDATASOURCES,
+					ExternalDataSources obj = BaseTools.readConfigObject(PATH_CONFIG_EXTERNALDATASOURCES,
 							ExternalDataSources.class);
 					if (null == obj) {
 						obj = ExternalDataSources.defaultInstance();
@@ -547,7 +552,7 @@ public class Config {
 		if (null == instance().externalStorageSources) {
 			synchronized (Config.class) {
 				if (null == instance().externalStorageSources) {
-					ExternalStorageSources obj = BaseTools.readObject(PATH_CONFIG_EXTERNALSTORAGESOURCES,
+					ExternalStorageSources obj = BaseTools.readConfigObject(PATH_CONFIG_EXTERNALSTORAGESOURCES,
 							ExternalStorageSources.class);
 					if (null == obj) {
 						obj = ExternalStorageSources.defaultInstance();
@@ -601,7 +606,7 @@ public class Config {
 		if (null == instance().person) {
 			synchronized (Config.class) {
 				if (null == instance().person) {
-					Person obj = BaseTools.readObject(PATH_CONFIG_PERSON, Person.class);
+					Person obj = BaseTools.readConfigObject(PATH_CONFIG_PERSON, Person.class);
 					if (null == obj) {
 						obj = Person.defaultInstance();
 					}
@@ -612,13 +617,30 @@ public class Config {
 		return instance().person;
 	}
 
+	private Communicate communicate = null;
+
+	public static Communicate communicate() throws Exception {
+		if (null == instance().communicate) {
+			synchronized (Config.class) {
+				if (null == instance().communicate) {
+					Communicate obj = BaseTools.readConfigObject(PATH_CONFIG_COMMUNICATE, Communicate.class);
+					if (null == obj) {
+						obj = Communicate.defaultInstance();
+					}
+					instance().communicate = obj;
+				}
+			}
+		}
+		return instance().communicate;
+	}
+
 	private Meeting meeting;
 
 	public static Meeting meeting() throws Exception {
 		if (null == instance().meeting) {
 			synchronized (Config.class) {
 				if (null == instance().meeting) {
-					Meeting obj = BaseTools.readObject(PATH_CONFIG_MEETING, Meeting.class);
+					Meeting obj = BaseTools.readConfigObject(PATH_CONFIG_MEETING, Meeting.class);
 					if (null == obj) {
 						obj = Meeting.defaultInstance();
 					}
@@ -635,7 +657,7 @@ public class Config {
 		if (null == instance().workTime) {
 			synchronized (Config.class) {
 				if (null == instance().workTime) {
-					com.x.base.core.project.config.WorkTime obj = BaseTools.readObject(PATH_CONFIG_WORKTIME,
+					com.x.base.core.project.config.WorkTime obj = BaseTools.readConfigObject(PATH_CONFIG_WORKTIME,
 							com.x.base.core.project.config.WorkTime.class);
 					if (null == obj) {
 						obj = com.x.base.core.project.config.WorkTime.defaultInstance();
@@ -655,7 +677,7 @@ public class Config {
 		if (null == instance().collect) {
 			synchronized (Config.class) {
 				if (null == instance().collect) {
-					Collect obj = BaseTools.readObject(PATH_CONFIG_COLLECT, Collect.class);
+					Collect obj = BaseTools.readConfigObject(PATH_CONFIG_COLLECT, Collect.class);
 					if (null == obj) {
 						obj = Collect.defaultInstance();
 					}
@@ -673,7 +695,8 @@ public class Config {
 		if (null == instance().dumpRestoreData) {
 			synchronized (Config.class) {
 				if (null == instance().dumpRestoreData) {
-					DumpRestoreData obj = BaseTools.readObject(PATH_CONFIG_DUMPRESTOREDATA, DumpRestoreData.class);
+					DumpRestoreData obj = BaseTools.readConfigObject(PATH_CONFIG_DUMPRESTOREDATA,
+							DumpRestoreData.class);
 					if (null == obj) {
 						obj = DumpRestoreData.defaultInstance();
 					}
@@ -690,7 +713,7 @@ public class Config {
 		if (null == instance().dumpRestoreStorage) {
 			synchronized (Config.class) {
 				if (null == instance().dumpRestoreStorage) {
-					DumpRestoreStorage obj = BaseTools.readObject(PATH_CONFIG_DUMPRESTORESTORAGE,
+					DumpRestoreStorage obj = BaseTools.readConfigObject(PATH_CONFIG_DUMPRESTORESTORAGE,
 							DumpRestoreStorage.class);
 					if (null == obj) {
 						obj = DumpRestoreStorage.defaultInstance();
@@ -715,6 +738,19 @@ public class Config {
 		return instance().initialScriptText;
 	}
 
+	public String initialServiceScriptText;
+
+	public static String initialServiceScriptText() throws Exception {
+		if (null == instance().initialServiceScriptText) {
+			synchronized (Config.class) {
+				if (null == instance().initialServiceScriptText) {
+					instance().initialServiceScriptText = BaseTools.readString(PATH_COMMONS_INITIALSERVICESCRIPTTEXT);
+				}
+			}
+		}
+		return instance().initialServiceScriptText;
+	}
+
 	public String mooToolsScriptText;
 
 	public static String mooToolsScriptText() throws Exception {
@@ -769,7 +805,7 @@ public class Config {
 		if (null == instance().storageMappings) {
 			synchronized (Config.class) {
 				if (null == instance().storageMappings) {
-					ExternalStorageSources obj = BaseTools.readObject(PATH_CONFIG_EXTERNALSTORAGESOURCES,
+					ExternalStorageSources obj = BaseTools.readConfigObject(PATH_CONFIG_EXTERNALSTORAGESOURCES,
 							ExternalStorageSources.class);
 					if ((obj != null)) {
 						instance().storageMappings = new StorageMappings(obj);
@@ -789,6 +825,9 @@ public class Config {
 			synchronized (Config.class) {
 				if (null == instance().sslKeyStore) {
 					File file = new File(BaseTools.getBasePath(), PATH_CONFIG_SSLKEYSTORE);
+					if ((!file.exists()) || file.isDirectory()) {
+						file = new File(BaseTools.getBasePath(), PATH_CONFIG_SSLKEYSTORE + ".jks");
+					}
 					if ((!file.exists()) || file.isDirectory()) {
 						file = new File(BaseTools.getBasePath(), PATH_CONFIG_SSLKEYSTORESAMPLE);
 					}
@@ -863,7 +902,7 @@ public class Config {
 			synchronized (Config.class) {
 				if (null == instance().messages) {
 					Messages obj = Messages.defaultInstance();
-					Messages custom = BaseTools.readObject(PATH_CONFIG_MESSAGES, Messages.class);
+					Messages custom = BaseTools.readConfigObject(PATH_CONFIG_MESSAGES, Messages.class);
 					if (null != custom) {
 						custom.entrySet().stream().forEach(o -> {
 							obj.put(o.getKey(), new Message(o.getValue().getConsumers()));
@@ -876,13 +915,32 @@ public class Config {
 		return instance().messages;
 	}
 
+	private PushConfig pushConfig;
+
+	public static PushConfig pushConfig() throws Exception {
+		if (null == instance().pushConfig) {
+			synchronized (Config.class) {
+				if (null == instance().pushConfig) {
+					PushConfig custom = BaseTools.readConfigObject(PATH_CONFIG_JPUSH, PushConfig.class);
+					if (null != custom) {
+						instance().pushConfig = custom;
+					} else {
+						instance().pushConfig = PushConfig.defaultInstance();
+					}
+				}
+			}
+		}
+		return instance().pushConfig;
+	}
+
 	private ProcessPlatform processPlatform;
 
 	public static ProcessPlatform processPlatform() throws Exception {
 		if (null == instance().processPlatform) {
 			synchronized (Config.class) {
 				if (null == instance().processPlatform) {
-					ProcessPlatform obj = BaseTools.readObject(PATH_CONFIG_PROCESSPLATFORM, ProcessPlatform.class);
+					ProcessPlatform obj = BaseTools.readConfigObject(PATH_CONFIG_PROCESSPLATFORM,
+							ProcessPlatform.class);
 					if (null == obj) {
 						obj = ProcessPlatform.defaultInstance();
 					}
@@ -899,7 +957,7 @@ public class Config {
 		if (null == instance().query) {
 			synchronized (Config.class) {
 				if (null == instance().query) {
-					Query obj = BaseTools.readObject(PATH_CONFIG_QUERY, Query.class);
+					Query obj = BaseTools.readConfigObject(PATH_CONFIG_QUERY, Query.class);
 					if (null == obj) {
 						obj = Query.defaultInstance();
 					}
@@ -916,7 +974,7 @@ public class Config {
 		if (null == instance().dingding) {
 			synchronized (Config.class) {
 				if (null == instance().dingding) {
-					Dingding obj = BaseTools.readObject(PATH_CONFIG_DINGDING, Dingding.class);
+					Dingding obj = BaseTools.readConfigObject(PATH_CONFIG_DINGDING, Dingding.class);
 					if (null == obj) {
 						obj = Dingding.defaultInstance();
 					}
@@ -933,7 +991,7 @@ public class Config {
 		if (null == instance().qiyeweixin) {
 			synchronized (Config.class) {
 				if (null == instance().qiyeweixin) {
-					Qiyeweixin obj = BaseTools.readObject(PATH_CONFIG_QIYEWEIXIN, Qiyeweixin.class);
+					Qiyeweixin obj = BaseTools.readConfigObject(PATH_CONFIG_QIYEWEIXIN, Qiyeweixin.class);
 					if (null == obj) {
 						obj = Qiyeweixin.defaultInstance();
 					}
@@ -950,7 +1008,8 @@ public class Config {
 		if (null == instance().zhengwuDingding) {
 			synchronized (Config.class) {
 				if (null == instance().zhengwuDingding) {
-					ZhengwuDingding obj = BaseTools.readObject(PATH_CONFIG_ZHENGWUDINGDING, ZhengwuDingding.class);
+					ZhengwuDingding obj = BaseTools.readConfigObject(PATH_CONFIG_ZHENGWUDINGDING,
+							ZhengwuDingding.class);
 					if (null == obj) {
 						obj = ZhengwuDingding.defaultInstance();
 					}
@@ -967,7 +1026,7 @@ public class Config {
 		if (null == instance().vfs) {
 			synchronized (Config.class) {
 				if (null == instance().vfs) {
-					Vfs obj = BaseTools.readObject(PATH_CONFIG_VFS, Vfs.class);
+					Vfs obj = BaseTools.readConfigObject(PATH_CONFIG_VFS, Vfs.class);
 					if (null == obj) {
 						obj = Vfs.defaultInstance();
 					}
@@ -984,7 +1043,7 @@ public class Config {
 		if (null == instance().appStyle) {
 			synchronized (Config.class) {
 				if (null == instance().appStyle) {
-					AppStyle obj = BaseTools.readObject(PATH_CONFIG_APPSTYLE, AppStyle.class);
+					AppStyle obj = BaseTools.readConfigObject(PATH_CONFIG_APPSTYLE, AppStyle.class);
 					if (null == obj) {
 						obj = AppStyle.defaultInstance();
 					}
@@ -1019,7 +1078,7 @@ public class Config {
 		if (null == instance().logLevel) {
 			synchronized (Config.class) {
 				if (null == instance().logLevel) {
-					LogLevel obj = BaseTools.readObject(PATH_CONFIG_LOGLEVEL, LogLevel.class);
+					LogLevel obj = BaseTools.readConfigObject(PATH_CONFIG_LOGLEVEL, LogLevel.class);
 					if (null == obj) {
 						obj = LogLevel.defaultInstance();
 					}
@@ -1067,7 +1126,7 @@ public class Config {
 		if (null == instance().slice) {
 			synchronized (Config.class) {
 				if (null == instance().slice) {
-					Slice obj = BaseTools.readObject(PATH_CONFIG_SLICE, Slice.class);
+					Slice obj = BaseTools.readConfigObject(PATH_CONFIG_SLICE, Slice.class);
 					if (null == obj) {
 						obj = Slice.defaultInstance();
 					}

+ 3 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/DumpRestoreData.java

@@ -14,11 +14,13 @@ public class DumpRestoreData extends ConfigObject {
 		return new DumpRestoreData();
 	}
 
+	public static final int default_batchSize = 1000;
+
 	public DumpRestoreData() {
 		this.enable = false;
 		this.includes = new ArrayList<String>();
 		this.excludes = new ArrayList<String>();
-		this.batchSize = 2000;
+		this.batchSize = default_batchSize;
 	}
 
 	@FieldDescribe("是否启用.")

+ 3 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/DumpRestoreStorage.java

@@ -15,10 +15,12 @@ public class DumpRestoreStorage extends GsonPropertyObject {
 		return new DumpRestoreStorage();
 	}
 
+	public static final int default_batchSize = 100;
+
 	public DumpRestoreStorage() {
 		this.includes = new ArrayList<String>();
 		this.excludes = new ArrayList<String>();
-		this.batchSize = 500;
+		this.batchSize = default_batchSize;
 		this.redistribute = true;
 		this.exceptionInvalidStorage = true;
 	}

+ 21 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/LogLevel.java

@@ -256,6 +256,15 @@ public class LogLevel extends ConfigObject {
 		@FieldDescribe("审计日志保留天数")
 		private Integer logSize;
 
+		@FieldDescribe("审计日志归属系统code")
+		private String system;
+
+		@FieldDescribe("审计日志归属系统名称")
+		private String systemName;
+
+		@FieldDescribe("审计日志归属省份")
+		private String companycode;
+
 		public Boolean enable() {
 			return BooleanUtils.isTrue(this.enable);
 		}
@@ -267,6 +276,18 @@ public class LogLevel extends ConfigObject {
 				return this.logSize;
 			}
 		}
+		public String getSystem() { return system; }
+
+		public void setSystem(String system) {
+			this.system = system;
+		}
+
+		public String getSystemName() { return systemName; }
+
+		public void setSystemName(String systemName) { this.systemName = systemName; }
+
+		public String getCompanycode() { return companycode; }
 
+		public void setCompanycode(String companycode) { this.companycode = companycode; }
 	}
 }

+ 21 - 60
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Messages.java

@@ -4,18 +4,14 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentSkipListMap;
 
-import org.apache.commons.lang3.BooleanUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.quartz.CronExpression;
-
-import com.x.base.core.project.annotation.FieldDescribe;
-import com.x.base.core.project.config.ProcessPlatform.Press;
 import com.x.base.core.project.message.MessageConnector;
 
 public class Messages extends ConcurrentSkipListMap<String, Message> {
 
 	private static final long serialVersionUID = 1336172131736006743L;
 
+	public static final Boolean DEFAULT_WEBSOCKETENABLE = true;
+
 	public Messages() throws Exception {
 		super();
 	}
@@ -98,12 +94,26 @@ public class Messages extends ConcurrentSkipListMap<String, Message> {
 				new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
 						MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
 						MessageConnector.CONSUME_QIYEWEIXIN));
-		
+
 		/* 文档发布消息通知 */
-		o.put(MessageConnector.TYPE_CMS_PUBLISH,
-				new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS,
-						MessageConnector.CONSUME_DINGDING, MessageConnector.CONSUME_ZHENGWUDINGDING,
-						MessageConnector.CONSUME_QIYEWEIXIN));
+//		o.put(MessageConnector.TYPE_CMS_PUBLISH,
+//				new Message(MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS ));
+
+		/* 社区新贴发布消息通知 */
+		o.put(MessageConnector.TYPE_BBS_SUBJECTCREATE,
+				new Message( MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS ));
+
+		/* 社区新回复发布消息通知 */
+		o.put(MessageConnector.TYPE_BBS_REPLYCREATE,
+				new Message( MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS ));
+		/* 脑图分享消息通知 */
+		o.put(MessageConnector.TYPE_MIND_FILESHARE,
+				new Message( MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS ));
+
+		/* 脑图发送消息通知 */
+		o.put(MessageConnector.TYPE_MIND_FILESEND,
+				new Message( MessageConnector.CONSUME_WS, MessageConnector.CONSUME_PMS ));
+
 		return o;
 	}
 
@@ -118,53 +128,4 @@ public class Messages extends ConcurrentSkipListMap<String, Message> {
 		return new ArrayList<String>();
 	}
 
-	@FieldDescribe("清理设置.")
-	private Clean clean;
-
-	public Clean clean() {
-		return this.clean == null ? new Clean() : this.clean;
-	}
-
-	public static class Clean extends ConfigObject {
-
-		public static Clean defaultInstance() {
-			Clean o = new Clean();
-			return o;
-		}
-
-		public final static Boolean DEFAULT_ENABLE = true;
-
-		public final static Integer DEFAULT_KEEP = 7;
-
-		public final static String DEFAULT_CRON = "30 30 6 * * ?";
-
-		@FieldDescribe("是否启用")
-		private Boolean enable = DEFAULT_ENABLE;
-
-		@FieldDescribe("定时cron表达式")
-		private String cron = DEFAULT_CRON;
-
-		@FieldDescribe("消息保留天数")
-		private Integer keep = DEFAULT_KEEP;
-
-		public String getCron() {
-			if (StringUtils.isNotEmpty(this.cron) && CronExpression.isValidExpression(this.cron)) {
-				return this.cron;
-			} else {
-				return DEFAULT_CRON;
-			}
-		}
-
-		public Boolean getEnable() {
-			return BooleanUtils.isTrue(this.enable);
-		}
-
-		public void setCron(String cron) {
-			this.cron = cron;
-		}
-
-		public void setEnable(Boolean enable) {
-			this.enable = enable;
-		}
-	}
 }

+ 8 - 8
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Node.java

@@ -189,13 +189,13 @@ public class Node extends ConfigObject {
 		}
 
 		@FieldDescribe("是否启用,默认每天凌晨2点进行备份.")
-		private Boolean enable = false;
+		private Boolean enable = true;
 
 		@FieldDescribe("定时任务cron表达式")
 		private String cron = "";
 
 		@FieldDescribe("最大保留份数,超过将自动删除最久的数据.")
-		private Integer size = 14;
+		private Integer size = 7;
 
 		@FieldDescribe("备份路径")
 		private String path = "";
@@ -228,14 +228,14 @@ public class Node extends ConfigObject {
 			return DateTools.cronAvailable(this.cron);
 		}
 
-		@FieldDescribe("是否启用,默认每天凌晨2点进行备份.")
-		private Boolean enable = false;
+		@FieldDescribe("是否启用,默认每天凌晨4点进行备份.")
+		private Boolean enable = true;
 
 		@FieldDescribe("定时任务cron表达式")
 		private String cron = "";
 
 		@FieldDescribe("最大保留份数,超过将自动删除最久的数据.")
-		private Integer size = 14;
+		private Integer size = 7;
 
 		@FieldDescribe("备份路径")
 		private String path = "";
@@ -245,7 +245,7 @@ public class Node extends ConfigObject {
 		}
 
 		public String cron() {
-			return (null == cron) ? "5 0 3 * * ?" : this.cron;
+			return (null == cron) ? "5 0 4 * * ?" : this.cron;
 		}
 
 		public Integer size() {
@@ -269,7 +269,7 @@ public class Node extends ConfigObject {
 		}
 
 		@FieldDescribe("是否启用,默认每天凌晨2点进行备份.")
-		private Boolean enable;
+		private Boolean enable = false;
 
 		@FieldDescribe("定时任务cron表达式")
 		private String cron = "";
@@ -302,7 +302,7 @@ public class Node extends ConfigObject {
 		}
 
 		@FieldDescribe("是否启用,默认每天凌晨2点进行备份.")
-		private Boolean enable;
+		private Boolean enable = false;
 
 		@FieldDescribe("定时任务cron表达式")
 		private String cron = "";

+ 20 - 1
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Person.java

@@ -38,6 +38,9 @@ public class Person extends ConfigObject {
 	public static final Integer DEFAULT_FAILURECOUNT = 5;
 	public static final Integer DEFAULT_TOKENEXPIREDMINUTES = 60 * 24 * 15;
 
+	public static final String DEFAULT_PASSWORDREGEX = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,}$";
+	public static final String DEFAULT_PASSWORDREGEXHINT = "6位以上,包含数字和字母.";
+
 	public Person() {
 		this.captchaLogin = DEFAULT_CAPTCHALOGIN;
 		this.codeLogin = DEFAULT_CODELOGIN;
@@ -47,6 +50,8 @@ public class Person extends ConfigObject {
 		this.passwordPeriod = DEFAULT_PASSWORDPERIOD;
 		this.register = REGISTER_TYPE_DISABLE;
 		this.superPermission = DEFAULT_SUPERPERMISSION;
+		this.passwordRegex = DEFAULT_PASSWORDREGEX;
+		this.passwordRegexHint = DEFAULT_PASSWORDREGEXHINT;
 	}
 
 	public static Person defaultInstance() {
@@ -70,9 +75,15 @@ public class Person extends ConfigObject {
 	@FieldDescribe("注册初始密码,使用()调用脚本生成初始密码,默认为:" + DEFAULT_PASSWORD)
 	private String password;
 
-	@FieldDescribe("密码过期时间,0表示不过期,默认值:0")
+	@FieldDescribe("密码过期时间(天),0表示不过期,默认值:0.")
 	private Integer passwordPeriod;
 
+	@FieldDescribe("密码校验正则表达式,默认6位以上,包含数字和字母.")
+	private String passwordRegex;
+
+	@FieldDescribe("密码校验不通过的提示信息.")
+	private String passwordRegexHint;
+
 	@FieldDescribe("是否允许用户自注册,disable:不允许,captcha通过验证码注册,code:通过短信注册,默认值:disable")
 	private String register;
 
@@ -174,6 +185,14 @@ public class Person extends ConfigObject {
 		return BooleanUtils.isTrue(this.superPermission) ? true : false;
 	}
 
+	public String getPasswordRegex() {
+		return StringUtils.isEmpty(this.passwordRegex) ? DEFAULT_PASSWORDREGEX : this.passwordRegex;
+	}
+
+	public String getPasswordRegexHint() {
+		return StringUtils.isEmpty(this.passwordRegexHint) ? DEFAULT_PASSWORDREGEXHINT : this.passwordRegexHint;
+	}
+
 	public String getRegister() {
 		if (StringUtils.equalsIgnoreCase(REGISTER_TYPE_CODE, this.register)) {
 			return REGISTER_TYPE_CODE;

+ 32 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ProcessPlatform.java

@@ -14,9 +14,17 @@ import com.x.base.core.project.tools.DefaultCharset;
 public class ProcessPlatform extends ConfigObject {
 
 	public final static Integer DEFAULT_FORMVERSIONPERIOD = 45;
+
 	public final static Integer DEFAULT_PROCESSVERSIONPERIOD = 45;
+
 	public final static Integer DEFAULT_SCRIPTVERSIONPERIOD = 45;
 
+	public final static Integer DEFAULT_FORMVERSIONCOUNT = 30;
+
+	public final static Integer DEFAULT_PROCESSVERSIONCOUNT = 30;
+
+	public final static Integer DEFAULT_SCRIPTVERSIONCOUNT = 30;
+
 	public final static String DEFAULT_DOCTOWORDTYPE = "local";
 
 	public final static String DOCTOWORDTYPE_LOCAL = "local";
@@ -37,6 +45,9 @@ public class ProcessPlatform extends ConfigObject {
 		this.reorganize = new Reorganize();
 		this.dataMerge = new DataMerge();
 		this.maintenanceIdentity = "";
+		this.formVersionCount = DEFAULT_FORMVERSIONCOUNT;
+		this.processVersionCount = DEFAULT_PROCESSVERSIONCOUNT;
+		this.scriptVersionCount = DEFAULT_SCRIPTVERSIONCOUNT;
 		this.formVersionPeriod = DEFAULT_FORMVERSIONPERIOD;
 		this.processVersionPeriod = DEFAULT_PROCESSVERSIONPERIOD;
 		this.scriptVersionPeriod = DEFAULT_SCRIPTVERSIONPERIOD;
@@ -66,6 +77,15 @@ public class ProcessPlatform extends ConfigObject {
 	@FieldDescribe("维护身份,当工作发生意外错误,无法找到对应的处理人情况下,先尝试将工作分配给创建身份,如果创建身份也不可获取,那么分配给指定人员,默认情况下这个值为空.")
 	private String maintenanceIdentity;
 
+	@FieldDescribe("表单历史版本保留数量,0为不保留.")
+	private Integer formVersionCount;
+
+	@FieldDescribe("流程历史版本保留数量,0为不保留.")
+	private Integer processVersionCount;
+
+	@FieldDescribe("脚本历史版本保留数量,0为不保留.")
+	private Integer scriptVersionCount;
+
 	@FieldDescribe("表单历史版本保留天数.")
 	private Integer formVersionPeriod;
 
@@ -84,6 +104,18 @@ public class ProcessPlatform extends ConfigObject {
 	@FieldDescribe("HTML版式公文转换成Word文件缺省site.")
 	private String docToWordDefaultSite;
 
+	public Integer getFormVersionCount() {
+		return formVersionCount == null ? DEFAULT_FORMVERSIONCOUNT : this.formVersionCount;
+	}
+
+	public Integer getProcessVersionCount() {
+		return processVersionCount == null ? DEFAULT_PROCESSVERSIONCOUNT : this.processVersionCount;
+	}
+
+	public Integer getScriptVersionCount() {
+		return scriptVersionCount == null ? DEFAULT_SCRIPTVERSIONCOUNT : this.scriptVersionCount;
+	}
+
 	public Integer getFormVersionPeriod() {
 		return (formVersionPeriod == null || formVersionPeriod < 1) ? DEFAULT_FORMVERSIONPERIOD
 				: this.formVersionPeriod;

+ 52 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/PushConfig.java

@@ -0,0 +1,52 @@
+package com.x.base.core.project.config;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+import org.apache.commons.lang3.BooleanUtils;
+
+public class PushConfig extends ConfigObject {
+
+    private static final String O2_app_key_default = "9aca7cc20fe0cc987cd913ca";
+    private static final String O2_master_secret_default = "96ee7e2e0daffd51bac57815";
+
+
+    public static PushConfig defaultInstance() {
+        return new PushConfig();
+    }
+    public PushConfig() {
+        this.enable = false;
+        this.appKey = O2_app_key_default;
+        this.masterSecret = O2_master_secret_default;
+    }
+
+
+    @FieldDescribe("是否启用.")
+    private Boolean enable;
+    @FieldDescribe("极光推送应用的AppKey")
+    private String appKey;
+    @FieldDescribe("极光推送应用的Master Secret")
+    private String masterSecret;
+
+    public Boolean getEnable() {
+        return BooleanUtils.isTrue(this.enable);
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public String getAppKey() {
+        return appKey;
+    }
+
+    public void setAppKey(String appKey) {
+        this.appKey = appKey;
+    }
+
+    public String getMasterSecret() {
+        return masterSecret;
+    }
+
+    public void setMasterSecret(String masterSecret) {
+        this.masterSecret = masterSecret;
+    }
+}

+ 4 - 4
o2server/x_base_core_project/src/main/java/com/x/base/core/project/connection/CipherConnectionAction.java

@@ -24,7 +24,7 @@ public class CipherConnectionAction {
 	}
 
 	public static ActionResponse get(Boolean xdebugger, Application application, String... strs) throws Exception {
-		String addr = application.getUrlRoot() + trim(Applications.joinQueryUri(strs));
+		String addr = application.getUrlJaxrsRoot() + trim(Applications.joinQueryUri(strs));
 		return get(xdebugger, addr);
 	}
 
@@ -37,7 +37,7 @@ public class CipherConnectionAction {
 	}
 
 	public static ActionResponse delete(Boolean xdebugger, Application application, String... strs) throws Exception {
-		String addr = application.getUrlRoot() + trim(Applications.joinQueryUri(strs));
+		String addr = application.getUrlJaxrsRoot() + trim(Applications.joinQueryUri(strs));
 		return delete(xdebugger, addr);
 	}
 
@@ -51,7 +51,7 @@ public class CipherConnectionAction {
 
 	public static ActionResponse post(Boolean xdebugger, Object body, Application application, String... strs)
 			throws Exception {
-		String addr = application.getUrlRoot() + trim(Applications.joinQueryUri(strs));
+		String addr = application.getUrlJaxrsRoot() + trim(Applications.joinQueryUri(strs));
 		return post(xdebugger, addr, body);
 	}
 
@@ -65,7 +65,7 @@ public class CipherConnectionAction {
 
 	public static ActionResponse put(Boolean xdebugger, Object body, Application application, String... strs)
 			throws Exception {
-		String addr = application.getUrlRoot() + trim(Applications.joinQueryUri(strs));
+		String addr = application.getUrlJaxrsRoot() + trim(Applications.joinQueryUri(strs));
 		return put(xdebugger, addr, body);
 	}
 

+ 0 - 2
o2server/x_base_core_project/src/main/java/com/x/base/core/project/gson/GsonPropertyObject.java

@@ -1,7 +1,5 @@
 package com.x.base.core.project.gson;
 
-import org.apache.commons.beanutils.PropertyUtils;
-
 import com.x.base.core.project.bean.PropertyObject;
 
 public abstract class GsonPropertyObject extends PropertyObject {

+ 4 - 2
o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/AbstractJaxrsAction.java

@@ -36,6 +36,9 @@ abstract class AbstractJaxrsAction {
 
 	protected <T> T convertToWrapIn(JsonElement jsonElement, Class<T> clz) throws Exception {
 		try {
+			if (null == jsonElement || jsonElement.isJsonNull()) {
+				return clz.newInstance();
+			}
 			return gson.fromJson(jsonElement, clz);
 		} catch (Exception e) {
 			throw new JsonElementConvertToWrapInException(e, clz);
@@ -75,8 +78,7 @@ abstract class AbstractJaxrsAction {
 				DefaultCharset.charset);
 		fileName = FilenameUtils.getName(fileName);
 		return fileName;
-		
+
 	}
 
-	
 }

+ 8 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/DescribeFilter.java

@@ -0,0 +1,8 @@
+package com.x.base.core.project.jaxrs;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = { "/describe/*" }, asyncSupported = true)
+public class DescribeFilter extends AnonymousCipherManagerUserJaxrsFilter {
+
+}

+ 31 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/jaxrs/WrapCount.java

@@ -0,0 +1,31 @@
+package com.x.base.core.project.jaxrs;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.gson.GsonPropertyObject;
+
+public class WrapCount extends GsonPropertyObject {
+
+	public WrapCount() {
+
+	}
+
+	public WrapCount(Long o) {
+		this.count = o;
+	}
+
+	public WrapCount(Integer o) {
+		this.count = o.longValue();
+	}
+
+	@FieldDescribe("数量")
+	private Long count;
+
+	public Long getCount() {
+		return count;
+	}
+
+	public void setCount(Long count) {
+		this.count = count;
+	}
+
+}

+ 116 - 10
o2server/x_base_core_project/src/main/java/com/x/base/core/project/logger/Audit.java

@@ -1,9 +1,11 @@
 package com.x.base.core.project.logger;
 
 import java.io.PrintStream;
+import java.net.InetAddress;
 import java.util.Date;
 import java.util.Objects;
 
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.helpers.MessageFormatter;
 
 import com.x.base.core.project.config.Config;
@@ -20,27 +22,131 @@ public class Audit {
 	private String uri = "";
 	private String userAgent = "";
 
+	private String userId = "";
+	private String userName = "";
+
 	protected Audit(String person, String remoteAddress, String uri, String userAgent, String className) {
 		this.start = new Date();
 		this.person = Objects.toString(person, "");
+		if(person==null || person.indexOf("@") == -1){
+			userId = Objects.toString(person, "");
+			userName = Objects.toString(person, "");
+		}else{
+			String persons[] = person.split("@");
+			userId = persons[1];
+			userName = persons[0];
+		}
 		this.remoteAddress = Objects.toString(remoteAddress, "");
 		this.uri = Objects.toString(uri, "");
 		this.userAgent = Objects.toString(userAgent, "");
 		this.className = Objects.toString(className, "");
+
+	}
+
+	public void log1() throws Exception {
+		this.log1("");
+	}
+
+	/**
+	 * 审计日志
+	 * @param message
+	 * @param os
+	 * @throws Exception
+	 */
+	public void log1(String message, Object... os){
+		try {
+			if (Config.logLevel().audit().enable()) {
+				Date end = new Date();
+				long elapsed = end.getTime() - start.getTime();
+				PrintStream stream = (PrintStream) Config.resource(Config.RESOURCE_AUDITLOGPRINTSTREAM);
+				stream.printf("%tF %tT,,,%d,,,%s,,,%s,,,%s,,,%s,,,%s,,,%s%n", end, end, elapsed, this.person,
+						this.remoteAddress, this.uri, this.userAgent, this.className,
+						MessageFormatter.arrayFormat(Objects.toString(message, ""), os).getMessage());
+			}
+		} catch (Exception e) {
+			System.out.println("审计日志打印异常"+e.getMessage());
+		}
+	}
+
+	/**
+	 * 移动集团审计日志格式:
+	 * 默认时间戳之类的信息|日志版本号|请求ID|请求深度|请求链|OA账号(OA&合同不为空)|员工工号(报账不为空)
+	 * |系统归属|系统名称|模块名称|表单类型|操作名称|是否统计上报|扩展信息|时间戳|耗时|请求结果|主机IP
+	 * |主机名|终端类型|终端IP |终端型号|终端IMEI|错误堆栈
+	 * @throws Exception
+	 */
+	public void log(String person, String op){
+		try {
+			if (Config.logLevel().audit().enable()) {
+				if(person!=null){
+					this.person = person;
+					if(person.indexOf("@") == -1){
+						userId = person;
+						userName = person;
+					}else{
+						String persons[] = person.split("@");
+						userId = persons[1];
+						userName = persons[0];
+					}
+				}
+				Date end = new Date();
+				long elapsed = end.getTime() - start.getTime();
+				InetAddress addr = InetAddress.getLocalHost();
+				String hostAddress = addr.getHostAddress();
+				String hostName = addr.getHostName();
+				String system = Objects.toString(Config.logLevel().audit().getSystem(), "OA");
+				String systemName = Objects.toString(Config.logLevel().audit().getSystemName(), "OA系统");
+				String companycode = Objects.toString(Config.logLevel().audit().getCompanycode(), "");
+				String mode = this.uri;
+				if(this.uri!=null) {
+					String[] uris = this.uri.split("/");
+					if (uris.length > 1) {
+						mode = uris[1];
+					}
+				}
+				PrintStream stream = (PrintStream) Config.resource(Config.RESOURCE_AUDITLOGPRINTSTREAM);
+				stream.printf("%tF %tT|2.0||1||%s|%s|%s|%s|%s||%s|true|%s|%d|%d|true|%s|%s|%s|%s|%s||", end, end, this.userId,
+						this.userId, systemName, system, mode, op, this.getParameter(op, system, companycode), end.getTime(), elapsed, hostAddress, hostName,
+						getTerminal(), this.remoteAddress, this.userAgent);
+				stream.println();
+			}
+		} catch (Exception e) {
+			System.out.println("审计日志打印异常"+e.getMessage());
+		}
 	}
 
-	public void log() throws Exception {
-		this.log("");
+	public String getTerminal(){
+		if(StringUtils.isNotBlank(this.userAgent)) {
+			String userAgent = this.userAgent.toLowerCase();
+			if (userAgent.indexOf("micromessenger") != -1) {
+				//微信
+				return "MOA";
+			} else if (userAgent.indexOf("android") != -1) {
+				//安卓
+				return "MOA";
+			} else if (userAgent.indexOf("iphone") != -1 || userAgent.indexOf("ipad") != -1 || userAgent.indexOf("ipod") != -1) {
+				//苹果
+				return "MOA";
+			} else {
+				//电脑
+				return "PC";
+			}
+		}
+		return "PC";
 	}
 
-	public void log(String message, Object... os) throws Exception {
-		if (Config.logLevel().audit().enable()) {
-			Date end = new Date();
-			long elapsed = end.getTime() - start.getTime();
-			PrintStream stream = (PrintStream) Config.resource(Config.RESOURCE_AUDITLOGPRINTSTREAM);
-			stream.printf("%tF %tT,,,%d,,,%s,,,%s,,,%s,,,%s,,,%s,,,%s%n", end, end, elapsed, this.person,
-					this.remoteAddress, this.uri, this.userAgent, this.className,
-					MessageFormatter.arrayFormat(Objects.toString(message, ""), os).getMessage());
+	public String getParameter(String op,String system,String companycode){
+		StringBuffer parameter =new StringBuffer();
+		if("登录".equals(op)){
+			parameter.append("LOG_RESULT=0&interfacename=").append(system).append("_")
+					.append(getTerminal()).append("_LOGIN&errorCode=ok&companycode=").append(companycode).append("&LOGIN_ENTRY=0");
+		}else if("注销".equals(op)){
+			parameter.append("LOG_RESULT=0&interfacename=").append(system).append("_")
+					.append(getTerminal()).append("_LOGOUT&errorCode=ok&companycode=").append(companycode).append("&LOGOUT_ENTRY=0");
+		}else{
+			parameter.append("LOG_RESULT=0&interfacename=").append(system).append("_")
+					.append(getTerminal()).append("_OPERATION&errorCode=ok&companycode=").append(companycode);
 		}
+		return parameter.toString();
 	}
 }

+ 10 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/message/MessageConnector.java

@@ -108,10 +108,20 @@ public class MessageConnector {
 	
 	public static final String TYPE_CMS_PUBLISH = "cms_publish";
 
+	public static final String TYPE_BBS_SUBJECTCREATE = "bbs_subjectCreate";
+
+	public static final String TYPE_BBS_REPLYCREATE = "bbs_replyCreate";
+
+	public static final String TYPE_MIND_FILESEND = "mind_fileSend";
+
+	public static final String TYPE_MIND_FILESHARE = "mind_fileShare";
+
 	public static final String CONSUME_WS = "ws";
 
 	public static final String CONSUME_PMS = "pms";
 
+	public static final String CONSUME_PMS_INNER = "pmsinner";
+
 	public static final String CONSUME_CALENDAR = "calendar";
 
 	public static final String CONSUME_DINGDING = "dingding";

+ 24 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/message/PmsInnerMessage.java

@@ -0,0 +1,24 @@
+package com.x.base.core.project.message;
+
+
+public class PmsInnerMessage extends Message {
+
+	private String person;
+	private String message;
+
+	public String getPerson() {
+		return person;
+	}
+
+	public void setPerson(String person) {
+		this.person = person;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+}

+ 3 - 2
o2server/x_base_core_project/src/main/java/com/x/base/core/project/scripting/Scripting.java

@@ -2,9 +2,10 @@ package com.x.base.core.project.scripting;
 
 import javax.script.ScriptEngineManager;
 
+import com.x.base.core.project.config.Config;
+
 public class Scripting {
 
-	public static final String ENGINE_NAME = "JavaScript";
 	private static ScriptEngineManager scriptEngineManager;
 
 	public static ScriptingEngine getEngine() {
@@ -15,7 +16,7 @@ public class Scripting {
 				}
 			}
 		}
-		ScriptingEngine engine = new ScriptingEngine(scriptEngineManager.getEngineByName(ENGINE_NAME));
+		ScriptingEngine engine = new ScriptingEngine(scriptEngineManager.getEngineByName(Config.SCRIPTING_ENGINE_NAME));
 		return engine;
 	}
 

+ 43 - 9
o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/BaseTools.java

@@ -1,11 +1,18 @@
 package com.x.base.core.project.tools;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 
 import com.google.gson.Gson;
+import com.google.gson.JsonElement;
 
 public class BaseTools {
 
@@ -29,27 +36,54 @@ public class BaseTools {
 		throw new Exception("can not define o2server base directory.");
 	}
 
-	public static <T> T readObject(String path, Class<T> cls) throws Exception {
+	public static <T> T readConfigObject(String path, Class<T> cls) throws Exception {
 		String base = BaseTools.getBasePath();
 		File file = new File(base, path);
 		if ((!file.exists()) || file.isDirectory()) {
 			return null;
 		}
 		String json = FileUtils.readFileToString(file, DefaultCharset.charset);
-		return (new Gson()).fromJson(json, cls);
+
+		Gson gson = new Gson();
+
+		JsonElement jsonElement = gson.fromJson(json, JsonElement.class);
+		if ((null != jsonElement) && jsonElement.isJsonObject()) {
+			LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
+			map = new Gson().fromJson(jsonElement, map.getClass());
+			removeComment(map);
+			jsonElement = gson.toJsonTree(map);
+		}
+		return gson.fromJson(jsonElement, cls);
 	}
 
-	public static <T> T readObject(String path, String otherPath, Class<T> cls) throws Exception {
+	private static void removeComment(Map<Object, Object> map) {
+		List<Entry<Object, Object>> entries = new ArrayList<>();
+		for (Entry<Object, Object> entry : map.entrySet()) {
+			if (StringUtils.startsWith(Objects.toString(entry.getKey()), "###")) {
+				entries.add(entry);
+				continue;
+			} else {
+				if (entry.getValue() instanceof Map) {
+					removeComment((Map<Object, Object>) entry.getValue());
+				}
+			}
+		}
+		for (Entry<Object, Object> entry : entries) {
+			map.remove(entry.getKey());
+		}
+	}
+
+	public static <T> T readConfigObject(String path, String otherPath, Class<T> cls) throws Exception {
 		String base = BaseTools.getBasePath();
 		File file = new File(base, path);
-		if ((!file.exists()) || file.isDirectory()) {
-			file = new File(base, otherPath);
+		if (file.exists() && file.isFile()) {
+			return readConfigObject(path, cls);
 		}
-		if ((!file.exists()) || file.isDirectory()) {
-			throw new Exception("can not get file with path:" + path + ", otherPath:" + otherPath + ".");
+		file = new File(base, otherPath);
+		if (file.exists() && file.isFile()) {
+			return readConfigObject(otherPath, cls);
 		}
-		String json = FileUtils.readFileToString(file, DefaultCharset.charset);
-		return (new Gson()).fromJson(json, cls);
+		throw new Exception("can not get file with path:" + path + ", otherPath:" + otherPath + ".");
 	}
 
 	public static void writeObject(String path, Object obj) throws Exception {

+ 0 - 221
o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/PasswordTools.java

@@ -1,221 +0,0 @@
-package com.x.base.core.project.tools;
-
-public class PasswordTools {
-    private static final int NUM = 1;
-    private static final int SMALL_LETTER = 2;
-    private static final int CAPITAL_LETTER = 3;
-    private static final int OTHER_CHAR = 4;
-    private static final String[] DICTIONARY = new String[]{"password", "abc123", "iloveyou", "adobe123", "123123", "sunshine", "1314520", "a1b2c3", "123qwe", "aaa111", "qweasd", "admin", "passwd"};
-
-    public PasswordTools() {
-    }
-
-    private static int checkCharacterType(char c) {
-        if (c >= '0' && c <= '9') {
-            return 1;
-        } else if (c >= 'A' && c <= 'Z') {
-            return 3;
-        } else {
-            return c >= 'a' && c <= 'z' ? 2 : 4;
-        }
-    }
-
-    private static int countLetter(String passwd, int type) {
-        int count = 0;
-        if (null != passwd && passwd.length() > 0) {
-            char[] arr$ = passwd.toCharArray();
-            int len$ = arr$.length;
-
-            for(int i$ = 0; i$ < len$; ++i$) {
-                char c = arr$[i$];
-                if (checkCharacterType(c) == type) {
-                    ++count;
-                }
-            }
-        }
-
-        return count;
-    }
-
-    public static int checkPasswordStrength(String passwd) {
-        if (StringTools.equalsNull(passwd)) {
-            throw new IllegalArgumentException("password is empty");
-        } else {
-            int len = passwd.length();
-            int level = 0;
-            if (countLetter(passwd, 1) > 0) {
-                ++level;
-            }
-
-            if (countLetter(passwd, 2) > 0) {
-                ++level;
-            }
-
-            if (len > 4 && countLetter(passwd, 3) > 0) {
-                ++level;
-            }
-
-            if (len > 6 && countLetter(passwd, 4) > 0) {
-                ++level;
-            }
-
-            if (len > 4 && countLetter(passwd, 1) > 0 && countLetter(passwd, 2) > 0 || countLetter(passwd, 1) > 0 && countLetter(passwd, 3) > 0 || countLetter(passwd, 1) > 0 && countLetter(passwd, 4) > 0 || countLetter(passwd, 2) > 0 && countLetter(passwd, 3) > 0 || countLetter(passwd, 2) > 0 && countLetter(passwd, 4) > 0 || countLetter(passwd, 3) > 0 && countLetter(passwd, 4) > 0) {
-                ++level;
-            }
-
-            if (len > 6 && countLetter(passwd, 1) > 0 && countLetter(passwd, 2) > 0 && countLetter(passwd, 3) > 0 || countLetter(passwd, 1) > 0 && countLetter(passwd, 2) > 0 && countLetter(passwd, 4) > 0 || countLetter(passwd, 1) > 0 && countLetter(passwd, 3) > 0 && countLetter(passwd, 4) > 0 || countLetter(passwd, 2) > 0 && countLetter(passwd, 3) > 0 && countLetter(passwd, 4) > 0) {
-                ++level;
-            }
-
-            if (len > 8 && countLetter(passwd, 1) > 0 && countLetter(passwd, 2) > 0 && countLetter(passwd, 3) > 0 && countLetter(passwd, 4) > 0) {
-                ++level;
-            }
-
-            if (len > 6 && countLetter(passwd, 1) >= 3 && countLetter(passwd, 2) >= 3 || countLetter(passwd, 1) >= 3 && countLetter(passwd, 3) >= 3 || countLetter(passwd, 1) >= 3 && countLetter(passwd, 4) >= 2 || countLetter(passwd, 2) >= 3 && countLetter(passwd, 3) >= 3 || countLetter(passwd, 2) >= 3 && countLetter(passwd, 4) >= 2 || countLetter(passwd, 3) >= 3 && countLetter(passwd, 4) >= 2) {
-                ++level;
-            }
-
-            if (len > 8 && countLetter(passwd, 1) >= 2 && countLetter(passwd, 2) >= 2 && countLetter(passwd, 3) >= 2 || countLetter(passwd, 1) >= 2 && countLetter(passwd, 2) >= 2 && countLetter(passwd, 4) >= 2 || countLetter(passwd, 1) >= 2 && countLetter(passwd, 3) >= 2 && countLetter(passwd, 4) >= 2 || countLetter(passwd, 2) >= 2 && countLetter(passwd, 3) >= 2 && countLetter(passwd, 4) >= 2) {
-                ++level;
-            }
-
-            if (len > 10 && countLetter(passwd, 1) >= 2 && countLetter(passwd, 2) >= 2 && countLetter(passwd, 3) >= 2 && countLetter(passwd, 4) >= 2) {
-                ++level;
-            }
-
-            if (countLetter(passwd, 4) >= 3) {
-                ++level;
-            }
-
-            if (countLetter(passwd, 4) >= 6) {
-                ++level;
-            }
-
-            if (len > 12) {
-                ++level;
-                if (len >= 16) {
-                    ++level;
-                }
-            }
-
-            if ("abcdefghijklmnopqrstuvwxyz".indexOf(passwd) > 0 || "ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(passwd) > 0) {
-                --level;
-            }
-
-            if ("qwertyuiop".indexOf(passwd) > 0 || "asdfghjkl".indexOf(passwd) > 0 || "zxcvbnm".indexOf(passwd) > 0) {
-                --level;
-            }
-
-            if (StringTools.isNumeric(passwd) && ("01234567890".indexOf(passwd) > 0 || "09876543210".indexOf(passwd) > 0)) {
-                --level;
-            }
-
-            if (countLetter(passwd, 1) == len || countLetter(passwd, 2) == len || countLetter(passwd, 3) == len) {
-                --level;
-            }
-
-            String part1;
-            String part2;
-            if (len % 2 == 0) {
-                part1 = passwd.substring(0, len / 2);
-                part2 = passwd.substring(len / 2);
-                if (part1.equals(part2)) {
-                    --level;
-                }
-
-                if (StringTools.isCharEqual(part1) && StringTools.isCharEqual(part2)) {
-                    --level;
-                }
-            }
-
-            if (len % 3 == 0) {
-                part1 = passwd.substring(0, len / 3);
-                part2 = passwd.substring(len / 3, len / 3 * 2);
-                String part3 = passwd.substring(len / 3 * 2);
-                if (part1.equals(part2) && part2.equals(part3)) {
-                    --level;
-                }
-            }
-
-            int i;
-            if (StringTools.isNumeric(passwd) && len >= 6) {
-                i = 0;
-                if (len == 8 || len == 6) {
-                    i = Integer.parseInt(passwd.substring(0, len - 4));
-                }
-
-                int size = StringTools.sizeOfInt(i);
-                int month = Integer.parseInt(passwd.substring(size, size + 2));
-                int day = Integer.parseInt(passwd.substring(size + 2, len));
-                if (i >= 1950 && i < 2050 && month >= 1 && month <= 12 && day >= 1 && day <= 31) {
-                    --level;
-                }
-            }
-
-            if (null != DICTIONARY && DICTIONARY.length > 0) {
-                for(i = 0; i < DICTIONARY.length; ++i) {
-                    if (passwd.equals(DICTIONARY[i]) || DICTIONARY[i].indexOf(passwd) >= 0) {
-                        --level;
-                        break;
-                    }
-                }
-            }
-
-            if (len <= 6) {
-                --level;
-                if (len <= 4) {
-                    --level;
-                    if (len <= 3) {
-                        level = 0;
-                    }
-                }
-            }
-
-            if (StringTools.isCharEqual(passwd)) {
-                level = 0;
-            }
-
-            if (level < 0) {
-                level = 0;
-            }
-
-            return level;
-        }
-    }
-
-    public static PasswordTools.LEVEL getPasswordLevel(String passwd) {
-        int level = checkPasswordStrength(passwd);
-        switch(level) {
-            case 0:
-            case 1:
-            case 2:
-            case 3:
-                return PasswordTools.LEVEL.EASY;
-            case 4:
-            case 5:
-            case 6:
-                return PasswordTools.LEVEL.MIDIUM;
-            case 7:
-            case 8:
-            case 9:
-                return PasswordTools.LEVEL.STRONG;
-            case 10:
-            case 11:
-            case 12:
-                return PasswordTools.LEVEL.VERY_STRONG;
-            default:
-                return PasswordTools.LEVEL.EXTREMELY_STRONG;
-        }
-    }
-
-    public static enum LEVEL {
-        EASY,
-        MIDIUM,
-        STRONG,
-        VERY_STRONG,
-        EXTREMELY_STRONG;
-
-        private LEVEL() {
-        }
-    }
-}

+ 10 - 2
o2server/x_base_core_project/src/main/java/com/x/base/core/project/tools/StringTools.java

@@ -380,10 +380,11 @@ public class StringTools {
 	}
 
 	public static String escapeSqlLikeKey(String str) {
-		if (StringUtils.isEmpty(str)) {
+		String text = StringUtils.replace(str, "\u3000", " ");
+		if (StringUtils.isEmpty(text)) {
 			return str;
 		} else {
-			return StringUtils.trim(StringUtils.replaceEach(str, SQL_LIKE, SQL_LIKE_SHIFT));
+			return StringUtils.trim(StringUtils.replaceEach(text, SQL_LIKE, SQL_LIKE_SHIFT));
 		}
 	}
 
@@ -429,4 +430,11 @@ public class StringTools {
 			return true;
 		}
 	}
+
+	public static boolean isAbsolutePath(String path) {
+		if (path.startsWith("/") || path.indexOf(":") > 0) {
+			return true;
+		}
+		return false;
+	}
 }

+ 0 - 25
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_bbs_assemble_control.java

@@ -15,29 +15,4 @@ import com.x.base.core.project.annotation.ModuleType;
 				"x_bbs_core_entity", "x_organization_core_express",
 				"x_organization_core_entity" }, storageTypes = { StorageType.bbs })
 public class x_bbs_assemble_control extends Deployable {
-
-//	public x_bbs_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSForumInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSSectionInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSSubjectInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSSubjectContent");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSReplyInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSSubjectAttachment");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSOperationRecord");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSUserInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSUserRole");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSRoleInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSPermissionRole");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSPermissionInfo");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSConfigSetting");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSVoteRecord");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSVoteOption");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSVoteOptionGroup");
-//		dependency.containerEntities.add("com.x.bbs.entity.BBSSubjectVoteResult");
-//		dependency.storageTypes.add(StorageType.bbs.toString());
-//		dependency.storeJars.add(x_bbs_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//	}
 }

+ 1 - 14
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_calendar_assemble_control.java

@@ -6,22 +6,9 @@ import com.x.base.core.project.annotation.ModuleCategory;
 import com.x.base.core.project.annotation.ModuleType;
 
 @Module(type = ModuleType.ASSEMBLE, category = ModuleCategory.OFFICIAL, name = "日程管理", packageName = "com.x.calendar.assemble.control", containerEntities = {
-		"com.x.calendar.core.entity.Calendar", "com.x.calendar.core.entity.Calendar_Event",
+		"com.x.calendar.core.entity.Calendar", "com.x.calendar.core.entity.Calendar_Event","com.x.calendar.core.entity.Calendar_EventComment",
 		"com.x.calendar.core.entity.Calendar_EventRepeatMaster", "com.x.calendar.core.entity.Calendar_Setting",
 		"com.x.calendar.core.entity.Calendar_SettingLobValue" }, storageTypes = { StorageType.calendar }, storeJars = {
 				"x_organization_core_express", "x_organization_core_entity", "x_calendar_core_entity" })
 public class x_calendar_assemble_control extends Deployable {
-
-//	public x_calendar_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.calendar.core.entity.Calendar");
-//		dependency.containerEntities.add("com.x.calendar.core.entity.Calendar_Event");
-//		dependency.containerEntities.add("com.x.calendar.core.entity.Calendar_EventRepeatMaster");
-//		dependency.containerEntities.add("com.x.calendar.core.entity.Calendar_Setting");
-//		dependency.containerEntities.add("com.x.calendar.core.entity.Calendar_SettingLobValue");
-//		dependency.storageTypes.add(StorageType.calendar.toString());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_calendar_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 39
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_cms_assemble_control.java

@@ -22,43 +22,4 @@ import com.x.base.core.project.annotation.ModuleType;
 						"x_organization_core_entity", "x_organization_core_express", "x_cms_core_entity","x_cms_core_express",
 						"x_query_core_entity", "x_query_core_express" })
 public class x_cms_assemble_control extends Deployable {
-
-//	public x_cms_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.AppDict");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.AppDictItem");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.Form");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.FormField");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.QueryView");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.Script");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.TemplateForm");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.View");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.ViewCategory");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.ViewFieldConfig");
-//		dependency.containerEntities.add("com.x.cms.core.entity.AppInfo");
-//		dependency.containerEntities.add("com.x.cms.core.entity.CategoryInfo");
-//		dependency.containerEntities.add("com.x.cms.core.entity.CategoryExt");
-//		dependency.containerEntities.add("com.x.cms.core.entity.Document");
-//		dependency.containerEntities.add("com.x.cms.core.entity.DocumentViewRecord");
-//		dependency.containerEntities.add("com.x.cms.core.entity.element.File");
-//		dependency.containerEntities.add("com.x.cms.core.entity.FileInfo");
-//		dependency.containerEntities.add("com.x.cms.core.entity.Log");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Attachment");
-//		dependency.containerEntities.add("com.x.query.core.entity.Item");
-//		dependency.containerEntities.add("com.x.query.core.entity.View");
-//		dependency.containerEntities.add("com.x.cms.core.entity.ReadRemind");
-//		dependency.containerEntities.add("com.x.cms.core.entity.DocumentCommend");
-//		dependency.containerEntities.add("com.x.cms.core.entity.DocumentCommentInfo");
-//		dependency.containerEntities.add("com.x.cms.core.entity.CmsBatchOperation");
-//
-//		dependency.storageTypes.add(StorageType.cms.toString());
-//		dependency.storageTypes.add(StorageType.processPlatform.toString());
-//		dependency.storeJars.add(x_processplatform_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_cms_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_query_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_query_core_express.class.getSimpleName());
-//	}
-
 }

+ 0 - 6
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_component_assemble_control.java

@@ -7,10 +7,4 @@ import com.x.base.core.project.annotation.ModuleType;
 @Module(type = ModuleType.ASSEMBLE, category = ModuleCategory.OFFICIAL, name = "组件", packageName = "com.x.component.assemble.control", containerEntities = {
 		"com.x.component.core.entity.Component" }, storeJars = { "x_component_core_entity" })
 public class x_component_assemble_control extends Deployable {
-
-//	public x_component_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.component.core.entity.Component");
-//		dependency.storeJars.add(x_component_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 11
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_file_assemble_control.java

@@ -11,15 +11,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.file.core.entity.open.OriginFile","com.x.file.core.entity.personal.Recycle" },
 		storageTypes = { StorageType.file }, storeJars = { "x_file_core_entity", "x_organization_core_express", "x_organization_core_entity" })
 public class x_file_assemble_control extends Deployable {
-
-//	public x_file_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.file.core.entity.personal.Folder");
-//		dependency.containerEntities.add("com.x.file.core.entity.personal.Attachment");
-//		dependency.containerEntities.add("com.x.file.core.entity.open.File");
-//		dependency.storageTypes.add(StorageType.file.toString());
-//		dependency.storeJars.add(x_file_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//	}
 }

+ 0 - 7
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_general_assemble_control.java

@@ -9,11 +9,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.general.core.entity.area.District" }, storageTypes = {
 				StorageType.file }, storeJars = { "x_general_core_entity" })
 public class x_general_assemble_control extends Deployable {
-
-//	public x_general_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.general.core.entity.area.District");
-//		dependency.storageTypes.add(StorageType.file.toString());
-//		dependency.storeJars.add(x_general_core_entity.class.getSimpleName());
-//	}
 }

+ 13 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_jpush_assemble_control.java

@@ -0,0 +1,13 @@
+package com.x.base.core.project;
+
+import com.x.base.core.project.annotation.Module;
+import com.x.base.core.project.annotation.ModuleCategory;
+import com.x.base.core.project.annotation.ModuleType;
+
+@Module(type = ModuleType.ASSEMBLE, category = ModuleCategory.OFFICIAL, name = "极光推送服务模块",
+		packageName = "com.x.jpush.assemble.control",
+		containerEntities = { "com.x.jpush.core.entity.SampleEntityClassName" },
+		storeJars = { "x_organization_core_entity", "x_organization_core_express" },
+		customJars = { "x_jpush_core_entity" })
+public class x_jpush_assemble_control extends Deployable {
+}

+ 10 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_jpush_core_entity.java

@@ -0,0 +1,10 @@
+package com.x.base.core.project;
+
+import com.x.base.core.project.annotation.Module;
+import com.x.base.core.project.annotation.ModuleCategory;
+import com.x.base.core.project.annotation.ModuleType;
+
+@Module(type = ModuleType.ENTITY, category = ModuleCategory.OFFICIAL, name = "极光推送外挂服务实体类", packageName = "com.x.jpush.core.entity")
+public class x_jpush_core_entity extends Compilable {
+
+}

+ 0 - 12
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_meeting_assemble_control.java

@@ -10,16 +10,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.meeting.core.entity.Attachment" }, storageTypes = { StorageType.meeting }, storeJars = {
 				"x_organization_core_entity", "x_organization_core_express", "x_meeting_core_entity" })
 public class x_meeting_assemble_control extends Deployable {
-
-//	public x_meeting_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.meeting.core.entity.Building");
-//		dependency.containerEntities.add("com.x.meeting.core.entity.Room");
-//		dependency.containerEntities.add("com.x.meeting.core.entity.Meeting");
-//		dependency.containerEntities.add("com.x.meeting.core.entity.Attachment");
-//		dependency.storageTypes.add(StorageType.meeting.toString());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_meeting_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 11
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_message_assemble_communicate.java

@@ -9,15 +9,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.message.core.entity.Mass" }, storeJars = { "x_message_core_entity", "x_meeting_core_entity",
 				"x_processplatform_core_entity", "x_organization_core_express" })
 public class x_message_assemble_communicate extends Deployable {
-
-//	public x_message_assemble_communicate() {
-//		super();
-//		dependency.containerEntities.add("com.x.message.core.entity.Instant");
-//		dependency.containerEntities.add("com.x.message.core.entity.Message");
-//		dependency.containerEntities.add("com.x.message.core.entity.Mass");
-//		dependency.storeJars.add(x_message_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_meeting_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_processplatform_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//	}
 }

+ 0 - 15
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_mind_assemble_control.java

@@ -10,19 +10,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.mind.entity.MindVersionInfo", "com.x.mind.entity.MindVersionContent" }, storeJars = {
 				"x_organization_core_entity", "x_organization_core_express", "x_mind_core_entity" })
 public class x_mind_assemble_control extends Deployable {
-
-//	public x_mind_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.mind.entity.MindBaseInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindContentInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindFolderInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindIconInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindRecycleInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindShareRecord");
-//		dependency.containerEntities.add("com.x.mind.entity.MindVersionInfo");
-//		dependency.containerEntities.add("com.x.mind.entity.MindVersionContent");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_mind_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 32
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_okr_assemble_control.java

@@ -20,36 +20,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.okr.entity.OkrWorkAppraiseInfo" }, storageTypes = { StorageType.okr }, storeJars = {
 				"x_organization_core_entity", "x_organization_core_express", "x_okr_core_entity" })
 public class x_okr_assemble_control extends Deployable {
-
-//	public x_okr_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.okr.entity.OkrAttachmentFileInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrCenterWorkInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrConfigSecretary");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrConfigSystem");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrConfigWorkLevel");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrConfigWorkType");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrTask");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrTaskHandled");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkAuthorizeRecord");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkBaseInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkDetailInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkDynamics");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkPerson");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkReportBaseInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkReportDetailInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkReportPersonLink");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkReportProcessLog");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkChat");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrStatisticReportContent");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrStatisticReportStatus");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrUserInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrErrorSystemIdentityInfo");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrErrorIdentityRecords");
-//		dependency.containerEntities.add("com.x.okr.entity.OkrWorkAppraiseInfo");
-//		dependency.storageTypes.add(StorageType.okr.toString());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_okr_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 11
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_organization_assemble_authentication.java

@@ -10,15 +10,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.organization.core.entity.OauthCode" }, storeJars = { "x_organization_core_entity",
 				"x_organization_core_express" })
 public class x_organization_assemble_authentication extends Deployable {
-
-//	public x_organization_assemble_authentication() {
-//		super();
-//		dependency.containerEntities.add("com.x.organization.core.entity.Person");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Identity");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Role");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Bind");
-//		dependency.containerEntities.add("com.x.organization.core.entity.OauthCode");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//	}
 }

+ 0 - 14
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_organization_assemble_control.java

@@ -11,18 +11,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.organization.core.entity.Unit", "com.x.organization.core.entity.UnitAttribute",
 		"com.x.organization.core.entity.UnitDuty" }, storeJars = { "x_organization_core_entity" })
 public class x_organization_assemble_control extends Deployable {
-
-//	public x_organization_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.organization.core.entity.Group");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Custom");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Role");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Person");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Identity");
-//		dependency.containerEntities.add("com.x.organization.core.entity.PersonAttribute");
-//		dependency.containerEntities.add("com.x.organization.core.entity.Unit");
-//		dependency.containerEntities.add("com.x.organization.core.entity.UnitAttribute");
-//		dependency.containerEntities.add("com.x.organization.core.entity.UnitDuty");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 13
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_portal_assemble_designer.java

@@ -10,17 +10,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.portal.core.entity.TemplatePage" }, storeJars = { "x_organization_core_entity",
 				"x_organization_core_express", "x_portal_core_entity" })
 public class x_portal_assemble_designer extends Deployable {
-
-//	public x_portal_assemble_designer() {
-//		super();
-//		dependency.containerEntities.add("com.x.portal.core.entity.Portal");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Widget");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Page");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Script");
-//		dependency.containerEntities.add("com.x.portal.core.entity.File");
-//		dependency.containerEntities.add("com.x.portal.core.entity.TemplatePage");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_portal_core_entity.class.getSimpleName());
-//	}
 }

+ 0 - 12
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_portal_assemble_surface.java

@@ -9,16 +9,4 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.portal.core.entity.Script", "com.x.portal.core.entity.File" }, storeJars = {
 				"x_organization_core_entity", "x_organization_core_express", "x_portal_core_entity" })
 public class x_portal_assemble_surface extends Deployable {
-
-//	public x_portal_assemble_surface() {
-//		super();
-//		dependency.containerEntities.add("com.x.portal.core.entity.Portal");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Widget");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Page");
-//		dependency.containerEntities.add("com.x.portal.core.entity.Script");
-//		dependency.containerEntities.add("com.x.portal.core.entity.File");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_portal_core_entity.class.getSimpleName());
-//	}
 }

+ 3 - 3
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_assemble_designer.java

@@ -27,9 +27,9 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.processplatform.core.entity.element.End", "com.x.processplatform.core.entity.element.ApplicationDict",
 		"com.x.processplatform.core.entity.element.ApplicationDictItem",
 		"com.x.processplatform.core.entity.element.QueryView", "com.x.processplatform.core.entity.element.QueryStat",
-		"com.x.processplatform.core.entity.element.Projection", "com.x.processplatform.core.entity.element.Mapping",
-		"com.x.query.core.entity.Item", "com.x.query.dynamic.entity.*" }, storeJars = { "x_organization_core_entity",
-				"x_organization_core_express", "x_processplatform_core_entity", "x_query_core_entity" }, dynamicJars = {
+		"com.x.processplatform.core.entity.element.Mapping", "com.x.query.core.entity.Item",
+		"com.x.query.dynamic.entity.*" }, storeJars = { "x_organization_core_entity", "x_organization_core_express",
+				"x_processplatform_core_entity", "x_query_core_entity" }, dynamicJars = {
 						"x_query_dynamic_entity" }, storageTypes = { StorageType.processPlatform })
 public class x_processplatform_assemble_designer extends Deployable {
 

+ 4 - 50
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_assemble_surface.java

@@ -25,55 +25,9 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.processplatform.core.entity.element.Process", "com.x.processplatform.core.entity.element.Route",
 		"com.x.processplatform.core.entity.element.Script", "com.x.processplatform.core.entity.element.Service",
 		"com.x.processplatform.core.entity.element.Split", "com.x.processplatform.core.entity.element.QueryView",
-		"com.x.processplatform.core.entity.element.QueryStat", "com.x.processplatform.core.entity.element.Projection",
-		"com.x.processplatform.core.entity.element.Mapping", "com.x.query.core.entity.Item" }, storageTypes = {
-				StorageType.processPlatform }, storeJars = { "x_organization_core_entity",
-						"x_organization_core_express", "x_processplatform_core_entity", "x_query_core_entity" })
+		"com.x.processplatform.core.entity.element.QueryStat", "com.x.processplatform.core.entity.element.Mapping",
+		"com.x.query.core.entity.Item" }, storageTypes = { StorageType.processPlatform }, storeJars = {
+				"x_organization_core_entity", "x_organization_core_express", "x_processplatform_core_entity",
+				"x_query_core_entity" })
 public class x_processplatform_assemble_surface extends Deployable {
-
-//	public x_processplatform_assemble_surface() {
-//		super();
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Attachment");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Read");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.ReadCompleted");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Review");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Hint");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.SerialNumber");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Task");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.TaskCompleted");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Work");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.WorkCompleted");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.WorkLog");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Agent");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Application");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.ApplicationDict");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.ApplicationDictItem");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Begin");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Cancel");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Choice");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Delay");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Embed");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.End");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.File");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Form");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.FormField");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Invoke");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Manual");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Merge");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Message");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Parallel");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Process");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Route");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Script");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Service");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.Split");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.QueryView");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.element.QueryStat");
-//		dependency.containerEntities.add("com.x.query.core.entity.Item");
-//		dependency.storageTypes.add(StorageType.processPlatform.toString());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_processplatform_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_query_core_entity.class.getSimpleName());
-//	}
 }

+ 2 - 3
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_processplatform_service_processing.java

@@ -25,9 +25,8 @@ import com.x.base.core.project.annotation.ModuleType;
 		"com.x.processplatform.core.entity.element.Service", "com.x.processplatform.core.entity.element.Agent",
 		"com.x.processplatform.core.entity.element.Delay", "com.x.processplatform.core.entity.element.File",
 		"com.x.processplatform.core.entity.element.Form", "com.x.processplatform.core.entity.element.FormField",
-		"com.x.processplatform.core.entity.element.Embed", "com.x.processplatform.core.entity.element.Projection",
-		"com.x.processplatform.core.entity.element.Mapping", "com.x.processplatform.core.entity.log.ProcessingError",
-		"com.x.query.core.entity.Item",
+		"com.x.processplatform.core.entity.element.Embed", "com.x.processplatform.core.entity.element.Mapping",
+		"com.x.processplatform.core.entity.log.ProcessingError", "com.x.query.core.entity.Item",
 		"com.x.query.dynamic.entity.*" }, storageTypes = { StorageType.processPlatform }, storeJars = {
 				"x_organization_core_entity", "x_organization_core_express", "x_processplatform_core_entity",
 				"x_query_core_entity" }, dynamicJars = { "x_query_dynamic_entity" })

+ 0 - 36
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_query_assemble_surface.java

@@ -21,40 +21,4 @@ import com.x.base.core.project.annotation.ModuleType;
 				"x_processplatform_core_entity", "x_cms_core_entity",
 				"x_query_core_express" }, dynamicJars = { "x_query_dynamic_entity" })
 public class x_query_assemble_surface extends Deployable {
-
-//	public x_query_assemble_surface() {
-//		super();
-//		dependency.containerEntities.add("com.x.query.core.entity.Item");
-//		dependency.containerEntities.add("com.x.query.core.entity.Query");
-//		dependency.containerEntities.add("com.x.query.core.entity.View");
-//		dependency.containerEntities.add("com.x.query.core.entity.Stat");
-//		dependency.containerEntities.add("com.x.query.core.entity.Reveal");
-//		dependency.containerEntities.add("com.x.query.core.entity.segment.Word");
-//		dependency.containerEntities.add("com.x.query.core.entity.segment.Entry");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.Entry");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.InText");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.OutText");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.InValue");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.OutValue");
-//		dependency.containerEntities.add("com.x.query.core.entity.neural.Model");
-//		dependency.containerEntities.add("com.x.query.core.entity.schema.Table");
-//		dependency.containerEntities.add("com.x.query.core.entity.schema.Statement");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Review");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Work");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.WorkCompleted");
-//		dependency.containerEntities.add("com.x.processplatform.core.entity.content.Attachment");
-//		dependency.containerEntities.add("com.x.cms.core.entity.Document");
-//		dependency.containerEntities.add("com.x.cms.core.entity.AppInfo");
-//		dependency.containerEntities.add("com.x.cms.core.entity.CategoryInfo");
-//		dependency.containerEntities.add("com.x.query.dynamic.entity.*");
-//		dependency.storageTypes.add(StorageType.processPlatform.toString());
-//		dependency.storageTypes.add(StorageType.cms.toString());
-//		dependency.storeJars.add(x_query_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_processplatform_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_cms_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_query_core_express.class.getSimpleName());
-//		dependency.dynamicJars.add("x_query_dynamic_entity");
-//	}
 }

+ 0 - 24
o2server/x_base_core_project/src/main/java/com/x/base/core/project/x_teamwork_assemble_control.java

@@ -20,28 +20,4 @@ containerEntities = {
 		"com.x.teamwork.core.entity.Dynamic", "com.x.teamwork.core.entity.DynamicDetail" }, storeJars = { "x_organization_core_entity",
 		"x_organization_core_express", "x_teamwork_core_entity" })
 public class x_teamwork_assemble_control extends Deployable {
-
-//	public x_teamwork_assemble_control() {
-//		super();
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.Chat");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.ChatContent");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.Dynamic");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.DynamicDetail");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.Project");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.ProjectDetail");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.ProjectExtFieldRele");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.ProjectGroup");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.ProjectGroupRele");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.Task");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.TaskDetail");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.TaskList");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.TaskListRele");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.TaskRelevance");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.TaskView");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.SystemConfig");
-//		dependency.containerEntities.add("com.x.teamwork.core.entity.SystemConfigLobValue");
-//		dependency.storeJars.add(x_organization_core_entity.class.getSimpleName());
-//		dependency.storeJars.add(x_organization_core_express.class.getSimpleName());
-//		dependency.storeJars.add(x_teamwork_core_entity.class.getSimpleName());
-//	}
 }

+ 17 - 0
o2server/x_bbs_assemble_control/pom.xml

@@ -48,6 +48,23 @@
 							</arguments>
 						</configuration>
 					</execution>
+					<execution>
+						<id>apiBuilder</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>java</goal>
+						</goals>
+						<configuration>
+							<addOutputToClasspath>true</addOutputToClasspath>
+							<includePluginDependencies>true</includePluginDependencies>
+							<includeProjectDependencies>true</includeProjectDependencies>
+							<mainClass>com.x.base.core.project.annotation.ApiBuilder</mainClass>
+							<arguments>
+								<argument>${basedir}</argument>
+								<argument>${project.build.sourceDirectory}</argument>
+							</arguments>
+						</configuration>
+					</execution>
 					<execution>
 						<id>checkAssemble</id>
 						<phase>prepare-package</phase>

+ 102 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/MessageFactory.java

@@ -0,0 +1,102 @@
+package com.x.bbs.assemble.control;
+
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.message.MessageConnector;
+import com.x.base.core.project.tools.ListTools;
+import com.x.bbs.assemble.control.queue.MessageWo;
+import org.apache.commons.lang3.StringUtils;
+import java.util.List;
+
+public class MessageFactory {
+
+	private static Logger logger = LoggerFactory.getLogger( MessageFactory.class );
+
+	/**
+	 * 新的回复,通知相关管理员
+	 * @param persons
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifyManager_forNewReply(List<String> persons, MessageWo messageWo ) throws Exception {
+		if(ListTools.isNotEmpty( persons )){
+			for( String person : persons ){
+				notifyManager_forNewReply( person, messageWo );
+			}
+		}
+	}
+
+	/**
+	 * 新的回复,通知主题创建者
+	 * @param persons
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifySubjectCreator_forNewReply(List<String> persons, MessageWo messageWo ) throws Exception {
+		if(ListTools.isNotEmpty( persons )){
+			for( String person : persons ){
+				notifySubjectCreator_forNewReply( person, messageWo );
+			}
+
+		}
+	}
+
+	/**
+	 * 新的回复,通知相关管理员
+	 * @param person
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifyManager_forNewReply( String person, MessageWo messageWo ) throws Exception {
+		if(StringUtils.isNotEmpty( person ) ){
+			String personName = StringUtils.isNotEmpty( messageWo.getCreatePerson() )?"":messageWo.getCreatePerson().split("@")[0];
+			String title = personName + "发表了新的回复:" + messageWo.getTitle();
+			logger.debug("bbs send notification:new reply for subject [" +  messageWo.getTitle() + "], target:" + person );
+			MessageConnector.send( MessageConnector.TYPE_BBS_REPLYCREATE,  title, person, messageWo );
+		}
+	}
+
+	/**
+	 * 新的回复,通知主题创建者
+	 * @param person
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifySubjectCreator_forNewReply( String person, MessageWo messageWo ) throws Exception {
+		if(StringUtils.isNotEmpty( person ) ){
+			String personName = StringUtils.isNotEmpty( messageWo.getCreatePerson() )?"":messageWo.getCreatePerson().split("@")[0];
+			String title = personName + "回复了您发表的主题:" + messageWo.getTitle();
+			logger.debug("bbs send notification:new reply for subject [" +  messageWo.getTitle() + "], target:" + person );
+			MessageConnector.send( MessageConnector.TYPE_BBS_REPLYCREATE,  title, person, messageWo );
+		}
+	}
+
+	/**
+	 * 新的主题发表,通知相关管理员
+	 * @param persons
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifyManager_forNewSubject(List<String> persons, MessageWo messageWo ) throws Exception {
+		if(ListTools.isNotEmpty( persons )){
+			for( String person : persons ){
+				notifyManager_forNewSubject( person, messageWo );
+			}
+		}
+	}
+
+	/**
+	 * 新的主题发表,通知相关管理员
+	 * @param person
+	 * @param messageWo
+	 * @throws Exception
+	 */
+	public static void notifyManager_forNewSubject( String person, MessageWo messageWo ) throws Exception {
+		if(StringUtils.isNotEmpty( person ) ){
+			String personName = StringUtils.isNotEmpty( messageWo.getCreatePerson() )?"":messageWo.getCreatePerson().split("@")[0];
+			String title = personName + "发表了新的主题:" + messageWo.getTitle();
+			logger.debug("bbs send notification:new reply for subject [" +  messageWo.getTitle() + "], target:" + person );
+			MessageConnector.send( MessageConnector.TYPE_BBS_SUBJECTCREATE,  title, person, messageWo );
+		}
+	}
+}

+ 15 - 3
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/ThisApplication.java

@@ -5,7 +5,10 @@ import java.util.List;
 import com.x.base.core.project.Context;
 import com.x.base.core.project.http.EffectivePerson;
 import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.message.MessageConnector;
 import com.x.base.core.project.tools.ListTools;
+import com.x.bbs.assemble.control.queue.QueueNewReplyNotify;
+import com.x.bbs.assemble.control.queue.QueueNewSubjectNotify;
 import com.x.bbs.assemble.control.schedule.SubjectReplyTotalStatisticTask;
 import com.x.bbs.assemble.control.schedule.SubjectTotalStatisticTask;
 import com.x.bbs.assemble.control.schedule.UserSubjectReplyPermissionStatisticTask;
@@ -21,9 +24,10 @@ import com.x.bbs.entity.BBSSectionInfo;
 public class ThisApplication {
 	
 	protected static Context context;
-	
-	public static final String BBSMANAGER = "BBSManager";
-	
+	public static final String BBSMANAGER = "BBSManager@CMSManagerSystemRole@R";
+	public static QueueNewReplyNotify queueNewReplyNotify;
+	public static QueueNewSubjectNotify queueNewSubjectNotify;
+
 	public static Context context() {
 		return context;
 	}
@@ -31,6 +35,14 @@ public class ThisApplication {
 	public static void init() throws Exception {
 		try {
 			initAllSystemConfig();
+			queueNewReplyNotify = new QueueNewReplyNotify();
+			queueNewSubjectNotify = new QueueNewSubjectNotify();
+
+			MessageConnector.start(context());
+
+			context().startQueue( queueNewReplyNotify );
+			context().startQueue( queueNewSubjectNotify );
+
 			context.schedule( SubjectTotalStatisticTask.class, "0 10 * * * ?");
 			context.schedule( SubjectReplyTotalStatisticTask.class, "0 40 * * * ?");
 			context.schedule( UserSubjectReplyPermissionStatisticTask.class, "0 0/30 * * * ?");

+ 23 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/factory/BBSVoteRecordFactory.java

@@ -136,4 +136,27 @@ public class BBSVoteRecordFactory extends AbstractFactory {
 		cq.orderBy( cb.desc( root.get( BBSVoteRecord_.createTime ) ) );
 		return em.createQuery(cq.where(p)).setMaxResults( maxRecordCount ).getResultList();
 	}
+
+	/**
+	 * 根据人员和选项组查询人员选择过的所有选项列表
+	 * @param personName
+	 * @param optionGroupId
+	 * @return
+	 * @throws Exception
+	 */
+	public List<BBSVoteRecord> listVoteCountByUserAndGroup(String personName, String optionGroupId) throws Exception {
+		if( StringUtils.isEmpty( personName ) ){
+			throw new Exception( "personName is empty!" );
+		}
+		if( StringUtils.isEmpty( optionGroupId ) ){
+			throw new Exception( "optionGroupId is empty!" );
+		}
+		EntityManager em = this.entityManagerContainer().get( BBSVoteRecord.class );
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<BBSVoteRecord> cq = cb.createQuery( BBSVoteRecord.class);
+		Root<BBSVoteRecord> root = cq.from( BBSVoteRecord.class );
+		Predicate p = cb.equal( root.get( BBSVoteRecord_.votorName ), personName );
+		p = cb.and( p, cb.equal( root.get( BBSVoteRecord_.optionGroupId ), optionGroupId ));
+		return em.createQuery(cq.where(p)).getResultList();
+	}
 }

+ 2 - 1
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/attachment/ActionAttachmentDelete.java

@@ -12,6 +12,7 @@ import com.x.base.core.project.http.EffectivePerson;
 import com.x.base.core.project.jaxrs.WoId;
 import com.x.base.core.project.logger.Logger;
 import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
 import com.x.bbs.assemble.control.ThisApplication;
 import com.x.bbs.assemble.control.jaxrs.subjectinfo.exception.ExceptionAttachmentIdEmpty;
 import com.x.bbs.assemble.control.jaxrs.subjectinfo.exception.ExceptionAttachmentNotExists;
@@ -76,7 +77,7 @@ public class ActionAttachmentDelete extends BaseAction {
 					subjectInfo = emc.find(subjectAttachment.getSubjectId(), BBSSubjectInfo.class);
 					emc.beginTransaction(BBSSubjectAttachment.class);
 					emc.beginTransaction(BBSSubjectInfo.class);
-					if (subjectInfo != null && subjectInfo.getAttachmentList() != null) {
+					if (subjectInfo != null && ListTools.isNotEmpty(subjectInfo.getAttachmentList())) {
 						subjectInfo.getAttachmentList().remove(subjectAttachment.getId());
 						emc.check(subjectInfo, CheckPersistType.all);
 					}

+ 11 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/replyinfo/ActionSave.java

@@ -5,6 +5,7 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import com.x.bbs.assemble.control.ThisApplication;
 import org.apache.commons.lang3.StringUtils;
 
 import com.google.gson.JsonElement;
@@ -274,6 +275,16 @@ public class ActionSave extends BaseAction {
 				logger.error(e, effectivePerson, request, null);
 			}
 		}
+
+		if ( check ) {
+			//根据论坛(Forum)、版块(Selection)以及主版块(MainSelection)相关配置判断该回帖是否允许消息提醒和邮件提醒发贴人
+			try {
+				ThisApplication.queueNewReplyNotify.send( replyInfo );
+			} catch (Exception e) {
+				logger.error(e, effectivePerson, request, null);
+			}
+
+		}
 		return result;
 	}
 

+ 1 - 1
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/replyinfo/BaseAction.java

@@ -25,7 +25,7 @@ public class BaseAction extends StandardJaxrsAction{
 	protected BBSForumInfoServiceAdv forumInfoServiceAdv = new BBSForumInfoServiceAdv();
 	protected BBSOperationRecordService operationRecordService = new BBSOperationRecordService();
 	protected UserManagerService userManagerService = new UserManagerService();
-	
+
 	protected Boolean checkUserPermission( String checkPermissionCode, List<String> permissionInfoList ) {
 		if( ListTools.isNotEmpty( permissionInfoList ) ){
 			for( String permissionCode : permissionInfoList ){

+ 1 - 1
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/sectioninfo/ActionListSubSectionByMainSectionId.java

@@ -84,7 +84,7 @@ public class ActionListSubSectionByMainSectionId extends BaseAction {
 			}
 		}		
 		if( check ){
-			if( sectionInfoList != null && sectionInfoList.size() > 0 ){
+			if( ListTools.isNotEmpty( sectionInfoList ) ){
 				try {
 					wraps = Wo.copier.copy( sectionInfoList );
 					if( ListTools.isNotEmpty( wraps )) {

+ 5 - 4
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/sectioninfo/ActionSave.java

@@ -7,6 +7,7 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import com.x.base.core.project.tools.ListTools;
 import org.apache.commons.lang3.StringUtils;
 
 import com.google.gson.JsonElement;
@@ -42,7 +43,7 @@ public class ActionSave extends BaseAction {
 		ActionResult<Wo> result = new ActionResult<>();
 		Wo wo = new Wo();
 		Boolean check = true;
-		String[] names = null;
+		List<String> names = null;
 		String[] typeCategory = null;
 		String personName = null;
 		BBSForumInfo forumInfo = null;
@@ -149,9 +150,9 @@ public class ActionSave extends BaseAction {
 		}
 		// 校验版块管理员(版主)是否存在
 		if (check) {
-			if ( StringUtils.isNotEmpty( wrapIn.getModeratorNames() )) {
+			if ( ListTools.isNotEmpty( wrapIn.getModeratorNames() )) {
 				// 判断指定的用户是否存在
-				names = wrapIn.getModeratorNames().split(",");
+				names = wrapIn.getModeratorNames();
 				for (String name : names) {
 					try {
 						personName = userManagerService.getPersonNameByFlag( name );
@@ -170,7 +171,7 @@ public class ActionSave extends BaseAction {
 					}
 				}
 			} else {
-				wrapIn.setModeratorNames(effectivePerson.getDistinguishedName());
+				wrapIn.addModeratorName( effectivePerson.getDistinguishedName() );
 			}
 		}
 		if (check) {

+ 10 - 19
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/jaxrs/subjectinfo/ActionSubjectSubmitVoteResult.java

@@ -37,31 +37,24 @@ public class ActionSubjectSubmitVoteResult extends BaseAction {
 
 		try {
 			wrapIn = this.convertToWrapIn(jsonElement, Wi.class);
-		} catch (Exception e) {
-			check = false;
-			Exception exception = new ExceptionWrapInConvert(e, jsonElement);
-			result.error(exception);
-			logger.error(e, effectivePerson, request, null);
-		}
-
-		if (check) {
 			wrapIn.setHostIp(request.getRemoteHost());
-		}
-
-		if (check) {
-			if (wrapIn.getId() == null) {
+			if ( wrapIn.getId() == null ) {
 				check = false;
 				Exception exception = new ExceptionSubjectPropertyEmpty("主题ID");
 				result.error(exception);
 			}
-		}
-		if (check) {
-			if (wrapIn.getOptionGroups() == null || wrapIn.getOptionGroups().isEmpty()) {
+			if ( wrapIn.getOptionGroups() == null || wrapIn.getOptionGroups().isEmpty() ) {
 				check = false;
 				Exception exception = new ExceptionSubjectPropertyEmpty("用户投票选择");
 				result.error(exception);
 			}
+		} catch (Exception e) {
+			check = false;
+			Exception exception = new ExceptionWrapInConvert(e, jsonElement);
+			result.error(exception);
+			logger.error(e, effectivePerson, request, null);
 		}
+
 		if (check) {
 			try {
 				subjectInfo = subjectInfoServiceAdv.get(wrapIn.getId());
@@ -83,15 +76,13 @@ public class ActionSubjectSubmitVoteResult extends BaseAction {
 		}
 
 		if (check) {
-			if ("投票".equals(subjectInfo.getTypeCategory())) {
+			if ( "投票".equals(subjectInfo.getTypeCategory()) ) {
 				try {
 					subjectVoteService.submitVoteResult(effectivePerson, subjectInfo, wrapIn.getOptionGroups());
-					
 					ApplicationCache.notify( BBSSubjectInfo.class );
-					
 				} catch (Exception e) {
 					check = false;
-					Exception exception = new ExceptionSubjectOperation(e, "系统在保存投票选项信息时发生异常");
+					Exception exception = new ExceptionSubjectOperation(e, "系统在保存投票选项信息时发生异常!");
 					result.error(exception);
 					logger.error(e, effectivePerson, request, null);
 				}

+ 129 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/MessageWo.java

@@ -0,0 +1,129 @@
+package com.x.bbs.assemble.control.queue;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+
+import java.util.Date;
+
+public class MessageWo{
+
+    @FieldDescribe("主贴ID或者回复ID")
+    private String id;
+
+    @FieldDescribe("标题:主题或者回复的标题")
+    private String title;
+
+    @FieldDescribe("Subject | Subject")
+    private String type;
+
+    @FieldDescribe("主贴ID.")
+    private String subjectId;
+
+    @FieldDescribe("回贴ID")
+    private String replyId;
+
+    @FieldDescribe("论坛分区Id")
+    private String forumId;
+
+    @FieldDescribe("论坛分区名称")
+    private String forumName;
+
+    @FieldDescribe("版块Id")
+    private String selectionId;
+
+    @FieldDescribe("版块名称")
+    private String selectionName;
+
+    @FieldDescribe("操作者")
+    private String createPerson;
+
+    @FieldDescribe("操作时间")
+    private Date createTime;
+
+    public String getReplyId() {
+        return this.replyId;
+    }
+
+    public void setReplyId(final String replyId) {
+        this.replyId = replyId;
+    }
+
+    public String getSubjectId() {
+        return this.subjectId;
+    }
+
+    public void setSubjectId(final String subjectId) {
+        this.subjectId = subjectId;
+    }
+
+    public String getForumId() {
+        return this.forumId;
+    }
+
+    public void setForumId(final String forumId) {
+        this.forumId = forumId;
+    }
+
+    public String getForumName() {
+        return this.forumName;
+    }
+
+    public void setForumName(final String forumName) {
+        this.forumName = forumName;
+    }
+
+    public String getSelectionId() {
+        return this.selectionId;
+    }
+
+    public void setSelectionId(final String selectionId) {
+        this.selectionId = selectionId;
+    }
+
+    public String getSelectionName() {
+        return this.selectionName;
+    }
+
+    public void setSelectionName(final String selectionName) {
+        this.selectionName = selectionName;
+    }
+
+    public String getCreatePerson() {
+        return this.createPerson;
+    }
+
+    public void setCreatePerson(final String createPerson) {
+        this.createPerson = createPerson;
+    }
+
+    public Date getCreateTime() {
+        return this.createTime;
+    }
+
+    public void setCreateTime(final Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return this.title;
+    }
+
+    public void setTitle(final String title) {
+        this.title = title;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(final String type) {
+        this.type = type;
+    }
+}

+ 187 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/QueueNewReplyNotify.java

@@ -0,0 +1,187 @@
+package com.x.bbs.assemble.control.queue;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.queue.AbstractQueue;
+import com.x.base.core.project.tools.ListTools;
+import com.x.bbs.assemble.control.MessageFactory;
+import com.x.bbs.entity.BBSForumInfo;
+import com.x.bbs.entity.BBSReplyInfo;
+import com.x.bbs.entity.BBSSectionInfo;
+import com.x.bbs.entity.BBSSubjectInfo;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Document正式发布后,向所有的阅读者推送消息通知
+ */
+public class QueueNewReplyNotify extends AbstractQueue<BBSReplyInfo> {
+	
+	private static  Logger logger = LoggerFactory.getLogger( QueueNewReplyNotify.class );
+
+	public void execute( BBSReplyInfo replyInfo) throws Exception {
+		if( replyInfo == null ) {
+			logger.warn("can not send publish notify for subject reply, bbsReplyInfo is NULL!" );
+			return;
+		}
+		logger.debug("system try to send notify for new replyInfo:" + replyInfo.getTitle() );
+
+		BBSForumInfo forumInfo = null;
+		BBSSectionInfo mainSectionInfo = null;
+		BBSSectionInfo sectionInfo = null;
+		BBSSubjectInfo subjectInfo = null;
+		try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create() ) {
+			if( StringUtils.isNotEmpty( replyInfo.getForumId() )){
+				forumInfo = emc.find( replyInfo.getForumId(), BBSForumInfo.class );
+			}
+			if( StringUtils.isNotEmpty( replyInfo.getMainSectionId() )){
+				mainSectionInfo = emc.find( replyInfo.getMainSectionId(), BBSSectionInfo.class );
+			}
+			if( StringUtils.isNotEmpty( replyInfo.getSectionId() )){
+				sectionInfo = emc.find( replyInfo.getSectionId(), BBSSectionInfo.class );
+			}
+			if( StringUtils.isNotEmpty( replyInfo.getSubjectId() )){
+				subjectInfo = emc.find( replyInfo.getSubjectId(), BBSSubjectInfo.class );
+			}
+		}catch( Exception e ){
+			throw e;
+		}
+
+		Boolean send_pushMessage = false;
+		String replyMessageNotifyType = null;
+		if( sectionInfo !=null  ){
+			if( !sectionInfo.getReplyMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				replyMessageNotifyType = sectionInfo.getReplyMessageNotifyType();
+			}
+		}else{
+			send_pushMessage = false;
+		}
+
+		if( mainSectionInfo !=null  ){
+			if( !mainSectionInfo.getReplyMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				replyMessageNotifyType = mainSectionInfo.getReplyMessageNotifyType();
+			}
+		}
+
+		if( forumInfo !=null  ){
+			if( !forumInfo.getReplyMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				replyMessageNotifyType = forumInfo.getReplyMessageNotifyType();
+			}
+		}else{
+			send_pushMessage = false;
+		}
+
+		MessageWo wo = composeMessageWo( forumInfo, sectionInfo, subjectInfo, replyInfo );
+		if( send_pushMessage && StringUtils.isNotEmpty( replyMessageNotifyType )){
+			//尝试发送pushMessage
+			List<String> managerAndModerator = caculatePerson( forumInfo, sectionInfo, replyMessageNotifyType );
+			//去一下重复
+			HashSet<String> set = new HashSet<String>( managerAndModerator );
+			managerAndModerator.clear();
+			managerAndModerator.addAll(set);
+
+			//向管理员发送Message通知
+			MessageFactory.notifyManager_forNewReply( managerAndModerator, wo );
+			//向主题发表者发送Message通知
+			if( needNotifySubjectCreator( replyMessageNotifyType ) ){
+				MessageFactory.notifySubjectCreator_forNewReply( subjectInfo.getCreatorName(), wo );
+			}
+		}
+		logger.debug("system send notify for new replyInfo completed!" );
+	}
+
+	/**
+	 * 根据指定的推送配置计算需要接收通知的人员列表
+	 * @param forumInfo
+	 * @param sectionInfo
+	 * @param replyMessageNotifyType
+	 * @return
+	 */
+	private List<String> caculatePerson( BBSForumInfo forumInfo, BBSSectionInfo sectionInfo, String replyMessageNotifyType ) {
+		List<String> persons = new ArrayList<>();
+		String[] sendPersonTypeConfig = null;
+		//回复消息通知类别:一共3位,第1位是否通知分区管理员ForumManagerList,第2位是否通知版主ModeratorNames,第3位是否通知发贴人,0-不通知|1-通知
+		if( StringUtils.isNotEmpty( replyMessageNotifyType )) {
+			sendPersonTypeConfig = replyMessageNotifyType.split(",");
+		}
+		if( sendPersonTypeConfig != null && sendPersonTypeConfig.length == 3 ){
+			if( StringUtils.equals( sendPersonTypeConfig[0], "1" ) ){
+				if( forumInfo != null && ListTools.isNotEmpty( forumInfo.getForumManagerList() ) ){
+					for( String manager : forumInfo.getForumManagerList() ){
+						if( !ListTools.contains( persons, manager )){
+							persons.add( manager );
+						}
+					}
+				}
+			}
+			if( StringUtils.equals( sendPersonTypeConfig[1], "1" ) ){
+				if( sectionInfo != null && ListTools.isNotEmpty( sectionInfo.getModeratorNames())){
+					for( String moderator : sectionInfo.getModeratorNames()){
+						if( !ListTools.contains( persons, moderator )){
+							persons.add( moderator );
+						}
+					}
+				}
+			}
+		}
+		return persons;
+	}
+
+	/**
+	 * 根据通知类型配置,检查是否需要向主题发表人发送通知
+	 * @param replyMessageNotifyType
+	 * @return
+	 */
+	private boolean needNotifySubjectCreator( String replyMessageNotifyType ) {
+		String[] sendPersonTypeConfig = null;
+		//回复消息通知类别:一共3位,第1位是否通知分区管理员ForumManagerList,第2位是否通知版主ModeratorNames,第3位是否通知发贴人,0-不通知|1-通知
+		if( StringUtils.isNotEmpty( replyMessageNotifyType )) {
+			sendPersonTypeConfig = replyMessageNotifyType.split(",");
+		}
+		if( sendPersonTypeConfig != null && sendPersonTypeConfig.length == 3 ){
+			if( StringUtils.equals( sendPersonTypeConfig[2], "1" ) ){
+				return true;
+			}
+		}
+		return false;
+	}
+
+	private MessageWo composeMessageWo(BBSForumInfo forumInfo, BBSSectionInfo sectionInfo, BBSSubjectInfo subjectInfo, BBSReplyInfo replyInfo) {
+		MessageWo messageWo = new MessageWo();
+		if( forumInfo != null ){
+			messageWo.setForumId( forumInfo.getId() );
+			messageWo.setForumName( forumInfo.getForumName() );
+		}
+		if( sectionInfo != null ){
+			messageWo.setSelectionId( sectionInfo.getId() );
+			messageWo.setSelectionName( sectionInfo.getSectionName() );
+		}
+		if( subjectInfo != null ){
+			messageWo.setTitle( subjectInfo.getTitle() );
+			messageWo.setSubjectId( subjectInfo.getId() );
+		}
+		if( subjectInfo != null ){
+			messageWo.setReplyId( replyInfo.getId() );
+			messageWo.setCreatePerson( replyInfo.getCreatorName() );
+			messageWo.setCreateTime(replyInfo.getCreateTime() );
+		}
+		messageWo.setId( replyInfo.getId() );
+		messageWo.setType( "Reply" );
+		return messageWo;
+	}
+}

+ 156 - 0
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/queue/QueueNewSubjectNotify.java

@@ -0,0 +1,156 @@
+package com.x.bbs.assemble.control.queue;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.queue.AbstractQueue;
+import com.x.base.core.project.tools.ListTools;
+import com.x.bbs.assemble.control.MessageFactory;
+import com.x.bbs.entity.BBSForumInfo;
+import com.x.bbs.entity.BBSSubjectInfo;
+import com.x.bbs.entity.BBSSectionInfo;
+import org.apache.commons.lang3.StringUtils;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * 新的主题发布后根据配置需要给指定人员发送消息通知
+ */
+public class QueueNewSubjectNotify extends AbstractQueue<BBSSubjectInfo> {
+	
+	private static  Logger logger = LoggerFactory.getLogger( QueueNewSubjectNotify.class );
+
+	public void execute( BBSSubjectInfo subjectInfo) throws Exception {
+		if( subjectInfo == null ) {
+			logger.warn("can not send publish notify for subject: NULL!" );
+			return;
+		}
+		logger.debug("system try to send notify for new subject info:" + subjectInfo.getTitle() );
+
+		BBSForumInfo forumInfo = null;
+		BBSSectionInfo mainSectionInfo = null;
+		BBSSectionInfo sectionInfo = null;
+		try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create() ) {
+			if( StringUtils.isNotEmpty( subjectInfo.getForumId() )){
+				forumInfo = emc.find( subjectInfo.getForumId(), BBSForumInfo.class );
+			}
+			if( StringUtils.isNotEmpty( subjectInfo.getMainSectionId() )){
+				mainSectionInfo = emc.find( subjectInfo.getMainSectionId(), BBSSectionInfo.class );
+			}
+			if( StringUtils.isNotEmpty( subjectInfo.getSectionId() )){
+				sectionInfo = emc.find( subjectInfo.getSectionId(), BBSSectionInfo.class );
+			}
+		}catch( Exception e ){
+			throw e;
+		}
+
+		Boolean send_pushMessage = false;
+		String subjectMessageNotifyType = null;
+		if( sectionInfo !=null  ){
+			if( !sectionInfo.getSubjectMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				subjectMessageNotifyType = sectionInfo.getSubjectMessageNotifyType();
+			}
+		}else{
+			send_pushMessage = false;
+		}
+
+		if( mainSectionInfo !=null  ){
+			if( !mainSectionInfo.getSubjectMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				subjectMessageNotifyType = mainSectionInfo.getSubjectMessageNotifyType();
+			}
+		}
+
+		if( forumInfo !=null  ){
+			if( !forumInfo.getSubjectMessageNotify() ){
+				send_pushMessage = false;
+			}else{
+				send_pushMessage = true;
+				subjectMessageNotifyType = forumInfo.getSubjectMessageNotifyType();
+			}
+		}else{
+			send_pushMessage = false;
+		}
+
+		MessageWo wo = composeMessageWo( forumInfo, sectionInfo, subjectInfo );
+		if( send_pushMessage && StringUtils.isNotEmpty( subjectMessageNotifyType )){
+			//尝试发送pushMessage
+			List<String> managerAndModerator = caculatePerson( forumInfo, sectionInfo, subjectMessageNotifyType );
+			//去一下重复
+			HashSet<String> set = new HashSet<String>( managerAndModerator );
+			managerAndModerator.clear();
+			managerAndModerator.addAll(set);
+
+			//向管理员发送Message通知
+			MessageFactory.notifyManager_forNewSubject( managerAndModerator, wo );
+		}
+		logger.debug("system send notify for new SubjectInfo completed!" );
+	}
+
+	/**
+	 * 根据指定的推送配置计算需要接收通知的人员列表
+	 * @param forumInfo
+	 * @param sectionInfo
+	 * @param subjectMessageNotifyType
+	 * @return
+	 */
+	private List<String> caculatePerson( BBSForumInfo forumInfo, BBSSectionInfo sectionInfo, String subjectMessageNotifyType ) {
+		List<String> persons = new ArrayList<>();
+		String[] sendPersonTypeConfig = null;
+		//新主题发布消息通知类别:一共3位,第1位是否通知分区管理员ForumManagerList,第2位是否通知版主ModeratorNames,0-不通知|1-通知
+		if( StringUtils.isNotEmpty( subjectMessageNotifyType )) {
+			sendPersonTypeConfig = subjectMessageNotifyType.split(",");
+		}
+		if( sendPersonTypeConfig != null && sendPersonTypeConfig.length == 2 ){
+			if( StringUtils.equals( sendPersonTypeConfig[0], "1" ) ){
+				if( forumInfo != null && ListTools.isNotEmpty( forumInfo.getForumManagerList() ) ){
+					for( String manager : forumInfo.getForumManagerList() ){
+						if( !ListTools.contains( persons, manager )){
+							persons.add( manager );
+						}
+					}
+				}
+			}
+			if( StringUtils.equals( sendPersonTypeConfig[1], "1" ) ){
+				if( sectionInfo != null && ListTools.isNotEmpty( sectionInfo.getModeratorNames())){
+					for( String moderator : sectionInfo.getModeratorNames()){
+						if( !ListTools.contains( persons, moderator )){
+							persons.add( moderator );
+						}
+					}
+				}
+			}
+		}
+		return persons;
+	}
+
+	private MessageWo composeMessageWo(BBSForumInfo forumInfo, BBSSectionInfo sectionInfo, BBSSubjectInfo subjectInfo ) {
+		MessageWo messageWo = new MessageWo();
+		if( forumInfo != null ){
+			messageWo.setForumId( forumInfo.getId() );
+			messageWo.setForumName( forumInfo.getForumName() );
+		}
+		if( sectionInfo != null ){
+			messageWo.setSelectionId( sectionInfo.getId() );
+			messageWo.setSelectionName( sectionInfo.getSectionName() );
+		}
+		if( subjectInfo != null ){
+			messageWo.setTitle( subjectInfo.getTitle() );
+			messageWo.setSubjectId( subjectInfo.getId() );
+			messageWo.setCreatePerson( subjectInfo.getCreatorName() );
+			messageWo.setCreateTime(subjectInfo.getCreateTime() );
+		}
+		messageWo.setId( subjectInfo.getId() );
+		messageWo.setType( "Subject" );
+		return messageWo;
+	}
+}

+ 21 - 12
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/service/BBSSectionInfoService.java

@@ -1,5 +1,6 @@
 package com.x.bbs.assemble.control.service;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -47,10 +48,13 @@ public class BBSSectionInfoService {
 			throw e;
 		}
 	}
-	
+
 	/**
 	 * 向数据库保存BBSSectionInfo对象
-	 * @param wrapIn
+	 * @param emc
+	 * @param _bBSSectionInfo
+	 * @return
+	 * @throws Exception
 	 */
 	public BBSSectionInfo save( EntityManagerContainer emc, BBSSectionInfo _bBSSectionInfo ) throws Exception {
 		BBSSectionInfo _bBSSectionInfo_tmp = null;
@@ -168,9 +172,10 @@ public class BBSSectionInfoService {
 
 	/**
 	 * 根据论坛ID查询论坛中所有的主版块信息数量
-	 * @param id
+	 * @param emc
+	 * @param forumId
 	 * @return
-	 * @throws Exception 
+	 * @throws Exception
 	 */
 	public Long countMainSectionByForumId( EntityManagerContainer emc, String forumId ) throws Exception {
 		if( forumId  == null || forumId.isEmpty() ){
@@ -179,12 +184,13 @@ public class BBSSectionInfoService {
 		Business business = new Business( emc );
 		return business.sectionInfoFactory().countMainSectionByForumId( forumId );
 	}
-	
+
 	/**
 	 * 根据主版块ID查询主版块中所有的子版块信息数量
-	 * @param id
+	 * @param emc
+	 * @param sectionId
 	 * @return
-	 * @throws Exception 
+	 * @throws Exception
 	 */
 	public Long countSubSectionByMainSectionId( EntityManagerContainer emc, String sectionId ) throws Exception {
 		if( sectionId  == null || sectionId.isEmpty() ){
@@ -267,7 +273,7 @@ public class BBSSectionInfoService {
 		if( sectionInfo == null ){
 			throw new Exception( "sectionInfo is null!" );
 		}
-		String[] currentManagerNames = null;
+
 		List<String> ids = null;
 		List<BBSUserRole> userRoleList= null;
 		String unitName = null;
@@ -276,9 +282,12 @@ public class BBSSectionInfoService {
 		BBSUserRole userRole_new = null;
 		Business business = null;
 		Boolean exists = false;
-		if( StringUtils.isNotEmpty( sectionInfo.getModeratorNames() ) ){
-			currentManagerNames = sectionInfo.getModeratorNames().split(",");
+		List<String> currentManagerNames = new ArrayList<>();
+
+		if( ListTools.isNotEmpty( sectionInfo.getModeratorNames() ) ){
+			currentManagerNames = sectionInfo.getModeratorNames();
 		}
+
 		business = new Business( emc );
 		emc.beginTransaction( BBSUserRole.class );
 		roleInfo = business.roleInfoFactory().getRoleByCode( "SECTION_MANAGER_" + sectionInfo.getId() );
@@ -292,7 +301,7 @@ public class BBSSectionInfoService {
 		if( ListTools.isNotEmpty( userRoleList ) ){
 			for( BBSUserRole userRole : userRoleList ){
 				exists = false;
-				if( ListTools.isNotEmpty( Arrays.asList( currentManagerNames )) ){
+				if( ListTools.isNotEmpty(currentManagerNames) ){
 					for( String name : currentManagerNames ){
 						if( name.equals( userRole.getObjectName()) || name.equalsIgnoreCase( userRole.getUniqueId() )){
 							exists = true;
@@ -304,7 +313,7 @@ public class BBSSectionInfoService {
 				}
 			}
 		}
-		if( currentManagerNames != null && currentManagerNames.length > 0 ){
+		if( ListTools.isNotEmpty( currentManagerNames ) ){
 			for( String name : currentManagerNames ){
 				exists = false;
 				if( ListTools.isNotEmpty( userRoleList ) ){

+ 42 - 17
o2server/x_bbs_assemble_control/src/main/java/com/x/bbs/assemble/control/service/BBSSubjectVoteService.java

@@ -17,6 +17,7 @@ import com.x.bbs.entity.BBSSubjectVoteResult;
 import com.x.bbs.entity.BBSVoteOption;
 import com.x.bbs.entity.BBSVoteOptionGroup;
 import com.x.bbs.entity.BBSVoteRecord;
+import org.apache.commons.lang3.StringUtils;
 
 public class BBSSubjectVoteService {
 
@@ -108,33 +109,40 @@ public class BBSSubjectVoteService {
 		//BBSVoteOptionGroup voteOptionGroup = null;
 		BBSVoteOption  voteOption = null;
 		BBSVoteRecord voteRecord = null;
+		BBSVoteOptionGroup voteOptionGroup = null;
 		//Business busines = null;
 		try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create() ) {
 			//busines = new Business(emc);
 			//emc.beginTransaction( BBSVoteOptionGroup.class );
 			emc.beginTransaction( BBSVoteOption.class );
 			emc.beginTransaction( BBSVoteRecord.class );
-			
+			Business buiness = new Business(emc);
 			for( WiVoteOptionGroup group : optionGroups ){
-				//voteOptionGroup = emc.find( group.getId(), BBSVoteOptionGroup.class );
+				voteOptionGroup = emc.find( group.getId(), BBSVoteOptionGroup.class );
 				if( ListTools.isNotEmpty( group.getSelectedVoteOptionIds() ) ){
 					for( String selectedOptionId : group.getSelectedVoteOptionIds()){
 						voteOption = emc.find( selectedOptionId, BBSVoteOption.class );
 						if( voteOption != null ){
-							voteRecord = new BBSVoteRecord();
-							voteRecord.setId( BBSVoteRecord.createId() );
-							voteRecord.setOptionId( selectedOptionId );
-							voteRecord.setForumId( subjectInfo.getForumId() );
-							voteRecord.setMainSectionId( subjectInfo.getMainSectionId() );
-							voteRecord.setSectionId( subjectInfo.getSectionId() );
-							voteRecord.setSubjectId( subjectInfo.getId());
-							voteRecord.setOptionValue( voteOption.getId() );
-							voteRecord.setCreateTime( new Date() );
-							voteRecord.setVotorName( effectivePerson.getDistinguishedName() );
-							emc.persist( voteRecord, CheckPersistType.all );
-							
-							voteOption.setChooseCount( voteOption.getChooseCount() + 1 );
-							emc.check( voteOption, CheckPersistType.all );
+							//查询一下是否已经投过票了
+							List<BBSVoteRecord> recordList = buiness.voteRecordFactory().listVoteCountByUserAndGroup( effectivePerson.getDistinguishedName(), group.getId() );
+							if( (ListTools.isEmpty( recordList) || recordList.size() < voteOptionGroup.getVoteChooseCount())
+									&& !doseNotChoosen( recordList, selectedOptionId )){
+								voteRecord = new BBSVoteRecord();
+								voteRecord.setOptionGroupId( voteOptionGroup.getId() );
+								voteRecord.setId( BBSVoteRecord.createId() );
+								voteRecord.setOptionId( selectedOptionId );
+								voteRecord.setForumId( subjectInfo.getForumId() );
+								voteRecord.setMainSectionId( subjectInfo.getMainSectionId() );
+								voteRecord.setSectionId( subjectInfo.getSectionId() );
+								voteRecord.setSubjectId( subjectInfo.getId());
+								voteRecord.setOptionValue( voteOption.getId() );
+								voteRecord.setCreateTime( new Date() );
+								voteRecord.setVotorName( effectivePerson.getDistinguishedName() );
+								emc.persist( voteRecord, CheckPersistType.all );
+
+								voteOption.setChooseCount( voteOption.getChooseCount() + 1 );
+								emc.check( voteOption, CheckPersistType.all );
+							}
 						}
 					}
 				}
@@ -144,7 +152,24 @@ public class BBSSubjectVoteService {
 			throw e;
 		}
 	}
-	
+
+	/**
+	 * 选项是否已经被选择过了。
+	 * @param recordList
+	 * @param selectedOptionId
+	 * @return
+	 */
+	private boolean doseNotChoosen(List<BBSVoteRecord> recordList, String selectedOptionId) {
+		if( ListTools.isNotEmpty( recordList)){
+			for( BBSVoteRecord voteRecord : recordList){
+				if(StringUtils.equals( voteRecord.getOptionId(), selectedOptionId )){
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
 	public void deleteAllVoteOptions( String subjectId ) throws Exception {
 		if( subjectId  == null || subjectId.isEmpty() ){
 			throw new Exception( "subjectId is null!" );

+ 449 - 23
o2server/x_bbs_assemble_control/src/main/webapp/jest/describe.js

@@ -157,7 +157,8 @@ Describe.writeOut = function(outs, json) {
 	}
 }
 
-Describe.createSample= function(m) {
+Describe.createSampleMootools = function(m) {
+	debugger;
 	var address = window.location.href;
 	address = address.substring(0,address.indexOf("/jest/"));
 	var address = address +"/"+ m.path;
@@ -179,7 +180,7 @@ Describe.createSample= function(m) {
 	
 	var strSample="";
 	if (m.contentType.indexOf('application/json') > -1) {
-		  strSample =  "var data = {};" + "\n";
+		        strSample =  "var data = {};" + "\n";
 			if (m.ins && m.ins.length > 0) {
 				$.each(m.ins, function(ii, i) {
 					switch (i.type) {
@@ -191,7 +192,12 @@ Describe.createSample= function(m) {
 								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
 							}
 						} else {
-							      strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+							     // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								 if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
 						}
 					}
 				});
@@ -200,18 +206,291 @@ Describe.createSample= function(m) {
 			} else if (m.useStringParameter) {
 				strSample += 'data = "参数";'+"\n";
 			}
+
+			strSample += " \n var mootoolsRequest = new Request({" + "\n";
+		    strSample += "        url:'"+address + "',\n";
+			strSample += "        method:'"+ m.type + "',\n";
+			strSample += "        dataType:'json',\n";
+		    strSample += "        headers : {'Content-Type':'application/json;charset=utf8','x-token':'实际的x-token'}" + ",\n";
+			if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+				strSample += "        data:JSON.stringify(data),\n";
+			}else{
+			  	strSample += "        data:data,\n";
+			}
+            strSample += "        onRequest: function(){ },"+ "\n";
+            strSample += "        onSuccess: function(responseText){},"+ "\n";
+            strSample += "        onFailure: function(){}"+ "\n";
+           strSample +="}).send();"+ "\n";
+	} else {
+		/*
+			strSample = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+							//formData.append(p.name, $('input[type=file]', '#formParameters')[0].files[0]);
+					strSample += 'formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					strSample += 'formData.append("'+p.name+'", "参数'+pi+'");' +  "\n";
+					}
+				});
+			}
 			
 			strSample += "$.ajax({" + "\n";
 			strSample += "type : '"+ m.type + "',\n";
-			strSample += "dataType : 'json'" + ",\n";
 			strSample += "url : '"+address + "',\n";
 			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : '"+m.contentType+ "',\n";
+			strSample += "contentType : false,\n";
+			strSample += "processData  : false,\n";
 			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
 			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : data"+"\n";
+			strSample += "data : formData"+"\n";
+			strSample += "});";	
+			*/
+	}
+
+	return  strSample;
+   }
+   
+Describe.createSampleJSO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+			if(parameter == ""){
+				parameter = "\"" + p.name + "\"" + ":" + '"替换参数'+pi +'"';
+			}else{
+				parameter = parameter +  ",\"" + p.name + "\"" + ":" + '替换参数'+pi +'"';
+			}
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			 var functionName = "do";
+			 strSample += "\n var root = \"" + uri + "\";" + "\n";
+			 strSample += " var options = { " + "\n";
+			 strSample += "                 " + functionName + ":{ //服务命名1,自定义"+ "\n";
+			 strSample += "                           \"uri\": \"/" + m.path + "\","+ "\n";;
+             strSample += "                           \"method\": \""+m.type+"\""+ "\n";
+			 strSample += "                      }"+ "\n";
+			 strSample += "     }" + "\n";
+			 strSample += "var action = new this.Action( root, options);" + "\n\n";
+			 strSample += "action.invoke({" + "\n";
+			 strSample += "        \"name\": \"" + functionName+ "\", //自定义的服务名" + "\n"; 
+			 strSample += "        \"parameter\": {" + parameter+ "},  //uri参数 " + "\n"; 
+             strSample += "        \"data\": data, //请求的正文, JsonObject " +  "\n"; 
+             strSample += "        \"success\": function(json){ //服务调用成功时的回调方法,json 是服务返回的数据" +  "\n"; 
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "        }.bind(this),"+ "\n"; 
+             strSample += "        \"failure\" : function(xhr){ //服务调用失败时的回调方法,xhr 为 XMLHttpRequest 对象" +  "\n";
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "     },"+ "\n"; 
+             strSample += "        \"async\" : true, //同步还是异步,默认为true" + "\n"; 
+             strSample += "        \"withCredentials\" : true, //是否允许跨域请求,默认为true" + "\n"; 
+             strSample += "        \"urlEncode\" : true //uri参数是否需要通过encodeURIComponent函数编码,默认为true" + "\n";
+             strSample += "});"			
+	} else {
+		
+	}
+	return  strSample;
+  }   
+   
+   
+   
+Describe.createSampleO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			
+			
+			if(m.type=="POST"){
+			   strSample += " \n var string = JSON.stringify(data);" + "\n";
+               strSample += " var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.postQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="GET"){
+               strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+                strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.getQuery( serviceRoot, path );"+ "\n";
+			}
+			if(m.type=="PUT"){
+			   strSample += " \n var string = JSON.stringify(data)"+ "\n";
+               strSample += " var applications = this.Action.applications"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address+ "\";"+ "\n"; ;
+               strSample += " var resp = applications.putQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="DELETE"){
+			   strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \" "+ uri + "\";"+ "\n";
+                 strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.deleteQuery( serviceRoot, path);"+ "\n";
+			}
+			
+               strSample += " var json = JSON.parse( resp.toString() );"+ "\n";
+			
+	} else {
+		
+	}
+	return  strSample;
+  }
+Describe.createSample= function(m) {
+	var address = window.location.href;
+	address = address.substring(0,address.indexOf("/jest/"));
+	var address = address +"/"+ m.path;
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+			if (m.ins && m.ins.length > 0) {
+				strSample =  "var data = {};" + "\n";
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += '   data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += '   data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+								if(i.isCollection){
+									strSample += '   data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += '   data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+														
+						
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += '    data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += '    data = "参数";'+"\n";
+			}
+			
+			strSample += "\n$.ajax({" + "\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        dataType : 'json'" + ",\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : '"+m.contentType+ "',\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			
+		   if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+			 strSample += "       data : JSON.stringify(data),\n";
+			}else{
+			  strSample += "      data : data"+"\n";
+			}
+			
 			strSample += "}).always(function(resultJson) {"+"\n";
-			strSample += "alert(JSON.stringify(resultJson, null, 4))" +"\n";
+			strSample += "        alert(JSON.stringify(resultJson, null, 4))" +"\n";
 			strSample += "});";
 			
 	} else {
@@ -227,28 +506,135 @@ Describe.createSample= function(m) {
 				});
 			}
 			strSample += "$.ajax({" + "\n";
-			strSample += "type : '"+ m.type + "',\n";
-			strSample += "url : '"+address + "',\n";
-			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : false,\n";
-			strSample += "processData  : false,\n";
-			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
-			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : formData"+"\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : false,\n";
+			strSample += "        processData  : false,\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			strSample += "        data : formData"+"\n";
 			strSample += "});";	
 	}
 
 	return  strSample;
    }
+Describe.createSampleCommon= function(m,className) {
+	 debugger;
+	var address = window.location.href;
+		address = address.substring(0,address.indexOf("/jest/"));
+	var root = address.substring(address.lastIndexOf("/")+1,address.length);
 
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+			$.each(m.pathParameters, function(pi, p) {
+				if(parameter == ""){
+					parameter =  p.name ;
+				}else{
+					parameter = parameter +  "," + p.name;
+				}
+			});
+		}
+	var query = "";
+		if (m.queryParameters && m.queryParameters.length > 0) {
+			$.each(m.queryParameters, function(pi, p) {
+				if (query == "") {
+					 query = "&" + p.name + '=' + '替换参数'+pi;
+				} else {
+					 query = query + "&"+ p.name + '=' + '替换参数'+pi;
+				}
+			});
+		}
+	var strSample="";
+	var body = "";
+	if (m.contentType.indexOf('application/json') > -1) {
+				if (m.ins && m.ins.length > 0) {
+					 body =  "var data = {};" + "\n";
+					$.each(m.ins, function(ii, i) {
+						switch (i.type) {
+						default:
+							if (i.isBaseType) {
+								if (i.isCollection) {
+									  body += '       data["'+i.name+'"] = ["参数1"];' + "\n";
+								} else {
+									  body += '       data["'+i.name+'"] = "参数";' + "\n";
+								}
+							} else {
+									if(i.isCollection){
+										body += '       data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+									}else{
+										body += '       data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+									}
+															
+							
+							}
+						}
+					});
+				} else if (m.useJsonElementParameter) {
+					body += '       data = {"参数1":"value1","参数2":"value2"};' +"\n";
+				} else if (m.useStringParameter) {
+					body += '       data = "参数";'+"\n";
+				}
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += body;	
+		 }	   
+	 }			
+	 strSample += "var action = this.Actions.load(\"" + root + "\");\n";
+	 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+	 if(parameter!=""){
+	   strSample += "      " + parameter  +",//uri的参数\n";
+	 }
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += "      data,//body请求参数\n";	
+		 }	   
+	 }
+	 strSample += "      function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+	 strSample += "         data = json.data; //为变量data赋值\n";
+	 strSample += "      }.bind(this),\n";
+	 strSample +=  "     function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+	 strSample +=  "        data = json.data; //为变量data赋值\n";
+	 strSample +=  "     }.bind(this),\n";
+	 strSample += "      false //同步执行 \n";
+	 strSample += "    );\n";
+				
+	}else{
+			var formData = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+					formData += '      formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					formData += '      formData.append("'+p.name+'", "参数值'+pi+'");' +  "\n";
+					}
+				});
+			}
+		 strSample += formData;
+		 strSample += "var action = this.Actions.get(\"" + root + "\");\n";
+		 //strSample += "action."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "      "+parameter  +",//uri的参数\n";
+		 strSample +=  "      formData"+",//from参数\n";
+		 strSample +=  "function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "false //同步执行 \n";
+		 strSample += ");\n"
+		} 
+   return  strSample ;		
+   }
 Describe.prototype = {
 	"load" : function() {
 		var str = '<ul>';
 		$.getJSON('../describe/describe.json?rd=' + Math.random(), function(json) {
 			$.each(json.jaxrs, function(ji, j) {
-				str += '<li xtype="menu" >' + j.name;
+				str += '<li xtype="menu" ' + 'style="margin-top: 30px;font-size:14px;font-weight:bold;"title="' +'" >' + j.name + ' <span style="font-style:italic">(' + j.description+ ')</span>';
 				$.each(j.methods, function(mi, m) {
-					str += '<ul><li xtype="li"><a id ="' + j.name + '_' + m.name + '" href="#">' + m.name + '</a></li></ul>';
+					str += '<ul><li xtype="li"  style="margin-top: 10px;margin-left:-24px;font-size:12px; font-weight:normal;line-height:18px" ><a id ="' + j.name + '_' + m.name + '" href="#"><b>' + m.name+'</b><br/><span style="color: #666666;">-'+ m.description + '</span>' + '</a></li></ul>';
 				});
 				str += '</li>'
 			});
@@ -262,7 +648,7 @@ Describe.prototype = {
 								var sample = "";
 								var txt = '<fieldset id="method"><legend>Method</legend>';
 								txt += '<table>';
-								txt += '<tr><td>name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
+								txt += '<tr><td style="width:100px;">name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
 								txt += '<tr><td>path:</td><td>' + m.path + '</td></tr>';
 								txt += '<tr><td>type:</td><td>' + m.type + '</td></tr>';
 								txt += '<tr><td>description:</td><td>' + m.description + '</td></tr>';
@@ -366,7 +752,7 @@ Describe.prototype = {
 									txt += '<fieldset id="outs"><legend>Out</legend>';
 									txt += '<table>';
 									$.each(m.outs, function(oi, o) {
-										txt += '<tr><td>' + o.name + '</td><td>' + o.type + '</td><td>' + (o.isCollection ? 'multi' : 'single') + '</td><td>' + o.description + '</td><td id="out_'
+										txt += '<tr><td style="width: 160px;">' + o.name + '</td><td style="width: 90px;">' + o.type + '</td><td style="width: 90px;">' + (o.isCollection ? 'multi' : 'single') + '</td><td style="width: 90px;">' + o.description + '</td><td id="out_'
 												+ o.name + '_out">&nbsp;</td></tr>';
 									});
 									txt += '</table>';
@@ -407,7 +793,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															//data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
 														}
 													}
 												});
@@ -431,7 +826,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
+														
 														}
 													}
 												});
@@ -493,7 +897,11 @@ Describe.prototype = {
 								})
 								
 								debugger;
-							 $('#Sample').html(Describe.createSample(m));
+							$('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;color: #1E7ACE;\">\n平台推荐脚本样例</span>\n\n"+ Describe.createSampleCommon(m,j.name)+ "</div><div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							
+							 /*
+							 $('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							 */
 							});
 				});
 			});
@@ -505,7 +913,13 @@ Describe.prototype = {
 						  }else{
 						     event.cancelBubble = true;
 						  }
-					    $(this).children().toggle();
+						$(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+					    //$(this).children().toggle();
 					});
 		  $("[xtype='li']").click( function(event) {
 			    if(event.stopPropagation){
@@ -514,6 +928,18 @@ Describe.prototype = {
 				     event.cancelBubble = true;
 				  }
 			})
+			$("[xtype='menu']").each(function(i){ 
+			if(i!=0){
+			  // $(this).children().toggle();
+			  $(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+			  }
+			}
+			);
 		});
 		
 	

+ 9 - 8
o2server/x_bbs_assemble_control/src/main/webapp/jest/index.html

@@ -99,7 +99,14 @@
 				
 				<div id="content"
 						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word;border-image: linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 100%, #ffffff);box-shadow: inset 15px 0 5px -16px #e7e7e7;background-image: -webkit-radial-gradient(right, #f2f2f2, #ffffff 100%);">&nbsp;</div>
-						
+				<fieldset>
+					<legend>
+						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
+					</legend>
+					<div id="result"
+						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
+				</fieldset>
+				
 			    <fieldset>
 					<legend>
 						Sample&nbsp;<a  id="btn_copy"  href="javascript:" data-clipboard-target="#Sample">copy</a>&nbsp;
@@ -109,13 +116,7 @@
 						</div>
 				</fieldset>		
 						
-				<fieldset>
-					<legend>
-						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
-					</legend>
-					<div id="result"
-						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
-				</fieldset>
+
 			</td>
 		</tr>
 	</table>

+ 83 - 27
o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSForumInfo.java

@@ -106,16 +106,18 @@ public class BBSForumInfo extends SliceJpaObject {
 	@Index(name = TABLE + IndexNameMiddle + forumVisible_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String forumVisible = "所有人";
-	
+
 	public static final String visiblePermissionList_FIELDNAME = "visiblePermissionList";
 	@FieldDescribe("版块可见范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + visiblePermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + visiblePermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + visiblePermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + visiblePermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ visiblePermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ visiblePermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ visiblePermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + visiblePermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> visiblePermissionList;
 
 	public static final String subjectPublishAble_FIELDNAME = "subjectPublishAble";
@@ -124,16 +126,18 @@ public class BBSForumInfo extends SliceJpaObject {
 	@Index(name = TABLE + IndexNameMiddle + subjectPublishAble_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String subjectPublishAble = "所有人";
-	
+
 	public static final String publishPermissionList_FIELDNAME = "publishPermissionList";
 	@FieldDescribe("可发布范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + publishPermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + publishPermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + publishPermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + publishPermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ publishPermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ publishPermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ publishPermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + publishPermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> publishPermissionList;
 
 	public static final String replyPublishAble_FIELDNAME = "replyPublishAble";
@@ -141,16 +145,18 @@ public class BBSForumInfo extends SliceJpaObject {
 	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + replyPublishAble_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String replyPublishAble = "所有人";
-	
+
 	public static final String replyPermissionList_FIELDNAME = "replyPermissionList";
 	@FieldDescribe("可回复范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + replyPermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + replyPermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + replyPermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + replyPermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ replyPermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ replyPermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ replyPermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + replyPermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> replyPermissionList;
 
 	public static final String indexListStyle_FIELDNAME = "indexListStyle";
@@ -256,6 +262,32 @@ public class BBSForumInfo extends SliceJpaObject {
 	@CheckPersist(allowEmpty = false)
 	private Integer orderNumber = 1;
 
+	public static final String replyMessageNotify_FIELDNAME = "replyMessageNotify";
+	@FieldDescribe("回复消息通知:true|false")
+	@Column(name = ColumnNamePrefix + replyMessageNotify_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + replyMessageNotify_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Boolean replyMessageNotify = false;
+
+	public static final String replyMessageNotifyType_FIELDNAME = "replyMessageNotifyType";
+	@FieldDescribe("回复消息通知类别:一共3位,第1位是否通知论坛分区管理员,第2位是否通知版主,第3位是否通知发贴人,0-不通知|1-通知")
+	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + replyMessageNotifyType_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String replyMessageNotifyType = "0,0,0";
+
+	public static final String subjectMessageNotify_FIELDNAME = "subjectMessageNotify";
+	@FieldDescribe("新主题发布消息通知:true|false")
+	@Column(name = ColumnNamePrefix + subjectMessageNotify_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + subjectMessageNotify_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Boolean subjectMessageNotify = false;
+
+	public static final String subjectMessageNotifyType_FIELDNAME = "subjectMessageNotifyType";
+	@FieldDescribe("新主题发布消息通知类别:一共2位,第1位是否通知论坛分区管理员,第2位是否通知版主,0-不通知|1-通知")
+	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + subjectMessageNotifyType_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String subjectMessageNotifyType = "0,0";
+
 	public String getForumName() {
 		return forumName;
 	}
@@ -440,6 +472,30 @@ public class BBSForumInfo extends SliceJpaObject {
 		this.typeCategory = typeCategory;
 	}
 
+	public Boolean getReplyMessageNotify() { return this.replyMessageNotify; }
+
+	public void setReplyMessageNotify(final Boolean replyMessageNotify) { this.replyMessageNotify = replyMessageNotify; }
+
+	public String getReplyMessageNotifyType() { return this.replyMessageNotifyType; }
+
+	public void setReplyMessageNotifyType(final String replyMessageNotifyType) { this.replyMessageNotifyType = replyMessageNotifyType; }
+
+	public Boolean getSubjectMessageNotify() {
+		return this.subjectMessageNotify;
+	}
+
+	public void setSubjectMessageNotify(final Boolean subjectMessageNotify) {
+		this.subjectMessageNotify = subjectMessageNotify;
+	}
+
+	public String getSubjectMessageNotifyType() {
+		return this.subjectMessageNotifyType;
+	}
+
+	public void setSubjectMessageNotifyType(final String subjectMessageNotifyType) {
+		this.subjectMessageNotifyType = subjectMessageNotifyType;
+	}
+
 	public long minusSection(Long count) {
 		if (this.sectionTotal == null || this.sectionTotal < 0) {
 			this.sectionTotal = 0L;
@@ -582,7 +638,7 @@ public class BBSForumInfo extends SliceJpaObject {
 	public void setVisiblePermissionList(List<String> visiblePermissionList) {
 		this.visiblePermissionList = visiblePermissionList;
 	}
-	
+
 	public List<String> addVisiblePermission(String permissoin) {
 		if (this.visiblePermissionList == null) {
 			this.visiblePermissionList = new ArrayList<>();
@@ -610,7 +666,7 @@ public class BBSForumInfo extends SliceJpaObject {
 		}
 		return this.publishPermissionList;
 	}
-	
+
 	public List<String> getReplyPermissionList() {
 		return replyPermissionList;
 	}
@@ -618,7 +674,7 @@ public class BBSForumInfo extends SliceJpaObject {
 	public void setReplyPermissionList(List<String> replyPermissionList) {
 		this.replyPermissionList = replyPermissionList;
 	}
-	
+
 	public List<String> addReplyPermission(String permissoin) {
 		if (this.replyPermissionList == null) {
 			this.replyPermissionList = new ArrayList<>();

+ 101 - 40
o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSSectionInfo.java

@@ -143,16 +143,18 @@ public class BBSSectionInfo extends SliceJpaObject {
 	@Index(name = TABLE + IndexNameMiddle + sectionVisible_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String sectionVisible = "所有人";
-	
+
 	public static final String visiblePermissionList_FIELDNAME = "visiblePermissionList";
 	@FieldDescribe("版块可见范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + visiblePermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + visiblePermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + visiblePermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + visiblePermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ visiblePermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ visiblePermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ visiblePermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + visiblePermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> visiblePermissionList;
 
 	public static final String subjectPublishAble_FIELDNAME = "subjectPublishAble";
@@ -160,16 +162,18 @@ public class BBSSectionInfo extends SliceJpaObject {
 	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + subjectPublishAble_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String subjectPublishAble = "所有人";
-	
+
 	public static final String publishPermissionList_FIELDNAME = "publishPermissionList";
 	@FieldDescribe("版块可发表范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + publishPermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + publishPermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + publishPermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + publishPermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ publishPermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ publishPermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix
+			+ publishPermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + publishPermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> publishPermissionList;
 
 	public static final String replyPublishAble_FIELDNAME = "replyPublishAble";
@@ -177,23 +181,30 @@ public class BBSSectionInfo extends SliceJpaObject {
 	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + replyPublishAble_FIELDNAME)
 	@CheckPersist(allowEmpty = false)
 	private String replyPublishAble = "所有人";
-	
+
 	public static final String replyPermissionList_FIELDNAME = "replyPermissionList";
 	@FieldDescribe("版块可回复范围")
-	@PersistentCollection( fetch = FetchType.EAGER )
-	@OrderColumn( name = ORDERCOLUMNCOLUMN )
-	@ContainerTable(name = TABLE + ContainerTableNameMiddle + replyPermissionList_FIELDNAME, joinIndex = @Index( name = TABLE
-			+ IndexNameMiddle + replyPermissionList_FIELDNAME + JoinIndexNameSuffix ))
-	@ElementColumn( length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + replyPermissionList_FIELDNAME )
-	@ElementIndex( name = TABLE + IndexNameMiddle + replyPermissionList_FIELDNAME + ElementIndexNameSuffix )
-	@CheckPersist( allowEmpty = true )
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ replyPermissionList_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+					+ replyPermissionList_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + replyPermissionList_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + replyPermissionList_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
 	private List<String> replyPermissionList;
 
 	public static final String moderatorNames_FIELDNAME = "moderatorNames";
 	@FieldDescribe("版主姓名:可多值,默认为创建者")
-	@Column(length = JpaObject.length_255B, name = ColumnNamePrefix + moderatorNames_FIELDNAME)
-	@CheckPersist(allowEmpty = false)
-	private String moderatorNames = "";
+	@PersistentCollection(fetch = FetchType.EAGER)
+	@OrderColumn(name = ORDERCOLUMNCOLUMN)
+	@ContainerTable(name = TABLE + ContainerTableNameMiddle
+			+ moderatorNames_FIELDNAME, joinIndex = @Index(name = TABLE + IndexNameMiddle
+			+ moderatorNames_FIELDNAME + JoinIndexNameSuffix))
+	@ElementColumn(length = AbstractPersistenceProperties.organization_name_length, name = ColumnNamePrefix + moderatorNames_FIELDNAME)
+	@ElementIndex(name = TABLE + IndexNameMiddle + moderatorNames_FIELDNAME + ElementIndexNameSuffix)
+	@CheckPersist(allowEmpty = true)
+	private List<String> moderatorNames;
 
 	public static final String sectionType_FIELDNAME = "sectionType";
 	@FieldDescribe("版块类别:图片新闻,普通新闻,公告,经典(默认)")
@@ -280,6 +291,40 @@ public class BBSSectionInfo extends SliceJpaObject {
 	@CheckPersist(allowEmpty = false)
 	private Integer orderNumber = 1;
 
+	public static final String replyMessageNotify_FIELDNAME = "replyMessageNotify";
+	@FieldDescribe("回复消息通知:true|false")
+	@Column(name = ColumnNamePrefix + replyMessageNotify_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + replyMessageNotify_FIELDNAME)
+	@CheckPersist(allowEmpty = false)
+	private Boolean replyMessageNotify = false;
+
+	public static final String replyMessageNotifyType_FIELDNAME = "replyMessageNotifyType";
+	@FieldDescribe("回复消息通知类别:一共3位,第1位是否通知论坛分区管理员,第2位是否通知版主,第3位是否通知发贴人,0-不通知|1-通知")
+	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + replyMessageNotifyType_FIELDNAME)
+	@CheckPersist(allowEmpty = false)
+	private String replyMessageNotifyType = "0,0,0";
+
+	public static final String subjectMessageNotify_FIELDNAME = "subjectMessageNotify";
+	@FieldDescribe("新主题发布消息通知:true|false")
+	@Column(name = ColumnNamePrefix + subjectMessageNotify_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + subjectMessageNotify_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Boolean subjectMessageNotify = false;
+
+	public static final String subjectMessageNotifyType_FIELDNAME = "subjectMessageNotifyType";
+	@FieldDescribe("新主题发布消息通知类别:一共2位,第1位是否通知论坛分区管理员,第2位是否通知版主,0-不通知|1-通知")
+	@Column(length = JpaObject.length_16B, name = ColumnNamePrefix + subjectMessageNotifyType_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String subjectMessageNotifyType = "0,0";
+
+	public Boolean getSubjectMessageNotify() { return this.subjectMessageNotify; }
+
+	public void setSubjectMessageNotify(final Boolean subjectMessageNotify) { this.subjectMessageNotify = subjectMessageNotify; }
+
+	public String getSubjectMessageNotifyType() { return this.subjectMessageNotifyType; }
+
+	public void setSubjectMessageNotifyType(final String subjectMessageNotifyType) { this.subjectMessageNotifyType = subjectMessageNotifyType; }
+
 	public String getForumName() {
 		return forumName;
 	}
@@ -368,14 +413,6 @@ public class BBSSectionInfo extends SliceJpaObject {
 		this.replyPublishAble = replyPublishAble;
 	}
 
-	public String getModeratorNames() {
-		return moderatorNames;
-	}
-
-	public void setModeratorNames(String moderatorNames) {
-		this.moderatorNames = moderatorNames;
-	}
-
 	public String getSectionType() {
 		return sectionType;
 	}
@@ -500,8 +537,22 @@ public class BBSSectionInfo extends SliceJpaObject {
 		return visiblePermissionList;
 	}
 
-	public void setVisiblePermissionList(List<String> visiblePermissionList) {
-		this.visiblePermissionList = visiblePermissionList;
+	public void setVisiblePermissionList(List<String> visiblePermissionList) { this.visiblePermissionList = visiblePermissionList; }
+
+	public Boolean getReplyMessageNotify() { return this.replyMessageNotify; }
+
+	public void setReplyMessageNotify(final Boolean replyMessageNotify) { this.replyMessageNotify = replyMessageNotify; }
+
+	public String getReplyMessageNotifyType() { return this.replyMessageNotifyType; }
+
+	public void setReplyMessageNotifyType(final String replyMessageNotifyType) { this.replyMessageNotifyType = replyMessageNotifyType; }
+
+	public List<String> getModeratorNames() {
+		return this.moderatorNames;
+	}
+
+	public void setModeratorNames(final List<String> moderatorNames) {
+		this.moderatorNames = moderatorNames;
 	}
 
 	public List<String> addVisitPermission(String permissoin) {
@@ -513,7 +564,7 @@ public class BBSSectionInfo extends SliceJpaObject {
 		}
 		return this.visiblePermissionList;
 	}
-	
+
 	public List<String> getPublishPermissionList() {
 		return publishPermissionList;
 	}
@@ -531,7 +582,7 @@ public class BBSSectionInfo extends SliceJpaObject {
 		}
 		return this.publishPermissionList;
 	}
-	
+
 	public List<String> getReplyPermissionList() {
 		return replyPermissionList;
 	}
@@ -539,7 +590,7 @@ public class BBSSectionInfo extends SliceJpaObject {
 	public void setReplyPermissionList(List<String> replyPermissionList) {
 		this.replyPermissionList = replyPermissionList;
 	}
-	
+
 	public List<String> addReplyPermission(String permissoin) {
 		if (this.replyPermissionList == null) {
 			this.replyPermissionList = new ArrayList<>();
@@ -549,4 +600,14 @@ public class BBSSectionInfo extends SliceJpaObject {
 		}
 		return this.replyPermissionList;
 	}
+
+	public List<String> addModeratorName(String person) {
+		if (this.moderatorNames == null) {
+			this.moderatorNames = new ArrayList<>();
+		}
+		if (!this.moderatorNames.contains(person)) {
+			this.moderatorNames.add(person);
+		}
+		return this.moderatorNames;
+	}
 }

+ 10 - 0
o2server/x_bbs_core_entity/src/main/java/com/x/bbs/entity/BBSVoteRecord.java

@@ -89,6 +89,12 @@ public class BBSVoteRecord extends SliceJpaObject {
 	@CheckPersist(allowEmpty = false)
 	private String subjectId = null;
 
+	public static final String optionGroupId_FIELDNAME = "optionGroupId";
+	@FieldDescribe("选项组ID")
+	@Column(length = JpaObject.length_id, name = ColumnNamePrefix + optionGroupId_FIELDNAME)
+	@CheckPersist(allowEmpty = false)
+	private String optionGroupId = null;
+
 	public static final String optionId_FIELDNAME = "optionId";
 	@FieldDescribe("用户投票结果选择项Id")
 	@Column(length = JpaObject.length_id, name = ColumnNamePrefix + optionId_FIELDNAME)
@@ -162,4 +168,8 @@ public class BBSVoteRecord extends SliceJpaObject {
 	public void setOptionId(String optionId) {
 		this.optionId = optionId;
 	}
+
+	public String getOptionGroupId() { return this.optionGroupId; }
+
+	public void setOptionGroupId(final String optionGroupId) { this.optionGroupId = optionGroupId; }
 }

+ 17 - 0
o2server/x_calendar_assemble_control/pom.xml

@@ -52,6 +52,23 @@
 							</arguments>
 						</configuration>
 					</execution>
+					<execution>
+						<id>apiBuilder</id>
+						<phase>prepare-package</phase>
+						<goals>
+							<goal>java</goal>
+						</goals>
+						<configuration>
+							<addOutputToClasspath>true</addOutputToClasspath>
+							<includePluginDependencies>true</includePluginDependencies>
+							<includeProjectDependencies>true</includeProjectDependencies>
+							<mainClass>com.x.base.core.project.annotation.ApiBuilder</mainClass>
+							<arguments>
+								<argument>${basedir}</argument>
+								<argument>${project.build.sourceDirectory}</argument>
+							</arguments>
+						</configuration>
+					</execution>
 					<execution>
 						<id>checkAssemble</id>
 						<phase>prepare-package</phase>

+ 4 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/AbstractFactory.java

@@ -1,6 +1,10 @@
 package com.x.calendar.assemble.control;
 
 import com.x.base.core.container.EntityManagerContainer;
+import com.x.calendar.core.entity.Calendar_EventComment;
+
+import java.util.Date;
+import java.util.List;
 
 public abstract class AbstractFactory {
 

+ 10 - 5
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/Business.java

@@ -1,10 +1,7 @@
 package com.x.calendar.assemble.control;
 
 import com.x.base.core.container.EntityManagerContainer;
-import com.x.calendar.assemble.control.factory.CalendarFactory;
-import com.x.calendar.assemble.control.factory.Calendar_EventFactory;
-import com.x.calendar.assemble.control.factory.Calendar_EventRepeatMasterFactory;
-import com.x.calendar.assemble.control.factory.Calendar_SettingFactory;
+import com.x.calendar.assemble.control.factory.*;
 import com.x.organization.core.express.Organization;
 
 public class Business {
@@ -50,7 +47,15 @@ public class Business {
 		}
 		return calendar_EventFactory;
 	}
-	
+
+	private Calendar_EventCommentFactory calendar_EventCommentFactory;
+	public Calendar_EventCommentFactory calendar_EventCommentFactory() throws Exception {
+		if (null == this.calendar_EventCommentFactory) {
+			this.calendar_EventCommentFactory = new Calendar_EventCommentFactory( this );
+		}
+		return calendar_EventCommentFactory;
+	}
+
 	private Calendar_EventRepeatMasterFactory calendar_EventRepeatMasterFactory;	
 	public Calendar_EventRepeatMasterFactory calendar_EventRepeatMasterFactory() throws Exception {
 		if (null == this.calendar_EventRepeatMasterFactory) {

+ 4 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/ThisApplication.java

@@ -7,6 +7,7 @@ import com.x.base.core.project.http.EffectivePerson;
 import com.x.base.core.project.message.MessageConnector;
 import com.x.base.core.project.tools.ListTools;
 import com.x.calendar.assemble.control.schedule.AlarmTrigger;
+import com.x.calendar.assemble.control.schedule.CheckEventComment;
 import com.x.calendar.assemble.control.service.UserManagerService;
 import com.x.calendar.core.entity.Calendar;
 import com.x.calendar.core.entity.Calendar_Event;
@@ -23,7 +24,10 @@ public class ThisApplication {
 	public static void init() throws Exception {
 		try {
 			MessageConnector.start(context());
+			//每30秒检查一次需要推送的消息
 			context.schedule(AlarmTrigger.class, "0/30 * * * * ?");
+			//每两小时检查一次comment信息的引用情况,删除多余的不必要的数据
+			context.schedule(CheckEventComment.class, "* * */2 * * ?");
 		} catch (Exception e) {
 			e.printStackTrace();
 		}

+ 104 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/factory/Calendar_EventCommentFactory.java

@@ -0,0 +1,104 @@
+package com.x.calendar.assemble.control.factory;
+
+import com.x.base.core.project.tools.ListTools;
+import com.x.calendar.assemble.control.AbstractFactory;
+import com.x.calendar.assemble.control.Business;
+import com.x.calendar.core.entity.*;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 日历备注信息信息表功能服务类
+ * @author O2LEE
+ */
+public class Calendar_EventCommentFactory extends AbstractFactory {
+	
+	public Calendar_EventCommentFactory(Business business) throws Exception {
+		super(business);
+	}
+
+	/**
+	 * 获取指定Id的日历备注信息信息对象
+	 * @param id
+	 * @return
+	 * @throws Exception
+	 */
+	public Calendar_EventComment get( String id ) throws Exception {
+		return this.entityManagerContainer().find(id, Calendar_EventComment.class );
+	}
+	
+	/**
+	 * 列示指定Id的日历备注信息信息列表
+	 * @param ids
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Calendar_EventComment> list( List<String> ids ) throws Exception {
+		if( ListTools.isEmpty( ids ) ){
+			return null;
+		}
+		EntityManager em = this.entityManagerContainer().get(Calendar_EventComment.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Calendar_EventComment> cq = cb.createQuery(Calendar_EventComment.class);
+		Root<Calendar_EventComment> root = cq.from(Calendar_EventComment.class);
+		Predicate p = root.get( Calendar_EventComment_.id).in(ids);
+		return em.createQuery(cq.where(p)).getResultList();
+	}
+
+	public Long countEventBundle( String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		EntityManager em = this.entityManagerContainer().get(Calendar_Event.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
+		Root<Calendar_Event> root = cq.from(Calendar_Event.class);
+		Predicate p = cb.equal( root.get(Calendar_Event_.commentId ), commentId);
+		cq.select(cb.count(root)).where(p);
+		return em.createQuery(cq.where(p)).getSingleResult();
+	}
+
+	public Long countRepeatMasterBundle( String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		EntityManager em = this.entityManagerContainer().get(Calendar_EventRepeatMaster.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
+		Root<Calendar_EventRepeatMaster> root = cq.from(Calendar_EventRepeatMaster.class);
+		Predicate p = cb.equal( root.get( Calendar_EventRepeatMaster_.commentId ), commentId);
+		cq.select(cb.count(root)).where(p);
+		return em.createQuery(cq.where(p)).getSingleResult();
+	}
+
+	/**
+	 * 查询检查时间早于now的maxCount条记录的ID列表
+	 * @param now
+	 * @param maxCount
+	 * @return
+	 * @throws Exception
+	 */
+	public List<String> listNeedCheckCommnetIds( Date now, Integer maxCount) throws Exception {
+		if( now == null ) {
+			now = new Date();
+		}
+		if( maxCount == null ) {
+			maxCount = 1000;
+		}
+		EntityManager em = this.entityManagerContainer().get(Calendar_EventComment.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<String> cq = cb.createQuery(String.class);
+		Root<Calendar_EventComment> root = cq.from(Calendar_EventComment.class);
+		Predicate p = cb.lessThan( root.get( Calendar_EventComment_.checkTime ), now );
+		cq.select(root.get(Calendar_EventComment_.id));
+		return em.createQuery(cq.where(p)).setMaxResults(maxCount).getResultList();
+	}
+}

+ 1 - 1
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/factory/Calendar_EventRepeatMasterFactory.java

@@ -136,7 +136,7 @@ public class Calendar_EventRepeatMasterFactory extends AbstractFactory {
 	 * 查询需要生成日历事件的重复主体信息ID列表
 	 * @param calendarIds
 	 * @param eventType
-	 * @param needCreateMonths
+	 * @param createMonth
 	 * @param personName
 	 * @param unitNames
 	 * @param groupNames

+ 18 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/ActionGet.java

@@ -5,6 +5,7 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import com.x.calendar.core.entity.Calendar_EventComment;
 import org.apache.commons.lang3.StringUtils;
 
 import com.x.base.core.project.annotation.FieldDescribe;
@@ -27,6 +28,7 @@ public class ActionGet extends BaseAction {
 		Wo wrap = null;
 		Calendar calendar = null;
 		Calendar_Event calendar_Event = null;
+		Calendar_EventComment calendar_EventComment = null;
 		Boolean check = true;
 		
 		if( check ){
@@ -68,6 +70,22 @@ public class ActionGet extends BaseAction {
 				logger.error( e, effectivePerson, request, null);
 			}
 		}
+
+		if( check ){
+			if( StringUtils.equals( "{#CLOB#}", calendar_Event.getComment() ) && StringUtils.isNotEmpty( calendar_Event.getCommentId() )){
+				try {
+					calendar_EventComment = calendar_EventServiceAdv.getCommentWithCommentId( calendar_Event.getCommentId() );
+					if( calendar_EventComment != null ) {
+						calendar_Event.setComment( calendar_EventComment.getLobValue() );
+					}
+				} catch (Exception e) {
+					check = false;
+					Exception exception = new ExceptionEventProcess( e, "系统根据ID查询指定日历记录信息时发生异常.ID:" + id );
+					result.error( exception );
+					logger.error( e, effectivePerson, request, null);
+				}
+			}
+		}
 		
 		if( check ){
 			try {

+ 2 - 2
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/ActionUpdateSingleEventWithId.java

@@ -129,7 +129,7 @@ public class ActionUpdateSingleEventWithId extends BaseAction {
 				logger.error( e, effectivePerson, request, null);
 			}
 		}
-		
+
 		if( check ) {
 			PromptException exception = this.eventValidate( new_Event, calendar );
 			if( exception != null ) {
@@ -152,7 +152,7 @@ public class ActionUpdateSingleEventWithId extends BaseAction {
 		return result;
 	}
 	
-public static class Wi extends Calendar_Event{
+	public static class Wi extends Calendar_Event{
 		
 		private static final long serialVersionUID = -5076990764713538973L;
 		

+ 6 - 11
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/jaxrs/event/BaseAction.java

@@ -25,14 +25,15 @@ public class BaseAction extends StandardJaxrsAction{
 	protected Calendar_EventServiceAdv calendar_EventServiceAdv = new Calendar_EventServiceAdv();
 	protected Calendar_EventRepeatMasterServiceAdv calendar_RepeatedMasterServiceAdv = new Calendar_EventRepeatMasterServiceAdv();
 	protected static DateOperation dateOperation = new DateOperation();
-	
+
 	/**
 	 * 对日历事件信息进行验证,给出正确的提示信息
-	 * @param calendar_Event
+	 * @param event
+	 * @param calendar
 	 * @return
-	 * @throws Exception 
+	 * @throws Exception
 	 */
-	protected PromptException eventValidate(Calendar_Event event, Calendar calendar ) throws Exception {
+	protected PromptException eventValidate( Calendar_Event event, Calendar calendar ) throws Exception {
 		
 		//日历ID不能为空
 		if( StringUtils.isEmpty( event.getCalendarId() ) ){
@@ -148,13 +149,7 @@ public class BaseAction extends StandardJaxrsAction{
 				return new ExceptionTaskEventCanNotRepeatMaster( event.getRepeatMasterId() ) ;
 			}
 		}
-		
-		if( StringUtils.isNotEmpty( event.getRepeatMasterId() ) ) {
-			//是重复主体,但是没有配置重复规则
-			if( StringUtils.isEmpty( event.getRecurrenceRule() )) {
-				return new ExceptionEventPropertyEmpty("重复规则(recurrenceRule)");
-			}
-		}
+
 		//如果有重复规则时,需要验证规则是否正确
 		if( StringUtils.isNotEmpty( event.getRecurrenceRule() )) {
 			//转换为RRule

+ 103 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/schedule/CheckEventComment.java

@@ -0,0 +1,103 @@
+package com.x.calendar.assemble.control.schedule;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.entity.annotation.CheckPersistType;
+import com.x.base.core.entity.annotation.CheckRemoveType;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.schedule.AbstractJob;
+import com.x.base.core.project.tools.ListTools;
+import com.x.calendar.assemble.control.service.Calendar_EventCommentQueryService;
+import com.x.calendar.core.entity.Calendar_EventComment;
+import org.quartz.JobExecutionContext;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 定期检查是否存在没有被任何event或者event_master引用的EventComment记录,如果有,则需要进行删除
+ * 
+ * @author O2LEE
+ *
+ */
+public class CheckEventComment extends AbstractJob {
+
+	private static Logger logger = LoggerFactory.getLogger(CheckEventComment.class);
+	protected Calendar_EventCommentQueryService calendar_EventCommentQueryService = new Calendar_EventCommentQueryService();
+
+	@Override
+	public void schedule(JobExecutionContext jobExecutionContext) throws Exception {
+		Date now = new Date();
+		List<String> ids = calendar_EventCommentQueryService.listNeedCheckCommnetIds( now, 500 );
+		Integer maxWhileTimes = 10;
+		while( ListTools.isNotEmpty( ids )){
+			if( --maxWhileTimes < 0 ){
+				break;
+			}
+			ids.forEach( commentId->{
+				try {
+					if( !check( commentId, now )){
+						removeEventComment( commentId );
+					}
+				} catch (Exception e) {
+					e.printStackTrace();
+				}
+			});
+			ids = calendar_EventCommentQueryService.listNeedCheckCommnetIds( now, 500 );
+		}
+		logger.info("The trigger for calendar alarm execute completed." + new Date());
+	}
+
+	/**
+	 * 根据commentId,删除指定的备注信息
+	 * @param commentId
+	 */
+	private void removeEventComment(String commentId ) throws Exception {
+		Boolean quote = false;
+		if( calendar_EventCommentQueryService.countEventBundle( commentId ) > 0 ){
+			quote = true;
+		}
+		if( calendar_EventCommentQueryService.countRepeatMasterBundle( commentId ) > 0 ){
+			quote = true;
+		}
+		if( !quote ){
+			//没有引用,直接
+			try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+				Calendar_EventComment entity = emc.find( commentId, Calendar_EventComment.class );
+				if( entity != null ){
+					emc.beginTransaction( Calendar_EventComment.class );
+					emc.remove( entity, CheckRemoveType.all );
+					emc.commit();
+				}
+			}
+		}
+	}
+
+	/**
+	 * 检查该ID是否有事件引用到
+	 * 
+	 * @param commentId
+	 * @return
+	 * @throws Exception
+	 */
+	private boolean check( String commentId, Date now ) throws Exception {
+		if( calendar_EventCommentQueryService.countEventBundle( commentId ) > 0 ){
+			return true;
+		}
+		if( calendar_EventCommentQueryService.countRepeatMasterBundle( commentId ) > 0 ){
+			return true;
+		}
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			Calendar_EventComment entity = emc.find( commentId, Calendar_EventComment.class );
+			if( entity != null ){
+				emc.beginTransaction( Calendar_EventComment.class );
+				entity.setCheckTime( new Date() );
+				emc.check( entity, CheckPersistType.all );
+				emc.commit();
+			}
+		}
+		return false;
+	}
+
+}

+ 92 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventCommentQueryService.java

@@ -0,0 +1,92 @@
+package com.x.calendar.assemble.control.service;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.calendar.core.entity.Calendar_EventComment;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 日程日历备注信息服务类
+ * @author O2LEE
+ *
+ */
+public class Calendar_EventCommentQueryService {
+	private Calendar_EventCommentService calendar_EventCommentService = new Calendar_EventCommentService();
+
+	public List<Calendar_EventComment> list(List<String> ids) throws Exception {
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return calendar_EventCommentService.list(emc, ids);
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
+
+	/**
+	 * 根据ID获取指定日历记录备注信息
+	 * @param id
+	 * @return
+	 * @throws Exception
+	 */
+	public Calendar_EventComment get(String id) throws Exception {
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return emc.find(id, Calendar_EventComment.class);
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
+
+	/**
+	 * 查询在事件信息中,commentId被引用的次数
+	 * @param commentId
+	 * @return
+	 * @throws Exception
+	 */
+	public Long countEventBundle( String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return calendar_EventCommentService.countEventBundle(emc, commentId);
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
+
+	/**
+	 * 查询在事件循环主体信息中,commentId被引用的次数
+	 * @param commentId
+	 * @return
+	 * @throws Exception
+	 */
+	public Long countRepeatMasterBundle( String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return calendar_EventCommentService.countRepeatMasterBundle(emc, commentId);
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
+
+	/**
+	 * 查询更新时间早于传入时间的前N条信息ID
+	 * @param now
+	 * @param maxCount
+	 * @return
+	 * @throws Exception
+	 */
+	public List<String> listNeedCheckCommnetIds( Date now, Integer maxCount ) throws Exception {
+		if( now == null ) {
+			now = new Date();
+		}
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return calendar_EventCommentService.listNeedCheckCommnetIds( emc, now, maxCount );
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
+}

+ 66 - 0
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventCommentService.java

@@ -0,0 +1,66 @@
+package com.x.calendar.assemble.control.service;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.calendar.assemble.control.Business;
+import com.x.calendar.common.date.DateOperation;
+import com.x.calendar.core.entity.Calendar_EventComment;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 日历记录信息服务类
+ * @author O2LEE
+ *
+ */
+public class Calendar_EventCommentService {
+	
+	private DateOperation dateOperation = new DateOperation();
+
+	/**
+	 * 获取指定的备注信息对象列表
+	 * @return
+	 * @throws Exception
+	 */
+	public List<Calendar_EventComment> list(EntityManagerContainer emc, List<String> ids ) throws Exception {
+		Business business =  new Business( emc );
+		return business.calendar_EventCommentFactory().list(ids);
+	}
+
+	public Long countEventBundle( EntityManagerContainer emc, String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		Business business =  new Business( emc );
+		return business.calendar_EventCommentFactory().countEventBundle(commentId);
+	}
+
+	public Long countRepeatMasterBundle( EntityManagerContainer emc, String commentId ) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return 0L;
+		}
+		Business business =  new Business( emc );
+		return business.calendar_EventCommentFactory().countRepeatMasterBundle(commentId);
+	}
+
+	/**
+	 * 查询检查时间早于now的maxCount条记录的ID列表
+	 * @param emc
+	 * @param now
+	 * @param maxCount
+	 * @return
+	 * @throws Exception
+	 */
+	public List<String> listNeedCheckCommnetIds(EntityManagerContainer emc, Date now, Integer maxCount) throws Exception {
+		if( now == null ) {
+			now = new Date();
+		}
+		if( maxCount == null ) {
+			maxCount = 1000;
+		}
+		Business business =  new Business( emc );
+		return business.calendar_EventCommentFactory().listNeedCheckCommnetIds( now, maxCount );
+	}
+}

+ 27 - 18
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventRepeatMasterService.java

@@ -19,17 +19,18 @@ import com.x.calendar.core.entity.Calendar_EventRepeatMaster;
 
 /**
  * 日历重复信息主体记录信息服务类
- * @author O2LEE
  *
  */
 public class Calendar_EventRepeatMasterService {
 
 	/**
 	 * 根据ID彻底删除指定的日历重复信息主体记录信息
-	 * @param id
+	 * @param emc
+	 * @param repeatMasterId
+	 * @param excludeIds 排除EventID列表
 	 * @throws Exception
 	 */
-	public void destoryWithMasterId( EntityManagerContainer emc, String repeatMasterId ) throws Exception {
+	public void destoryWithMasterId( EntityManagerContainer emc, String repeatMasterId, List<String> excludeIds ) throws Exception {
 		Calendar_EventRepeatMaster calendar_EventRepeatMaster = null;
 		if( StringUtils.isEmpty( repeatMasterId ) ){
 			throw new Exception( "repeatMasterId is empty, system can not delete any object." );
@@ -43,9 +44,11 @@ public class Calendar_EventRepeatMasterService {
 		emc.beginTransaction( Calendar_EventRepeatMaster.class );
 		if( ListTools.isNotEmpty( eventIds )) {
 			for( String id : eventIds ) {
-				calendar_Event = emc.find( id, Calendar_Event.class );
-				if( calendar_Event != null ) {
-					emc.remove( calendar_Event, CheckRemoveType.all );
+				if( !ListTools.contains( excludeIds, id ) ) {
+					calendar_Event = emc.find( id, Calendar_Event.class );
+					if( calendar_Event != null) {
+						emc.remove( calendar_Event, CheckRemoveType.all );
+					}
 				}
 			}
 		}
@@ -57,8 +60,9 @@ public class Calendar_EventRepeatMasterService {
 
 	/**
 	 * 创建日历重复信息主体记录信息
-	 * @param calendar_record
-	 * @param b 
+	 * @param emc
+	 * @param calendar_EventRepeatMaster
+	 * @param autoTransaction
 	 * @return
 	 * @throws Exception
 	 */
@@ -67,7 +71,7 @@ public class Calendar_EventRepeatMasterService {
 			Boolean autoTransaction ) throws Exception {
 		if( autoTransaction == null ) {
 			autoTransaction = true;
-		}		
+		}
 		Calendar_EventRepeatMaster calendar_EventRepeatMaster_old = null;
 		calendar_EventRepeatMaster_old = emc.find( calendar_EventRepeatMaster.getId(), Calendar_EventRepeatMaster.class );
 		if( calendar_EventRepeatMaster_old != null ){
@@ -79,17 +83,19 @@ public class Calendar_EventRepeatMasterService {
 			if( StringUtils.isEmpty( calendar_EventRepeatMaster.getId() )) {
 				calendar_EventRepeatMaster.setId( Calendar_Event.createId() );
 			}
-			emc.persist( calendar_EventRepeatMaster, CheckPersistType.all);			
+			emc.persist( calendar_EventRepeatMaster, CheckPersistType.all);
 			if(autoTransaction) {
 				emc.commit();
 			}
 		}
 		return calendar_EventRepeatMaster;
 	}
-	
+
 	/**
 	 * 更新日历重复信息主体记录信息
-	 * @param calendar_record
+	 * @param emc
+	 * @param calendar_EventRepeatMaster
+	 * @param autoTransaction
 	 * @return
 	 * @throws Exception
 	 */
@@ -105,10 +111,14 @@ public class Calendar_EventRepeatMasterService {
 		Business business = new Business(emc);
 		calendar_EventRepeatMaster_old = business.calendar_EventRepeatMasterFactory().get( calendar_EventRepeatMaster.getId() );
 		if( calendar_EventRepeatMaster_old != null ){
-			emc.beginTransaction( Calendar_EventRepeatMaster.class );
+			if(autoTransaction) {
+				emc.beginTransaction( Calendar_EventRepeatMaster.class );
+			}
 			calendar_EventRepeatMaster.copyTo(calendar_EventRepeatMaster_old, JpaObject.FieldsUnmodify);
 			emc.check( calendar_EventRepeatMaster_old, CheckPersistType.all);
-			emc.commit();
+			if(autoTransaction) {
+				emc.commit();
+			}
 		}else{
 			throw new Exception("old object calendar_EventRepeatMaster{'id':' "+ calendar_EventRepeatMaster.getId() +" '} is not exists. ");
 		}
@@ -198,19 +208,18 @@ public class Calendar_EventRepeatMasterService {
 		}		
 		return result;
 	}
-	
+
 	/**
 	 * 根据条件和时间范围查询需要进行事件生成的重复主体ID列表,  时间根据已经生成过的日期来判断
 	 * @param emc
 	 * @param calendarIds
 	 * @param eventType
-	 * @param startTime
-	 * @param endTime
+	 * @param createMonth
 	 * @param personName
 	 * @param unitNames
 	 * @param groupNames
 	 * @return
-	 * @throws Exception 
+	 * @throws Exception
 	 */
 	public List<String> listNeedRepeatMaster( EntityManagerContainer emc, List<String> calendarIds, String eventType,
 			String createMonth, String personName, List<String> unitNames, List<String> groupNames) throws Exception {

+ 4 - 4
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventRepeatMasterServiceAdv.java

@@ -116,16 +116,16 @@ public class Calendar_EventRepeatMasterServiceAdv{
 	 */
 	public void destoryWithMasterId(String id) throws Exception {
 		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
-			 calendar_EventRepeatMasterService.destoryWithMasterId(emc, id );
+			 calendar_EventRepeatMasterService.destoryWithMasterId(emc, id, null );
 		} catch ( Exception e ) {
 			throw e;
 		}
 	}
-	
+
 	/**
 	 * 检查该repeatMaster下所有的记录是不是全都是已经删除了,如果没有有效的记录的话,就全部删除掉
-	 * @param repeatMaster
-	 * @throws Exception 
+	 * @param repeatMasterId
+	 * @throws Exception
 	 */
 	public void checkRepeatMaster(String repeatMasterId) throws Exception {
 		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {

+ 59 - 4
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventService.java

@@ -4,6 +4,8 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import com.x.base.core.project.tools.StringTools;
+import com.x.calendar.core.entity.Calendar_EventComment;
 import org.apache.commons.lang3.StringUtils;
 
 import com.x.base.core.container.EntityManagerContainer;
@@ -65,13 +67,12 @@ public class Calendar_EventService {
 			emc.commit();
 		}
 	}
-	
+
 	/**
 	 * 创建日历记录信息
 	 * @param emc
 	 * @param calendar_record
-	 * @param calendar_EventDetail 
-	 * @param autoTransaction - 是否自动提交
+	 * @param autoTransaction
 	 * @return
 	 * @throws Exception
 	 */
@@ -274,5 +275,59 @@ public class Calendar_EventService {
 			}
 			return ids;
 		}
-	}	
+	}
+
+	/**
+	 * 创建一个新的Calendar_EventComment,不检查是否已经存在
+	 * @param emc
+	 * @param calendar_event
+	 * @return
+	 * @throws Exception
+	 */
+	public Calendar_EventComment createNewEventComment( EntityManagerContainer emc, Calendar_Event calendar_event ) throws Exception {
+		Calendar_EventComment calendar_EventComment = null;
+		//先判断commnet的大小,如果过长,则需要存储到Calendar_EventComment表里
+		if( StringUtils.isNotEmpty( calendar_event.getComment() ) && StringTools.utf8Length( calendar_event.getComment() ) > 255 ){
+			emc.beginTransaction( Calendar_EventComment.class );
+			//需要新建一个Calendar_EventComment
+			calendar_EventComment = new Calendar_EventComment();
+			calendar_EventComment.setId( Calendar_EventComment.createId() );
+			calendar_EventComment.setLobValue( calendar_event.getComment() );
+			emc.persist( calendar_EventComment, CheckPersistType.all );
+			emc.commit();
+		}
+		return calendar_EventComment;
+	}
+
+	/**
+	 * 创建或者检查Calendar_EventComment,如果已经存在,则进行更新
+	 * @param emc
+	 * @param calendar_event
+	 * @return
+	 * @throws Exception
+	 */
+	public Calendar_EventComment createOrUpdateEventComment( EntityManagerContainer emc, Calendar_Event calendar_event ) throws Exception {
+		Calendar_EventComment calendar_EventComment = null;
+		//先判断commnet的大小,如果过长,则需要存储到Calendar_EventComment表里
+		if( StringUtils.isNotEmpty( calendar_event.getComment() ) && StringTools.utf8Length( calendar_event.getComment() ) > 255 ){
+			emc.beginTransaction( Calendar_EventComment.class );
+			if( StringUtils.isNotEmpty( calendar_event.getCommentId() )){
+				//根据ID查询出Calendar_EventComment
+				calendar_EventComment = emc.find( calendar_event.getCommentId(), Calendar_EventComment.class );
+			}
+			if( calendar_EventComment == null ){
+				//需要新建一个Calendar_EventComment
+				calendar_EventComment = new Calendar_EventComment();
+				calendar_EventComment.setId( Calendar_EventComment.createId() );
+				calendar_EventComment.setLobValue( calendar_event.getComment() );
+				emc.persist( calendar_EventComment, CheckPersistType.all );
+			}else{
+				//需要更新Calendar_EventComment
+				calendar_EventComment.setLobValue( calendar_event.getComment() );
+				emc.check( calendar_EventComment, CheckPersistType.all );
+			}
+			emc.commit();
+		}
+		return calendar_EventComment;
+	}
 }

+ 110 - 19
o2server/x_calendar_assemble_control/src/main/java/com/x/calendar/assemble/control/service/Calendar_EventServiceAdv.java

@@ -8,6 +8,8 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 
+import com.x.base.core.project.tools.StringTools;
+import com.x.calendar.core.entity.Calendar_EventComment;
 import org.apache.commons.lang3.StringUtils;
 
 import com.x.base.core.container.EntityManagerContainer;
@@ -83,6 +85,7 @@ public class Calendar_EventServiceAdv{
 
 	/**
 	 * 保存日历记录信息
+	 * 2019-11-11 添加逻辑,适应超长的备注信息,如果备注信息超长,则将信息存储到Comment表中,并且在event和eventmaster里存储引用的ID
 	 * @param calendar_event
 	 * @param effectivePerson 
 	 * @return
@@ -105,14 +108,25 @@ public class Calendar_EventServiceAdv{
 		if( StringUtils.isEmpty( calendar_event.getUpdatePerson() )) {
 			calendar_event.setUpdatePerson( effectivePerson.getDistinguishedName() );
 		}
-		
-		try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {			
+
+		Calendar_EventComment calendar_EventComment = null;
+		try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			calendar_EventComment = calendar_EventService.createNewEventComment( emc, calendar_event );
+
+			//修改Comment信息
+			if( calendar_EventComment != null ){
+				calendar_event.setComment( "{#CLOB#}" );
+				calendar_event.setCommentId( calendar_EventComment.getId() );
+			}else{
+				calendar_event.setCommentId( null );
+			}
+
 			//如果是复重的日程,保存为重复信息主体,否则,保存为普通日程信息
 			if( StringUtils.isNotEmpty( calendar_event.getRecurrenceRule()) ) {
-				Calendar_EventRepeatMaster calendar_EventRepeatMaster = composeEventRepeatMasterWithEvent( calendar_event );				
+				Calendar_EventRepeatMaster calendar_EventRepeatMaster = composeEventRepeatMasterWithEvent( calendar_event );
 				calendar_event.setRepeatMasterId( calendar_EventRepeatMaster.getId() );
-				emc.beginTransaction( Calendar_EventRepeatMaster.class );	
-				calendar_EventRepeatMaster = calendar_EventRepeatMasterService.create(emc, calendar_EventRepeatMaster, false );				
+				emc.beginTransaction( Calendar_EventRepeatMaster.class );
+				calendar_EventRepeatMasterService.create(emc, calendar_EventRepeatMaster, false );
 			}
 			
 			if( StringUtils.isEmpty( calendar_event.getId() )) {
@@ -127,11 +141,10 @@ public class Calendar_EventServiceAdv{
 		}
 		return calendar_event;
 	}
-	
+
 	/**
 	 * 保存日历记录信息
 	 * @param calendar_event
-	 * @param effectivePerson 
 	 * @return
 	 * @throws Exception
 	 */
@@ -157,6 +170,14 @@ public class Calendar_EventServiceAdv{
 			if( StringUtils.isEmpty( calendar_event.getId() )) {
 				calendar_event.setId( Calendar_Event.createId() );
 			}
+			Calendar_EventComment calendar_EventComment = calendar_EventService.createNewEventComment( emc, calendar_event );
+			//修改Comment信息
+			if( calendar_EventComment != null ){
+				calendar_event.setComment( "{#CLOB#}" );
+				calendar_event.setCommentId( calendar_EventComment.getId() );
+			}else{
+				calendar_event.setCommentId( null );
+			}
 			emc.beginTransaction( Calendar_Event.class );
 			//保存日程信息
 			calendar_event = calendar_EventService.create( emc, calendar_event, false );
@@ -218,10 +239,20 @@ public class Calendar_EventServiceAdv{
 				calendar_EventRepeatMaster.setUpdatePerson( effectivePerson.getDistinguishedName() );
 			}
 			calendar_EventRepeatMaster.setCreatedMonthList( new ArrayList<>());
-			emc.beginTransaction( Calendar_EventRepeatMaster.class );	
+
+			//判断事件的备注信息是否超长,如果已经存在则需要更新一下
+			Calendar_EventComment calendar_EventComment = calendar_EventService.createOrUpdateEventComment( emc, calendar_event );
+			if( calendar_EventComment != null ){
+				calendar_EventRepeatMaster.setComment( "{#CLOB#}" );
+				calendar_EventRepeatMaster.setCommentId( calendar_EventComment.getId() );
+			}else{
+				calendar_EventRepeatMaster.setCommentId( null );
+			}
+
+			emc.beginTransaction( Calendar_EventRepeatMaster.class );
 			emc.check( calendar_EventRepeatMaster, CheckPersistType.all );
 			
-			//2、删除该RepeatMaster已经生成的所有日程事件
+			//2、删除该RepeatMaster已经生成的所有日程事件,等待重新生成
 			eventIds = business.calendar_EventFactory().listWithRepeatMaster(repeatMasterId, null, null );
 			if( ListTools.isNotEmpty( eventIds )) {
 				count = eventIds.size();
@@ -334,11 +365,21 @@ public class Calendar_EventServiceAdv{
 			
 			calendar_EventRepeatMaster_new = copyEventPropertyToMaster( calendar_event );
 			calendar_EventRepeatMaster_new.setRecurrenceStartTime( calendar_event.getStartTime() );
-			
+
+			//处理新的calendar_EventRepeatMaster_new的备注信息,原来的calendar_EventRepeatMaster不动
+			Calendar_EventComment calendar_EventComment = calendar_EventService.createNewEventComment( emc, calendar_event );
+			if( calendar_EventComment != null ){
+				calendar_EventRepeatMaster_new.setComment( "{#CLOB#}" );
+				calendar_EventRepeatMaster_new.setCommentId( calendar_EventComment.getId() );
+			}else{
+				calendar_EventRepeatMaster_new.setCommentId( null );
+			}
+
 			emc.beginTransaction( Calendar_EventRepeatMaster.class );	
 			emc.check( calendar_EventRepeatMaster, CheckPersistType.all );
 			emc.persist( calendar_EventRepeatMaster_new, CheckPersistType.all  );
 			emc.commit();
+
 		} catch ( Exception e ) {
 			throw e;
 		}
@@ -375,7 +416,36 @@ public class Calendar_EventServiceAdv{
 			if( StringUtils.isEmpty( calendar_event.getId() )) {
 				old_event.setId( Calendar_Event.createId() );
 			}
+			//检查日程备注信息的长度,如果超长,则需要新建一个Calendar_EventComment记录
+			//如果超长,则创建一个新的则需要新建一个Calendar_EventComment记录
+			Calendar_EventComment calendar_EventComment = calendar_EventService.createNewEventComment( emc, calendar_event );
+			if( calendar_EventComment != null ){
+				old_event.setComment( "{#CLOB#}" );
+				old_event.setCommentId( calendar_EventComment.getId() );
+			}else{
+				old_event.setCommentId( null );
+			}
+
 			emc.beginTransaction( Calendar_Event.class );
+			if( StringUtils.isEmpty( old_event.getRepeatMasterId() ) ){
+				//原来不是重复的日程,修改后复重的日程,保存为重复信息主体
+				if( StringUtils.isNotEmpty( calendar_event.getRecurrenceRule()) ) {
+					Calendar_EventRepeatMaster calendar_EventRepeatMaster = composeEventRepeatMasterWithEvent( calendar_event );
+					old_event.setRepeatMasterId( calendar_EventRepeatMaster.getId() );
+					emc.beginTransaction( Calendar_EventRepeatMaster.class );
+					calendar_EventRepeatMasterService.create(emc, calendar_EventRepeatMaster, false );
+				}
+			}else{
+				if( StringUtils.isEmpty( calendar_event.getRecurrenceRule()) ) {
+					//原来是重复的,现在不重复了,需要把repeatMaster删除,还有已经生成的所有event
+					if( StringUtils.isNotEmpty( old_event.getRepeatMasterId() )){
+						ArrayList arrayList = new ArrayList<>();
+						arrayList.add( old_event.getId() );
+						calendar_EventRepeatMasterService.destoryWithMasterId( emc, old_event.getRepeatMasterId(), arrayList );
+					}
+				}
+			}
+
 			//保存日程信息
 			calendar_event = calendar_EventService.update( emc, old_event, false );
 			emc.commit();
@@ -449,20 +519,24 @@ public class Calendar_EventServiceAdv{
 			List<String> needCreateMonths = new DateOperation().listMonthsBetweenDate( startTime, endTime );
 			
 			if( ListTools.isNotEmpty( needCreateMonths )) {
+				List<String> repeatMasterIds = new ArrayList<>();
+				List<String> repeatMasterIds_month = null;
+
 				for( String createMonth : needCreateMonths ) {
 					//先看看有没有需要生成的日历重复主体
-					List<String> repeatMasterIds = calendar_EventRepeatMasterService.listNeedRepeatMaster( emc, calendarIds,  eventType, createMonth, 
-						personName, unitNames, groupNames);
-					if( ListTools.isNotEmpty( repeatMasterIds )) {
-						//根据日期范围为指定的日期重复主体生成日历事件信息
-						calendar_EventService.createCalendarWithMaster( emc, repeatMasterIds, startTime, endTime, needCreateMonths );	
+					repeatMasterIds_month = calendar_EventRepeatMasterService.listNeedRepeatMaster( emc, calendarIds,  eventType, createMonth, personName, unitNames, groupNames);
+					if( ListTools.isNotEmpty( repeatMasterIds_month )){
+						repeatMasterIds.addAll( repeatMasterIds_month );
 					}
 				}
+				if( ListTools.isNotEmpty( repeatMasterIds )) {
+					//根据日期范围为指定的日期重复主体生成日历事件信息
+					calendar_EventService.createCalendarWithMaster( emc, repeatMasterIds, startTime, endTime, needCreateMonths );
+				}
 			}
 			
 			//最后从日历事件信息表里按条件进行数据查询返回
-			return calendar_EventService.listWithCondition( emc, key, eventType, source, createPerson, calendarIds, personName, 
-					 unitNames, groupNames, startTime, endTime );
+			return calendar_EventService.listWithCondition( emc, key, eventType, source, createPerson, calendarIds, personName, unitNames, groupNames, startTime, endTime );
 		} catch ( Exception e ) {
 			throw e;
 		}
@@ -726,11 +800,11 @@ public class Calendar_EventServiceAdv{
         CalendarOutputter outputter = new CalendarOutputter();
         outputter.output(calendar, fout );
 	}
-	
+
 	/**
 	 * 将一个日程事件写为一个ical文件
 	 * @param o2_calendar_event
-	 * @param path
+	 * @param out
 	 * @throws ValidationException
 	 * @throws IOException
 	 */
@@ -856,4 +930,21 @@ public class Calendar_EventServiceAdv{
 			throw e;
 		}
 	}
+
+	/**
+	 * 根据commentId获取Calendar_EventComment信息
+	 * @param commentId
+	 * @return
+	 * @throws Exception
+	 */
+	public Calendar_EventComment getCommentWithCommentId(String commentId) throws Exception {
+		if( StringUtils.isEmpty( commentId ) ) {
+			return null;
+		}
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			return emc.find( commentId, Calendar_EventComment.class );
+		} catch ( Exception e ) {
+			throw e;
+		}
+	}
 }

+ 449 - 23
o2server/x_calendar_assemble_control/src/main/webapp/jest/describe.js

@@ -157,7 +157,8 @@ Describe.writeOut = function(outs, json) {
 	}
 }
 
-Describe.createSample= function(m) {
+Describe.createSampleMootools = function(m) {
+	debugger;
 	var address = window.location.href;
 	address = address.substring(0,address.indexOf("/jest/"));
 	var address = address +"/"+ m.path;
@@ -179,7 +180,7 @@ Describe.createSample= function(m) {
 	
 	var strSample="";
 	if (m.contentType.indexOf('application/json') > -1) {
-		  strSample =  "var data = {};" + "\n";
+		        strSample =  "var data = {};" + "\n";
 			if (m.ins && m.ins.length > 0) {
 				$.each(m.ins, function(ii, i) {
 					switch (i.type) {
@@ -191,7 +192,12 @@ Describe.createSample= function(m) {
 								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
 							}
 						} else {
-							      strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+							     // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								 if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
 						}
 					}
 				});
@@ -200,18 +206,291 @@ Describe.createSample= function(m) {
 			} else if (m.useStringParameter) {
 				strSample += 'data = "参数";'+"\n";
 			}
+
+			strSample += " \n var mootoolsRequest = new Request({" + "\n";
+		    strSample += "        url:'"+address + "',\n";
+			strSample += "        method:'"+ m.type + "',\n";
+			strSample += "        dataType:'json',\n";
+		    strSample += "        headers : {'Content-Type':'application/json;charset=utf8','x-token':'实际的x-token'}" + ",\n";
+			if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+				strSample += "        data:JSON.stringify(data),\n";
+			}else{
+			  	strSample += "        data:data,\n";
+			}
+            strSample += "        onRequest: function(){ },"+ "\n";
+            strSample += "        onSuccess: function(responseText){},"+ "\n";
+            strSample += "        onFailure: function(){}"+ "\n";
+           strSample +="}).send();"+ "\n";
+	} else {
+		/*
+			strSample = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+							//formData.append(p.name, $('input[type=file]', '#formParameters')[0].files[0]);
+					strSample += 'formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					strSample += 'formData.append("'+p.name+'", "参数'+pi+'");' +  "\n";
+					}
+				});
+			}
 			
 			strSample += "$.ajax({" + "\n";
 			strSample += "type : '"+ m.type + "',\n";
-			strSample += "dataType : 'json'" + ",\n";
 			strSample += "url : '"+address + "',\n";
 			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : '"+m.contentType+ "',\n";
+			strSample += "contentType : false,\n";
+			strSample += "processData  : false,\n";
 			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
 			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : data"+"\n";
+			strSample += "data : formData"+"\n";
+			strSample += "});";	
+			*/
+	}
+
+	return  strSample;
+   }
+   
+Describe.createSampleJSO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+			if(parameter == ""){
+				parameter = "\"" + p.name + "\"" + ":" + '"替换参数'+pi +'"';
+			}else{
+				parameter = parameter +  ",\"" + p.name + "\"" + ":" + '替换参数'+pi +'"';
+			}
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			 var functionName = "do";
+			 strSample += "\n var root = \"" + uri + "\";" + "\n";
+			 strSample += " var options = { " + "\n";
+			 strSample += "                 " + functionName + ":{ //服务命名1,自定义"+ "\n";
+			 strSample += "                           \"uri\": \"/" + m.path + "\","+ "\n";;
+             strSample += "                           \"method\": \""+m.type+"\""+ "\n";
+			 strSample += "                      }"+ "\n";
+			 strSample += "     }" + "\n";
+			 strSample += "var action = new this.Action( root, options);" + "\n\n";
+			 strSample += "action.invoke({" + "\n";
+			 strSample += "        \"name\": \"" + functionName+ "\", //自定义的服务名" + "\n"; 
+			 strSample += "        \"parameter\": {" + parameter+ "},  //uri参数 " + "\n"; 
+             strSample += "        \"data\": data, //请求的正文, JsonObject " +  "\n"; 
+             strSample += "        \"success\": function(json){ //服务调用成功时的回调方法,json 是服务返回的数据" +  "\n"; 
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "        }.bind(this),"+ "\n"; 
+             strSample += "        \"failure\" : function(xhr){ //服务调用失败时的回调方法,xhr 为 XMLHttpRequest 对象" +  "\n";
+             strSample += "        //这里进行具体的处理"+ "\n"; 
+             strSample += "     },"+ "\n"; 
+             strSample += "        \"async\" : true, //同步还是异步,默认为true" + "\n"; 
+             strSample += "        \"withCredentials\" : true, //是否允许跨域请求,默认为true" + "\n"; 
+             strSample += "        \"urlEncode\" : true //uri参数是否需要通过encodeURIComponent函数编码,默认为true" + "\n";
+             strSample += "});"			
+	} else {
+		
+	}
+	return  strSample;
+  }   
+   
+   
+   
+Describe.createSampleO2= function(m) {
+	var address = window.location.href;
+	    address = address.substring(0,address.indexOf("/jest/"));
+	var uri = address.substring(address.lastIndexOf("/")+1,address.length);
+	 address =  m.path;
+	 address = address.substring(address.indexOf("jaxrs/")+6,address.length);
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+		  strSample =  "var data = {};" + "\n";
+			if (m.ins && m.ins.length > 0) {
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += 'data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += 'data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+							           // strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								if(i.isCollection){
+									strSample += 'data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += 'data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += 'data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += 'data = "参数";'+"\n";
+			}
+			
+			
+			if(m.type=="POST"){
+			   strSample += " \n var string = JSON.stringify(data);" + "\n";
+               strSample += " var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.postQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="GET"){
+               strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+                strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.getQuery( serviceRoot, path );"+ "\n";
+			}
+			if(m.type=="PUT"){
+			   strSample += " \n var string = JSON.stringify(data)"+ "\n";
+               strSample += " var applications = this.Action.applications"+ "\n";
+               strSample += " var serviceRoot = \"" + uri + "\";"+ "\n";
+               strSample += " var path = \"" + address+ "\";"+ "\n"; ;
+               strSample += " var resp = applications.putQuery( serviceRoot, path , string);"+ "\n";
+			}
+			if(m.type=="DELETE"){
+			   strSample += " \n var applications = this.Action.applications;"+ "\n";
+               strSample += " var serviceRoot = \" "+ uri + "\";"+ "\n";
+                 strSample += " var path = \"" + address + "\";"+ "\n"; ;
+               strSample += " var resp = applications.deleteQuery( serviceRoot, path);"+ "\n";
+			}
+			
+               strSample += " var json = JSON.parse( resp.toString() );"+ "\n";
+			
+	} else {
+		
+	}
+	return  strSample;
+  }
+Describe.createSample= function(m) {
+	var address = window.location.href;
+	address = address.substring(0,address.indexOf("/jest/"));
+	var address = address +"/"+ m.path;
+	if (m.pathParameters && m.pathParameters.length > 0) {
+		$.each(m.pathParameters, function(pi, p) {
+			address = address.replace('{' + p.name + '}', '替换参数'+pi);
+		});
+	}
+	if (m.queryParameters && m.queryParameters.length > 0) {
+		$.each(m.queryParameters, function(pi, p) {
+			var query = p.name + '=' + '替换参数'+pi;
+			if (address.indexOf("?") > 0) {
+				address += '&' + query;
+			} else {
+				address += '?' + query;
+			}
+		});
+	}
+	
+	var strSample="";
+	if (m.contentType.indexOf('application/json') > -1) {
+			if (m.ins && m.ins.length > 0) {
+				strSample =  "var data = {};" + "\n";
+				$.each(m.ins, function(ii, i) {
+					switch (i.type) {
+					default:
+						if (i.isBaseType) {
+							if (i.isCollection) {
+								  strSample += '   data["'+i.name+'"] = ["参数1"];' + "\n";
+							} else {
+								  strSample += '   data["'+i.name+'"] = "参数";' + "\n";
+							}
+						} else {
+								if(i.isCollection){
+									strSample += '   data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+								}else{
+									strSample += '   data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+								}
+														
+						
+						}
+					}
+				});
+			} else if (m.useJsonElementParameter) {
+				strSample += '    data = {"参数1":"value1","参数2":"value2"};' +"\n";
+			} else if (m.useStringParameter) {
+				strSample += '    data = "参数";'+"\n";
+			}
+			
+			strSample += "\n$.ajax({" + "\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        dataType : 'json'" + ",\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : '"+m.contentType+ "',\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			
+		   if((m.contentType.indexOf('application/json') > -1) && (!m.useStringParameter)){
+			 strSample += "       data : JSON.stringify(data),\n";
+			}else{
+			  strSample += "      data : data"+"\n";
+			}
+			
 			strSample += "}).always(function(resultJson) {"+"\n";
-			strSample += "alert(JSON.stringify(resultJson, null, 4))" +"\n";
+			strSample += "        alert(JSON.stringify(resultJson, null, 4))" +"\n";
 			strSample += "});";
 			
 	} else {
@@ -227,28 +506,135 @@ Describe.createSample= function(m) {
 				});
 			}
 			strSample += "$.ajax({" + "\n";
-			strSample += "type : '"+ m.type + "',\n";
-			strSample += "url : '"+address + "',\n";
-			strSample += "headers : {'x-debugger' : true}" + ",\n";
-			strSample += "contentType : false,\n";
-			strSample += "processData  : false,\n";
-			strSample += "xhrFields : {'withCredentials' : true}" + ",\n";
-			strSample += "crossDomain : true"+ ",\n";
-			strSample += "data : formData"+"\n";
+			strSample += "        type : '"+ m.type + "',\n";
+			strSample += "        url : '"+address + "',\n";
+			strSample += "        headers : {'x-debugger' : true}" + ",\n";
+			strSample += "        contentType : false,\n";
+			strSample += "        processData  : false,\n";
+			strSample += "        xhrFields : {'withCredentials' : true}" + ",\n";
+			strSample += "        crossDomain : true"+ ",\n";
+			strSample += "        data : formData"+"\n";
 			strSample += "});";	
 	}
 
 	return  strSample;
    }
+Describe.createSampleCommon= function(m,className) {
+	 debugger;
+	var address = window.location.href;
+		address = address.substring(0,address.indexOf("/jest/"));
+	var root = address.substring(address.lastIndexOf("/")+1,address.length);
 
+	var parameter = "";
+	if (m.pathParameters && m.pathParameters.length > 0) {
+			$.each(m.pathParameters, function(pi, p) {
+				if(parameter == ""){
+					parameter =  p.name ;
+				}else{
+					parameter = parameter +  "," + p.name;
+				}
+			});
+		}
+	var query = "";
+		if (m.queryParameters && m.queryParameters.length > 0) {
+			$.each(m.queryParameters, function(pi, p) {
+				if (query == "") {
+					 query = "&" + p.name + '=' + '替换参数'+pi;
+				} else {
+					 query = query + "&"+ p.name + '=' + '替换参数'+pi;
+				}
+			});
+		}
+	var strSample="";
+	var body = "";
+	if (m.contentType.indexOf('application/json') > -1) {
+				if (m.ins && m.ins.length > 0) {
+					 body =  "var data = {};" + "\n";
+					$.each(m.ins, function(ii, i) {
+						switch (i.type) {
+						default:
+							if (i.isBaseType) {
+								if (i.isCollection) {
+									  body += '       data["'+i.name+'"] = ["参数1"];' + "\n";
+								} else {
+									  body += '       data["'+i.name+'"] = "参数";' + "\n";
+								}
+							} else {
+									if(i.isCollection){
+										body += '       data["'+i.name+'"] = [{"参数1":"value1","参数2":"value2"}];'+"\n";
+									}else{
+										body += '       data["'+i.name+'"] = {"参数1":"value1","参数2":"value2"};'+"\n";
+									}
+															
+							
+							}
+						}
+					});
+				} else if (m.useJsonElementParameter) {
+					body += '       data = {"参数1":"value1","参数2":"value2"};' +"\n";
+				} else if (m.useStringParameter) {
+					body += '       data = "参数";'+"\n";
+				}
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += body;	
+		 }	   
+	 }			
+	 strSample += "var action = this.Actions.load(\"" + root + "\");\n";
+	 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+	 if(parameter!=""){
+	   strSample += "      " + parameter  +",//uri的参数\n";
+	 }
+	 if(m.type != "GET" ){
+		 if( body != ""){
+	        strSample += "      data,//body请求参数\n";	
+		 }	   
+	 }
+	 strSample += "      function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+	 strSample += "         data = json.data; //为变量data赋值\n";
+	 strSample += "      }.bind(this),\n";
+	 strSample +=  "     function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+	 strSample +=  "        data = json.data; //为变量data赋值\n";
+	 strSample +=  "     }.bind(this),\n";
+	 strSample += "      false //同步执行 \n";
+	 strSample += "    );\n";
+				
+	}else{
+			var formData = "var formData = new FormData();" + "\n";
+			if (m.formParameters && m.formParameters.length > 0) {
+				$.each(m.formParameters, function(pi, p) {
+					if (p.type == "File") {
+					formData += '      formData.append("'+p.name+'", $("input[type=file]")[0].files[0]);' +  "\n";
+					} else {
+					formData += '      formData.append("'+p.name+'", "参数值'+pi+'");' +  "\n";
+					}
+				});
+			}
+		 strSample += formData;
+		 strSample += "var action = this.Actions.get(\"" + root + "\");\n";
+		 //strSample += "action."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "       action."+ className + "."+m.name+ "(//平台封装好的方法\n";
+		 strSample += "      "+parameter  +",//uri的参数\n";
+		 strSample +=  "      formData"+",//from参数\n";
+		 strSample +=  "function( json ){ //服务调用成功的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "function( json ){ //服务调用失败的回调函数, json为服务传回的数据\n";
+		 strSample +=  "      data = json.data; //为变量data赋值\n";
+		 strSample +=  "}.bind(this),\n";
+		 strSample +=  "false //同步执行 \n";
+		 strSample += ");\n"
+		} 
+   return  strSample ;		
+   }
 Describe.prototype = {
 	"load" : function() {
 		var str = '<ul>';
 		$.getJSON('../describe/describe.json?rd=' + Math.random(), function(json) {
 			$.each(json.jaxrs, function(ji, j) {
-				str += '<li xtype="menu" >' + j.name;
+				str += '<li xtype="menu" ' + 'style="margin-top: 30px;font-size:14px;font-weight:bold;"title="' +'" >' + j.name + ' <span style="font-style:italic">(' + j.description+ ')</span>';
 				$.each(j.methods, function(mi, m) {
-					str += '<ul><li xtype="li"><a id ="' + j.name + '_' + m.name + '" href="#">' + m.name + '</a></li></ul>';
+					str += '<ul><li xtype="li"  style="margin-top: 10px;margin-left:-24px;font-size:12px; font-weight:normal;line-height:18px" ><a id ="' + j.name + '_' + m.name + '" href="#"><b>' + m.name+'</b><br/><span style="color: #666666;">-'+ m.description + '</span>' + '</a></li></ul>';
 				});
 				str += '</li>'
 			});
@@ -262,7 +648,7 @@ Describe.prototype = {
 								var sample = "";
 								var txt = '<fieldset id="method"><legend>Method</legend>';
 								txt += '<table>';
-								txt += '<tr><td>name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
+								txt += '<tr><td style="width:100px;">name:</td><td><a href="../describe/sources/' + m.className.replace(/\./g, '/') + '.java">' + m.name + '</a></td></tr>';
 								txt += '<tr><td>path:</td><td>' + m.path + '</td></tr>';
 								txt += '<tr><td>type:</td><td>' + m.type + '</td></tr>';
 								txt += '<tr><td>description:</td><td>' + m.description + '</td></tr>';
@@ -366,7 +752,7 @@ Describe.prototype = {
 									txt += '<fieldset id="outs"><legend>Out</legend>';
 									txt += '<table>';
 									$.each(m.outs, function(oi, o) {
-										txt += '<tr><td>' + o.name + '</td><td>' + o.type + '</td><td>' + (o.isCollection ? 'multi' : 'single') + '</td><td>' + o.description + '</td><td id="out_'
+										txt += '<tr><td style="width: 160px;">' + o.name + '</td><td style="width: 90px;">' + o.type + '</td><td style="width: 90px;">' + (o.isCollection ? 'multi' : 'single') + '</td><td style="width: 90px;">' + o.description + '</td><td id="out_'
 												+ o.name + '_out">&nbsp;</td></tr>';
 									});
 									txt += '</table>';
@@ -407,7 +793,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															//data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
 														}
 													}
 												});
@@ -431,7 +826,16 @@ Describe.prototype = {
 																data[i.name] = $('#' + i.name, '#ins').val();
 															}
 														} else {
-															data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															if($('#' + i.name, '#ins').val() == ""){
+																if(i.isCollection){
+																	data[i.name] = [{}];
+																}else{
+																	data[i.name] = {};
+																}
+															}else{
+																data[i.name] = $.parseJSON($('#' + i.name, '#ins').val());
+															}
+														
 														}
 													}
 												});
@@ -493,7 +897,11 @@ Describe.prototype = {
 								})
 								
 								debugger;
-							 $('#Sample').html(Describe.createSample(m));
+							$('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;color: #1E7ACE;\">\n平台推荐脚本样例</span>\n\n"+ Describe.createSampleCommon(m,j.name)+ "</div><div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							
+							 /*
+							 $('#Sample').html("<div style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n前台脚本样例</span>\n\n"+ Describe.createSampleJSO2(m)+ "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\n后台脚本样例</span>\n\n" + Describe.createSampleO2(m) + "</div><div  style=\"border-bottom:1px solid #E6E6E6;padding-bottom: 40px;line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\nmootools样例</span>\n\n"+Describe.createSampleMootools(m)+"</div><div  style=\"line-height:21px\"><span style=\"font-size:17px;font-weight:bold;\">\n\njquery样例</span>\n\n<span style=\"\">"+ Describe.createSample(m)+"</span></div>");
+							 */
 							});
 				});
 			});
@@ -505,7 +913,13 @@ Describe.prototype = {
 						  }else{
 						     event.cancelBubble = true;
 						  }
-					    $(this).children().toggle();
+						$(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+					    //$(this).children().toggle();
 					});
 		  $("[xtype='li']").click( function(event) {
 			    if(event.stopPropagation){
@@ -514,6 +928,18 @@ Describe.prototype = {
 				     event.cancelBubble = true;
 				  }
 			})
+			$("[xtype='menu']").each(function(i){ 
+			if(i!=0){
+			  // $(this).children().toggle();
+			  $(this).children().each(function(i){
+							debugger;
+							if(this.tagName != "SPAN"){
+							$(this).toggle();
+							}
+						});
+			  }
+			}
+			);
 		});
 		
 	

+ 9 - 8
o2server/x_calendar_assemble_control/src/main/webapp/jest/index.html

@@ -99,7 +99,14 @@
 				
 				<div id="content"
 						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word;border-image: linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 100%, #ffffff);box-shadow: inset 15px 0 5px -16px #e7e7e7;background-image: -webkit-radial-gradient(right, #f2f2f2, #ffffff 100%);">&nbsp;</div>
-						
+				<fieldset>
+					<legend>
+						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
+					</legend>
+					<div id="result"
+						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
+				</fieldset>
+				
 			    <fieldset>
 					<legend>
 						Sample&nbsp;<a  id="btn_copy"  href="javascript:" data-clipboard-target="#Sample">copy</a>&nbsp;
@@ -109,13 +116,7 @@
 						</div>
 				</fieldset>		
 						
-				<fieldset>
-					<legend>
-						Result&nbsp;<a id="btn_copy" href="javascript:" data-clipboard-target="#result">copy</a>&nbsp;
-					</legend>
-					<div id="result"
-						style="white-space: pre; font-size: 12px; word-break: break-all; word-wrap: break-word; width: 1400px">&nbsp;</div>
-				</fieldset>
+
 			</td>
 		</tr>
 	</table>

+ 11 - 38
o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_Event.java

@@ -90,14 +90,6 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 	public Calendar_Event() {
 	}
 
-	/**
-	 * Create a new calendar event with the given subject and given start and end
-	 * times as UNIX timestamps.
-	 * 
-	 * @param title
-	 * @param startTime
-	 * @param endTime
-	 */
 	public Calendar_Event(final String id, final String title, final Date startTime, final Date endTime) {
 		this.id = id;
 		this.title = title;
@@ -106,14 +98,6 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 		this.isAllDayEvent = false;
 	}
 
-	/**
-	 * Create a new calendar entry with the given subject, starting at <begin> and
-	 * with a duration of <duration> milliseconds.
-	 * 
-	 * @param title
-	 * @param startTime
-	 * @param duration
-	 */
 	public Calendar_Event(final String id, final String title, final Date startTime, final int duration) {
 		this.id = id;
 		this.title = title;
@@ -122,30 +106,12 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 		this.isAllDayEvent = false;
 	}
 
-	/**
-	 * Create a new calendar entry with the given start, a duration and a recurrence
-	 * 
-	 * @param id
-	 * @param title
-	 * @param startTime
-	 * @param duration
-	 * @param recurrenceRule
-	 */
 	public Calendar_Event(final String id, final String title, final Date startTime, final int duration,
 			final String recurrenceRule) {
 		this(id, title, startTime, duration);
 		this.recurrenceRule = recurrenceRule;
 	}
 
-	/**
-	 * Create a new calendar entry with the given start and end
-	 * 
-	 * @param id
-	 * @param subject
-	 * @param begin
-	 * @param end
-	 * @param recurrenceRule
-	 */
 	public Calendar_Event(final String id, final String title, final Date startTime, final Date endTime,
 			final String recurrenceRule) {
 		this(id, title, startTime, endTime);
@@ -197,6 +163,12 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 	@CheckPersist(allowEmpty = true)
 	private String comment = null;
 
+	public static final String commentId_FIELDNAME = "commentId";
+	@FieldDescribe("备注LOB信息")
+	@Column(length = JpaObject.length_id, name = ColumnNamePrefix + commentId_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String commentId = null;
+
 	public static final String startTime_FIELDNAME = "startTime";
 	@FieldDescribe("事件开始时间")
 	@Temporal(TemporalType.TIMESTAMP)
@@ -754,6 +726,10 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 		this.color = color;
 	}
 
+	public String getCommentId() { return commentId; }
+
+	public void setCommentId(String commentId) { this.commentId = commentId; }
+
 	/**
 	 * 是否是在一天内结束的日程或者事件
 	 * 
@@ -799,12 +775,9 @@ public class Calendar_Event extends SliceJpaObject implements Cloneable, Compara
 
 	/**
 	 * 判断事件是否在指定的时间范围之内 Check if the event recurs within the given period
-	 * 
 	 * @param periodStart
 	 * @param periodEnd
-	 * @param kEvent
-	 * @return <code>true</code> if event recurs in the given period, otherwise
-	 *         <code>false</code>
+	 * @return
 	 */
 	public boolean isRecurringInPeriod(final Date periodStart, final Date periodEnd) {
 		final DateList recurDates = getRecurringsInPeriod(periodStart, periodEnd);

+ 85 - 0
o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_EventComment.java

@@ -0,0 +1,85 @@
+package com.x.calendar.core.entity;
+
+import com.x.base.core.entity.JpaObject;
+import com.x.base.core.entity.SliceJpaObject;
+import com.x.base.core.entity.annotation.CheckPersist;
+import com.x.base.core.entity.annotation.ContainerEntity;
+import com.x.base.core.project.annotation.FieldDescribe;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * 日程事件超长LOB信息
+ * 如果事件COMMENT超过70个字符时,使用LOB字段进行存储,在COMMENT中使用'CLOB'来标记,在COMMENTID里指定其记录引用
+ * 
+ * @author O2LEE
+ *
+ */
+@ContainerEntity
+@Entity
+@Table(name = PersistenceProperties.Calendar_EventComment.table, uniqueConstraints = {
+		@UniqueConstraint(name = PersistenceProperties.Calendar_EventComment.table + JpaObject.IndexNameMiddle
+				+ JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
+						JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }) })
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class Calendar_EventComment extends SliceJpaObject {
+
+	private static final long serialVersionUID = 1325197931747463979L;
+	private static final String TABLE = PersistenceProperties.Calendar_EventComment.table;
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	@FieldDescribe("数据库主键,自动生成.")
+	@Id
+	@Column(length = length_id, name = ColumnNamePrefix + id_FIELDNAME, unique = true)
+	private String id = createId();
+
+	public void onPersist() throws Exception {
+	}
+	/*
+	 * =============================================================================
+	 * ===== 以上为 JpaObject 默认字段
+	 * =============================================================================
+	 * =====
+	 */
+
+	/*
+	 * =============================================================================
+	 * ===== 以下为具体不同的业务及数据表字段要求
+	 * =============================================================================
+	 * =====
+	 */
+
+	public static final String lobValue_FIELDNAME = "lobValue";
+	@Lob
+	@Basic(fetch = FetchType.EAGER)
+	@FieldDescribe("COMMENT信息的LOB值")
+	@Column(name = "xlobValue", length = JpaObject.length_10M)
+	private String lobValue = "";
+
+	public static final String checkTime_FIELDNAME = "checkTime";
+	@FieldDescribe("检查时间")
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = ColumnNamePrefix + checkTime_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private Date checkTime = null;
+
+	public Date getCheckTime() { return checkTime; }
+
+	public void setCheckTime(Date checkTime) { this.checkTime = checkTime; }
+
+	public String getLobValue() {
+		return lobValue;
+	}
+
+	public void setLobValue(String lobValue) {
+		this.lobValue = lobValue;
+	}
+}

+ 23 - 56
o2server/x_calendar_core_entity/src/main/java/com/x/calendar/core/entity/Calendar_EventRepeatMaster.java

@@ -18,6 +18,7 @@ import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 import javax.persistence.UniqueConstraint;
 
+import com.x.base.core.project.tools.ListTools;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.openjpa.persistence.PersistentCollection;
 import org.apache.openjpa.persistence.jdbc.ContainerTable;
@@ -99,14 +100,6 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	public Calendar_EventRepeatMaster() {
 	}
 
-	/**
-	 * Create a new calendar event with the given subject and given start and end
-	 * times as UNIX timestamps.
-	 * 
-	 * @param title
-	 * @param startTime
-	 * @param endTime
-	 */
 	public Calendar_EventRepeatMaster(final String id, final String title, final Date startTime, final Date endTime) {
 		this.id = id;
 		this.title = title;
@@ -116,14 +109,6 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 		this.isAllDayEvent = false;
 	}
 
-	/**
-	 * Create a new calendar entry with the given subject, starting at <begin> and
-	 * with a duration of <duration> milliseconds.
-	 * 
-	 * @param title
-	 * @param startTime
-	 * @param duration
-	 */
 	public Calendar_EventRepeatMaster(final String id, final String title, final Date startTime, final int duration) {
 		this.id = id;
 		this.title = title;
@@ -133,30 +118,12 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 		this.isAllDayEvent = false;
 	}
 
-	/**
-	 * Create a new calendar entry with the given start, a duration and a recurrence
-	 * 
-	 * @param id
-	 * @param title
-	 * @param startTime
-	 * @param duration
-	 * @param recurrenceRule
-	 */
 	public Calendar_EventRepeatMaster(final String id, final String title, final Date startTime, final int duration,
 			final String recurrenceRule) {
 		this(id, title, startTime, duration);
 		this.recurrenceRule = recurrenceRule;
 	}
 
-	/**
-	 * Create a new calendar entry with the given start and end
-	 * 
-	 * @param id
-	 * @param subject
-	 * @param begin
-	 * @param end
-	 * @param recurrenceRule
-	 */
 	public Calendar_EventRepeatMaster(final String id, final String title, final Date startTime, final Date endTime,
 			final String recurrenceRule) {
 		this(id, title, startTime, endTime);
@@ -201,6 +168,12 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	@CheckPersist(allowEmpty = true)
 	private String comment = null;
 
+	public static final String commentId_FIELDNAME = "commentId";
+	@FieldDescribe("备注LOB信息")
+	@Column(length = JpaObject.length_id, name = ColumnNamePrefix + commentId_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String commentId = null;
+
 	public static final String startTime_FIELDNAME = "startTime";
 	@FieldDescribe("事件开始时间")
 	@Temporal(TemporalType.TIMESTAMP)
@@ -508,6 +481,10 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 		return targetType;
 	}
 
+	public String getCommentId() { return commentId; }
+
+	public void setCommentId(String commentId) { this.commentId = commentId; }
+
 	public List<String> getParticipants() {
 		if (this.participants == null) {
 			this.participants = new ArrayList<>();
@@ -840,9 +817,7 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 
 	/**
 	 * 获取重复时间表达式中结束的日期
-	 * 
-	 * @param rule
-	 * @return date of recurrence end
+	 * @return
 	 */
 	public Date getRecurrenceEndDate() {
 		final TimeZone tz = TimeZoneRegistryFactory.getInstance().createRegistry()
@@ -865,12 +840,10 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	}
 
 	/**
-	 * 获取日程事件下一次执行的事件 Get the recurring event
-	 * 
-	 * @param today
-	 * @param kEvent
-	 * @return affected <code>KalendarEvent</code> or <code>null</code> if not
-	 *         recurring in period
+	 * 取日程事件下一次执行的事件
+	 * @param periodStart
+	 * @param periodEnd
+	 * @return
 	 * @throws Exception
 	 */
 	public Calendar_Event getRecurringInPeriod(final Date periodStart, final Date periodEnd) throws Exception {
@@ -900,13 +873,10 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	}
 
 	/**
-	 * 判断事件是否在指定的时间范围之内 Check if the event recurs within the given period
-	 * 
+	 * 判断事件是否在指定的时间范围之内
 	 * @param periodStart
 	 * @param periodEnd
-	 * @param kEvent
-	 * @return <code>true</code> if event recurs in the given period, otherwise
-	 *         <code>false</code>
+	 * @return
 	 * @throws Exception
 	 */
 	private boolean isRecurringInPeriod(final Date periodStart, final Date periodEnd) throws Exception {
@@ -939,7 +909,7 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 
 			// 排队日期
 			final String recurrenceExc = getRecurrenceExc();
-			if (recurrenceExc != null && !recurrenceExc.equals("")) {
+			if ( StringUtils.isNotEmpty( recurrenceExc )) {
 				try {
 					final ExDate exdate = new ExDate();
 					if (recurrenceExc.length() > 8) {
@@ -964,13 +934,10 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	}
 
 	/**
-	 * 计算一个重复日程事件在指定时间范围内所有的日程事件列表 Get all recurrings of an event within the given
-	 * period
-	 * 
+	 * 计算一个重复日程事件在指定时间范围内所有的日程事件列表
 	 * @param periodStart
 	 * @param periodEnd
-	 * @param kEvent
-	 * @return list with <code>KalendarRecurEvent</code>
+	 * @return
 	 * @throws Exception
 	 */
 	public List<Calendar_Event> getRecurringDatesInPeriod(final Date periodStart, final Date periodEnd)
@@ -1043,7 +1010,7 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	 */
 	private List<Date> getRecurrenceExcludeDates(final String recurrenceExc) {
 		final List<Date> recurExcDates = new ArrayList<Date>();
-		if (recurrenceExc != null && !recurrenceExc.equals("")) {
+		if ( StringUtils.isNotEmpty( recurrenceExc )) {
 			try {
 				final net.fortuna.ical4j.model.ParameterList pl = new net.fortuna.ical4j.model.ParameterList();
 				final ExDate exdate = new ExDate(pl, recurrenceExc);
@@ -1067,7 +1034,7 @@ public class Calendar_EventRepeatMaster extends SliceJpaObject implements Clonea
 	 * @return string with exclude rule
 	 */
 	private static String getRecurrenceExcludeRule(final List<Date> dates) {
-		if (dates != null && dates.size() > 0) {
+		if (ListTools.isNotEmpty( dates )) {
 			final DateList dl = new DateList();
 			for (final Date date : dates) {
 				final net.fortuna.ical4j.model.Date dd = new net.fortuna.ical4j.model.Date(date);

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff