소스 검색

init from phab

xielq 4 년 전
부모
커밋
7e7d9244e0
68개의 변경된 파일4078개의 추가작업 그리고 0개의 파일을 삭제
  1. 0 0
      README.md
  2. 79 0
      build.gradle
  3. 3 0
      gradle.properties
  4. 2 0
      settings.gradle
  5. 6 0
      src/main/docker/Dockerfile
  6. 17 0
      src/main/java/com/uas/erp/manage/client/UasManageClientApplication.java
  7. 109 0
      src/main/java/com/uas/erp/manage/client/api/v1/ArtifactControllerV1.java
  8. 45 0
      src/main/java/com/uas/erp/manage/client/api/v1/ClientController.java
  9. 122 0
      src/main/java/com/uas/erp/manage/client/api/v1/ContainerControllerV1.java
  10. 111 0
      src/main/java/com/uas/erp/manage/client/api/v1/ProjectControllerV1.java
  11. 36 0
      src/main/java/com/uas/erp/manage/client/api/v1/ResourceControllerV1.java
  12. 59 0
      src/main/java/com/uas/erp/manage/client/api/v1/SettingControllerV1.java
  13. 11 0
      src/main/java/com/uas/erp/manage/client/config/AppConfig.java
  14. 23 0
      src/main/java/com/uas/erp/manage/client/config/ExceptionConfig.java
  15. 61 0
      src/main/java/com/uas/erp/manage/client/config/WebMvcConfig.java
  16. 135 0
      src/main/java/com/uas/erp/manage/client/config/WebSecurityConfig.java
  17. 93 0
      src/main/java/com/uas/erp/manage/client/domain/ClientContainerInfo.java
  18. 79 0
      src/main/java/com/uas/erp/manage/client/domain/ClientInfo.java
  19. 94 0
      src/main/java/com/uas/erp/manage/client/domain/ClientProjectInfo.java
  20. 87 0
      src/main/java/com/uas/erp/manage/client/domain/MavenMetadata.java
  21. 60 0
      src/main/java/com/uas/erp/manage/client/domain/MavenPom.java
  22. 135 0
      src/main/java/com/uas/erp/manage/client/entity/Artifact.java
  23. 84 0
      src/main/java/com/uas/erp/manage/client/entity/ArtifactItem.java
  24. 62 0
      src/main/java/com/uas/erp/manage/client/entity/Client.java
  25. 189 0
      src/main/java/com/uas/erp/manage/client/entity/Container.java
  26. 95 0
      src/main/java/com/uas/erp/manage/client/entity/Project.java
  27. 63 0
      src/main/java/com/uas/erp/manage/client/entity/ProjectDeployLog.java
  28. 54 0
      src/main/java/com/uas/erp/manage/client/entity/ProjectResourceReplace.java
  29. 83 0
      src/main/java/com/uas/erp/manage/client/entity/Setting.java
  30. 79 0
      src/main/java/com/uas/erp/manage/client/init/DefaultClientSetting.java
  31. 20 0
      src/main/java/com/uas/erp/manage/client/plugins/ProjectBuildPlugin.java
  32. 34 0
      src/main/java/com/uas/erp/manage/client/plugins/ProjectResourceReplacePlugin.java
  33. 20 0
      src/main/java/com/uas/erp/manage/client/repository/ArtifactItemRepository.java
  34. 15 0
      src/main/java/com/uas/erp/manage/client/repository/ArtifactRepository.java
  35. 12 0
      src/main/java/com/uas/erp/manage/client/repository/ClientRepository.java
  36. 15 0
      src/main/java/com/uas/erp/manage/client/repository/ContainerRepository.java
  37. 19 0
      src/main/java/com/uas/erp/manage/client/repository/ProjectDeployLogRepository.java
  38. 19 0
      src/main/java/com/uas/erp/manage/client/repository/ProjectRepository.java
  39. 17 0
      src/main/java/com/uas/erp/manage/client/repository/SettingRepository.java
  40. 192 0
      src/main/java/com/uas/erp/manage/client/service/ArtifactService.java
  41. 92 0
      src/main/java/com/uas/erp/manage/client/service/ClientService.java
  42. 292 0
      src/main/java/com/uas/erp/manage/client/service/ContainerService.java
  43. 251 0
      src/main/java/com/uas/erp/manage/client/service/LocalRepositoryService.java
  44. 132 0
      src/main/java/com/uas/erp/manage/client/service/ProjectService.java
  45. 35 0
      src/main/java/com/uas/erp/manage/client/service/RemoteOpsService.java
  46. 115 0
      src/main/java/com/uas/erp/manage/client/service/RemoteRepositoryService.java
  47. 52 0
      src/main/java/com/uas/erp/manage/client/service/SettingService.java
  48. 33 0
      src/main/java/com/uas/erp/manage/client/task/ScheduledArtifactUpdater.java
  49. 44 0
      src/main/java/com/uas/erp/manage/client/task/ScheduledContainerRefresher.java
  50. 34 0
      src/main/java/com/uas/erp/manage/client/task/ScheduledRemotePusher.java
  51. 16 0
      src/main/java/com/uas/erp/manage/client/util/DateTimeUtils.java
  52. 16 0
      src/main/java/com/uas/erp/manage/client/util/FileUtils.java
  53. 22 0
      src/main/java/com/uas/erp/manage/client/util/IOUtils.java
  54. 26 0
      src/main/java/com/uas/erp/manage/client/util/ObjectUtils.java
  55. 46 0
      src/main/java/com/uas/erp/manage/client/util/ShellUtils.java
  56. 26 0
      src/main/java/com/uas/erp/manage/client/util/StringUtil.java
  57. 65 0
      src/main/java/com/uas/erp/manage/client/util/ZipUtils.java
  58. 99 0
      src/main/java/com/uas/erp/manage/client/web/ResponseWrap.java
  59. 47 0
      src/main/java/com/uas/erp/manage/client/web/ResultWrap.java
  60. 53 0
      src/main/java/com/uas/ops/diff/domain/Manifest.java
  61. 34 0
      src/main/resources/application.yml
  62. 1 0
      src/main/resources/i18n/messages.properties
  63. 1 0
      src/main/resources/i18n/messages_en_US.properties
  64. 1 0
      src/main/resources/i18n/messages_zh_CN.properties
  65. 15 0
      src/main/resources/init/artifact.json
  66. 31 0
      src/main/resources/init/setting.json
  67. 30 0
      src/test/java/com/uas/ops/uas/client/RemoteOpsTest.java
  68. 30 0
      src/test/java/com/uas/ops/uas/client/RemoteRepositoryTest.java

+ 0 - 0
README.md


+ 79 - 0
build.gradle

@@ -0,0 +1,79 @@
+group 'com.uas.erp'
+version '1.0.0'
+
+buildscript {
+    ext {
+        springBootVersion = '1.4.4.RELEASE'
+        dockerVersion = '0.12.0'
+        dockerRegistry = "10.10.100.200:5000"
+    }
+    repositories {
+        maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+        maven { url "https://plugins.gradle.org/m2/" }
+        maven { url "https://repo.spring.io/libs-release" }
+        mavenCentral()
+        jcenter()
+    }
+    dependencies {
+        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+        classpath "gradle.plugin.com.palantir.gradle.docker:gradle-docker:${dockerVersion}"
+    }
+}
+
+apply plugin: 'java'
+apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'org.springframework.boot'
+apply plugin: "com.palantir.docker"
+
+jar {
+    baseName = project.name
+    version = ''
+}
+
+sourceCompatibility = 1.7
+
+repositories {
+    mavenLocal()
+    maven { url "http://repo.spring.io/libs-milestone" }
+    maven { url "http://repo.spring.io/libs-release" }
+    maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+    mavenCentral()
+}
+
+dependencyManagement {
+    imports {
+        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR5'
+    }
+}
+
+dependencies {
+    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
+    compile "org.springframework.boot:spring-boot-starter-web"
+    compile "org.springframework.boot:spring-boot-starter-security"
+    compile "org.springframework.session:spring-session"
+    testCompile "org.springframework.boot:spring-boot-starter-test"
+    compile "com.h2database:h2"
+    compile "com.alibaba:fastjson:$fastjsonVersion"
+    compile "com.thoughtworks.xstream:xstream:$xstreamVersion"
+}
+
+bootRun {
+    addResources = true
+}
+
+docker {
+    name "${dockerRegistry}/${project.name}:${project.version}"
+    dockerfile "${projectDir}/src/main/docker/Dockerfile"
+    files "${buildDir}/libs/${project.name}.jar"
+}.dependsOn build
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: "http://10.10.101.21:8081/artifactory/libs-release-local") {
+                authentication(userName: "yingp", password: "111111")
+            }
+        }
+    }
+}.dependsOn build

+ 3 - 0
gradle.properties

@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1024m
+fastjsonVersion=1.2.14
+xstreamVersion=1.4.10

+ 2 - 0
settings.gradle

@@ -0,0 +1,2 @@
+rootProject.name = 'uas-manage-client'
+

+ 6 - 0
src/main/docker/Dockerfile

@@ -0,0 +1,6 @@
+FROM hub.c.163.com/library/java:8-jre-alpine
+VOLUME /tmp # reate a temporary file on my host under "/var/lib/docker" and link it to the container under "/tmp".
+ADD uas_manage_client.jar app.jar
+RUN sh -c "touch /app.jar" #  "touch" the jar file so that it has a file modification time (Docker creates all container files in an "unmodified" state by default). This actually isn’t important for the simple app that we wrote, but any static content (e.g. "index.html") would require the file to have a modification time.
+ENV JAVA_OPTS=""
+ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Dspring.profiles.active=prod -Duser.timezone=GMT+08 -Djava.security.egd=file:/dev/./urandom -jar /app.jar"] # To reduce Tomcat startup time we added a system property pointing to "/dev/urandom" as a source of entropy.

+ 17 - 0
src/main/java/com/uas/erp/manage/client/UasManageClientApplication.java

@@ -0,0 +1,17 @@
+package com.uas.erp.manage.client;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * Created by Pro1 on 2017/6/17.
+ */
+@SpringBootApplication
+@EnableScheduling
+public class UasManageClientApplication {
+
+    public static void main(String[] args) {
+        new SpringApplicationBuilder(UasManageClientApplication.class).web(true).run(args);
+    }
+}

+ 109 - 0
src/main/java/com/uas/erp/manage/client/api/v1/ArtifactControllerV1.java

@@ -0,0 +1,109 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.service.ArtifactService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@RestController
+@RequestMapping(path = "/v1/artifact")
+public class ArtifactControllerV1 {
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    /**
+     * 所有信息
+     * @return
+     */
+    @GetMapping(path = "/list")
+    public ResponseEntity getArtifacts() {
+        return ResponseWrap.ok(artifactService.getArtifacts());
+    }
+
+    /**
+     * 查看仓库信息
+     * @param id
+     * @return
+     */
+    @GetMapping(path = "/{id}")
+    public ResponseEntity getArtifact(@PathVariable("id") long id) throws Exception{
+        return ResponseWrap.ok(artifactService.getArtifact(id));
+    }
+
+    /**
+     * 查看仓库信息
+     * @param groupId
+     * @param artifactId
+     * @return
+     */
+    @GetMapping(path = "/{groupId}/{artifactId}")
+    public ResponseEntity getArtifact(@PathVariable("groupId") String groupId,@PathVariable("artifactId") String artifactId) throws Exception{
+        return ResponseWrap.ok(artifactService.getArtifact(groupId, artifactId));
+    }
+
+    /**
+     * 详细版本信息
+     * @param groupId
+     * @param artifactId
+     * @return
+     */
+    @GetMapping(path = "/{groupId}/{artifactId}/items")
+    public ResponseEntity getArtifactItems(@PathVariable("groupId") String groupId, @PathVariable("artifactId") String artifactId) {
+        return ResponseWrap.ok(artifactService.getArtifactItems(groupId, artifactId));
+    }
+
+    /**
+     * 更新到最新版本
+     * @param id
+     * @return
+     */
+    @GetMapping(path = "/{id}/pull")
+    public ResponseEntity updateArtifactVersion(@PathVariable("id") long id) throws Exception{
+        Artifact artifact = artifactService.getArtifact(id);
+        Assert.notNull(artifact);
+        artifactService.update(artifact);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 详细版本信息
+     * @param id
+     * @return
+     */
+    @GetMapping(path = "/{id}/items")
+    public ResponseEntity getArtifactItems(@PathVariable("id") long id) {
+        return ResponseWrap.ok(artifactService.getArtifactItems(id));
+    }
+
+    /**
+     * 保存
+     * @param artifact
+     * @return
+     */
+    @PostMapping
+    public ResponseEntity saveArtifact(Artifact artifact) {
+        artifactService.safetySave(artifact);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 删除
+     * @param id
+     * @return
+     */
+    @DeleteMapping(path = "/{id}")
+    public ResponseEntity deleteArtifact(@PathVariable("id") long id) {
+        Artifact artifact = artifactService.getArtifact(id);
+        Assert.notNull(artifact);
+        artifactService.delete(artifact);
+        return ResponseWrap.ok();
+    }
+
+}

+ 45 - 0
src/main/java/com/uas/erp/manage/client/api/v1/ClientController.java

@@ -0,0 +1,45 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.entity.Client;
+import com.uas.erp.manage.client.service.ClientService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@RestController
+@RequestMapping(path = "/v1/client")
+public class ClientController {
+
+    @Autowired
+    private ClientService clientService;
+
+    @GetMapping
+    public ResponseEntity getClient() {
+        return ResponseWrap.ok(clientService.getClient());
+    }
+
+    @PostMapping
+    public ResponseEntity saveClient(Client client) {
+        clientService.safetySave(client);
+        return ResponseWrap.ok();
+    }
+
+    @GetMapping(path = "/info")
+    public ResponseEntity getClientInfo() {
+        return ResponseWrap.ok(clientService.getClientInfo());
+    }
+
+    @PostMapping(path = "/init")
+    public ResponseEntity initClient() {
+        clientService.initClient();
+        return ResponseWrap.ok();
+    }
+
+}

+ 122 - 0
src/main/java/com/uas/erp/manage/client/api/v1/ContainerControllerV1.java

@@ -0,0 +1,122 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.entity.Container;
+import com.uas.erp.manage.client.service.ContainerService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@RestController
+@RequestMapping(path = "/v1/container")
+public class ContainerControllerV1 {
+
+    @Autowired
+    private ContainerService containerService;
+
+    /**
+     * 输入容器路径时检测
+     * @param path
+     * @return
+     * @throws Exception
+     */
+    @GetMapping(path = "/check")
+    public ResponseEntity checkByPath(@RequestParam String path) throws Exception{
+        return ResponseWrap.ok(containerService.getContainerByPath(path));
+    }
+
+    /**
+     * 保存
+     * @param container
+     * @return
+     */
+    @PostMapping
+    public ResponseEntity save(Container container) throws Exception {
+        containerService.safetySave(container);
+        return ResponseWrap.ok();
+    }
+
+    @GetMapping(path = "/list")
+    public ResponseEntity getAll() {
+        return ResponseWrap.ok(containerService.findAll());
+    }
+
+    /**
+     * 获取容器
+     * @param containerId
+     * @return
+     */
+    @GetMapping(path = "/{containerId}")
+    public ResponseEntity get(@PathVariable("containerId") long containerId) {
+        return ResponseWrap.ok(containerService.findOne(containerId));
+    }
+
+    /**
+     * 删除容器
+     * @param containerId
+     * @return
+     */
+    @DeleteMapping(path = "/{containerId}")
+    public ResponseEntity delete(@PathVariable("containerId") long containerId) {
+        Container container = containerService.findOne(containerId);
+        Assert.notNull(container);
+        containerService.delete(container);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 安装容器环境
+     * @param containerId
+     * @return
+     */
+    @RequestMapping(path = "/{containerId}/install")
+    public ResponseEntity install(@PathVariable("containerId") long containerId) {
+        Container container = containerService.findOne(containerId);
+        Assert.notNull(container);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 停止容器
+     * @param containerId
+     * @return
+     */
+    @RequestMapping(path = "/{containerId}/stop")
+    public ResponseEntity stop(@PathVariable("containerId") long containerId) throws Exception {
+        Container container = containerService.findOne(containerId);
+        Assert.notNull(container);
+        containerService.stop(container);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 启动容器
+     * @param containerId
+     * @return
+     */
+    @RequestMapping(path = "/{containerId}/start")
+    public ResponseEntity start(@PathVariable("containerId") long containerId) throws Exception {
+        Container container = containerService.findOne(containerId);
+        Assert.notNull(container);
+        containerService.start(container);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 重启容器
+     * @param containerId
+     * @return
+     */
+    @RequestMapping(path = "/{containerId}/restart")
+    public ResponseEntity restart(@PathVariable("containerId") long containerId) throws Exception{
+        Container container = containerService.findOne(containerId);
+        Assert.notNull(container);
+        containerService.restart(container);
+        return ResponseWrap.ok();
+    }
+
+}

+ 111 - 0
src/main/java/com/uas/erp/manage/client/api/v1/ProjectControllerV1.java

@@ -0,0 +1,111 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.ArtifactItem;
+import com.uas.erp.manage.client.entity.Project;
+import com.uas.erp.manage.client.service.ArtifactService;
+import com.uas.erp.manage.client.service.ProjectService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@RestController
+@RequestMapping(path = "/v1/project")
+public class ProjectControllerV1 {
+
+    @Autowired
+    private ProjectService projectService;
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    @GetMapping(path = "/list")
+    public ResponseEntity getAll(String groupId, String artifactId) {
+        List<Project> projects = null;
+        if (null != groupId && null != artifactId) {
+            Artifact artifact = artifactService.getArtifact(groupId, artifactId);
+            projects = projectService.findByArtifactId(artifact.getId());
+        } else {
+            projects = projectService.findAll();
+        }
+        return ResponseWrap.ok(projects);
+    }
+
+    @PostMapping
+    public ResponseEntity save(Project project) {
+        projectService.save(project);
+        return ResponseWrap.ok();
+    }
+
+    @GetMapping(path = "/{id}")
+    public ResponseEntity get(@PathVariable("id") long id) {
+        return ResponseWrap.ok(projectService.get(id));
+    }
+
+    @DeleteMapping(path = "/{id}")
+    public ResponseEntity delete(@PathVariable("id") long id) throws Exception{
+        projectService.delete(id);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 部署{artifact}相关全部项目
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @throws Exception
+     */
+    @RequestMapping(path = "/deploy")
+    public ResponseEntity deployProject(final String groupId, final String artifactId, String version) throws Exception{
+        Artifact artifact = artifactService.getArtifact(groupId, artifactId);
+        Assert.notNull(artifact);
+        // 检测并更新仓库
+        ArtifactItem artifactItem = null;
+        if (!StringUtils.isEmpty(version))
+            artifactItem = artifactService.updateToVersion(artifact, version);// 指定版本
+        else
+            artifactItem = artifactService.update(artifact);// 最新版本
+        List<Project> projects = projectService.findByArtifactId(artifact.getId());
+        if (!CollectionUtils.isEmpty(projects)) {
+            for (Project project:projects) {
+                projectService.deploy(project, artifactItem);
+            }
+        }
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 指定项目及部署版本
+     * @param projectId
+     * @param artifactItemId
+     */
+    @RequestMapping(path = "/{projectId}/deploy")
+    public ResponseEntity deployProject(@PathVariable("projectId") long projectId, @RequestParam long artifactItemId) throws Exception{
+        Project project = projectService.findOne(projectId);
+        Assert.notNull(project);
+        ArtifactItem artifactItem = artifactService.getArtifactItem(artifactItemId);
+        Assert.notNull(artifactItem);
+        projectService.deploy(project, artifactItem);
+        return ResponseWrap.ok();
+    }
+
+    /**
+     * 查找日志
+     * @return
+     */
+    @GetMapping(path = "/{projectId}/deploy/log")
+    public ResponseEntity getDeployLog(@PathVariable("projectId") long projectId) {
+        return ResponseWrap.ok(projectService.getDeployLogs(projectId));
+    }
+
+}

+ 36 - 0
src/main/java/com/uas/erp/manage/client/api/v1/ResourceControllerV1.java

@@ -0,0 +1,36 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.service.LocalRepositoryService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+@RestController
+@RequestMapping(path = "/v1/resource")
+public class ResourceControllerV1 {
+
+    @Autowired
+    private LocalRepositoryService localRepository;
+
+    /**
+     * 保存字符串到文件
+     * @param resource
+     * @return resource relative path
+     * @throws IOException
+     */
+    @PostMapping
+    public ResponseEntity saveResource(String resource) throws IOException{
+        return ResponseWrap.ok(localRepository.saveResourceAsAttach(resource));
+    }
+
+    @GetMapping ResponseEntity getResource(String path) throws IOException{
+        return ResponseWrap.ok(localRepository.getAttachAsString(path));
+    }
+
+}

+ 59 - 0
src/main/java/com/uas/erp/manage/client/api/v1/SettingControllerV1.java

@@ -0,0 +1,59 @@
+package com.uas.erp.manage.client.api.v1;
+
+import com.uas.erp.manage.client.entity.Setting;
+import com.uas.erp.manage.client.service.SettingService;
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/22.
+ */
+@RestController
+@RequestMapping(path = "/v1/setting")
+public class SettingControllerV1 {
+
+    @Autowired
+    private SettingService settingService;
+
+    /**
+     * 取配置列表
+     * @param group 组别
+     * @return
+     */
+    @GetMapping(path = "/list")
+    public ResponseEntity getSettings(String group) {
+        List<Setting> settings = null;
+        if (StringUtils.isEmpty(group)) {
+            settings = settingService.findAll();
+        } else {
+            settings = settingService.findByGroup(group);
+        }
+        return ResponseWrap.ok(settings);
+    }
+
+    @GetMapping(path = "/{key}")
+    public ResponseEntity getSetting(@PathVariable("key") String key) {
+        return ResponseWrap.ok(settingService.findOne(key));
+    }
+
+    @PostMapping
+    public ResponseEntity saveSetting(Setting setting) {
+        settingService.save(setting);
+        return ResponseWrap.ok();
+    }
+
+    @DeleteMapping(path = "/{key}")
+    public ResponseEntity deleteSetting(@PathVariable("key") String key) {
+        Setting setting = settingService.findOne(key);
+        Assert.notNull(setting);
+        settingService.delete(setting);
+        return ResponseWrap.ok();
+    }
+
+}

+ 11 - 0
src/main/java/com/uas/erp/manage/client/config/AppConfig.java

@@ -0,0 +1,11 @@
+package com.uas.erp.manage.client.config;
+
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by Pro1 on 2017/6/17.
+ */
+@Configuration
+public class AppConfig {
+
+}

+ 23 - 0
src/main/java/com/uas/erp/manage/client/config/ExceptionConfig.java

@@ -0,0 +1,23 @@
+package com.uas.erp.manage.client.config;
+
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Created by Pro1 on 2017/6/22.
+ */
+@ControllerAdvice
+public class ExceptionConfig {
+
+    @ExceptionHandler(value = Exception.class)
+    @ResponseBody
+    public ResponseEntity defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
+        return ResponseWrap.badRequest(e.getMessage());
+    }
+
+}

+ 61 - 0
src/main/java/com/uas/erp/manage/client/config/WebMvcConfig.java

@@ -0,0 +1,61 @@
+package com.uas.erp.manage.client.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
+import org.springframework.web.servlet.i18n.SessionLocaleResolver;
+
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Created by Pro1 on 2017/6/21.
+ */
+@Configuration
+public class WebMvcConfig extends WebMvcConfigurerAdapter {
+
+    @Bean
+    public LocaleResolver localeResolver() {
+        SessionLocaleResolver slr = new SessionLocaleResolver();
+        slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
+        return slr;
+    }
+
+    @Bean
+    public LocaleChangeInterceptor localeChangeInterceptor() {
+        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
+        lci.setParamName("lang");
+        return lci;
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(localeChangeInterceptor());
+    }
+
+    @Bean
+    public HttpMessageConverter<String> responseBodyConverter() {
+        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        return converter;
+    }
+
+    @Override
+    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
+        super.configureMessageConverters(converters);
+        converters.add(responseBodyConverter());
+    }
+
+    @Bean
+    public RestTemplate restTemplate() {
+        RestTemplate restTemplate = new RestTemplate();
+        restTemplate.getMessageConverters().add(0, responseBodyConverter());
+        return restTemplate;
+    }
+}

+ 135 - 0
src/main/java/com/uas/erp/manage/client/config/WebSecurityConfig.java

@@ -0,0 +1,135 @@
+package com.uas.erp.manage.client.config;
+
+import com.uas.erp.manage.client.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.security.web.access.channel.ChannelProcessingFilter;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.util.matcher.AnyRequestMatcher;
+import org.springframework.session.ExpiringSession;
+import org.springframework.session.MapSessionRepository;
+import org.springframework.session.SessionRepository;
+import org.springframework.session.web.http.HeaderHttpSessionStrategy;
+import org.springframework.session.web.http.SessionRepositoryFilter;
+import org.springframework.ui.ModelMap;
+
+import javax.servlet.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Created by Pro1 on 2017/6/20.
+ */
+@Configuration
+@EnableWebSecurity
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
+
+    @Autowired
+    private MessageSource messageSource;
+
+    @Bean
+    public SessionRepository<ExpiringSession> sessionRepository() {
+        return new MapSessionRepository();
+    }
+
+    @Bean
+    public SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter() {
+        SessionRepositoryFilter<ExpiringSession> sessionRepositoryFilter = new SessionRepositoryFilter<ExpiringSession>(
+                sessionRepository());
+        sessionRepositoryFilter.setHttpSessionStrategy(new HeaderHttpSessionStrategy());
+        return sessionRepositoryFilter;
+    }
+
+    @Override
+    public void configure(WebSecurity web) throws Exception {
+        web.ignoring().antMatchers("/resources/**", "/static/**", "/public/**");
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+        http.authorizeRequests()
+                .antMatchers("/")
+                .permitAll()
+                .anyRequest()
+                .authenticated()
+                .and()
+                .formLogin()
+                .loginProcessingUrl("/login")
+                .successHandler(authenticationSuccessHandler())
+                .failureHandler(authenticationFailureHandler())
+                .and()
+                .exceptionHandling()
+                .defaultAuthenticationEntryPointFor(jsonAuthenticationEntryPoint(), AnyRequestMatcher.INSTANCE)
+                .and()
+                .logout()
+                .logoutUrl("/logout")
+                .and()
+                .addFilterBefore(sessionRepositoryFilter(), ChannelProcessingFilter.class)
+                .csrf()
+                .disable()
+                .sessionManagement()
+                .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
+    }
+
+    /**
+     * 登录成功时
+     * @return
+     */
+    @Bean
+    public AuthenticationSuccessHandler authenticationSuccessHandler() {
+        return new AuthenticationSuccessHandler() {
+            @Override
+            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
+                // 客户端保存token,后续每次请求header里面加x-auth-token进行身份验证
+                ResponseWrap.ok(response, new ModelMap("token", request.getSession().getId()));
+            }
+        };
+    }
+
+    /**
+     * 登录失败时
+     * @return
+     */
+    @Bean
+    public AuthenticationFailureHandler authenticationFailureHandler() {
+        return new AuthenticationFailureHandler() {
+            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
+                ResponseWrap.badRequest(response, messageSource.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", null, LocaleContextHolder.getLocale()));
+            }
+        };
+    }
+
+    /**
+     * 身份信息验证失败时
+     * @return
+     */
+    @Bean
+    public AuthenticationEntryPoint jsonAuthenticationEntryPoint() {
+        return new AuthenticationEntryPoint() {
+            @Override
+            public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
+                ResponseWrap.badRequest(response, HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.getReasonPhrase());
+            }
+        };
+    }
+
+    @Autowired
+    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+        auth.inMemoryAuthentication().withUser("admin").password("select").roles("ADMIN");
+    }
+}

+ 93 - 0
src/main/java/com/uas/erp/manage/client/domain/ClientContainerInfo.java

@@ -0,0 +1,93 @@
+package com.uas.erp.manage.client.domain;
+
+import com.uas.erp.manage.client.entity.Container;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+public class ClientContainerInfo {
+
+    private Long containerId;
+
+    private String type;
+
+    private String host;
+
+    private String home;
+
+    private Integer port;
+
+    private String description;
+
+    private String status;
+
+    public Long getContainerId() {
+        return containerId;
+    }
+
+    public void setContainerId(Long containerId) {
+        this.containerId = containerId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getHome() {
+        return home;
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public ClientContainerInfo(){
+
+    }
+
+    public ClientContainerInfo(Container container) {
+        this.containerId = container.getId();
+        this.description = container.getDescription();
+        this.host = container.getHost();
+        this.home = container.getHome();
+        this.port = container.getPort();
+        this.type = container.getType();
+        this.status = container.getStatus();
+    }
+}

+ 79 - 0
src/main/java/com/uas/erp/manage/client/domain/ClientInfo.java

@@ -0,0 +1,79 @@
+package com.uas.erp.manage.client.domain;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+public class ClientInfo {
+
+    private String clientId;
+
+    private String name;
+
+    private String ip;
+
+    private String basePath;
+
+    private Long lastConnectTime;
+
+    private List<ClientContainerInfo> containers;
+
+    private List<ClientProjectInfo> projects;
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public void setBasePath(String basePath) {
+        this.basePath = basePath;
+    }
+
+    public Long getLastConnectTime() {
+        return lastConnectTime;
+    }
+
+    public void setLastConnectTime(Long lastConnectTime) {
+        this.lastConnectTime = lastConnectTime;
+    }
+
+    public List<ClientProjectInfo> getProjects() {
+        return projects;
+    }
+
+    public void setProjects(List<ClientProjectInfo> projects) {
+        this.projects = projects;
+    }
+
+    public List<ClientContainerInfo> getContainers() {
+        return containers;
+    }
+
+    public void setContainers(List<ClientContainerInfo> containers) {
+        this.containers = containers;
+    }
+}

+ 94 - 0
src/main/java/com/uas/erp/manage/client/domain/ClientProjectInfo.java

@@ -0,0 +1,94 @@
+package com.uas.erp.manage.client.domain;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.Project;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+public class ClientProjectInfo {
+
+    private Long projectId;
+
+    private String groupId;
+
+    private String artifactId;
+
+    private String description;
+
+    private String contextName;
+
+    private String deployVersion;
+
+    private Long deployTime;
+
+    public ClientProjectInfo() {
+
+    }
+
+    public ClientProjectInfo(Artifact artifact, Project project) {
+        this.projectId = project.getId();
+        this.groupId = artifact.getGroupId();
+        this.artifactId = artifact.getArtifactId();
+        this.description = project.getDescription();
+        this.contextName = project.getContextName();
+        this.deployVersion = project.getDeployVersion();
+        this.deployTime = project.getDeployTime();
+    }
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Long projectId) {
+        this.projectId = projectId;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getContextName() {
+        return contextName;
+    }
+
+    public void setContextName(String contextName) {
+        this.contextName = contextName;
+    }
+
+    public String getDeployVersion() {
+        return deployVersion;
+    }
+
+    public void setDeployVersion(String deployVersion) {
+        this.deployVersion = deployVersion;
+    }
+
+    public Long getDeployTime() {
+        return deployTime;
+    }
+
+    public void setDeployTime(Long deployTime) {
+        this.deployTime = deployTime;
+    }
+}

+ 87 - 0
src/main/java/com/uas/erp/manage/client/domain/MavenMetadata.java

@@ -0,0 +1,87 @@
+package com.uas.erp.manage.client.domain;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@XStreamAlias("metadata")
+public class MavenMetadata {
+
+    private String groupId;
+
+    private String artifactId;
+
+    private Versioning versioning;
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public Versioning getVersioning() {
+        return versioning;
+    }
+
+    public void setVersioning(Versioning versioning) {
+        this.versioning = versioning;
+    }
+
+    @XStreamAlias("versioning")
+    public static class Versioning {
+
+        private String latest;
+
+        private String release;
+
+        private String lastUpdated;
+
+        private List<String> versions;
+
+        public String getLatest() {
+            return latest;
+        }
+
+        public void setLatest(String latest) {
+            this.latest = latest;
+        }
+
+        public String getRelease() {
+            return release;
+        }
+
+        public void setRelease(String release) {
+            this.release = release;
+        }
+
+        public String getLastUpdated() {
+            return lastUpdated;
+        }
+
+        public void setLastUpdated(String lastUpdated) {
+            this.lastUpdated = lastUpdated;
+        }
+
+        public List<String> getVersions() {
+            return versions;
+        }
+
+        public void setVersions(List<String> versions) {
+            this.versions = versions;
+        }
+    }
+
+}

+ 60 - 0
src/main/java/com/uas/erp/manage/client/domain/MavenPom.java

@@ -0,0 +1,60 @@
+package com.uas.erp.manage.client.domain;
+
+import com.thoughtworks.xstream.annotations.XStreamAlias;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@XStreamAlias("project")
+public class MavenPom {
+
+    private String groupId;
+
+    private String artifactId;
+
+    private String packaging;
+
+    private String version;
+
+    private String name;
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getPackaging() {
+        return packaging;
+    }
+
+    public void setPackaging(String packaging) {
+        this.packaging = packaging;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 135 - 0
src/main/java/com/uas/erp/manage/client/entity/Artifact.java

@@ -0,0 +1,135 @@
+package com.uas.erp.manage.client.entity;
+
+import javax.persistence.*;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+@Table(indexes = {@Index(columnList = "groupId,artifactId", unique = true)})
+public class Artifact {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String repoType;
+
+    private String groupId;
+
+    private String artifactId;
+
+    private String packaging;
+
+    private String description;
+
+    private String lastVersion;
+
+    private Long lastUpdateTime;
+
+    private Long lastVersionTime;
+
+    private Boolean autoUpdate;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(String artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * 最新版本
+     * @return
+     */
+    public String getLastVersion() {
+        return lastVersion;
+    }
+
+    public void setLastVersion(String lastVersion) {
+        this.lastVersion = lastVersion;
+    }
+
+    public void setLast(ArtifactItem artifactItem) {
+        this.lastVersion = artifactItem.getVersion();
+        this.lastVersionTime = artifactItem.getVersionTime();
+        this.lastUpdateTime = artifactItem.getUpdateTime();
+    }
+
+    /**
+     * 更新时间
+     * @return
+     */
+    public Long getLastUpdateTime() {
+        return lastUpdateTime;
+    }
+
+    public void setLastUpdateTime(Long lastUpdateTime) {
+        this.lastUpdateTime = lastUpdateTime;
+    }
+
+    /**
+     * 版本提交时间
+     * @return
+     */
+    public Long getLastVersionTime() {
+        return lastVersionTime;
+    }
+
+    public void setLastVersionTime(Long lastVersionTime) {
+        this.lastVersionTime = lastVersionTime;
+    }
+
+    public String getRepoType() {
+        return repoType;
+    }
+
+    public void setRepoType(String repoType) {
+        this.repoType = repoType;
+    }
+
+    public boolean isAutoUpdate() {
+        return null != autoUpdate && autoUpdate.booleanValue();
+    }
+
+    public void setAutoUpdate(Boolean autoUpdate) {
+        this.autoUpdate = autoUpdate;
+    }
+
+    public String getPackaging() {
+        return packaging;
+    }
+
+    public void setPackaging(String packaging) {
+        this.packaging = packaging;
+    }
+
+    public static enum RepoType {
+        MAVEN,DIFF
+    }
+}

+ 84 - 0
src/main/java/com/uas/erp/manage/client/entity/ArtifactItem.java

@@ -0,0 +1,84 @@
+package com.uas.erp.manage.client.entity;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.erp.manage.client.domain.MavenMetadata;
+import com.uas.erp.manage.client.util.DateTimeUtils;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+@Table(indexes = {@Index(columnList = "artifactId,version", unique = true)})
+public class ArtifactItem {
+    public ArtifactItem() {
+    }
+
+    public ArtifactItem(Artifact artifact, Manifest manifest) {
+        this.artifactId = artifact.getId();
+        this.version = manifest.getVersion();
+        this.versionTime = manifest.getLastChanged();
+        this.updateTime = new Date().getTime();
+    }
+
+    public ArtifactItem(Artifact artifact, MavenMetadata metadata) throws Exception{
+        this.artifactId = artifact.getId();
+        this.version = metadata.getVersioning().getLatest();
+        this.versionTime = DateTimeUtils.parseDateTime(metadata.getVersioning().getLastUpdated(), "yyyyMMddHHmmss").getTime();
+        this.updateTime = new Date().getTime();
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private Long artifactId;
+
+    private String version;
+
+    private Long versionTime;
+
+    private Long updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public Long getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(Long artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public Long getVersionTime() {
+        return versionTime;
+    }
+
+    public void setVersionTime(Long versionTime) {
+        this.versionTime = versionTime;
+    }
+
+    public Long getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Long updateTime) {
+        this.updateTime = updateTime;
+    }
+}

+ 62 - 0
src/main/java/com/uas/erp/manage/client/entity/Client.java

@@ -0,0 +1,62 @@
+package com.uas.erp.manage.client.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@Entity
+public class Client {
+
+    @Id
+    private String id;
+
+    private String name;
+
+    private String basePath;
+
+    private boolean init;
+
+    private Long initTime;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public void setBasePath(String basePath) {
+        this.basePath = basePath;
+    }
+
+    public boolean isInit() {
+        return init;
+    }
+
+    public void setInit(boolean init) {
+        this.init = init;
+    }
+
+    public Long getInitTime() {
+        return initTime;
+    }
+
+    public void setInitTime(Long initTime) {
+        this.initTime = initTime;
+    }
+}

+ 189 - 0
src/main/java/com/uas/erp/manage/client/entity/Container.java

@@ -0,0 +1,189 @@
+package com.uas.erp.manage.client.entity;
+
+import org.springframework.util.StringUtils;
+
+import javax.persistence.*;
+import java.util.Set;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+public class Container {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String type;
+
+    private String host;
+
+    @Column(unique = true)
+    private String home;
+
+    private Integer port;
+
+    @Column(unique = true)
+    private String description;
+
+    private String status;
+
+    private String startCommand;
+
+    private String stopCommand;
+
+    private String statusCommand;
+
+    private String processCommand;
+
+    private String deployCommand;
+
+    private String webappsHome;
+
+    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
+    @JoinColumn(name="parentId")
+    private Set<Container> nodes;
+
+    public Container() {
+
+    }
+
+    public Container(String home) {
+        this.home = home;
+        this.status = Status.UNRECOGNIZED.name();
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getHome() {
+        return home;
+    }
+
+    public void setHome(String home) {
+        this.home = home;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public String getStartCommand() {
+        return startCommand;
+    }
+
+    public void setStartCommand(String startCommand) {
+        this.startCommand = startCommand;
+    }
+
+    public String getStopCommand() {
+        return stopCommand;
+    }
+
+    public void setStopCommand(String stopCommand) {
+        this.stopCommand = stopCommand;
+    }
+
+    public String getStatusCommand() {
+        return statusCommand;
+    }
+
+    public void setStatusCommand(String statusCommand) {
+        this.statusCommand = statusCommand;
+    }
+
+    public String getProcessCommand() {
+        return processCommand;
+    }
+
+    public void setProcessCommand(String processCommand) {
+        this.processCommand = processCommand;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getDeployCommand() {
+        return deployCommand;
+    }
+
+    public void setDeployCommand(String deployCommand) {
+        this.deployCommand = deployCommand;
+    }
+
+    public String getWebappsHome() {
+        return webappsHome;
+    }
+
+    public void setWebappsHome(String webappsHome) {
+        this.webappsHome = webappsHome;
+    }
+
+    /**
+     * 集群节点
+     * @return
+     */
+    public Set<Container> getNodes() {
+        return nodes;
+    }
+
+    public void setNodes(Set<Container> nodes) {
+        this.nodes = nodes;
+    }
+
+    public boolean isCluster() {
+        return Type.CLUSTER.equals(Type.valueOf(this.getType()));
+    }
+
+    public boolean isRemote() {
+        return !StringUtils.isEmpty(this.host) && !"localhost".equals(this.host)
+                && !"127.0.0.1".equals(this.host);
+    }
+
+    public static enum Type {
+        TOMCAT,JBOSS,SPRING_BOOT,CLUSTER,OTHER
+    }
+
+    public static enum Status {
+        RUNNING,STOPPED,UNRECOGNIZED
+    }
+}

+ 95 - 0
src/main/java/com/uas/erp/manage/client/entity/Project.java

@@ -0,0 +1,95 @@
+package com.uas.erp.manage.client.entity;
+
+import javax.persistence.*;
+import java.util.Set;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+public class Project {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private String description;
+
+    private Long artifactId;
+
+    private Long containerId;
+
+    private String contextName;
+
+    private String deployVersion;
+
+    private Long deployTime;
+
+    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
+    @JoinColumn(name="projectId")
+    private Set<ProjectResourceReplace> resourceReplaces;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Long getArtifactId() {
+        return artifactId;
+    }
+
+    public void setArtifactId(Long artifactId) {
+        this.artifactId = artifactId;
+    }
+
+    public Long getContainerId() {
+        return containerId;
+    }
+
+    public void setContainerId(Long containerId) {
+        this.containerId = containerId;
+    }
+
+    public String getDeployVersion() {
+        return deployVersion;
+    }
+
+    public void setDeployVersion(String deployVersion) {
+        this.deployVersion = deployVersion;
+    }
+
+    public Long getDeployTime() {
+        return deployTime;
+    }
+
+    public void setDeployTime(Long deployTime) {
+        this.deployTime = deployTime;
+    }
+
+    public String getContextName() {
+        return contextName;
+    }
+
+    public void setContextName(String contextName) {
+        this.contextName = contextName;
+    }
+
+    public Set<ProjectResourceReplace> getResourceReplaces() {
+        return resourceReplaces;
+    }
+
+    public void setResourceReplaces(Set<ProjectResourceReplace> resourceReplaces) {
+        this.resourceReplaces = resourceReplaces;
+    }
+}

+ 63 - 0
src/main/java/com/uas/erp/manage/client/entity/ProjectDeployLog.java

@@ -0,0 +1,63 @@
+package com.uas.erp.manage.client.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import java.util.Date;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+public class ProjectDeployLog {
+    public ProjectDeployLog() {
+    }
+
+    public ProjectDeployLog(Project project, ArtifactItem artifactItem) {
+        this.projectId = project.getId();
+        this.deployTime = new Date().getTime();
+        this.deployVersion = artifactItem.getVersion();
+    }
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private Long projectId;
+
+    private Long deployTime;
+
+    private String deployVersion;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Long projectId) {
+        this.projectId = projectId;
+    }
+
+    public Long getDeployTime() {
+        return deployTime;
+    }
+
+    public void setDeployTime(Long deployTime) {
+        this.deployTime = deployTime;
+    }
+
+    public String getDeployVersion() {
+        return deployVersion;
+    }
+
+    public void setDeployVersion(String deployVersion) {
+        this.deployVersion = deployVersion;
+    }
+}

+ 54 - 0
src/main/java/com/uas/erp/manage/client/entity/ProjectResourceReplace.java

@@ -0,0 +1,54 @@
+package com.uas.erp.manage.client.entity;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+@Entity
+public class ProjectResourceReplace {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    private Long projectId;
+
+    private String path;
+
+    private String filePath;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getProjectId() {
+        return projectId;
+    }
+
+    public void setProjectId(Long projectId) {
+        this.projectId = projectId;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public String getFilePath() {
+        return filePath;
+    }
+
+    public void setFilePath(String filePath) {
+        this.filePath = filePath;
+    }
+}

+ 83 - 0
src/main/java/com/uas/erp/manage/client/entity/Setting.java

@@ -0,0 +1,83 @@
+package com.uas.erp.manage.client.entity;
+
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+
+/**
+ * 配置
+ * Created by Pro1 on 2017/6/19.
+ */
+@Entity
+public class Setting {
+
+    @Id
+    private String key;
+
+    @Column(name = "group_")
+    private String group;
+
+    private static final String default_group = "default";
+
+    private String description;
+    @Column(name = "value_")
+    private String value;
+
+    public Setting() {
+    }
+
+    public Setting(String key, String value) {
+        this(null, key, null, value);
+    }
+
+    public Setting(String key, String description, String value) {
+        this(null, key, description, value);
+    }
+
+    public Setting(String group, String key, String description, String value) {
+        this.group = StringUtils.isEmpty(group) ? default_group : group;
+        Assert.notNull(key);
+        this.key = key;
+        this.description = StringUtils.isEmpty(description) ? key : description;
+        this.value = value;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    /**
+     * 分组
+     * @return
+     */
+    public String getGroup() {
+        return group;
+    }
+
+    public void setGroup(String group) {
+        this.group = group;
+    }
+}

+ 79 - 0
src/main/java/com/uas/erp/manage/client/init/DefaultClientSetting.java

@@ -0,0 +1,79 @@
+package com.uas.erp.manage.client.init;
+
+import com.alibaba.fastjson.JSON;
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.Client;
+import com.uas.erp.manage.client.entity.Setting;
+import com.uas.erp.manage.client.service.*;
+import com.uas.erp.manage.client.util.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@Component
+public class DefaultClientSetting implements CommandLineRunner {
+
+    @Autowired
+    private ClientService clientService;
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    @Autowired
+    private SettingService settingService;
+
+    @Autowired
+    private ContainerService containerService;
+
+    @Autowired
+    private ProjectService projectService;
+
+    @Autowired
+    private Environment environment;
+
+    @Override
+    public void run(String... strings) throws Exception {
+        if (null == clientService.getClient()) {
+            // 客户端
+            Client client = new Client();
+            // 所有客户的ID唯一
+            client.setId(StringUtil.uuid());
+            client.setInit(isDev());
+            clientService.save(client);
+
+            // 清除可能存在的旧数据
+            settingService.deleteAll();
+            projectService.deleteAll();
+            containerService.deleteAll();
+            artifactService.deleteAll();
+
+            // 默认数据
+            String settingsStr = StringUtil.copyResource("init/setting.json");
+            if (!StringUtils.isEmpty(settingsStr)) {
+                List<Setting> settings = JSON.parseArray(settingsStr, Setting.class);
+                settingService.save(settings);
+            }
+            String artifactsStr = StringUtil.copyResource("init/artifact.json");
+            if (!StringUtils.isEmpty(artifactsStr)) {
+                List<Artifact> artifacts = JSON.parseArray(artifactsStr, Artifact.class);
+                artifactService.save(artifacts);
+            }
+        }
+    }
+
+    private boolean isDev() {
+        for (String env : environment.getActiveProfiles()) {
+            if ("dev".equalsIgnoreCase(env)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 20 - 0
src/main/java/com/uas/erp/manage/client/plugins/ProjectBuildPlugin.java

@@ -0,0 +1,20 @@
+package com.uas.erp.manage.client.plugins;
+
+import com.uas.erp.manage.client.entity.Project;
+
+import java.io.File;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+public abstract class ProjectBuildPlugin {
+
+    protected Project project;
+
+    public ProjectBuildPlugin(Project project) {
+        this.project = project;
+    }
+
+    public abstract void onBuild(File target) throws Exception;
+
+}

+ 34 - 0
src/main/java/com/uas/erp/manage/client/plugins/ProjectResourceReplacePlugin.java

@@ -0,0 +1,34 @@
+package com.uas.erp.manage.client.plugins;
+
+import com.uas.erp.manage.client.entity.Project;
+import com.uas.erp.manage.client.entity.ProjectResourceReplace;
+import com.uas.erp.manage.client.service.LocalRepositoryService;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.File;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+public class ProjectResourceReplacePlugin extends ProjectBuildPlugin{
+
+    private LocalRepositoryService localRepository;
+
+    public ProjectResourceReplacePlugin(Project project, LocalRepositoryService localRepository) {
+        super(project);
+        this.localRepository = localRepository;
+    }
+
+    @Override
+    public void onBuild(File target) throws Exception {
+        if (!CollectionUtils.isEmpty(project.getResourceReplaces())) {
+            for (ProjectResourceReplace replace:project.getResourceReplaces()) {
+                File file = localRepository.getAttach(replace.getFilePath());
+                if (file.exists()) {
+                    FileCopyUtils.copy(file, new File(target.getAbsolutePath() + replace.getPath()));
+                }
+            }
+        }
+    }
+}

+ 20 - 0
src/main/java/com/uas/erp/manage/client/repository/ArtifactItemRepository.java

@@ -0,0 +1,20 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.ArtifactItem;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface ArtifactItemRepository extends JpaRepository<ArtifactItem, Long>{
+
+    ArtifactItem findByArtifactIdAndVersion(long artifactId, String version);
+
+    List<ArtifactItem> findByArtifactIdOrderByVersionDesc(long artifactId);
+
+    void deleteByArtifactId(long artifactId);
+}

+ 15 - 0
src/main/java/com/uas/erp/manage/client/repository/ArtifactRepository.java

@@ -0,0 +1,15 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface ArtifactRepository extends JpaRepository<Artifact, Long>{
+
+    Artifact findByGroupIdAndArtifactId(String groupId, String artifactId);
+
+}

+ 12 - 0
src/main/java/com/uas/erp/manage/client/repository/ClientRepository.java

@@ -0,0 +1,12 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.Client;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+@Repository
+public interface ClientRepository extends JpaRepository<Client, String>{
+}

+ 15 - 0
src/main/java/com/uas/erp/manage/client/repository/ContainerRepository.java

@@ -0,0 +1,15 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.Container;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface ContainerRepository extends JpaRepository<Container, Long>{
+
+    Container findByHome(String home);
+
+}

+ 19 - 0
src/main/java/com/uas/erp/manage/client/repository/ProjectDeployLogRepository.java

@@ -0,0 +1,19 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.ProjectDeployLog;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface ProjectDeployLogRepository extends JpaRepository<ProjectDeployLog, Long>{
+
+    List<ProjectDeployLog> findByProjectIdOrderByDeployTimeDesc(long projectId);
+
+    void deleteByProjectId(long projectId);
+
+}

+ 19 - 0
src/main/java/com/uas/erp/manage/client/repository/ProjectRepository.java

@@ -0,0 +1,19 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.Project;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface ProjectRepository extends JpaRepository<Project, Long>{
+
+    List<Project> findByArtifactId(long artifactId);
+
+    List<Project> findByContainerId(long containerId);
+
+}

+ 17 - 0
src/main/java/com/uas/erp/manage/client/repository/SettingRepository.java

@@ -0,0 +1,17 @@
+package com.uas.erp.manage.client.repository;
+
+import com.uas.erp.manage.client.entity.Setting;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Repository
+public interface SettingRepository extends JpaRepository<Setting, String>{
+
+    List<Setting> findByGroupOrderByKey(String group);
+
+}

+ 192 - 0
src/main/java/com/uas/erp/manage/client/service/ArtifactService.java

@@ -0,0 +1,192 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.erp.manage.client.domain.MavenMetadata;
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.ArtifactItem;
+import com.uas.erp.manage.client.entity.Project;
+import com.uas.erp.manage.client.repository.ArtifactItemRepository;
+import com.uas.erp.manage.client.repository.ArtifactRepository;
+import com.uas.erp.manage.client.util.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Service
+public class ArtifactService {
+
+    @Autowired
+    private ArtifactRepository artifactRepository;
+
+    @Autowired
+    private ArtifactItemRepository artifactItemRepository;
+
+    @Autowired
+    private LocalRepositoryService localRepository;
+
+    @Autowired
+    private RemoteRepositoryService remoteRepository;
+
+    @Autowired
+    private ProjectService projectService;
+
+    private Map<Long, String> artifactUpdateTasks = new HashMap<Long, String>();
+
+    public Artifact getArtifact(long id) {
+        return artifactRepository.findOne(id);
+    }
+
+    public Artifact getArtifact(String groupId, String artifactId) {
+        return artifactRepository.findByGroupIdAndArtifactId(groupId, artifactId);
+    }
+
+    public ArtifactItem getArtifactItem(long artifactId, String version) {
+        return artifactItemRepository.findByArtifactIdAndVersion(artifactId, version);
+    }
+
+    public ArtifactItem getArtifactItem(long artifactItemId) {
+        return artifactItemRepository.findOne(artifactItemId);
+    }
+
+    public ArtifactItem getArtifactItem(String groupId, String artifactId, String version) {
+        Artifact artifact = getArtifact(groupId, artifactId);
+        if (null != artifact) {
+            return getArtifactItem(artifact.getId(), version);
+        }
+        return null;
+    }
+
+    public List<ArtifactItem> getArtifactItems(long id) {
+        Artifact artifact = getArtifact(id);
+        if (null != artifact) {
+            return artifactItemRepository.findByArtifactIdOrderByVersionDesc(artifact.getId());
+        }
+        return null;
+    }
+
+    public List<ArtifactItem> getArtifactItems(String groupId, String artifactId) {
+        Artifact artifact = getArtifact(groupId, artifactId);
+        if (null != artifact) {
+            return artifactItemRepository.findByArtifactIdOrderByVersionDesc(artifact.getId());
+        }
+        return null;
+    }
+
+    public List<Artifact> getArtifacts() {
+        return artifactRepository.findAll();
+    }
+
+    public void safetySave(Artifact artifact) {
+        Artifact oldArtifact = getArtifact(artifact.getGroupId(), artifact.getArtifactId());
+        if (null != oldArtifact) {
+            oldArtifact.setDescription(artifact.getDescription());
+            oldArtifact.setAutoUpdate(artifact.isAutoUpdate());
+        } else {
+            oldArtifact = artifact;
+        }
+        artifactRepository.save(oldArtifact);
+    }
+
+    public void save(Artifact artifact) {
+        artifactRepository.save(artifact);
+    }
+
+    public void save(List<Artifact> artifacts) {
+        artifactRepository.save(artifacts);
+    }
+
+    @Transactional
+    public void delete(Artifact artifact) {
+        List<Project> projects = projectService.findByArtifactId(artifact.getId());
+        Assert.isTrue(CollectionUtils.isEmpty(projects), "有项目正在使用该软件,无法删除");
+        Assert.isNull(getUpdateTask(artifact.getId()), "软件正在更新,请稍后操作");
+        artifactItemRepository.deleteByArtifactId(artifact.getId());
+        artifactRepository.delete(artifact);
+    }
+
+    public void deleteAll() {
+        artifactRepository.deleteAll();
+    }
+    /**
+     * 更新到远程仓库的最新版
+     * @param artifact
+     * @throws Exception
+     */
+    public ArtifactItem update(Artifact artifact) throws Exception{
+        String newVersion = remoteRepository.getLastVersion(artifact);
+        return updateToVersion(artifact, newVersion);
+    }
+
+    /**
+     * 更新到指定版本
+     * @param artifact
+     * @param version
+     * @throws Exception
+     */
+    public ArtifactItem updateToVersion(Artifact artifact, String version) throws Exception{
+        ArtifactItem artifactItem = getArtifactItem(artifact.getId(), version);
+        if (null == artifactItem) {
+            String taskName = artifactUpdateTasks.get(artifact.getId());
+            if (null != taskName) {
+                throw new Exception(String.format("仓库正在更新!执行步骤为【%s】", taskName));
+            }
+            try {
+                artifactUpdateTasks.put(artifact.getId(), String.format("下载版本%s清单", version));
+                if (Artifact.RepoType.DIFF.equals(Artifact.RepoType.valueOf(artifact.getRepoType()))) {
+                    artifactItem = updateFromDiffRepo(artifact, version);
+                } else {
+                    artifactItem = updateFromMavenRepo(artifact, version);
+                }
+                artifactUpdateTasks.put(artifact.getId(), "记录日志");
+                // update artifact info
+                artifactItem = artifactItemRepository.save(artifactItem);
+                artifact.setLast(artifactItem);
+                artifact = artifactRepository.save(artifact);
+            } finally {
+                artifactUpdateTasks.remove(artifact.getId());
+            }
+        }
+        return artifactItem;
+    }
+
+    private ArtifactItem updateFromDiffRepo(Artifact artifact, String version) throws Exception {
+        // get last manifest
+        byte[] data = remoteRepository.getManifestFile(artifact.getGroupId(), artifact.getArtifactId(), version);
+        Manifest manifest = ObjectUtils.read(data);
+        ArtifactItem artifactItem = new ArtifactItem(artifact, manifest);
+        localRepository.saveManifestFile(artifact, artifactItem, data);
+
+        artifactUpdateTasks.put(artifact.getId(), String.format("下载%s到%s差异包", artifact.getLastVersion(), version));
+        // get diff
+        data = remoteRepository.getDiffFile(artifact.getGroupId(), artifact.getArtifactId(), artifact.getLastVersion(), version);
+        localRepository.saveDiffFile(artifact, artifactItem, data);
+        return artifactItem;
+    }
+
+    private ArtifactItem updateFromMavenRepo(Artifact artifact, String version) throws Exception {
+        MavenMetadata metadata = remoteRepository.getMetadata(artifact.getGroupId(), artifact.getArtifactId());
+        ArtifactItem artifactItem = new ArtifactItem(artifact, metadata);
+        artifactUpdateTasks.put(artifact.getId(), String.format("下载%s程序包", version));
+        byte[] data = remoteRepository.getMavenFile(artifact.getGroupId(), artifact.getArtifactId(), version);
+        localRepository.saveMavenFile(artifact, artifactItem, data);
+        return artifactItem;
+    }
+
+    public Map<Long, String> getUpdateTasks() {
+        return artifactUpdateTasks;
+    }
+
+    public String getUpdateTask(long artifactId) {
+        return artifactUpdateTasks.get(artifactId);
+    }
+
+}

+ 92 - 0
src/main/java/com/uas/erp/manage/client/service/ClientService.java

@@ -0,0 +1,92 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.erp.manage.client.domain.ClientContainerInfo;
+import com.uas.erp.manage.client.domain.ClientInfo;
+import com.uas.erp.manage.client.domain.ClientProjectInfo;
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.Client;
+import com.uas.erp.manage.client.entity.Container;
+import com.uas.erp.manage.client.entity.Project;
+import com.uas.erp.manage.client.repository.ClientRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+@Service
+public class ClientService {
+
+    @Autowired
+    private ClientRepository clientRepository;
+
+    @Autowired
+    private ProjectService projectService;
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    @Autowired
+    private ContainerService containerService;
+
+    public Client getClient() {
+        List<Client> clients = clientRepository.findAll();
+        return CollectionUtils.isEmpty(clients) ? null : clients.get(0);
+    }
+
+    public void save(Client client) {
+        clientRepository.save(client);
+    }
+
+    public void safetySave(Client client) {
+        Client oldOne = getClient();
+        if (null != oldOne) {
+            oldOne.setName(client.getName());
+            oldOne.setBasePath(client.getBasePath());
+        }
+        clientRepository.save(oldOne);
+    }
+
+    public void initClient() {
+        Client client = getClient();
+        client.setInit(true);
+        client.setInitTime(System.currentTimeMillis());
+        clientRepository.save(client);
+    }
+
+    public ClientInfo getClientInfo() {
+        Client client = getClient();
+        if (null != client && client.isInit()) {
+            ClientInfo info = new ClientInfo();
+            info.setClientId(client.getId());
+            info.setBasePath(client.getBasePath());
+            info.setName(client.getName());
+
+            List<Project> projects = projectService.findAll();
+            List<ClientProjectInfo> projectInfos = new ArrayList<ClientProjectInfo>();
+            if (!CollectionUtils.isEmpty(projects)) {
+                for (Project project:projects) {
+                    Artifact artifact = artifactService.getArtifact(project.getArtifactId());
+                    projectInfos.add(new ClientProjectInfo(artifact, project));
+                }
+            }
+            info.setProjects(projectInfos);
+
+            List<Container> containers = containerService.findAll();
+            List<ClientContainerInfo> containerInfos = new ArrayList<ClientContainerInfo>();
+            if (!CollectionUtils.isEmpty(containers)) {
+                for (Container container:containers) {
+                    containerInfos.add(new ClientContainerInfo(container));
+                }
+            }
+            info.setContainers(containerInfos);
+            return info;
+        }
+        return null;
+    }
+
+}

+ 292 - 0
src/main/java/com/uas/erp/manage/client/service/ContainerService.java

@@ -0,0 +1,292 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.erp.manage.client.entity.Container;
+import com.uas.erp.manage.client.entity.Project;
+import com.uas.erp.manage.client.repository.ContainerRepository;
+import com.uas.erp.manage.client.util.ShellUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.*;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Service
+public class ContainerService {
+
+    @Autowired
+    private ContainerRepository containerRepository;
+
+    @Autowired
+    private ProjectService projectService;
+
+    public Container getContainerByPath(String path) throws Exception {
+        Container container = new Container(path);
+        File dir = new File(path);
+        if (dir.exists() && dir.isDirectory()) {
+            if (new File(dir.getAbsolutePath() + "/bin/catalina.sh").exists()) {
+                container.setType(Container.Type.TOMCAT.name());
+                container.setStartCommand(dir.getAbsolutePath() + "/bin/catalina.sh start");
+                container.setStopCommand(dir.getAbsolutePath() + "/bin/catalina.sh stop");
+                container.setStatusCommand(dir.getAbsolutePath() + "/bin/catalina.sh status");
+                container.setProcessCommand(String.format("ps aux | grep '%s' | grep -v 'grep' | awk '{print $2}'", dir.getAbsolutePath()));
+                container.setWebappsHome(dir.getAbsolutePath() + "/webapps");
+            } else if (new File(dir.getAbsolutePath() + "/bin/standalone.sh").exists()) {
+                container.setType(Container.Type.JBOSS.name());
+                container.setWebappsHome(dir.getAbsolutePath() + "/standalone/deployment");
+            }
+        }
+        return container;
+    }
+
+    public String getPid(Container container) throws Exception {
+        if (!StringUtils.isEmpty(container.getProcessCommand())) {
+            if (container.isRemote()) {
+                return ShellUtils.execute(String.format("ssh root@%s '%s'", container.getHost(),
+                        container.getProcessCommand()));
+            } else {
+                return ShellUtils.execute(container.getProcessCommand());
+            }
+        }
+        return null;
+    }
+
+    public String getStatus(Container container) throws Exception{
+        if (container.isCluster()) {
+            if (!CollectionUtils.isEmpty(container.getNodes())) {
+                for (Container node:container.getNodes()) {
+                    if (!Container.Status.RUNNING.name().equals(getStatus(node))) {
+                        return Container.Status.UNRECOGNIZED.name();
+                    }
+                }
+                return Container.Status.RUNNING.name();
+            }
+            return Container.Status.UNRECOGNIZED.name();
+        } else {
+            if (!StringUtils.isEmpty(getPid(container)))
+                return Container.Status.RUNNING.name();
+            return Container.Status.STOPPED.name();
+        }
+    }
+
+    public void safetySave(Container container) throws Exception{
+        Container oldOne = null;
+        if (null != container.getId()){
+            oldOne = containerRepository.findOne(container.getId());
+            if (null != oldOne) {
+                oldOne.setDescription(container.getDescription());
+                oldOne.setHome(container.getHome());
+                oldOne.setType(container.getType());
+                oldOne.setPort(container.getPort());
+                oldOne.setStatus(getStatus(oldOne));
+                oldOne.setWebappsHome(container.getWebappsHome());
+                oldOne.setProcessCommand(container.getProcessCommand());
+                oldOne.setStatusCommand(container.getStatusCommand());
+                oldOne.setStartCommand(container.getStartCommand());
+                oldOne.setStopCommand(container.getStopCommand());
+                oldOne.setNodes(container.getNodes());
+            } else {
+                oldOne = container;
+                oldOne.setId(null);
+            }
+        } else {
+            oldOne = containerRepository.findByHome(container.getHome());
+            if (null != oldOne) {
+                oldOne.setDescription(container.getDescription());
+                oldOne.setType(container.getType());
+                oldOne.setPort(container.getPort());
+                oldOne.setStatus(getStatus(oldOne));
+                oldOne.setWebappsHome(container.getWebappsHome());
+                oldOne.setProcessCommand(container.getProcessCommand());
+                oldOne.setStatusCommand(container.getStatusCommand());
+                oldOne.setStartCommand(container.getStartCommand());
+                oldOne.setStopCommand(container.getStopCommand());
+                oldOne.setNodes(container.getNodes());
+            } else {
+                oldOne = container;
+            }
+        }
+        containerRepository.save(oldOne);
+    }
+
+    public void save(Container container) {
+        containerRepository.save(container);
+    }
+
+    public void save(List<Container> containers) {
+        containerRepository.save(containers);
+    }
+
+    @Transactional
+    public void delete(Container container){
+        List<Project> projects = projectService.findByContainerId(container.getId());
+        Assert.isTrue(CollectionUtils.isEmpty(projects), "有项目正在使用该容器,无法删除");
+        if (container.isCluster() && !CollectionUtils.isEmpty(container.getNodes())) {
+            for (Container node:container.getNodes()) {
+                delete(node);
+            }
+        }
+        containerRepository.delete(container);
+    }
+
+    public void deleteAll() {
+        containerRepository.deleteAll();
+    }
+
+    public Container findOne(long containerId) {
+        return containerRepository.findOne(containerId);
+    }
+
+    public List<Container> findAll() {
+        return containerRepository.findAll();
+    }
+
+    public void start(Container container) throws Exception{
+        if (!StringUtils.isEmpty(container.getStartCommand())) {
+            if (container.isRemote()) {
+                ShellUtils.execute(String.format("ssh root@%s '%s'", container.getHost(),
+                        container.getStartCommand()));
+            } else {
+                ShellUtils.execute(container.getStartCommand());
+            }
+        } else {
+            if (container.isCluster()) {
+                if (!CollectionUtils.isEmpty(container.getNodes())) {
+                    for (Container node : container.getNodes()) {
+                        start(node);
+                    }
+                }
+            }
+        }
+    }
+
+    public void stop(Container container) throws Exception {
+        if (!StringUtils.isEmpty(container.getStopCommand())) {
+            if (container.isRemote()) {
+                ShellUtils.execute(String.format("ssh root@%s '%s'", container.getHost(),
+                        container.getStopCommand()));
+            } else {
+                ShellUtils.execute(container.getStopCommand());
+            }
+        } else {
+            if (container.isCluster()) {
+                if (!CollectionUtils.isEmpty(container.getNodes())) {
+                    for (Container node : container.getNodes()) {
+                        stop(node);
+                    }
+                } else {
+                    String pid = getPid(container);
+                    if (!StringUtils.isEmpty(pid)) {
+                        if (container.isRemote()) {
+                            ShellUtils.execute(String.format("ssh root@%s 'kill -9 %s'", container.getHost(), pid));
+                        } else {
+                            ShellUtils.execute("kill -9 " + pid);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public void restart(Container container) throws Exception {
+        stop(container);
+        start(container);
+    }
+
+    /**
+     * 清除旧文件目录
+     * @param container
+     * @param context
+     */
+    public void clearByContext(Container container, String context) throws Exception{
+        if (container.isCluster()) {
+            if (!CollectionUtils.isEmpty(container.getNodes())) {
+                for (Container node : container.getNodes()) {
+                    if (node.isRemote())
+                        clearRemoteByContext(node, context);
+                    else
+                        clearLocalByContext(container, context);
+                }
+            }
+        } else {
+            if (container.isRemote())
+                clearRemoteByContext(container, context);
+            else
+                clearLocalByContext(container, context);
+        }
+    }
+
+    private void clearLocalByContext(Container container, String context) throws Exception{
+        File deployDir = new File(container.getWebappsHome());
+        File dir = new File(deployDir, context);
+        if (dir.exists()) {
+            FileSystemUtils.deleteRecursively(dir);
+        }
+        File file = new File(deployDir, context + ".war");
+        if (file.exists()) {
+            file.delete();
+        }
+        file = new File(deployDir, context + ".deployed");
+        if (file.exists()) {
+            file.delete();
+        }
+        file = new File(deployDir, context + ".undeployed");
+        if (file.exists()) {
+            file.delete();
+        }
+        file = new File(deployDir, context + ".deploying");
+        if (file.exists()) {
+            file.delete();
+        }
+    }
+
+    private void clearRemoteByContext(Container container, String context) throws Exception{
+        File deployDir = new File(container.getWebappsHome());
+        ShellUtils.execute(String.format("ssh root@%s 'rm -rf %s/%s'", container.getHost(), deployDir.getAbsolutePath(),
+                context));
+        ShellUtils.execute(String.format("ssh root@%s 'rm -rf %s/%s.war'", container.getHost(), deployDir.getAbsolutePath(),
+                context));
+        ShellUtils.execute(String.format("ssh root@%s 'rm -rf %s/%s.deployed'", container.getHost(), deployDir.getAbsolutePath(),
+                context));
+        ShellUtils.execute(String.format("ssh root@%s 'rm -rf %s/%s.undeployed'", container.getHost(), deployDir.getAbsolutePath(),
+                context));
+        ShellUtils.execute(String.format("ssh root@%s 'rm -rf %s/%s.deploying'", container.getHost(), deployDir.getAbsolutePath(),
+                context));
+    }
+
+    public void deployByFile(Container container, File buildFile) throws Exception{
+        if (!StringUtils.isEmpty(container.getDeployCommand())) {
+            if (container.isRemote()) {
+                // send file
+                ShellUtils.execute(String.format("scp %s root@%s:/tmp/", buildFile.getAbsolutePath(),
+                        container.getHost(), buildFile.getName()));
+                // deploy
+                ShellUtils.execute(String.format("ssh root@%s '%s %s'", container.getHost(),
+                        container.getDeployCommand(), "/tmp/" + buildFile.getName()));
+            } else {
+                ShellUtils.execute(container.getDeployCommand() + " " + buildFile.getAbsolutePath());
+            }
+        } else {
+            if (container.isCluster()) {
+                if (!CollectionUtils.isEmpty(container.getNodes())) {
+                    for (Container node : container.getNodes()) {
+                        deployByFile(node, buildFile);
+                    }
+                }
+            } else {
+                if (container.isRemote()) {
+                    // send file only
+                    ShellUtils.execute(String.format("scp %s root@%s:", buildFile.getAbsolutePath(),
+                            container.getHost(), container.getWebappsHome()));
+                } else {
+                    FileCopyUtils.copy(buildFile, new File(container.getWebappsHome()));
+                }
+            }
+        }
+    }
+
+}

+ 251 - 0
src/main/java/com/uas/erp/manage/client/service/LocalRepositoryService.java

@@ -0,0 +1,251 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.ops.diff.domain.Manifest;
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.entity.ArtifactItem;
+import com.uas.erp.manage.client.plugins.ProjectBuildPlugin;
+import com.uas.erp.manage.client.util.*;
+import com.uas.erp.manage.client.util.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.*;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/17.
+ */
+@Service
+public class LocalRepositoryService {
+
+    @Autowired
+    private SettingService settingService;
+
+    private File getFile(String...dirOrFileNames) {
+        return new File(StringUtils.arrayToDelimitedString(dirOrFileNames, File.separator));
+    }
+
+    private String getLocalRepositoryHome() {
+        String localResourceHome = settingService.getValue("resource.path");
+        Assert.notNull(localResourceHome);
+        return localResourceHome + File.separator + "repository";
+    }
+
+    private String getLocalAttachHome() {
+        String localResourceHome = settingService.getValue("resource.path");
+        Assert.notNull(localResourceHome);
+        return localResourceHome + File.separator + "attach";
+    }
+
+    private File getArtifactHome(Artifact artifact) {
+        File dir = getFile(getLocalRepositoryHome(), artifact.getGroupId(), artifact.getArtifactId());
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+        return dir;
+    }
+
+    private File getArtifactItemHome(Artifact artifact, ArtifactItem artifactItem) {
+        File dir = getFile(getArtifactHome(artifact).getAbsolutePath(), artifactItem.getVersion());
+        if (!dir.exists()) {
+            dir.mkdirs();
+        }
+        return dir;
+    }
+
+    public void saveManifestFile(Artifact artifact, ArtifactItem artifactItem, byte[] data) throws IOException{
+        File dir = getArtifactItemHome(artifact, artifactItem);
+        File manifestFile = new File(dir, ".manifest");
+        FileCopyUtils.copy(data, manifestFile);
+    }
+
+    public void saveDiffFile(Artifact artifact, ArtifactItem artifactItem, byte[] data) throws IOException{
+        File dir = getArtifactItemHome(artifact, artifactItem);
+        ZipUtils.unzip(data, dir.getAbsolutePath());
+    }
+
+    public void saveMavenFile(Artifact artifact, ArtifactItem artifactItem, byte[] data) throws IOException{
+        File dir = getArtifactItemHome(artifact, artifactItem);
+        ZipUtils.unzip(data, dir.getAbsolutePath());
+    }
+
+    public File getManifestFile(Artifact artifact, ArtifactItem artifactItem) {
+        File dir = getArtifactItemHome(artifact, artifactItem);
+        return new File(dir, ".manifest");
+    }
+
+    public Manifest getManifest(Artifact artifact, ArtifactItem artifactItem) throws Exception{
+        File manifestFile = getManifestFile(artifact, artifactItem);
+        if (manifestFile.exists()) {
+            Manifest manifest = ObjectUtils.read(FileCopyUtils.copyToByteArray(manifestFile));
+            return manifest;
+        }
+        return null;
+    }
+
+    /**
+     * 按指定版本清单收集差异文件进行编译
+     * @param buildName
+     * @param plugins
+     * @throws Exception
+     */
+    public File buildByManifest(Artifact artifact, List<ArtifactItem> allItems, ArtifactItem currentItem, String buildName, ProjectBuildPlugin...plugins) throws Exception{
+        Manifest manifest = getManifest(artifact, currentItem);
+        if (null != manifest) {
+            File tmpdir = FileUtils.createTemporaryDirectory();
+            File buildFile = getBuildFile(artifact, buildName);
+            try {
+                copyResourcesByManifest(artifact, allItems, manifest, tmpdir.getAbsolutePath());
+                // plugins after copy-resources
+                if (null != plugins) {
+                    for (ProjectBuildPlugin plugin:plugins) {
+                        plugin.onBuild(tmpdir);
+                    }
+                }
+                ZipUtils.zip(tmpdir, buildFile);
+                return buildFile;
+            } finally {
+                FileSystemUtils.deleteRecursively(tmpdir);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 编译后文件默认存放在{repository}/{groupId}/{artifactId}下面
+     * @param artifact
+     * @param buildName
+     * @return
+     */
+    private File getBuildFile(Artifact artifact, String buildName) {
+        // tomcat的命名方法
+        if (StringUtils.isEmpty(buildName) || "/".equals(buildName)) {
+            buildName = "ROOT";
+        }
+        return getFile(getArtifactHome(artifact).getAbsolutePath(), buildName + "." + artifact.getPackaging());
+    }
+
+    /**
+     * 按清单搜集文件
+     * @param artifact
+     * @param manifest
+     * @param target
+     */
+    private void copyResourcesByManifest(Artifact artifact, List<ArtifactItem> allItems, Manifest manifest, String target) throws IOException{
+        if (null != manifest.getChildren()) {
+            if (!"/".equals(manifest.getPath())) {
+                new File(target + manifest.getPath()).mkdirs();
+            }
+            for (Manifest child:manifest.getChildren()) {
+                copyResourcesByManifest(artifact, allItems, child, target);
+            }
+        } else {
+            File file = getResourceByVersion(artifact, allItems, manifest.getPath(), manifest.getVersion());
+            if (null != file) {
+                FileCopyUtils.copy(file, new File(target + manifest.getPath()));
+            }
+        }
+    }
+
+    /**
+     * 按版本从高到低依次遍历查找资源
+     * @param artifact
+     * @param filePath
+     * @param needVersion
+     * @return
+     */
+    private File getResourceByVersion(Artifact artifact, List<ArtifactItem> allItems, String filePath, String needVersion) {
+        for (ArtifactItem item:allItems) {
+            // less or equals {version}
+            if (item.getVersion().compareTo(needVersion) <= 0) {
+                File file = getFile(getArtifactItemHome(artifact, item).getAbsolutePath(), filePath);
+                if (file.exists()) {
+                    return file;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 字符串保存到本地附件
+     * @param resourceStr
+     * @return
+     * @throws IOException
+     */
+    public String saveResourceAsAttach(String resourceStr) throws IOException{
+        File file = new File(getLocalAttachHome(), StringUtil.uuid());
+        if (!file.getParentFile().exists()) {
+            file.getParentFile().mkdirs();
+        }
+        FileCopyUtils.copy(resourceStr.getBytes(Charset.forName("UTF-8")), file);
+        return file.getName();
+    }
+
+    public File getAttach(String attachName){
+        return new File(getLocalAttachHome(), attachName);
+    }
+
+    /**
+     * 读取本地附件文件
+     * @param attachName
+     * @return
+     * @throws IOException
+     */
+    public byte[] getAttachAsByteArray(String attachName) throws IOException{
+        File file = getAttach(attachName);
+        if (file.exists()) {
+            return FileCopyUtils.copyToByteArray(file);
+        }
+        return null;
+    }
+
+    /**
+     * 读取本地附件文件字符串内容
+     * @param attachName
+     * @return
+     * @throws IOException
+     */
+    public String getAttachAsString(String attachName) throws IOException{
+        File file = getAttach(attachName);
+        if (file.exists()) {
+            FileReader reader = new FileReader(file);
+            try {
+                return FileCopyUtils.copyToString(reader);
+            } finally {
+                IOUtils.closeQuietly(reader);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 复制maven文件编译
+     * @param artifact
+     * @param currentItem
+     * @param buildName
+     * @param plugins
+     * @return
+     * @throws Exception
+     */
+    public File buildMavenFile(Artifact artifact, ArtifactItem currentItem, String buildName, ProjectBuildPlugin...plugins) throws Exception{
+        File tmpdir = FileUtils.createTemporaryDirectory();
+        File buildFile = getBuildFile(artifact, buildName);
+        try {
+            FileSystemUtils.copyRecursively(getArtifactItemHome(artifact, currentItem), tmpdir);
+            // plugins after copy-resources
+            if (null != plugins) {
+                for (ProjectBuildPlugin plugin:plugins) {
+                    plugin.onBuild(tmpdir);
+                }
+            }
+            ZipUtils.zip(tmpdir, buildFile);
+            return buildFile;
+        } finally {
+            FileSystemUtils.deleteRecursively(tmpdir);
+        }
+    }
+
+}

+ 132 - 0
src/main/java/com/uas/erp/manage/client/service/ProjectService.java

@@ -0,0 +1,132 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.erp.manage.client.entity.*;
+import com.uas.erp.manage.client.plugins.ProjectResourceReplacePlugin;
+import com.uas.erp.manage.client.repository.ProjectDeployLogRepository;
+import com.uas.erp.manage.client.repository.ProjectRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import java.io.File;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Service
+public class ProjectService {
+
+    @Autowired
+    private ProjectRepository projectRepository;
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    @Autowired
+    private LocalRepositoryService localRepository;
+
+    @Autowired
+    private ContainerService containerService;
+
+    @Autowired
+    private ProjectDeployLogRepository projectDeployLogRepository;
+
+    private Map<Long, String> projectDeployTasks = new HashMap<Long, String>();
+
+    public void save(Project project) {
+        projectRepository.save(project);
+    }
+
+    public Project get(long id) {
+        return projectRepository.findOne(id);
+    }
+
+    @Transactional
+    public void delete(long id) throws Exception{
+        Project project = projectRepository.findOne(id);
+        if (null != project) {
+            Container container = containerService.findOne(project.getContainerId());
+            if (null != container)
+                containerService.clearByContext(container, project.getContextName());
+            projectDeployLogRepository.deleteByProjectId(id);
+            projectRepository.delete(project);
+        }
+    }
+
+    public void deleteAll() {
+        projectDeployLogRepository.deleteAll();
+        projectRepository.deleteAll();
+        this.projectDeployTasks = new HashMap<Long, String>();
+    }
+
+    public Project findOne(long id) {
+        return projectRepository.findOne(id);
+    }
+
+    public List<Project> findAll() {
+        return projectRepository.findAll();
+    }
+
+    public List<Project> findByArtifactId(long artifactId) {
+        return projectRepository.findByArtifactId(artifactId);
+    }
+
+    public List<Project> findByContainerId(long containerId) {
+        return projectRepository.findByContainerId(containerId);
+    }
+
+    public void deploy(Project project, ArtifactItem artifactItem) throws Exception{
+        String taskName = projectDeployTasks.get(project.getId());
+        if (null != taskName)
+            throw new Exception(String.format("项目正在部署!执行步骤为【%s】", taskName));
+        try {
+            projectDeployTasks.put(project.getId(), "打包");
+            final Artifact artifact = artifactService.getArtifact(artifactItem.getArtifactId());
+            List<ArtifactItem> allItems = artifactService.getArtifactItems(artifact.getId());
+            // 打包
+            File buildFile = null;
+            if (Artifact.RepoType.DIFF.equals(Artifact.RepoType.valueOf(artifact.getRepoType()))) {
+                buildFile = localRepository.buildByManifest(artifact, allItems, artifactItem, project.getContextName(),
+                        new ProjectResourceReplacePlugin(project, localRepository));
+            } else {
+                buildFile = localRepository.buildMavenFile(artifact, artifactItem, project.getContextName(),
+                        new ProjectResourceReplacePlugin(project, localRepository));
+            }
+            // 部署
+            Container container = containerService.findOne(project.getContainerId());
+            Assert.notNull(container);
+            projectDeployTasks.put(project.getId(), "停止容器");
+            containerService.stop(container);
+            containerService.clearByContext(container, project.getContextName());
+            containerService.deployByFile(container, buildFile);
+            projectDeployTasks.put(project.getId(), "启动容器");
+            containerService.start(container);
+            projectDeployTasks.put(project.getId(), "记录日志");
+            project.setDeployTime(new Date().getTime());
+            project.setDeployVersion(artifactItem.getVersion());
+            save(project);
+            // 日志
+            projectDeployLogRepository.save(new ProjectDeployLog(project, artifactItem));
+        } finally {
+            projectDeployTasks.remove(project.getId());
+        }
+    }
+
+    public Map<Long, String> getDeployTasks() {
+        return projectDeployTasks;
+    }
+
+    public String getDeployTask(long projectId) {
+        return projectDeployTasks.get(projectId);
+    }
+
+    public List<ProjectDeployLog> getDeployLogs(long projectId) {
+        return projectDeployLogRepository.findByProjectIdOrderByDeployTimeDesc(projectId);
+    }
+
+}

+ 35 - 0
src/main/java/com/uas/erp/manage/client/service/RemoteOpsService.java

@@ -0,0 +1,35 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.erp.manage.client.domain.ClientInfo;
+import com.uas.erp.manage.client.web.ResultWrap;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Service
+public class RemoteOpsService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private SettingService settingService;
+
+    private Logger logger = Logger.getLogger(RemoteOpsService.class);
+
+    private String getOpsUrl() {
+        return settingService.getValue("ops.url");
+    }
+
+    public void pushClientInfoToRemote(ClientInfo clientInfo){
+        ResultWrap<String> result = restTemplate.postForObject(getOpsUrl() + "/client/info", clientInfo, ResultWrap.class);
+        if (!result.isSuccess()) {
+            logger.error("pushClientInfoToRemote return error: [" + result.getMessage() + "]");
+        }
+    }
+
+}

+ 115 - 0
src/main/java/com/uas/erp/manage/client/service/RemoteRepositoryService.java

@@ -0,0 +1,115 @@
+package com.uas.erp.manage.client.service;
+
+import com.thoughtworks.xstream.XStream;
+import com.uas.erp.manage.client.domain.MavenMetadata;
+import com.uas.erp.manage.client.domain.MavenPom;
+import com.uas.erp.manage.client.entity.Artifact;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.net.URL;
+
+/**
+ * Created by Pro1 on 2017/6/17.
+ */
+@Service
+public class RemoteRepositoryService {
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Autowired
+    private SettingService settingService;
+
+    private String getDiffRepositoryUrl() {
+        return settingService.getValue("diff.repo.url");
+    }
+
+    private String getMavenRepositoryUrl() {
+        return settingService.getValue("maven.repo.url");
+    }
+
+    /**
+     * 获取最新版本
+     * @param artifact
+     * @return
+     */
+    public String getLastVersion(Artifact artifact) throws Exception{
+        if (Artifact.RepoType.DIFF.equals(Artifact.RepoType.valueOf(artifact.getRepoType()))) {
+            return restTemplate.getForObject(getDiffRepositoryUrl() + "/version?groupId={groupId}&artifactId={artifactId}", String.class,
+                    artifact.getGroupId(), artifact.getArtifactId());
+        }
+        MavenMetadata metadata = getMetadata(artifact.getGroupId(), artifact.getArtifactId());
+        return null == metadata ? null : metadata.getVersioning().getLatest();
+    }
+
+    /**
+     * (diff)下载版本文件清单
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @return
+     */
+    public byte[] getManifestFile(String groupId, String artifactId, String version) {
+        return restTemplate.getForObject(getDiffRepositoryUrl() + "/manifest?groupId={groupId}&artifactId={artifactId}&version={version}",
+                byte[].class, groupId, artifactId, version);
+    }
+
+    /**
+     * (diff)下载版本间差异文件包
+     * @param groupId
+     * @param artifactId
+     * @param fromVersion
+     * @param toVersion
+     * @return
+     */
+    public byte[] getDiffFile(String groupId, String artifactId, String fromVersion, String toVersion) {
+        return restTemplate.getForObject(getDiffRepositoryUrl() + "/diff?groupId={groupId}&artifactId={artifactId}&fromVersion={fromVersion}&toVersion={toVersion}",
+                byte[].class, groupId, artifactId, fromVersion, toVersion);
+    }
+
+    /**
+     * (maven)版本信息
+     * @param groupId
+     * @param artifactId
+     * @return
+     */
+    public MavenMetadata getMetadata(String groupId, String artifactId) throws Exception{
+        XStream xStream = new XStream();
+        xStream.setMode(XStream.NO_REFERENCES);
+        xStream.processAnnotations(new Class[]{MavenMetadata.class, MavenMetadata.Versioning.class});
+        return (MavenMetadata) xStream.fromXML(new URL(getMavenRepositoryUrl() + "/" + groupId.replace(".", "/") + artifactId + "/maven-metadata.xml"));
+    }
+
+    /**
+     * (maven)POM文件
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @return
+     * @throws Exception
+     */
+    public MavenPom getPom(String groupId, String artifactId, String version) throws Exception{
+        XStream xStream = new XStream();
+        xStream.setMode(XStream.NO_REFERENCES);
+        xStream.processAnnotations(MavenPom.class);
+        return (MavenPom) xStream.fromXML(new URL(String.format(getMavenRepositoryUrl() + "/%s/%s/%s/%s-%s.pom",
+                groupId.replace(".", "/"), artifactId, version, artifactId, version)));
+    }
+
+    /**
+     * (maven)仓库文件
+     * @param groupId
+     * @param artifactId
+     * @param version
+     * @return
+     * @throws Exception
+     */
+    public byte[] getMavenFile(String groupId, String artifactId, String version) throws Exception {
+        MavenPom pom = getPom(groupId, artifactId, version);
+        return restTemplate.getForObject(getMavenRepositoryUrl() + "/{groupPath}/{artifactId}/{version}/{artifactId}-{version}.{packaging}",
+                byte[].class, groupId.replace(".", "/"), artifactId, version, artifactId, version, pom.getPackaging());
+    }
+
+}

+ 52 - 0
src/main/java/com/uas/erp/manage/client/service/SettingService.java

@@ -0,0 +1,52 @@
+package com.uas.erp.manage.client.service;
+
+import com.uas.erp.manage.client.entity.Setting;
+import com.uas.erp.manage.client.repository.SettingRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Service
+public class SettingService {
+
+    @Autowired
+    private SettingRepository settingRepository;
+
+    public List<Setting> findAll() {
+        return settingRepository.findAll();
+    }
+
+    public List<Setting> findByGroup(String group) {
+        return settingRepository.findByGroupOrderByKey(group);
+    }
+
+    public Setting findOne(String key) {
+        return settingRepository.findOne(key);
+    }
+
+    public String getValue(String key) {
+        Setting setting = settingRepository.findOne(key);
+        return null != setting ? setting.getValue() : null;
+    }
+
+    public void save(Setting setting) {
+        settingRepository.save(setting);
+    }
+
+    public void save(List<Setting> settings) {
+        settingRepository.save(settings);
+    }
+
+    public void delete(Setting setting) {
+        settingRepository.delete(setting);
+    }
+
+    public void deleteAll() {
+        settingRepository.deleteAll();
+    }
+
+}

+ 33 - 0
src/main/java/com/uas/erp/manage/client/task/ScheduledArtifactUpdater.java

@@ -0,0 +1,33 @@
+package com.uas.erp.manage.client.task;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.service.ArtifactService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/17.
+ */
+@Component
+public class ScheduledArtifactUpdater {
+
+    @Autowired
+    private ArtifactService artifactService;
+
+    @Scheduled(cron = "0 0 1 * * *")
+    public void update() throws Exception{
+        List<Artifact> artifacts = artifactService.getArtifacts();
+        if (!CollectionUtils.isEmpty(artifacts)) {
+            for (Artifact artifact:artifacts) {
+                if (artifact.isAutoUpdate())
+                    artifactService.update(artifact);
+            }
+        }
+    }
+
+}

+ 44 - 0
src/main/java/com/uas/erp/manage/client/task/ScheduledContainerRefresher.java

@@ -0,0 +1,44 @@
+package com.uas.erp.manage.client.task;
+
+import com.uas.erp.manage.client.entity.Container;
+import com.uas.erp.manage.client.service.ContainerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Component
+public class ScheduledContainerRefresher {
+
+    @Autowired
+    private ContainerService containerService;
+
+    /**
+     * 每分钟检测容器状态
+     * @throws Exception
+     */
+    @Scheduled(cron = "0 * * * * *")
+    public void refreshStatus() throws Exception{
+        List<Container> containers = containerService.findAll();
+        if (!CollectionUtils.isEmpty(containers)) {
+            List<Container> changed = new ArrayList<Container>();
+            for (Container container:containers) {
+                String status = containerService.getStatus(container);
+                if (!status.equals(container.getStatus())) {
+                    container.setStatus(status);
+                    changed.add(container);
+                }
+            }
+            if (!CollectionUtils.isEmpty(changed)) {
+                containerService.save(changed);
+            }
+        }
+    }
+
+}

+ 34 - 0
src/main/java/com/uas/erp/manage/client/task/ScheduledRemotePusher.java

@@ -0,0 +1,34 @@
+package com.uas.erp.manage.client.task;
+
+import com.uas.erp.manage.client.domain.ClientInfo;
+import com.uas.erp.manage.client.service.ClientService;
+import com.uas.erp.manage.client.service.RemoteOpsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+@Component
+public class ScheduledRemotePusher {
+
+    @Autowired
+    private ClientService clientService;
+
+    @Autowired
+    private RemoteOpsService remoteOpsService;
+
+    /**
+     * 每5分钟报告一次
+     * @throws Exception
+     */
+    @Scheduled(cron = "0 */5 * * * *")
+    public void pushClientInfoToRemote() throws Exception{
+        ClientInfo info = clientService.getClientInfo();
+        if (null != info) {
+            remoteOpsService.pushClientInfoToRemote(info);
+        }
+    }
+
+}

+ 16 - 0
src/main/java/com/uas/erp/manage/client/util/DateTimeUtils.java

@@ -0,0 +1,16 @@
+package com.uas.erp.manage.client.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Created by Pro1 on 2017/6/26.
+ */
+public class DateTimeUtils {
+
+    public static Date parseDateTime(String date, String formatter) throws ParseException{
+        return new SimpleDateFormat(formatter).parse(date);
+    }
+
+}

+ 16 - 0
src/main/java/com/uas/erp/manage/client/util/FileUtils.java

@@ -0,0 +1,16 @@
+package com.uas.erp.manage.client.util;
+
+import java.io.File;
+
+/**
+ * Created by Pro1 on 2017/6/27.
+ */
+public class FileUtils {
+
+    public static File createTemporaryDirectory() {
+        File tmpdir = new File(System.getProperty("java.io.tmpdir"), StringUtil.uuid());
+        tmpdir.mkdir();
+        return tmpdir;
+    }
+
+}

+ 22 - 0
src/main/java/com/uas/erp/manage/client/util/IOUtils.java

@@ -0,0 +1,22 @@
+package com.uas.erp.manage.client.util;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Created by Pro1 on 2017/6/15.
+ */
+public class IOUtils {
+
+    public static void closeQuietly(Closeable... closeables) {
+        if(null != closeables)
+            for(Closeable closeable:closeables)
+                try {
+                    if(closeable != null) {
+                        closeable.close();
+                    }
+                } catch (IOException var2) {
+                }
+    }
+
+}

+ 26 - 0
src/main/java/com/uas/erp/manage/client/util/ObjectUtils.java

@@ -0,0 +1,26 @@
+package com.uas.erp.manage.client.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+/**
+ * Created by Pro1 on 2017/6/13.
+ */
+public class ObjectUtils {
+
+    /**
+     * 读对象
+     *
+     * @param data
+     * @return
+     * @throws Exception
+     */
+    public static <T> T read(byte[] data) throws IOException, ClassNotFoundException {
+        ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(data));
+        T obj = (T) is.readObject();
+        is.close();
+        return obj;
+    }
+
+}

+ 46 - 0
src/main/java/com/uas/erp/manage/client/util/ShellUtils.java

@@ -0,0 +1,46 @@
+package com.uas.erp.manage.client.util;
+
+import org.springframework.util.FileCopyUtils;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+
+/**
+ * Created by Pro1 on 2017/6/19.
+ */
+public class ShellUtils {
+
+    /**
+     * 本地执行命令
+     *
+     * @param command
+     * @return
+     * @throws Exception
+     */
+    public static String execute(String command) throws Exception {
+        BufferedReader bufferedReader = null;
+        BufferedReader errBufferedReader = null;
+        BufferedWriter bufferedWriter = null;
+        try {
+            // 执行Shell命令
+            Process pid = Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command });
+            if (pid != null) {
+                bufferedReader = new BufferedReader(new InputStreamReader(pid.getInputStream()), 1024);
+                errBufferedReader = new BufferedReader(new InputStreamReader(pid.getErrorStream()), 1024);
+                StringWriter writer = new StringWriter();
+                bufferedWriter = new BufferedWriter(writer);
+                pid.waitFor();
+                // 读取Shell的输出内容,并添加到stringBuffer中
+                FileCopyUtils.copy(bufferedReader, bufferedWriter);
+                FileCopyUtils.copy(errBufferedReader, bufferedWriter);
+                return writer.toString();
+            }
+        } finally {
+            IOUtils.closeQuietly(bufferedReader, errBufferedReader, bufferedWriter);
+        }
+        return null;
+    }
+
+}

+ 26 - 0
src/main/java/com/uas/erp/manage/client/util/StringUtil.java

@@ -0,0 +1,26 @@
+package com.uas.erp.manage.client.util;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.UUID;
+
+/**
+ * Created by Pro1 on 2017/6/13.
+ */
+public class StringUtil {
+
+    public static String uuid() {
+        return UUID.randomUUID().toString();
+    }
+
+    public static String copyResource(String resourcePath) throws IOException{
+        ClassPathResource resource = new ClassPathResource(resourcePath);
+        if (resource.exists()) {
+            return StreamUtils.copyToString(resource.getInputStream(), Charset.forName("UTF-8"));
+        }
+        return null;
+    }
+}

+ 65 - 0
src/main/java/com/uas/erp/manage/client/util/ZipUtils.java

@@ -0,0 +1,65 @@
+package com.uas.erp.manage.client.util;
+
+import org.springframework.util.StreamUtils;
+
+import java.io.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * Created by Pro1 on 2017/6/13.
+ */
+public class ZipUtils {
+
+    public static void unzip(byte[] zipData, String targetPath) throws IOException{
+        ZipInputStream in = new ZipInputStream(new ByteArrayInputStream(zipData));
+        ZipEntry entry;
+        File file;
+        BufferedOutputStream out = null;
+        while((entry = in.getNextEntry())!=null && !entry.isDirectory()){
+            file = new File(targetPath, entry.getName());
+            if (!file.getParentFile().exists()) {
+               file.getParentFile().mkdirs();
+            }
+            out = new BufferedOutputStream(new FileOutputStream(file));
+            StreamUtils.copy(in, out);
+            out.flush();
+        }
+        in.closeEntry();
+        IOUtils.closeQuietly(in, out);
+    }
+
+    public static void zip(File source, File zipFile) throws IOException{
+        if (source.exists()) {
+            FileOutputStream fileOut = new FileOutputStream(zipFile);
+            ZipOutputStream zipOut = new ZipOutputStream(fileOut);
+            try {
+                addEntry(null, source, zipOut);
+                // 如果希望保留sourcePath文件夹,使用addEntry("", source, zipOut);
+            } finally {
+                IOUtils.closeQuietly(zipOut, fileOut);
+            }
+        }
+    }
+
+    private static void addEntry(String entryPath, File source, ZipOutputStream zipOut) throws IOException {
+        String entry = null == entryPath ? "" : (entryPath + source.getName());
+        if (source.isDirectory()) {
+            entry = entry.isEmpty() ? entry : (entry + File.separator);
+            for (File file : source.listFiles()) {
+                addEntry(entry, file, zipOut);
+            }
+        } else {
+            FileInputStream fileIn = new FileInputStream(source);
+            try {
+                zipOut.putNextEntry(new ZipEntry(entry));
+                StreamUtils.copy(fileIn, zipOut);
+                zipOut.closeEntry();
+            } finally {
+                IOUtils.closeQuietly(fileIn);
+            }
+        }
+    }
+
+}

+ 99 - 0
src/main/java/com/uas/erp/manage/client/web/ResponseWrap.java

@@ -0,0 +1,99 @@
+package com.uas.erp.manage.client.web;
+
+import com.alibaba.fastjson.JSON;
+import org.springframework.boot.jackson.JsonObjectSerializer;
+import org.springframework.boot.json.JsonJsonParser;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.ui.ModelMap;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Created by Pro1 on 2017/6/20.
+ */
+public class ResponseWrap {
+
+    private static final String successParam = "success";
+
+    private static final String responseCodeParam = "code";
+
+    private static final String responseMessageParam = "message";
+
+    private static final String responseContentParam = "content";
+
+    public static ModelMap success() {
+        return new ModelMap(successParam, true);
+    }
+
+    public static <T> ModelMap success(T content) {
+        return success().addAttribute(responseContentParam, content);
+    }
+
+    public static ModelMap error() {
+        return new ModelMap(successParam, false);
+    }
+
+    public static ModelMap error(String message) {
+        return error().addAttribute(responseMessageParam, message);
+    }
+
+    public static <T> ModelMap error(int code) {
+        return error().addAttribute(responseCodeParam, code);
+    }
+
+    public static <T> ModelMap error(int code, String message) {
+        return error(code).addAttribute(responseMessageParam, message);
+    }
+
+    public static ResponseEntity ok() {
+        return ResponseEntity.ok(success());
+    }
+
+    public static <T> ResponseEntity ok(T content) {
+        return ResponseEntity.ok(success(content));
+    }
+
+    public static <T> void ok(HttpServletResponse response, T content) throws IOException{
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(success(content)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void ok(HttpServletResponse response) throws IOException {
+        ok(response, null);
+    }
+
+    public static ResponseEntity badRequest() {
+        // do not use ResponseEntity.badRequest()
+        return ResponseEntity.ok(error());
+    }
+
+    public static <T> ResponseEntity badRequest(String message) {
+        return ResponseEntity.ok(error(message));
+    }
+
+    public static <T> void badRequest(HttpServletResponse response, int code, String message) throws IOException{
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(error(code, message)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void badRequest(HttpServletResponse response, String message) throws IOException {
+        badRequest(response, HttpStatus.BAD_REQUEST.value(), message);
+    }
+
+    public static <T> void badRequest(HttpServletResponse response) throws IOException {
+        badRequest(response, HttpStatus.BAD_REQUEST.value(), null);
+    }
+
+}

+ 47 - 0
src/main/java/com/uas/erp/manage/client/web/ResultWrap.java

@@ -0,0 +1,47 @@
+package com.uas.erp.manage.client.web;
+
+/**
+ * Created by Pro1 on 2017/6/23.
+ */
+public class ResultWrap<T> {
+
+    private boolean success;
+
+    private Integer code;
+
+    private String message;
+
+    private T content;
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public T getContent() {
+        return content;
+    }
+
+    public void setContent(T content) {
+        this.content = content;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 53 - 0
src/main/java/com/uas/ops/diff/domain/Manifest.java

@@ -0,0 +1,53 @@
+package com.uas.ops.diff.domain;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Created by Pro1 on 2017/6/13.
+ */
+public class Manifest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String path;
+    private String version;
+    private long lastChanged;
+    private List<Manifest> children;
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * 上次更新时间
+     */
+    public long getLastChanged() {
+        return lastChanged;
+    }
+
+    public void setLastChanged(long lastChanged) {
+        this.lastChanged = lastChanged;
+    }
+
+    public List<Manifest> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<Manifest> children) {
+        this.children = children;
+    }
+
+}

+ 34 - 0
src/main/resources/application.yml

@@ -0,0 +1,34 @@
+server:
+  port: 9090
+  contextPath: /uas_manage_client
+  tomcat:
+    uri-encoding: UTF-8
+
+spring:
+  application:
+    name: uas-manage-client
+  http:
+    encoding:
+      force: true
+      charset: utf-8
+      enabled: true
+  messages:
+    basename: i18n/messages
+  jpa:
+    show_sql: false
+    database: H2
+    hibernate:
+      ddl-auto: update
+  datasource:
+    driverClassName: org.h2.Driver
+    url: jdbc:h2:mem:uas
+  profiles:
+    active: dev
+---
+spring:
+  profiles: dev
+---
+spring:
+  profiles: prod
+  datasource:
+    url: jdbc:h2:file:~/data/uas_manage_client;FILE_LOCK=NO;DB_CLOSE_ON_EXIT=FALSE

+ 1 - 0
src/main/resources/i18n/messages.properties

@@ -0,0 +1 @@
+AbstractUserDetailsAuthenticationProvider.badCredentials=Bad Credentials

+ 1 - 0
src/main/resources/i18n/messages_en_US.properties

@@ -0,0 +1 @@
+AbstractUserDetailsAuthenticationProvider.badCredentials=Bad Credentials

+ 1 - 0
src/main/resources/i18n/messages_zh_CN.properties

@@ -0,0 +1 @@
+AbstractUserDetailsAuthenticationProvider.badCredentials=\u5BC6\u7801\u9519\u8BEF

+ 15 - 0
src/main/resources/init/artifact.json

@@ -0,0 +1,15 @@
+[{
+  "groupId": "com.uas.erp",
+  "artifactId": "uas",
+  "description": "UAS1.0程序",
+  "autoUpdate": true,
+  "repoType": "DIFF",
+  "packaging": "war"
+},{
+  "groupId": "com.uas.report",
+  "artifactId": "report",
+  "description": "Jasper打印程序",
+  "autoUpdate": true,
+  "repoType": "MAVEN",
+  "packaging": "war"
+}]

+ 31 - 0
src/main/resources/init/setting.json

@@ -0,0 +1,31 @@
+[{
+  "group": "local",
+  "key": "base.path",
+  "description": "主目录",
+  "value": "/home/uas"
+},{
+  "group": "local",
+  "key": "program.path",
+  "description": "软件安装默认路径",
+  "value": "/home/uas/program"
+},{
+  "group": "local",
+  "key": "resource.path",
+  "description": "本地资源路径",
+  "value": "/home/uas/data/resources"
+},{
+  "group": "api",
+  "key": "diff.repo.url",
+  "description": "远程Diff软件仓库地址",
+  "value": "http://diff-repo.ubtob.com/v1"
+},{
+  "group": "api",
+  "key": "maven.repo.url",
+  "description": "远程Maven软件仓库地址",
+  "value": "http://maven.ubtob.com/artifactory/libs-release"
+},{
+  "group": "api",
+  "key": "manage.url",
+  "description": "远程管理中心地址",
+  "value": "http://uas-manage-server.ubtob.com/v1"
+}]

+ 30 - 0
src/test/java/com/uas/ops/uas/client/RemoteOpsTest.java

@@ -0,0 +1,30 @@
+package com.uas.ops.uas.client;
+
+import com.uas.erp.manage.client.domain.ClientInfo;
+import com.uas.erp.manage.client.service.RemoteOpsService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Created by Pro1 on 2017/6/30.
+ */
+//@RunWith(SpringJUnit4ClassRunner.class)
+//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = UasOpsClientApplication.class)
+public class RemoteOpsTest {
+
+    @Autowired
+    private RemoteOpsService remoteOpsService;
+
+//    @Test
+    public void testSendClientInfo() {
+        ClientInfo info = new ClientInfo();
+        info.setClientId("123");
+        info.setName("测试");
+        remoteOpsService.pushClientInfoToRemote(info);
+    }
+
+}

+ 30 - 0
src/test/java/com/uas/ops/uas/client/RemoteRepositoryTest.java

@@ -0,0 +1,30 @@
+package com.uas.ops.uas.client;
+
+import com.uas.erp.manage.client.entity.Artifact;
+import com.uas.erp.manage.client.service.RemoteRepositoryService;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * Created by Pro1 on 2017/6/30.
+ */
+//@RunWith(SpringJUnit4ClassRunner.class)
+//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = UasOpsClientApplication.class)
+public class RemoteRepositoryTest {
+
+    @Autowired
+    private RemoteRepositoryService remoteRepositoryService;
+
+//    @Test
+    public void getVersion() throws Exception{
+        Artifact artifact = new Artifact();
+        artifact.setGroupId("com.uas.erp");
+        artifact.setArtifactId("uas");
+        artifact.setRepoType(Artifact.RepoType.DIFF.name());
+        System.out.println(remoteRepositoryService.getLastVersion(artifact));
+    }
+
+}