dcs il y a 1 an
commit
1aedf0747f
100 fichiers modifiés avec 6481 ajouts et 0 suppressions
  1. 8 0
      .idea/.gitignore
  2. 42 0
      .idea/compiler.xml
  3. 16 0
      .idea/encodings.xml
  4. 30 0
      .idea/jarRepositories.xml
  5. 20 0
      .idea/misc.xml
  6. 10 0
      .idea/runConfigurations.xml
  7. 0 0
      .idea/sonarlint/issuestore/index.pb
  8. 6 0
      .idea/vcs.xml
  9. 54 0
      pom.xml
  10. BIN
      shiro-redis/.DS_Store
  11. 6 0
      shiro-redis/.gitignore
  12. 3 0
      shiro-redis/.travis.yml
  13. 21 0
      shiro-redis/LICENSE
  14. 11 0
      shiro-redis/README.md
  15. 1 0
      shiro-redis/_config.yml
  16. 86 0
      shiro-redis/checkstyle.xml
  17. 442 0
      shiro-redis/docs/README.md
  18. 2 0
      shiro-redis/docs/_config.yml
  19. 214 0
      shiro-redis/pom.xml
  20. BIN
      shiro-redis/src/.DS_Store
  21. 48 0
      shiro-redis/src/main/java/org/crazycake/shiro/IRedisManager.java
  22. 289 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisCache.java
  23. 99 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisCacheManager.java
  24. 234 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisClusterManager.java
  25. 77 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisManager.java
  26. 105 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisSentinelManager.java
  27. 282 0
      shiro-redis/src/main/java/org/crazycake/shiro/RedisSessionDAO.java
  28. 29 0
      shiro-redis/src/main/java/org/crazycake/shiro/SessionInMemory.java
  29. 172 0
      shiro-redis/src/main/java/org/crazycake/shiro/WorkAloneRedisManager.java
  30. 10 0
      shiro-redis/src/main/java/org/crazycake/shiro/exception/CacheManagerPrincipalIdNotAssignedException.java
  31. 10 0
      shiro-redis/src/main/java/org/crazycake/shiro/exception/PrincipalIdNullException.java
  32. 18 0
      shiro-redis/src/main/java/org/crazycake/shiro/exception/PrincipalInstanceException.java
  33. 10 0
      shiro-redis/src/main/java/org/crazycake/shiro/exception/SerializationException.java
  34. 59 0
      shiro-redis/src/main/java/org/crazycake/shiro/serializer/MultiClassLoaderObjectInputStream.java
  35. 60 0
      shiro-redis/src/main/java/org/crazycake/shiro/serializer/ObjectSerializer.java
  36. 10 0
      shiro-redis/src/main/java/org/crazycake/shiro/serializer/RedisSerializer.java
  37. 42 0
      shiro-redis/src/main/java/org/crazycake/shiro/serializer/StringSerializer.java
  38. 256 0
      shiro-redis/src/test/java/fixture/TestFixture.java
  39. 44 0
      shiro-redis/src/test/java/org/crazycake/shiro/RedisCacheManagerTest.java
  40. 173 0
      shiro-redis/src/test/java/org/crazycake/shiro/RedisCacheTest.java
  41. 55 0
      shiro-redis/src/test/java/org/crazycake/shiro/RedisClusterManagerTest.java
  42. 143 0
      shiro-redis/src/test/java/org/crazycake/shiro/RedisSessionDAOTest.java
  43. 31 0
      shiro-redis/src/test/java/org/crazycake/shiro/model/FakeAuth.java
  44. 87 0
      shiro-redis/src/test/java/org/crazycake/shiro/model/FakeSession.java
  45. 56 0
      shiro-redis/src/test/java/org/crazycake/shiro/model/UserInfo.java
  46. 4 0
      shiro-redis/src/test/resources/shiro-standalone.ini
  47. BIN
      virgo.api/.DS_Store
  48. 32 0
      virgo.api/.classpath
  49. 2 0
      virgo.api/.gitignore
  50. 40 0
      virgo.api/.project
  51. 4 0
      virgo.api/.settings/org.eclipse.core.resources.prefs
  52. 7 0
      virgo.api/.settings/org.eclipse.jdt.core.prefs
  53. 4 0
      virgo.api/.settings/org.eclipse.m2e.core.prefs
  54. 4 0
      virgo.api/.settings/org.eclipse.wst.common.project.facet.core.xml
  55. 53 0
      virgo.api/pom.xml
  56. 20 0
      virgo.api/src/main/java/com/bosshand/virgo/api/Application.java
  57. 26 0
      virgo.api/src/main/java/com/bosshand/virgo/api/CorsConfig.java
  58. 45 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/CollaborativeController.java
  59. 44 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ConfigurationUrlController.java
  60. 41 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ConstructionLogController.java
  61. 71 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/DesignChangeController.java
  62. 42 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/DrawingsMarkedController.java
  63. 93 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ElementController.java
  64. 72 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ElementStepController.java
  65. 414 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/FlowManagerController.java
  66. 177 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/FlowSynergyDataController.java
  67. 113 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/InspectController.java
  68. 76 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/MaterialBatchController.java
  69. 44 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/MaterialCheckController.java
  70. 51 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/NoticeController.java
  71. 111 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/PartItemMetaDataController.java
  72. 80 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/PointToPointController.java
  73. 159 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectController.java
  74. 69 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectFlowMetaDataController.java
  75. 231 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectItemController.java
  76. 69 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/RectificationController.java
  77. 213 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/SetUpController.java
  78. 41 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/SignOnBehalfControler.java
  79. 51 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/TypeCascadeController.java
  80. 80 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/WeeklyController.java
  81. 60 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/WeeklyPersonController.java
  82. 60 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyCompanyController.java
  83. 60 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyDepartmentController.java
  84. 60 0
      virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyPersonController.java
  85. 20 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/BimModelTargetDao.java
  86. 20 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/BimTypeDao.java
  87. 18 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/CollaborativeDao.java
  88. 17 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/ConfigurationUrlDao.java
  89. 15 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/ConstructionLogDao.java
  90. 23 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/DesignChangeDao.java
  91. 19 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/DrawingsMarkedDao.java
  92. 15 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementDao.java
  93. 21 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementStepDao.java
  94. 19 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementStepModelDao.java
  95. 20 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/EnvironmentDao.java
  96. 18 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/EnvironmentTypeDao.java
  97. 22 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/EquipmentDao.java
  98. 18 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/EquipmentTypeDao.java
  99. 22 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/FlowInstanceDao.java
  100. 0 0
      virgo.api/src/main/java/com/bosshand/virgo/api/dao/FlowInstanceNodeDao.java

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/

+ 42 - 0
.idea/compiler.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="CompilerConfiguration">
+    <annotationProcessing>
+      <profile name="Maven default annotation processors profile" enabled="true">
+        <sourceOutputDir name="target/generated-sources/annotations" />
+        <sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
+        <outputRelativeToContentRoot value="true" />
+        <module name="core" />
+        <module name="ringzle" />
+        <module name="file" />
+        <module name="manager" />
+        <module name="eureka" />
+        <module name="zuul" />
+        <module name="api" />
+        <module name="config" />
+        <module name="faceSDK" />
+        <module name="frontend" />
+        <module name="warpdrive" />
+      </profile>
+    </annotationProcessing>
+    <bytecodeTargetLevel>
+      <module name="bim" target="1.8" />
+    </bytecodeTargetLevel>
+  </component>
+  <component name="JavacSettings">
+    <option name="ADDITIONAL_OPTIONS_OVERRIDE">
+      <module name="api" options="-parameters" />
+      <module name="bim" options="-parameters" />
+      <module name="config" options="-parameters" />
+      <module name="core" options="-parameters" />
+      <module name="eureka" options="-parameters" />
+      <module name="faceSDK" options="-parameters" />
+      <module name="file" options="-parameters" />
+      <module name="frontend" options="-parameters" />
+      <module name="manager" options="-parameters" />
+      <module name="ringzle" options="-parameters" />
+      <module name="warpdrive" options="-parameters" />
+      <module name="zuul" options="-parameters" />
+    </option>
+  </component>
+</project>

+ 16 - 0
.idea/encodings.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/virgo.api/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.config/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.core/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.eureka/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.faceSDK/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.file/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.frontend/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.manager/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.ringzle/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.warpdrive/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/virgo.zuul/src/main/java" charset="UTF-8" />
+  </component>
+</project>

+ 30 - 0
.idea/jarRepositories.xml

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RemoteRepositoriesConfiguration">
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Central Repository" />
+      <option name="url" value="https://repo.maven.apache.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="central" />
+      <option name="name" value="Maven Central repository" />
+      <option name="url" value="https://repo1.maven.org/maven2" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="jboss.community" />
+      <option name="name" value="JBoss Community repository" />
+      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="getui-nexus" />
+      <option name="name" value="getui-nexus" />
+      <option name="url" value="http://mvn.gt.igexin.com/nexus/content/repositories/releases/" />
+    </remote-repository>
+    <remote-repository>
+      <option name="id" value="com.e-iceblue" />
+      <option name="name" value="com.e-iceblue" />
+      <option name="url" value="http://repo.e-iceblue.cn/repository/maven-public/" />
+    </remote-repository>
+  </component>
+</project>

+ 20 - 0
.idea/misc.xml

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="AnalysisProjectProfileManager">
+    <option name="PROJECT_PROFILE" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <list size="0" />
+  </component>
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
+  <component name="SuppressionsComponent">
+    <option name="suppComments" value="[]" />
+  </component>
+</project>

+ 10 - 0
.idea/runConfigurations.xml

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="RunConfigurationProducerService">
+    <option name="ignoredProducers">
+      <set>
+        <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
+      </set>
+    </option>
+  </component>
+</project>

+ 0 - 0
.idea/sonarlint/issuestore/index.pb


+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 54 - 0
pom.xml

@@ -0,0 +1,54 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.bosshand</groupId>
+    <artifactId>virgo</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <name>virgo</name>
+    <url>http://www.bosshand.com</url>
+    
+	<!-- Inherit defaults from Spring Boot -->
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.1.8.RELEASE</version>
+	</parent>
+	
+	 <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>		
+		<java.version>1.8</java.version>
+    	<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
+		<druid.version>1.0.25</druid.version>
+  	</properties>
+
+    <modules>
+        <module>virgo.faceSDK</module>
+        <module>virgo.core</module>
+		<module>virgo.config</module>
+		<module>virgo.eureka</module>
+		<module>virgo.api</module>			
+		<module>virgo.manager</module>
+		<module>virgo.zuul</module>
+		<module>virgo.file</module>
+		<module>virgo.warpdrive</module>
+
+		<module>virgo.ringzle</module>
+
+		<module>virgo.frontend</module>
+
+    </modules>
+
+    <dependencyManagement>
+		<dependencies>
+		  <dependency>
+			<groupId>org.springframework.cloud</groupId>
+			<artifactId>spring-cloud-dependencies</artifactId>
+			<version>${spring-cloud.version}</version>
+			<type>pom</type>
+			<scope>import</scope>
+		  </dependency>
+		</dependencies>
+    </dependencyManagement>
+
+</project>

BIN
shiro-redis/.DS_Store


+ 6 - 0
shiro-redis/.gitignore

@@ -0,0 +1,6 @@
+.settings
+.classpath
+.project
+target
+.idea
+shiro-redis.iml

+ 3 - 0
shiro-redis/.travis.yml

@@ -0,0 +1,3 @@
+language: java
+services:
+  - redis-server

+ 21 - 0
shiro-redis/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 xi yang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 11 - 0
shiro-redis/README.md

@@ -0,0 +1,11 @@
+shiro-redis
+=============
+
+## Introduction
+
+shiro only provide the support of ehcache and concurrentHashMap. Here is an implement of redis cache can be used by shiro. Hope it will help you!
+
+## Documentation
+
+Official documentation [is located here](http://alexxiyang.github.io/shiro-redis/).
+

+ 1 - 0
shiro-redis/_config.yml

@@ -0,0 +1 @@
+theme: jekyll-theme-merlot

+ 86 - 0
shiro-redis/checkstyle.xml

@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!DOCTYPE module PUBLIC
+        "-//Puppy Crawl//DTD Check Configuration 1.3//EN"
+        "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
+<!--
+  Checkstyle configuration that checks the sun coding conventions from:
+
+    - the Java Language Specification at
+      http://java.sun.com/docs/books/jls/second_edition/html/index.html
+
+    - the Sun Code Conventions at http://java.sun.com/docs/codeconv/
+
+    - the Javadoc guidelines at
+      http://java.sun.com/j2se/javadoc/writingdoccomments/index.html
+
+    - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html
+
+    - some best practices
+
+  Checkstyle is very configurable. Be sure to read the documentation at
+  http://checkstyle.sf.net (or in your downloaded distribution).
+
+  Most Checks are configurable, be sure to consult the documentation.
+
+  To completely disable a check, just comment it out or delete it from the file.
+
+  Finally, it is worth reading the documentation.
+-->
+
+<module name="Checker">
+    <module name="Translation"/>
+    <module name="FileLength"/>
+    <module name="TreeWalker">
+        <module name="ConstantName"/>
+        <module name="LocalFinalVariableName"/>
+        <module name="LocalVariableName"/>
+        <module name="MemberName"/>
+        <module name="MethodName"/>
+        <module name="PackageName"/>
+        <module name="ParameterName"/>
+        <module name="StaticVariableName"/>
+        <module name="TypeName"/>
+        <module name="RedundantImport"/>
+        <module name="LineLength">
+            <property name="max" value="180"/>
+        </module>
+        <module name="MethodLength"/>
+        <module name="ParameterNumber"/>
+        <module name="EmptyForIteratorPad"/>
+        <module name="GenericWhitespace"/>
+        <module name="MethodParamPad"/>
+        <module name="NoWhitespaceAfter"/>
+        <module name="NoWhitespaceBefore"/>
+        <module name="OperatorWrap"/>
+        <module name="ParenPad"/>
+        <module name="TypecastParenPad"/>
+        <module name="WhitespaceAfter"/>
+        <module name="WhitespaceAround"/>
+        <module name="ModifierOrder"/>
+        <module name="RedundantModifier"/>
+        <module name="AvoidNestedBlocks"/>
+        <module name="EmptyBlock"/>
+        <module name="LeftCurly"/>
+        <module name="NeedBraces"/>
+        <module name="RightCurly"/>
+        <module name="EmptyStatement"/>
+        <module name="EqualsHashCode"/>
+        <module name="HiddenField">
+            <property name="ignoreSetter" value="true" />
+            <property name="ignoreConstructorParameter" value="true" />
+        </module>
+        <module name="IllegalInstantiation"/>
+        <module name="InnerAssignment"/>
+        <module name="MagicNumber"/>
+        <module name="MissingSwitchDefault"/>
+        <module name="SimplifyBooleanExpression"/>
+        <module name="SimplifyBooleanReturn"/>
+        <module name="FinalClass"/>
+        <module name="HideUtilityClassConstructor"/>
+        <module name="InterfaceIsType"/>
+        <module name="VisibilityModifier"/>
+        <module name="ArrayTypeStyle"/>
+        <module name="TodoComment"/>
+        <module name="UpperEll"/>
+    </module>
+</module>

+ 442 - 0
shiro-redis/docs/README.md

@@ -0,0 +1,442 @@
+shiro-redis
+=============
+
+[![Build Status](https://travis-ci.org/alexxiyang/shiro-redis.svg?branch=master)](https://travis-ci.org/alexxiyang/shiro-redis)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.crazycake/shiro-redis/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.crazycake/shiro-redis)
+
+shiro only provide the support of ehcache and concurrentHashMap. Here is an implement of redis cache can be used by shiro. Hope it will help you!
+
+# Download
+
+You can choose these 2 ways to include shiro-redis into your project
+* use "git clone https://github.com/alexxiyang/shiro-redis.git" to clone project to your local workspace and build jar file by your self
+* add maven dependency 
+
+```xml
+<dependency>
+    <groupId>org.crazycake</groupId>
+    <artifactId>shiro-redis</artifactId>
+    <version>3.2.3</version>
+</dependency>
+```
+
+> **Note:**\
+> Do not use version < 3.1.0\
+> **注意**:\
+> 请不要使用3.1.0以下版本
+
+# Before use
+Here is the first thing you need to know. Shiro-redis needs an id field to identify your authorization object in Redis. So please make sure your principal class has a field which you can get unique id of this object. Please setting this id field name by `cacheManager.principalIdFieldName = <your id field name of principal object>`
+
+For example:
+
+If you create SimpleAuthenticationInfo like the following:
+```java
+@Override
+protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+    UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken)token;
+    UserInfo userInfo = new UserInfo();
+    userInfo.setUsername(usernamePasswordToken.getUsername());
+    return new SimpleAuthenticationInfo(userInfo, "123456", getName());
+}
+```
+
+Then the userInfo object is your principal object. You need to make sure `UserInfo` has an unique field to identify it in Redis. Take userId as an example:
+```java
+public class UserInfo implements Serializable{
+
+    private Integer userId
+
+    private String username;
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Integer getUserId() {
+        return this.userId;
+    }
+}
+```
+
+Put userId as the value of `cacheManager.principalIdFieldName`, like this:
+```properties
+cacheManager.principalIdFieldName = userId
+```
+
+If you're using Spring, the configuration should be
+```xml
+<property name="principalIdFieldName" value="userId" />
+```
+
+Then shiro-redis will call `userInfo.getUserId()` to get the id for storing Redis object.
+
+# How to configure ?
+
+You can configure shiro-redis either in `shiro.ini` or in `spring-*.xml`
+
+## shiro.ini
+Here is the configuration for shiro.ini.
+
+### Redis Standalone
+
+```properties
+[main]
+#====================================
+# shiro-redis configuration [start]
+#====================================
+
+#===================================
+# Redis Manager [start]
+#===================================
+
+# Create redisManager
+redisManager = org.crazycake.shiro.RedisManager
+
+# Redis host. If you don't specify host the default value is 127.0.0.1:6379
+redisManager.host = 127.0.0.1:6379
+
+#===================================
+# Redis Manager [end]
+#===================================
+
+#=========================================
+# Redis session DAO [start]
+#=========================================
+
+# Create redisSessionDAO
+redisSessionDAO = org.crazycake.shiro.RedisSessionDAO
+
+# Use redisManager as cache manager
+redisSessionDAO.redisManager = $redisManager
+
+sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
+
+sessionManager.sessionDAO = $redisSessionDAO
+
+securityManager.sessionManager = $sessionManager
+
+#=========================================
+# Redis session DAO [end]
+#=========================================
+
+#==========================================
+# Redis cache manager [start]
+#==========================================
+
+# Create cacheManager
+cacheManager = org.crazycake.shiro.RedisCacheManager
+
+# Principal id field name. The field which you can get unique id to identify this principal.
+# For example, if you use UserInfo as Principal class, the id field maybe `id`, `userId`, `email`, etc.
+# Remember to add getter to this id field. For example, `getId()`, `getUserId()`, `getEmail()`, etc.
+# Default value is id, that means your principal object must has a method called `getId()`
+#
+cacheManager.principalIdFieldName = id
+
+# Use redisManager as cache manager
+cacheManager.redisManager = $redisManager
+
+securityManager.cacheManager = $cacheManager
+
+#==========================================
+# Redis cache manager [end]
+#==========================================
+
+#=================================
+# shiro-redis configuration [end]
+#=================================
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+Here is a [tutorial project](https://github.com/alexxiyang/shiro-redis-tutorial) for you to understand how to configure `shiro-redis` in `shiro.ini`.
+
+### Redis Sentinel
+if you're using Redis Sentinel, please change the redisManager configuration into the following:
+```properties
+#===================================
+# Redis Manager [start]
+#===================================
+
+# Create redisManager
+redisManager = org.crazycake.shiro.RedisSentinelManager
+
+# Sentinel host. If you don't specify host the default value is 127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381
+redisManager.host = 127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381
+
+# Sentinel master name
+redisManager.masterName = mymaster
+
+#===================================
+# Redis Manager [end]
+#===================================
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+### Redis Cluster
+If you're using redis cluster, here is an example of configuration :
+
+```properties
+#===================================
+# Redis Manager [start]
+#===================================
+
+# Create redisManager
+redisManager = org.crazycake.shiro.RedisClusterManager
+
+# Redis host and port list
+redisManager.host = 192.168.21.3:7000,192.168.21.3:7001,192.168.21.3:7002,192.168.21.3:7003,192.168.21.3:7004,192.168.21.3:7005
+
+#===================================
+# Redis Manager [end]
+#===================================
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+## Spring
+
+### Redis Standalone
+spring.xml:
+```xml
+<!-- shiro-redis configuration [start] -->
+
+<!-- Redis Manager [start] -->
+<bean id="redisManager" class="org.crazycake.shiro.RedisManager">
+    <property name="host" value="127.0.0.1:6379"/>
+</bean>
+<!-- Redis Manager [end] -->
+
+<!-- Redis session DAO [start] -->
+<bean id="redisSessionDAO" class="org.crazycake.shiro.RedisSessionDAO">
+    <property name="redisManager" ref="redisManager" />
+</bean>
+<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
+    <property name="sessionDAO" ref="redisSessionDAO" />
+</bean>
+<!-- Redis session DAO [end] -->
+
+<!-- Redis cache manager [start] -->
+<bean id="cacheManager" class="org.crazycake.shiro.RedisCacheManager">
+    <property name="redisManager" ref="redisManager" />
+</bean>
+<!-- Redis cache manager [end] -->
+
+<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
+    <property name="sessionManager" ref="sessionManager" />
+    <property name="cacheManager" ref="cacheManager" />
+
+    <!-- other configurations -->
+    <property name="realm" ref="exampleRealm"/>
+    <property name="rememberMeManager.cipherKey" value="kPH+bIxk5D2deZiIxcaaaA==" />
+</bean>
+
+<!-- shiro-redis configuration [end] -->
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+Here is a [tutorial project](https://github.com/alexxiyang/shiro-redis-spring-tutorial) for you to understand how to configure `shiro-redis` in spring configuration file.
+
+### Redis Sentinel
+If you use redis sentinel, here is an example of configuration :
+```xml
+<!-- shiro-redis configuration [start] -->
+<!-- shiro redisManager -->
+<bean id="redisManager" class="org.crazycake.shiro.RedisSentinelManager">
+    <property name="host" value="127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381"/>
+    <property name="masterName" value="mymaster"/>
+</bean>
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+### Redis Cluster
+If you use redis cluster, here is an example of configuration :
+```xml
+<!-- shiro-redis configuration [start] -->
+<!-- shiro redisManager -->
+<bean id="redisManager" class="org.crazycake.shiro.RedisClusterManager">
+    <property name="host" value="192.168.21.3:7000,192.168.21.3:7001,192.168.21.3:7002,192.168.21.3:7003,192.168.21.3:7004,192.168.21.3:7005"/>
+</bean>
+```
+
+For complete configurable options list, check [Configurable Options](#configurable-options).
+
+## Serializer
+Since redis only accept `byte[]`, there comes to a serializer problem.
+Shiro-redis is using StringSerializer as key serializer and ObjectSerializer as value serializer.
+You can use your own custom serializer, as long as this custom serializer implemens `org.crazycake.shiro.serializer.RedisSerializer`
+
+For example, let's change the charset of keySerializer.
+```properties
+# If you want change charset of keySerializer or use your own custom serializer, you need to define serializer first
+#
+# cacheManagerKeySerializer = org.crazycake.shiro.serializer.StringSerializer
+
+# Supported encodings refer to https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html
+# UTF-8, UTF-16, UTF-32, ISO-8859-1, GBK, Big5, etc
+#
+# cacheManagerKeySerializer.charset = UTF-8
+
+# cacheManager.keySerializer = $cacheManagerKeySerializer
+```
+
+These 4 Serializers are replaceable:
+- cacheManager.keySerializer
+- cacheManager.valueSerializer
+- redisSessionDAO.keySerializer
+- redisSessionDAO.valueSerializer
+
+## Configurable Options
+
+### RedisManager
+
+| Title              | Default              | Description                 |
+| :------------------| :------------------- | :---------------------------|
+| host               | `127.0.0.1:6379`     | Redis host. If you don't specify host the default value is `127.0.0.1:6379`. If you run redis in sentinel mode or cluster mode, separate host names with comma, like `127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381` |
+| masterName         | `mymaster`           | **Only used for sentinel mode**<br>The master node of Redis sentinel mode |
+| timeout            | `2000`               | Redis connect timeout. Timeout for jedis try to connect to redis server(In milliseconds)  |
+| soTimeout          | `2000`               | **Only used for sentinel mode or cluster mode**<br>The timeout for jedis try to read data from redis server |
+| maxAttempts        | `3`                  | **Only used for cluster mode**<br>Max attempts to connect to server |
+| password           |                      | Redis password |
+| database           | `0`                  | Redis database. Default value is 0 |
+| jedisPoolConfig    | `new redis.clients.jedis.JedisPoolConfig()` | JedisPoolConfig. You can create your own JedisPoolConfig instance and set attributes as you wish<br>Most of time, you don't need to set jedisPoolConfig<br>Here is an example.<br>`jedisPoolConfig = redis.clients.jedis.JedisPoolConfig`<br>`jedisPoolConfig.testWhileIdle = false`<br>`redisManager.jedisPoolConfig = jedisPoolConfig` |
+| count              | `100`                |  Scan count. Shiro-redis use Scan to get keys, so you can define the number of elements returned at every iteration. |
+| jedisPool          | `null`               | **Only used for sentinel mode or single mode**<br>You can create your own JedisPool instance and set attributes as you wish |
+
+### RedisSessionDAO
+
+| Title              | Default              | Description                 |
+| :------------------| :------------------- | :---------------------------|
+| redisManager       |                      | RedisManager which you just configured above (Required) |
+| expire             | `-2`                 | Redis cache key/value expire time. The expire time is in second.<br>Special values:<br>`-1`: no expire<br>`-2`: the same timeout with session<br>Default value: `-2`<br>**Note**: Make sure expire time is longer than session timeout. |
+| keyPrefix          | `shiro:session:`     | Custom your redis key prefix for session management<br>**Note**: Remember to add colon at the end of prefix. |
+| sessionInMemoryTimeout | `1000`           | When we do signin, `doReadSession(sessionId)` will be called by shiro about 10 times. So shiro-redis save Session in ThreadLocal to remit this problem. sessionInMemoryTimeout is expiration of Session in ThreadLocal. <br>Most of time, you don't need to change it. |
+| sessionInMemoryEnabled | `true`           | Whether or not enable temporary save session in ThreadLocal      |
+| keySerializer        | `org.crazycake.shiro.serializer.StringSerializer` | The key serializer of cache manager<br>You can change the implement of key serializer or the encoding of StringSerializer.<br>Supported encodings refer to [Supported Encodings](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html). Such as `UTF-8`, `UTF-16`, `UTF-32`, `ISO-8859-1`, `GBK`, `Big5`, etc<br>For more detail, check [Serializer](#serializer) |
+| valueSerializer      | `org.crazycake.shiro.serializer.ObjectSerializer` | The value serializer of cache manager<br>You can change the implement of value serializer<br>For more detail, check [Serializer](#serializer) |
+
+### CacheManager
+
+| Title                | Default              | Description                 |
+| :--------------------| :------------------- | :---------------------------|
+| redisManager         |                      | RedisManager which you just configured above (Required) |
+| principalIdFieldName | `id`                 | Principal id field name. The field which you can get unique id to identify this principal.<br>For example, if you use UserInfo as Principal class, the id field maybe `id`, `userId`, `email`, etc.<br>Remember to add getter to this id field. For example, `getId()`, `getUserId(`), `getEmail()`, etc.<br>Default value is `id`, that means your principal object must has a method called `getId()` |
+| expire               | `1800`               | Redis cache key/value expire time. <br>The expire time is in second. |
+| keyPrefix            | `shiro:cache:`       | Custom your redis key prefix for cache management<br>**Note**: Remember to add colon at the end of prefix. |
+| keySerializer        | `org.crazycake.shiro.serializer.StringSerializer` | The key serializer of cache manager<br>You can change the implement of key serializer or the encoding of StringSerializer.<br>Supported encodings refer to [Supported Encodings](https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html). Such as `UTF-8`, `UTF-16`, `UTF-32`, `ISO-8859-1`, `GBK`, `Big5`, etc<br>For more detail, check [Serializer](#serializer) |
+| valueSerializer      | `org.crazycake.shiro.serializer.ObjectSerializer` | The value serializer of cache manager<br>You can change the implement of value serializer<br>For more detail, check [Serializer](#serializer) |
+
+# Spring boot starter
+
+Shiro-redis’s Spring-Boot integration is the easiest way to integrate Shiro-redis into a Spring-base application.
+
+> Note: `shiro-redis-spring-boot-starter` version `3.2.1` is based on `shiro-spring-boot-web-starter` version `1.4.0-RC2`
+
+First include the Shiro-redis Spring boot starter dependency in you application classpath
+
+```xml
+<dependency>
+    <groupId>org.crazycake</groupId>
+    <artifactId>shiro-redis-spring-boot-starter</artifactId>
+    <version>3.2.1</version>
+</dependency>
+```
+
+The next step depends on whether you've created your own `SessionManager` or `SessionsSecurityManager`.
+Because `shiro-redis-spring-boot-starter` will create `RedisSessionDAO` and `RedisCacheManager` for you. Then inject them into `SessionManager` and `SessionsSecurityManager` automatically.
+
+But if you've created your own `SessionManager` or `SessionsSecurityManager` as below:
+```java
+@Bean
+public SessionsSecurityManager securityManager(List<Realm> realms) {
+    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realms);
+    // other stuff
+    return securityManager;
+}
+```
+You will have to inject them by yourself. for more deail, see below
+
+## If you haven't created your own `SessionManager` or `SessionsSecurityManager`
+
+You are all set. Enjoy it!
+
+## If you have created your own `SessionManager` or `SessionsSecurityManager`
+
+Inject `redisSessionDAO` and `redisCacheManager` which created by `shiro-redis-spring-boot-starter` already
+```java
+@Autowired
+RedisSessionDAO redisSessionDAO;
+
+@Autowired
+RedisCacheManager redisCacheManager;
+```
+
+Inject them into `SessionManager` and `SessionsSecurityManager`
+
+```java
+@Bean
+public SessionManager sessionManager() {
+    DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
+
+    // inject redisSessionDAO
+    sessionManager.setSessionDAO(redisSessionDAO);
+    return sessionManager;
+}
+
+@Bean
+public SessionsSecurityManager securityManager(List<Realm> realms, SessionManager sessionManager) {
+    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realms);
+
+    //inject sessionManager
+    securityManager.setSessionManager(sessionManager);
+
+    // inject redisCacheManager
+    securityManager.setCacheManager(redisCacheManager);
+    return securityManager;
+}
+```
+
+For full example, see [shiro-redis-spring-boot-tutorial](https://github.com/alexxiyang/shiro-redis-spring-boot-tutorial)
+
+### Configuration Properties
+
+| Title                                              | Default              | Description                 |
+| :--------------------------------------------------| :------------------- | :---------------------------|
+| shiro-redis.enabled                                | `true`               | Enables shiro-redis’s Spring module |
+| shiro-redis.redis-manager.deploy-mode               | `standalone`         | Redis deploy mode. Options: `standalone`, `sentinel`, 'cluster' |
+| shiro-redis.redis-manager.host                      | `127.0.0.1:6379`     | Redis host. If you don't specify host the default value is `127.0.0.1:6379`. If you run redis in sentinel mode or cluster mode, separate host names with comma, like `127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381` |
+| shiro-redis.redis-manager.master-name               | `mymaster`           | **Only used for sentinel mode**<br>The master node of Redis sentinel mode |
+| shiro-redis.redis-manager.timeout                   | `2000`               | Redis connect timeout. Timeout for jedis try to connect to redis server(In milliseconds)  |
+| shiro-redis.redis-manager.so-timeout                | `2000`               | **Only used for sentinel mode or cluster mode**<br>The timeout for jedis try to read data from redis server |
+| shiro-redis.redis-manager.max-attempts              | `3`                  | **Only used for cluster mode**<br>Max attempts to connect to server |
+| shiro-redis.redis-manager.password                  |                      | Redis password |
+| shiro-redis.redis-manager.database                  | `0`                  | Redis database. Default value is 0 |
+| shiro-redis.redis-manager.count                     | `100`                |  Scan count. Shiro-redis use Scan to get keys, so you can define the number of elements returned at every iteration. |
+| shiro-redis.session-dao.expire                     | `-2`                 | Redis cache key/value expire time. The expire time is in second.<br>Special values:<br>`-1`: no expire<br>`-2`: the same timeout with session<br>Default value: `-2`<br>**Note**: Make sure expire time is longer than session timeout. |
+| shiro-redis.session-dao.key-prefix                 | `shiro:session:`     | Custom your redis key prefix for session management<br>**Note**: Remember to add colon at the end of prefix. |
+| shiro-redis.session-dao.session-in-memory-timeout  | `1000`           | When we do signin, `doReadSession(sessionId)` will be called by shiro about 10 times. So shiro-redis save Session in ThreadLocal to remit this problem. sessionInMemoryTimeout is expiration of Session in ThreadLocal. <br>Most of time, you don't need to change it. |
+| shiro-redis.session-dao.session-in-memory-enabled  | `true`           | Whether or not enable temporary save session in ThreadLocal      |
+| shiro-redis.cache-manager.principal-id-field-name  | `id`                 | Principal id field name. The field which you can get unique id to identify this principal.<br>For example, if you use UserInfo as Principal class, the id field maybe `id`, `userId`, `email`, etc.<br>Remember to add getter to this id field. For example, `getId()`, `getUserId(`), `getEmail()`, etc.<br>Default value is `id`, that means your principal object must has a method called `getId()` |
+| shiro-redis.cache-manager.expire                   | `1800`               | Redis cache key/value expire time. <br>The expire time is in second. |
+| shiro-redis.cache-manager.key-prefix               | `shiro:cache:`       | Custom your redis key prefix for cache management<br>**Note**: Remember to add colon at the end of prefix. |
+
+
+## Working with `spring-boot-devtools`
+If you are using `shiro-redis` with `spring-boot-devtools`. Please add this line to `resources/META-INF/spring-devtools.properties` (Create it if there is no this file):
+```ini
+restart.include.shiro-redis=/shiro-[\\w-\\.]+jar
+```
+
+# If you found any bugs
+
+Please create the issue
+
+可以用中文

+ 2 - 0
shiro-redis/docs/_config.yml

@@ -0,0 +1,2 @@
+theme: jekyll-theme-merlot
+show_downloads: true

+ 214 - 0
shiro-redis/pom.xml

@@ -0,0 +1,214 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>org.crazycake</groupId>
+	<artifactId>shiro-redis</artifactId>
+	<version>3.2.3</version>
+	<packaging>jar</packaging>
+
+	<name>shiro-redis</name>
+	<description>shiro only provide the support of ehcache and concurrentHashMap. Here is an implement of redis cache can be used by shiro. Hope it will help you!</description>
+	<url>https://github.com/alexxiyang/shiro-redis</url>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<junit>4.11</junit>
+		<slf4j>1.7.5</slf4j>
+	</properties>
+
+	<licenses>
+		<license>
+			<name>The Apache Software License, Version 2.0</name>
+			<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+			<distribution>repo</distribution>
+		</license>
+	</licenses>
+
+	<dependencies>
+		<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
+		<dependency>
+			<groupId>redis.clients</groupId>
+			<artifactId>jedis</artifactId>
+			<version>2.9.0</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-api</artifactId>
+			<version>1.7.2</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.shiro</groupId>
+			<artifactId>shiro-core</artifactId>
+			<version>1.3.2</version>
+		</dependency>
+
+		<!-- Testing -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>4.11</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>1.7.7</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>commons-logging</groupId>
+			<artifactId>commons-logging</artifactId>
+			<version>1.1.2</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-all</artifactId>
+			<version>1.9.5</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.github.javafaker</groupId>
+			<artifactId>javafaker</artifactId>
+			<version>0.16</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<developers>
+		<developer>
+				<id>alexxiyang</id>
+			<name>Alex Yang</name>
+			<email>alexxiyang@gmail.com</email>
+			<timezone>GMT-7</timezone>
+			<organizationUrl>https://github.com/alexxiyang</organizationUrl>
+			<roles>
+			</roles>
+		</developer>
+	</developers>
+	<scm>
+		<connection>scm:git:https://github.com/alexxiyang/shiro-redis.git</connection>
+		<developerConnection>scm:git:https://github.com/alexxiyang/shiro-redis.git</developerConnection>
+		<url>https://github.com/alexxiyang/shiro-redis.git</url>
+	</scm>
+	<distributionManagement>
+		<snapshotRepository>
+			<id>ossrh</id>
+			<url>https://oss.sonatype.org/content/repositories/snapshots</url>
+		</snapshotRepository>
+		<repository>
+			<id>ossrh</id>
+			<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+		</repository>
+	</distributionManagement>
+	<build>
+		<finalName>shiro-redis</finalName>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.0.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+					<encoding>UTF-8</encoding>
+					<compilerArgument>-nowarn</compilerArgument>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-checkstyle-plugin</artifactId>
+				<version>2.9.1</version>
+				<executions>
+					<execution>
+						<id>checkstyle</id>
+						<phase>validate</phase>
+						<goals>
+							<goal>check</goal>
+						</goals>
+						<configuration>
+							<failOnViolation>true</failOnViolation>
+							<consoleOutput>true</consoleOutput>
+							<configLocation>checkstyle.xml</configLocation>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+	<profiles>
+		<profile>
+			<id>release-sign-artifacts</id>
+			<activation>
+				<property>
+					<name>release</name>
+					<value>true</value>
+				</property>
+			</activation>
+
+			<properties>
+				<gpg.keyname>D688E942</gpg.keyname>	<!-- GPG Key ID to use for signing -->
+				<release.username>alexxiyang</release.username>
+			</properties>
+
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.sonatype.plugins</groupId>
+						<artifactId>nexus-staging-maven-plugin</artifactId>
+						<version>1.6.7</version>
+						<extensions>true</extensions>
+						<configuration>
+							<serverId>ossrh</serverId>
+							<nexusUrl>https://oss.sonatype.org/</nexusUrl>
+							<autoReleaseAfterClose>true</autoReleaseAfterClose>
+						</configuration>
+					</plugin>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-source-plugin</artifactId>
+						<version>2.2.1</version>
+						<executions>
+							<execution>
+								<id>attach-sources</id>
+								<goals>
+									<goal>jar-no-fork</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-javadoc-plugin</artifactId>
+						<version>2.9.1</version>
+						<executions>
+							<execution>
+								<id>attach-javadocs</id>
+								<goals>
+									<goal>jar</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-gpg-plugin</artifactId>
+						<version>1.6</version>
+						<executions>
+							<execution>
+								<id>sign-artifacts</id>
+								<phase>verify</phase>
+								<goals>
+									<goal>sign</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+</project>

BIN
shiro-redis/src/.DS_Store


+ 48 - 0
shiro-redis/src/main/java/org/crazycake/shiro/IRedisManager.java

@@ -0,0 +1,48 @@
+package org.crazycake.shiro;
+
+import java.util.Set;
+
+/**
+ * redisManager interface
+ *
+ **/
+
+public interface IRedisManager {
+
+    /**
+     * get value from redis
+     * @param key key
+     * @return value
+     */
+    byte[] get(byte[] key);
+
+    /**
+     * set value
+     * @param key  key
+     * @param value value
+     * @param expire expire
+     * @return value
+     */
+    byte[] set(byte[] key, byte[] value, int expire);
+
+    /**
+     * del
+     * @param key key
+     */
+    void del(byte[] key);
+
+    /**
+     * dbsize
+     * @param pattern pattern
+     * @return key-value size
+     */
+    Long dbSize(byte[] pattern);
+
+    /**
+     * keys
+     * @param pattern key pattern
+     * @return key set
+     */
+    Set<byte[]> keys(byte[] pattern);
+
+}

+ 289 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisCache.java

@@ -0,0 +1,289 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.util.CollectionUtils;
+import org.crazycake.shiro.exception.CacheManagerPrincipalIdNotAssignedException;
+import org.crazycake.shiro.exception.PrincipalIdNullException;
+import org.crazycake.shiro.exception.PrincipalInstanceException;
+import org.crazycake.shiro.exception.SerializationException;
+import org.crazycake.shiro.serializer.ObjectSerializer;
+import org.crazycake.shiro.serializer.RedisSerializer;
+import org.crazycake.shiro.serializer.StringSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+public class RedisCache<K, V> implements Cache<K, V> {
+
+	private static Logger logger = LoggerFactory.getLogger(RedisCache.class);
+
+	private RedisSerializer keySerializer = new StringSerializer();
+	private RedisSerializer valueSerializer = new ObjectSerializer();
+	private IRedisManager redisManager;
+	private String keyPrefix = RedisCacheManager.DEFAULT_CACHE_KEY_PREFIX;
+	private int expire = RedisCacheManager.DEFAULT_EXPIRE;
+	private String principalIdFieldName = RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME;
+
+	/**
+	 *
+	 * @param redisManager redisManager
+	 * @param keySerializer keySerializer
+	 * @param valueSerializer valueSerializer
+	 * @param prefix authorization prefix
+	 * @param expire expire
+	 * @param principalIdFieldName id field name of principal object
+	 */
+	public RedisCache(IRedisManager redisManager, RedisSerializer keySerializer, RedisSerializer valueSerializer, String prefix, int expire, String principalIdFieldName) {
+		 if (redisManager == null) {
+	         throw new IllegalArgumentException("redisManager cannot be null.");
+	     }
+	     this.redisManager = redisManager;
+		 if (keySerializer == null) {
+			 throw new IllegalArgumentException("keySerializer cannot be null.");
+		 }
+		 this.keySerializer = keySerializer;
+		if (valueSerializer == null) {
+			throw new IllegalArgumentException("valueSerializer cannot be null.");
+		}
+		 this.valueSerializer = valueSerializer;
+		 if (prefix != null && !"".equals(prefix)) {
+			 this.keyPrefix = prefix;
+		 }
+         this.expire = expire;
+		 if (principalIdFieldName != null) {
+			 this.principalIdFieldName = principalIdFieldName;
+		 }
+	}
+
+	/**
+	 * get shiro authorization redis key-value
+	 * @param key key
+	 * @return value
+	 * @throws CacheException get cache exception
+	 */
+	@Override
+	public V get(K key) throws CacheException {
+		logger.debug("get key [" + key + "]");
+
+		if (key == null) {
+			return null;
+		}
+
+		try {
+			Object redisCacheKey = getRedisCacheKey(key);
+			byte[] rawValue = redisManager.get(keySerializer.serialize(redisCacheKey));
+			if (rawValue == null) {
+				return null;
+			}
+			V value = (V) valueSerializer.deserialize(rawValue);
+			return value;
+		} catch (SerializationException e) {
+			throw new CacheException(e);
+		}
+	}
+
+	@Override
+	public V put(K key, V value) throws CacheException {
+		if (key == null) {
+			logger.warn("Saving a null key is meaningless, return value directly without call Redis.");
+			return value;
+		}
+		try {
+			Object redisCacheKey = getRedisCacheKey(key);
+			logger.debug("put key [" + redisCacheKey + "]");
+			redisManager.set(keySerializer.serialize(redisCacheKey), value != null ? valueSerializer.serialize(value) : null, expire);
+			return value;
+		} catch (SerializationException e) {
+			throw new CacheException(e);
+		}
+	}
+
+	@Override
+	public V remove(K key) throws CacheException {
+		logger.debug("remove key [" + key + "]");
+        if (key == null) {
+            return null;
+        }
+		try {
+            Object redisCacheKey = getRedisCacheKey(key);
+            byte[] rawValue = redisManager.get(keySerializer.serialize(redisCacheKey));
+            V previous = (V) valueSerializer.deserialize(rawValue);
+            redisManager.del(keySerializer.serialize(redisCacheKey));
+            return previous;
+        } catch (SerializationException e) {
+            throw new CacheException(e);
+        }
+	}
+
+	private Object getRedisCacheKey(K key) {
+		if (key == null) {
+			return null;
+		}
+		if (keySerializer instanceof StringSerializer) {
+			return this.keyPrefix + getStringRedisKey(key);
+		}
+		return key;
+	}
+
+	private String getStringRedisKey(K key) {
+		String redisKey;
+		if (key instanceof PrincipalCollection) {
+			redisKey = getRedisKeyFromPrincipalIdField((PrincipalCollection) key);
+        } else {
+			redisKey = key.toString();
+		}
+		return redisKey;
+	}
+
+	private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
+		Object principalObject = key.getPrimaryPrincipal();
+		if (principalObject instanceof String) {
+		    return principalObject.toString();
+		}
+		Method pincipalIdGetter = getPrincipalIdGetter(principalObject);
+		return getIdObj(principalObject, pincipalIdGetter);
+	}
+
+	private String getIdObj(Object principalObject, Method pincipalIdGetter) {
+		String redisKey;
+		try {
+		    Object idObj = pincipalIdGetter.invoke(principalObject);
+		    if (idObj == null) {
+		        throw new PrincipalIdNullException(principalObject.getClass(), this.principalIdFieldName);
+            }
+			redisKey = idObj.toString();
+		} catch (IllegalAccessException e) {
+			throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
+		} catch (InvocationTargetException e) {
+			throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
+		}
+		return redisKey;
+	}
+
+	private Method getPrincipalIdGetter(Object principalObject) {
+		Method pincipalIdGetter = null;
+		String principalIdMethodName = this.getPrincipalIdMethodName();
+		try {
+			pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
+		} catch (NoSuchMethodException e) {
+			throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName);
+		}
+		return pincipalIdGetter;
+	}
+
+	private String getPrincipalIdMethodName() {
+		if (this.principalIdFieldName == null || "".equals(this.principalIdFieldName)) {
+			throw new CacheManagerPrincipalIdNotAssignedException();
+		}
+		return "get" + this.principalIdFieldName.substring(0, 1).toUpperCase() + this.principalIdFieldName.substring(1);
+	}
+
+
+	@Override
+	public void clear() throws CacheException {
+		logger.debug("clear cache");
+        Set<byte[]> keys = null;
+        try {
+            keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
+        } catch (SerializationException e) {
+            logger.error("get keys error", e);
+        }
+        if (keys == null || keys.size() == 0) {
+            return;
+        }
+        for (byte[] key: keys) {
+            redisManager.del(key);
+        }
+	}
+
+	/**
+	 * get all authorization key-value quantity
+	 * @return key-value size
+	 */
+	@Override
+	public int size() {
+		Long longSize = 0L;
+		try {
+			longSize = new Long(redisManager.dbSize(keySerializer.serialize(this.keyPrefix + "*")));
+		} catch (SerializationException e) {
+			logger.error("get keys error", e);
+		}
+		return longSize.intValue();
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public Set<K> keys() {
+		Set<byte[]> keys = null;
+		try {
+			keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
+		} catch (SerializationException e) {
+			logger.error("get keys error", e);
+			return Collections.emptySet();
+		}
+
+		if (CollectionUtils.isEmpty(keys)) {
+			return Collections.emptySet();
+		}
+
+		Set<K> convertedKeys = new HashSet<K>();
+		for (byte[] key:keys) {
+			try {
+				convertedKeys.add((K) keySerializer.deserialize(key));
+			} catch (SerializationException e) {
+				logger.error("deserialize keys error", e);
+			}
+		}
+		return convertedKeys;
+	}
+
+	@Override
+	public Collection<V> values() {
+		Set<byte[]> keys = null;
+		try {
+			keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
+		} catch (SerializationException e) {
+			logger.error("get values error", e);
+			return Collections.emptySet();
+		}
+
+		if (CollectionUtils.isEmpty(keys)) {
+			return Collections.emptySet();
+		}
+
+		List<V> values = new ArrayList<V>(keys.size());
+		for (byte[] key : keys) {
+			V value = null;
+			try {
+				value = (V) valueSerializer.deserialize(redisManager.get(key));
+			} catch (SerializationException e) {
+				logger.error("deserialize values= error", e);
+			}
+			if (value != null) {
+				values.add(value);
+			}
+		}
+		return Collections.unmodifiableList(values);
+	}
+
+	public String getKeyPrefix() {
+		return keyPrefix;
+	}
+
+	public void setKeyPrefix(String keyPrefix) {
+		this.keyPrefix = keyPrefix;
+	}
+
+	public String getPrincipalIdFieldName() {
+		return principalIdFieldName;
+	}
+
+	public void setPrincipalIdFieldName(String principalIdFieldName) {
+		this.principalIdFieldName = principalIdFieldName;
+	}
+}

+ 99 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisCacheManager.java

@@ -0,0 +1,99 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.CacheManager;
+import org.crazycake.shiro.serializer.ObjectSerializer;
+import org.crazycake.shiro.serializer.RedisSerializer;
+import org.crazycake.shiro.serializer.StringSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class RedisCacheManager implements CacheManager {
+
+	private final Logger logger = LoggerFactory.getLogger(RedisCacheManager.class);
+
+	// fast lookup by name map
+	private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
+	private RedisSerializer keySerializer = new StringSerializer();
+	private RedisSerializer valueSerializer = new ObjectSerializer();
+
+	private IRedisManager redisManager;
+
+	// expire time in seconds
+	public static final int DEFAULT_EXPIRE = 1800;
+	private int expire = DEFAULT_EXPIRE;
+
+	/**
+	 * The Redis key prefix for caches
+	 */
+	public static final String DEFAULT_CACHE_KEY_PREFIX = "shiro:cache:";
+	private String keyPrefix = DEFAULT_CACHE_KEY_PREFIX;
+
+	public static final String DEFAULT_PRINCIPAL_ID_FIELD_NAME = "id";
+	private String principalIdFieldName = DEFAULT_PRINCIPAL_ID_FIELD_NAME;
+
+	@Override
+	public <K, V> Cache<K, V> getCache(String name) throws CacheException {
+		logger.debug("get cache, name=" + name);
+
+		Cache cache = caches.get(name);
+
+		if (cache == null) {
+			cache = new RedisCache<K, V>(redisManager, keySerializer, valueSerializer, keyPrefix + name + ":", expire, principalIdFieldName);
+			caches.put(name, cache);
+		}
+		return cache;
+	}
+
+	public IRedisManager getRedisManager() {
+		return redisManager;
+	}
+
+	public void setRedisManager(IRedisManager redisManager) {
+		this.redisManager = redisManager;
+	}
+
+	public String getKeyPrefix() {
+		return keyPrefix;
+	}
+
+	public void setKeyPrefix(String keyPrefix) {
+		this.keyPrefix = keyPrefix;
+	}
+
+	public RedisSerializer getKeySerializer() {
+		return keySerializer;
+	}
+
+	public void setKeySerializer(RedisSerializer keySerializer) {
+		this.keySerializer = keySerializer;
+	}
+
+	public RedisSerializer getValueSerializer() {
+		return valueSerializer;
+	}
+
+	public void setValueSerializer(RedisSerializer valueSerializer) {
+		this.valueSerializer = valueSerializer;
+	}
+
+	public int getExpire() {
+		return expire;
+	}
+
+	public void setExpire(int expire) {
+		this.expire = expire;
+	}
+
+	public String getPrincipalIdFieldName() {
+		return principalIdFieldName;
+	}
+
+	public void setPrincipalIdFieldName(String principalIdFieldName) {
+		this.principalIdFieldName = principalIdFieldName;
+	}
+}

+ 234 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisClusterManager.java

@@ -0,0 +1,234 @@
+package org.crazycake.shiro;
+
+import redis.clients.jedis.*;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class RedisClusterManager implements IRedisManager {
+
+    private static final int DEFAULT_COUNT = 100;
+    private static final int DEFAULT_MAX_ATTEMPTS = 3;
+    private static final String DEFAULT_HOST = "127.0.0.1:7000,127.0.0.1:7001,127.0.0.1:7002";
+    private String host = DEFAULT_HOST;
+
+    // timeout for jedis try to connect to redis server, not expire time! In milliseconds
+    private int timeout = Protocol.DEFAULT_TIMEOUT;
+
+    // timeout for jedis try to read data from redis server
+    private int soTimeout = Protocol.DEFAULT_TIMEOUT;
+
+    private String password;
+
+    private int database = Protocol.DEFAULT_DATABASE;
+
+    private int count = DEFAULT_COUNT;
+
+    private int maxAttempts = DEFAULT_MAX_ATTEMPTS;
+
+    /**
+     * JedisPoolConfig used to initialize JedisPool.
+     */
+    private JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+
+    private volatile JedisCluster jedisCluster = null;
+
+    private void init() {
+        synchronized (this) {
+            if (jedisCluster == null) {
+                jedisCluster = new JedisCluster(getHostAndPortSet(), timeout, soTimeout, maxAttempts, password, getJedisPoolConfig());
+            }
+        }
+    }
+
+    private Set<HostAndPort> getHostAndPortSet() {
+        String[] hostAndPortArr = host.split(",");
+        Set<HostAndPort> hostAndPorts = new HashSet<HostAndPort>();
+        for (String hostAndPortStr : hostAndPortArr) {
+            String[] hostAndPort = hostAndPortStr.split(":");
+            hostAndPorts.add(new HostAndPort(hostAndPort[0], Integer.parseInt(hostAndPort[1])));
+        }
+        return hostAndPorts;
+    }
+
+
+    protected JedisCluster getJedisCluster() {
+        if (jedisCluster == null) {
+            init();
+        }
+        return jedisCluster;
+    }
+
+    @Override
+    public byte[] get(byte[] key) {
+        if (key == null) {
+            return null;
+        }
+        return getJedisCluster().get(key);
+    }
+
+    @Override
+    public byte[] set(byte[] key, byte[] value, int expireTime) {
+        if (key == null) {
+            return null;
+        }
+        getJedisCluster().set(key, value);
+        if (expireTime >= 0) {
+            getJedisCluster().expire(key, expireTime);
+        }
+        return value;
+    }
+
+    @Override
+    public void del(byte[] key) {
+        if (key == null) {
+            return;
+        }
+        getJedisCluster().del(key);
+    }
+
+    @Override
+    public Long dbSize(byte[] pattern) {
+        Long dbSize = 0L;
+        Map<String, JedisPool> clusterNodes = getJedisCluster().getClusterNodes();
+        Iterator<Map.Entry<String, JedisPool>> nodeIt = clusterNodes.entrySet().iterator();
+        while (nodeIt.hasNext()) {
+            Map.Entry<String, JedisPool> node = nodeIt.next();
+            long nodeDbSize = getDbSizeFromClusterNode(node.getValue(), pattern);
+            if (nodeDbSize == 0L) {
+                continue;
+            }
+            dbSize += nodeDbSize;
+        }
+        return dbSize;
+    }
+
+    @Override
+    public Set<byte[]> keys(byte[] pattern) {
+        Set<byte[]> keys = new HashSet<byte[]>();
+        Map<String, JedisPool> clusterNodes = getJedisCluster().getClusterNodes();
+        Iterator<Map.Entry<String, JedisPool>> nodeIt = clusterNodes.entrySet().iterator();
+        while (nodeIt.hasNext()) {
+            Map.Entry<String, JedisPool> node = nodeIt.next();
+            Set<byte[]> nodeKeys = getKeysFromClusterNode(node.getValue(), pattern);
+            if (nodeKeys == null || nodeKeys.size() == 0) {
+                continue;
+            }
+            keys.addAll(nodeKeys);
+        }
+
+        return keys;
+    }
+
+    private Set<byte[]> getKeysFromClusterNode(JedisPool jedisPool, byte[] pattern) {
+        Set<byte[]> keys = new HashSet<byte[]>();
+        Jedis jedis = jedisPool.getResource();
+
+        try {
+            ScanParams params = new ScanParams();
+            params.count(count);
+            params.match(pattern);
+            byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
+            ScanResult<byte[]> scanResult;
+            do {
+                scanResult = jedis.scan(cursor, params);
+                keys.addAll(scanResult.getResult());
+                cursor = scanResult.getCursorAsBytes();
+            } while (scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
+        } finally {
+            jedis.close();
+        }
+        return keys;
+    }
+
+    private long getDbSizeFromClusterNode(JedisPool jedisPool, byte[] pattern) {
+        long dbSize = 0L;
+        Jedis jedis = jedisPool.getResource();
+
+        try {
+            ScanParams params = new ScanParams();
+            params.count(count);
+            params.match(pattern);
+            byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
+            ScanResult<byte[]> scanResult;
+            do {
+                scanResult = jedis.scan(cursor, params);
+                dbSize++;
+                cursor = scanResult.getCursorAsBytes();
+            } while (scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
+        } finally {
+            jedis.close();
+        }
+        return dbSize;
+    }
+
+    public int getMaxAttempts() {
+        return maxAttempts;
+    }
+
+    public void setMaxAttempts(int maxAttempts) {
+        this.maxAttempts = maxAttempts;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    public int getSoTimeout() {
+        return soTimeout;
+    }
+
+    public void setSoTimeout(int soTimeout) {
+        this.soTimeout = soTimeout;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public int getDatabase() {
+        return database;
+    }
+
+    public void setDatabase(int database) {
+        this.database = database;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    public void setJedisCluster(JedisCluster jedisCluster) {
+        this.jedisCluster = jedisCluster;
+    }
+
+    public JedisPoolConfig getJedisPoolConfig() {
+        return jedisPoolConfig;
+    }
+
+    public void setJedisPoolConfig(JedisPoolConfig jedisPoolConfig) {
+        this.jedisPoolConfig = jedisPoolConfig;
+    }
+}

+ 77 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisManager.java

@@ -0,0 +1,77 @@
+package org.crazycake.shiro;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+import redis.clients.jedis.Protocol;
+
+public class RedisManager extends WorkAloneRedisManager implements IRedisManager {
+
+	private static final String DEFAULT_HOST = "127.0.0.1:6379";
+	private String host = DEFAULT_HOST;
+
+	// timeout for jedis try to connect to redis server, not expire time! In milliseconds
+	private int timeout = Protocol.DEFAULT_TIMEOUT;
+
+	private String password;
+
+	private int database = Protocol.DEFAULT_DATABASE;
+
+	private JedisPool jedisPool;
+
+	private void init() {
+		synchronized (this) {
+			if (jedisPool == null) {
+				String[] hostAndPort = host.split(":");
+				jedisPool = new JedisPool(getJedisPoolConfig(), hostAndPort[0], Integer.parseInt(hostAndPort[1]), timeout, password, database);
+			}
+		}
+	}
+
+	@Override
+	protected Jedis getJedis() {
+		if (jedisPool == null) {
+			init();
+		}
+		return jedisPool.getResource();
+	}
+
+	public String getHost() {
+		return host;
+	}
+
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	public int getTimeout() {
+		return timeout;
+	}
+
+	public void setTimeout(int timeout) {
+		this.timeout = timeout;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public int getDatabase() {
+		return database;
+	}
+
+	public void setDatabase(int database) {
+		this.database = database;
+	}
+
+	public JedisPool getJedisPool() {
+		return jedisPool;
+	}
+
+	public void setJedisPool(JedisPool jedisPool) {
+		this.jedisPool = jedisPool;
+	}
+}

+ 105 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisSentinelManager.java

@@ -0,0 +1,105 @@
+package org.crazycake.shiro;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisSentinelPool;
+import redis.clients.jedis.Protocol;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class RedisSentinelManager extends WorkAloneRedisManager implements IRedisManager {
+
+	private static final String DEFAULT_HOST = "127.0.0.1:26379,127.0.0.1:26380,127.0.0.1:26381";
+	private String host = DEFAULT_HOST;
+
+	private static final String DEFAULT_MASTER_NAME = "mymaster";
+	private String masterName = DEFAULT_MASTER_NAME;
+
+	// timeout for jedis try to connect to redis server, not expire time! In milliseconds
+	private int timeout = Protocol.DEFAULT_TIMEOUT;
+
+	// timeout for jedis try to read data from redis server
+	private int soTimeout = Protocol.DEFAULT_TIMEOUT;
+
+	private String password;
+
+	private int database = Protocol.DEFAULT_DATABASE;
+
+	private JedisSentinelPool jedisPool;
+
+	@Override
+	protected Jedis getJedis() {
+		if (jedisPool == null) {
+			init();
+		}
+		return jedisPool.getResource();
+	}
+
+	private void init() {
+		synchronized (this) {
+			if (jedisPool == null) {
+				String[] sentinelHosts = host.split(",\\s*");
+				Set<String> sentinels = new HashSet<String>();
+				Collections.addAll(sentinels, sentinelHosts);
+				jedisPool = new JedisSentinelPool(masterName, sentinels, getJedisPoolConfig(), timeout, soTimeout, password, database);
+			}
+		}
+	}
+
+	public String getHost() {
+		return host;
+	}
+
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	public int getTimeout() {
+		return timeout;
+	}
+
+	public void setTimeout(int timeout) {
+		this.timeout = timeout;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public int getDatabase() {
+		return database;
+	}
+
+	public void setDatabase(int database) {
+		this.database = database;
+	}
+
+	public String getMasterName() {
+		return masterName;
+	}
+
+	public void setMasterName(String masterName) {
+		this.masterName = masterName;
+	}
+
+	public int getSoTimeout() {
+		return soTimeout;
+	}
+
+	public void setSoTimeout(int soTimeout) {
+		this.soTimeout = soTimeout;
+	}
+
+	public JedisSentinelPool getJedisPool() {
+		return jedisPool;
+	}
+
+	public void setJedisPool(JedisSentinelPool jedisPool) {
+		this.jedisPool = jedisPool;
+	}
+}

+ 282 - 0
shiro-redis/src/main/java/org/crazycake/shiro/RedisSessionDAO.java

@@ -0,0 +1,282 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
+import org.crazycake.shiro.exception.SerializationException;
+import org.crazycake.shiro.serializer.ObjectSerializer;
+import org.crazycake.shiro.serializer.RedisSerializer;
+import org.crazycake.shiro.serializer.StringSerializer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Serializable;
+import java.util.*;
+
+public class RedisSessionDAO extends AbstractSessionDAO {
+
+	private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
+
+	private static final String DEFAULT_SESSION_KEY_PREFIX = "shiro:session:";
+	private String keyPrefix = DEFAULT_SESSION_KEY_PREFIX;
+
+	private static final long DEFAULT_SESSION_IN_MEMORY_TIMEOUT = 1000L;
+	/**
+	 * doReadSession be called about 10 times when login.
+	 * Save Session in ThreadLocal to resolve this problem. sessionInMemoryTimeout is expiration of Session in ThreadLocal.
+	 * The default value is 1000 milliseconds (1s).
+	 * Most of time, you don't need to change it.
+	 */
+	private long sessionInMemoryTimeout = DEFAULT_SESSION_IN_MEMORY_TIMEOUT;
+
+	private static final boolean DEFAULT_SESSION_IN_MEMORY_ENABLED = true;
+
+	private boolean sessionInMemoryEnabled = DEFAULT_SESSION_IN_MEMORY_ENABLED;
+
+	// expire time in seconds
+	private static final int DEFAULT_EXPIRE = -2;
+	private static final int NO_EXPIRE = -1;
+
+	/**
+	 * Please make sure expire is longer than sesion.getTimeout()
+	 */
+	private int expire = DEFAULT_EXPIRE;
+
+	private static final int MILLISECONDS_IN_A_SECOND = 1000;
+
+	private IRedisManager redisManager;
+	private RedisSerializer keySerializer = new StringSerializer();
+	private RedisSerializer valueSerializer = new ObjectSerializer();
+	private static ThreadLocal sessionsInThread = new ThreadLocal();
+	
+	@Override
+	public void update(Session session) throws UnknownSessionException {
+		this.saveSession(session);
+		if (this.sessionInMemoryEnabled) {
+			this.setSessionToThreadLocal(session.getId(), session);
+		}
+	}
+	
+	/**
+	 * save session
+	 * @param session
+	 * @throws UnknownSessionException
+	 */
+	private void saveSession(Session session) throws UnknownSessionException {
+		if (session == null || session.getId() == null) {
+			logger.error("session or session id is null");
+			throw new UnknownSessionException("session or session id is null");
+		}
+		byte[] key;
+		byte[] value;
+		try {
+			key = keySerializer.serialize(getRedisSessionKey(session.getId()));
+			value = valueSerializer.serialize(session);
+		} catch (SerializationException e) {
+			logger.error("serialize session error. session id=" + session.getId());
+			throw new UnknownSessionException(e);
+		}
+		if (expire == DEFAULT_EXPIRE) {
+			this.redisManager.set(key, value, (int) (session.getTimeout() / MILLISECONDS_IN_A_SECOND));
+			return;
+		}
+		if (expire != NO_EXPIRE && expire * MILLISECONDS_IN_A_SECOND < session.getTimeout()) {
+			logger.warn("Redis session expire time: "
+					+ (expire * MILLISECONDS_IN_A_SECOND)
+					+ " is less than Session timeout: "
+					+ session.getTimeout()
+					+ " . It may cause some problems.");
+		}
+		this.redisManager.set(key, value, expire);
+	}
+
+	@Override
+	public void delete(Session session) {
+		if (session == null || session.getId() == null) {
+			logger.error("session or session id is null");
+			return;
+		}
+		try {
+			redisManager.del(keySerializer.serialize(getRedisSessionKey(session.getId())));
+		} catch (SerializationException e) {
+			logger.error("delete session error. session id=" + session.getId());
+		}
+	}
+
+	@Override
+	public Collection<Session> getActiveSessions() {
+		Set<Session> sessions = new HashSet<Session>();
+		try {
+			Set<byte[]> keys = redisManager.keys(this.keySerializer.serialize(this.keyPrefix + "*"));
+			if (keys != null && keys.size() > 0) {
+				for (byte[] key:keys) {
+					Session s = (Session) valueSerializer.deserialize(redisManager.get(key));
+					sessions.add(s);
+				}
+			}
+		} catch (SerializationException e) {
+			logger.error("get active sessions error.");
+		}
+		return sessions;
+	}
+
+	@Override
+	protected Serializable doCreate(Session session) {
+		if (session == null) {
+			logger.error("session is null");
+			throw new UnknownSessionException("session is null");
+		}
+		Serializable sessionId = this.generateSessionId(session);  
+        this.assignSessionId(session, sessionId);
+        this.saveSession(session);
+		return sessionId;
+	}
+
+	@Override
+	protected Session doReadSession(Serializable sessionId) {
+		if (sessionId == null) {
+			logger.warn("session id is null");
+			return null;
+		}
+
+		if (this.sessionInMemoryEnabled) {
+			Session session = getSessionFromThreadLocal(sessionId);
+			if (session != null) {
+				return session;
+			}
+		}
+
+		Session session = null;
+		logger.debug("read session from redis");
+		try {
+			session = (Session) valueSerializer.deserialize(redisManager.get(keySerializer.serialize(getRedisSessionKey(sessionId))));
+			if (this.sessionInMemoryEnabled) {
+				setSessionToThreadLocal(sessionId, session);
+			}
+		} catch (SerializationException e) {
+			logger.error("read session error. settionId=" + sessionId);
+		}
+		return session;
+	}
+
+	private void setSessionToThreadLocal(Serializable sessionId, Session s) {
+		Map<Serializable, SessionInMemory> sessionMap = (Map<Serializable, SessionInMemory>) sessionsInThread.get();
+		if (sessionMap == null) {
+            sessionMap = new HashMap<Serializable, SessionInMemory>();
+            sessionsInThread.set(sessionMap);
+        }
+
+		removeExpiredSessionInMemory(sessionMap);
+
+		SessionInMemory sessionInMemory = new SessionInMemory();
+		sessionInMemory.setCreateTime(new Date());
+		sessionInMemory.setSession(s);
+		sessionMap.put(sessionId, sessionInMemory);
+	}
+
+	private void removeExpiredSessionInMemory(Map<Serializable, SessionInMemory> sessionMap) {
+		Iterator<Serializable> it = sessionMap.keySet().iterator();
+		while (it.hasNext()) {
+			Serializable sessionId = it.next();
+			SessionInMemory sessionInMemory = sessionMap.get(sessionId);
+			if (sessionInMemory == null) {
+				it.remove();
+				continue;
+			}
+			long liveTime = getSessionInMemoryLiveTime(sessionInMemory);
+			if (liveTime > sessionInMemoryTimeout) {
+				it.remove();
+			}
+		}
+	}
+
+	private Session getSessionFromThreadLocal(Serializable sessionId) {
+
+		if (sessionsInThread.get() == null) {
+			return null;
+		}
+
+		Map<Serializable, SessionInMemory> sessionMap = (Map<Serializable, SessionInMemory>) sessionsInThread.get();
+		SessionInMemory sessionInMemory = sessionMap.get(sessionId);
+		if (sessionInMemory == null) {
+			return null;
+		}
+		long liveTime = getSessionInMemoryLiveTime(sessionInMemory);
+		if (liveTime > sessionInMemoryTimeout) {
+			sessionMap.remove(sessionId);
+			return null;
+		}
+
+		logger.debug("read session from memory");
+		return sessionInMemory.getSession();
+	}
+
+	private long getSessionInMemoryLiveTime(SessionInMemory sessionInMemory) {
+		Date now = new Date();
+		return now.getTime() - sessionInMemory.getCreateTime().getTime();
+	}
+
+	private String getRedisSessionKey(Serializable sessionId) {
+		return this.keyPrefix + sessionId;
+	}
+
+	public IRedisManager getRedisManager() {
+		return redisManager;
+	}
+
+	public void setRedisManager(IRedisManager redisManager) {
+		this.redisManager = redisManager;
+	}
+
+	public String getKeyPrefix() {
+		return keyPrefix;
+	}
+
+	public void setKeyPrefix(String keyPrefix) {
+		this.keyPrefix = keyPrefix;
+	}
+
+	public RedisSerializer getKeySerializer() {
+		return keySerializer;
+	}
+
+	public void setKeySerializer(RedisSerializer keySerializer) {
+		this.keySerializer = keySerializer;
+	}
+
+	public RedisSerializer getValueSerializer() {
+		return valueSerializer;
+	}
+
+	public void setValueSerializer(RedisSerializer valueSerializer) {
+		this.valueSerializer = valueSerializer;
+	}
+
+	public long getSessionInMemoryTimeout() {
+		return sessionInMemoryTimeout;
+	}
+
+	public void setSessionInMemoryTimeout(long sessionInMemoryTimeout) {
+		this.sessionInMemoryTimeout = sessionInMemoryTimeout;
+	}
+
+	public int getExpire() {
+		return expire;
+	}
+
+	public void setExpire(int expire) {
+		this.expire = expire;
+	}
+
+	public boolean getSessionInMemoryEnabled() {
+		return sessionInMemoryEnabled;
+	}
+
+	public void setSessionInMemoryEnabled(boolean sessionInMemoryEnabled) {
+		this.sessionInMemoryEnabled = sessionInMemoryEnabled;
+	}
+
+	public static ThreadLocal getSessionsInThread() {
+		return sessionsInThread;
+	}
+}

+ 29 - 0
shiro-redis/src/main/java/org/crazycake/shiro/SessionInMemory.java

@@ -0,0 +1,29 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.session.Session;
+
+import java.util.Date;
+
+/**
+ * Use ThreadLocal as a temporary storage of Session, so that shiro wouldn't keep read redis several times while a request coming.
+ */
+public class SessionInMemory {
+    private Session session;
+    private Date createTime;
+
+    public Session getSession() {
+        return session;
+    }
+
+    public void setSession(Session session) {
+        this.session = session;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}

+ 172 - 0
shiro-redis/src/main/java/org/crazycake/shiro/WorkAloneRedisManager.java

@@ -0,0 +1,172 @@
+package org.crazycake.shiro;
+
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPoolConfig;
+import redis.clients.jedis.ScanParams;
+import redis.clients.jedis.ScanResult;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Abstract class of RedisManager.
+ */
+public abstract class WorkAloneRedisManager implements IRedisManager {
+
+    /**
+     * We are going to operate redis by acquiring Jedis object.
+     * The subclass should realizes the way to get Jedis objects by implement the getJedis().
+     * @return Jedis
+     */
+    protected abstract Jedis getJedis();
+
+    /**
+     * Default value of count.
+     */
+    protected static final int DEFAULT_COUNT = 100;
+
+    /**
+     * The number of elements returned at every iteration.
+     */
+    private int count = DEFAULT_COUNT;
+
+    /**
+     * JedisPoolConfig used to initialize JedisPool.
+     */
+    private JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
+
+    /**
+     * get value from redis
+     * @param key key
+     * @return value
+     */
+    @Override
+    public byte[] get(byte[] key) {
+        if (key == null) {
+            return null;
+        }
+        byte[] value = null;
+        Jedis jedis = getJedis();
+        try {
+            value = jedis.get(key);
+        } finally {
+            jedis.close();
+        }
+        return value;
+    }
+
+    /**
+     * set
+     * @param key key
+     * @param value value
+     * @param expireTime expire time
+     * @return value
+     */
+    @Override
+    public byte[] set(byte[] key, byte[] value, int expireTime) {
+        if (key == null) {
+            return null;
+        }
+        Jedis jedis = getJedis();
+        try {
+            jedis.set(key, value);
+            // -1 and 0 is not a valid expire time in Jedis
+            if (expireTime > 0) {
+                jedis.expire(key, expireTime);
+            }
+         } finally {
+            jedis.close();
+        }
+        return value;
+    }
+
+    /**
+     * Delete a key-value pair.
+     * @param key key
+     */
+    @Override
+    public void del(byte[] key) {
+        if (key == null) {
+            return;
+        }
+        Jedis jedis = getJedis();
+        try {
+            jedis.del(key);
+        } finally {
+            jedis.close();
+        }
+    }
+
+    /**
+     * Return the size of redis db.
+     * @param pattern key pattern
+     * @return key-value size
+     */
+    @Override
+    public Long dbSize(byte[] pattern) {
+        long dbSize = 0L;
+        Jedis jedis = getJedis();
+        try {
+            ScanParams params = new ScanParams();
+            params.count(count);
+            params.match(pattern);
+            byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
+            ScanResult<byte[]> scanResult;
+            do {
+                scanResult = jedis.scan(cursor, params);
+                List<byte[]> results = scanResult.getResult();
+                for (byte[] result : results) {
+                    dbSize++;
+                }
+                cursor = scanResult.getCursorAsBytes();
+            } while (scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
+        } finally {
+            jedis.close();
+        }
+        return dbSize;
+    }
+
+    /**
+     * Return all the keys of Redis db. Filtered by pattern.
+     * @param pattern key pattern
+     * @return key set
+     */
+    public Set<byte[]> keys(byte[] pattern) {
+        Set<byte[]> keys = new HashSet<byte[]>();
+        Jedis jedis = getJedis();
+
+        try {
+            ScanParams params = new ScanParams();
+            params.count(count);
+            params.match(pattern);
+            byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;
+            ScanResult<byte[]> scanResult;
+            do {
+                scanResult = jedis.scan(cursor, params);
+                keys.addAll(scanResult.getResult());
+                cursor = scanResult.getCursorAsBytes();
+            } while (scanResult.getStringCursor().compareTo(ScanParams.SCAN_POINTER_START) > 0);
+        } finally {
+            jedis.close();
+        }
+        return keys;
+
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+
+    public JedisPoolConfig getJedisPoolConfig() {
+        return jedisPoolConfig;
+    }
+
+    public void setJedisPoolConfig(JedisPoolConfig jedisPoolConfig) {
+        this.jedisPoolConfig = jedisPoolConfig;
+    }
+}

+ 10 - 0
shiro-redis/src/main/java/org/crazycake/shiro/exception/CacheManagerPrincipalIdNotAssignedException.java

@@ -0,0 +1,10 @@
+package org.crazycake.shiro.exception;
+
+public class CacheManagerPrincipalIdNotAssignedException extends RuntimeException  {
+
+    private static final String MESSAGE = "CacheManager didn't assign Principal Id field name!";
+
+    public CacheManagerPrincipalIdNotAssignedException() {
+        super(MESSAGE);
+    }
+}

+ 10 - 0
shiro-redis/src/main/java/org/crazycake/shiro/exception/PrincipalIdNullException.java

@@ -0,0 +1,10 @@
+package org.crazycake.shiro.exception;
+
+public class PrincipalIdNullException extends RuntimeException  {
+
+    private static final String MESSAGE = "Principal Id shouldn't be null!";
+
+    public PrincipalIdNullException(Class clazz, String idMethodName) {
+        super(clazz + " id field: " +  idMethodName + ", value is null\n" + MESSAGE);
+    }
+}

+ 18 - 0
shiro-redis/src/main/java/org/crazycake/shiro/exception/PrincipalInstanceException.java

@@ -0,0 +1,18 @@
+package org.crazycake.shiro.exception;
+
+public class PrincipalInstanceException extends RuntimeException  {
+
+    private static final String MESSAGE = "We need a field to identify this Cache Object in Redis. "
+            + "So you need to defined an id field which you can get unique id to identify this principal. "
+            + "For example, if you use UserInfo as Principal class, the id field maybe userId, userName, email, etc. "
+            + "For example, getUserId(), getUserName(), getEmail(), etc.\n"
+            + "Default value is \"id\", that means your principal object has a method called \"getId()\"";
+
+    public PrincipalInstanceException(Class clazz, String idMethodName) {
+        super(clazz + " must has getter for field: " +  idMethodName + "\n" + MESSAGE);
+    }
+
+    public PrincipalInstanceException(Class clazz, String idMethodName, Exception e) {
+        super(clazz + " must has getter for field: " +  idMethodName + "\n" + MESSAGE, e);
+    }
+}

+ 10 - 0
shiro-redis/src/main/java/org/crazycake/shiro/exception/SerializationException.java

@@ -0,0 +1,10 @@
+package org.crazycake.shiro.exception;
+
+public class SerializationException extends Exception {
+    public SerializationException(String msg) {
+        super(msg);
+    }
+    public SerializationException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}

+ 59 - 0
shiro-redis/src/main/java/org/crazycake/shiro/serializer/MultiClassLoaderObjectInputStream.java

@@ -0,0 +1,59 @@
+package org.crazycake.shiro.serializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * For fixing https://github.com/alexxiyang/shiro-redis/issues/84
+ */
+public class MultiClassLoaderObjectInputStream extends ObjectInputStream {
+	private static Logger logger = LoggerFactory.getLogger(MultiClassLoaderObjectInputStream.class);
+	
+	MultiClassLoaderObjectInputStream(InputStream str) throws IOException {
+		super(str);
+	}
+
+	/**
+	 * Try :
+	 * 1. thread class loader
+	 * 2. application class loader
+	 * 3. system class loader
+	 * @param desc
+	 * @return
+	 * @throws IOException
+	 * @throws ClassNotFoundException
+	 */
+	@Override
+	protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
+        String name = desc.getName();
+
+		try {
+			ClassLoader cl = Thread.currentThread().getContextClassLoader();
+			return Class.forName(name, false, cl);
+		} catch (Throwable ex) {
+			logger.debug("Cannot access thread context ClassLoader!", ex);
+		}
+		
+		try {
+			ClassLoader cl = MultiClassLoaderObjectInputStream.class.getClassLoader();
+			return Class.forName(name, false, cl);
+		} catch (Throwable ex) {
+			logger.debug("Cannot access application ClassLoader", ex);
+		}
+		
+		try {
+			ClassLoader cl = ClassLoader.getSystemClassLoader();
+			return Class.forName(name, false, cl);
+		} catch (Throwable ex) {
+			logger.debug("Cannot access system ClassLoader", ex);
+		}
+
+        return super.resolveClass(desc);
+    }
+
+}

+ 60 - 0
shiro-redis/src/main/java/org/crazycake/shiro/serializer/ObjectSerializer.java

@@ -0,0 +1,60 @@
+package org.crazycake.shiro.serializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.crazycake.shiro.exception.SerializationException;
+
+public class ObjectSerializer implements RedisSerializer<Object> {
+
+    public static final int BYTE_ARRAY_OUTPUT_STREAM_SIZE = 128;
+
+    @Override
+    public byte[] serialize(Object object) throws SerializationException {
+        byte[] result = new byte[0];
+
+        if (object == null) {
+            return result;
+        }
+        ByteArrayOutputStream byteStream = new ByteArrayOutputStream(BYTE_ARRAY_OUTPUT_STREAM_SIZE);
+        if (!(object instanceof Serializable)) {
+            throw new SerializationException("requires a Serializable payload "
+                    + "but received an object of type [" + object.getClass().getName() + "]");
+        }
+        try {
+            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteStream);
+            objectOutputStream.writeObject(object);
+            objectOutputStream.flush();
+            result =  byteStream.toByteArray();
+        } catch (IOException e) {
+            throw new SerializationException("serialize error, object=" + object, e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Object deserialize(byte[] bytes) throws SerializationException {
+        Object result = null;
+
+        if (bytes == null || bytes.length == 0) {
+            return result;
+        }
+
+        try {
+            ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+            ObjectInputStream objectInputStream = new MultiClassLoaderObjectInputStream(byteStream);
+            result = objectInputStream.readObject();
+        } catch (IOException e) {
+            throw new SerializationException("deserialize error", e);
+        } catch (ClassNotFoundException e) {
+            throw new SerializationException("deserialize error", e);
+        }
+
+        return result;
+    }
+}

+ 10 - 0
shiro-redis/src/main/java/org/crazycake/shiro/serializer/RedisSerializer.java

@@ -0,0 +1,10 @@
+package org.crazycake.shiro.serializer;
+
+import org.crazycake.shiro.exception.SerializationException;
+
+public interface RedisSerializer<T> {
+
+    byte[] serialize(T t) throws SerializationException;
+
+    T deserialize(byte[] bytes) throws SerializationException;
+}

+ 42 - 0
shiro-redis/src/main/java/org/crazycake/shiro/serializer/StringSerializer.java

@@ -0,0 +1,42 @@
+package org.crazycake.shiro.serializer;
+
+import org.crazycake.shiro.exception.SerializationException;
+
+import java.io.UnsupportedEncodingException;
+
+public class StringSerializer implements RedisSerializer<String> {
+
+    private static final String DEFAULT_CHARSET = "UTF-8";
+
+    /**
+     * Refer to https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html
+     * UTF-8, UTF-16, UTF-32, ISO-8859-1, GBK, Big5, etc
+     */
+    private String charset = DEFAULT_CHARSET;
+
+    @Override
+    public byte[] serialize(String s) throws SerializationException {
+        try {
+            return (s == null ? null : s.getBytes(charset));
+        } catch (UnsupportedEncodingException e) {
+            throw new SerializationException("serialize error, string=" + s, e);
+        }
+    }
+
+    @Override
+    public String deserialize(byte[] bytes) throws SerializationException {
+        try {
+            return (bytes == null ? null : new String(bytes, charset));
+        } catch (UnsupportedEncodingException e) {
+            throw new SerializationException("deserialize error", e);
+        }
+    }
+
+    public String getCharset() {
+        return charset;
+    }
+
+    public void setCharset(String charset) {
+        this.charset = charset;
+    }
+}

+ 256 - 0
shiro-redis/src/test/java/fixture/TestFixture.java

@@ -0,0 +1,256 @@
+package fixture;
+
+import com.github.javafaker.Faker;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.crazycake.shiro.RedisCache;
+import org.crazycake.shiro.RedisManager;
+import org.crazycake.shiro.RedisSessionDAO;
+import org.crazycake.shiro.exception.SerializationException;
+import org.crazycake.shiro.model.FakeAuth;
+import org.crazycake.shiro.model.FakeSession;
+import org.crazycake.shiro.model.UserInfo;
+import org.crazycake.shiro.serializer.RedisSerializer;
+import org.junit.Assert;
+import redis.clients.jedis.Jedis;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+public class TestFixture {
+
+    private static Properties properties = loadProperties("shiro-standalone.ini");
+    private static Faker faker = new Faker();
+
+    //  /$$       /$$                       /$$
+    // | $$      | $$                      | $$
+    // | $$$$$$$ | $$  /$$$$$$   /$$$$$$$ /$$$$$$
+    // | $$__  $$| $$ |____  $$ /$$_____/|_  $$_/
+    // | $$  \ $$| $$  /$$$$$$$|  $$$$$$   | $$
+    // | $$  | $$| $$ /$$__  $$ \____  $$  | $$ /$$
+    // | $$$$$$$/| $$|  $$$$$$$ /$$$$$$$/  |  $$$$/
+    // |_______/ |__/ \_______/|_______/    \___/
+
+
+    public static void blastRedis() {
+        Jedis jedis = doGetRedisInstance();
+        jedis.flushAll();
+        jedis.close();
+    }
+
+    //                                /$$$$$$   /$$$$$$          /$$       /$$
+    //                               /$$__  $$ /$$__  $$        | $$      | $$
+    //  /$$$$$$$  /$$$$$$$  /$$$$$$ | $$  \__/| $$  \__//$$$$$$ | $$  /$$$$$$$
+    // /$$_____/ /$$_____/ |____  $$| $$$$    | $$$$   /$$__  $$| $$ /$$__  $$
+    //|  $$$$$$ | $$        /$$$$$$$| $$_/    | $$_/  | $$  \ $$| $$| $$  | $$
+    // \____  $$| $$       /$$__  $$| $$      | $$    | $$  | $$| $$| $$  | $$
+    // /$$$$$$$/|  $$$$$$$|  $$$$$$$| $$      | $$    |  $$$$$$/| $$|  $$$$$$$
+    //|_______/  \_______/ \_______/|__/      |__/     \______/ |__/ \_______/
+
+    public static <K, V> RedisCache scaffoldRedisCache(RedisManager redisManager, RedisSerializer<K> keySerializer, RedisSerializer<V> valueSerializer, String prefix, int expire, String principalIdFieldName) {
+        return new RedisCache<K, V>(redisManager, keySerializer, valueSerializer, prefix, expire, principalIdFieldName);
+    }
+
+    public static RedisSessionDAO scaffoldRedisSessionDAO(RedisManager redisManager, String prefix) {
+        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
+        redisSessionDAO.setRedisManager(redisManager);
+        redisSessionDAO.setKeyPrefix(prefix);
+        redisSessionDAO.setExpire(NumberUtils.toInt(properties.getProperty("redisSessionDAO.expire")));
+        return redisSessionDAO;
+    }
+
+    public static String scaffoldPrefix() {
+        return faker.university().name().replace(" ", "_") + ":";
+    }
+
+    public static RedisManager scaffoldStandaloneRedisManager() {
+        RedisManager redisManager = new RedisManager();
+        redisManager.setHost(properties.getProperty("redisManager.host"));
+        return redisManager;
+    }
+
+    public static UserInfo scaffoldUser() {
+        UserInfo user = new UserInfo();
+        user.setId(faker.number().randomDigitNotZero());
+        user.setUsername(faker.name().username());
+        user.setAge(faker.number().numberBetween(18, 60));
+        user.setRole(faker.number().randomDigitNotZero());
+        return user;
+    }
+
+    public static FakeSession scaffoldSession() {
+        return new FakeSession(faker.number().randomDigitNotZero(), faker.name().username());
+    }
+
+    public static FakeSession scaffoldEmptySession() {
+        return new FakeSession();
+    }
+
+    public static String scaffoldUsername() {
+        return faker.name().username();
+    }
+
+    public static PrincipalCollection scaffoldAuthKey(UserInfo user) {
+        SimplePrincipalCollection key = new SimplePrincipalCollection();
+        key.add(user, faker.beer().name());
+        return key;
+    }
+
+    public static Set scaffoldKeys(Object... users) {
+        Set keys = new HashSet();
+        for (Object user : users) {
+            keys.add(user);
+        }
+        return keys;
+    }
+
+    //                         /$$     /$$
+    //                        | $$    |__/
+    //    /$$$$$$   /$$$$$$$ /$$$$$$   /$$  /$$$$$$  /$$$$$$$   /$$$$$$$
+    //   |____  $$ /$$_____/|_  $$_/  | $$ /$$__  $$| $$__  $$ /$$_____/
+    //    /$$$$$$$| $$        | $$    | $$| $$  \ $$| $$  \ $$|  $$$$$$
+    //   /$$__  $$| $$        | $$ /$$| $$| $$  | $$| $$  | $$ \____  $$
+    //  |  $$$$$$$|  $$$$$$$  |  $$$$/| $$|  $$$$$$/| $$  | $$ /$$$$$$$/
+    //   \_______/ \_______/   \___/  |__/ \______/ |__/  |__/|_______/
+
+    public static void doPutAuth(RedisCache redisCache, PrincipalCollection user) {
+        if (user == null) {
+            redisCache.put(null, null);
+            return;
+        }
+        redisCache.put(user, turnUserToFakeAuth((UserInfo)user.getPrimaryPrincipal()));
+    }
+
+    public static void doRemoveAuth(RedisCache redisCache, PrincipalCollection user) {
+        redisCache.remove(user);
+    }
+
+    public static void doClearAuth(RedisCache redisCache) {
+        redisCache.clear();
+    }
+
+    public static Set doKeysAuth(RedisCache redisCache) {
+        return redisCache.keys();
+    }
+
+    public static void doSetSessionDAOExpire(RedisSessionDAO redisSessionDAO, int expire) {
+        redisSessionDAO.setExpire(expire);
+    }
+
+    public static void doChangeSessionName(FakeSession session, String name) {
+        session.setName(name);
+    }
+
+    private static Jedis doGetRedisInstance() {
+        return new Jedis(properties.getProperty("redisManager.host").split(":")[0]);
+    }
+
+    //                                                      /$$
+    //                                                     | $$
+    //    /$$$$$$   /$$$$$$$ /$$$$$$$  /$$$$$$   /$$$$$$  /$$$$$$
+    //   |____  $$ /$$_____//$$_____/ /$$__  $$ /$$__  $$|_  $$_/
+    //    /$$$$$$$|  $$$$$$|  $$$$$$ | $$$$$$$$| $$  \__/  | $$
+    //   /$$__  $$ \____  $$\____  $$| $$_____/| $$        | $$ /$$
+    //  |  $$$$$$$ /$$$$$$$//$$$$$$$/|  $$$$$$$| $$        |  $$$$/
+    //   \_______/|_______/|_______/  \_______/|__/         \___/
+
+    public static void assertRedisEmpty() {
+        Jedis jedis = doGetRedisInstance();
+        assertThat("Redis should be empty",jedis.dbSize(), is(0L));
+    }
+
+    public static void assertKeysEquals(Set actualKeys, Set expectKeys) {
+        Assert.assertEquals(expectKeys, actualKeys);
+    }
+
+    public static void assertAuthEquals(FakeAuth actualAuth, FakeAuth expectAuth) {
+        assertThat(actualAuth.getId(), is(expectAuth.getId()));
+        assertThat(actualAuth.getRole(), is(expectAuth.getRole()));
+    }
+
+    public static void assertPrincipalInstanceException(Exception e) {
+        assertThat(e, is(notNullValue()));
+        assertThat(e.getMessage(), containsString("must has getter for field: " + properties.getProperty("cacheManager.principalIdFieldName")));
+    }
+
+    public static void assertEquals(Object actual, Object expect) {
+        assertThat(actual,is(expect));
+    }
+
+    public static void assertSessionEquals(Session actualSession, Session expectSession) {
+        assertThat(actualSession.getId(), is(expectSession.getId()));
+        assertThat(((FakeSession)actualSession).getName(), is(((FakeSession)expectSession).getName()));
+    }
+
+    //     /$$                                             /$$$$$$
+    //    | $$                                            /$$__  $$
+    //   /$$$$$$    /$$$$$$  /$$$$$$  /$$$$$$$   /$$$$$$$| $$  \__//$$$$$$   /$$$$$$
+    //  |_  $$_/   /$$__  $$|____  $$| $$__  $$ /$$_____/| $$$$   /$$__  $$ /$$__  $$
+    //    | $$    | $$  \__/ /$$$$$$$| $$  \ $$|  $$$$$$ | $$_/  | $$$$$$$$| $$  \__/
+    //    | $$ /$$| $$      /$$__  $$| $$  | $$ \____  $$| $$    | $$_____/| $$
+    //    |  $$$$/| $$     |  $$$$$$$| $$  | $$ /$$$$$$$/| $$    |  $$$$$$$| $$
+    //     \___/  |__/      \_______/|__/  |__/|_______/ |__/     \_______/|__/
+    //
+
+    public static Set turnPrincipalCollectionToString(Set<PrincipalCollection> users, String prefix) {
+        Set<String> keys = new HashSet<String>();
+        for (PrincipalCollection user : users) {
+            keys.add(prefix + ((UserInfo)user.getPrimaryPrincipal()).getId());
+        }
+        return keys;
+    }
+
+    public static FakeAuth turnUserToFakeAuth(UserInfo user) {
+        FakeAuth auth = new FakeAuth();
+        auth.setId(user.getId());
+        auth.setRole(user.getRole());
+        return auth;
+    }
+
+    //     /$$                         /$$
+    //    | $$                        | $$
+    //   /$$$$$$    /$$$$$$   /$$$$$$ | $$  /$$$$$$$
+    //  |_  $$_/   /$$__  $$ /$$__  $$| $$ /$$_____/
+    //    | $$    | $$  \ $$| $$  \ $$| $$|  $$$$$$
+    //    | $$ /$$| $$  | $$| $$  | $$| $$ \____  $$
+    //    |  $$$$/|  $$$$$$/|  $$$$$$/| $$ /$$$$$$$/
+    //     \___/   \______/  \______/ |__/|_______/
+
+    public static Properties loadProperties(String propFileName) {
+
+        Properties props = new Properties();
+        InputStream inputStream = TestFixture.class.getClassLoader()
+                .getResourceAsStream(propFileName);
+
+        if (inputStream != null) {
+            try {
+                props.load(inputStream);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return props;
+    }
+
+    public static Long getRedisTTL(String key, RedisSerializer keySerializer) {
+        Jedis jedis = doGetRedisInstance();
+        Long ttl = 0L;
+        try {
+            ttl = jedis.ttl(keySerializer.serialize(key));
+        } catch (SerializationException e) {
+            e.printStackTrace();
+        }
+        jedis.close();
+        return ttl;
+    }
+
+}

+ 44 - 0
shiro-redis/src/test/java/org/crazycake/shiro/RedisCacheManagerTest.java

@@ -0,0 +1,44 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.cache.Cache;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static fixture.TestFixture.*;
+
+public class RedisCacheManagerTest {
+
+    private RedisManager redisManager;
+    private RedisCacheManager redisCacheManager;
+
+    @Before
+    public void setUp() {
+        redisManager = Mockito.mock(RedisManager.class);
+        redisCacheManager = new RedisCacheManager();
+        redisCacheManager.setRedisManager(redisManager);
+    }
+
+    @After
+    public void tearDown() {
+        blastRedis();
+    }
+
+    @Test
+    public void testGetCache() {
+        Cache cache = redisCacheManager.getCache("testCache1");
+        Cache cache1 = redisCacheManager.getCache("testCache1");
+        assertThat(cache,is(cache1));
+
+        redisCacheManager.setKeyPrefix("testRedisManager1:");
+        Cache cache2 = redisCacheManager.getCache("testCache2");
+        assertThat(cache2.getClass().getName(), is("org.crazycake.shiro.RedisCache"));
+
+        RedisCache redisCache2 = (RedisCache) cache2;
+        assertThat(redisCache2.getKeyPrefix(), is("testRedisManager1:testCache2:"));
+    }
+
+}

+ 173 - 0
shiro-redis/src/test/java/org/crazycake/shiro/RedisCacheTest.java

@@ -0,0 +1,173 @@
+package org.crazycake.shiro;
+
+import static fixture.TestFixture.*;
+import static org.junit.Assert.fail;
+
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.SimplePrincipalCollection;
+import org.crazycake.shiro.exception.CacheManagerPrincipalIdNotAssignedException;
+import org.crazycake.shiro.exception.PrincipalInstanceException;
+import org.crazycake.shiro.model.FakeAuth;
+import org.crazycake.shiro.model.UserInfo;
+import org.crazycake.shiro.serializer.ObjectSerializer;
+import org.crazycake.shiro.serializer.StringSerializer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.github.javafaker.Faker;
+
+/**
+ * input key, value (java)
+ * output value (java)
+ */
+public class RedisCacheTest {
+
+    private RedisCache<PrincipalCollection, FakeAuth> redisCache;
+    private RedisCache<PrincipalCollection, FakeAuth> redisCacheWithPrincipalIdFieldName;
+    private RedisCache<PrincipalCollection, FakeAuth> redisCacheWithEmptyPrincipalIdFieldName;
+    private RedisCache<PrincipalCollection, String> redisCacheWithStrings;
+
+    private Properties properties = loadProperties("shiro-standalone.ini");
+    private PrincipalCollection user1;
+    private PrincipalCollection user2;
+    private PrincipalCollection user3;
+    private PrincipalCollection user4;
+
+    private Set users1_2_3;
+    private String prefix;
+
+    private void blast() {
+        blastRedis();
+    }
+
+    private void scaffold() {
+        RedisManager redisManager = scaffoldStandaloneRedisManager();
+        prefix = scaffoldPrefix();
+        redisCache = scaffoldRedisCache(redisManager, new StringSerializer(), new ObjectSerializer(), prefix, NumberUtils.toInt(properties.getProperty("cacheManager.expire")), RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME);
+        redisCacheWithPrincipalIdFieldName = scaffoldRedisCache(redisManager, new StringSerializer(), new ObjectSerializer(), prefix, NumberUtils.toInt(properties.getProperty("cacheManager.expire")), properties.getProperty("cacheManager.principalIdFieldName"));
+        redisCacheWithEmptyPrincipalIdFieldName = scaffoldRedisCache(redisManager, new StringSerializer(), new ObjectSerializer(), prefix, NumberUtils.toInt(properties.getProperty("cacheManager.expire")), "");
+        redisCacheWithStrings = scaffoldRedisCache(redisManager, new StringSerializer(), new ObjectSerializer(), prefix, NumberUtils.toInt(properties.getProperty("cacheManager.expire")), properties.getProperty("cacheManager.principalIdFieldName"));
+        user1 = scaffoldAuthKey(scaffoldUser());
+        user2 = scaffoldAuthKey(scaffoldUser());
+        user3 = scaffoldAuthKey(scaffoldUser());
+        user4 = new SimplePrincipalCollection(Faker.instance().gameOfThrones().character(), Faker.instance().gameOfThrones().city());
+        users1_2_3 = scaffoldKeys(user1, user2, user3);
+    }
+
+
+    @Before
+    public void setUp() {
+        blast();
+        scaffold();
+    }
+
+    @After
+    public void tearDown() {
+        blast();
+    }
+
+
+    @Test
+    public void testInitialize() {
+        try {
+            new RedisCache<String, String>(null, null, null, "abc:", 1, RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME);
+            fail("Excepted exception to be thrown");
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "redisManager cannot be null.");
+        }
+
+        try {
+            new RedisCache<String, String>(new RedisManager(), null, null, "abc:", 1, RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME);
+            fail("Excepted exception to be thrown");
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "keySerializer cannot be null.");
+        }
+
+        try {
+            new RedisCache<String, String>(new RedisManager(), new StringSerializer(), null, "abc:", 1, RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME);
+            fail("Excepted exception to be thrown");
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "valueSerializer cannot be null.");
+        }
+
+        RedisCache rc = new RedisCache(new RedisManager(), new StringSerializer(), new ObjectSerializer(), "abc", 1, RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME);
+        assertEquals(rc.getKeyPrefix(), "abc");
+    }
+
+    @Test
+    public void testPutNull() {
+        doPutAuth(redisCache, null);
+        assertRedisEmpty();
+    }
+
+    @Test
+    public void testPut() {
+        doPutAuth(redisCache, user1);
+        FakeAuth fakeAuth = redisCache.get(user1);
+        assertAuthEquals(fakeAuth, turnUserToFakeAuth((UserInfo)user1.getPrimaryPrincipal()));
+    }
+    
+    @Test
+    public void testPutString() {
+        redisCacheWithStrings.put(user4, user4.getPrimaryPrincipal().toString());
+        String auth = redisCacheWithStrings.get(user4);
+        assertEquals(auth, user4.getPrimaryPrincipal());
+    }
+
+    @Test
+    public void testSize() throws InterruptedException {
+        doPutAuth(redisCache, user1);
+        doPutAuth(redisCache, user2);
+        Thread.sleep(800);
+        assertEquals(redisCache.size(), 2);
+    }
+
+    @Test
+    public void testPutInvalidPrincipal() {
+        try {
+            doPutAuth(redisCacheWithPrincipalIdFieldName, user3);
+            fail();
+        } catch (PrincipalInstanceException e) {
+            assertPrincipalInstanceException(e);
+        }
+    }
+
+    @Test
+    public void testPutPrincipalWithEmptyIdFieldName() {
+        try {
+            doPutAuth(redisCacheWithEmptyPrincipalIdFieldName, user3);
+            fail();
+        } catch (CacheManagerPrincipalIdNotAssignedException e) {
+            assertEquals(e.getMessage(), "CacheManager didn't assign Principal Id field name!");
+        }
+    }
+
+    @Test
+    public void testRemove() {
+        doPutAuth(redisCache, user1);
+        doRemoveAuth(redisCache, user1);
+        assertRedisEmpty();
+    }
+
+    @Test
+    public void testClear() {
+        doClearAuth(redisCache);
+        assertRedisEmpty();
+    }
+
+    @Test
+    public void testKeys() {
+        doPutAuth(redisCache, user1);
+        doPutAuth(redisCache, user2);
+        doPutAuth(redisCache, user3);
+        Set actualKeys = doKeysAuth(redisCache);
+        assertKeysEquals(actualKeys, turnPrincipalCollectionToString(users1_2_3, prefix));
+    }
+
+
+}

+ 55 - 0
shiro-redis/src/test/java/org/crazycake/shiro/RedisClusterManagerTest.java

@@ -0,0 +1,55 @@
+package org.crazycake.shiro;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import redis.clients.jedis.JedisCluster;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+import static fixture.TestFixture.*;
+
+public class RedisClusterManagerTest {
+
+    private RedisClusterManager redisClusterManager;
+    private JedisCluster jedisCluster;
+
+    @Before
+    public void setUp() throws Exception {
+        jedisCluster = mock(JedisCluster.class);
+        redisClusterManager = new RedisClusterManager();
+        redisClusterManager.setJedisCluster(jedisCluster);
+    }
+
+    @After
+    public void tearDown() {
+        blastRedis();
+    }
+
+    @Test
+    public void get() {
+        byte[] value = redisClusterManager.get(null);
+        assertThat(value, is(nullValue()));
+        byte[] testKey = "123".getBytes();
+        byte[] expectValue = "abc".getBytes();
+        when(jedisCluster.get(testKey)).thenReturn(expectValue);
+        byte[] testValue = redisClusterManager.get(testKey);
+        assertThat(testValue, is(expectValue));
+    }
+
+    @Test
+    public void set() {
+        redisClusterManager.set(null, null, -1);
+        verify(jedisCluster, times(0)).set(any(byte[].class), any(byte[].class));
+        redisClusterManager.set(new byte[0], null, -1);
+        verify(jedisCluster, times(1)).set(any(byte[].class), any(byte[].class));
+        verify(jedisCluster, times(0)).expire(any(byte[].class), any(int.class));
+        redisClusterManager.set(new byte[0], null, 0);
+        verify(jedisCluster, times(1)).expire(any(byte[].class), any(int.class));
+        redisClusterManager.set(new byte[0], null, 1);
+        verify(jedisCluster, times(2)).expire(any(byte[].class), any(int.class));
+    }
+}

+ 143 - 0
shiro-redis/src/test/java/org/crazycake/shiro/RedisSessionDAOTest.java

@@ -0,0 +1,143 @@
+package org.crazycake.shiro;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.UnknownSessionException;
+import org.crazycake.shiro.exception.SerializationException;
+import org.crazycake.shiro.model.FakeSession;
+import org.crazycake.shiro.serializer.StringSerializer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Map;
+
+import static fixture.TestFixture.*;
+import static org.junit.Assert.fail;
+
+public class RedisSessionDAOTest {
+
+    private RedisSessionDAO redisSessionDAO;
+    private FakeSession session1;
+    private FakeSession session2;
+    private FakeSession emptySession;
+    private String name1;
+    private String prefix;
+    private void blast() {
+        blastRedis();
+    }
+
+    private void scaffold() {
+        prefix = scaffoldPrefix();
+        RedisManager redisManager = scaffoldStandaloneRedisManager();
+        redisSessionDAO = scaffoldRedisSessionDAO(redisManager, prefix);
+        session1 = scaffoldSession();
+        session2 = scaffoldSession();
+        emptySession = scaffoldEmptySession();
+        name1 = scaffoldUsername();
+    }
+
+    @Before
+    public void setUp() {
+        blast();
+        scaffold();
+    }
+
+    @After
+    public void tearDown() {
+        blast();
+    }
+
+    @Test
+    public void testDoCreateNull() {
+        try {
+            redisSessionDAO.doCreate(null);
+            fail();
+        } catch (UnknownSessionException e) {
+            assertEquals(e.getMessage(), "session is null");
+        }
+    }
+
+    @Test
+    public void testDoCreate() {
+        redisSessionDAO.doCreate(session1);
+        Session actualSession = redisSessionDAO.doReadSession(session1.getId());
+        assertSessionEquals(actualSession, session1);
+    }
+
+    @Test
+    public void testDoCreateWithSessionTimeout() {
+        doSetSessionDAOExpire(redisSessionDAO, -2);
+        redisSessionDAO.doCreate(session2);
+        assertEquals(getRedisTTL(prefix + session2.getId(), new StringSerializer()), 1800L);
+    }
+
+    @Test
+    public void testUpdateNull() {
+        try {
+            redisSessionDAO.update(null);
+            fail();
+        } catch (UnknownSessionException e) {
+            assertEquals(e.getMessage(), "session or session id is null");
+        }
+    }
+
+    @Test
+    public void testUpdateEmptySession() {
+        try {
+            redisSessionDAO.update(emptySession);
+            fail();
+        } catch (UnknownSessionException e) {
+            assertEquals(e.getMessage(), "session or session id is null");
+        }
+    }
+
+    @Test
+    public void testUpdate() {
+        redisSessionDAO.doCreate(session1);
+        redisSessionDAO.doReadSession(session1.getId());
+        doChangeSessionName(session1, name1);
+        redisSessionDAO.update(session1);
+        FakeSession actualSession = (FakeSession)redisSessionDAO.doReadSession(session1.getId());
+        assertEquals(actualSession.getName(), name1);
+    }
+
+    @Test
+    public void testUpdateWithoutSessionInMemory() {
+        redisSessionDAO.setSessionInMemoryEnabled(false);
+        redisSessionDAO.doCreate(session1);
+        redisSessionDAO.doReadSession(session1.getId());
+        doChangeSessionName(session1, name1);
+        redisSessionDAO.update(session1);
+        FakeSession actualSession = (FakeSession)redisSessionDAO.doReadSession(session1.getId());
+        assertEquals(actualSession.getName(), name1);
+    }
+
+    @Test
+    public void testDelete() {
+        redisSessionDAO.doCreate(session1);
+        redisSessionDAO.delete(session1);
+        assertRedisEmpty();
+    }
+
+    @Test
+    public void testGetActiveSessions() {
+        redisSessionDAO.doCreate(session1);
+        redisSessionDAO.doCreate(session2);
+        Collection<Session> activeSessions = redisSessionDAO.getActiveSessions();
+        assertEquals(activeSessions.size(), 2);
+    }
+
+    @Test
+    public void testRemoveExpiredSessionInMemory() throws InterruptedException, SerializationException {
+        redisSessionDAO.setSessionInMemoryTimeout(500L);
+        redisSessionDAO.doCreate(session1);
+        redisSessionDAO.doReadSession(session1.getId());
+        Thread.sleep(1000);
+        redisSessionDAO.doCreate(session2);
+        redisSessionDAO.doReadSession(session2.getId());
+        Map<Serializable, SessionInMemory> sessionMap = (Map<Serializable, SessionInMemory>) redisSessionDAO.getSessionsInThread().get();
+        assertEquals(sessionMap.size(), 1);
+    }
+}

+ 31 - 0
shiro-redis/src/test/java/org/crazycake/shiro/model/FakeAuth.java

@@ -0,0 +1,31 @@
+package org.crazycake.shiro.model;
+
+import java.io.Serializable;
+
+public class FakeAuth implements Serializable{
+    private Integer id;
+    private Integer role;
+
+    public FakeAuth() {}
+
+    public FakeAuth(Integer id, Integer role) {
+        this.id = id;
+        this.role = role;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getRole() {
+        return role;
+    }
+
+    public void setRole(Integer role) {
+        this.role = role;
+    }
+}

+ 87 - 0
shiro-redis/src/test/java/org/crazycake/shiro/model/FakeSession.java

@@ -0,0 +1,87 @@
+package org.crazycake.shiro.model;
+
+import org.apache.shiro.session.InvalidSessionException;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.SimpleSession;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+
+public class FakeSession extends SimpleSession implements Serializable, Session{
+    private Integer id;
+    private String name;
+
+    public FakeSession() {}
+
+    public FakeSession(Integer id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public Date getStartTimestamp() {
+        return null;
+    }
+
+    @Override
+    public Date getLastAccessTime() {
+        return null;
+    }
+
+    @Override
+    public void setTimeout(long l) throws InvalidSessionException {
+
+    }
+
+    @Override
+    public String getHost() {
+        return null;
+    }
+
+    @Override
+    public void touch() throws InvalidSessionException {
+
+    }
+
+    @Override
+    public void stop() throws InvalidSessionException {
+
+    }
+
+    @Override
+    public Collection<Object> getAttributeKeys() throws InvalidSessionException {
+        return null;
+    }
+
+    @Override
+    public Object getAttribute(Object o) throws InvalidSessionException {
+        return null;
+    }
+
+    @Override
+    public void setAttribute(Object o, Object o1) throws InvalidSessionException {
+
+    }
+
+    @Override
+    public Object removeAttribute(Object o) throws InvalidSessionException {
+        return null;
+    }
+}

+ 56 - 0
shiro-redis/src/test/java/org/crazycake/shiro/model/UserInfo.java

@@ -0,0 +1,56 @@
+package org.crazycake.shiro.model;
+
+import java.io.Serializable;
+
+public class UserInfo implements Serializable {
+
+    private Integer id;
+
+    private String username;
+
+    private Integer age;
+
+    private String city;
+
+    private Integer role;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getCity() {
+        return city;
+    }
+
+    public void setCity(String city) {
+        this.city = city;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Integer getAge() {
+        return age;
+    }
+
+    public void setAge(Integer age) {
+        this.age = age;
+    }
+
+    public Integer getRole() {
+        return role;
+    }
+
+    public void setRole(Integer role) {
+        this.role = role;
+    }
+}

+ 4 - 0
shiro-redis/src/test/resources/shiro-standalone.ini

@@ -0,0 +1,4 @@
+redisManager.host = git.bosshand.com:6666
+redisSessionDAO.expire = 3000
+cacheManager.expire = 3000
+cacheManager.principalIdFieldName = userId

BIN
virgo.api/.DS_Store


+ 32 - 0
virgo.api/.classpath

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

+ 2 - 0
virgo.api/.gitignore

@@ -0,0 +1,2 @@
+/target/
+.iml

+ 40 - 0
virgo.api/.project

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>api</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.springframework.ide.eclipse.core.springbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.springframework.ide.eclipse.boot.validation.springbootbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.springframework.ide.eclipse.core.springnature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+	</natures>
+</projectDescription>

+ 4 - 0
virgo.api/.settings/org.eclipse.core.resources.prefs

@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding/<project>=UTF-8

+ 7 - 0
virgo.api/.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,7 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8

+ 4 - 0
virgo.api/.settings/org.eclipse.m2e.core.prefs

@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

+ 4 - 0
virgo.api/.settings/org.eclipse.wst.common.project.facet.core.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+  <installed facet="cloudfoundry.standalone.app" version="1.0"/>
+</faceted-project>

+ 53 - 0
virgo.api/pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.bosshand.virgo</groupId>
+	<artifactId>api</artifactId>
+	<!-- Inherit defaults from Spring Boot -->
+	<parent>
+		<groupId>com.bosshand</groupId>
+		<artifactId>virgo</artifactId>
+		<version>0.0.1-SNAPSHOT</version>
+		<relativePath>../pom.xml</relativePath>
+	</parent>
+	<dependencies>
+		<!-- LEO associate dependency -->
+		<dependency>
+			<groupId>com.bosshand.virgo</groupId>
+			<artifactId>core</artifactId>
+			<version>0.0.1-SNAPSHOT</version>
+		</dependency>
+
+		<dependency>
+			<groupId>com.squareup.okhttp3</groupId>
+			<artifactId>okhttp</artifactId>
+			<version>3.6.0</version>
+		</dependency>
+
+		<dependency>
+		    <groupId>org.springframework.cloud</groupId>
+		    <artifactId>spring-cloud-starter-openfeign</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-quartz</artifactId>
+			<version>2.6.2</version>
+		</dependency>
+
+
+	</dependencies>
+		
+	<!-- Package as an executable jar -->
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 20 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/Application.java

@@ -0,0 +1,20 @@
+package com.bosshand.virgo.api;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@EnableFeignClients
+@SpringBootApplication
+//@EnableEurekaClient
+@EnableTransactionManagement
+@MapperScan("com.bosshand.virgo.core.dao,com.bosshand.virgo.api.dao,com.bosshand.virgo.api.metadata.dao")
+@ComponentScan(basePackages = {"com.bosshand"})
+public class Application {
+	public static void main(String[] args) {
+		SpringApplication.run(Application.class, args);
+	}
+}

+ 26 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/CorsConfig.java

@@ -0,0 +1,26 @@
+package com.bosshand.virgo.api;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter; 
+
+@Configuration
+public class CorsConfig {
+	private CorsConfiguration buildConfig() {
+		CorsConfiguration corsConfiguration = new CorsConfiguration();
+		corsConfiguration.addAllowedOrigin("*");
+		corsConfiguration.addAllowedHeader("*");
+		corsConfiguration.addAllowedMethod("*");
+		return corsConfiguration;
+	}
+
+	@Bean
+	public CorsFilter corsFilter() {
+		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+		source.registerCorsConfiguration("/**", buildConfig());
+		return new CorsFilter(source);
+	}
+
+}

+ 45 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/CollaborativeController.java

@@ -0,0 +1,45 @@
+package com.bosshand.virgo.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.model.Collaborative;
+import com.bosshand.virgo.api.service.CollaborativeService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("collaborative")
+public class CollaborativeController {
+
+	@Autowired
+	private CollaborativeService collaborativeService;
+
+	@ApiOperation(value = "获取协同审核", notes = "获取协同审核")
+	@RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+	public Response getList(@PathVariable long projectId) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		return Response.ok(collaborativeService.getList(user, projectId));
+	}
+
+	@ApiOperation(value = "新增协同审核", notes = "新增协同审核")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insert(@RequestBody Collaborative collaborative) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		return Response.ok(collaborativeService.insert(collaborative, user));
+	}
+	
+	@ApiOperation(value = "回执协同审核", notes = "回执协同审核")
+	@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
+	public Response isReceipt(@PathVariable int id) {
+		return Response.ok(collaborativeService.isReceipt(id));
+	}
+
+}

+ 44 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ConfigurationUrlController.java

@@ -0,0 +1,44 @@
+package com.bosshand.virgo.api.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.bosshand.virgo.api.model.ConfigurationUrl;
+import com.bosshand.virgo.api.service.ConfigurationUrlService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("configurationUrl")
+public class ConfigurationUrlController {
+	
+	@Autowired
+	private ConfigurationUrlService configurationUrlService;
+
+	@RequestMapping(value = "/url", method = RequestMethod.GET)
+	public String get() {
+		return JSONObject.toJSONString(configurationUrlService.getList().get(0));
+	}
+
+	@ApiOperation(value = "获取配置url", notes = "获取配置url")
+	@RequestMapping(value = "/", method = RequestMethod.GET)
+	public Response getList() {
+		return Response.ok(configurationUrlService.getList());
+	}
+
+	@ApiOperation(value = "配置url", notes = "配置url")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insert(@RequestBody ConfigurationUrl configurationUrl) {
+		return Response.ok(configurationUrlService.insert(configurationUrl));
+	}
+	
+	@ApiOperation(value = "修改配置url", notes = "修改配置url")
+	@RequestMapping(value = "/", method = RequestMethod.PUT)
+	public Response update(@RequestBody ConfigurationUrl configurationUrl) {
+		return Response.ok(configurationUrlService.update(configurationUrl));
+	}
+
+}

+ 41 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ConstructionLogController.java

@@ -0,0 +1,41 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.service.ConstructionLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import com.bosshand.virgo.api.model.Project;
+import com.bosshand.virgo.api.service.ProjectService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("constructionLog")
+public class ConstructionLogController {
+	
+	@Autowired
+	private ConstructionLogService constructionLogService;
+	
+	@Autowired
+	private ProjectService projectService;
+
+	@RequestMapping(value = "/saveNotice", method = RequestMethod.POST)
+	public void saveNotice(@RequestBody String data) {
+		constructionLogService.saveConstructionLog(data);
+	}
+
+	@ApiOperation(value = "施工日志", notes = "施工日志")
+	@RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+	public Response getNotice(@PathVariable long projectId) {
+		Project project = projectService.get(projectId);
+		return Response.ok(constructionLogService.getByProjectId(project.getYuiProjectId()));
+	}
+
+	@ApiOperation(value = "安全日志", notes = "安全日志")
+	@RequestMapping(value = "/security/{projectId}", method = RequestMethod.GET)
+	public Response getSecurityNotice(@PathVariable long projectId) {
+		Project project = projectService.get(projectId);
+		return Response.ok(constructionLogService.getSecurityNotice(project.getYuiProjectId()));
+	}
+
+}

+ 71 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/DesignChangeController.java

@@ -0,0 +1,71 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.DesignChange;
+import com.bosshand.virgo.api.service.DesignChangeService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+public class DesignChangeController {
+
+    @Autowired
+    private DesignChangeService designChangeService;
+
+    @ApiOperation(value = "新增", notes = "新增")
+    @RequestMapping(value = "designChange", method = RequestMethod.POST)
+    public Response add(@RequestBody DesignChange designChange) {
+        MgrUser user = ContextUtils.getCurrentUser();
+        designChange.setCreateBy(user.getName());
+        designChange.setCreateByUserId(user.getId());
+        return Response.ok(designChangeService.save(designChange));
+    }
+
+    @ApiOperation(value = "编辑", notes = "编辑")
+    @RequestMapping(value = "designChange", method = RequestMethod.PUT)
+    public Response edit(@RequestBody DesignChange designChange) {
+        MgrUser user = ContextUtils.getCurrentUser();
+        designChange.setCreateBy(user.getName());
+        designChange.setCreateByUserId(user.getId());
+        return Response.ok(designChangeService.update(designChange));
+    }
+
+    @ApiOperation(value = "删除", notes = "删除")
+    @RequestMapping(value = "designChange/{id}", method = RequestMethod.DELETE)
+    public Response del(@PathVariable long id) {
+        designChangeService.delete(id);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "查询列表", notes = "查询列表")
+    @RequestMapping(value = "designChange/queryList", method = RequestMethod.POST)
+    public Response getByList(@RequestBody DesignChange designChange) {
+        return Response.ok(designChangeService.queryByList(designChange));
+    }
+
+    @ApiOperation(value = "查询", notes = "查询")
+    @RequestMapping(value = "designChange/query", method = RequestMethod.POST)
+    public Response getByProjectId(@RequestBody DesignChange designChange) {
+        return Response.ok(designChangeService.query(designChange));
+    }
+
+    @ApiOperation(value = "分页查询", notes = "分页查询")
+    @RequestMapping(value = "designChange/query/{currPage}/{pageSize}", method = RequestMethod.POST)
+    public Response getPageByProjectId(@RequestBody DesignChange designChange, @PathVariable int currPage, @PathVariable int pageSize) {
+        List<DesignChange> totalCount = designChangeService.query(designChange);
+        List<DesignChange> dataList = totalCount.stream().skip((currPage - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
+        Map<String, Object> result = new HashMap<String, Object>();
+        result.put("dataList", dataList);
+        result.put("totalCount", totalCount.size());
+        return Response.ok(result);
+    }
+
+}

+ 42 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/DrawingsMarkedController.java

@@ -0,0 +1,42 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.DrawingsMarked;
+import com.bosshand.virgo.api.service.DrawingsMarkedService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("drawingsMarked")
+public class DrawingsMarkedController {
+
+    @Autowired
+    DrawingsMarkedService drawingsMarkedService;
+
+
+    @ApiOperation(value = "保存图纸标注", notes = "保存图纸标注")
+    @RequestMapping(value = "/", method = RequestMethod.POST)
+    public Response saveDrawingsMarked(@RequestBody DrawingsMarked drawingsMarked) {
+        return Response.ok( drawingsMarkedService.save(drawingsMarked));
+    }
+
+    @ApiOperation(value = "修改图纸标注", notes = "修改图纸标注")
+    @RequestMapping(value = "/", method = RequestMethod.PUT)
+    public Response updateDrawingsMarked(@RequestBody DrawingsMarked drawingsMarked) {
+        return Response.ok(drawingsMarkedService.update(drawingsMarked));
+    }
+
+    @ApiOperation(value = "根据ids获取图纸标注", notes = "根据ids获取图纸标注")
+    @RequestMapping(value = "/{ids}", method = RequestMethod.GET)
+    public Response getDrawingsMarkedByIds(@PathVariable String ids) {
+        return Response.ok(drawingsMarkedService.getIds(ids));
+    }
+
+    @ApiOperation(value = "根据fileId获取图纸标注", notes = "根据fileId获取图纸标注")
+    @RequestMapping(value = "/file/{fileId}", method = RequestMethod.GET)
+    public Response getDrawingsMarkedByFileId(@PathVariable int fileId) {
+        return Response.ok(drawingsMarkedService.getFileId(fileId));
+    }
+
+}

+ 93 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ElementController.java

@@ -0,0 +1,93 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.Element;
+import com.bosshand.virgo.api.service.ConfigurationUrlService;
+import com.bosshand.virgo.api.service.ElementService;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.QRCodeUtil;
+import com.bosshand.virgo.exception.ServiceException;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("element")
+public class ElementController {
+
+    @Autowired
+    ElementService elementService;
+
+    @Autowired
+    ConfigurationUrlService configurationUrlService;
+
+    @ApiOperation(value = "生成构件列表", notes = "生成构件列表")
+    @RequestMapping(value = "/create/{integrateId}", method = RequestMethod.GET)
+    public Response create(@PathVariable String integrateId) {
+        if (elementService.create(integrateId)) {
+            return Response.ok();
+        }
+        return Response.fail(200001, "查看集成是否成功");
+    }
+
+    @ApiOperation(value = "重新生成构件列表", notes = "重新生成构件列表")
+    @RequestMapping(value = "/recreate/{integrateId}", method = RequestMethod.GET)
+    public Response recreate(@PathVariable String integrateId) {
+        if (elementService.recreate(integrateId)) {
+            return Response.ok();
+        }
+        return Response.fail(200001, "查看集成是否成功");
+    }
+
+    @ApiOperation(value = "查询构件列表", notes = "查询构件列表")
+    @RequestMapping(value = "/list", method = RequestMethod.POST)
+    public Response getList(@RequestBody Element element) {
+        return Response.ok(elementService.getIntegrateId(element));
+    }
+
+    @ApiOperation(value = "查询构件列表", notes = "查询构件列表")
+    @RequestMapping(value = "/list/{currPage}/{pageSize}", method = RequestMethod.POST)
+    public Response getList(@RequestBody Element element, @PathVariable int currPage, @PathVariable int pageSize) {
+        List<Element> list = elementService.getIntegrateId(element);
+        List<Element> dataList = list.stream().skip((currPage - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
+        Map<String, Object> result = new HashMap<>();
+        result.put("dataList", dataList);
+        result.put("totalCount", list.size());
+        return Response.ok(result);
+    }
+
+    @ApiOperation(value = "查看构件二维码", notes = "查看构件二维码")
+    @RequestMapping(value = "/qr/{id}", method = RequestMethod.GET)
+    public Response getQr(@PathVariable long id) {
+        String url = configurationUrlService.getList().get(0).getCoordinationUrl();
+        byte[] qr = null;
+        try {
+            qr = QRCodeUtil.getQRCodeBytes(url + "/api/element/track/" + id);
+        } catch (Exception e) {
+            throw new ServiceException("qr is fail");
+        }
+        Map<String, Object> result = new HashMap<String, Object>();
+        String qrBase64 = "data:image/png;base64," + Base64.getEncoder().encodeToString(qr);
+        result.put("qrBase64", qrBase64);
+        return Response.ok(result);
+    }
+
+    @ApiOperation(value = "追踪", notes = "追踪")
+    @RequestMapping(value = "/track/{id}", method = RequestMethod.GET)
+    public Response track(@PathVariable long id) {
+        return Response.ok(elementService.track(id));
+    }
+
+    @ApiOperation(value = "更新加工厂和状态字段", notes = "更新加工厂和状态字段")
+    @RequestMapping(value = "/factory", method = RequestMethod.POST)
+    public Response track(@RequestBody Element element) {
+        elementService.factory(element);
+        return Response.ok();
+    }
+
+}

+ 72 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ElementStepController.java

@@ -0,0 +1,72 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.ElementStep;
+import com.bosshand.virgo.api.model.ElementStepModel;
+import com.bosshand.virgo.api.service.ElementStepService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("elementStep")
+public class ElementStepController {
+
+    @Autowired
+    ElementStepService elementStepService;
+
+    @ApiOperation(value = "默认步骤", notes = "默认步骤")
+    @RequestMapping(value = "/model", method = RequestMethod.GET)
+    public Response getListModel() {
+        return Response.ok(elementStepService.getModelList());
+    }
+
+    @ApiOperation(value = "新加默认步骤", notes = "新加默认步骤")
+    @RequestMapping(value = "/model", method = RequestMethod.POST)
+    public Response saveModel(@RequestBody ElementStepModel elementStepModel) {
+        elementStepService.saveModel(elementStepModel);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "删除默认步骤", notes = "删除默认步骤")
+    @RequestMapping(value = "/model/{id}", method = RequestMethod.DELETE)
+    public Response deleteModel(@PathVariable long id) {
+        elementStepService.deleteModel(id);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "修改默认步骤", notes = "修改默认步骤")
+    @RequestMapping(value = "/model", method = RequestMethod.PUT)
+    public Response updateModel(@RequestBody ElementStepModel elementStepModel) {
+        elementStepService.updateModel(elementStepModel);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "通过elementId获取步骤", notes = "通过elementId获取步骤")
+    @RequestMapping(value = "/{elementId}", method = RequestMethod.GET)
+    public Response getList(@PathVariable String elementId) {
+        return Response.ok(elementStepService.getList(elementId));
+    }
+
+    @ApiOperation(value = "增加单个构件下的步骤", notes = "增加单个构件下的步骤")
+    @RequestMapping(value = "", method = RequestMethod.POST)
+    public Response save(@RequestBody ElementStep elementStep) {
+        elementStepService.save(elementStep);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "修改单个构件下的步骤", notes = "修改单个构件下的步骤")
+    @RequestMapping(value = "", method = RequestMethod.PUT)
+    public Response update(@RequestBody ElementStep elementStep) {
+        elementStepService.update(elementStep);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "删除单个构件下的步骤", notes = "删除单个构件下的步骤")
+    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+    public Response delete(@PathVariable long id) {
+        elementStepService.delete(id);
+        return Response.ok();
+    }
+
+}

+ 414 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/FlowManagerController.java

@@ -0,0 +1,414 @@
+package com.bosshand.virgo.api.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.bosshand.virgo.api.model.*;
+import com.bosshand.virgo.api.service.FlowInstanceService;
+import com.bosshand.virgo.api.service.FlowUserConfigService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+
+@RestController
+public class FlowManagerController {
+
+	@Autowired
+	private FlowInstanceService flowInstanceService;
+
+	@Autowired
+	private FlowUserConfigService flowUserConfigService;
+
+	@ApiOperation(value = "流程样例模板新增", notes = "流程样例模板新增")
+	@RequestMapping(value = "/flowModel/{type}", method = RequestMethod.POST)
+	public Response insertFlowModel(@PathVariable int type, @RequestBody FlowModel flowModel) {
+		flowModel.setType(type);
+		flowInstanceService.insertflowModel(flowModel);
+		return Response.ok(flowModel);
+	}
+
+	@ApiOperation(value = "流程样例模板修改", notes = "流程样例模板修改")
+	@RequestMapping(value = "/flowModel/", method = RequestMethod.PUT)
+	public Response insertFlowModel(@RequestBody FlowModel flowModel) {
+		flowInstanceService.updateflowModel(flowModel);
+		return Response.ok(flowModel);
+	}
+
+	@ApiOperation(value = "流程样例模板删除", notes = "流程样例模板删除")
+	@RequestMapping(value = "/flowModel/{id}", method = RequestMethod.DELETE)
+	public Response insertFlowModel(@PathVariable long id) {
+		flowInstanceService.deleteflowModel(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "流程模板节点样例新增", notes = "流程模板节点样例新增")
+	@RequestMapping(value = "/flowModelNode/{flowModelId}", method = RequestMethod.POST)
+	public Response insertFlowModelNode(@PathVariable long flowModelId, @RequestBody FlowModelNode flowModelNode) {
+		flowModelNode.setFlowModelId(flowModelId);
+		flowInstanceService.insertflowModelNode(flowModelNode);
+		return Response.ok(flowModelNode);
+	}
+
+	@ApiOperation(value = "流程模板节点样例修改", notes = "流程模板节点样例修改")
+	@RequestMapping(value = "/flowModelNode/", method = RequestMethod.PUT)
+	public Response insertFlowModelNode(@RequestBody FlowModelNode flowModelNode) {
+		flowInstanceService.updateflowModelNode(flowModelNode);
+		return Response.ok(flowModelNode);
+	}
+
+	@ApiOperation(value = "流程模板节点样例删除", notes = "流程模板节点样例删除")
+	@RequestMapping(value = "/flowModelNode/{id}", method = RequestMethod.DELETE)
+	public Response deleteFlowModelNode(@PathVariable long id) {
+		flowInstanceService.deleteflowModelNode(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "协同流程同有极流程绑定", notes = "协同流程同有极流程绑定")
+	@RequestMapping(value = "/binding/flowModel/{id}/{yuiFlowTypes}", method = RequestMethod.POST)
+	public Response bindingFlowModel(@PathVariable int id, @PathVariable String yuiFlowTypes) {
+		FlowModel flowModel = flowInstanceService.get(id);
+		flowModel.setYuiFlowTypes(yuiFlowTypes);
+		flowInstanceService.updateflowModel(flowModel);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "协同流程同施工方流程绑定", notes = "协同流程同施工方流程绑定")
+	@RequestMapping(value = "/binding/flowModel/construction/{id}/{constructionFlowTypes}", method = RequestMethod.POST)
+	public Response bindingFlowModelByConstruction(@PathVariable int id, @PathVariable String constructionFlowTypes) {
+		FlowModel flowModel = flowInstanceService.get(id);
+		flowModel.setConstructionFlowTypes(constructionFlowTypes);
+		flowInstanceService.updateflowModel(flowModel);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "获取流程样例列表", notes = "获取流程样例列表")
+	@RequestMapping(value = "flow/", method = RequestMethod.GET)
+	public Response getAll() {
+		return Response.ok(flowInstanceService.getAllFlowModel());
+	}
+	
+	@ApiOperation(value = "根据organizationType获取流程样例列表", notes = "根据organizationType获取流程样例列表")
+	@RequestMapping(value = "flow/organizationType/{organizationType}", method = RequestMethod.GET)
+	public Response getByOrganizationType(@PathVariable int organizationType) {
+		return Response.ok(flowInstanceService.getAllFlowModel(organizationType));
+	}
+	
+	@ApiOperation(value = "根据yuiProjectId获取流程样例列表", notes = "根据yuiProjectId获取流程样例列表")
+	@RequestMapping(value = "flow/projectFromYui/{yuiProjectId}", method = RequestMethod.GET)
+	public Response getProjectFromYuiAll(@PathVariable long yuiProjectId) {
+		return Response.ok(flowInstanceService.getProjectFromYuiAll(yuiProjectId));
+	}
+
+	@ApiOperation(value = "获取流程样例", notes = "获取流程样例")
+	@RequestMapping(value = "flow/{id}", method = RequestMethod.GET)
+	public Response get(@PathVariable long id) {
+		return Response.ok(flowInstanceService.get(id));
+	}
+
+	@ApiOperation(value = "根据项目ID获取流程设置", notes = "根据项目ID获取流程设置")
+	@RequestMapping(value = "project/{projectId}/{projectItemId}/flowInstance/", method = RequestMethod.GET)
+	public Response getAll(@PathVariable long projectId, @PathVariable long projectItemId) {
+		return Response.ok(flowInstanceService.getAllFlowInstance(projectId, projectItemId));
+	}
+
+	@ApiOperation(value = "根据项目ID开启流程", notes = "根据项目ID开启流程")
+	@RequestMapping(value = "project/{projectId}/{projectItemId}/flowInstance/", method = RequestMethod.POST)
+	public Response enable(@PathVariable long projectId, @PathVariable long projectItemId) {
+		flowInstanceService.enableFlow(projectId, projectItemId);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "获取流程模板信息", notes = "获取流程模板信息")
+	@RequestMapping(value = "project/{projectId}/flowInstance/{flowInstanceId}", method = RequestMethod.GET)
+	public Response getFlowInstance(@PathVariable long projectId, @PathVariable long flowInstanceId) {
+		// TODO check the project and flow
+		return Response.ok(flowInstanceService.getInstance(flowInstanceId));
+	}
+	
+	@ApiOperation(value = "设置流程模板节点", notes = "设置流程模板节点")
+	@RequestMapping(value = "project/{projectId}/flowInstance/{flowInstanceId}", method = RequestMethod.POST)
+	public Response updateFlowInstanceNode(@RequestBody FlowInstanceNode node){
+		//TODO check the project and flow 
+		return Response.ok(flowInstanceService.updateInstanceNode(node));
+
+	}
+	
+	@ApiOperation(value = "新增节点", notes = "新增节点")
+	@RequestMapping(value = "flowInstanceNode", method = RequestMethod.POST)
+	public Response insertInstanceNode(@RequestBody FlowInstanceNode flowInstanceNode) {
+		return Response.ok(flowInstanceService.insertInstanceNode(flowInstanceNode));
+	}
+
+	@ApiOperation(value = "更新节点", notes = "更新节点")
+	@RequestMapping(value = "flowInstanceNode", method = RequestMethod.PUT)
+	public Response updateInstanceNode(@RequestBody FlowInstanceNode flowInstanceNode) {
+		flowInstanceService.updateInstanceNode(flowInstanceNode);
+		return Response.ok(flowInstanceNode);
+	}
+
+	@ApiOperation(value = "删除节点", notes = "删除节点")
+	@RequestMapping(value = "flowInstanceNode/{id}", method = RequestMethod.DELETE)
+	public Response deleteInstanceNode(@PathVariable long id) {
+		flowInstanceService.deleteInstanceNode(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "更新节点状态", notes = "更新节点状态")
+	@RequestMapping(value = "flowInstanceNode/{id}", method = RequestMethod.PUT)
+	public Response updateFlowInstanceNodeStatus(@PathVariable long id){
+		return Response.ok(flowInstanceService.updateFlowInstanceNodeStatus(id));
+	}
+
+	@ApiOperation(value = "更新组织对应的审核步骤", notes = "更新组织对应的审核步骤")
+	@RequestMapping(value = "/{organizationType}/{flowType}", method = RequestMethod.POST)
+	public Response updateFlowUserList(@PathVariable long organizationType, @PathVariable long flowType, @RequestBody FlowApproverListDto dto) {
+		flowInstanceService.updateFlowUserList(organizationType, flowType, dto);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "更新提交者", notes = "更新提交者")
+	@RequestMapping(value = "/{organizationType}/{flowType}", method = RequestMethod.PUT)
+	public Response updateFlowUserListToSubmitter(@PathVariable long organizationType, @PathVariable long flowType, @RequestBody FlowApproverListDto dto) {
+		flowInstanceService.updateFlowUserListToSubmitter(flowType, dto);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "根据单位工程获取单个组织对应的审核步骤", notes = "根据单位工程获取单个组织对应的审核步骤")
+	@RequestMapping(value = "projectItem/{projectItemId}/{organizationType}/{flowType}", method = RequestMethod.GET)
+	public Response getFlowUserList(@PathVariable long projectItemId, @PathVariable long organizationType, @PathVariable long flowType) {
+		return Response.ok(JSON.parse(flowInstanceService.getFlowUserList(projectItemId, organizationType, flowType)));
+	}
+	
+	@ApiOperation(value = "根据有极系统中单位工程获取包含的所有流程", notes = "根据有极系统中单位工程获取包含的所有流程")
+	@RequestMapping(value = "projectItemFromYui/{projectItemId}", method = RequestMethod.GET)
+	public Response getAllFlowFromYui(@PathVariable long projectItemId) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getAllFlowFromYui(projectItemId)));
+	}
+	
+	@ApiOperation(value = "根据有极系统中单位工程flowType获取包含的单个或多个流程", notes = "根据有极系统中单位工程flowType获取包含的单个或多个流程")
+	@RequestMapping(value = "projectItemFromYui/{projectItemId}/{flowType}", method = RequestMethod.GET)
+	public Response getOnlyFlowFromYui(@PathVariable long projectItemId, @PathVariable String flowType) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getOnlyFlowFromYui(projectItemId, flowType)));
+	}
+	
+	@ApiOperation(value = "根据施工方单位工程flowType获取包含的单个或多个流程", notes = "根据施工方单位工程flowType获取包含的单个或多个流程")
+	@RequestMapping(value = "projectItemFromConstruction/{projectItemId}/{flowType}", method = RequestMethod.GET)
+	public Response getOnlyFlowFromConstruction(@PathVariable long projectItemId, @PathVariable String flowType) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getOnlyFlowFromConstruction(projectItemId, flowType)));
+	}
+	
+	@ApiOperation(value = "根据协同系统中单位工程flowType获取包含的单个流程", notes = "根据协同系统中单位工程flowType获取包含的单个流程")
+	@RequestMapping(value = "projectItemFromCoordination/{projectItemId}/{flowType}", method = RequestMethod.GET)
+	public Response getOnlyFlow(@PathVariable long projectItemId, @PathVariable long flowType) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getOnlyFlow(projectItemId, flowType)));
+	}
+	
+	@ApiOperation(value = "根据协同系统中单位工程flowType获取包含的单个流程2", notes = "根据协同系统中单位工程flowType获取包含的单个流程2")
+	@RequestMapping(value = "projectItemFromCoordination2/{projectItemId}/{flowType}", method = RequestMethod.GET)
+	public Response getOnlyFlow2(@PathVariable long projectItemId, @PathVariable long flowType) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getOnlyFlow2(projectItemId, flowType)));
+	}
+	
+	@ApiOperation(value = "根据协同系统中项目flowType获取包含的单个流程", notes = "根据协同系统中项目flowType获取包含的单个流程")
+	@RequestMapping(value = "projectFromCoordination/{projectItemId}/{flowType}", method = RequestMethod.GET)
+	public Response getProjectOnlyFlow(@PathVariable long projectItemId, @PathVariable long flowType) {
+		return Response.ok(JSON.toJSON(flowInstanceService.getProjectOnlyFlow(projectItemId, flowType)));
+	}
+
+	@ApiOperation(value = "根据id获取有极流程数据", notes = "根据id获取有极流程数据")
+	@RequestMapping(value = "flowYuiDataFromYui/details/{id}", method = RequestMethod.GET)
+	public Response getFlowYuiDataById(@PathVariable long id) {
+		return Response.ok(flowInstanceService.getFlowYuiData(id));
+	}
+	
+	@ApiOperation(value = "根据projectFlowId获取有极流程数据", notes = "根据projectFlowId获取有极流程数据")
+	@RequestMapping(value = "flowYuiDataFromYui/projectFlow/{projectFlowId}", method = RequestMethod.GET)
+	public Response getFlowYuiDataByProjectFlowId(@PathVariable long projectFlowId) {
+		return Response.ok(flowInstanceService.getByProjectFlowId(projectFlowId));
+	}
+	
+	@ApiOperation(value = "有极流程数据新增", notes = "有极流程数据新增")
+	@RequestMapping(value = "flowYuiDataFromYui/", method = RequestMethod.POST)
+	public Response insertFlowYuiData(
+		@RequestParam(value="flowId", required=true) long flowId, 
+		@RequestParam(value="flowName", required=true) String flowName,
+		@RequestParam(value="flowType", required=true) int flowType,
+		@RequestParam(value="yuiFlowType", required=true) int yuiFlowType,
+		@RequestParam(value="yuiProjectId", required=true) int yuiProjectId,
+		@RequestParam(value="yuiProjectItemId", required=true) long yuiProjectItemId,
+		@RequestParam(value="yuiProjectItemTargetId", required=false) Long yuiProjectItemTargetId,
+		@RequestParam(value="yuiProjectFlowId", required=false) Long yuiProjectFlowId,
+		@RequestParam(value="coment", required=false) String coment, 
+		@RequestParam(value="content", required=true) String content, 
+		@RequestParam(value="flowTemplateId", required=false) Long flowTemplateId,
+		@RequestParam(value="flowUserList", required=true) String flowUserList) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setDate(new Date());
+		flowYuiData.setFlowId(flowId);
+		flowYuiData.setFlowName(flowName);
+		flowYuiData.setFlowType(flowType);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		flowYuiData.setYuiProjectItemId(yuiProjectItemId);
+		flowYuiData.setYuiProjectItemTargetId(yuiProjectItemTargetId == null ? 0 : yuiProjectItemTargetId);
+		flowYuiData.setYuiProjectFlowId(yuiProjectFlowId == null ? 0 : yuiProjectFlowId);
+		flowYuiData.setComent(coment);
+		flowYuiData.setContent(content);
+		flowYuiData.setFlowTemplateId(flowTemplateId == null ? 0 : flowTemplateId);
+		flowYuiData.setFlowUserList(flowUserList);
+		flowInstanceService.insertFlowYuiData(flowYuiData);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "通过youjiProjectFlowId获取thisProjectFlowId", notes = "通过youjiProjectFlowId获取thisProjectFlowId")
+	@RequestMapping(value = "flowYuiDataFromYui/youjiProjectFlowId/{youjiProjectFlowId}", method = RequestMethod.GET)
+	public Response getProjectFlowId(@PathVariable long youjiProjectFlowId) {
+		return Response.ok(flowInstanceService.getProjectFlowId(youjiProjectFlowId));
+	}
+	
+	@ApiOperation(value = "有极流程数据yuiProjectItemTargetId查询", notes = "有极流程数据yuiProjectItemTargetId查询")
+	@RequestMapping(value = "flowYuiDataFromYui/{yuiFlowType}/{yuiProjectItemTargetId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataListByTargetId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectItemTargetId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectItemTargetId(yuiProjectItemTargetId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "有极流程数据yuiProjectItemId查询", notes = "有极流程数据yuiProjectItemId查询")
+	@RequestMapping(value = "flowYuiDataFromYui/{yuiFlowType}/itemId/{yuiProjectItemId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataListByItemId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectItemId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectItemId(yuiProjectItemId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "有极流程数据yuiProjectId查询", notes = "有极流程数据yuiProjectId查询")
+	@RequestMapping(value = "flowYuiDataFromYui/{yuiFlowType}/projectId/{yuiProjectId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataListByProjectId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "有极流程数据编辑", notes = "有极流程数据编辑")
+	@RequestMapping(value = "flowYuiDataFromYui/", method = RequestMethod.PUT)
+	public Response updateFlowYuiData(@RequestBody FlowYuiData flowYuiData) {
+		flowInstanceService.updateFlowYuiData(flowYuiData);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "根据yuiProjectId有极流程数据查询", notes = "根据yuiProjectId有极流程数据查询")
+	@RequestMapping(value = "fromYui/{yuiProjectId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataListByYuiProjectId(@PathVariable long yuiProjectId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "根据yuiFlowType和yuiProjectId有极流程数据查询", notes = "根据yuiFlowType和yuiProjectId有极流程数据查询")
+	@RequestMapping(value = "fromYui/{yuiFlowType}/{yuiProjectId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataListByYuiFlowType(@PathVariable int yuiFlowType, @PathVariable long yuiProjectId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "根据flowTemplateId查询协同流程数据", notes = "根据flowTemplateId查询协同流程数据")
+	@RequestMapping(value = "fromYuiByFlowTemplateId/{yuiProjectId}/{flowTemplateId}/", method = RequestMethod.GET)
+	public Response getFlowYuiDataByFlowTemplateId(@PathVariable long yuiProjectId, @PathVariable long flowTemplateId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(-1);
+		flowYuiData.setYuiFlowType(-1);
+		flowYuiData.setFlowTemplateId(flowTemplateId);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "更新状态", notes = "更新状态")
+	@RequestMapping(value = "flowYuiDataFromYui/{id}/projectFlow/{projectFlowId}", method = RequestMethod.PUT)
+	public Response updateFlowYuiDataStatus(@PathVariable long id, @PathVariable long projectFlowId) {
+		flowInstanceService.updateFlowYuiDataStatus(id, projectFlowId);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "恢复状态", notes = "恢复状态")
+	@RequestMapping(value = "flowYuiDataFromYui/restore/{id}", method = RequestMethod.PUT)
+	public Response restoreFlowYuiDataStatus(@PathVariable long id) {
+		flowInstanceService.restoreFlowYuiDataStatus(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "根据organizationId获取有极流程数据", notes = "根据organizationId获取有极流程数据")
+	@RequestMapping(value = "flowYuiDataFromYui/{organizationId}", method = RequestMethod.GET)
+	public Response getFlowYuiData(@PathVariable long organizationId) {
+		return Response.ok(flowInstanceService.getFlowYuiDataByFlowId(organizationId));
+	}
+	
+	@ApiOperation(value = "获取TargetId已提交projectFlowId", notes = "获取TargetId已提交projectFlowId")
+	@RequestMapping(value = "flowYuiDataFromYui/document/{yuiFlowType}/{yuiProjectItemTargetId}/", method = RequestMethod.GET)
+	public Response getCommitedByProjectFlowIdByTargetId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectItemTargetId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectItemTargetId(yuiProjectItemTargetId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "获取ItemId已提交projectFlowId", notes = "获取ItemId已提交projectFlowId")
+	@RequestMapping(value = "flowYuiDataFromYui/document/{yuiFlowType}/ItemId/{yuiProjectItemId}/", method = RequestMethod.GET)
+	public Response getCommitedByProjectFlowIdByItemId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectItemId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectItemId(yuiProjectItemId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "获取ProjectId已提交projectFlowId", notes = "获取ProjectId已提交projectFlowId")
+	@RequestMapping(value = "flowYuiDataFromYui/document/{yuiFlowType}/ProjectId/{yuiProjectId}/", method = RequestMethod.GET)
+	public Response getCommitedByProjectFlowIdByProjectId(@PathVariable int yuiFlowType, @PathVariable long yuiProjectId) {
+		FlowYuiData flowYuiData = new FlowYuiData();
+		flowYuiData.setStatus(1);
+		flowYuiData.setYuiFlowType(yuiFlowType);
+		flowYuiData.setYuiProjectId(yuiProjectId);
+		return Response.ok(flowInstanceService.getListByFlowYuiData(flowYuiData));
+	}
+	
+	@ApiOperation(value = "获取已完成流程中documentIds", notes = "获取已完成流程中documentIds")
+	@RequestMapping(value = "flowYuiDataFromYui/document/{projectFlowIds}/", method = RequestMethod.GET)
+	public Response getFlowFinishDocumentIds(@PathVariable String projectFlowIds) {
+		return Response.ok(flowInstanceService.getFlowFinishDocumentIds(projectFlowIds));
+	}
+	
+	@ApiOperation(value = "统计流程状态", notes = "统计流程状态")
+	@RequestMapping(value = "flowYuiDataFromYui/peojectFlow/{yuiProjectId}/{yuiFlowTypes}/", method = RequestMethod.GET)
+	public Response statisticalProcessState(@PathVariable long yuiProjectId, @PathVariable String yuiFlowTypes) {
+		return Response.ok(flowInstanceService.statisticalProcessState(yuiProjectId, yuiFlowTypes));
+	}
+
+	//===================================================================================================
+
+	@ApiOperation(value = "流程用户配置", notes = "流程用户配置")
+	@RequestMapping(value = "/flowUserConfig", method = RequestMethod.POST)
+	public Response saveOrUpdateFlowUserConfig(@RequestBody FlowUserConfig flowUserConfig) {
+		flowUserConfigService.saveOrUpdateFlowUserConfig(flowUserConfig);
+		return Response.ok(flowUserConfig);
+	}
+
+	@ApiOperation(value = "获取流程用户配置", notes = "获取流程用户配置")
+	@RequestMapping(value = "/flowUserConfig/{projectId}/{userId}", method = RequestMethod.GET)
+	public Response getFlowUserConfig(@PathVariable long projectId, @PathVariable long userId) {
+		return Response.ok(flowUserConfigService.getUserProjectId(userId, projectId));
+	}
+
+}

+ 177 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/FlowSynergyDataController.java

@@ -0,0 +1,177 @@
+package com.bosshand.virgo.api.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.bosshand.virgo.api.model.FlowSynergyData;
+import com.bosshand.virgo.api.service.FlowSynergyDataService;
+import com.bosshand.virgo.api.service.InspectService;
+import com.bosshand.virgo.api.service.PointToPointService;
+import com.bosshand.virgo.api.service.SignOnBehalfService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("flowSynergy")
+public class FlowSynergyDataController {
+
+	@Autowired
+	FlowSynergyDataService flowSynergyDataService;
+
+	@Autowired
+	InspectService inspectService;
+
+	@Autowired
+	PointToPointService pointToPointService;
+
+	@Autowired
+	SignOnBehalfService signOnBehalfService;
+
+	@ApiOperation(value = "协同流程查询", notes = "协同流程查询")
+	@RequestMapping(value = "/list", method = RequestMethod.POST)
+	public Response list(@RequestBody FlowSynergyData flowSynergyData) {
+		return Response.ok(flowSynergyDataService.getListAll(flowSynergyData));
+	}
+
+	@ApiOperation(value = "协同流程待办数据", notes = "协同流程待办数据")
+	@RequestMapping(value = "/stay/{projectId}", method = RequestMethod.GET)
+	public Response stay(@PathVariable long projectId) {
+		return Response.ok(flowSynergyDataService.stay(projectId));
+	}
+
+	@ApiOperation(value = "项目中心的记录查询", notes = "项目中心的记录查询")
+	@RequestMapping(value = "/query/list", method = RequestMethod.POST)
+	public Response listQuery(@RequestBody FlowSynergyData flowSynergyData) {
+		return Response.ok(flowSynergyDataService.listQuery(flowSynergyData));
+	}
+
+	@ApiOperation(value = "当前用户有查看记录权限", notes = "当前用户有查看记录权限")
+	@RequestMapping(value = "/judge/{id}", method = RequestMethod.GET)
+	public Response judge(@PathVariable long id) {
+		FlowSynergyData flowSynergyData = flowSynergyDataService.judge(id);
+		if (flowSynergyData != null) {
+			return Response.ok(flowSynergyData);
+		}
+		return Response.fail(200001, "该用户没有查看权限");
+	}
+
+	@ApiOperation(value = "协同流程统计查询", notes = "协同流程统计查询")
+	@RequestMapping(value = "/census", method = RequestMethod.POST)
+	public Response census(@RequestParam(value="startDate", required=true) String startDate,
+						   @RequestParam(value="endDate", required=true) String endDate,
+						   @RequestParam(value="projectId", required=true) long projectId,
+						   @RequestParam(value="projectItemId", required=true) long projectItemId,
+						   @RequestParam(value="flowType", required=true) int flowType) {
+		return Response.ok(flowSynergyDataService.census(startDate,endDate,projectId,projectItemId,flowType));
+	}
+
+	@ApiOperation(value = "协同流程统计多个flowType查询", notes = "协同流程统计多个flowType查询")
+	@RequestMapping(value = "/censusByFlowTypes", method = RequestMethod.POST)
+	public Response censusByFlowTypes(@RequestParam(value="startDate", required=true) String startDate,
+						   @RequestParam(value="endDate", required=true) String endDate,
+						   @RequestParam(value="projectId", required=true) long projectId,
+						   @RequestParam(value="flowTypes", required=true) String flowTypes) {
+		return Response.ok(flowSynergyDataService.censusByFlowTypes(startDate,endDate,projectId,flowTypes));
+	}
+
+	@ApiOperation(value = "协同流程分页查询", notes = "协同流程分页查询")
+	@RequestMapping(value = "/list/{currPage}/{pageSize}", method = RequestMethod.POST)
+	public Response listLimit(@RequestBody FlowSynergyData flowSynergyData, @PathVariable int currPage, @PathVariable int pageSize) {
+		List<FlowSynergyData> list = flowSynergyDataService.getList(flowSynergyData);
+		List<FlowSynergyData> dataList = list.stream().skip((currPage - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
+		Map<String, Object> result = new HashMap<>();
+		result.put("dataList", dataList);
+		result.put("totalCount", list.size());
+		return Response.ok(result);
+	}
+
+	@ApiOperation(value = "消息中心统计", notes = "消息中心统计")
+	@RequestMapping(value = "/censusSum/{projectId}", method = RequestMethod.GET)
+	public Response censusType(@PathVariable long projectId) {
+		long userId = ContextUtils.getCurrentUser().getId();
+		JSONObject json = new JSONObject();
+		JSONObject jo = inspectService.censusInspect(-projectId);
+		json.put("inspect", jo.getIntValue("create")
+				+ jo.getIntValue("receive")
+				+ jo.getIntValue("cc"));
+		JSONObject ja = pointToPointService.census(projectId);
+		json.put("pointToPoint", ja.getIntValue("create")
+				+ ja.getIntValue("receive")
+				+ ja.getIntValue("cc"));
+		json.put("process", flowSynergyDataService.censusSum(projectId, userId));
+		JSONObject stay = inspectService.stay(-projectId, userId);
+		JSONObject stay1 = flowSynergyDataService.stay(projectId);
+		JSONObject stay2 = pointToPointService.stay(projectId);
+		JSONObject stay3 = signOnBehalfService.stay(projectId, userId);
+		json.put("stay", stay.getJSONArray("stayReply").size()
+				+ stay.getJSONArray("stayWriteOff").size()
+				+ stay1.getJSONArray("submitList").size()
+				+ stay1.getJSONArray("returnList").size()
+				+ stay1.getJSONArray("examineList").size()
+				+ stay2.getJSONArray("staySignIn").size()
+				+ stay2.getJSONArray("stayReceipt").size()
+				+ stay2.getJSONArray("staySubmit").size()
+				+ stay3.getJSONArray("send").size()
+				+ stay3.getJSONArray("receive").size());
+		return Response.ok(json);
+	}
+
+	@ApiOperation(value = "协同流程类型统计分页查询", notes = "协同流程类型统计分页查询")
+	@RequestMapping(value = "/census/{projectId}/{type}/{currPage}/{pageSize}", method = RequestMethod.POST)
+	public Response listCensusLimit(@PathVariable long projectId,
+									@PathVariable int type,
+									@PathVariable int currPage,
+									@PathVariable int pageSize) {
+		long userId = ContextUtils.getCurrentUser().getId();
+		List<FlowSynergyData> list = flowSynergyDataService.getListByProject(type, projectId, userId);
+		List<FlowSynergyData> dataList = list.stream().skip((currPage - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
+		Map<String, Object> result = new HashMap<>();
+		result.put("dataList", dataList);
+		result.put("totalCount", list.size());
+		return Response.ok(result);
+	}
+	
+	@ApiOperation(value = "协同流程按照flowType查询", notes = "协同流程按照flowType查询")
+	@RequestMapping(value = "/list/{projectId}/{flowTypes}", method = RequestMethod.GET)
+	public Response listByFlowType(@PathVariable long projectId, @PathVariable String flowTypes) {
+		return Response.ok(flowSynergyDataService.getListByFlowType(projectId,flowTypes));
+	}
+
+	@ApiOperation(value = "协同流程新增", notes = "协同流程新增")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insert(@RequestBody FlowSynergyData flowSynergyData) {
+		MgrUser user = ContextUtils.getCurrentUser() ;
+		flowSynergyData.setCreatedByUserId(user.getId());
+		flowSynergyData.setCreatedByUserName(user.getName());
+		return Response.ok(flowSynergyDataService.insert(flowSynergyData));
+	}
+
+	@ApiOperation(value = "协同流程删除", notes = "协同流程删除")
+	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+	public Response delete(@PathVariable long id) {
+		flowSynergyDataService.delete(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "协同流程更新", notes = "协同流程更新")
+	@RequestMapping(value = "/", method = RequestMethod.PUT)
+	public Response update(@RequestBody FlowSynergyData flowSynergyData) {
+		flowSynergyDataService.update(flowSynergyData);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "协同流程更新状态", notes = "协同流程更新状态")
+	@RequestMapping(value = "/state", method = RequestMethod.PUT)
+	public Response updateState(@RequestBody FlowSynergyData flowSynergyData) {
+		flowSynergyDataService.updateState(flowSynergyData);
+		return Response.ok();
+	}
+
+}

+ 113 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/InspectController.java

@@ -0,0 +1,113 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.Inspect;
+import com.bosshand.virgo.api.service.InspectService;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+
+@RestController
+@RequestMapping("inspect")
+public class InspectController {
+
+	@Autowired
+	private InspectService inspectService;
+
+	@ApiOperation(value = "巡查详情", notes = "巡查详情")
+	@RequestMapping(value = "/detail/{id}", method = RequestMethod.GET)
+	public Response getInspect(@PathVariable long id) {
+		return Response.ok(inspectService.getInspect(id));
+	}
+
+	@ApiOperation(value = "根据类型获取巡查列表", notes = "根据类型获取巡查列表")
+	@RequestMapping(value = "/{inspectType}/{yuiProjectId}", method = RequestMethod.GET)
+	public Response getByInspectType(@PathVariable int inspectType, @PathVariable long yuiProjectId) {
+		return Response.ok(inspectService.getByInspectType(inspectType, yuiProjectId));
+	}
+
+	@ApiOperation(value = "统计巡查", notes = "统计巡查")
+	@RequestMapping(value = "/census/{yuiProjectId}", method = RequestMethod.GET)
+	public Response censusInspect(@PathVariable long yuiProjectId) {
+		return Response.ok(inspectService.censusInspect(yuiProjectId));
+	}
+
+	@ApiOperation(value = "企业间公开的已销项巡查列表", notes = "企业间公开的已销项巡查列表")
+	@RequestMapping(value = "/open", method = RequestMethod.POST)
+	public Response getByInspectOpen(@RequestBody Inspect inspect) {
+		inspect.setIsRed(2);
+		return Response.ok(inspectService.getByInspect(inspect));
+	}
+
+	@ApiOperation(value = "与自己相关的已销项巡查列表", notes = "与自己相关的已销项巡查列表")
+	@RequestMapping(value = "/oneself", method = RequestMethod.POST)
+	public Response getByInspectSelf(@RequestBody Inspect inspect) {
+		long userId = ContextUtils.getCurrentUser().getId();
+		return Response.ok(inspectService.getByInspectSelf(inspect, userId));
+	}
+
+	@ApiOperation(value = "与自己相关的待办巡查列表", notes = "与自己相关的待办巡查列表")
+	@RequestMapping(value = "/oneself/{yuiProjectId}", method = RequestMethod.GET)
+	public Response stay(@PathVariable long yuiProjectId) {
+		long userId = ContextUtils.getCurrentUser().getId();
+		return Response.ok(inspectService.stay(yuiProjectId, userId));
+	}
+
+	@ApiOperation(value = "新增巡查", notes = "新增巡查")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insertInspect(@RequestParam(value = "inspectType", required = false) Integer inspectType,
+			@RequestParam(value = "yuiProjectId", required = false) Long yuiProjectId,
+			@RequestParam(value = "yuiProjectItemId", required = false) Long yuiProjectItemId,
+			@RequestParam(value = "yuiProjectItemName", required = false) String yuiProjectItemName,
+			@RequestParam(value = "isRed", required = false) Integer isRed,
+			@RequestParam(value = "status", required = false) Integer status,
+			@RequestParam(value = "approveList", required = false) String approveList,
+			@RequestParam(value = "content", required = false) String content) {
+		Inspect inspect = new Inspect();
+		inspect.setDate(new Date());
+		inspect.setInspectType(inspectType == null ? 0 : inspectType);
+		inspect.setYuiProjectId(yuiProjectId == null ? 0 : yuiProjectId);
+		inspect.setYuiProjectItemId(yuiProjectItemId == null ? 0 : yuiProjectItemId);
+		inspect.setYuiProjectItemName(yuiProjectItemName);
+		inspect.setIsRed(isRed == null ? 0 : isRed);
+		inspect.setStatus(status == null ? 0 : status);
+		inspect.setApproveList(approveList);
+		inspect.setContent(content);
+		inspectService.addInspect(inspect);
+		return Response.ok(inspect);
+	}
+
+	@ApiOperation(value = "删除巡查", notes = "删除巡查")
+	@RequestMapping(value = "/", method = RequestMethod.DELETE)
+	public Response deleteInspect(@PathVariable long id) {
+		inspectService.deleteInspect(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "修改巡查", notes = "修改巡查")
+	@RequestMapping(value = "/", method = RequestMethod.PUT)
+	public Response updateInspect(@RequestParam(value = "id", required = true) long id,
+			@RequestParam(value = "yuiProjectId", required = false) Long yuiProjectId,
+			@RequestParam(value = "yuiProjectItemId", required = false) Long yuiProjectItemId,
+			@RequestParam(value = "yuiProjectItemName", required = false) String yuiProjectItemName,
+			@RequestParam(value = "isRed", required = false) Integer isRed,
+			@RequestParam(value = "status", required = false) Integer status,
+			@RequestParam(value = "approveList", required = false) String approveList,
+			@RequestParam(value = "content", required = false) String content) {
+		Inspect inspect = new Inspect();
+		inspect.setId(id);
+		inspect.setYuiProjectId(yuiProjectId == null ? 0 : yuiProjectId);
+		inspect.setYuiProjectItemId(yuiProjectItemId == null ? 0 : yuiProjectItemId);
+		inspect.setYuiProjectItemName(yuiProjectItemName);
+		inspect.setIsRed(isRed == null ? 0 : isRed);
+		inspect.setStatus(status == null ? 0 : status);
+		inspect.setApproveList(approveList);
+		inspect.setContent(content);
+		inspectService.updateInspect(inspect);
+		return Response.ok();
+	}
+
+}

+ 76 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/MaterialBatchController.java

@@ -0,0 +1,76 @@
+package com.bosshand.virgo.api.controller;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.model.MaterialBatch;
+import com.bosshand.virgo.api.service.MaterialBatchService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+public class MaterialBatchController {
+
+	@Autowired
+	private MaterialBatchService materialBatchService;
+
+	@ApiOperation(value = "新增", notes = "新增")
+	@RequestMapping(value = "materialbatch", method = RequestMethod.POST)
+	public Response addMaterialBatch(@RequestBody MaterialBatch materialBatch) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		materialBatch.setCreateBy(user.getName());
+		materialBatch.setCreateByUserId(user.getId());
+		return Response.ok(materialBatchService.save(materialBatch));
+	}
+
+	@ApiOperation(value = "编辑", notes = "编辑")
+	@RequestMapping(value = "materialbatch", method = RequestMethod.PUT)
+	public Response editMaterialBatch(@RequestBody MaterialBatch materialBatch) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		materialBatch.setCreateBy(user.getName());
+		materialBatch.setCreateByUserId(user.getId());
+		return Response.ok(materialBatchService.update(materialBatch));
+	}
+
+	@ApiOperation(value = "删除", notes = "删除")
+	@RequestMapping(value = "materialbatch/{id}", method = RequestMethod.DELETE)
+	public Response delMaterialBatch(@PathVariable long id) {
+		materialBatchService.delete(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "查询列表", notes = "查询列表")
+	@RequestMapping(value = "materialbatch/queryList", method = RequestMethod.POST)
+	public Response getMaterialBatchByList(@RequestBody MaterialBatch materialBatch) {
+		return Response.ok(materialBatchService.queryByList(materialBatch));
+	}
+	
+	@ApiOperation(value = "查询", notes = "查询")
+	@RequestMapping(value = "materialbatch/query", method = RequestMethod.POST)
+	public Response getMaterialBatchByProjectId(@RequestBody MaterialBatch materialBatch) {
+		return Response.ok(materialBatchService.query(materialBatch));
+	}
+	
+	@ApiOperation(value = "分页查询", notes = "分页查询")
+	@RequestMapping(value = "materialbatch/query/{currPage}/{pageSize}", method = RequestMethod.POST)
+	public Response getMaterialBatchByProjectId(@RequestBody MaterialBatch materialBatch, @PathVariable int currPage, @PathVariable int pageSize) {
+		List<MaterialBatch> list = materialBatchService.query(materialBatch, currPage, pageSize);
+		List<MaterialBatch> totalCount = materialBatchService.query(materialBatch);
+		Map<String, Object> result = new HashMap<String, Object>();
+		result.put("dataList", list);
+		result.put("totalCount", totalCount.size());
+		return Response.ok(result);
+	}
+
+}

+ 44 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/MaterialCheckController.java

@@ -0,0 +1,44 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.MaterialCheck;
+import com.bosshand.virgo.api.service.MaterialCheckService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("materialcheck")
+public class MaterialCheckController {
+
+    @Autowired
+    private MaterialCheckService materialcheckService;
+
+    @ApiOperation(value = "查询", notes = "查询")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    public Response getList(@RequestBody MaterialCheck materialCheck) {
+        return Response.ok(materialcheckService.getList(materialCheck));
+    }
+
+    @ApiOperation(value = "新增", notes = "新增")
+    @RequestMapping(value = "", method = RequestMethod.POST)
+    public Response add(@RequestBody MaterialCheck materialCheck) {
+        materialcheckService.save(materialCheck);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "编辑", notes = "编辑")
+    @RequestMapping(value = "", method = RequestMethod.PUT)
+    public Response edit(@RequestBody MaterialCheck materialCheck) {
+        materialcheckService.update(materialCheck);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "删除", notes = "删除")
+    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+    public Response edit(@PathVariable long id) {
+        materialcheckService.delete(id);
+        return Response.ok();
+    }
+
+}

+ 51 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/NoticeController.java

@@ -0,0 +1,51 @@
+package com.bosshand.virgo.api.controller;
+
+import java.util.Date;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.model.Notice;
+import com.bosshand.virgo.api.service.NoticeService;
+import com.bosshand.virgo.core.response.Response;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("notice")
+public class NoticeController {
+
+	@Autowired
+	private NoticeService noticeService;
+
+	@ApiOperation(value = "项目公告", notes = "项目公告")
+	@RequestMapping(value = "/{yuiProjectId}", method = RequestMethod.GET)
+	public Response getNotice(@PathVariable long yuiProjectId) {
+		return Response.ok(noticeService.getByYuiProjectId(yuiProjectId));
+	}
+	
+	@ApiOperation(value = "项目公告删除", notes = "项目公告删除")
+	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+	public Response deleteNotice(@PathVariable long id) {
+		noticeService.deleteNotice(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "项目公告导入", notes = "项目公告导入")
+	@RequestMapping(value = "/noticeImport", method = RequestMethod.POST)
+	public Response insertNotice(
+		@RequestParam(value = "yuiProjectId", required = true) long yuiProjectId,
+		@RequestParam(value = "data", required = true) String data) {
+		Notice notice = new Notice();
+		notice.setDate(new Date());
+		notice.setData(data);
+		notice.setYuiProjectId(yuiProjectId);
+		noticeService.insert(notice);
+		return Response.ok();
+	}
+
+}

+ 111 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/PartItemMetaDataController.java

@@ -0,0 +1,111 @@
+package com.bosshand.virgo.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.metadata.model.PartItemMetaData;
+import com.bosshand.virgo.api.metadata.model.PartItemMetadataFlowNode;
+import com.bosshand.virgo.api.metadata.service.PartItemMetaDataService;
+import com.bosshand.virgo.core.response.Response;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("part")
+public class PartItemMetaDataController {
+
+	@Autowired
+	PartItemMetaDataService partItemMetaDataService;
+
+	@ApiOperation(value = "项目类型", notes = "项目类型")
+	@RequestMapping(value = "/list", method = RequestMethod.GET)
+	public Response list() {
+		return Response.ok(partItemMetaDataService.getParentId(-1));
+	}
+	
+	@ApiOperation(value = "通过parentId获取", notes = "通过parentId获取")
+	@RequestMapping(value = "/list/{parentId}", method = RequestMethod.GET)
+	public Response listByParentId(@PathVariable long parentId) {
+		return Response.ok(partItemMetaDataService.getParentId(parentId));
+	}
+	
+	@ApiOperation(value = "类别树", notes = "类别树")
+	@RequestMapping(value = "/tree/{id}", method = RequestMethod.GET)
+	public Response getTree(@PathVariable long id) {
+		return Response.ok(partItemMetaDataService.getRootPartItemMetaData(id));
+	}
+	
+	@ApiOperation(value = "类别树", notes = "传多个id类别树")
+	@RequestMapping(value = "/tree/list/{ids}", method = RequestMethod.GET)
+	public Response getTree(@PathVariable String ids) {
+		return Response.ok(partItemMetaDataService.getList(ids));
+	}
+	
+	@ApiOperation(value = "最底层类别树", notes = "最底层类别树")
+	@RequestMapping(value = "/tree/checked/{ids}", method = RequestMethod.GET)
+	public Response getOnlyPartItemMetaData(@PathVariable String ids) {
+		return Response.ok(partItemMetaDataService.checked(ids));
+	}
+	
+	@ApiOperation(value = "json", notes = "json")
+	@RequestMapping(value = "/{typeId}", method = RequestMethod.GET)
+	public Response getTypeId(@PathVariable long typeId) {
+		return Response.ok(partItemMetaDataService.getTypeId(typeId));
+	}
+	
+	@ApiOperation(value = "类别树节点修改", notes = "类别树节点修改")
+	@RequestMapping(value = "/tree", method = RequestMethod.PUT)
+	public Response updatePartItemMetaData(@RequestBody PartItemMetaData partItemMetaData) {
+		return Response.ok(partItemMetaDataService.updatePartItemMetaData(partItemMetaData));
+	}
+	
+	@ApiOperation(value = "类别树节点IdentifyType批量修改", notes = "类别树节点IdentifyType批量修改")
+	@RequestMapping(value = "/tree/identifyType/{id}", method = RequestMethod.PUT)
+	public Response updatePartItemMetaDataByIdentifyType(@PathVariable long id) {
+		partItemMetaDataService.updatePartItemMetaDataByIdentifyType(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "类别树节点保存", notes = "类别树节点保存")
+	@RequestMapping(value = "/tree", method = RequestMethod.POST)
+	public Response savePartItemMetaData(@RequestBody PartItemMetaData partItemMetaData) {
+		return Response.ok(partItemMetaDataService.savePartItemMetaData(partItemMetaData));
+	}
+	
+	@ApiOperation(value = "类别树节点删除", notes = "类别树节点删除")
+	@RequestMapping(value = "/tree/{id}", method = RequestMethod.DELETE)
+	public Response deletePartItemMetaData(@PathVariable long id) {
+		partItemMetaDataService.deletePartItemMetaData(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "获取检验批", notes = "获取检验批")
+	@RequestMapping(value = "/partItem/{partItemIds}", method = RequestMethod.GET)
+	public Response getPartItemId(@PathVariable String partItemIds) {
+		return Response.ok(partItemMetaDataService.getPartItemIds(partItemIds));
+	}
+	
+	@ApiOperation(value = "修改检验批", notes = "修改检验批")
+	@RequestMapping(value = "/partItem", method = RequestMethod.PUT)
+	public Response updatePartItemMetadataFlowNode(@RequestBody PartItemMetadataFlowNode partItemMetadataFlowNode) {
+		return Response.ok(partItemMetaDataService.updatePartItemMetadataFlowNode(partItemMetadataFlowNode));
+	}
+	
+	@ApiOperation(value = "保存检验批", notes = "保存检验批")
+	@RequestMapping(value = "/partItem", method = RequestMethod.POST)
+	public Response savePartItemMetadataFlowNode(@RequestBody PartItemMetadataFlowNode partItemMetadataFlowNode){
+		return Response.ok(partItemMetaDataService.savePartItemMetadataFlowNode(partItemMetadataFlowNode));
+	}
+	
+	@ApiOperation(value = "删除检验批", notes = "删除检验批")
+	@RequestMapping(value = "/partItem/{id}", method = RequestMethod.DELETE)
+	public Response deletePartItemMetadataFlowNode(@PathVariable long id) {
+		partItemMetaDataService.deletePartItemMetadataFlowNode(id);
+		return Response.ok();
+	}
+
+}

+ 80 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/PointToPointController.java

@@ -0,0 +1,80 @@
+package com.bosshand.virgo.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.model.PointToPoint;
+import com.bosshand.virgo.api.service.PointToPointService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("pointToPoint")
+public class PointToPointController {
+
+	@Autowired
+	private PointToPointService pointToPointService;
+
+	@ApiOperation(value = "详情", notes = "详情")
+	@RequestMapping(value = "/detail/{id}", method = RequestMethod.GET)
+	public Response getPointToPoint(@PathVariable long id) {
+		return Response.ok(pointToPointService.get(id));
+	}
+
+	@ApiOperation(value = "列表", notes = "列表")
+	@RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+	public Response getList(@PathVariable long projectId) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		return Response.ok(pointToPointService.getList(user.getId(), projectId));
+	}
+
+	@ApiOperation(value = "待办数据", notes = "待办数据")
+	@RequestMapping(value = "/stay/{projectId}", method = RequestMethod.GET)
+	public Response stay(@PathVariable long projectId) {
+		return Response.ok(pointToPointService.stay(projectId));
+	}
+
+	@ApiOperation(value = "统计", notes = "统计")
+	@RequestMapping(value = "/census/{projectId}", method = RequestMethod.GET)
+	public Response census(@PathVariable long projectId) {
+		return Response.ok(pointToPointService.census(projectId));
+	}
+
+	@ApiOperation(value = "新增", notes = "新增")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insert(@RequestBody PointToPoint pointToPoint) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		pointToPoint.setSender(user.getId());
+		pointToPointService.insert(pointToPoint);
+		return Response.ok(pointToPoint);
+	}
+
+	@ApiOperation(value = "修改", notes = "修改")
+	@RequestMapping(value = "/", method = RequestMethod.PUT)
+	public Response update(@RequestBody PointToPoint pointToPoint) {
+		pointToPointService.update(pointToPoint);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "修改状态", notes = "修改状态")
+	@RequestMapping(value = "/{id}/{state}", method = RequestMethod.PUT)
+	public Response updateState(@PathVariable long id, @PathVariable int state) {
+		pointToPointService.updateState(id, state);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "删除", notes = "删除")
+	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+	public Response delete(@PathVariable long id) {
+		pointToPointService.delete(id);
+		return Response.ok();
+	}
+
+}

+ 159 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectController.java

@@ -0,0 +1,159 @@
+package com.bosshand.virgo.api.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.bosshand.virgo.api.model.Project;
+import com.bosshand.virgo.api.service.ProjectService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.AESUtil;
+import com.bosshand.virgo.core.utils.ContextUtils;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+@RequestMapping("project")
+public class ProjectController {
+	
+	@Autowired
+	ProjectService projectService;
+
+	@ApiOperation(value = "项目管理", notes = "项目列表")
+	@RequestMapping(value = "/list", method = RequestMethod.POST)
+	public Response getProjectList(@RequestBody JSONObject parameter) {
+		List<Project> list = projectService.getProjectList(parameter);
+		int totalCount = projectService.getTotalCount(parameter);
+		Map<String, Object> result = new HashMap<String, Object>();
+		result.put("dataList", list);
+		result.put("totalCount", totalCount);
+		return Response.ok(result);
+	}
+
+	@ApiOperation(value = "获取项目中所有集成过的BIM", notes = "获取项目中所有集成过的BIM")
+	@RequestMapping(value = "/getBimByList", method = RequestMethod.GET)
+	public Response getBimByList() {
+		return Response.ok(projectService.getBimByList());
+	}
+
+	@ApiOperation(value = "获取项目下模型列表", notes = "获取项目下模型列表")
+	@RequestMapping(value = "/bimList/{id}", method = RequestMethod.GET)
+	public Response bimList(@PathVariable long id) {
+		return Response.ok(projectService.bimList(id));
+	}
+	
+	@ApiOperation(value = "项目管理", notes = "项目名称")
+	@RequestMapping(value = "/getProjectName/{yuiProjectId}", method = RequestMethod.GET)
+	public Response getProjectName(@PathVariable long yuiProjectId) {
+		return Response.ok(projectService.getByYuiProjectId(yuiProjectId));
+	}
+	
+	@ApiOperation(value = "项目管理", notes = "项目修改")
+	@RequestMapping(value = "/update", method = RequestMethod.PUT)
+	public Response updateProject(@RequestBody Project project) {
+		projectService.updateProject(project);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "项目管理", notes = "项目删除")
+	@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
+	public Response deleteProject(@PathVariable long id) {
+		projectService.deleteProject(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "项目管理", notes = "项目详情")
+	@RequestMapping(value = "/{organizationId}/{id}", method = RequestMethod.GET)
+	public Response getProject(@PathVariable long organizationId, @PathVariable long id) {
+		Project project = projectService.get(id);
+		return Response.ok(project);
+	}
+
+	@ApiOperation(value = "项目管理", notes = "获取项目")
+	@RequestMapping(value = "/getProject/{id}", method = RequestMethod.GET)
+	public Response getProject(@PathVariable long id) {
+		return Response.ok(projectService.getProject(id));
+	}
+
+	@ApiOperation(value = "项目管理", notes = "项目新增")
+	@RequestMapping(value = "/{organizationId}/", method = RequestMethod.POST)
+	public Response insertProject(@PathVariable long organizationId, @RequestBody Project project) {
+		project.setOrganizationId(organizationId);
+		projectService.insert(project);
+		return Response.ok(project);
+	}
+
+	@ApiOperation(value = "运营项目管理", notes = "运营项目新增")
+	@RequestMapping(value = "/operate/{operateOrganizationId}", method = RequestMethod.POST)
+	public Response insertOperateProject(@PathVariable long operateOrganizationId, @RequestBody Project project) {
+		project.setOperateOrganizationId(operateOrganizationId);
+		projectService.insertOperateProject(project);
+		return Response.ok(project);
+	}
+
+	@ApiOperation(value = "根据运营组织获取项目", notes = "根据运营组织获取项目列表")
+	@RequestMapping(value = "/operate/{operateOrganizationId}", method = RequestMethod.GET)
+	public Response getOperateOrganizationId(@PathVariable long operateOrganizationId) {
+		List<Project> list = projectService.getOperateOrganizationId(operateOrganizationId);
+		return Response.ok(list);
+	}
+	
+	@ApiOperation(value = "根据组织获取项目", notes = "根据组织获取项目列表")
+	@RequestMapping(value = "/{organizationId}/", method = RequestMethod.GET)
+	public Response getProjectByOrganizationId(@PathVariable long organizationId) {
+		List<Project> list = projectService.getProjectByOrganizationId(organizationId);
+		return Response.ok(list);
+	}
+	
+	@ApiOperation(value = "从有极同步项目到协同平台", notes = "从有极同步项目到协同平台")
+	@RequestMapping(value = "/youji/{url}/", method = RequestMethod.GET)
+	public Response syncProject(@PathVariable String url) {
+		String result = projectService.syncProject(AESUtil.decrypt(url));
+		return Response.ok(JSON.parse(result));
+	}
+	
+	@ApiOperation(value = "协同平台删除有极项目", notes = "协同平台删除有极项目")
+	@RequestMapping(value = "/youji/{url}/delete/{id}/", method = RequestMethod.DELETE)
+	@Transactional
+	public Response deleteProjectByYui(@PathVariable long id, @PathVariable String url) {
+		projectService.syncProject(AESUtil.decrypt(url));
+		projectService.deleteProject(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value="切换用户项目", notes="切换项目")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response saveLastProject(@RequestBody Project project) {
+		MgrUser user = ContextUtils.getCurrentUser();
+		user.setLastProjectId(project.getId());
+		//save user
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "获取有极审核过程", notes = "获取有极审核过程")
+	@RequestMapping(value = "/youji/flowApprover", method = RequestMethod.GET)
+	public Response flowApprover(@RequestParam(value="flowId", required=true) long flowId, @RequestParam(value="projectId", required=true) long projectId, 
+			@RequestParam(value="url", required=true) String url) {
+		String path = url + "/projectVision/showDetail?projectFlowId=" + flowId +"&projectId="+ projectId;
+		return Response.ok(JSON.parse(projectService.flowApprover(path)));
+	}
+	
+	@ApiOperation(value = "获取有极单位工程结构", notes = "获取有极单位工程结构")
+	@RequestMapping(value = "/youji/showPartItem", method = RequestMethod.POST)
+	public Response insertFlowYuiData(@RequestParam(value="url", required=true) String url) {
+		return Response.ok(JSON.parse(projectService.flowApprover(url)));
+	}
+
+	@ApiOperation(value = "重新部署后重新启动周报任务", notes = "重新部署后重新启动周报任务")
+	@RequestMapping(value = "/regenerate/{projectId}", method = RequestMethod.GET)
+	public Response regenerate(@PathVariable long projectId) {
+		projectService.regenerate(projectId);
+		return Response.ok();
+	}
+
+}

+ 69 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectFlowMetaDataController.java

@@ -0,0 +1,69 @@
+package com.bosshand.virgo.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.metadata.model.ProjectFlowApproverMetaData;
+import com.bosshand.virgo.api.metadata.model.ProjectFlowMetaData;
+import com.bosshand.virgo.api.metadata.service.ProjectFlowApproverMetaDataService;
+import com.bosshand.virgo.api.metadata.service.ProjectFlowMetaDataService;
+import com.bosshand.virgo.core.response.Response;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("projectFlowMetaData")
+public class ProjectFlowMetaDataController {
+	
+	@Autowired
+	ProjectFlowMetaDataService projectFlowMetaDataService;
+	
+	@Autowired
+	ProjectFlowApproverMetaDataService projectFlowApproverMetaDataService;
+	
+	@ApiOperation(value = "流程模板", notes = "流程模板列表")
+	@RequestMapping(value = "/", method = RequestMethod.GET)
+	public Response getList() {
+		return Response.ok(projectFlowMetaDataService.getList());
+	}
+	
+	@ApiOperation(value = "流程模板", notes = "流程模板新增")
+	@RequestMapping(value = "/", method = RequestMethod.POST)
+	public Response insert(@RequestBody ProjectFlowMetaData projectFlowMetaData) {
+		projectFlowMetaDataService.save(projectFlowMetaData);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "流程模板", notes = "流程模板修改")
+	@RequestMapping(value = "/", method = RequestMethod.PUT)
+	public Response update(@RequestBody ProjectFlowMetaData projectFlowMetaDat) {
+		projectFlowMetaDataService.update(projectFlowMetaDat);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "流程模板", notes = "流程模板删除")
+	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
+	public Response delete(@PathVariable long id) {
+		projectFlowMetaDataService.delete(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "流程模板节点", notes = "流程模板节点新增")
+	@RequestMapping(value = "/node", method = RequestMethod.POST)
+	public Response insert(@RequestBody ProjectFlowApproverMetaData projectFlowApproverMetaData) {
+		projectFlowApproverMetaDataService.save(projectFlowApproverMetaData);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "流程模板节点", notes = "流程模板节点删除")
+	@RequestMapping(value = "/node/{id}", method = RequestMethod.DELETE)
+	public Response deleteNode(@PathVariable long id) {
+		projectFlowApproverMetaDataService.delete(id);
+		return Response.ok();
+	}
+
+}

+ 231 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/ProjectItemController.java

@@ -0,0 +1,231 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.*;
+import com.bosshand.virgo.api.service.ProjectItemService;
+import com.bosshand.virgo.api.service.ProjectService;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.AESUtil;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("projectItem")
+public class ProjectItemController {
+	
+	@Autowired
+	ProjectService projectService;
+	
+	@Autowired
+	ProjectItemService projectItemService;
+	
+	@ApiOperation(value = "单位工程管理", notes = "单位工程新增")
+	@RequestMapping(value = "/{projectId}", method = RequestMethod.POST)
+	public Response insertProjectItem(@PathVariable long projectId, @RequestBody ProjectItem projectItem) {
+		projectItem.setProjectId(projectId);
+		projectItemService.insert(projectItem);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "单位工程管理", notes = "单位工程删除")
+	@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
+	public Response deleteProjectItem(@PathVariable long id) {
+		projectItemService.delete(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "单位工程管理", notes = "单位工程修改")
+	@RequestMapping(value = "/update", method = RequestMethod.PUT)
+	public Response updateProjectItem(@RequestBody ProjectItem projectItem) {
+		projectItemService.update(projectItem);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "根据项目获取单位工程列表", notes = "根据项目获取单位工程列表")
+	@RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+	public Response getProjectItemList(@PathVariable long projectId) {
+		return Response.ok(projectItemService.getProjectItemList(projectId));
+	}
+	
+	@ApiOperation(value = "单位工程管理", notes = "单位工程集成次数修改")
+	@RequestMapping(value = "/update/integrate/{projectItemId}", method = RequestMethod.PUT)
+	public Response updateProjectItemIntegrateNumber(@PathVariable long projectItemId) {
+		projectItemService.updateProjectItemIntegrateNumber(projectItemId);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "单位工程管理", notes = "单位工程信息")
+	@RequestMapping(value = "/projectItem/{projectItemId}", method = RequestMethod.GET)
+	public Response getProjectItem(@PathVariable long projectItemId) {
+		return Response.ok(projectItemService.getProjectItem(projectItemId));
+	}
+	
+	@ApiOperation(value = "同步有极单位工程", notes = "同步有极单位工程")
+	@RequestMapping(value = "youji/{url}/project/{projectId}/", method = RequestMethod.GET)
+	public Response syncProjectItem(@PathVariable String url, @PathVariable long projectId) {
+		String result = projectService.syncProject(AESUtil.decrypt(url));
+		return Response.ok(projectItemService.syncProjectItem(projectId, result));
+	}
+	
+	@ApiOperation(value = "获取指定项目中所有organizationId", notes = "获取指定项目中所有organizationId")
+	@RequestMapping(value = "/organization/{projectId}", method = RequestMethod.GET)
+	public Response getOrganizationIds(@PathVariable long projectId) {
+		return Response.ok(projectItemService.getOrganizationIds(projectId));
+	}
+	
+	@ApiOperation(value = "获取指定单位工程中所有organizationId", notes = "获取指定单位工程中所有organizationId")
+	@RequestMapping(value = "/organizationToYui/{yuiProjectItemId}", method = RequestMethod.GET)
+	public Response getOrganizationIdsByYuiProjectItemId(@PathVariable long yuiProjectItemId) {
+		return Response.ok(projectItemService.getOrganizationIdsByYuiProjectItemId(yuiProjectItemId));
+	}
+	
+	@ApiOperation(value = "楼层新增", notes = "楼层新增")
+	@RequestMapping(value = "/projectItemTarget", method = RequestMethod.POST)
+	public Response insertProjectItemTarget(@RequestBody ProjectItemTarget projectItemTarget) {
+		projectItemService.insertProjectItemTarget(projectItemTarget);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "楼层删除", notes = "楼层删除")
+	@RequestMapping(value = "/projectItemTarget/{id}", method = RequestMethod.DELETE)
+	public Response deleteProjectItemTarget(@PathVariable long id) {
+		projectItemService.deleteProjectItemTarget(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "楼层修改", notes = "楼层修改")
+	@RequestMapping(value = "/projectItemTarget", method = RequestMethod.PUT)
+	public Response updateProjectItemTarget(@RequestBody ProjectItemTarget projectItemTarget) {
+		projectItemService.updateProjectItemTarget(projectItemTarget);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "楼层查询", notes = "楼层查询")
+	@RequestMapping(value = "/projectItemTarget/{projectItemId}", method = RequestMethod.GET)
+	public Response getProjectItemTargetList(@PathVariable long projectItemId) {
+		return Response.ok(projectItemService.getByProjectItemId(projectItemId));
+	}
+	
+	@ApiOperation(value = "楼层详情", notes = "楼层详情")
+	@RequestMapping(value = "/projectItemTarget/details/{id}", method = RequestMethod.GET)
+	public Response getProjectItemTarget(@PathVariable long id) {
+		return Response.ok(projectItemService.getByProjectItemTargetId(id));
+	}
+
+	@ApiOperation(value = "房间新增", notes = "房间新增")
+	@RequestMapping(value = "/projectItemTargetRoom", method = RequestMethod.POST)
+	public Response insertProjectItemTargetRoom(@RequestBody ProjectItemTargetRoom projectItemTargetRoom) {
+		projectItemService.insertProjectItemTargetRoom(projectItemTargetRoom);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "房间删除", notes = "房间删除")
+	@RequestMapping(value = "/projectItemTargetRoom/{id}", method = RequestMethod.DELETE)
+	public Response deleteProjectItemTargetRoom(@PathVariable long id) {
+		projectItemService.deleteProjectItemTargetRoom(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "房间修改", notes = "房间修改")
+	@RequestMapping(value = "/projectItemTargetRoom", method = RequestMethod.PUT)
+	public Response updateProjectItemTargetRoom(@RequestBody ProjectItemTargetRoom projectItemTargetRoom) {
+		projectItemService.updateProjectItemTargetRoom(projectItemTargetRoom);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "房间查询", notes = "房间查询")
+	@RequestMapping(value = "/projectItemTargetRoom/query", method = RequestMethod.POST)
+	public Response getProjectItemTargetRoom(@RequestBody ProjectItemTargetRoom projectItemTargetRoom) {
+		return Response.ok(projectItemService.getProjectItemTargetRoom(projectItemTargetRoom));
+	}
+
+	@ApiOperation(value = "房间查询", notes = "房间查询")
+	@RequestMapping(value = "/projectItemTargetRoom/{projectItemTargetId}", method = RequestMethod.GET)
+	public Response getProjectItemTargetRoomList(@PathVariable long projectItemTargetId) {
+		return Response.ok(projectItemService.getProjectItemTargetId(projectItemTargetId));
+	}
+
+	@ApiOperation(value = "房间详情", notes = "房间详情")
+	@RequestMapping(value = "/projectItemTargetRoom/details/{id}", method = RequestMethod.GET)
+	public Response getProjectItemTargetRoom(@PathVariable long id) {
+		return Response.ok(projectItemService.getByProjectItemTargetRootId(id));
+	}
+	
+	@ApiOperation(value = "bim绑定", notes = "获取")
+	@RequestMapping(value = "/target/{projectItemTargetId}", method = RequestMethod.GET)
+	public Response getBimModelTarget(@PathVariable long projectItemTargetId) {
+		return Response.ok(projectItemService.getBimModelTarget(projectItemTargetId));
+	}
+	
+	@ApiOperation(value = "bim绑定", notes = "绑定")
+	@RequestMapping(value = "/target", method = RequestMethod.POST)
+	public Response saveBimModelTarget(@RequestBody BimModelTarget bimModelTarget) {
+		projectItemService.saveBimModelTarget(bimModelTarget);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "bim绑定", notes = "修改")
+	@RequestMapping(value = "/target", method = RequestMethod.PUT)
+	public Response updateBimModelTarget(@RequestBody BimModelTarget bimModelTarget) {
+		projectItemService.updateBimModelTarget(bimModelTarget);
+		return Response.ok();
+	}
+	
+	//*******************************************************************
+	
+	@ApiOperation(value = "bim类型列表", notes = "bim类型列表")
+	@RequestMapping(value = "/bimType", method = RequestMethod.GET)
+	public Response getBimTypeList() {
+		return Response.ok(projectItemService.getBimTypeList());
+	}
+	
+	@ApiOperation(value = "bim类型保存", notes = "bim类型保存")
+	@RequestMapping(value = "/bimType", method = RequestMethod.POST)
+	public Response saveBimType(@RequestBody BimType bimType) {
+		projectItemService.saveBimType(bimType);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "bim类型修改", notes = "bim类型修改")
+	@RequestMapping(value = "/bimType", method = RequestMethod.PUT)
+	public Response updateBimType(@RequestBody BimType bimType) {
+		projectItemService.updateBimType(bimType);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "bim类型删除", notes = "bim类型删除")
+	@RequestMapping(value = "/bimType/{id}", method = RequestMethod.DELETE)
+	public Response deleteBimType(@PathVariable int id) {
+		projectItemService.deleteBimType(id);
+		return Response.ok();
+	}
+	
+	//*******************************************************************
+
+	@ApiOperation(value = "IdentifyType类型列表", notes = "IdentifyType类型列表")
+	@RequestMapping(value = "/identifyType", method = RequestMethod.GET)
+	public Response getIdentifyTypeList() {
+		return Response.ok(projectItemService.getIdentifyTypeList());
+	}
+	
+	@ApiOperation(value = "IdentifyType类型保存", notes = "IdentifyType类型保存")
+	@RequestMapping(value = "/identifyType", method = RequestMethod.POST)
+	public Response saveIdentifyType(@RequestBody IdentifyType identifyType) {
+		projectItemService.saveIdentifyType(identifyType);
+		return Response.ok(identifyType);
+	}
+	
+	@ApiOperation(value = "IdentifyType类型修改", notes = "IdentifyType类型修改")
+	@RequestMapping(value = "/identifyType", method = RequestMethod.PUT)
+	public Response updateIdentifyType(@RequestBody IdentifyType identifyType) {
+		projectItemService.updateIdentifyType(identifyType);
+		return Response.ok(identifyType);
+	}
+	
+	@ApiOperation(value = "IdentifyType类型删除", notes = "IdentifyType类型删除")
+	@RequestMapping(value = "/identifyType/{id}", method = RequestMethod.DELETE)
+	public Response deleteIdentifyType(@PathVariable int id) {
+		projectItemService.deleteIdentifyType(id);
+		return Response.ok();
+	}
+}

+ 69 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/RectificationController.java

@@ -0,0 +1,69 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.Rectification;
+import com.bosshand.virgo.api.service.RectificationService;
+import com.bosshand.virgo.core.model.MgrUser;
+import com.bosshand.virgo.core.response.Response;
+import com.bosshand.virgo.core.utils.ContextUtils;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+public class RectificationController {
+
+    @Autowired
+    private RectificationService rectificationService;
+
+    @ApiOperation(value = "新增", notes = "新增")
+    @RequestMapping(value = "/rectification", method = RequestMethod.POST)
+    public Response add(@RequestBody Rectification rectification) {
+        Rectification rf = new Rectification();
+        rf.setFlowSynergyDataId(rectification.getFlowSynergyDataId());
+        List<Rectification> rfs = rectificationService.getList(rf);
+        if (rfs.size() > 0) {
+            rectification.setId(rfs.get(0).getId());
+            rectificationService.update(rectification);
+            return Response.ok(rectification);
+        }
+        MgrUser user = ContextUtils.getCurrentUser();
+        rectification.setCreateUserId(user.getId());
+        rectification.setCreateUserName(user.getName());
+        return Response.ok(rectificationService.insert(rectification));
+    }
+
+    @ApiOperation(value = "编辑", notes = "编辑")
+    @RequestMapping(value = "/rectification", method = RequestMethod.PUT)
+    public Response edit(@RequestBody Rectification rectification) {
+        return Response.ok(rectificationService.update(rectification));
+    }
+
+    @ApiOperation(value = "删除", notes = "删除")
+    @RequestMapping(value = "/rectification/{id}", method = RequestMethod.DELETE)
+    public Response del(@PathVariable long id) {
+        rectificationService.delete(id);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "查询", notes = "查询")
+    @RequestMapping(value = "/rectification/query", method = RequestMethod.POST)
+    public Response getList(@RequestBody Rectification rectification) {
+        return Response.ok(rectificationService.getList(rectification));
+    }
+
+    @ApiOperation(value = "分页查询", notes = "分页查询")
+    @RequestMapping(value = "/rectification/{currPage}/{pageSize}", method = RequestMethod.POST)
+    public Response listLimit(@RequestBody Rectification rectification, @PathVariable int currPage, @PathVariable int pageSize) {
+        List<Rectification> list = rectificationService.getList(rectification, currPage, pageSize);
+        List<Rectification> totalCount = rectificationService.getList(rectification);
+        Map<String, Object> result = new HashMap<String, Object>();
+        result.put("dataList", list);
+        result.put("totalCount", totalCount.size());
+        return Response.ok(result);
+    }
+
+}

+ 213 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/SetUpController.java

@@ -0,0 +1,213 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.service.SetUpService;
+import com.bosshand.virgo.core.response.Response;
+
+import io.swagger.annotations.ApiOperation;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("setup")
+public class SetUpController {
+	
+	@Autowired
+	private SetUpService setUpService;
+	
+	@ApiOperation(value = "查询工种", notes = "查询工种")
+	@RequestMapping(value = "/workType/{projectId}", method = RequestMethod.GET)
+	public Response getWorkType(@PathVariable long projectId) {
+		return Response.ok(setUpService.getWorkTypeProjectId(projectId));
+	}
+	
+	@ApiOperation(value = "新增工种", notes = "新增工种")
+	@RequestMapping(value = "/workType", method = RequestMethod.POST)
+	public Response addWorkType(@RequestBody WorkType workType) {
+		return Response.ok(setUpService.saveWorkType(workType));
+	}
+	
+	@ApiOperation(value = "编辑工种", notes = "编辑工种")
+	@RequestMapping(value = "/workType", method = RequestMethod.PUT)
+	public Response editWorkType(@RequestBody WorkType workType) {
+		return Response.ok(setUpService.updateWorkType(workType));
+	}
+	
+	@ApiOperation(value = "删除工种", notes = "删除工种")
+	@RequestMapping(value = "/workType/{id}", method = RequestMethod.DELETE)
+	public Response delWorkType(@PathVariable long id) {
+		setUpService.deleteWorkType(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "查询仓库", notes = "查询仓库")
+	@RequestMapping(value = "/warehouse/{projectId}", method = RequestMethod.GET)
+	public Response getWarehouse(@PathVariable long projectId) {
+		return Response.ok(setUpService.getWarehouseProjectId(projectId));
+	}
+	
+	@ApiOperation(value = "新增仓库", notes = "新增仓库")
+	@RequestMapping(value = "/warehouse", method = RequestMethod.POST)
+	public Response addWarehouse(@RequestBody Warehouse warehouse) {
+		return Response.ok(setUpService.saveWarehouse(warehouse));
+	}
+	
+	@ApiOperation(value = "编辑仓库", notes = "编辑仓库")
+	@RequestMapping(value = "/warehouse", method = RequestMethod.PUT)
+	public Response editWarehouse(@RequestBody Warehouse warehouse) {
+		return Response.ok(setUpService.updateWarehouse(warehouse));
+	}
+	
+	@ApiOperation(value = "删除仓库", notes = "删除仓库")
+	@RequestMapping(value = "/warehouse/{id}", method = RequestMethod.DELETE)
+	public Response delWarehouse(@PathVariable long id) {
+		setUpService.deleteWarehouse(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "查询设备", notes = "查询设备")
+	@RequestMapping(value = "/equipment/query", method = RequestMethod.POST)
+	public Response getEquipmentQuery(@RequestBody Equipment equipment) {
+		return Response.ok(setUpService.getEquipmentQuery(equipment));
+	}
+
+	@ApiOperation(value = "查询设备", notes = "查询设备")
+	@RequestMapping(value = "/equipment/{projectId}", method = RequestMethod.GET)
+	public Response getEquipment(@PathVariable long projectId) {
+		return Response.ok(setUpService.getEquipmentProjectId(projectId));
+	}
+	
+	@ApiOperation(value = "新增设备", notes = "新增设备")
+	@RequestMapping(value = "/equipment", method = RequestMethod.POST)
+	public Response addEquipment(@RequestBody Equipment equipment) {
+		return Response.ok(setUpService.saveEquipment(equipment));
+	}
+	
+	@ApiOperation(value = "编辑设备", notes = "编辑设备")
+	@RequestMapping(value = "/equipment", method = RequestMethod.PUT)
+	public Response editEquipment(@RequestBody Equipment equipment) {
+		return Response.ok(setUpService.updateEquipment(equipment));
+	}
+	
+	@ApiOperation(value = "删除设备", notes = "删除设备")
+	@RequestMapping(value = "/equipment/{id}", method = RequestMethod.DELETE)
+	public Response delEquipment(@PathVariable long id) {
+		setUpService.deleteEquipment(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "查询环境", notes = "查询环境")
+	@RequestMapping(value = "/environment/query", method = RequestMethod.POST)
+	public Response getEnvironmentQuery(@RequestBody Environment environment) {
+		return Response.ok(setUpService.getEnvironmentQuery(environment));
+	}
+
+	@ApiOperation(value = "查询环境", notes = "查询环境")
+	@RequestMapping(value = "/environment/{projectId}", method = RequestMethod.GET)
+	public Response getEnvironment(@PathVariable long projectId) {
+		return Response.ok(setUpService.getEnvironmentProjectId(projectId));
+	}
+
+	@ApiOperation(value = "新增环境", notes = "新增环境")
+	@RequestMapping(value = "/environment", method = RequestMethod.POST)
+	public Response addEnvironment(@RequestBody Environment environment) {
+		return Response.ok(setUpService.saveEnvironment(environment));
+	}
+
+	@ApiOperation(value = "编辑环境", notes = "编辑环境")
+	@RequestMapping(value = "/environment", method = RequestMethod.PUT)
+	public Response editEnvironment(@RequestBody Environment environment) {
+		return Response.ok(setUpService.updateEnvironment(environment));
+	}
+
+	@ApiOperation(value = "删除环境", notes = "删除环境")
+	@RequestMapping(value = "/environment/{id}", method = RequestMethod.DELETE)
+	public Response delEnvironment(@PathVariable long id) {
+		setUpService.deleteEnvironment(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "删除环境类型", notes = "删除环境类型")
+	@RequestMapping(value = "/environmentType/{id}", method = RequestMethod.DELETE)
+	public Response deleteEnvironmentType(@PathVariable long id) {
+		setUpService.deleteEnvironmentType(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "保存环境类型", notes = "保存环境类型")
+	@RequestMapping(value = "/environmentType", method = RequestMethod.POST)
+	public Response saveEnvironmentType(@RequestBody EnvironmentType environmentType) {
+		return Response.ok(setUpService.saveEnvironmentType(environmentType));
+	}
+
+	@ApiOperation(value = "修改环境类型", notes = "修改环境类型")
+	@RequestMapping(value = "/environmentType", method = RequestMethod.PUT)
+	public Response updateEnvironmentType(@RequestBody EnvironmentType environmentType) {
+		return Response.ok(setUpService.updateEnvironmentType(environmentType));
+	}
+
+	@ApiOperation(value = "查询环境类型", notes = "查询环境类型")
+	@RequestMapping(value = "/environmentType", method = RequestMethod.GET)
+	public Response getEnvironmentTypeList() {
+		return Response.ok(setUpService.getEnvironmentTypeList());
+	}
+
+	@ApiOperation(value = "删除设备类型", notes = "删除设备类型")
+	@RequestMapping(value = "/equipmentType/{id}", method = RequestMethod.DELETE)
+	public Response deleteEquipmentType(@PathVariable long id) {
+		setUpService.deleteEquipmentType(id);
+		return Response.ok();
+	}
+
+	@ApiOperation(value = "保存设备类型", notes = "保存设备类型")
+	@RequestMapping(value = "/equipmentType", method = RequestMethod.POST)
+	public Response saveEquipmentType(@RequestBody EquipmentType equipmentType) {
+		return Response.ok(setUpService.saveEquipmentType(equipmentType));
+	}
+
+	@ApiOperation(value = "修改设备类型", notes = "修改设备类型")
+	@RequestMapping(value = "/equipmentType", method = RequestMethod.PUT)
+	public Response updateEquipmentType(@RequestBody EquipmentType equipmentType) {
+		return Response.ok(setUpService.updateEquipmentType(equipmentType));
+	}
+
+	@ApiOperation(value = "查询设备类型", notes = "查询设备类型")
+	@RequestMapping(value = "/equipmentType", method = RequestMethod.GET)
+	public Response getEquipmentTypeList() {
+		return Response.ok(setUpService.getEquipmentTypeList());
+	}
+
+
+	@ApiOperation(value = "获取材料分类", notes = "获取材料分类")
+	@RequestMapping(value = "/materialcategory", method = RequestMethod.GET)
+	public Response getMaterialCategory() {
+		return Response.ok(setUpService.getNodeTreeById(1));
+	}
+	
+	@ApiOperation(value = "新增材料分类", notes = "新增材料分类")
+	@RequestMapping(value = "/materialcategory", method = RequestMethod.POST)
+	public Response addMaterialCategory(@RequestBody MaterialCategory materialCategory) {
+		return Response.ok(setUpService.saveMaterialCategory(materialCategory));
+	}
+	
+	@ApiOperation(value = "编辑材料分类", notes = "编辑材料分类")
+	@RequestMapping(value = "/materialcategory", method = RequestMethod.PUT)
+	public Response editMaterialCategory(@RequestBody MaterialCategory materialcategory) {
+		return Response.ok(setUpService.updateMaterialCategory(materialcategory));
+	}
+	
+	@ApiOperation(value = "删除材料分类", notes = "删除材料分类")
+	@RequestMapping(value = "/materialcategory/{id}", method = RequestMethod.DELETE)
+	public Response delMaterialCategory(@PathVariable long id) {
+		setUpService.deleteMaterialCategory(id);
+		return Response.ok();
+	}
+	
+}

+ 41 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/SignOnBehalfControler.java

@@ -0,0 +1,41 @@
+package com.bosshand.virgo.api.controller;
+
+
+import com.bosshand.virgo.api.model.SignOnBehalf;
+import com.bosshand.virgo.api.service.SignOnBehalfService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("signonbehalf")
+public class SignOnBehalfControler {
+
+    @Autowired
+    private SignOnBehalfService signOnBehalfService;
+
+    @ApiOperation(value = "查询", notes = "查询")
+    @RequestMapping(value = "/query", method = RequestMethod.POST)
+    public Response getList(@RequestBody SignOnBehalf signOnBehalf) {
+        return Response.ok(signOnBehalfService.getList(signOnBehalf));
+    }
+
+    @ApiOperation(value = "新增", notes = "新增")
+    @RequestMapping(value = "", method = RequestMethod.POST)
+    public Response add(@RequestBody SignOnBehalf signOnBehalf) {
+        signOnBehalfService.save(signOnBehalf);
+        return Response.ok();
+    }
+
+    @ApiOperation(value = "编辑", notes = "编辑")
+    @RequestMapping(value = "", method = RequestMethod.PUT)
+    public Response edit(@RequestBody SignOnBehalf signOnBehalf) {
+        signOnBehalfService.update(signOnBehalf);
+        return Response.ok();
+    }
+
+}

+ 51 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/TypeCascadeController.java

@@ -0,0 +1,51 @@
+package com.bosshand.virgo.api.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.bosshand.virgo.api.model.TypeCascade;
+import com.bosshand.virgo.api.service.TypeCascadeService;
+import com.bosshand.virgo.core.response.Response;
+
+import io.swagger.annotations.ApiOperation;
+
+@RestController
+@RequestMapping("typeCascade")
+public class TypeCascadeController {
+	
+	@Autowired
+	private TypeCascadeService typeCascadeService;
+	
+	@ApiOperation(value = "新增", notes = "新增")
+	@RequestMapping(value = "/tree", method = RequestMethod.POST)
+	public Response addTree(@RequestBody TypeCascade typeCascade) {
+		return Response.ok(typeCascadeService.addTree(typeCascade));
+	}
+	
+	@ApiOperation(value = "编辑", notes = "编辑")
+	@RequestMapping(value = "/tree", method = RequestMethod.PUT)
+	public Response editTree(@RequestBody TypeCascade typeCascade) {
+		return Response.ok(typeCascadeService.updateTree(typeCascade));
+	}
+	
+	@ApiOperation(value = "删除", notes = "删除")
+	@RequestMapping(value = "/tree/{id}", method = RequestMethod.DELETE)
+	public Response delTree(@PathVariable long id) {
+		typeCascadeService.delTree(id);
+		return Response.ok();
+	}
+	
+	@ApiOperation(value = "级联树", notes = "级联树")
+	@RequestMapping(value = "/tree/{id}", method = RequestMethod.GET)
+	public Response getTree(@PathVariable long id) {
+		if(id == -1) {
+			return Response.ok(typeCascadeService.getParentId(id));
+		}
+		return Response.ok(typeCascadeService.getRoot(id));
+	}
+
+}

+ 80 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/WeeklyController.java

@@ -0,0 +1,80 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.Weekly;
+import com.bosshand.virgo.api.model.WeeklySet;
+import com.bosshand.virgo.api.model.WeeklyType;
+import com.bosshand.virgo.api.service.WeeklyService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("weekly")
+public class WeeklyController {
+
+    @Autowired
+    private WeeklyService weeklyService;
+
+    @ApiOperation(value = "根据project获取周报", notes = "根据project获取周报")
+    @RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+    public Response list(@PathVariable long projectId) {
+        return Response.ok(weeklyService.getByProjectId(projectId));
+    }
+
+    @ApiOperation(value = "获取提交出来的周报", notes = "获取提交出来的周报")
+    @RequestMapping(value = "/submit/{projectId}", method = RequestMethod.GET)
+    public Response listProjectSubmit(@PathVariable long projectId) {
+        return Response.ok(weeklyService.getByProject(projectId));
+    }
+
+    @ApiOperation(value = "获取与自己企业相关的提交出来的周报", notes = "根据project获取提交出来的周报")
+    @RequestMapping(value = "/submit/{organizationId}/{projectId}", method = RequestMethod.GET)
+    public Response listOrganizationSubmit(@PathVariable long organizationId, @PathVariable long projectId) {
+        return Response.ok(weeklyService.getByOrganization(organizationId, projectId));
+    }
+
+    @ApiOperation(value = "修改周报状态", notes = "修改周报状态")
+    @RequestMapping(method = RequestMethod.PUT)
+    public Response updateState(@RequestBody Weekly weekly) {
+        return Response.ok(weeklyService.updateState(weekly));
+    }
+
+    @ApiOperation(value = "周报类型详情", notes = "周报类型详情")
+    @RequestMapping(value = "/type/{weeklyId}", method = RequestMethod.GET)
+    public Response getWeeklyType(@PathVariable long weeklyId) {
+        return Response.ok(weeklyService.getByWeeklyId(weeklyId));
+    }
+
+    @ApiOperation(value = "新增类型", notes = "新增类型")
+    @RequestMapping(value = "/type", method = RequestMethod.POST)
+    public Response addWeeklyType(@RequestBody WeeklyType weeklyType) {
+        return Response.ok(weeklyService.saveWeeklyType(weeklyType));
+    }
+
+    @ApiOperation(value = "编辑类型", notes = "编辑类型")
+    @RequestMapping(value = "/type", method = RequestMethod.PUT)
+    public Response editWeeklyType(@RequestBody WeeklyType weeklyType) {
+        return Response.ok(weeklyService.updateWeeklyType(weeklyType));
+    }
+
+    @ApiOperation(value = "新增配置", notes = "新增配置")
+    @RequestMapping(value = "/set", method = RequestMethod.POST)
+    public Response saveWeeklySet(@RequestBody WeeklySet weeklySet) {
+        return Response.ok(weeklyService.saveWeeklySet(weeklySet));
+    }
+
+    @ApiOperation(value = "编辑配置", notes = "编辑配置")
+    @RequestMapping(value = "/set", method = RequestMethod.PUT)
+    public Response updateWeeklySet(@RequestBody WeeklySet weeklySet) {
+        return Response.ok(weeklyService.updateWeeklySet(weeklySet));
+    }
+
+    @ApiOperation(value = "获取配置", notes = "获取配置")
+    @RequestMapping(value = "/set/query", method = RequestMethod.POST)
+    public Response getByWeeklySet(@RequestBody WeeklySet weeklySet) {
+        return Response.ok(weeklyService.getByWeeklySet(weeklySet));
+    }
+
+
+}

+ 60 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/WeeklyPersonController.java

@@ -0,0 +1,60 @@
+package com.bosshand.virgo.api.controller;
+
+import com.bosshand.virgo.api.model.WeeklyPerson;
+import com.bosshand.virgo.api.model.WeeklyTypePerson;
+import com.bosshand.virgo.api.service.WeeklyPersonService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("weeklyPerson")
+public class WeeklyPersonController {
+
+    @Autowired
+    private WeeklyPersonService weeklyPersonService;
+
+    @ApiOperation(value = "获取周报列表", notes = "获取周报列表")
+    @RequestMapping(value = "/{organizationId}/{projectId}/{userId}", method = RequestMethod.GET)
+    public Response list(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId) {
+        return Response.ok(weeklyPersonService.getList(organizationId,projectId, userId));
+    }
+
+    @ApiOperation(value = "根据期数获取周报", notes = "根据期数获取周报")
+    @RequestMapping(value = "/number/{organizationId}/{projectId}/{userId}/{number}", method = RequestMethod.GET)
+    public Response getNumber(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId, @PathVariable int number) {
+        return Response.ok(weeklyPersonService.getNumber(organizationId,projectId,userId,number));
+    }
+
+    @ApiOperation(value = "根据状态获取周报", notes = "根据状态获取周报")
+    @RequestMapping(value = "/{organizationId}/{projectId}/{userId}/{state}", method = RequestMethod.GET)
+    public Response listState(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId, @PathVariable int state) {
+        return Response.ok(weeklyPersonService.getState(organizationId, projectId, userId, state));
+    }
+
+    @ApiOperation(value = "修改个人周报状态", notes = "修改个人周报状态")
+    @RequestMapping(method = RequestMethod.PUT)
+    public Response updateState(@RequestBody WeeklyPerson weeklyPerson) {
+        return Response.ok(weeklyPersonService.updateState(weeklyPerson));
+    }
+
+    @ApiOperation(value = "个人周报类型详情", notes = "个人周报类型详情")
+    @RequestMapping(value = "/type/{weeklyPersonId}", method = RequestMethod.GET)
+    public Response getWeeklyTypePerson(@PathVariable long weeklyPersonId) {
+        return Response.ok(weeklyPersonService.getByWeeklyPersonId(weeklyPersonId));
+    }
+
+    @ApiOperation(value = "新增类型", notes = "新增类型")
+    @RequestMapping(value = "/type", method = RequestMethod.POST)
+    public Response addWeeklyTypePerson(@RequestBody WeeklyTypePerson weeklyTypePerson) {
+        return Response.ok(weeklyPersonService.saveWeeklyTypePerson(weeklyTypePerson));
+    }
+
+    @ApiOperation(value = "编辑类型", notes = "编辑类型")
+    @RequestMapping(value = "/type", method = RequestMethod.PUT)
+    public Response editWeeklyTypePerson(@RequestBody WeeklyTypePerson weeklyTypePerson) {
+        return Response.ok(weeklyPersonService.updateWeeklyTypePerson(weeklyTypePerson));
+    }
+
+}

+ 60 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyCompanyController.java

@@ -0,0 +1,60 @@
+package com.bosshand.virgo.api.controller.operate;
+
+import com.bosshand.virgo.api.model.operate.OperateWeeklyCompany;
+import com.bosshand.virgo.api.model.operate.OperateWeeklyTypeCompany;
+import com.bosshand.virgo.api.service.operate.OperateWeeklyCompanyService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("operateWeeklyCompany")
+public class OperateWeeklyCompanyController {
+
+    @Autowired
+    private OperateWeeklyCompanyService operateWeeklyCompanyService;
+
+    @ApiOperation(value = "根据project获取周报", notes = "根据project获取周报")
+    @RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+    public Response list(@PathVariable long projectId) {
+        return Response.ok(operateWeeklyCompanyService.getByProjectId(projectId));
+    }
+
+    @ApiOperation(value = "获取提交出来的周报", notes = "获取提交出来的周报")
+    @RequestMapping(value = "/submit/{projectId}", method = RequestMethod.GET)
+    public Response listProjectSubmit(@PathVariable long projectId) {
+        return Response.ok(operateWeeklyCompanyService.getByProject(projectId));
+    }
+
+    @ApiOperation(value = "获取与自己企业相关的提交出来的周报", notes = "根据project获取提交出来的周报")
+    @RequestMapping(value = "/submit/{organizationId}/{projectId}", method = RequestMethod.GET)
+    public Response listOrganizationSubmit(@PathVariable long organizationId, @PathVariable long projectId) {
+        return Response.ok(operateWeeklyCompanyService.getByOrganization(organizationId, projectId));
+    }
+
+    @ApiOperation(value = "修改周报状态", notes = "修改周报状态")
+    @RequestMapping(method = RequestMethod.PUT)
+    public Response updateState(@RequestBody OperateWeeklyCompany operateWeeklyCompany) {
+        return Response.ok(operateWeeklyCompanyService.updateState(operateWeeklyCompany));
+    }
+
+    @ApiOperation(value = "周报类型详情", notes = "周报类型详情")
+    @RequestMapping(value = "/type/{weeklyId}", method = RequestMethod.GET)
+    public Response getWeeklyType(@PathVariable long weeklyId) {
+        return Response.ok(operateWeeklyCompanyService.getByWeeklyId(weeklyId));
+    }
+
+    @ApiOperation(value = "新增类型", notes = "新增类型")
+    @RequestMapping(value = "/type", method = RequestMethod.POST)
+    public Response addWeeklyType(@RequestBody OperateWeeklyTypeCompany operateWeeklyTypeCompany) {
+        return Response.ok(operateWeeklyCompanyService.saveWeeklyType(operateWeeklyTypeCompany));
+    }
+
+    @ApiOperation(value = "编辑类型", notes = "编辑类型")
+    @RequestMapping(value = "/type", method = RequestMethod.PUT)
+    public Response editWeeklyType(@RequestBody OperateWeeklyTypeCompany operateWeeklyTypeCompany) {
+        return Response.ok(operateWeeklyCompanyService.updateWeeklyType(operateWeeklyTypeCompany));
+    }
+
+}

+ 60 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyDepartmentController.java

@@ -0,0 +1,60 @@
+package com.bosshand.virgo.api.controller.operate;
+
+import com.bosshand.virgo.api.model.operate.OperateWeeklyDepartment;
+import com.bosshand.virgo.api.model.operate.OperateWeeklyTypeDepartment;
+import com.bosshand.virgo.api.service.operate.OperateWeeklyDepartmentService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("operateWeeklyDepartment")
+public class OperateWeeklyDepartmentController {
+
+    @Autowired
+    private OperateWeeklyDepartmentService operateWeeklyDepartmentService;
+
+    @ApiOperation(value = "根据project获取周报", notes = "根据project获取周报")
+    @RequestMapping(value = "/{projectId}", method = RequestMethod.GET)
+    public Response list(@PathVariable long projectId) {
+        return Response.ok(operateWeeklyDepartmentService.getByProjectId(projectId));
+    }
+
+    @ApiOperation(value = "获取提交出来的周报", notes = "获取提交出来的周报")
+    @RequestMapping(value = "/submit/{projectId}", method = RequestMethod.GET)
+    public Response listProjectSubmit(@PathVariable long projectId) {
+        return Response.ok(operateWeeklyDepartmentService.getByProject(projectId));
+    }
+
+    @ApiOperation(value = "获取与自己企业相关的提交出来的周报", notes = "根据project获取提交出来的周报")
+    @RequestMapping(value = "/submit/{organizationId}/{projectId}", method = RequestMethod.GET)
+    public Response listOrganizationSubmit(@PathVariable long organizationId, @PathVariable long projectId) {
+        return Response.ok(operateWeeklyDepartmentService.getByOrganization(organizationId, projectId));
+    }
+
+    @ApiOperation(value = "修改周报状态", notes = "修改周报状态")
+    @RequestMapping(method = RequestMethod.PUT)
+    public Response updateState(@RequestBody OperateWeeklyDepartment operateWeeklyDepartment) {
+        return Response.ok(operateWeeklyDepartmentService.updateState(operateWeeklyDepartment));
+    }
+
+    @ApiOperation(value = "周报类型详情", notes = "周报类型详情")
+    @RequestMapping(value = "/type/{weeklyId}", method = RequestMethod.GET)
+    public Response getWeeklyType(@PathVariable long weeklyId) {
+        return Response.ok(operateWeeklyDepartmentService.getByWeeklyId(weeklyId));
+    }
+
+    @ApiOperation(value = "新增类型", notes = "新增类型")
+    @RequestMapping(value = "/type", method = RequestMethod.POST)
+    public Response addWeeklyType(@RequestBody OperateWeeklyTypeDepartment operateWeeklyTypeDepartment) {
+        return Response.ok(operateWeeklyDepartmentService.saveWeeklyType(operateWeeklyTypeDepartment));
+    }
+
+    @ApiOperation(value = "编辑类型", notes = "编辑类型")
+    @RequestMapping(value = "/type", method = RequestMethod.PUT)
+    public Response editWeeklyType(@RequestBody OperateWeeklyTypeDepartment operateWeeklyTypeDepartment) {
+        return Response.ok(operateWeeklyDepartmentService.updateWeeklyType(operateWeeklyTypeDepartment));
+    }
+
+}

+ 60 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/controller/operate/OperateWeeklyPersonController.java

@@ -0,0 +1,60 @@
+package com.bosshand.virgo.api.controller.operate;
+
+import com.bosshand.virgo.api.model.operate.OperateWeeklyPerson;
+import com.bosshand.virgo.api.model.operate.OperateWeeklyTypePerson;
+import com.bosshand.virgo.api.service.operate.OperateWeeklyPersonService;
+import com.bosshand.virgo.core.response.Response;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("operateWeeklyPerson")
+public class OperateWeeklyPersonController {
+
+    @Autowired
+    private OperateWeeklyPersonService operateWeeklyPersonService;
+
+    @ApiOperation(value = "获取周报列表", notes = "获取周报列表")
+    @RequestMapping(value = "/{organizationId}/{projectId}/{userId}", method = RequestMethod.GET)
+    public Response list(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId) {
+        return Response.ok(operateWeeklyPersonService.getList(organizationId,projectId, userId));
+    }
+
+    @ApiOperation(value = "根据期数获取周报", notes = "根据期数获取周报")
+    @RequestMapping(value = "/number/{organizationId}/{projectId}/{userId}/{number}", method = RequestMethod.GET)
+    public Response getNumber(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId, @PathVariable int number) {
+        return Response.ok(operateWeeklyPersonService.getNumber(organizationId,projectId,userId,number));
+    }
+
+    @ApiOperation(value = "根据状态获取周报", notes = "根据状态获取周报")
+    @RequestMapping(value = "/{organizationId}/{projectId}/{userId}/{state}", method = RequestMethod.GET)
+    public Response listState(@PathVariable long organizationId, @PathVariable long projectId, @PathVariable long userId, @PathVariable int state) {
+        return Response.ok(operateWeeklyPersonService.getState(organizationId, projectId, userId, state));
+    }
+
+    @ApiOperation(value = "修改个人周报状态", notes = "修改个人周报状态")
+    @RequestMapping(method = RequestMethod.PUT)
+    public Response updateState(@RequestBody OperateWeeklyPerson operateWeeklyPerson) {
+        return Response.ok(operateWeeklyPersonService.updateState(operateWeeklyPerson));
+    }
+
+    @ApiOperation(value = "个人周报类型详情", notes = "个人周报类型详情")
+    @RequestMapping(value = "/type/{weeklyPersonId}", method = RequestMethod.GET)
+    public Response getWeeklyTypePerson(@PathVariable long weeklyPersonId) {
+        return Response.ok(operateWeeklyPersonService.getByWeeklyPersonId(weeklyPersonId));
+    }
+
+    @ApiOperation(value = "新增类型", notes = "新增类型")
+    @RequestMapping(value = "/type", method = RequestMethod.POST)
+    public Response addWeeklyTypePerson(@RequestBody OperateWeeklyTypePerson operateWeeklyTypePerson) {
+        return Response.ok(operateWeeklyPersonService.saveWeeklyTypePerson(operateWeeklyTypePerson));
+    }
+
+    @ApiOperation(value = "编辑类型", notes = "编辑类型")
+    @RequestMapping(value = "/type", method = RequestMethod.PUT)
+    public Response editWeeklyTypePerson(@RequestBody OperateWeeklyTypePerson operateWeeklyTypePerson) {
+        return Response.ok(operateWeeklyPersonService.updateWeeklyTypePerson(operateWeeklyTypePerson));
+    }
+
+}

+ 20 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/BimModelTargetDao.java

@@ -0,0 +1,20 @@
+package com.bosshand.virgo.api.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.bosshand.virgo.api.model.BimModelTarget;
+
+@Mapper
+public interface BimModelTargetDao {
+
+	void save(BimModelTarget bimModelTarget);
+
+	void update(BimModelTarget bimModelTarget);
+
+	BimModelTarget getByProjectItemTargetId(long projectItemTargetId);
+
+	List<BimModelTarget> getProjectItemTargetIds(List<Long> ids);
+
+}

+ 20 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/BimTypeDao.java

@@ -0,0 +1,20 @@
+package com.bosshand.virgo.api.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.bosshand.virgo.api.model.BimType;
+
+@Mapper
+public interface BimTypeDao {
+	
+	void delete(int id);
+	
+	void save(BimType bimType);
+
+	void update(BimType bimType);
+	
+	List<BimType> getList();
+
+}

+ 18 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/CollaborativeDao.java

@@ -0,0 +1,18 @@
+package com.bosshand.virgo.api.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.bosshand.virgo.api.model.Collaborative;
+
+@Mapper
+public interface CollaborativeDao {
+	
+	public int insert(Collaborative collaborative);
+
+	public List<Collaborative> getList(long projectId);
+
+	public int isReceipt(int id);
+
+}

+ 17 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/ConfigurationUrlDao.java

@@ -0,0 +1,17 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.ConfigurationUrl;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ConfigurationUrlDao {
+
+	public int insert(ConfigurationUrl configurationUrl);
+
+	public List<ConfigurationUrl> getList();
+
+	public int update(ConfigurationUrl configurationUrl);
+
+}

+ 15 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/ConstructionLogDao.java

@@ -0,0 +1,15 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.ConstructionLog;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ConstructionLogDao {
+
+	public int insert(ConstructionLog constructionLog);
+
+	public List<ConstructionLog> getByProjectId(long projectId);
+	
+}

+ 23 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/DesignChangeDao.java

@@ -0,0 +1,23 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.DesignChange;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface DesignChangeDao {
+
+    public void save(DesignChange designChange);
+
+    public void update(DesignChange designChange);
+
+    public DesignChange get(long id);
+
+    public List<DesignChange> query(DesignChange designChange);
+
+    public List<DesignChange> queryByList(DesignChange designChange);
+
+    public void delete(long id);
+
+}

+ 19 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/DrawingsMarkedDao.java

@@ -0,0 +1,19 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.DrawingsMarked;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface DrawingsMarkedDao {
+
+    int save(DrawingsMarked drawingsMarked);
+
+    List<DrawingsMarked> getIds(String[] ids);
+
+    List<DrawingsMarked> getFileId(int fileId);
+
+    int update(DrawingsMarked drawingsMarked);
+
+}

+ 15 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementDao.java

@@ -0,0 +1,15 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.Element;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ElementDao {
+    Element get(long id);
+    int batchSave(List<Element> list);
+    List<Element> getList(Element element);
+    int update(Element element);
+    int delByIntegrateId(String integrateId);
+}

+ 21 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementStepDao.java

@@ -0,0 +1,21 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.ElementStep;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ElementStepDao {
+
+    int save(ElementStep ElementStep);
+
+    int saveList(List<ElementStep> list);
+
+    int delete(long id);
+
+    int update(ElementStep elementStep);
+
+    List<ElementStep> getList(String elementId);
+
+}

+ 19 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/ElementStepModelDao.java

@@ -0,0 +1,19 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.ElementStepModel;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface ElementStepModelDao {
+
+    int save(ElementStepModel elementStepModel);
+
+    int delete(long id);
+
+    int update(ElementStepModel elementStepModel);
+
+    List<ElementStepModel> getList();
+
+}

+ 20 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/EnvironmentDao.java

@@ -0,0 +1,20 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.Environment;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface EnvironmentDao {
+
+    public void save(Environment environment);
+
+    public void update(Environment environment);
+
+    public void delete(long id);
+
+    public List<Environment> getProjectId(long projectId);
+
+    public List<Environment> getEnvironmentQuery(Environment environment);
+}

+ 18 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/EnvironmentTypeDao.java

@@ -0,0 +1,18 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.EnvironmentType;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface EnvironmentTypeDao {
+
+    void delete(long id);
+
+    void save(EnvironmentType environmentType);
+
+    void update(EnvironmentType environmentType);
+
+    List<EnvironmentType> getList();
+}

+ 22 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/EquipmentDao.java

@@ -0,0 +1,22 @@
+package com.bosshand.virgo.api.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.bosshand.virgo.api.model.Equipment;
+
+@Mapper
+public interface EquipmentDao {
+
+	public void save(Equipment equipment);
+
+	public void update(Equipment equipment);
+
+	public void delete(long id);
+
+	public List<Equipment> getProjectId(long projectId);
+
+	public List<Equipment> getEquipmentQuery(Equipment equipment);
+
+}

+ 18 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/EquipmentTypeDao.java

@@ -0,0 +1,18 @@
+package com.bosshand.virgo.api.dao;
+
+import com.bosshand.virgo.api.model.EquipmentType;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface EquipmentTypeDao {
+
+    void delete(long id);
+
+    void save(EquipmentType equipmentType);
+
+    void update(EquipmentType equipmentType);
+
+    List<EquipmentType> getList();
+}

+ 22 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/FlowInstanceDao.java

@@ -0,0 +1,22 @@
+package com.bosshand.virgo.api.dao;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import com.bosshand.virgo.api.model.FlowInstance;
+
+@Mapper
+public interface FlowInstanceDao {
+	public FlowInstance get(long id);
+	public List<FlowInstance> listByProjectId(long projectId);
+	public List<FlowInstance> listByProjectItemId(long projectId, long projectItemId);
+	public List<FlowInstance> getFlowInstance(long projectId, long projectItemId, long flowType);
+	//TODO add the mapper
+	public int save(FlowInstance flowInstance);
+	public int update(FlowInstance flowInstance);
+	public int updateSubmitter(FlowInstance flowInstance);
+	public void delete(long flowInstanceId);
+	public List<FlowInstance> getProjectItemIds(List<Long> projectItemIds, long flowType);
+	public FlowInstance getProjectItemId(long projectItemId, long flowType);
+}

+ 0 - 0
virgo.api/src/main/java/com/bosshand/virgo/api/dao/FlowInstanceNodeDao.java


Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff