mcy 6 years ago
parent
commit
50ea6870dc

+ 5 - 1
canal-admin/canal-admin-server/pom.xml

@@ -14,7 +14,7 @@
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-webflux</artifactId>
+            <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -29,6 +29,10 @@
             <groupId>commons-dbutils</groupId>
             <artifactId>commons-dbutils</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 116 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java

@@ -0,0 +1,116 @@
+package com.alibaba.otter.canal.admin.config;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.alibaba.otter.canal.admin.controller.UserController;
+import com.alibaba.otter.canal.admin.model.BaseModel;
+import com.alibaba.otter.canal.admin.model.User;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.io.PrintWriter;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(new HandlerInterceptor() {
+
+            @Override
+            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+                                     Object o) throws Exception {
+                httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
+                httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
+                httpServletResponse.setHeader("Access-Control-Allow-Headers",
+                    "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Token");
+                httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
+                httpServletResponse.setHeader("Access-Control-Max-Age", String.valueOf(3600 * 24));
+
+                if (HttpMethod.OPTIONS.toString().equals(httpServletRequest.getMethod())) {
+                    httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
+                    return false;
+                }
+
+                return true;
+            }
+        }).addPathPatterns("/api/**");
+
+        registry.addInterceptor(new HandlerInterceptor() {
+
+            @Override
+            public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+                                     Object o) throws Exception {
+                String token = httpServletRequest.getHeader("X-Token");
+                boolean valid = false;
+                if (token != null) {
+                    User user = UserController.loginUsers.getIfPresent(token);
+                    if (user != null) {
+                        valid = true;
+                    }
+                }
+                if (!valid) {
+                    BaseModel baseModel = BaseModel.getInstance(null);
+                    baseModel.setCode(50014);
+                    baseModel.setMessage("Expired token");
+                    ObjectMapper mapper = new ObjectMapper();
+                    String json = mapper.writeValueAsString(baseModel);
+                    try {
+                        httpServletResponse.setContentType("application/json;charset=UTF-8");
+                        PrintWriter out = httpServletResponse.getWriter();
+                        out.print(json);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    return false;
+                }
+
+                return true;
+            }
+        }).addPathPatterns("/api/**").excludePathPatterns("/api/**/user/**");
+    }
+
+    /**
+     * 跨域支持
+     *
+     * @param registry
+     */
+    // @Override
+    // public void addCorsMappings(CorsRegistry registry) {
+    // registry.addMapping("/api")
+    // .allowedOrigins("http://127.0.0.1")
+    // .allowCredentials(true)
+    // .allowedMethods("*")
+    // .allowedHeaders("Origin, X-Requested-With, Content-Type, Accept,
+    // Authorization")
+    // .maxAge(3600 * 24);
+    // }
+
+    /**
+     * 添加静态资源--过滤swagger-api (开源的在线API文档)
+     *
+     * @param registry
+     */
+    // @Override
+    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
+    // // 过滤swagger
+    // registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
+    //
+    // registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+    //
+    // registry.addResourceHandler("/swagger-resources/**")
+    // .addResourceLocations("classpath:/META-INF/resources/swagger-resources/");
+    //
+    // registry.addResourceHandler("/swagger/**").addResourceLocations("classpath:/META-INF/resources/swagger*");
+    //
+    // registry.addResourceHandler("/v2/api-docs/**")
+    // .addResourceLocations("classpath:/META-INF/resources/v2/api-docs/");
+    //
+    // }
+}

+ 5 - 4
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java

@@ -1,5 +1,6 @@
 package com.alibaba.otter.canal.admin.controller;
 
+import com.alibaba.otter.canal.admin.model.BaseModel;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -10,14 +11,14 @@ import com.alibaba.otter.canal.admin.model.CanalConfig;
 import com.alibaba.otter.canal.admin.service.CanalConfigService;
 
 @RestController
-@RequestMapping("/api/{env}/config")
+@RequestMapping("/api/{env}/canal")
 public class CanalConfigController {
 
     @Autowired
     CanalConfigService canalConfigService;
 
-    @RequestMapping(value = "/canal", method = RequestMethod.GET)
-    public CanalConfig canalConfig(@PathVariable String env) {
-        return canalConfigService.getCanalConfig();
+    @RequestMapping(value = "/config", method = RequestMethod.GET)
+    public BaseModel<CanalConfig> canalConfig(@PathVariable String env) {
+        return BaseModel.getInstance(canalConfigService.getCanalConfig());
     }
 }

+ 57 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/UserController.java

@@ -0,0 +1,57 @@
+package com.alibaba.otter.canal.admin.controller;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.github.benmanes.caffeine.cache.LoadingCache;
+import org.springframework.web.bind.annotation.*;
+
+import com.alibaba.otter.canal.admin.model.BaseModel;
+import com.alibaba.otter.canal.admin.model.User;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+@RestController
+@RequestMapping("/api/{env}/user")
+public class UserController {
+
+    public static final LoadingCache<String, User> loginUsers = Caffeine.newBuilder()
+        .maximumSize(10_000)
+        .expireAfterAccess(10, TimeUnit.MINUTES)
+        .build(key -> null);
+
+    @PostMapping(value = "/login")
+    public BaseModel<Map<String, String>> login(@RequestBody User user, @PathVariable String env) {
+        if ("admin".equals(user.getUsername()) && "121212".equals(user.getPassword())) {
+            Map<String, String> tokenResp = new HashMap<>();
+            String token = UUID.randomUUID().toString();
+            loginUsers.put(token, user);
+            tokenResp.put("token", token);
+            return BaseModel.getInstance(tokenResp);
+        } else {
+            BaseModel<Map<String, String>> model = BaseModel.getInstance(null);
+            model.setCode(40001);
+            model.setMessage("Invalid username or password");
+            return model;
+        }
+    }
+
+    @GetMapping(value = "/info")
+    public BaseModel<User> info(@RequestParam String token, @PathVariable String env) {
+        User user = loginUsers.getIfPresent(token);
+        if (user != null) {
+            return BaseModel.getInstance(user);
+        } else {
+            BaseModel<User> model = BaseModel.getInstance(null);
+            model.setCode(50014);
+            model.setMessage("Invalid token");
+            return model;
+        }
+    }
+
+    @PostMapping(value = "/logout")
+    public BaseModel<String> logout(@PathVariable String env) {
+        return BaseModel.getInstance("success");
+    }
+}

+ 38 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/BaseModel.java

@@ -0,0 +1,38 @@
+package com.alibaba.otter.canal.admin.model;
+
+public class BaseModel<T> {
+
+    private Integer code = 20000;
+    private String  message;
+    private T       data;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public static <T> BaseModel<T> getInstance(T data) {
+        BaseModel<T> baseModel = new BaseModel<>();
+        baseModel.data = data;
+        return baseModel;
+    }
+}

+ 68 - 0
canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/User.java

@@ -0,0 +1,68 @@
+package com.alibaba.otter.canal.admin.model;
+
+public class User {
+
+    private Long   id;
+    private String username;
+    private String password;
+    private String roles  = "admin";
+    private String introduction;
+    private String avatar = "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif";
+    private String name   = "Canal Manager";
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getRoles() {
+        return roles;
+    }
+
+    public void setRoles(String roles) {
+        this.roles = roles;
+    }
+
+    public String getIntroduction() {
+        return introduction;
+    }
+
+    public void setIntroduction(String introduction) {
+        this.introduction = introduction;
+    }
+
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 1 - 1
canal-admin/canal-admin-ui/.env.development

@@ -2,7 +2,7 @@
 ENV = 'development'
 
 # base api
-VUE_APP_BASE_API = '/dev-api'
+VUE_APP_BASE_API = 'http://127.0.0.1:8089/api/v1'
 
 # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
 # to control whether the babel-plugin-dynamic-import-node plugin is enabled.

+ 1 - 1
canal-admin/canal-admin-ui/.env.production

@@ -2,5 +2,5 @@
 ENV = 'production'
 
 # base api
-VUE_APP_BASE_API = '/prod-api'
+VUE_APP_BASE_API = '/api/v1'
 

+ 4 - 4
canal-admin/canal-admin-ui/src/main.js

@@ -23,10 +23,10 @@ import '@/permission' // permission control
  * Currently MockJs will be used in the production environment,
  * please remove it before going online! ! !
  */
-import { mockXHR } from '../mock'
-if (process.env.NODE_ENV === 'production') {
-  mockXHR()
-}
+// import { mockXHR } from '../mock'
+// if (process.env.NODE_ENV === 'production') {
+//   mockXHR()
+// }
 
 // set ElementUI lang to EN
 Vue.use(ElementUI, {

+ 22 - 0
canal-admin/canal-admin-ui/src/router/index.js

@@ -55,6 +55,28 @@ export const constantRoutes = [
     }]
   },
 
+  {
+    path: '/canalServer',
+    component: Layout,
+    redirect: '/canalServer/config',
+    name: 'Canal Server',
+    meta: { title: 'Canal Server', icon: 'example' },
+    children: [
+      {
+        path: 'canalServer',
+        name: 'Canal主配置',
+        component: () => import('@/views/canalServer/config'),
+        meta: { title: 'Canal主配置', icon: 'form' }
+      },
+      {
+        path: 'tree',
+        name: 'Tree',
+        component: () => import('@/views/tree/index'),
+        meta: { title: 'Tree', icon: 'tree' }
+      }
+    ]
+  },
+
   {
     path: '/example',
     component: Layout,

+ 3 - 3
canal-admin/canal-admin-ui/src/settings.js

@@ -1,16 +1,16 @@
 module.exports = {
 
-  title: 'Vue Admin Template',
+  title: 'Canal Admin',
 
   /**
    * @type {boolean} true | false
    * @description Whether fix the header
    */
-  fixedHeader: false,
+  fixedHeader: true,
 
   /**
    * @type {boolean} true | false
    * @description Whether show the logo in sidebar
    */
-  sidebarLogo: false
+  sidebarLogo: true
 }

+ 1 - 1
canal-admin/canal-admin-ui/src/utils/request.js

@@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth'
 const service = axios.create({
   baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
   // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 5000 // request timeout
+  timeout: 60000 // request timeout
 })
 
 // request interceptor

+ 1 - 1
canal-admin/canal-admin-ui/src/views/form/index.vue

@@ -5,7 +5,7 @@
         <el-form-item>
           canal.properties&nbsp;&nbsp;&nbsp;&nbsp;
           <el-button type="primary" @click="onSubmit">修改</el-button>
-          <el-button @click="onCancel">取消</el-button>
+          <el-button @click="onCancel">返回</el-button>
         </el-form-item>
       </div>
       <editor v-model="content" lang="yaml" theme="chrome" width="100%" :height="800" @init="editorInit" />

+ 5 - 0
canal-admin/pom.xml

@@ -43,6 +43,11 @@
                 <artifactId>commons-dbutils</artifactId>
                 <version>1.6</version>
             </dependency>
+            <dependency>
+                <groupId>com.github.ben-manes.caffeine</groupId>
+                <artifactId>caffeine</artifactId>
+                <version>2.6.2</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>