You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by ra...@apache.org on 2021/11/03 05:48:10 UTC

[dubbo-admin] branch develop updated: [Feature] Dubbo Admin provides service mock ability. (#838)

This is an automated email from the ASF dual-hosted git repository.

ranke pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-admin.git


The following commit(s) were added to refs/heads/develop by this push:
     new e14a255  [Feature] Dubbo Admin provides service mock ability. (#838)
e14a255 is described below

commit e14a2556ca25b51b0da81d9dcf1bc93bcf7f8d66
Author: brotherlu-xcq <12...@qq.com>
AuthorDate: Wed Nov 3 13:48:03 2021 +0800

    [Feature] Dubbo Admin provides service mock ability. (#838)
    
    * commit the API
    
    * develop the front page.
    
    * add edit logic
    
    * develop the front page and test.
    
    * ui change
    
    * change the config key and group
    
    * change rule enable to config center.
    
    * update GlobalMockRule update logic.
    
    * remove the GlobalMockRule
    
    * [feature admin mock] move the diver dependency out of the project.
    
    * [feature admin mock] remove the contributor name and date in javadoc.
    
    * [feature admin mock] optimize the delete mock rule step.
    
    * [feature admin mock] fix the dialog cannot be closed when delete successfully.
    
    * [feature admin mock] add the support for h2 database.
    
    * [feature admin mock] rollback to zookeeper registry.
    
    * [feature admin mock] fix properties.
    
    * [feature admin mock] change mock-admin-api maven version.
    
    * [feature admin mock] fix the feedback and add the parameters in docker-compose.
    
    * [feature admin mock] fix the ci problem.
    
    * [feature admin mock] fix the ci problem.
    
    * [feature admin mock] removed unused import.
    
    * [feature admin mock] add license.
---
 docker/latest/Dockerfile                           |   2 +-
 docker/stack.yml                                   |  15 +-
 .../src/bin/config/application.properties          |  18 ++
 dubbo-admin-distribution/src/bin/startup.cmd       |   2 +-
 dubbo-admin-distribution/src/bin/startup.sh        |   4 +-
 dubbo-admin-server/pom.xml                         |  27 ++
 .../apache/dubbo/admin/DubboAdminApplication.java  |   7 +-
 .../apache/dubbo/admin/config/ConfigCenter.java    |  40 +--
 .../dubbo/admin/controller/MockRuleController.java |  62 +++++
 .../MockRuleMapper.java}                           |  19 +-
 .../apache/dubbo/admin/model/domain/MockRule.java  |  98 +++++++
 .../apache/dubbo/admin/model/dto/MockRuleDTO.java  |  95 +++++++
 .../MockServiceProvider.java}                      |  32 ++-
 .../registry/config/impl/NacosConfiguration.java   |  14 +-
 .../dubbo/admin/service/MockRuleService.java       |  63 +++++
 .../admin/service/impl/MockRuleServiceImpl.java    | 116 ++++++++
 .../src/main/resources/application.properties      |  18 ++
 .../schema.sql}                                    |  26 +-
 .../dubbo/admin/AbstractSpringIntegrationTest.java |   2 +
 dubbo-admin-ui/src/api/menu.js                     |   8 +-
 dubbo-admin-ui/src/components/test/ServiceMock.vue | 299 ++++++++++++++++++++-
 dubbo-admin-ui/src/lang/en.js                      |  16 +-
 dubbo-admin-ui/src/lang/zh.js                      |  16 +-
 dubbo-admin-ui/src/router/index.js                 |   2 +-
 pom.xml                                            |  16 ++
 25 files changed, 907 insertions(+), 110 deletions(-)

diff --git a/docker/latest/Dockerfile b/docker/latest/Dockerfile
index 5ce8b3e..a4e4f75 100644
--- a/docker/latest/Dockerfile
+++ b/docker/latest/Dockerfile
@@ -25,7 +25,7 @@ RUN apt-get update && apt-get install -y tini
 COPY --from=0 /source/dubbo-admin-snapshot/dubbo-admin-distribution/target/dubbo-admin-0.3.0-SNAPSHOT.jar /app.jar
 COPY --from=0 /source/dubbo-admin-snapshot/docker/entrypoint.sh /usr/local/bin/entrypoint.sh
 
-ENV JAVA_OPTS ""
+ENV JAVA_OPTS "-Dloader.path=/opt-libs"
 
 ENTRYPOINT ["tini", "--", "/usr/local/bin/entrypoint.sh"]
 EXPOSE 8080
diff --git a/docker/stack.yml b/docker/stack.yml
index ebb35f2..0392bc1 100644
--- a/docker/stack.yml
+++ b/docker/stack.yml
@@ -26,7 +26,20 @@ services:
       - zookeeper
     ports:
       - 8080:8080
+# the db driver path
+    volumes:
+      - "/mnt/opt-libs:/opt-libs"
     environment:
       - admin.registry.address=zookeeper://zookeeper:2181
       - admin.config-center=zookeeper://zookeeper:2181
-      - admin.metadata-report.address=zookeeper://zookeeper:2181
\ No newline at end of file
+      - admin.metadata-report.address=zookeeper://zookeeper:2181
+      - dubbo.application.name=dubbo-admin
+      - dubbo.registry.address=zookeeper://zookeeper:2181
+      - mybatis-plus.global-config.db-config.id-type=none
+      - spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+      - spring.datasource.url=jdbc:mysql://xxx:3306/dubbo-admin?characterEncoding=utf8&connectTimeout=1000&socketTimeout=10000&autoReconnect=true
+      - spring.datasource.username=root
+      - spring.datasource.password=mysql
+# use internal h2 as database
+#      - spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;
+#      - spring.datasource.username=sa
\ No newline at end of file
diff --git a/dubbo-admin-distribution/src/bin/config/application.properties b/dubbo-admin-distribution/src/bin/config/application.properties
index df17468..dbbc16c 100644
--- a/dubbo-admin-distribution/src/bin/config/application.properties
+++ b/dubbo-admin-distribution/src/bin/config/application.properties
@@ -56,3 +56,21 @@ admin.check.sessionTimeoutMilli=3600000
 server.compression.enabled=true
 server.compression.mime-types=text/css,text/javascript,application/javascript
 server.compression.min-response-size=10240
+
+#dubbo config
+dubbo.application.name=dubbo-admin
+dubbo.registry.address=${admin.registry.address}
+
+# mysql
+#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+#spring.datasource.url=jdbc:mysql://localhost:3306/dubbo-admin?characterEncoding=utf8&connectTimeout=1000&socketTimeout=10000&autoReconnect=true
+#spring.datasource.username=root
+#spring.datasource.password=mysql
+
+# h2
+spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;
+spring.datasource.username=sa
+spring.datasource.password=
+
+# id generate type
+mybatis-plus.global-config.db-config.id-type=none
\ No newline at end of file
diff --git a/dubbo-admin-distribution/src/bin/startup.cmd b/dubbo-admin-distribution/src/bin/startup.cmd
index 67af660..5a78317 100644
--- a/dubbo-admin-distribution/src/bin/startup.cmd
+++ b/dubbo-admin-distribution/src/bin/startup.cmd
@@ -26,6 +26,6 @@ set SERVER=dubbo-admin
 
 set "JAVA_OPT=%JAVA_OPT% -Xms512m -Xmx512m -Xmn256m"
 
-set "JAVA_OPT=%JAVA_OPT% -jar %BASE_DIR%\lib\%SERVER%.jar"
+set "JAVA_OPT=%JAVA_OPT% -Dloader.path=%BASE_DIR%\opt-libs -jar %BASE_DIR%\lib\%SERVER%.jar"
 
 call "%JAVA%" %JAVA_OPT% dubbo.admin %*
diff --git a/dubbo-admin-distribution/src/bin/startup.sh b/dubbo-admin-distribution/src/bin/startup.sh
index 765f814..3bb5e72 100644
--- a/dubbo-admin-distribution/src/bin/startup.sh
+++ b/dubbo-admin-distribution/src/bin/startup.sh
@@ -63,6 +63,6 @@ if [ ! -f "${BASE_DIR}/logs/start.out" ]; then
 fi
 
 JAVA_OPT="${JAVA_OPT} -Xms512m -Xmx512m -Xmn256m"
-JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/lib/${SERVER}.jar"
-nohup $JAVA ${JAVA_OPT} dubbo.admin >> ${BASE_DIR}/logs/catlog.out 2>&1 &
+JAVA_OPT="${JAVA_OPT} -Dloader.path=${BASE_DIR}/opt-libs -jar ${BASE_DIR}/lib/${SERVER}.jar"
+nohup "$JAVA" ${JAVA_OPT} dubbo.admin >> ${BASE_DIR}/logs/catlog.out 2>&1 &
 echo "${SERVER} is starting,you can check the ${BASE_DIR}/logs/catlog.out"
\ No newline at end of file
diff --git a/dubbo-admin-server/pom.xml b/dubbo-admin-server/pom.xml
index 2eaa4f3..73be90f 100644
--- a/dubbo-admin-server/pom.xml
+++ b/dubbo-admin-server/pom.xml
@@ -204,6 +204,30 @@
             <version>${jjwt-version}</version>
         </dependency>
 
+
+        <dependency>
+            <groupId>org.apache.dubbo.extensions</groupId>
+            <artifactId>dubbo-mock-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+
+        <!-- the mysql db driver need user put it in /opt-libs path -->
+<!--        <dependency>-->
+<!--            <groupId>mysql</groupId>-->
+<!--            <artifactId>mysql-connector-java</artifactId>-->
+<!--            <version>5.1.49</version>-->
+<!--            <scope>provided</scope>-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>runtime</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -212,6 +236,9 @@
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <version>2.0.2.RELEASE</version>
+                <configuration>
+                    <layout>ZIP</layout>
+                </configuration>
                 <executions>
                     <execution>
                         <phase>package</phase>
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
index 4f73eae..0be95b4 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
@@ -17,14 +17,17 @@
 
 package org.apache.dubbo.admin;
 
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
 
 @SpringBootApplication(exclude={
-		DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class
+		HibernateJpaAutoConfiguration.class
 })
+@EnableDubbo(scanBasePackages = {"org.apache.dubbo.admin.provider"})
+@MapperScan(basePackages = {"org.apache.dubbo.admin.mapper"})
 public class DubboAdminApplication {
 
 	public static void main(String[] args) {
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
index e2c3e3e..2ca8958 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/config/ConfigCenter.java
@@ -17,8 +17,6 @@
 
 package org.apache.dubbo.admin.config;
 
-import org.apache.commons.lang3.StringUtils;
-
 import org.apache.dubbo.admin.common.exception.ConfigurationException;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
@@ -28,8 +26,9 @@ import org.apache.dubbo.admin.registry.mapping.impl.NoOpServiceMapping;
 import org.apache.dubbo.admin.registry.metadata.MetaDataCollector;
 import org.apache.dubbo.admin.registry.metadata.impl.NoOpMetadataCollector;
 import org.apache.dubbo.admin.service.impl.InstanceRegistryCache;
+
+import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.config.Environment;
 import org.apache.dubbo.common.extension.ExtensionLoader;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
@@ -39,18 +38,12 @@ import org.apache.dubbo.registry.RegistryFactory;
 import org.apache.dubbo.registry.RegistryService;
 import org.apache.dubbo.registry.client.ServiceDiscovery;
 import org.apache.dubbo.registry.client.ServiceDiscoveryFactory;
-import org.apache.dubbo.rpc.model.ApplicationModel;
-
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.DependsOn;
 
 import java.util.Arrays;
-import java.util.Collections;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
 
 import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
 import static org.apache.dubbo.registry.client.ServiceDiscoveryFactory.getExtension;
@@ -138,38 +131,9 @@ public class ConfigCenter {
                 //throw exception
             }
         }
-        initDubboEnvironment();
         return dynamicConfiguration;
     }
 
-    private void initDubboEnvironment() {
-        Environment env = ApplicationModel.getEnvironment();
-        SortedMap<String, String> sortedMap = new TreeMap<>();
-        if (registryUrl == null) {
-            if (StringUtils.isNotBlank(registryAddress)) {
-                registryUrl = formUrl(registryAddress, registryGroup, registryNameSpace, username, password);
-            }
-        }
-
-        if (metadataUrl == null) {
-            if (StringUtils.isNotEmpty(metadataAddress)) {
-                metadataUrl = formUrl(metadataAddress, metadataGroup, metadataGroupNameSpace, username, password);
-                metadataUrl = metadataUrl.addParameter(CLUSTER_KEY, cluster);
-            }
-        }
-        if (registryUrl != null) {
-            sortedMap.put("dubbo.registry.address", registryUrl.toFullString());
-        }
-        if (configCenterUrl != null) {
-            sortedMap.put("dubbo.config-center.address", configCenterUrl.toFullString());
-        }
-        if (metadataUrl != null) {
-            sortedMap.put("dubbo.metadata-report.address", metadataUrl.toFullString());
-        }
-        Map<String, String> map = Collections.unmodifiableSortedMap(sortedMap);
-        env.updateAppConfigMap(map);
-    }
-
     /*
      * generate registry client
      */
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MockRuleController.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MockRuleController.java
new file mode 100644
index 0000000..435e651
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/controller/MockRuleController.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.controller;
+
+import org.apache.dubbo.admin.annotation.Authority;
+import org.apache.dubbo.admin.model.dto.MockRuleDTO;
+import org.apache.dubbo.admin.service.MockRuleService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Mock Rule Controller.
+ */
+@Authority(needLogin = true)
+@RestController
+@RequestMapping("/api/{env}/mock/rule")
+public class MockRuleController {
+
+    @Autowired
+    private MockRuleService mockRuleService;
+
+    @PostMapping
+    public boolean createOrUpdateMockRule(@RequestBody MockRuleDTO mockRule) {
+        mockRuleService.createOrUpdateMockRule(mockRule);
+        return true;
+    }
+
+    @DeleteMapping
+    public boolean deleteMockRule(@RequestBody MockRuleDTO mockRule) {
+        mockRuleService.deleteMockRuleById(mockRule.getId());
+        return true;
+    }
+
+    @GetMapping("/list")
+    public Page<MockRuleDTO> listMockRules(@RequestParam(required = false) String filter, Pageable pageable) {
+        return mockRuleService.listMockRulesByPage(filter, pageable);
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/mapper/MockRuleMapper.java
similarity index 58%
copy from dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
copy to dubbo-admin-server/src/main/java/org/apache/dubbo/admin/mapper/MockRuleMapper.java
index 4f73eae..1b670ca 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/mapper/MockRuleMapper.java
@@ -15,19 +15,14 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.admin;
+package org.apache.dubbo.admin.mapper;
 
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.apache.dubbo.admin.model.domain.MockRule;
 
-@SpringBootApplication(exclude={
-		DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class
-})
-public class DubboAdminApplication {
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
-	public static void main(String[] args) {
-		SpringApplication.run(DubboAdminApplication.class, args);
-	}
+/**
+ * The database operator of mock rule.
+ */
+public interface MockRuleMapper extends BaseMapper<MockRule> {
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MockRule.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MockRule.java
new file mode 100644
index 0000000..4ed3634
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/domain/MockRule.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.domain;
+
+import org.apache.dubbo.admin.model.dto.MockRuleDTO;
+
+/**
+ * The entity for database query and insert.
+ */
+public class MockRule {
+
+    private Long id;
+
+    private String serviceName;
+
+    private String methodName;
+
+    private String rule;
+
+    private Boolean enable;
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    @java.lang.Override
+    public String toString() {
+        return "MockRule{" +
+                "id=" + id +
+                ", serviceName='" + serviceName + '\'' +
+                ", methodName='" + methodName + '\'' +
+                ", rule='" + rule + '\'' +
+                ", enable=" + enable +
+                '}';
+    }
+
+
+    public static MockRule toMockRule(MockRuleDTO mockRule) {
+        MockRule rule = new MockRule();
+        rule.setServiceName(mockRule.getServiceName().trim());
+        rule.setMethodName(mockRule.getMethodName().trim());
+        rule.setId(mockRule.getId());
+        rule.setRule(mockRule.getRule());
+        rule.setEnable(mockRule.getEnable());
+        return rule;
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/MockRuleDTO.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/MockRuleDTO.java
new file mode 100644
index 0000000..d808cdf
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/model/dto/MockRuleDTO.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.model.dto;
+
+import org.apache.dubbo.admin.model.domain.MockRule;
+
+import org.springframework.beans.BeanUtils;
+
+/**
+ * the dto which provide to front end.
+ */
+public class MockRuleDTO {
+
+    private Long id;
+
+    private String serviceName;
+
+    private String methodName;
+
+    private String rule;
+
+    private Boolean enable;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public void setServiceName(String serviceName) {
+        this.serviceName = serviceName;
+    }
+
+    public String getMethodName() {
+        return methodName;
+    }
+
+    public void setMethodName(String methodName) {
+        this.methodName = methodName;
+    }
+
+    public Boolean getEnable() {
+        return enable;
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    @Override
+    public String toString() {
+        return "MockRuleDTO{" +
+                "id=" + id +
+                ", serviceName='" + serviceName + '\'' +
+                ", methodName='" + methodName + '\'' +
+                ", rule='" + rule + '\'' +
+                ", enable=" + enable +
+                '}';
+    }
+
+    public static MockRuleDTO toMockRuleDTO(MockRule mockRule) {
+        MockRuleDTO mockRuleDTO = new MockRuleDTO();
+        BeanUtils.copyProperties(mockRule, mockRuleDTO);
+        return mockRuleDTO;
+    }
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/provider/MockServiceProvider.java
similarity index 51%
copy from dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
copy to dubbo-admin-server/src/main/java/org/apache/dubbo/admin/provider/MockServiceProvider.java
index 4f73eae..d0bb07d 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/provider/MockServiceProvider.java
@@ -15,19 +15,27 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.admin;
+package org.apache.dubbo.admin.provider;
 
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.apache.dubbo.admin.service.MockRuleService;
 
-@SpringBootApplication(exclude={
-		DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class
-})
-public class DubboAdminApplication {
+import org.apache.dubbo.config.annotation.DubboService;
+import org.apache.dubbo.mock.api.MockContext;
+import org.apache.dubbo.mock.api.MockResult;
+import org.apache.dubbo.mock.api.MockService;
+import org.springframework.beans.factory.annotation.Autowired;
 
-	public static void main(String[] args) {
-		SpringApplication.run(DubboAdminApplication.class, args);
-	}
+/**
+ * The {@link MockServiceProvider} register as a dubbo service, provide the mock function for the consumer of {@link MockService}.
+ */
+@DubboService
+public class MockServiceProvider implements MockService {
+
+    @Autowired
+    private MockRuleService mockRuleService;
+
+    @Override
+    public MockResult mock(MockContext mockContext) {
+        return mockRuleService.getMockData(mockContext);
+    }
 }
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/config/impl/NacosConfiguration.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/config/impl/NacosConfiguration.java
index f5d0c7b..18e82cb 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/config/impl/NacosConfiguration.java
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/registry/config/impl/NacosConfiguration.java
@@ -17,24 +17,24 @@
 
 package org.apache.dubbo.admin.registry.config.impl;
 
-import com.alibaba.nacos.api.PropertyKeyConst;
-import java.util.Map;
 import org.apache.dubbo.admin.common.util.Constants;
 import org.apache.dubbo.admin.registry.config.GovernanceConfiguration;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringConstantFieldValuePredicate;
 
 import com.alibaba.nacos.api.NacosFactory;
+import com.alibaba.nacos.api.PropertyKeyConst;
 import com.alibaba.nacos.api.config.ConfigService;
 import com.alibaba.nacos.api.exception.NacosException;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.StringConstantFieldValuePredicate;
 
+import java.util.Map;
 import java.util.Properties;
 
-import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
 import static com.alibaba.nacos.api.PropertyKeyConst.NAMESPACE;
+import static com.alibaba.nacos.api.PropertyKeyConst.SERVER_ADDR;
 
 public class NacosConfiguration implements GovernanceConfiguration {
     private static final Logger logger = LoggerFactory.getLogger(NacosConfiguration.class);
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MockRuleService.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MockRuleService.java
new file mode 100644
index 0000000..2389219
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/MockRuleService.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service;
+
+import org.apache.dubbo.admin.model.dto.MockRuleDTO;
+
+import org.apache.dubbo.mock.api.MockContext;
+import org.apache.dubbo.mock.api.MockResult;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+
+/**
+ * The {@link MockRuleService} mainly works on the function of response the request of mock consumer
+ * and maintain the mock rule data.
+ */
+public interface MockRuleService {
+
+    /**
+     * create or update mock rule. if the request contains id, then will be an update operation.
+     *
+     * @param mockRule mock rule.
+     */
+    void createOrUpdateMockRule(MockRuleDTO mockRule);
+
+    /**
+     * delete the mock rule data by mock rule id.
+     *
+     * @param id mock rule id.
+     */
+    void deleteMockRuleById(Long id);
+
+    /**
+     * list the mock rules by filter and return data by page.
+     *
+     * @param filter filter condition.
+     * @param pageable pageable params.
+     * @return mock rules by page.
+     */
+    Page<MockRuleDTO> listMockRulesByPage(String filter, Pageable pageable);
+
+    /**
+     * return the mock rule data by {@link MockContext}.
+     *
+     * @param mockContext mock context provide by consumer.
+     * @return mock data.
+     */
+    MockResult getMockData(MockContext mockContext);
+}
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MockRuleServiceImpl.java b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MockRuleServiceImpl.java
new file mode 100644
index 0000000..7b659d5
--- /dev/null
+++ b/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/service/impl/MockRuleServiceImpl.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.admin.service.impl;
+
+import org.apache.dubbo.admin.mapper.MockRuleMapper;
+import org.apache.dubbo.admin.model.domain.MockRule;
+import org.apache.dubbo.admin.model.dto.MockRuleDTO;
+import org.apache.dubbo.admin.service.MockRuleService;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.apache.dubbo.mock.api.MockContext;
+import org.apache.dubbo.mock.api.MockResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * The implement of {@link MockRuleService}.
+ */
+@Component
+public class MockRuleServiceImpl implements MockRuleService {
+
+    @Autowired
+    private MockRuleMapper mockRuleMapper;
+
+    @Override
+    public void createOrUpdateMockRule(MockRuleDTO mockRule) {
+        if (Objects.isNull(mockRule.getServiceName()) || Objects.isNull(mockRule.getMethodName())
+                || Objects.isNull(mockRule.getRule())) {
+            throw new IllegalStateException("Param serviceName, methodName, rule cannot be null");
+        }
+        MockRule rule = MockRule.toMockRule(mockRule);
+        QueryWrapper<MockRule> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("service_name", mockRule.getServiceName());
+        queryWrapper.eq("method_name", mockRule.getMethodName());
+        MockRule existRule = mockRuleMapper.selectOne(queryWrapper);
+
+        // check if we can save or update the rule, we need keep the serviceName + methodName is unique.
+        if (Objects.nonNull(existRule)) {
+            if (Objects.equals(rule.getServiceName(), existRule.getServiceName())
+                    && Objects.equals(rule.getMethodName(), existRule.getMethodName())) {
+                if (!Objects.equals(rule.getId(), existRule.getId())) {
+                    throw new DuplicateKeyException("Service Name and Method Name must be unique");
+                }
+            }
+        }
+
+        if (Objects.nonNull(rule.getId())) {
+            mockRuleMapper.updateById(rule);
+            return;
+        }
+        mockRuleMapper.insert(rule);
+    }
+
+    @Override
+    public void deleteMockRuleById(Long id) {
+        MockRule mockRule = mockRuleMapper.selectById(id);
+        if (Objects.isNull(mockRule)) {
+            throw new IllegalStateException("Mock Rule cannot find");
+        }
+        mockRuleMapper.deleteById(id);
+    }
+
+    @Override
+    public Page<MockRuleDTO> listMockRulesByPage(String filter, Pageable pageable) {
+        QueryWrapper<MockRule> queryWrapper = new QueryWrapper<>();
+        Optional.ofNullable(filter)
+                .ifPresent(f -> queryWrapper.like("service_name", f));
+        List<MockRule> mockRules = mockRuleMapper.selectList(queryWrapper);
+        int total = mockRules.size();
+        final List<MockRuleDTO> content = mockRules.stream()
+                .skip(pageable.getOffset())
+                .limit(pageable.getPageSize())
+                .map(MockRuleDTO::toMockRuleDTO)
+                .collect(Collectors.toList());
+        return new PageImpl<>(content, pageable, total);
+    }
+
+    @Override
+    public MockResult getMockData(MockContext mockContext) {
+        QueryWrapper<MockRule> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("service_name", mockContext.getServiceName());
+        queryWrapper.eq("method_name", mockContext.getMethodName());
+        MockRule mockRule = mockRuleMapper.selectOne(queryWrapper);
+        MockResult mockResult = new MockResult();
+        if (Objects.isNull(mockRule)) {
+            return mockResult;
+        }
+        mockResult.setEnable(mockRule.getEnable());
+        mockResult.setContent(mockRule.getRule());
+        return mockResult;
+    }
+}
diff --git a/dubbo-admin-server/src/main/resources/application.properties b/dubbo-admin-server/src/main/resources/application.properties
index da49bf2..4aa924b 100644
--- a/dubbo-admin-server/src/main/resources/application.properties
+++ b/dubbo-admin-server/src/main/resources/application.properties
@@ -61,3 +61,21 @@ server.compression.min-response-size=10240
 admin.check.tokenTimeoutMilli=3600000
 #Jwt signingKey
 admin.check.signSecret=86295dd0c4ef69a1036b0b0c15158d77
+
+#dubbo config
+dubbo.application.name=dubbo-admin
+dubbo.registry.address=${admin.registry.address}
+
+# mysql
+#spring.datasource.driver-class-name=com.mysql.jdbc.Driver
+#spring.datasource.url=jdbc:mysql://localhost:3306/dubbo-admin?characterEncoding=utf8&connectTimeout=1000&socketTimeout=10000&autoReconnect=true
+#spring.datasource.username=root
+#spring.datasource.password=mysql
+
+# h2
+spring.datasource.url=jdbc:h2:mem:~/dubbo-admin;
+spring.datasource.username=sa
+spring.datasource.password=
+
+# id generate type
+mybatis-plus.global-config.db-config.id-type=none
\ No newline at end of file
diff --git a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java b/dubbo-admin-server/src/main/resources/schema.sql
similarity index 58%
copy from dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
copy to dubbo-admin-server/src/main/resources/schema.sql
index 4f73eae..f738db7 100644
--- a/dubbo-admin-server/src/main/java/org/apache/dubbo/admin/DubboAdminApplication.java
+++ b/dubbo-admin-server/src/main/resources/schema.sql
@@ -15,19 +15,13 @@
  * limitations under the License.
  */
 
-package org.apache.dubbo.admin;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
-import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
-
-@SpringBootApplication(exclude={
-		DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class
-})
-public class DubboAdminApplication {
-
-	public static void main(String[] args) {
-		SpringApplication.run(DubboAdminApplication.class, args);
-	}
-}
+CREATE TABLE IF NOT EXISTS `mock_rule` (
+    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `service_name` varchar(255) DEFAULT NULL COMMENT '服务名',
+    `method_name` varchar(255) DEFAULT NULL COMMENT '方法名',
+    `rule` text COMMENT '规则',
+    `enable` tinyint(1) NOT NULL DEFAULT '1',
+    `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`)
+);
\ No newline at end of file
diff --git a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
index 0626da2..01bed98 100644
--- a/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
+++ b/dubbo-admin-server/src/test/java/org/apache/dubbo/admin/AbstractSpringIntegrationTest.java
@@ -76,6 +76,8 @@ public abstract class AbstractSpringIntegrationTest {
                     "admin.metadata-report.address=zookeeper://" + zkServer.getConnectString());
             TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext,
                     "admin.config-center=zookeeper://" + zkServer.getConnectString());
+            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext,
+                    "dubbo.config.ignore-duplicated-interface=true");
         }
     }
 }
diff --git a/dubbo-admin-ui/src/api/menu.js b/dubbo-admin-ui/src/api/menu.js
index a68f536..1f9cfe0 100644
--- a/dubbo-admin-ui/src/api/menu.js
+++ b/dubbo-admin-ui/src/api/menu.js
@@ -33,7 +33,13 @@ const Menu = [
   },
   { title: 'serviceTest', path: '/test', icon: 'code' },
   { title: 'apiDocs', path: '/apiDocs', icon: 'code' },
-  { title: 'serviceMock', path: '/mock', icon: 'build', badge: 'feature' },
+  { title: 'serviceMock',
+    path: '/mock',
+    icon: 'build',
+    items: [
+      { title: 'mockRule', path: '/mock/rule', badge: 'new' }
+    ]
+  },
   {
     title: 'serviceMetrics',
     path: 'metrics',
diff --git a/dubbo-admin-ui/src/components/test/ServiceMock.vue b/dubbo-admin-ui/src/components/test/ServiceMock.vue
index cf3c2fd..1708774 100644
--- a/dubbo-admin-ui/src/components/test/ServiceMock.vue
+++ b/dubbo-admin-ui/src/components/test/ServiceMock.vue
@@ -16,30 +16,301 @@
   -->
 
 <template>
-  <v-container
-    fill-height
-  >
-    <v-layout align-center>
-      <v-flex text-xs-center>
-        <h1 class="display-2 primary--text">{{$t('later.serviceMock')}}</h1>
-        <v-btn
-          href="#/service"
-          color="primary"
-          outline
-        >
-          {{$t('goIndex')}}
-        </v-btn>
+  <v-container grid-list-xl fluid>
+    <v-layout row wrap>
+      <v-flex lg12>
+        <breadcrumb title="serviceMock" :items="breads"></breadcrumb>
+      </v-flex>
+      <v-flex lg12>
+        <v-card flat color="transparent">
+          <v-card-text>
+            <v-form>
+              <v-layout row wrap>
+                <v-combobox
+                  id="mockRule"
+                  :loading="searchLoading"
+                  :search-input.sync="input"
+                  v-model="filter"
+                  flat
+                  append-icon=""
+                  hide-no-data
+                  :hint="$t('testModule.searchServiceHint')"
+                  :label="$t('placeholders.searchService')"
+                  @update:searchInput="updateFilter"
+                  @keyup.enter="submitSearch"
+                ></v-combobox>
+                <v-btn @click="submitSearch" color="primary" large>{{ $t('search') }}</v-btn>
+              </v-layout>
+            </v-form>
+          </v-card-text>
+        </v-card>
+      </v-flex>
+      <v-flex xs12>
+        <v-card>
+          <v-toolbar flat color="transparent" class="elevation-0">
+            <v-toolbar-title><span class="headline">{{$t('ruleList')}}</span></v-toolbar-title>
+            <v-spacer></v-spacer>
+            <v-btn outline color="primary" @click.stop="openDialog" class="mb-2">{{$t('create')}}</v-btn>
+          </v-toolbar>
+          <v-card-text class="pa-0">
+            <v-data-table :headers="headers"
+                          :items="mockRules"
+                          :pagination.sync="pagination"
+                          :total-items="totalItems"
+                          :loading="loadingRules"
+                          class="elevation-1">
+              <template slot="items" slot-scope="props">
+                <td>{{ props.item.serviceName }}</td>
+                <td>
+                  <v-chip label>{{ props.item.methodName }}</v-chip>
+                </td>
+                <td>{{ props.item.rule }}
+                </td>
+                <td>
+                  <v-switch v-model="props.item.enable" inset @change="enableOrDisableMockRule(props.item)"></v-switch>
+                </td>
+                <td>
+                  <v-btn class="tiny" color="primary" @click="editMockRule(props.item)"> {{$t('edit')}} </v-btn>
+                  <v-btn class="tiny" color="error" @click="openDeleteDialog(props.item)"> {{$t('delete')}} </v-btn>
+                </td>
+              </template>
+            </v-data-table>
+          </v-card-text>
+        </v-card>
       </v-flex>
     </v-layout>
+
+    <v-dialog v-model="dialog" width="800px" persistent>
+      <v-card>
+        <v-card-title class="justify-center">
+          <span class="headline">{{dialogType === 1 ? $t('createMockRule') : $t('editMockRule')}}</span>
+        </v-card-title>
+        <v-card-text >
+          <v-text-field
+            :label="$t('serviceName')"
+            :hint="$t('dataIdClassHint')"
+            v-model="mockRule.serviceName"
+          ></v-text-field>
+
+          <v-text-field
+            :label="$t('methodName')"
+            :hint="$t('methodNameHint')"
+            v-model="mockRule.methodName"
+          ></v-text-field>
+
+          <v-subheader class="pa-0 mt-3">{{$t('ruleContent')}}</v-subheader>
+          <ace-editor v-model="mockRule.rule"></ace-editor>
+
+        </v-card-text>
+        <v-card-actions>
+          <v-spacer></v-spacer>
+          <v-btn flat @click.native="closeDialog">{{$t('close')}}</v-btn>
+          <v-btn depressed color="primary" @click.native="saveOrUpdateMockRule">{{$t('save')}}</v-btn>
+        </v-card-actions>
+      </v-card>
+    </v-dialog>
+
+    <v-dialog v-model="warnDialog" persistent max-width="500px">
+      <v-card>
+        <v-card-title class="headline">{{$t('deleteRuleTitle')}}</v-card-title>
+        <v-card-actions>
+          <v-spacer></v-spacer>
+          <v-btn color="darken-1" flat @click.native="closeDeleteDialog">{{$t('cancel')}}</v-btn>
+          <v-btn color="primary darken-1" depressed @click.native="deleteMockRule">{{$t('confirm')}}</v-btn>
+        </v-card-actions>
+      </v-card>
+    </v-dialog>
   </v-container>
 </template>
 
 <script>
+  import JsonEditor from '@/components/public/JsonEditor'
+  import Search from '@/components/public/Search'
+  import Breadcrumb from '@/components/public/Breadcrumb'
+  import yaml from 'js-yaml'
+  import AceEditor from '@/components/public/AceEditor'
+
   export default {
-    name: 'ServiceMock'
+    name: 'ServiceMock',
+    components: {
+      JsonEditor,
+      Search,
+      Breadcrumb,
+      yaml,
+      AceEditor
+    },
+    data() {
+      return {
+        headers: [],
+        mockRules: [],
+        breads: [
+          {
+            text: 'mockRule',
+            href: '/mock'
+          }
+        ],
+        pagination: {
+          page: 1,
+          rowsPerPage: 10 // -1 for All
+        },
+        loadingRules: false,
+        searchLoading: false,
+        filter: null,
+        totalItems: 0,
+        dialog: false,
+        mockRule: {
+          serviceName: '',
+          methodName: '',
+          rule: '',
+          enable: true
+        },
+        dialogType: 1,
+        warnDialog: false,
+        deleteRule: null
+      }
+    },
+    methods: {
+      setHeaders() {
+        this.headers = [
+          {
+            text: this.$t('serviceName'),
+            value: 'serviceName',
+            sortable: false
+          },
+          {
+            text: this.$t('methodName'),
+            value: 'methodName',
+            sortable: false
+          },
+          {
+            text: this.$t('mockData'),
+            value: 'rule',
+            sortable: false
+          },
+          {
+            text: this.$t('enabled'),
+            value: 'enable',
+            sortable: false
+          },
+          {
+            text: this.$t('operation'),
+            value: 'operation',
+            sortable: false
+          }
+        ]
+      },
+      listMockRules(filter) {
+        const page = this.pagination.page - 1;
+        const size = this.pagination.rowsPerPage === -1 ? this.totalItems : this.pagination.rowsPerPage;
+        this.loadingRules = true;
+        this.$axios.get('/mock/rule/list', {
+          params: {
+            page,
+            size,
+            filter
+          }
+        }).then(res => {
+          this.mockRules = res.data.content;
+          this.totalItems = res.data.totalElements
+        }).catch(e => {
+          this.showSnackbar('error', e.response.data.message)
+        }).finally(() => this.loadingRules = false)
+      },
+      submitSearch() {
+        this.listMockRules(this.filter)
+      },
+      openDialog() {
+        this.dialog = true
+      },
+      closeDialog() {
+        this.dialog = false;
+        this.dialogType = 1;
+        this.mockRule = {
+          serviceName: '',
+          methodName: '',
+          rule: '',
+          enable: true
+        }
+      },
+      saveOrUpdateMockRule() {
+        this.$axios.post("/mock/rule", this.mockRule).then(res => {
+          this.$notify(this.$t('saveRuleSuccess'), 'success');
+          this.closeDialog();
+          this.listMockRules()
+        }).catch(e => this.showSnackbar('error', e.response.data.message))
+      },
+      deleteMockRule() {
+        const id = this.deleteRule.id
+        this.$axios.delete('/mock/rule', {
+          data: {id}}
+          ).then(res => {
+            this.$notify(this.$t('deleteRuleSuccess'), 'success');
+            this.closeDeleteDialog()
+            this.listMockRules(this.filter)
+        })
+        .catch(e => this.$notify(e.response.data.message, 'error'))
+      },
+      editMockRule(mockRule) {
+        this.mockRule = mockRule;
+        this.openDialog();
+        this.dialogType = 2
+      },
+      enableOrDisableMockRule(mockRule) {
+        this.$axios.post('/mock/rule', mockRule)
+        .then(res => this.$notify(mockRule.enable ? this.$t('enableRuleSuccess') : this.$t('disableRuleSuccess'), 'success'))
+        .catch(e => this.$notify(e.data.response.message, 'error'))
+      },
+      updateFilter() {
+        this.filter = document.querySelector('#mockRule').value.trim();
+      },
+      closeDeleteDialog() {
+        this.warnDialog = false
+        this.deleteRule = null
+      },
+      openDeleteDialog(rule) {
+        this.warnDialog = true
+        this.deleteRule = rule
+      }
+    },
+    mounted() {
+      this.setHeaders();
+      this.listMockRules(this.filter);
+    },
+    computed: {
+      area () {
+        return this.$i18n.locale
+      }
+    },
+    watch: {
+      input (val) {
+        this.querySelections(val)
+      },
+      area () {
+        this.setHeaders()
+      },
+      pagination: {
+        handler (newVal, oldVal) {
+          if (newVal.page === oldVal.page && newVal.rowsPerPage === oldVal.rowsPerPage) {
+            return
+          }
+          const filter = this.filter;
+          this.listMockRules(filter)
+        },
+        deep: true
+      }
+    }
   }
 </script>
 
 <style scoped>
 
+  .tiny {
+    min-width: 30px;
+    height: 20px;
+    font-size: 8px;
+  }
+
+  .tiny-icon {
+    font-size: 18px;
+  }
 </style>
diff --git a/dubbo-admin-ui/src/lang/en.js b/dubbo-admin-ui/src/lang/en.js
index f047218..c84fd7a 100644
--- a/dubbo-admin-ui/src/lang/en.js
+++ b/dubbo-admin-ui/src/lang/en.js
@@ -206,5 +206,19 @@ export default {
       none: 'none'
     }
   },
-  authFailed: 'Authorized failed,please login.'
+  authFailed: 'Authorized failed,please login.',
+
+  ruleList: 'Rule List',
+  mockRule: 'Mock Rule',
+  mockData: 'Mock Data',
+  globalDisable: 'Global Disable',
+  globalEnable: 'Global Enable',
+  saveRuleSuccess: 'Save Rule Successfully',
+  deleteRuleSuccess: 'Delete Rule Successfully',
+  disableRuleSuccess: 'Disable Rule Successfully',
+  enableRuleSuccess: 'Enable Rule Successfully',
+  methodNameHint: 'The method name of Service',
+  createMockRule: 'Create Mock Rule',
+  editMockRule: 'Edit Mock Rule',
+  deleteRuleTitle: 'Are you sure to delete this mock rule?'
 }
diff --git a/dubbo-admin-ui/src/lang/zh.js b/dubbo-admin-ui/src/lang/zh.js
index 084a129..fa979c4 100644
--- a/dubbo-admin-ui/src/lang/zh.js
+++ b/dubbo-admin-ui/src/lang/zh.js
@@ -206,5 +206,19 @@ export default {
       none: '无'
     }
   },
-  authFailed: '权限验证失败'
+  authFailed: '权限验证失败',
+
+  ruleList: '规则列表',
+  mockRule: '规则配置',
+  mockData: '模拟数据',
+  globalDisable: '全局禁用',
+  globalEnable: '全局启用',
+  saveRuleSuccess: '保存规则成功',
+  deleteRuleSuccess: '删除成功',
+  disableRuleSuccess: '禁用成功',
+  enableRuleSuccess: '启用成功',
+  methodNameHint: '服务方法名',
+  createMockRule: '创建规则',
+  editMockRule: '修改规则',
+  deleteRuleTitle: '确定要删除此服务Mock规则吗?'
 }
diff --git a/dubbo-admin-ui/src/router/index.js b/dubbo-admin-ui/src/router/index.js
index 6343d34..8cb9574 100644
--- a/dubbo-admin-ui/src/router/index.js
+++ b/dubbo-admin-ui/src/router/index.js
@@ -137,7 +137,7 @@ export default new Router({
           }
         },
         {
-          path: '/mock',
+          path: '/mock/rule',
           name: 'ServiceMock',
           component: ServiceMock,
           meta: {
diff --git a/pom.xml b/pom.xml
index 573085b..c9ec158 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,6 +62,9 @@
 		<jacoco-version>0.8.2</jacoco-version>
 		<apollo-version>1.2.0</apollo-version>
 		<guava-version>20.0</guava-version>
+		<dubbo-mock-version>3.0.0</dubbo-mock-version>
+		<mybatis-plus-boot-version>3.4.2</mybatis-plus-boot-version>
+
 		<maven-checkstyle-plugin-version>3.0.0</maven-checkstyle-plugin-version>
 		<spring-boot-version>2.3.12.RELEASE</spring-boot-version>
 		<maven_compiler_version>3.6.0</maven_compiler_version>
@@ -127,6 +130,19 @@
 				<artifactId>guava</artifactId>
 				<version>${guava-version}</version>
 			</dependency>
+
+			<dependency>
+				<groupId>org.apache.dubbo.extensions</groupId>
+				<artifactId>dubbo-mock-api</artifactId>
+				<version>${dubbo-mock-version}</version>
+			</dependency>
+
+			<dependency>
+				<groupId>com.baomidou</groupId>
+				<artifactId>mybatis-plus-boot-starter</artifactId>
+				<version>${mybatis-plus-boot-version}</version>
+			</dependency>
+
 		</dependencies>
 	</dependencyManagement>