作者 钟来

修改日志输出内容imei号为空的异常

正在显示 73 个修改的文件 包含 2717 行增加307 行删除
@@ -8,8 +8,10 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -8,8 +8,10 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
8 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 8 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
9 import org.springframework.beans.factory.support.DefaultListableBeanFactory; 9 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
10 import org.springframework.beans.support.ResourceEditorRegistrar; 10 import org.springframework.beans.support.ResourceEditorRegistrar;
  11 +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
11 import org.springframework.context.ApplicationContext; 12 import org.springframework.context.ApplicationContext;
12 import org.springframework.context.ApplicationContextAware; 13 import org.springframework.context.ApplicationContextAware;
  14 +import org.springframework.context.annotation.AnnotationConfigApplicationContext;
13 import org.springframework.stereotype.Component; 15 import org.springframework.stereotype.Component;
14 16
15 /** 17 /**
@@ -174,4 +176,17 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC @@ -174,4 +176,17 @@ public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationC
174 { 176 {
175 return null != beanFactory; 177 return null != beanFactory;
176 } 178 }
  179 +
  180 + /**
  181 + * 获取当前的AnnotationConfigApplicationContext
  182 + *
  183 + * @return AnnotationConfigApplicationContext
  184 + */
  185 + public static AnnotationConfigServletWebServerApplicationContext getAnnotationConfigApplicationContext() {
  186 + if (applicationContext instanceof AnnotationConfigServletWebServerApplicationContext) {
  187 + return (AnnotationConfigServletWebServerApplicationContext) applicationContext;
  188 + } else {
  189 + throw new IllegalStateException("Current ApplicationContext is not an instance of AnnotationConfigApplicationContext");
  190 + }
  191 + }
177 } 192 }
@@ -6,16 +6,21 @@ import org.slf4j.Logger; @@ -6,16 +6,21 @@ import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory; 6 import org.slf4j.LoggerFactory;
7 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Autowired;
8 import org.springframework.stereotype.Component; 8 import org.springframework.stereotype.Component;
  9 +import org.springframework.util.AntPathMatcher;
9 import org.springframework.util.StreamUtils; 10 import org.springframework.util.StreamUtils;
10 11
11 import javax.servlet.*; 12 import javax.servlet.*;
12 import javax.servlet.annotation.WebFilter; 13 import javax.servlet.annotation.WebFilter;
13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletRequest;
  15 +import javax.servlet.http.HttpServletResponse;
14 import java.io.IOException; 16 import java.io.IOException;
15 import java.io.UnsupportedEncodingException; 17 import java.io.UnsupportedEncodingException;
16 -import java.util.Enumeration;  
17 -import java.util.HashMap;  
18 -import java.util.Map; 18 +import java.nio.file.FileSystems;
  19 +import java.nio.file.PathMatcher;
  20 +import java.nio.file.Paths;
  21 +import java.util.*;
  22 +import java.util.regex.Pattern;
  23 +import java.util.stream.Collectors;
19 24
20 /** 25 /**
21 * 实现 Filter 26 * 实现 Filter
@@ -28,7 +33,6 @@ import java.util.Map; @@ -28,7 +33,6 @@ import java.util.Map;
28 @WebFilter(filterName="httpServletRequestReplacedFilter",urlPatterns="/*") 33 @WebFilter(filterName="httpServletRequestReplacedFilter",urlPatterns="/*")
29 public class HttpServletRequestReplacedFilter implements Filter { 34 public class HttpServletRequestReplacedFilter implements Filter {
30 private final Logger logger = LoggerFactory.getLogger(this.getClass()); 35 private final Logger logger = LoggerFactory.getLogger(this.getClass());
31 -  
32 @Override 36 @Override
33 public void init(FilterConfig arg0) throws ServletException { 37 public void init(FilterConfig arg0) throws ServletException {
34 } 38 }
@@ -39,8 +43,22 @@ public class HttpServletRequestReplacedFilter implements Filter { @@ -39,8 +43,22 @@ public class HttpServletRequestReplacedFilter implements Filter {
39 43
40 RequestReaderHttpServletRequestWrapper requestWrapper = null; 44 RequestReaderHttpServletRequestWrapper requestWrapper = null;
41 if (request instanceof HttpServletRequest) { 45 if (request instanceof HttpServletRequest) {
42 - requestWrapper = new RequestReaderHttpServletRequestWrapper((HttpServletRequest) request);  
43 - printLog((HttpServletRequest)request,requestWrapper.getBody()); 46 + HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  47 + //解决Invalid character found in method name的问题
  48 + String method = httpServletRequest.getMethod();
  49 + if (!isValidHttpMethod(method)) {
  50 + HttpServletResponse httpServletResponse = (HttpServletResponse) response;
  51 +
  52 + httpServletResponse.getWriter().write("Invalid HTTP method");
  53 + httpServletResponse.setStatus(400); // Bad Request
  54 + return;
  55 + }
  56 +
  57 + if (!match(httpServletRequest.getRequestURI().toString()))
  58 + {
  59 + requestWrapper = new RequestReaderHttpServletRequestWrapper(httpServletRequest);
  60 + printLog(httpServletRequest,requestWrapper.getBody());
  61 + }
44 } 62 }
45 //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。 63 //获取请求中的流如何,将取出来的字符串,再次转换成流,然后把它放入到新request对象中。
46 // 在chain.doFiler方法中传递新的request对象 64 // 在chain.doFiler方法中传递新的request对象
@@ -51,7 +69,6 @@ public class HttpServletRequestReplacedFilter implements Filter { @@ -51,7 +69,6 @@ public class HttpServletRequestReplacedFilter implements Filter {
51 } 69 }
52 70
53 } 71 }
54 -  
55 @Override 72 @Override
56 public void destroy() { 73 public void destroy() {
57 } 74 }
@@ -76,4 +93,38 @@ public class HttpServletRequestReplacedFilter implements Filter { @@ -76,4 +93,38 @@ public class HttpServletRequestReplacedFilter implements Filter {
76 map.put("body",body); 93 map.put("body",body);
77 logger.info("---------------------参数:"+ GsonConstructor.get().toJson(map)+"----------------------------"); 94 logger.info("---------------------参数:"+ GsonConstructor.get().toJson(map)+"----------------------------");
78 } 95 }
  96 +
  97 + // 设置排除路径
  98 + private final static List<String> excludeUrls = Arrays.asList("/","/v2/api-docs","/swagger-resources/**","/resources/**","/**/*.html","/**/*.js","/**/*.css","/**/*.gif","/**/*.jpg","/**/*.png","/**/*.ico","/**/*.woff","/**/*.ttf","/**/*.svg");
  99 +
  100 + public static boolean match( String path) {
  101 + path = path.replace("\\", "/").trim();
  102 + // 创建一个 Ant 风格的路径匹配器
  103 + AntPathMatcher matcher = new AntPathMatcher();
  104 + for (String excludeUrl:excludeUrls)
  105 + {
  106 + // 使用 matcher 的 match 方法来判断给定的路径是否匹配模式
  107 + if (matcher.match(excludeUrl, path))
  108 + {
  109 + return true;
  110 + }
  111 + }
  112 +
  113 + return false;
  114 + }
  115 +
  116 + private static final String[] VALID_METHODS = {"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "TRACE", "CONNECT"};
  117 + private boolean isValidHttpMethod(String method) {
  118 + if (method == null || method.isEmpty()) {
  119 + return false;
  120 + }
  121 +
  122 + for (String validMethod : VALID_METHODS) {
  123 + if (validMethod.equalsIgnoreCase(method)) {
  124 + return true;
  125 + }
  126 + }
  127 +
  128 + return false;
  129 + }
79 } 130 }
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-jar</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-jar-plugins-init</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <dependencies>
  21 + <dependency>
  22 + <groupId>org.slf4j</groupId>
  23 + <artifactId>slf4j-api</artifactId>
  24 + </dependency>
  25 + <dependency>
  26 + <groupId>com.zhonglai.luhui</groupId>
  27 + <artifactId>ruoyi-common</artifactId>
  28 + </dependency>
  29 +
  30 + <dependency>
  31 + <groupId>net.jodah</groupId>
  32 + <artifactId>expiringmap</artifactId>
  33 + </dependency>
  34 +
  35 + <!-- 文档 -->
  36 + <dependency >
  37 + <groupId>io.springfox</groupId>
  38 + <artifactId>springfox-swagger2</artifactId>
  39 + <version>${swagger.version}</version>
  40 + <exclusions>
  41 + <exclusion>
  42 + <groupId>io.swagger</groupId>
  43 + <artifactId>swagger-models</artifactId>
  44 + </exclusion>
  45 + <exclusion>
  46 + <groupId>com.google.guava</groupId>
  47 + <artifactId>guava</artifactId>
  48 + </exclusion>
  49 + </exclusions>
  50 + </dependency>
  51 + </dependencies>
  52 +</project>
  1 +package com.zhonglai.luhui.plugins;
  2 +
  3 +import com.zhonglai.luhui.plugins.config.PluginsClassLoader;
  4 +import net.jodah.expiringmap.ExpirationListener;
  5 +import net.jodah.expiringmap.ExpirationPolicy;
  6 +import net.jodah.expiringmap.ExpiringMap;
  7 +import org.slf4j.Logger;
  8 +import org.slf4j.LoggerFactory;
  9 +import org.springframework.boot.CommandLineRunner;
  10 +import org.springframework.context.annotation.Bean;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import javax.annotation.PreDestroy;
  14 +import java.io.File;
  15 +import java.io.IOException;
  16 +import java.nio.file.*;
  17 +import java.util.concurrent.TimeUnit;
  18 +
  19 +@Component
  20 +public class FileChangeListener {
  21 + private static Logger log = LoggerFactory.getLogger(FileChangeListener.class);
  22 + private WatchService watchService;
  23 + private Thread watcherThread;
  24 + private volatile boolean running = true;
  25 +
  26 + private static Integer time = 5;
  27 +
  28 + private static ExpiringMap<String, Boolean> upFileMap = ExpiringMap.builder().maxSize(100).expiration(time, TimeUnit.SECONDS)
  29 + .variableExpiration()
  30 + .asyncExpirationListener((ExpirationListener<String, Boolean>) (s, b) -> log.info("超时清除>>>>>>>:{} ",s))
  31 + .expirationPolicy(ExpirationPolicy.CREATED).build();
  32 +
  33 + public void startFileWatcher() throws IOException {
  34 + //初始化插件
  35 + InitPlugins.init();
  36 +
  37 + //注册文件监听
  38 + registerListener();
  39 +
  40 + //启动监听线程
  41 + startThread();
  42 +
  43 + }
  44 +
  45 +
  46 + private void registerListener() throws IOException {
  47 + // 创建WatchService,它是对操作系统的文件监视器的封装,相对之前,不需要遍历文件目录,效率要高很多
  48 + watchService = FileSystems.getDefault().newWatchService();
  49 + // 注册指定目录使用的监听器,监视目录下文件的变化;
  50 + // PS:Path必须是目录,不能是文件;
  51 + // StandardWatchEventKinds.ENTRY_MODIFY,表示监视文件的修改事件
  52 + Path path = Paths.get(InitPlugins.getPluginsPath());
  53 + path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
  54 + }
  55 +
  56 + private void startThread()
  57 + {
  58 + // 创建并启动监听线程
  59 + watcherThread = new Thread(this::watchFileChanges);
  60 + watcherThread.start();
  61 + }
  62 +
  63 + private void watchFileChanges() {
  64 + while (running) {
  65 + try {
  66 + //记录变化的文件
  67 + // 获取目录的变化:
  68 + // take()是一个阻塞方法,会等待监视器发出的信号才返回。
  69 + // 还可以使用watcher.poll()方法,非阻塞方法,会立即返回当时监视器中是否有信号。
  70 + // 返回结果WatchKey,是一个单例对象,与前面的register方法返回的实例是同一个;
  71 + WatchKey key = watchService.take();
  72 +
  73 + //记录变化的文件
  74 + // 处理文件变化事件:
  75 + // key.pollEvents()用于获取文件变化事件,只能获取一次,不能重复获取,类似队列的形式。
  76 + for (WatchEvent<?> event : key.pollEvents()) {
  77 + System.out.println(event.kind()+"事件触发"+": " + event.context());
  78 + // event.kind():事件类型
  79 + if (event.kind() == StandardWatchEventKinds.OVERFLOW) {
  80 + //事件可能lost or discarded
  81 + continue;
  82 + }
  83 + // 返回触发事件的文件或目录的路径(相对路径)
  84 + Path fileName = (Path) event.context();
  85 + Path dir = (Path) key.watchable();
  86 + Path fullPath = dir.resolve(fileName);
  87 + File file = fullPath.toFile();
  88 +
  89 + if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY)
  90 + {
  91 + if(file.exists() && file.length()>0)
  92 + {
  93 + if(!upFileMap.containsKey(fullPath.toString()))
  94 + {
  95 + PluginsClassLoader.uploadJar(file);
  96 + upFileMap.put(fullPath.toString(),true);
  97 + }
  98 + }
  99 + }
  100 + if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE)
  101 + {
  102 + PluginsClassLoader.unloadJar(file.getAbsolutePath());
  103 + }
  104 + }
  105 +
  106 +
  107 + // 每次调用WatchService的take()或poll()方法时需要通过本方法重置
  108 + if (!key.reset()) {
  109 + break;
  110 + }
  111 + } catch (Exception e) {
  112 + e.printStackTrace();
  113 + // 如果有必要,可以在这里优雅地处理异常,比如重新注册WatchKey
  114 + break;
  115 + }
  116 + }
  117 + }
  118 +
  119 + @PreDestroy
  120 + public void stopFileWatcher() {
  121 + running = false; // 设置标志以停止线程
  122 +
  123 + // 等待线程完成(可选,但可能不总是需要的,取决于你的需求)
  124 + try {
  125 + watcherThread.join();
  126 + } catch (InterruptedException e) {
  127 + e.printStackTrace();
  128 + }
  129 +
  130 + // 关闭WatchService
  131 + try {
  132 + if (watchService != null) {
  133 + watchService.
  134 + close();
  135 + }
  136 + } catch (IOException e) {
  137 + e.printStackTrace();
  138 + }
  139 + }
  140 +
  141 + @Bean
  142 + public CommandLineRunner onApplicationEvent() {
  143 + return args -> {
  144 + // 在这里编写启动后需要执行的逻辑
  145 + System.out.println("Spring Boot 应用已启动完成,执行额外的加载操作...");
  146 + // 执行加载数据库,连接外部服务等操作
  147 + startFileWatcher();
  148 + };
  149 + }
  150 +
  151 + public static void main(String[] args) throws IOException {
  152 + FileChangeListener fileChangeListener = new FileChangeListener();
  153 + fileChangeListener.startFileWatcher();
  154 + System.out.println("启动成功");
  155 + }
  156 +}
  1 +package com.zhonglai.luhui.plugins;
  2 +
  3 +
  4 +import com.zhonglai.luhui.plugins.config.PluginsClassLoader;
  5 +
  6 +import java.io.File;
  7 +import java.net.MalformedURLException;
  8 +
  9 +
  10 +public class InitPlugins {
  11 +
  12 + private static final String pluginsPath = "plugins";
  13 + private static final String pluginsJarPath = "pluginsjar";
  14 +
  15 +
  16 + public static void init()
  17 + {
  18 + File[] files = getJarFiles(getPluginsPath());
  19 + PluginsClassLoader.uploadJar(files);
  20 + }
  21 +
  22 + public static String getPluginsPath()
  23 + {
  24 + String jarFilePath = System.getProperty("jarFilePath");
  25 + String path = null != jarFilePath?jarFilePath:System.getProperty("user.dir")+"/"+pluginsPath;
  26 + return path;
  27 + }
  28 +
  29 + public static String getPluginsJarPath()
  30 + {
  31 + String path = System.getProperty("user.dir")+"/"+pluginsJarPath;
  32 + return path;
  33 + }
  34 +
  35 +
  36 + public static File[] getJarFiles(String jarFilePath)
  37 + {
  38 + File file = new File(jarFilePath);
  39 + if(file.exists() && file.isDirectory())
  40 + {
  41 +
  42 + File[] files = file.listFiles((dir, name) -> {
  43 + if(name.endsWith(".jar"))
  44 + {
  45 + return true;
  46 + }
  47 + return false;
  48 + });
  49 + return files;
  50 + }
  51 + return null;
  52 + }
  53 +
  54 + public static void main(String[] args) throws MalformedURLException {
  55 + File[] files = getJarFiles(getPluginsPath());
  56 + PluginsClassLoader.uploadJar(files);
  57 + }
  58 +
  59 +
  60 + public static String toJarPath(String filePath)
  61 + {
  62 + return filePath.replace(pluginsPath,pluginsJarPath);
  63 + }
  64 +}
  1 +package com.zhonglai.luhui.plugins.config;
  2 +
  3 +import com.ruoyi.common.utils.spring.SpringUtils;
  4 +import com.zhonglai.luhui.plugins.InitPlugins;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.stereotype.Component;
  8 +import org.springframework.stereotype.Service;
  9 +
  10 +import java.io.*;
  11 +import java.lang.reflect.InvocationTargetException;
  12 +import java.lang.reflect.Modifier;
  13 +import java.net.URL;
  14 +import java.net.URLClassLoader;
  15 +import java.nio.file.Files;
  16 +import java.nio.file.Path;
  17 +import java.nio.file.Paths;
  18 +import java.util.Enumeration;
  19 +import java.util.Iterator;
  20 +import java.util.Map;
  21 +import java.util.concurrent.ConcurrentHashMap;
  22 +import java.util.jar.JarEntry;
  23 +import java.util.jar.JarFile;
  24 +
  25 +import io.swagger.annotations.Api;
  26 +import io.swagger.annotations.ApiOperation;
  27 +import io.swagger.annotations.ApiResponse;
  28 +import io.swagger.annotations.ApiResponses;
  29 +import springfox.documentation.service.Operation;
  30 +import springfox.documentation.spring.web.plugins.Docket;
  31 +import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
  32 +
  33 +
  34 +import org.springframework.web.method.HandlerMethod;
  35 +
  36 +import java.lang.reflect.Method;
  37 +import java.util.*;
  38 +
  39 +/**
  40 + * 自定义的类加载器
  41 + */
  42 +public class PluginsClassLoader extends URLClassLoader {
  43 + private static final Logger log = LoggerFactory.getLogger(PluginsClassLoader.class);
  44 + /**
  45 + * 存放类
  46 + */
  47 + private static ConcurrentHashMap<String,PluginsClassLoader> jarMap = new ConcurrentHashMap<>();
  48 +
  49 + private static ConcurrentHashMap<String,Class<?>> classMap = new ConcurrentHashMap<>();
  50 +
  51 + private PluginsClassLoader(URL[] urls) {
  52 + super(urls,PluginsClassLoader.class.getClassLoader());
  53 + }
  54 +
  55 + /**
  56 + * 卸载jar
  57 + * @throws IOException
  58 + */
  59 + public static void unloadJar(String... filePaths) throws IOException {
  60 + for (String filePath:filePaths)
  61 + {
  62 + String key = InitPlugins.toJarPath(filePath);
  63 +
  64 + // 移除并关闭 ClassLoader
  65 + PluginsClassLoader pluginsClassLoader = jarMap.remove(key);
  66 + if (pluginsClassLoader != null) {
  67 + try {
  68 + pluginsClassLoader.close();
  69 + } catch (IOException e) {
  70 + log.error("Failed to close ClassLoader for JAR: " + key, e);
  71 + }
  72 + }
  73 +
  74 + // 移除 classMap 中的类
  75 + Iterator<Map.Entry<String, Class<?>>> it = classMap.entrySet().iterator();
  76 + while (it.hasNext()) {
  77 + Map.Entry<String, Class<?>> entry = it.next();
  78 + if (entry.getValue().getClassLoader() == pluginsClassLoader) {
  79 + it.remove();
  80 + }
  81 + }
  82 +
  83 + File file = new File(key);
  84 + if(file.exists())
  85 + {
  86 + file.delete();
  87 + }
  88 +
  89 + }
  90 +
  91 + }
  92 +
  93 +
  94 + /**
  95 + * 更新jar
  96 + * @throws IOException
  97 + */
  98 + public static void uploadJar(File... filePaths) {
  99 + try {
  100 + for (File file:filePaths)
  101 + {
  102 + String filePath = file.getAbsolutePath();
  103 + System.out.println("绝对路径:"+filePath);
  104 +
  105 + unloadJar(filePath);
  106 +
  107 + String key = InitPlugins.toJarPath(filePath);
  108 +
  109 + copyFile(filePath,key);
  110 +
  111 + PluginsClassLoader pluginsClassLoader = new PluginsClassLoader(new URL[]{new URL("file:"+key)});
  112 + jarMap.put(key,pluginsClassLoader);
  113 +
  114 + laodJar(new File(key),pluginsClassLoader);
  115 + }
  116 + } catch (IOException e) {
  117 + log.error("更新jar异常",e);
  118 + }
  119 +
  120 + }
  121 +
  122 +
  123 +
  124 + private static void laodJar(File jarfile, ClassLoader classLoader) {
  125 + try (JarFile jarFile = new JarFile(jarfile)) {
  126 + Enumeration<JarEntry> entries = jarFile.entries();
  127 + while (entries.hasMoreElements()) {
  128 + JarEntry jarEntry = entries.nextElement();
  129 + String entryName = jarEntry.getName();
  130 + if (entryName != null && entryName.endsWith(".class")) {
  131 + entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
  132 + Class<?> clas = classLoader.loadClass(entryName);
  133 + if (SpringUtils.isSpringBean()) {
  134 + Object bean = loadBean(clas);
  135 + }
  136 + classMap.put(entryName, clas);
  137 + }else if(entryName.endsWith("jar.config"))
  138 + {
  139 + //加载配置文件jar.config
  140 + InputStream is = classLoader.getResourceAsStream(entryName);
  141 + String scanPath = loadconfig(is).getProperty("scan-path");
  142 + SpringUtils.getAnnotationConfigApplicationContext().scan(scanPath);
  143 + }
  144 + }
  145 + } catch (IOException | ClassNotFoundException e) {
  146 + log.error("加载jar:"+jarfile.getAbsolutePath()+" 失败",e);
  147 + }
  148 + }
  149 +
  150 + private static Properties loadconfig() throws IOException {
  151 + return loadconfig(null);
  152 + }
  153 +
  154 + private static Properties loadconfig(InputStream is) throws IOException {
  155 + Properties prop = new Properties();
  156 + // 加载配置文件
  157 + prop.load(is);
  158 +
  159 + return prop;
  160 + }
  161 +
  162 +
  163 + private static <T> T loadBean(Class<T> clas)
  164 + {
  165 + if(isInstantiable(clas))
  166 + {
  167 + try {
  168 + Object object = clas.newInstance();
  169 + if(clas.isAnnotationPresent(Component.class) || clas.isAnnotationPresent(Service.class))
  170 + {
  171 + SpringUtils.registerBean(null,object);
  172 + return SpringUtils.getBean(clas);
  173 + }else {
  174 + return (T) object;
  175 + }
  176 +
  177 + } catch (InstantiationException e) {
  178 + throw new RuntimeException(e);
  179 + } catch (IllegalAccessException e) {
  180 + throw new RuntimeException(e);
  181 + }
  182 + }
  183 + return null;
  184 + }
  185 + private static boolean isInstantiable(Class<?> clazz) {
  186 + // 检查类是否是抽象类或接口
  187 + if (Modifier.isAbstract(clazz.getModifiers()) || clazz.isInterface()) {
  188 + return false;
  189 + }
  190 + // 尝试查找并访问默认的无参构造器
  191 + try {
  192 + clazz.getDeclaredConstructor((Class[]) null);
  193 + return true;
  194 + } catch (NoSuchMethodException e) {
  195 + return false;
  196 + }
  197 + }
  198 +
  199 + public static <T> T getJarClass(Class<T> tClass,String classname) {
  200 + Class clazz = classMap.get(classname);
  201 + if (null != clazz)
  202 + {
  203 + try {
  204 + if (tClass.isAssignableFrom(clazz) && !clazz.equals(tClass)) {
  205 + return tClass.cast(clazz.getDeclaredConstructor().newInstance());
  206 + }else if(tClass.isAssignableFrom(clazz) && clazz.equals(tClass))
  207 + {
  208 + return tClass.newInstance();
  209 + }
  210 + } catch (InstantiationException e) {
  211 + throw new RuntimeException(e);
  212 + } catch (IllegalAccessException e) {
  213 + throw new RuntimeException(e);
  214 + } catch (InvocationTargetException e) {
  215 + throw new RuntimeException(e);
  216 + } catch (NoSuchMethodException e) {
  217 + throw new RuntimeException(e);
  218 + }
  219 +
  220 + }
  221 + return null;
  222 + }
  223 +
  224 + public static void copyFile(String sourcePathStr, String targetPathStr) {
  225 + Path sourcePath = Paths.get(sourcePathStr);
  226 + Path targetPath = Paths.get(targetPathStr);
  227 +
  228 + // 检查源文件是否存在
  229 + if (!Files.exists(sourcePath)) {
  230 + log.error("Source file does not exist: " + sourcePath.toString());
  231 + return;
  232 + }
  233 +
  234 + // 检查目标文件所在目录是否存在,如果不存在则创建
  235 + Path targetDir = targetPath.getParent();
  236 + if (!Files.exists(targetDir)) {
  237 + try {
  238 + Files.createDirectories(targetDir);
  239 + } catch (IOException e) {
  240 + log.error("Failed to create target directory: " + targetDir.toString(),e);
  241 + return;
  242 + }
  243 + }
  244 +
  245 + // 执行文件复制
  246 + try {
  247 + Files.copy(sourcePath, targetPath);
  248 + System.out.println("File copied successfully from " + sourcePath.toString() + " to " + targetPath.toString());
  249 + } catch (IOException e) {
  250 + throw new RuntimeException("Failed to copy file from " + sourcePath.toString() + " to " + targetPath.toString(), e);
  251 + }
  252 + }
  253 +}
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 <module>lh-jar-rocketmq</module> 18 <module>lh-jar-rocketmq</module>
19 <module>lh-jar-sys-service</module> 19 <module>lh-jar-sys-service</module>
20 <module>lh-jar-order-service</module> 20 <module>lh-jar-order-service</module>
  21 + <module>lh-jar-plugins-init</module>
21 </modules> 22 </modules>
22 23
23 <properties> 24 <properties>
@@ -7,11 +7,15 @@ import com.ruoyi.common.core.domain.AjaxResult; @@ -7,11 +7,15 @@ import com.ruoyi.common.core.domain.AjaxResult;
7 import com.ruoyi.common.core.domain.Message; 7 import com.ruoyi.common.core.domain.Message;
8 import com.ruoyi.common.enums.BusinessType; 8 import com.ruoyi.common.enums.BusinessType;
9 import com.ruoyi.common.utils.GsonConstructor; 9 import com.ruoyi.common.utils.GsonConstructor;
  10 +import com.ruoyi.framework.config.ThreadPoolConfig;
10 import com.zhonglai.luhui.action.BaseController; 11 import com.zhonglai.luhui.action.BaseController;
11 import com.zhonglai.luhui.device.domain.IotDevice; 12 import com.zhonglai.luhui.device.domain.IotDevice;
  13 +import com.zhonglai.luhui.device.domain.IotProductTranslate;
12 import com.zhonglai.luhui.device.dto.CommandType; 14 import com.zhonglai.luhui.device.dto.CommandType;
13 import com.zhonglai.luhui.device.dto.DeviceCommand; 15 import com.zhonglai.luhui.device.dto.DeviceCommand;
14 import com.zhonglai.luhui.device.service.IIotDeviceService; 16 import com.zhonglai.luhui.device.service.IIotDeviceService;
  17 +import com.zhonglai.luhui.device.service.IIotProductTranslateService;
  18 +import com.zhonglai.luhui.device.service.impl.IotProductTranslateServiceImpl;
15 import com.zhonglai.luhui.rocketmq.service.RocketMqService; 19 import com.zhonglai.luhui.rocketmq.service.RocketMqService;
16 import io.swagger.annotations.Api; 20 import io.swagger.annotations.Api;
17 import io.swagger.annotations.ApiImplicitParam; 21 import io.swagger.annotations.ApiImplicitParam;
@@ -27,6 +31,9 @@ import org.springframework.web.bind.annotation.RestController; @@ -27,6 +31,9 @@ import org.springframework.web.bind.annotation.RestController;
27 31
28 import javax.servlet.http.HttpServletRequest; 32 import javax.servlet.http.HttpServletRequest;
29 import java.io.IOException; 33 import java.io.IOException;
  34 +import java.util.List;
  35 +import java.util.concurrent.ScheduledExecutorService;
  36 +import java.util.concurrent.TimeUnit;
30 37
31 @Api(tags = "控制器") 38 @Api(tags = "控制器")
32 @RestController 39 @RestController
@@ -37,6 +44,12 @@ public class ControlDeviceConreoller extends BaseController { @@ -37,6 +44,12 @@ public class ControlDeviceConreoller extends BaseController {
37 44
38 @Autowired 45 @Autowired
39 private IIotDeviceService iotDeviceService; 46 private IIotDeviceService iotDeviceService;
  47 +
  48 + @Autowired
  49 + private IotProductTranslateServiceImpl iotProductTranslateService;
  50 +
  51 + @Autowired
  52 + private ScheduledExecutorService scheduledExecutorService;
40 @ApiOperation(value = "写指令",notes = "body参数描述:\r\n" + 53 @ApiOperation(value = "写指令",notes = "body参数描述:\r\n" +
41 "{\n" + 54 "{\n" +
42 " \"0\":{\n" + 55 " \"0\":{\n" +
@@ -138,6 +151,17 @@ public class ControlDeviceConreoller extends BaseController { @@ -138,6 +151,17 @@ public class ControlDeviceConreoller extends BaseController {
138 JsonObject jsonObject = new JsonObject(); 151 JsonObject jsonObject = new JsonObject();
139 jsonObject.addProperty("product_id",product_id); 152 jsonObject.addProperty("product_id",product_id);
140 deviceCommand.setData(jsonObject); 153 deviceCommand.setData(jsonObject);
  154 +
  155 + scheduledExecutorService.schedule(() -> {
  156 + IotProductTranslate iotProductTranslate = new IotProductTranslate();
  157 + iotProductTranslate.setProduct_id(product_id);
  158 + List<IotProductTranslate> list = iotProductTranslateService.selectIotProductTranslateList(iotProductTranslate);
  159 + for (IotProductTranslate iotProductTranslate1:list)
  160 + {
  161 + iotProductTranslateService.upCache(iotProductTranslate1);
  162 + }
  163 + }, 0, TimeUnit.SECONDS);
  164 +
141 return sysControl(deviceCommand); 165 return sysControl(deviceCommand);
142 } 166 }
143 167
1 -# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 47.112.163.61 # 端口,默认为6379 port: 9527 # 数据库索引 database: 1 # 密码 password: Luhui586 # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-admin # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/tool/gen/generatorCodeFromDb,/data/**,/monitor/server/upload,/monitor/server/getSysMonitorServerList,/monitor/server/getSysMonitorServerLogList # NameServer地址 rocketmq: name-server: 47.115.144.179:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1  
  1 +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 119.23.218.181 # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-admin # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login,/register,/captchaImage,/getCacheObject,/v2/api-docs,/tool/gen/generatorCodeFromDb,/data/**,/monitor/server/upload,/monitor/server/getSysMonitorServerList,/monitor/server/getSysMonitorServerLogList # NameServer地址 rocketmq: name-server: 8.129.224.117:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1
@@ -166,4 +166,38 @@ public class IotTerminalController extends BaseController @@ -166,4 +166,38 @@ public class IotTerminalController extends BaseController
166 iotTerminalService.batchUpName(ids,names,userid); 166 iotTerminalService.batchUpName(ids,names,userid);
167 return toAjax( userTerminalGroupRelationService.groupTerminal(iot_terminal_group_id,ids,userid)); 167 return toAjax( userTerminalGroupRelationService.groupTerminal(iot_terminal_group_id,ids,userid));
168 } 168 }
  169 +
  170 + @ApiOperation("统计用户终端")
  171 + @GetMapping("/countUserDevices")
  172 + public AjaxResult countUserDevices()
  173 + {
  174 + String ids = SecurityUtils.getUserId()+"";
  175 + String sql = "SELECT t.mqtt_username,COUNT(t.mqtt_username) ct FROM \n" +
  176 + "(\n" +
  177 + "SELECT b.`device_id`,a.`iot_terminal_id`,b.`mqtt_username` FROM `mqtt_broker`.`user_terminal_group_relation` a LEFT JOIN `mqtt_broker`.`iot_terminal` b ON b.`id`=a.`iot_terminal_id` WHERE a.user_info_id IN("+ids+")\n" +
  178 + "UNION \n" +
  179 + "SELECT device_id,id iot_terminal_id,device_model mqtt_username FROM `liu_yu_le`.`device_info` WHERE device_type=0 and user_id IN("+ids+")\n" +
  180 + "UNION\n" +
  181 + "SELECT base_station_id device_id,id iot_terminal_id,'WDB' mqtt_username FROM `liu_yu_le`.`wdb_terminal` WHERE user_id IN("+ids+")\n" +
  182 + ") t GROUP BY t.mqtt_username HAVING COUNT(t.mqtt_username) > 0";
  183 + List list = publicService.getObjectListBySQL(sql);
  184 + return AjaxResult.success(list);
  185 + }
  186 + @ApiOperation("统计用户设备")
  187 + @GetMapping("/countUserHostDevices")
  188 + public AjaxResult countUserHostDevices()
  189 + {
  190 + String ids = SecurityUtils.getUserId()+"";
  191 + String sql = "SELECT t.mqtt_username,COUNT(t.mqtt_username) ct FROM (\n" +
  192 + "SELECT * FROM \n" +
  193 + "(\n" +
  194 + "SELECT b.`device_id`,b.`mqtt_username` FROM `mqtt_broker`.`user_terminal_group_relation` a LEFT JOIN `mqtt_broker`.`iot_terminal` b ON b.`id`=a.`iot_terminal_id` WHERE a.user_info_id IN("+ids+") GROUP BY b.`device_id`\n" +
  195 + "UNION \n" +
  196 + "SELECT id device_id,device_model mqtt_username FROM `liu_yu_le`.`device_host` WHERE user_id IN("+ids+")\n" +
  197 + ") mt GROUP BY device_id \n" +
  198 + ") t GROUP BY t.mqtt_username HAVING COUNT(t.mqtt_username) > 0";
  199 + List list = publicService.getObjectListBySQL(sql);
  200 + return AjaxResult.success(list);
  201 + }
  202 +
169 } 203 }
1 -# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 18080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 47.112.163.61 # 端口,默认为6379 port: 9527 # 数据库索引 database: 1 # 密码 password: Luhui586 # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-api # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login/ApiLogin/*,/content/**,/test/**,/fish/FishPriceCollection/*,/iot/IotTerminal/listByDeviceId/* # NameServer地址 rocketmq: name-server: 47.115.144.179:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1  
  1 +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 18080 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # redis 配置 redis: # 地址 host: 8.129.224.117 # 端口,默认为6379 port: 6379 # 数据库索引 database: 1 # 密码 password: # 连接超时时间 timeout: 10s lettuce: pool: # 连接池中的最小空闲连接 min-idle: 0 # 连接池中的最大空闲连接 max-idle: 8 # 连接池的最大数据库连接数 max-active: 8 # #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1ms # token配置 token: # 令牌自定义标识 header: Authorization # 令牌密钥 secret: abcdefghijklmnopqrstuvwxyz # 令牌有效期(默认30分钟) expireTime: 1440 rediskey: lh-api # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* mqtt: client: device_life: 180 sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /login/ApiLogin/*,/content/**,/test/**,/fish/FishPriceCollection/*,/iot/IotTerminal/listByDeviceId/* # NameServer地址 rocketmq: name-server: 47.115.144.179:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-mqtt-service-deviceCommand-test send-tags: 1
1 package com.zhonglai.luhui.device.protocol.http.analysis.analysis; 1 package com.zhonglai.luhui.device.protocol.http.analysis.analysis;
2 2
3 import com.google.gson.JsonObject; 3 import com.google.gson.JsonObject;
  4 +import com.ruoyi.common.utils.GsonConstructor;
4 import com.zhonglai.luhui.device.analysis.comm.factory.Topic; 5 import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
5 import com.zhonglai.luhui.device.analysis.util.TopicUtil; 6 import com.zhonglai.luhui.device.analysis.util.TopicUtil;
6 import com.zhonglai.luhui.device.protocol.factory.analysis.ProtocolParserFactory; 7 import com.zhonglai.luhui.device.protocol.factory.analysis.ProtocolParserFactory;
@@ -8,7 +9,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; @@ -8,7 +9,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
8 import com.zhonglai.luhui.device.protocol.http.analysis.analysis.topic.*; 9 import com.zhonglai.luhui.device.protocol.http.analysis.analysis.topic.*;
9 import org.springframework.stereotype.Service; 10 import org.springframework.stereotype.Service;
10 11
11 -public class ProtocolParserServiceImpl implements ProtocolParserFactory<JsonObject> { 12 +public class ProtocolParserServiceImpl implements ProtocolParserFactory {
12 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}/{{messageid}}"; 13 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}/{{messageid}}";
13 14
14 @Override 15 @Override
@@ -19,7 +20,8 @@ public class ProtocolParserServiceImpl implements ProtocolParserFactory<JsonObje @@ -19,7 +20,8 @@ public class ProtocolParserServiceImpl implements ProtocolParserFactory<JsonObje
19 } 20 }
20 21
21 @Override 22 @Override
22 - public AnalysisResult analysisPayload(Topic topic, JsonObject payload) { 23 + public AnalysisResult analysisPayload(Topic topic, byte[] payloadby) {
  24 + JsonObject payload = GsonConstructor.get().fromJson(new String(payloadby), JsonObject.class);
23 switch (topic.getTopicType()) 25 switch (topic.getTopicType())
24 { 26 {
25 case "online": 27 case "online":
@@ -8,7 +8,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; @@ -8,7 +8,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
8 import com.zhonglai.luhui.device.protocol.modbus.TopicConfig; 8 import com.zhonglai.luhui.device.protocol.modbus.TopicConfig;
9 import com.zhonglai.luhui.device.protocol.modbus.dto.ModbusDto; 9 import com.zhonglai.luhui.device.protocol.modbus.dto.ModbusDto;
10 10
11 -public class ModbusProtocolParserFactoryImpl implements ProtocolParserFactory<byte[]> { 11 +public class ModbusProtocolParserFactoryImpl implements ProtocolParserFactory {
12 12
13 @Override 13 @Override
14 public Topic analysisTopic(String topicStr) { 14 public Topic analysisTopic(String topicStr) {
@@ -20,7 +20,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; @@ -20,7 +20,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
20 import com.zhonglai.luhui.device.protocol.factory.dto.ParserDeviceHostDto; 20 import com.zhonglai.luhui.device.protocol.factory.dto.ParserDeviceHostDto;
21 21
22 22
23 -public class PLC004ProtocolParserFactoryImpl implements ProtocolParserFactory<byte[]> { 23 +public class PLC004ProtocolParserFactoryImpl implements ProtocolParserFactory {
24 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}"; 24 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}";
25 @Override 25 @Override
26 public Topic analysisTopic(String topicStr) { 26 public Topic analysisTopic(String topicStr) {
@@ -36,7 +36,7 @@ public class ProtocolParserAndPurificationFactory<T> { @@ -36,7 +36,7 @@ public class ProtocolParserAndPurificationFactory<T> {
36 * @param payload 数据信息 36 * @param payload 数据信息
37 * @return 37 * @return
38 */ 38 */
39 - public ProtocolPurificationModel analysisAndPurification(String imei,IotProduct iotProduct, String topicStr, T payload ) throws InstantiationException, IllegalAccessException { 39 + public ProtocolPurificationModel analysisAndPurification(String imei,IotProduct iotProduct, String topicStr, byte[] payload ) throws InstantiationException, IllegalAccessException {
40 Topic baseTopic = TopicUtil.initTopicFromModelStr(topicStr,"/{{roleid}}/{{username}}"); //我们定义的topic 40 Topic baseTopic = TopicUtil.initTopicFromModelStr(topicStr,"/{{roleid}}/{{username}}"); //我们定义的topic
41 41
42 //根据产品类型找到对应的解析服务 42 //根据产品类型找到对应的解析服务
@@ -8,7 +8,7 @@ import com.zhonglai.luhui.device.protocol.factory.analysis.topic.*; @@ -8,7 +8,7 @@ import com.zhonglai.luhui.device.protocol.factory.analysis.topic.*;
8 import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; 8 import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
9 import org.springframework.stereotype.Service; 9 import org.springframework.stereotype.Service;
10 10
11 -public class DefaultProtocolParserFactoryImpl implements ProtocolParserFactory<byte[]>{ 11 +public class DefaultProtocolParserFactoryImpl implements ProtocolParserFactory{
12 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}"; 12 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}";
13 13
14 @Override 14 @Override
@@ -7,9 +7,8 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; @@ -7,9 +7,8 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
7 7
8 /** 8 /**
9 * 协议解析工厂 9 * 协议解析工厂
10 - * @param <T>  
11 */ 10 */
12 -public interface ProtocolParserFactory<T> { 11 +public interface ProtocolParserFactory {
13 Topic analysisTopic(String topicStr); 12 Topic analysisTopic(String topicStr);
14 - AnalysisResult analysisPayload(Topic topic, T payload); 13 + AnalysisResult analysisPayload(Topic topic, byte[] payload);
15 } 14 }
@@ -48,7 +48,7 @@ public abstract class BaseCallback<T> { @@ -48,7 +48,7 @@ public abstract class BaseCallback<T> {
48 /** 48 /**
49 * 数据处理的工作流 49 * 数据处理的工作流
50 */ 50 */
51 - protected ProtocolPurificationModel messageArrived(String imei,String s,T payload) throws ClassNotFoundException, InstantiationException, IllegalAccessException { 51 + protected ProtocolPurificationModel messageArrived(String imei,String s,byte[] payload) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
52 //判断网关是否存在 52 //判断网关是否存在
53 ParserDeviceHostDto oldparserDeviceHostDto = persistenceDBService.getOldParserDeviceHostDto(imei); 53 ParserDeviceHostDto oldparserDeviceHostDto = persistenceDBService.getOldParserDeviceHostDto(imei);
54 if(null == oldparserDeviceHostDto) 54 if(null == oldparserDeviceHostDto)
@@ -282,4 +282,8 @@ public class DefaultDbService { @@ -282,4 +282,8 @@ public class DefaultDbService {
282 return baseDao.findBysql("SELECT * FROM `iot_product_payload_model_number` WHERE product_id=?", IotProductPayloadModelNumber.class,product_id); 282 return baseDao.findBysql("SELECT * FROM `iot_product_payload_model_number` WHERE product_id=?", IotProductPayloadModelNumber.class,product_id);
283 } 283 }
284 284
  285 + public String getProductUsernames()
  286 + {
  287 + return baseDao.findBysql("SELECT GROUP_CONCAT(mqtt_username) users FROM `iot_product`",String.class);
  288 + }
285 } 289 }
@@ -11,7 +11,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult; @@ -11,7 +11,7 @@ import com.zhonglai.luhui.device.protocol.factory.dto.AnalysisResult;
11 import com.zhonglai.luhui.device.protocol.uyu.analysis.topic.CkaDtSndR; 11 import com.zhonglai.luhui.device.protocol.uyu.analysis.topic.CkaDtSndR;
12 import com.zhonglai.luhui.device.protocol.uyu.analysis.topic.CkaDtSndS; 12 import com.zhonglai.luhui.device.protocol.uyu.analysis.topic.CkaDtSndS;
13 13
14 -public class UyuProtocolParserFactoryImpl implements ProtocolParserFactory<byte[]> { 14 +public class UyuProtocolParserFactoryImpl implements ProtocolParserFactory {
15 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}"; 15 private static final String topicModel = "/{{roleid}}/{{username}}/{{clientid}}/{{payloadtype}}/{{topicType}}";
16 @Override 16 @Override
17 public Topic analysisTopic(String topicStr) { 17 public Topic analysisTopic(String topicStr) {
@@ -23,7 +23,7 @@ import org.springframework.stereotype.Service; @@ -23,7 +23,7 @@ import org.springframework.stereotype.Service;
23 import java.util.ArrayList; 23 import java.util.ArrayList;
24 import java.util.List; 24 import java.util.List;
25 25
26 -public class ProtocolParserServiceImpl implements ProtocolParserFactory<byte[]> { 26 +public class ProtocolParserServiceImpl implements ProtocolParserFactory{
27 private static final String topicModel = "/{{roleid}}/{{username}}/{{password}}/{{payloadtype}}/{{clientid}}/{{topicType}}"; 27 private static final String topicModel = "/{{roleid}}/{{username}}/{{password}}/{{payloadtype}}/{{clientid}}/{{topicType}}";
28 28
29 @Override 29 @Override
@@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*; @@ -31,6 +31,7 @@ import org.springframework.web.bind.annotation.*;
31 31
32 import javax.servlet.http.HttpServletRequest; 32 import javax.servlet.http.HttpServletRequest;
33 import java.io.IOException; 33 import java.io.IOException;
  34 +import java.nio.charset.StandardCharsets;
34 import java.util.HashMap; 35 import java.util.HashMap;
35 import java.util.List; 36 import java.util.List;
36 import java.util.Map; 37 import java.util.Map;
@@ -60,11 +61,10 @@ public class HttpDataProxyController { @@ -60,11 +61,10 @@ public class HttpDataProxyController {
60 public AjaxResult post(@PathVariable String role, @PathVariable String username, @PathVariable String imei, @PathVariable Integer time, @PathVariable String topicType, HttpServletRequest request) throws IOException { 61 public AjaxResult post(@PathVariable String role, @PathVariable String username, @PathVariable String imei, @PathVariable Integer time, @PathVariable String topicType, HttpServletRequest request) throws IOException {
61 byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream()); 62 byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream());
62 String body = new String(bodyBytes, request.getCharacterEncoding()); 63 String body = new String(bodyBytes, request.getCharacterEncoding());
63 - JsonObject jsonObject = GsonConstructor.get().fromJson(body,JsonObject.class);  
64 String topic = "/"+role+"/"+username+"/"+imei+"/Json/"+topicType+"/"+time; 64 String topic = "/"+role+"/"+username+"/"+imei+"/Json/"+topicType+"/"+time;
65 - DeviceDataLog.info(imei, DataLogType.发来数据,topic,jsonObject); 65 + DeviceDataLog.info(imei, DataLogType.发来数据,topic,body);
66 66
67 - ProtocolPurificationModel protocolPurificationModel = httpCallback.messageArrived(imei,topic,jsonObject); 67 + ProtocolPurificationModel protocolPurificationModel = httpCallback.messageArrived(imei,topic,body.getBytes(StandardCharsets.UTF_8));
68 68
69 Map<String,Object> map = HttpNoticeCach.consumer(imei); 69 Map<String,Object> map = HttpNoticeCach.consumer(imei);
70 if (null == map) 70 if (null == map)
@@ -19,9 +19,9 @@ import java.util.TimerTask; @@ -19,9 +19,9 @@ import java.util.TimerTask;
19 19
20 20
21 @Service 21 @Service
22 -public class HttpCallback extends BaseCallback<JsonObject> { 22 +public class HttpCallback extends BaseCallback<byte[]> {
23 23
24 - public ProtocolPurificationModel messageArrived(String imei, String topic, JsonObject data) 24 + public ProtocolPurificationModel messageArrived(String imei, String topic, byte[] data)
25 { 25 {
26 try { 26 try {
27 return HttpCallback.super.messageArrived(imei,topic,data); 27 return HttpCallback.super.messageArrived(imei,topic,data);
@@ -18,30 +18,102 @@ @@ -18,30 +18,102 @@
18 </properties> 18 </properties>
19 19
20 <dependencies> 20 <dependencies>
21 - <!-- 核心模块--> 21 + <!-- spring-boot-devtools -->
22 <dependency> 22 <dependency>
23 - <groupId>com.zhonglai.luhui</groupId>  
24 - <artifactId>ruoyi-framework</artifactId> 23 + <groupId>org.springframework.boot</groupId>
  24 + <artifactId>spring-boot-devtools</artifactId>
  25 + <optional>true</optional> <!-- 表示依赖不会传递 -->
25 </dependency> 26 </dependency>
  27 + <!-- SpringBoot Web容器 -->
26 <dependency> 28 <dependency>
27 - <groupId>com.zhonglai.luhui</groupId>  
28 - <artifactId>lh-common-datasource</artifactId> 29 + <groupId>org.springframework.boot</groupId>
  30 + <artifactId>spring-boot-starter-web</artifactId>
  31 + </dependency>
  32 + <!-- Spring框架基本的核心工具 -->
  33 + <dependency>
  34 + <groupId>org.springframework</groupId>
  35 + <artifactId>spring-context-support</artifactId>
  36 + </dependency>
  37 + <!-- SpringWeb模块 -->
  38 + <dependency>
  39 + <groupId>org.springframework</groupId>
  40 + <artifactId>spring-web</artifactId>
  41 + </dependency>
  42 + <!-- yml解析器 -->
  43 + <dependency>
  44 + <groupId>org.yaml</groupId>
  45 + <artifactId>snakeyaml</artifactId>
  46 + </dependency>
  47 + <!-- servlet包 -->
  48 + <dependency>
  49 + <groupId>javax.servlet</groupId>
  50 + <artifactId>javax.servlet-api</artifactId>
  51 + </dependency>
  52 + <dependency>
  53 + <groupId>org.apache.commons</groupId>
  54 + <artifactId>commons-text</artifactId>
  55 + </dependency>
  56 +
  57 + <!-- 文档 -->
  58 + <dependency>
  59 + <groupId>io.springfox</groupId>
  60 + <artifactId>springfox-swagger2</artifactId>
  61 + <version>${swagger.version}</version>
  62 + <exclusions>
  63 + <exclusion>
  64 + <groupId>io.swagger</groupId>
  65 + <artifactId>swagger-models</artifactId>
  66 + </exclusion>
  67 + <exclusion>
  68 + <groupId>com.google.guava</groupId>
  69 + <artifactId>guava</artifactId>
  70 + </exclusion>
  71 + </exclusions>
  72 + </dependency>
  73 + <!--https://mvnrepository.com/artifact/io.swagger/swagger-models-->
  74 + <dependency>
  75 + <groupId>io.swagger</groupId>
  76 + <artifactId>swagger-models</artifactId>
  77 + <version>${swagger-models.version}</version>
  78 + </dependency>
  79 + <dependency>
  80 + <groupId>io.springfox</groupId>
  81 + <artifactId>springfox-swagger-ui</artifactId>
  82 + <version>${swagger.version}</version>
  83 + </dependency>
  84 + <!--&lt;!&ndash; https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui &ndash;&gt;-->
  85 + <dependency>
  86 + <groupId>com.github.xiaoymin</groupId>
  87 + <artifactId>swagger-bootstrap-ui</artifactId>
  88 + <version>${swagger-ui.version}</version>
29 </dependency> 89 </dependency>
  90 +
  91 + <!-- 支持data -->
30 <dependency> 92 <dependency>
31 - <groupId>org.aspectj</groupId>  
32 - <artifactId>aspectjweaver</artifactId> 93 + <groupId>org.projectlombok</groupId>
  94 + <artifactId>lombok</artifactId>
33 </dependency> 95 </dependency>
  96 +
  97 + <!--常用工具类 -->
34 <dependency> 98 <dependency>
35 - <groupId>org.aspectj</groupId>  
36 - <artifactId>aspectjrt</artifactId> 99 + <groupId>org.apache.commons</groupId>
  100 + <artifactId>commons-lang3</artifactId>
37 </dependency> 101 </dependency>
  102 +
  103 +
  104 + <dependency>
  105 + <groupId>com.squareup.okhttp3</groupId>
  106 + <artifactId>okhttp</artifactId>
  107 + </dependency>
  108 +
  109 + <!-- 通用工具-->
38 <dependency> 110 <dependency>
39 <groupId>com.zhonglai.luhui</groupId> 111 <groupId>com.zhonglai.luhui</groupId>
40 - <artifactId>lh-jar-device-analysis</artifactId> 112 + <artifactId>lh-domain</artifactId>
41 </dependency> 113 </dependency>
42 <dependency> 114 <dependency>
43 <groupId>com.zhonglai.luhui</groupId> 115 <groupId>com.zhonglai.luhui</groupId>
44 - <artifactId>lh-jar-device-service</artifactId> 116 + <artifactId>lh-device-protocol-factory</artifactId>
45 </dependency> 117 </dependency>
46 </dependencies> 118 </dependencies>
47 119
1 package com.zhonglai.luhui.http.service; 1 package com.zhonglai.luhui.http.service;
2 2
3 -import com.ruoyi.framework.config.ResourcesConfig;  
4 -import com.zhonglai.luhui.device.service.DeviceControlService; 3 +import com.zhonglai.luhui.device.analysis.comm.config.CacheConfig;
  4 +import com.zhonglai.luhui.device.analysis.comm.config.FastJson2JsonRedisSerializer;
5 import org.springframework.boot.SpringApplication; 5 import org.springframework.boot.SpringApplication;
6 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 import org.springframework.boot.autoconfigure.SpringBootApplication;
7 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 7 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@@ -9,17 +9,15 @@ import org.springframework.context.annotation.ComponentScan; @@ -9,17 +9,15 @@ import org.springframework.context.annotation.ComponentScan;
9 import org.springframework.context.annotation.FilterType; 9 import org.springframework.context.annotation.FilterType;
10 10
11 @ComponentScan(basePackages = { 11 @ComponentScan(basePackages = {
12 - "com.ruoyi.common",  
13 - "com.ruoyi.framework",  
14 - "com.zhonglai.luhui.datasource",  
15 - "com.zhonglai.luhui.dao",  
16 - "com.zhonglai.luhui.device",  
17 - "com.zhonglai.luhui.redis",  
18 - "com.zhonglai.luhui.rocketmq", 12 + "com.ruoyi.common.utils.spring",
  13 + "com.zhonglai.luhui.device.protocol",
  14 + "com.zhonglai.luhui.device.analysis.comm.config",
19 "com.zhonglai.luhui.http.service", 15 "com.zhonglai.luhui.http.service",
20 -}  
21 -)  
22 -@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) 16 +},excludeFilters = @ComponentScan.Filter(
  17 + type = FilterType.ASSIGNABLE_TYPE,
  18 + classes = {CacheConfig.class, FastJson2JsonRedisSerializer.class}
  19 +) )
  20 +@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
23 public class LhHttpServiceApplication { 21 public class LhHttpServiceApplication {
24 public static void main(String[] args) { 22 public static void main(String[] args) {
25 SpringApplication.run(LhHttpServiceApplication.class,args); 23 SpringApplication.run(LhHttpServiceApplication.class,args);
1 package com.zhonglai.luhui.http.service.config; 1 package com.zhonglai.luhui.http.service.config;
2 2
3 -import com.ruoyi.common.config.RuoYiConfig;  
4 import io.swagger.annotations.ApiOperation; 3 import io.swagger.annotations.ApiOperation;
5 -import org.springframework.beans.factory.annotation.Autowired;  
6 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Bean;
7 import org.springframework.context.annotation.Configuration; 5 import org.springframework.context.annotation.Configuration;
8 import springfox.documentation.builders.ApiInfoBuilder; 6 import springfox.documentation.builders.ApiInfoBuilder;
@@ -18,9 +16,6 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2; @@ -18,9 +16,6 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
18 @Configuration 16 @Configuration
19 @EnableSwagger2 17 @EnableSwagger2
20 public class SwaggerConfig { 18 public class SwaggerConfig {
21 - /** 系统基础配置 */  
22 - @Autowired  
23 - private RuoYiConfig ruoyiConfig;  
24 @Bean 19 @Bean
25 public Docket createRestApi() { 20 public Docket createRestApi() {
26 return new Docket(DocumentationType.SWAGGER_2) 21 return new Docket(DocumentationType.SWAGGER_2)
@@ -39,13 +34,13 @@ public class SwaggerConfig { @@ -39,13 +34,13 @@ public class SwaggerConfig {
39 // 用ApiInfoBuilder进行定制 34 // 用ApiInfoBuilder进行定制
40 return new ApiInfoBuilder() 35 return new ApiInfoBuilder()
41 // 设置标题 36 // 设置标题
42 - .title("标题:登陆服务") 37 + .title("标题:http协议服务监听")
43 // 描述 38 // 描述
44 - .description("描述:各种角色的登陆接口") 39 + .description("描述:用于通过http发送指令控制终端端操作")
45 // 作者信息 40 // 作者信息
46 - .contact(new Contact(ruoyiConfig.getName(), null, null)) 41 + .contact(new Contact("", null, null))
47 // 版本 42 // 版本
48 - .version("版本号:" + ruoyiConfig.getVersion()) 43 + .version("版本号:1.1.1" )
49 .build(); 44 .build();
50 } 45 }
51 46
1 -package com.zhonglai.luhui.http.service.controller;  
2 -  
3 -import com.ruoyi.common.core.domain.AjaxResult;  
4 -import com.ruoyi.common.exception.ServiceException;  
5 -import com.ruoyi.common.utils.StringUtils;  
6 -import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;  
7 -import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDto;  
8 -import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew;  
9 -import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;  
10 -import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory;  
11 -import com.zhonglai.luhui.device.analysis.comm.factory.Topic;  
12 -import com.zhonglai.luhui.device.analysis.comm.service.CacheService;  
13 -import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceService;  
14 -import com.zhonglai.luhui.device.domain.IotDevice;  
15 -import com.zhonglai.luhui.device.service.IIotDeviceService;  
16 -import com.zhonglai.luhui.http.service.util.HttpServletRequestUtil;  
17 -import io.swagger.annotations.Api;  
18 -import io.swagger.annotations.ApiOperation;  
19 -import org.slf4j.Logger;  
20 -import org.slf4j.LoggerFactory;  
21 -import org.springframework.beans.factory.annotation.Autowired;  
22 -import org.springframework.web.bind.annotation.ModelAttribute;  
23 -import org.springframework.web.bind.annotation.PathVariable;  
24 -import org.springframework.web.bind.annotation.RequestMapping;  
25 -import org.springframework.web.bind.annotation.RestController;  
26 -  
27 -import javax.servlet.http.HttpServletRequest;  
28 -import javax.servlet.http.HttpServletResponse;  
29 -  
30 -@Api(tags = "设备操作")  
31 -@RestController  
32 -@RequestMapping("/device")  
33 -public class DeviceServiceController {  
34 -  
35 - private static final Logger log = LoggerFactory.getLogger(DeviceServiceController.class);  
36 -  
37 - private static String authKey = "key";  
38 -  
39 - @Autowired  
40 - private IIotDeviceService deviceService ;  
41 -  
42 - @Autowired  
43 - private BusinessAgreementFactory businessAgreementFactory;  
44 -  
45 - @Autowired  
46 - private CacheService cacheService; //数据缓存  
47 -  
48 - @Autowired  
49 - private DataPersistenceService dataPersistenceService; //数据持久化  
50 -  
51 - /**  
52 - * 添加校验  
53 - * @return  
54 - */  
55 - @ModelAttribute  
56 - public void preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
57 - {  
58 - String key = request.getParameter(authKey);  
59 - if(StringUtils.isNoneEmpty(key))  
60 - {  
61 - response.setStatus(403);  
62 - throw new ServiceException("验证失败");  
63 - }  
64 -  
65 - }  
66 -  
67 - @ApiOperation("更新指定设备的全部数据")  
68 - @RequestMapping(value = "putAllData/{deviceid}/{messageid}")  
69 - public AjaxResult putDeviceAllData(@PathVariable String deviceid,@PathVariable String messageid,HttpServletRequest request) throws Exception {  
70 - String str = HttpServletRequestUtil.getAllParametersAsJSON(request);  
71 -  
72 - if(StringUtils.isEmpty(str))  
73 - {  
74 - return AjaxResult.error("数据为空");  
75 - }  
76 -  
77 - String imei = deviceid.split("_")[0];  
78 - IotDevice iotDevice = deviceService.selectIotDeviceByClient_id(imei);  
79 - Topic topic = new Topic();  
80 - topic.setRoleid(iotDevice.getProduct_id()+"");  
81 - topic.setUsername(iotDevice.getMqtt_username());  
82 - topic.setClientid(iotDevice.getClient_id());  
83 - topic.setTopicType("PUT");  
84 - topic.setMessageid(messageid);  
85 - topic.setPayloadtype("json");  
86 -  
87 - //转化为协议对象  
88 - BusinessDto businessDto = BusinessDtoClassNew.newBean(topic.getPayloadtype(),str.getBytes()).analyticalModel(iotDevice.getThings_model_value());  
89 -  
90 - BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic);  
91 - //解析为业务对象  
92 - ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto));  
93 - if(null == dto)  
94 - {  
95 - return AjaxResult.error("没有业务解析方法");  
96 - }  
97 - log.info("{} 解析到的dto【{}】",dto);  
98 -  
99 - //缓存数据  
100 - cacheService.updateCache(topic,dto);  
101 -  
102 - //数据持久化  
103 - dataPersistenceService.persistence(topic,dto);  
104 - return AjaxResult.success();  
105 - }  
106 -  
107 - @ApiOperation("更新指定设备的部分数据")  
108 - @RequestMapping(value = "putPartialData/{deviceid}")  
109 - public AjaxResult putDevicePartialData(@PathVariable String deviceid)  
110 - {  
111 - return AjaxResult.success();  
112 - }  
113 -} 1 +//package com.zhonglai.luhui.http.service.controller;
  2 +//
  3 +//import com.ruoyi.common.core.domain.AjaxResult;
  4 +//import com.ruoyi.common.exception.ServiceException;
  5 +//import com.ruoyi.common.utils.StringUtils;
  6 +//import com.zhonglai.luhui.device.analysis.comm.dto.ServerDto;
  7 +//import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDto;
  8 +//import com.zhonglai.luhui.device.analysis.comm.dto.business.BusinessDtoClassNew;
  9 +//import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreement;
  10 +//import com.zhonglai.luhui.device.analysis.comm.factory.BusinessAgreementFactory;
  11 +//import com.zhonglai.luhui.device.analysis.comm.factory.Topic;
  12 +//import com.zhonglai.luhui.device.analysis.comm.service.CacheService;
  13 +//import com.zhonglai.luhui.device.analysis.comm.service.DataPersistenceService;
  14 +//import com.zhonglai.luhui.device.domain.IotDevice;
  15 +//import com.zhonglai.luhui.device.service.IIotDeviceService;
  16 +//import com.zhonglai.luhui.http.service.util.HttpServletRequestUtil;
  17 +//import io.swagger.annotations.Api;
  18 +//import io.swagger.annotations.ApiOperation;
  19 +//import org.slf4j.Logger;
  20 +//import org.slf4j.LoggerFactory;
  21 +//import org.springframework.beans.factory.annotation.Autowired;
  22 +//import org.springframework.web.bind.annotation.ModelAttribute;
  23 +//import org.springframework.web.bind.annotation.PathVariable;
  24 +//import org.springframework.web.bind.annotation.RequestMapping;
  25 +//import org.springframework.web.bind.annotation.RestController;
  26 +//
  27 +//import javax.servlet.http.HttpServletRequest;
  28 +//import javax.servlet.http.HttpServletResponse;
  29 +//
  30 +//@Api(tags = "设备操作")
  31 +//@RestController
  32 +//@RequestMapping("/device")
  33 +//public class DeviceServiceController {
  34 +//
  35 +// private static final Logger log = LoggerFactory.getLogger(DeviceServiceController.class);
  36 +//
  37 +// private static String authKey = "key";
  38 +//
  39 +// @Autowired
  40 +// private IIotDeviceService deviceService ;
  41 +//
  42 +// @Autowired
  43 +// private BusinessAgreementFactory businessAgreementFactory;
  44 +//
  45 +// @Autowired
  46 +// private CacheService cacheService; //数据缓存
  47 +//
  48 +// @Autowired
  49 +// private DataPersistenceService dataPersistenceService; //数据持久化
  50 +//
  51 +// /**
  52 +// * 添加校验
  53 +// * @return
  54 +// */
  55 +// @ModelAttribute
  56 +// public void preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  57 +// {
  58 +// String key = request.getParameter(authKey);
  59 +// if(StringUtils.isNoneEmpty(key))
  60 +// {
  61 +// response.setStatus(403);
  62 +// throw new ServiceException("验证失败");
  63 +// }
  64 +//
  65 +// }
  66 +//
  67 +// @ApiOperation("更新指定设备的全部数据")
  68 +// @RequestMapping(value = "putAllData/{deviceid}/{messageid}")
  69 +// public AjaxResult putDeviceAllData(@PathVariable String deviceid,@PathVariable String messageid,HttpServletRequest request) throws Exception {
  70 +// String str = HttpServletRequestUtil.getAllParametersAsJSON(request);
  71 +//
  72 +// if(StringUtils.isEmpty(str))
  73 +// {
  74 +// return AjaxResult.error("数据为空");
  75 +// }
  76 +//
  77 +// String imei = deviceid.split("_")[0];
  78 +// IotDevice iotDevice = deviceService.selectIotDeviceByClient_id(imei);
  79 +// Topic topic = new Topic();
  80 +// topic.setRoleid(iotDevice.getProduct_id()+"");
  81 +// topic.setUsername(iotDevice.getMqtt_username());
  82 +// topic.setClientid(iotDevice.getClient_id());
  83 +// topic.setTopicType("PUT");
  84 +// topic.setMessageid(messageid);
  85 +// topic.setPayloadtype("json");
  86 +//
  87 +// //转化为协议对象
  88 +// BusinessDto businessDto = BusinessDtoClassNew.newBean(topic.getPayloadtype(),str.getBytes()).analyticalModel(iotDevice.getThings_model_value());
  89 +//
  90 +// BusinessAgreement businessAgreement = businessAgreementFactory.createBusinessAgreement(topic);
  91 +// //解析为业务对象
  92 +// ServerDto dto = businessAgreement.analysis(topic,businessAgreement.toData(businessDto));
  93 +// if(null == dto)
  94 +// {
  95 +// return AjaxResult.error("没有业务解析方法");
  96 +// }
  97 +// log.info("{} 解析到的dto【{}】",dto);
  98 +//
  99 +// //缓存数据
  100 +// cacheService.updateCache(topic,dto);
  101 +//
  102 +// //数据持久化
  103 +// dataPersistenceService.persistence(topic,dto);
  104 +// return AjaxResult.success();
  105 +// }
  106 +//
  107 +// @ApiOperation("更新指定设备的部分数据")
  108 +// @RequestMapping(value = "putPartialData/{deviceid}")
  109 +// public AjaxResult putDevicePartialData(@PathVariable String deviceid)
  110 +// {
  111 +// return AjaxResult.success();
  112 +// }
  113 +//}
  1 +package com.zhonglai.luhui.http.service.controller;
  2 +
  3 +import com.zhonglai.luhui.device.service.IIotDeviceService;
  4 +import com.zhonglai.luhui.http.service.model.LogMessageDto;
  5 +import com.zhonglai.luhui.http.service.service.HttpCallback;
  6 +import io.swagger.annotations.Api;
  7 +import io.swagger.annotations.ApiImplicitParam;
  8 +import io.swagger.annotations.ApiImplicitParams;
  9 +import io.swagger.annotations.ApiOperation;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.web.bind.annotation.*;
  12 +
  13 +import java.nio.charset.StandardCharsets;
  14 +
  15 +@Api(tags = "首页")
  16 +@RestController
  17 +@RequestMapping("/")
  18 +public class IndexController {
  19 +
  20 + @Autowired
  21 + private HttpCallback httpCallback ;
  22 + @ApiOperation("获取一天的日志")
  23 + @ApiImplicitParams({
  24 + @ApiImplicitParam(value = "时间",name = "time"),
  25 + @ApiImplicitParam(value = "设备imei",name = "clientId"),
  26 + @ApiImplicitParam(value = "产品账号",name = "username"),
  27 + @ApiImplicitParam(value = "topic",name = "topic"),
  28 + @ApiImplicitParam(value = "数据消息",name = "message"),
  29 + })
  30 + @PostMapping(value = "logpost")
  31 + public void logpost(@RequestBody LogMessageDto logMessageDto) {
  32 + httpCallback.messageArrived(logMessageDto.getClientId(),logMessageDto.getTopic(),logMessageDto.getMessage().getBytes(StandardCharsets.UTF_8));
  33 + }
  34 +
  35 +}
  1 +package com.zhonglai.luhui.http.service.model;
  2 +
  3 +public class LogMessageDto {
  4 + private String time;
  5 + private String username;
  6 + private String clientId;
  7 + private String topic;
  8 + private String message;
  9 +
  10 + public String getUsername() {
  11 + return username;
  12 + }
  13 +
  14 + public void setUsername(String username) {
  15 + this.username = username;
  16 + }
  17 +
  18 + public String getClientId() {
  19 + return clientId;
  20 + }
  21 +
  22 + public void setClientId(String clientId) {
  23 + this.clientId = clientId;
  24 + }
  25 +
  26 + public String getTime() {
  27 + return time;
  28 + }
  29 +
  30 + public void setTime(String time) {
  31 + this.time = time;
  32 + }
  33 +
  34 + public String getTopic() {
  35 + return topic;
  36 + }
  37 +
  38 + public void setTopic(String topic) {
  39 + this.topic = topic;
  40 + }
  41 +
  42 + public String getMessage() {
  43 + return message;
  44 + }
  45 +
  46 + public void setMessage(String message) {
  47 + this.message = message;
  48 + }
  49 +}
  1 +package com.zhonglai.luhui.http.service.service;
  2 +
  3 +import com.ruoyi.common.utils.StringUtils;
  4 +import com.zhonglai.luhui.device.analysis.comm.config.SysParameter;
  5 +import com.zhonglai.luhui.device.protocol.factory.dto.ProtocolPurificationModel;
  6 +import com.zhonglai.luhui.device.protocol.factory.service.BaseCallback;
  7 +import com.zhonglai.luhui.device.protocol.factory.service.impl.DefaultDbService;
  8 +import org.aspectj.lang.annotation.AfterReturning;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.beans.factory.annotation.Value;
  11 +import org.springframework.boot.context.event.ApplicationReadyEvent;
  12 +import org.springframework.context.event.EventListener;
  13 +import org.springframework.stereotype.Service;
  14 +
  15 +import javax.annotation.PostConstruct;
  16 +
  17 +
  18 +@Service
  19 +public class HttpCallback extends BaseCallback<byte[]> {
  20 + @Value("${sys.register-product}")
  21 + private String registerProduct; //客户端操作时间
  22 + @Autowired
  23 + private DefaultDbService defaultDbService;
  24 +
  25 + @Value("${server.port}")
  26 + private long port;
  27 + public ProtocolPurificationModel messageArrived(String imei, String topic, byte[] data)
  28 + {
  29 + try {
  30 + return HttpCallback.super.messageArrived(imei,topic,data);
  31 + } catch (Exception e) {
  32 + log.error(imei+"解析数据失败",e);
  33 + }
  34 + return null;
  35 + }
  36 +
  37 + @EventListener(ApplicationReadyEvent.class)
  38 + public void registerService()
  39 + {
  40 + if(StringUtils.isBlank(registerProduct))
  41 + {
  42 + registerProduct =defaultDbService.getProductUsernames();
  43 + }
  44 + for (String product:registerProduct.split(","))
  45 + {
  46 + JedisService.registerLogListenService(product, SysParameter.service_ip+":"+port);
  47 + }
  48 + }
  49 +}
  1 +package com.zhonglai.luhui.http.service.service;
  2 +
  3 +import com.zhonglai.luhui.device.protocol.factory.control.ClienNoticeServiceFactory;
  4 +import com.zhonglai.luhui.device.protocol.factory.dto.NoticeMessageDto;
  5 +import org.springframework.stereotype.Service;
  6 +
  7 +@Service
  8 +public class HttpClienNoticeServiceImpl implements ClienNoticeServiceFactory {
  9 + @Override
  10 + public boolean sendMessage(NoticeMessageDto noticeMessageDomain) {
  11 + return false;
  12 + }
  13 +}
  1 +package com.zhonglai.luhui.http.service.service;
  2 +
  3 +import cn.hutool.db.nosql.redis.RedisDS;
  4 +
  5 +import java.util.Map;
  6 +
  7 +public class JedisService {
  8 + private static RedisDS jedis = RedisDS.create();
  9 +
  10 + public static Map<String,String> getLogListenServiceRegister()
  11 + {
  12 + return jedis.getJedis().hgetAll("log-listen-service-register");
  13 + }
  14 + public static Long registerLogListenService(String username,String host)
  15 + {
  16 + return jedis.getJedis().hset("log-listen-service-register",username,host);
  17 + }
  18 + public static void main(String[] args) {
  19 + jedis.getJedis().hset("log-listen-service-register", "6_WP","localhost:8443");
  20 + jedis.getJedis().hset("log-listen-service-register", "6_WP","localhost:84431");
  21 + System.out.println(jedis.getJedis().hget("log-listen-service-register","6_WP"));
  22 + }
  23 +}
1 -# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8065 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true ##redic配置 redis: database: 1 # Redis服务器地址 写你的ip host: 47.112.163.61 # Redis服务器连接端口 port: 9527 # Redis服务器连接密码(默认为空) password: Luhui586 # 连接池最大连接数(使用负值表示没有限制 类似于mysql的连接池 jedis: pool: max-active: 200 # 连接池最大阻塞等待时间(使用负值表示没有限制) 表示连接池的链接拿完了 现在去申请需要等待的时间 max-wait: -1 # 连接池中的最大空闲连接 max-idle: 10 # 连接池中的最小空闲连接 min-idle: 0 # 连接超时时间(毫秒) 去链接redis服务端 timeout: 6000 # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.luhui.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /** redis: field: "lh:mqttservice:" isText: false # NameServer地址 rocketmq: name-server: 47.115.144.179:9876 # 默认的消息组 producer: group: deviceCommand send-message-timeout: 30000 send-topic: lh-http-service-deviceCommand-test send-tags: 1  
  1 +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 实例演示开关 demoEnabled: true # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8065 servlet: # 应用的访问路径 context-path: / tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 mqtt: client: #客户端操作时间 operationTime: 10 sys: register-product: 6_WP #rocketmq配置信息 rocketmq: #nameservice服务器地址(多个以英文逗号隔开) name-server: 47.115.144.179:9876 consumerGroup: lh-http-service topic: deviceCommandListen operationToken: ${random.uuid}
  1 +#-------------------------------------------------------------------------------
  2 +# Redis客户端配置样例
  3 +# 每一个分组代表一个Redis实例
  4 +# 无分组的Pool配置为所有分组的共用配置,如果分组自己定义Pool配置,则覆盖共用配置
  5 +# 池配置来自于:https://www.cnblogs.com/jklk/p/7095067.html
  6 +#-------------------------------------------------------------------------------
  7 +
  8 +#----- 默认(公有)配置
  9 +# 地址,默认localhost
  10 +host = 47.112.163.61
  11 +# 端口,默认6379
  12 +port = 9527
  13 +# 超时,默认2000
  14 +timeout = 2000
  15 +# 连接超时,默认timeout
  16 +connectionTimeout = 2000
  17 +# 读取超时,默认timeout
  18 +soTimeout = 2000
  19 +# 密码,默认无
  20 +password = Luhui586
  21 +# 数据库序号,默认0
  22 +database = 0
  23 +# 客户端名,默认"Hutool"
  24 +clientName = Hutool
  25 +# SSL连接,默认false
  26 +ssl = false;
  27 +
  28 +#----- 自定义分组的连接
  29 +[custom]
  30 +# 地址,默认localhost
  31 +host = 47.112.163.61
  32 +# 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
  33 +BlockWhenExhausted = true;
  34 +# 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
  35 +evictionPolicyClassName = org.apache.commons.pool2.impl.DefaultEvictionPolicy
  36 +# 是否启用pool的jmx管理功能, 默认true
  37 +jmxEnabled = true;
  38 +# 是否启用后进先出, 默认true
  39 +lifo = true;
  40 +# 最大空闲连接数, 默认8个
  41 +maxIdle = 8
  42 +# 最小空闲连接数, 默认0
  43 +minIdle = 0
  44 +# 最大连接数, 默认8个
  45 +maxTotal = 8
  46 +# 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
  47 +maxWaitMillis = -1
  48 +# 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
  49 +minEvictableIdleTimeMillis = 1800000
  50 +# 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
  51 +numTestsPerEvictionRun = 3;
  52 +# 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
  53 +SoftMinEvictableIdleTimeMillis = 1800000
  54 +# 在获取连接的时候检查有效性, 默认false
  55 +testOnBorrow = false
  56 +# 在空闲时检查有效性, 默认false
  57 +testWhileIdle = false
  58 +# 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
  59 +timeBetweenEvictionRunsMillis = -1
1 -#错误消息  
2 -not.null=* 必须填写  
3 -user.jcaptcha.error=验证码错误  
4 -user.jcaptcha.expire=验证码已失效  
5 -user.not.exists=用户不存在/密码错误  
6 -user.password.not.match=用户不存在/密码错误  
7 -user.password.retry.limit.count=密码输入错误{0}次  
8 -user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定10分钟  
9 -user.password.delete=对不起,您的账号已被删除  
10 -user.blocked=用户已封禁,请联系管理员  
11 -role.blocked=角色已封禁,请联系管理员  
12 -user.logout.success=退出成功  
13 -  
14 -length.not.valid=长度必须在{min}到{max}个字符之间  
15 -  
16 -user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头  
17 -user.password.not.valid=* 5-50个字符  
18 -  
19 -user.email.not.valid=邮箱格式错误  
20 -user.mobile.phone.number.not.valid=手机号格式错误  
21 -user.login.success=登录成功  
22 -user.register.success=注册成功  
23 -user.notfound=请重新登录  
24 -user.forcelogout=管理员强制退出,请重新登录  
25 -user.unknown.error=未知错误,请重新登录  
26 -  
27 -##文件上传消息  
28 -upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB!  
29 -upload.filename.exceed.length=上传的文件名最长{0}个字符  
30 -  
31 -##权限  
32 -no.permission=您没有数据的权限,请联系管理员添加权限 [{0}]  
33 -no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}]  
34 -no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}]  
35 -no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}]  
36 -no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}]  
37 -no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}]  
1 -<?xml version="1.0" encoding="UTF-8"?>  
2 -<configuration>  
3 - <!-- 日志存放路径 -->  
4 - <property name="log.path" value="logs" />  
5 - <!-- 日志输出格式 -->  
6 - <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />  
7 -  
8 - <!-- 控制台输出 -->  
9 - <appender name="console" class="ch.qos.logback.core.ConsoleAppender">  
10 - <encoder>  
11 - <pattern>${log.pattern}</pattern>  
12 - </encoder>  
13 - </appender>  
14 -  
15 - <!-- 系统日志输出 -->  
16 - <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">  
17 - <file>${log.path}/sys-info.log</file>  
18 - <!-- 循环政策:基于时间创建日志文件 -->  
19 - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
20 - <!-- 日志文件名格式 -->  
21 - <fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>  
22 - <!-- 日志最大的历史 60天 -->  
23 - <maxHistory>60</maxHistory>  
24 - </rollingPolicy>  
25 - <encoder>  
26 - <pattern>${log.pattern}</pattern>  
27 - </encoder>  
28 - <filter class="ch.qos.logback.classic.filter.LevelFilter">  
29 - <!-- 过滤的级别 -->  
30 - <level>INFO</level>  
31 - <!-- 匹配时的操作:接收(记录) -->  
32 - <onMatch>ACCEPT</onMatch>  
33 - <!-- 不匹配时的操作:拒绝(不记录) -->  
34 - <onMismatch>DENY</onMismatch>  
35 - </filter>  
36 - </appender>  
37 -  
38 - <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">  
39 - <file>${log.path}/sys-error.log</file>  
40 - <!-- 循环政策:基于时间创建日志文件 -->  
41 - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
42 - <!-- 日志文件名格式 -->  
43 - <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>  
44 - <!-- 日志最大的历史 60天 -->  
45 - <maxHistory>60</maxHistory>  
46 - </rollingPolicy>  
47 - <encoder>  
48 - <pattern>${log.pattern}</pattern>  
49 - </encoder>  
50 - <filter class="ch.qos.logback.classic.filter.LevelFilter">  
51 - <!-- 过滤的级别 -->  
52 - <level>ERROR</level>  
53 - <!-- 匹配时的操作:接收(记录) -->  
54 - <onMatch>ACCEPT</onMatch>  
55 - <!-- 不匹配时的操作:拒绝(不记录) -->  
56 - <onMismatch>DENY</onMismatch>  
57 - </filter>  
58 - </appender>  
59 -  
60 - <!-- 用户访问日志输出 -->  
61 - <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">  
62 - <file>${log.path}/sys-user.log</file>  
63 - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
64 - <!-- 按天回滚 daily -->  
65 - <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>  
66 - <!-- 日志最大的历史 60天 -->  
67 - <maxHistory>60</maxHistory>  
68 - </rollingPolicy>  
69 - <encoder>  
70 - <pattern>${log.pattern}</pattern>  
71 - </encoder>  
72 - </appender>  
73 -  
74 - <!-- 系统模块日志级别控制 -->  
75 - <logger name="com.ruoyi" level="info" />  
76 - <!-- Spring日志级别控制 -->  
77 - <logger name="org.springframework" level="warn" />  
78 -  
79 - <root level="info">  
80 - <appender-ref ref="console" />  
81 - </root>  
82 -  
83 - <!--系统操作日志-->  
84 - <root level="info">  
85 - <appender-ref ref="file_info" />  
86 - <appender-ref ref="file_error" />  
87 - </root>  
88 -  
89 - <!--系统用户操作日志-->  
90 - <logger name="sys-user" level="info">  
91 - <appender-ref ref="sys-user"/>  
92 - </logger>  
93 -</configuration>  
@@ -29,7 +29,7 @@ mqtt: @@ -29,7 +29,7 @@ mqtt:
29 client: 29 client:
30 #客户端操作时间 30 #客户端操作时间
31 operationTime: 10 31 operationTime: 10
32 - productids: 30 32 + productids: 17
33 33
34 #rocketmq配置信息 34 #rocketmq配置信息
35 rocketmq: 35 rocketmq:
  1 +package com.zhonglai.luhui.mqtt;
  2 +
  3 +import io.netty.channel.ChannelHandler;
  4 +import io.netty.channel.ChannelHandlerContext;
  5 +import io.netty.channel.SimpleChannelInboundHandler;
  6 +
  7 +@ChannelHandler.Sharable
  8 +public class LogServerHandler extends SimpleChannelInboundHandler<String> {
  9 +
  10 +
  11 + @Override
  12 + public void channelActive(ChannelHandlerContext ctx) {
  13 + System.out.println("Connection established: " + ctx.channel().remoteAddress());
  14 + }
  15 +
  16 + @Override
  17 + public void channelInactive(ChannelHandlerContext ctx) {
  18 + System.out.println("Connection closed: " + ctx.channel().remoteAddress());
  19 + }
  20 +
  21 + @Override
  22 + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
  23 + cause.printStackTrace();
  24 + ctx.close(); // 关闭有异常的连接
  25 + }
  26 +
  27 + @Override
  28 + protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception {
  29 + // 处理接收到的日志信息,这里直接输出到控制台
  30 + System.out.println("Received log: " + s);
  31 + }
  32 +}
  1 +package com.zhonglai.luhui.mqtt;
  2 +
  3 +import io.netty.channel.Channel;
  4 +import io.netty.channel.ChannelInitializer;
  5 +import io.netty.channel.socket.SocketChannel;
  6 +import io.netty.handler.codec.string.StringDecoder;
  7 +import io.netty.handler.codec.string.StringEncoder;
  8 +
  9 +public class LogServerInitializer extends ChannelInitializer<SocketChannel> {
  10 +
  11 + @Override
  12 + protected void initChannel(SocketChannel ch) {
  13 + ch.pipeline().addLast(new StringDecoder()); // 将字节解码为字符串
  14 + ch.pipeline().addLast(new StringEncoder()); // 将字符串编码为字节
  15 + ch.pipeline().addLast(new LogServerHandler()); // 自定义日志处理器
  16 + }
  17 +}
  1 +package com.zhonglai.luhui.mqtt;
  2 +
  3 +import io.netty.bootstrap.ServerBootstrap;
  4 +import io.netty.channel.ChannelFuture;
  5 +import io.netty.channel.ChannelOption;
  6 +import io.netty.channel.EventLoopGroup;
  7 +import io.netty.channel.nio.NioEventLoopGroup;
  8 +import io.netty.channel.socket.nio.NioServerSocketChannel;
  9 +import io.netty.handler.logging.LogLevel;
  10 +import io.netty.handler.logging.LoggingHandler;
  11 +import io.netty.handler.codec.string.StringDecoder;
  12 +import io.netty.handler.codec.string.StringEncoder;
  13 +public class TestMain {
  14 + private final int port;
  15 +
  16 + public TestMain(int port) {
  17 + this.port = port;
  18 + }
  19 +
  20 + public void start() throws InterruptedException {
  21 + EventLoopGroup bossGroup = new NioEventLoopGroup(1);
  22 + EventLoopGroup workerGroup = new NioEventLoopGroup();
  23 +
  24 + try {
  25 + ServerBootstrap bootstrap = new ServerBootstrap();
  26 + bootstrap.group(bossGroup, workerGroup)
  27 + .channel(NioServerSocketChannel.class)
  28 + .handler(new LoggingHandler(LogLevel.INFO))
  29 + .childHandler(new LogServerInitializer())
  30 + .childOption(ChannelOption.SO_KEEPALIVE, true);
  31 +
  32 + // 启动服务器
  33 + ChannelFuture future = bootstrap.bind(port).sync();
  34 + System.out.println("Log Server started on port: " + port);
  35 +
  36 + // 等待服务器关闭
  37 + future.channel().closeFuture().sync();
  38 + } finally {
  39 + // 关闭线程组
  40 + bossGroup.shutdownGracefully();
  41 + workerGroup.shutdownGracefully();
  42 + }
  43 + }
  44 + public static void main(String[] args) throws InterruptedException {
  45 + new TestMain(8080).start(); // 监听端口 5000
  46 + }
  47 +}
@@ -89,7 +89,7 @@ public class TerminalService { @@ -89,7 +89,7 @@ public class TerminalService {
89 89
90 public void subscribe() throws MqttException { 90 public void subscribe() throws MqttException {
91 List<String> ts = getCompletionTopics(); 91 List<String> ts = getCompletionTopics();
92 - mqttclient.subscribe(ts.toArray(new String[ts.size()])); 92 +// mqttclient.subscribe(ts.toArray(new String[ts.size()]));
93 } 93 }
94 94
95 public List<String> getCompletionTopics() 95 public List<String> getCompletionTopics()
@@ -41,7 +41,7 @@ spring: @@ -41,7 +41,7 @@ spring:
41 41
42 mqtt: 42 mqtt:
43 #链接地址 43 #链接地址
44 - broker: tcp://175.24.61.68:1883 44 + broker: tcp://iot.yu2le.com:1883
45 #唯一标识 45 #唯一标识
46 clientId: ${random.uuid} 46 clientId: ${random.uuid}
47 #公司id 47 #公司id
@@ -67,6 +67,6 @@ sys: @@ -67,6 +67,6 @@ sys:
67 #rocketmq配置信息 67 #rocketmq配置信息
68 rocketmq: 68 rocketmq:
69 #nameservice服务器地址(多个以英文逗号隔开) 69 #nameservice服务器地址(多个以英文逗号隔开)
70 - name-server: 47.115.144.179:9876 70 + name-server: 8.129.224.117:9876
71 send-topic: lh-mqtt-service-deviceCommand-test 71 send-topic: lh-mqtt-service-deviceCommand-test
72 send-tag: 1 72 send-tag: 1
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-modules</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-ssh-service-lesten</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <dependencies>
  21 + <dependency>
  22 + <groupId>com.jcraft</groupId>
  23 + <artifactId>jsch</artifactId>
  24 + </dependency>
  25 + <dependency>
  26 + <groupId>org.slf4j</groupId>
  27 + <artifactId>slf4j-api</artifactId>
  28 + </dependency>
  29 + <dependency>
  30 + <groupId>cn.hutool</groupId>
  31 + <artifactId>hutool-all</artifactId>
  32 + </dependency>
  33 + <dependency>
  34 + <groupId>redis.clients</groupId>
  35 + <artifactId>jedis</artifactId>
  36 + </dependency>
  37 + </dependencies>
  38 +</project>
  1 +package com.zhonglai.luhui.http.service.ssh;
  2 +
  3 +import com.zhonglai.luhui.http.service.ssh.service.SSHTailService;
  4 +
  5 +
  6 +public class SshServiceLestenMain {
  7 + public static void main(String[] args) {
  8 + SSHTailService sshTailService = new SSHTailService();
  9 + sshTailService.startListening();
  10 + }
  11 +}
  1 +package com.zhonglai.luhui.http.service.ssh.config;
  2 +
  3 +import java.util.concurrent.ExecutorService;
  4 +import java.util.concurrent.LinkedBlockingQueue;
  5 +import java.util.concurrent.ThreadPoolExecutor;
  6 +import java.util.concurrent.TimeUnit;
  7 +
  8 +import java.util.concurrent.Executors;
  9 +import java.util.concurrent.ScheduledExecutorService;
  10 +
  11 +public class ThreadPool {
  12 + //业务处理异步线程池,线程池参数可以根据您的业务特点调整,或者您也可以用其他异步方式处理接收到的消息。
  13 + private final static ExecutorService executorService = new ThreadPoolExecutor(
  14 + Runtime.getRuntime().availableProcessors(),
  15 + Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
  16 + new LinkedBlockingQueue<>(2000));
  17 +
  18 + //定时任务线程池
  19 + private final static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
  20 +
  21 + public static ExecutorService getExecutorService() {
  22 + return executorService;
  23 + }
  24 +
  25 + public static ScheduledExecutorService getScheduledExecutorService() {
  26 + return scheduledExecutorService;
  27 + }
  28 +}
  1 +package com.zhonglai.luhui.http.service.ssh.config;
  2 +
  3 +import com.zhonglai.luhui.http.service.ssh.service.JedisService;
  4 +
  5 +import java.util.HashMap;
  6 +import java.util.Map;
  7 +import java.util.concurrent.TimeUnit;
  8 +
  9 +/**
  10 + * topic订阅服务器配置
  11 + */
  12 +public class TopicSubscribeService {
  13 + private static Map<String,String> lisenServiceRegister = new HashMap<>();
  14 +
  15 + public static void init()
  16 + {
  17 + //一分钟更新一次,监听服务器的注册信息
  18 + ThreadPool.getScheduledExecutorService().scheduleAtFixedRate(new Runnable() {
  19 + @Override
  20 + public void run() {
  21 + Map<String,String> map = JedisService.getLogListenServiceRegister();
  22 + if(null != map && map.size() != 0)
  23 + {
  24 + for (String key : map.keySet())
  25 + {
  26 + lisenServiceRegister.put(key,map.get(key));
  27 + }
  28 + }
  29 + }
  30 + },0,60, TimeUnit.SECONDS);
  31 + }
  32 +
  33 + public static String getTopicSubscribeService(String username)
  34 + {
  35 + return lisenServiceRegister.get(username);
  36 + }
  37 +
  38 +}
  1 +package com.zhonglai.luhui.http.service.ssh.dto;
  2 +
  3 +public class LogMessageDto {
  4 + private String time;
  5 + private String username;
  6 + private String clientId;
  7 + private String topic;
  8 + private String message;
  9 +
  10 + public String getUsername() {
  11 + return username;
  12 + }
  13 +
  14 + public void setUsername(String username) {
  15 + this.username = username;
  16 + }
  17 +
  18 + public String getClientId() {
  19 + return clientId;
  20 + }
  21 +
  22 + public void setClientId(String clientId) {
  23 + this.clientId = clientId;
  24 + }
  25 +
  26 + public String getTime() {
  27 + return time;
  28 + }
  29 +
  30 + public void setTime(String time) {
  31 + this.time = time;
  32 + }
  33 +
  34 + public String getTopic() {
  35 + return topic;
  36 + }
  37 +
  38 + public void setTopic(String topic) {
  39 + this.topic = topic;
  40 + }
  41 +
  42 + public String getMessage() {
  43 + return message;
  44 + }
  45 +
  46 + public void setMessage(String message) {
  47 + this.message = message;
  48 + }
  49 +}
  1 +package com.zhonglai.luhui.http.service.ssh.service;
  2 +
  3 +import cn.hutool.db.nosql.redis.RedisDS;
  4 +
  5 +import java.util.Map;
  6 +
  7 +public class JedisService {
  8 + private static RedisDS jedis = RedisDS.create();
  9 +
  10 + public static Map<String,String> getLogListenServiceRegister()
  11 + {
  12 + return jedis.getJedis().hgetAll("log-listen-service-register");
  13 + }
  14 + public static void main(String[] args) {
  15 + jedis.getJedis().hset("log-listen-service-register", "6_WP","localhost:8443");
  16 + jedis.getJedis().hset("log-listen-service-register", "6_WP","localhost:84431");
  17 + System.out.println(jedis.getJedis().hget("log-listen-service-register","6_WP"));
  18 + }
  19 +}
  1 +package com.zhonglai.luhui.http.service.ssh.service;
  2 +
  3 +import cn.hutool.http.HttpUtil;
  4 +import cn.hutool.json.JSONUtil;
  5 +import com.jcraft.jsch.Channel;
  6 +import com.jcraft.jsch.JSch;
  7 +import com.jcraft.jsch.Session;
  8 +import com.zhonglai.luhui.http.service.ssh.config.ThreadPool;
  9 +import com.zhonglai.luhui.http.service.ssh.config.TopicSubscribeService;
  10 +import com.zhonglai.luhui.http.service.ssh.dto.LogMessageDto;
  11 +import org.slf4j.Logger;
  12 +import org.slf4j.LoggerFactory;
  13 +
  14 +import java.io.*;
  15 +import java.util.regex.Matcher;
  16 +import java.util.regex.Pattern;
  17 +
  18 +public class SSHTailService {
  19 + private static Logger log = LoggerFactory.getLogger(SSHTailService.class);
  20 +
  21 +
  22 + private static final Pattern LOG_PATTERN = Pattern.compile("【(.*?)】【(.*?)】【(.*?)】【(.*?)】(.*)");
  23 + private String host;
  24 + private String user;
  25 + private String password;
  26 + private String logFilePath;
  27 +
  28 + private Session session = null; // SSH 会话
  29 + private Channel channel = null; // SSH 通道
  30 +
  31 +
  32 + public void init() {
  33 + this.host = "175.24.61.68";
  34 + this.user = "root";
  35 + this.password = "Luhui586";
  36 + this.logFilePath = "/root/hivemq-ce-2021.2/log/mylogs/message.log";
  37 + }
  38 +
  39 + public BufferedReader open()
  40 + {
  41 + try {
  42 + // 建立 SSH 连接
  43 + JSch jsch = new JSch();
  44 + session = jsch.getSession(user, host, 22);
  45 + session.setPassword(password);
  46 + session.setConfig("StrictHostKeyChecking", "no");
  47 + session.setConfig("ServerAliveInterval", "60"); // 保持连接
  48 + session.connect();
  49 + System.out.println("SSH连接成功");
  50 +
  51 + // 打开 Shell 通道
  52 + channel = session.openChannel("shell");
  53 + InputStream in = channel.getInputStream();
  54 + OutputStream out = channel.getOutputStream();
  55 + channel.connect();
  56 +
  57 + // 发送 tail 命令
  58 + out.write(("tail -f " + logFilePath + "\n").getBytes());
  59 + out.flush();
  60 +
  61 + // 读取并解析日志行
  62 + return new BufferedReader(new InputStreamReader(in));
  63 +
  64 + } catch (Exception e) {
  65 + log.error("ssh服务启动失败",e);
  66 + }
  67 + return null;
  68 + }
  69 +
  70 + public void startListening() {
  71 + try {
  72 + init();
  73 + BufferedReader bufferedReader = open();
  74 + if(null != bufferedReader)
  75 + {
  76 + read(bufferedReader);
  77 + }
  78 + }catch (Exception e)
  79 + {
  80 + log.error("执行错误",e);
  81 + }finally {
  82 + close();
  83 + startListening();
  84 + }
  85 +
  86 + }
  87 +
  88 + public void read(BufferedReader bufferedReader)
  89 + {
  90 + try {
  91 + String line;
  92 + while ((line = bufferedReader.readLine()) != null) {
  93 + System.out.println("读取到一行: " + line);
  94 + LogMessageDto logMessageDto = parseLogLine(line);
  95 + if(null !=logMessageDto && null != logMessageDto.getMessage() && !"".equals(logMessageDto.getMessage()))
  96 + {
  97 + String host = TopicSubscribeService.getTopicSubscribeService(logMessageDto.getUsername());
  98 + if(null != host && host.length()!=0)
  99 + {
  100 + ThreadPool.getExecutorService().execute(() -> {
  101 + HttpUtil.post("http://"+host+"/logpost", JSONUtil.toJsonStr(logMessageDto));
  102 + });
  103 + }
  104 + }
  105 + }
  106 + }catch (Exception e)
  107 + {
  108 + log.error("读取日志信息异常",e);
  109 + }finally {
  110 + close();
  111 + }
  112 +
  113 + }
  114 +
  115 + public void close()
  116 + {
  117 + // 关闭资源
  118 + if (channel != null && channel.isConnected()) {
  119 + channel.disconnect();
  120 + }
  121 + if (session != null && session.isConnected()) {
  122 + session.disconnect();
  123 + }
  124 + }
  125 + private LogMessageDto parseLogLine(String line) {
  126 + // 根据日志格式解析内容
  127 + Matcher matcher = LOG_PATTERN.matcher(line);
  128 + if (matcher.matches()) {
  129 + LogMessageDto logMessageDto = new LogMessageDto();
  130 + logMessageDto.setTime(matcher.group(1));
  131 + logMessageDto.setUsername(matcher.group(2));
  132 + logMessageDto.setClientId(matcher.group(3));
  133 + logMessageDto.setTopic(matcher.group(4));
  134 + logMessageDto.setMessage(matcher.group(5));
  135 + if(null != logMessageDto.getMessage() )
  136 + {
  137 + logMessageDto.setMessage(logMessageDto.getMessage().replace("|||","\n"));
  138 + }
  139 + return logMessageDto;
  140 + } else {
  141 + log.error("日志行格式不正确: " + line);
  142 + }
  143 + return null;
  144 + }
  145 +
  146 +}
  1 +#-------------------------------------------------------------------------------
  2 +# Redis客户端配置样例
  3 +# 每一个分组代表一个Redis实例
  4 +# 无分组的Pool配置为所有分组的共用配置,如果分组自己定义Pool配置,则覆盖共用配置
  5 +# 池配置来自于:https://www.cnblogs.com/jklk/p/7095067.html
  6 +#-------------------------------------------------------------------------------
  7 +
  8 +#----- 默认(公有)配置
  9 +# 地址,默认localhost
  10 +host = 47.112.163.61
  11 +# 端口,默认6379
  12 +port = 9527
  13 +# 超时,默认2000
  14 +timeout = 2000
  15 +# 连接超时,默认timeout
  16 +connectionTimeout = 2000
  17 +# 读取超时,默认timeout
  18 +soTimeout = 2000
  19 +# 密码,默认无
  20 +password = Luhui586
  21 +# 数据库序号,默认0
  22 +database = 0
  23 +# 客户端名,默认"Hutool"
  24 +clientName = Hutool
  25 +# SSL连接,默认false
  26 +ssl = false;
  27 +
  28 +#----- 自定义分组的连接
  29 +[custom]
  30 +# 地址,默认localhost
  31 +host = 47.112.163.61
  32 +# 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
  33 +BlockWhenExhausted = true;
  34 +# 设置的逐出策略类名, 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
  35 +evictionPolicyClassName = org.apache.commons.pool2.impl.DefaultEvictionPolicy
  36 +# 是否启用pool的jmx管理功能, 默认true
  37 +jmxEnabled = true;
  38 +# 是否启用后进先出, 默认true
  39 +lifo = true;
  40 +# 最大空闲连接数, 默认8个
  41 +maxIdle = 8
  42 +# 最小空闲连接数, 默认0
  43 +minIdle = 0
  44 +# 最大连接数, 默认8个
  45 +maxTotal = 8
  46 +# 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常, 小于零:阻塞不确定的时间, 默认-1
  47 +maxWaitMillis = -1
  48 +# 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
  49 +minEvictableIdleTimeMillis = 1800000
  50 +# 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
  51 +numTestsPerEvictionRun = 3;
  52 +# 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
  53 +SoftMinEvictableIdleTimeMillis = 1800000
  54 +# 在获取连接的时候检查有效性, 默认false
  55 +testOnBorrow = false
  56 +# 在空闲时检查有效性, 默认false
  57 +testWhileIdle = false
  58 +# 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
  59 +timeBetweenEvictionRunsMillis = -1
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-superweb-jar</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-web-douyin</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 + <dependencies>
  20 + <!-- 通用工具-->
  21 + <dependency>
  22 + <groupId>com.zhonglai.luhui</groupId>
  23 + <artifactId>lh-domain</artifactId>
  24 + </dependency>
  25 +
  26 + <dependency>
  27 + <groupId>com.zhonglai.luhui</groupId>
  28 + <artifactId>lh-public-dao</artifactId>
  29 + </dependency>
  30 + <dependency>
  31 + <groupId>com.zhonglai.luhui</groupId>
  32 + <artifactId>lh-common-datasource</artifactId>
  33 + </dependency>
  34 + <dependency>
  35 + <groupId>com.zhonglai.luhui</groupId>
  36 + <artifactId>lh-jar-action</artifactId>
  37 + </dependency>
  38 +
  39 + <!-- 文档 -->
  40 + <dependency>
  41 + <groupId>com.zhonglai.luhui</groupId>
  42 + <artifactId>lh-common-swagger</artifactId>
  43 + </dependency>
  44 +
  45 + </dependencies>
  46 +</project>
  1 +package com.zhonglai.luhui.web.douyin.config;
  2 +
  3 +import com.ruoyi.common.config.RuoYiConfig;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +import springfox.documentation.builders.ApiInfoBuilder;
  8 +import springfox.documentation.builders.PathSelectors;
  9 +import springfox.documentation.builders.RequestHandlerSelectors;
  10 +import springfox.documentation.service.ApiInfo;
  11 +import springfox.documentation.service.Contact;
  12 +import springfox.documentation.spi.DocumentationType;
  13 +import springfox.documentation.spring.web.plugins.Docket;
  14 +import springfox.documentation.swagger2.annotations.EnableSwagger2;
  15 +
  16 +
  17 +@Configuration
  18 +@EnableSwagger2
  19 +public class DouyinSwaggerConfig {
  20 + /** 系统基础配置 */
  21 + @Autowired
  22 + private RuoYiConfig ruoyiConfig;
  23 + @Bean
  24 + public Docket createDouyinRestApi() {
  25 + return new Docket(DocumentationType.SWAGGER_2)
  26 + .groupName("抖音")
  27 + .apiInfo(apiInfo())
  28 + .select()
  29 + .apis(RequestHandlerSelectors.basePackage("com.zhonglai.luhui.web.douyin.controller"))
  30 + .paths(PathSelectors.any())
  31 + .build();
  32 + }
  33 +
  34 + /**
  35 + * 添加摘要信息
  36 + */
  37 + private ApiInfo apiInfo()
  38 + {
  39 + // 用ApiInfoBuilder进行定制
  40 + return new ApiInfoBuilder()
  41 + // 设置标题
  42 + .title("标题:抖音业务")
  43 + // 描述
  44 + .description("描述:抖音相关业务")
  45 + // 作者信息
  46 + .contact(new Contact(ruoyiConfig.getName(), null, null))
  47 + // 版本
  48 + .version("版本号:" + ruoyiConfig.getVersion())
  49 + .build();
  50 + }
  51 +
  52 +}
  1 +package com.zhonglai.luhui.web.douyin.config;
  2 +
  3 +public class DouyingConfig {
  4 + public static String client_key = "aw1lv7cqpap1nm2x";
  5 + public static String client_secret = "c006743430919ad918c0951acece4fa4";
  6 +}
  1 +package com.zhonglai.luhui.web.douyin.controller;
  2 +
  3 +import cn.hutool.http.HttpUtil;
  4 +import com.ruoyi.common.core.domain.Message;
  5 +import com.ruoyi.common.utils.DateUtils;
  6 +import com.ruoyi.common.utils.GsonConstructor;
  7 +import com.zhonglai.luhui.action.BaseController;
  8 +import com.zhonglai.luhui.dao.service.PublicService;
  9 +import com.zhonglai.luhui.web.douyin.config.DouyingConfig;
  10 +import com.zhonglai.luhui.web.douyin.util.dto.DyAccessTokenResponsData;
  11 +import com.zhonglai.luhui.web.douyin.util.DouyinFunctionUtil;
  12 +import com.zhonglai.luhui.web.douyin.util.dto.DyRespons;
  13 +import com.zhonglai.luhui.web.douyin.util.dto.DyUserinfoResponsData;
  14 +import io.swagger.annotations.Api;
  15 +import io.swagger.annotations.ApiOperation;
  16 +import org.springframework.beans.factory.annotation.Autowired;
  17 +import org.springframework.stereotype.Controller;
  18 +import org.springframework.transaction.annotation.Transactional;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import javax.servlet.http.HttpServletRequest;
  22 +import javax.servlet.http.HttpServletResponse;
  23 +import java.io.IOException;
  24 +import java.io.PrintWriter;
  25 +import java.net.URLDecoder;
  26 +import java.util.HashMap;
  27 +import java.util.Map;
  28 +
  29 +@Api(tags = "抖音用户业务")
  30 +@Controller
  31 +@RequestMapping("/douyin/douyinUser")
  32 +public class DouyinUserController extends BaseController {
  33 + @Autowired
  34 + private PublicService publicService;
  35 + @ApiOperation("授权")
  36 + @GetMapping(value = "/oauthUrl")
  37 + public void oauthUrl(String okRetunUrl, HttpServletRequest httpServletRequest, HttpServletResponse respons) throws IOException {
  38 + String scopes = "user_info";
  39 +// String scopes = "user_info,open.account.data,im.direct_message,item.comment";
  40 + String redirect_uri = "https://"+httpServletRequest.getServerName()+httpServletRequest.getContextPath()+"/douyin/douyinUser/callback";
  41 + String url = DouyinFunctionUtil.oauthUrl(scopes,okRetunUrl,redirect_uri);
  42 + logger.info("抖音授权链接【{}】",url);
  43 + // 重定向到生成的URL
  44 + respons.sendRedirect(url);
  45 + }
  46 +
  47 + @ApiOperation("获取用户信息")
  48 + @Transactional
  49 + @RequestMapping(value = "/callback")
  50 + public void callback(String code,String state,HttpServletResponse respons) throws IOException {
  51 + String okRetunUrl = state;
  52 + DyRespons<DyAccessTokenResponsData> dyRespons = DouyinFunctionUtil.accessToken(code);
  53 + switch (dyRespons.getMessage())
  54 + {
  55 + case "success":
  56 + DyAccessTokenResponsData oauthAccessTokenOkData = dyRespons.getData();
  57 + Long lg = publicService.selectCountBySql("select count(*) ct from `liu_yu_le`.`dy_oauth_access_token` where open_id='"+oauthAccessTokenOkData.getOpen_id()+"'");
  58 + if(lg>0)
  59 + {
  60 + publicService.updateBySql("UPDATE `liu_yu_le`.`dy_oauth_access_token` SET access_token='"+oauthAccessTokenOkData.getAccess_token()+"',expires_in="+(oauthAccessTokenOkData.getExpires_in()+DateUtils.getNowTimeMilly())+",refresh_token='"+oauthAccessTokenOkData.getRefresh_token()+"',refresh_expires_in="+(oauthAccessTokenOkData.getRefresh_expires_in()+DateUtils.getNowTimeMilly())+",scope='"+oauthAccessTokenOkData.getScope()+"' WHERE open_id='"+oauthAccessTokenOkData.getOpen_id()+"'");
  61 + }else{
  62 + publicService.updateBySql("INSERT INTO `liu_yu_le`.`dy_oauth_access_token`(`open_id`,`access_token`,`expires_in`,`refresh_token`,`refresh_expires_in`,`scope`,`create_time`) VALUES('"+oauthAccessTokenOkData.getOpen_id()+"','"+oauthAccessTokenOkData.getAccess_token()+"',"+(oauthAccessTokenOkData.getExpires_in()+DateUtils.getNowTimeMilly())+",'"+oauthAccessTokenOkData.getRefresh_token()+"',"+(oauthAccessTokenOkData.getRefresh_expires_in()+DateUtils.getNowTimeMilly())+",'"+oauthAccessTokenOkData.getScope()+"',"+ DateUtils.getNowTimeMilly() +")");
  63 + }
  64 + lg = publicService.selectCountBySql("select count(*) ct from `liu_yu_le`.`dy_userinfo` where open_id='"+oauthAccessTokenOkData.getOpen_id()+"'");
  65 + DyRespons<DyUserinfoResponsData> dyUserinfoResponsDataDyRespons = DouyinFunctionUtil.userinfo(oauthAccessTokenOkData.getAccess_token(),oauthAccessTokenOkData.getOpen_id());
  66 + DyUserinfoResponsData dyUserinfoResponsData = dyUserinfoResponsDataDyRespons.getData();
  67 + if(lg>0)
  68 + {
  69 + publicService.updateBySql("UPDATE `liu_yu_le`.`dy_userinfo` SET union_id='"+dyUserinfoResponsData.getUnion_id()+"',nickname='"+dyUserinfoResponsData.getNickname()+"',avatar='"+dyUserinfoResponsData.getAvatar()+"' WHERE open_id='"+dyUserinfoResponsData.getOpen_id()+"'");
  70 + }else{
  71 + publicService.updateBySql("INSERT INTO `liu_yu_le`.`dy_userinfo`(`open_id`,`union_id`,`nickname`,`avatar`,`create_time`) VALUES('"+dyUserinfoResponsData.getOpen_id()+"','"+dyUserinfoResponsData.getUnion_id()+"','"+dyUserinfoResponsData.getNickname()+"','"+dyUserinfoResponsData.getAvatar()+"',"+ DateUtils.getNowTimeMilly() +")");
  72 + }
  73 + okRetunUrl = URLDecoder.decode(okRetunUrl, "UTF-8");
  74 + // 重定向到生成的URL
  75 + String reUrl = okRetunUrl+"?open_id="+oauthAccessTokenOkData.getOpen_id();
  76 + logger.info("获取用户成功重定向到指定页面:{}",reUrl);
  77 + respons.sendRedirect(reUrl);
  78 + break;
  79 + default:
  80 + // 构建错误信息的HTML
  81 + String errorMessageHtml = "<html><body><h1>错误信息</h1><p>" + GsonConstructor.get().toJson(dyRespons) + "</p></body></html>";
  82 +
  83 + // 设置响应的内容类型和字符编码
  84 + respons.setContentType("text/html; charset=UTF-8");
  85 +
  86 + // 输出HTML内容
  87 + try (PrintWriter out = respons.getWriter()) {
  88 + out.print(errorMessageHtml);
  89 + }
  90 + break;
  91 + }
  92 +
  93 + }
  94 +}
  1 +package com.zhonglai.luhui.web.douyin.controller;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +import com.ruoyi.common.utils.GsonConstructor;
  5 +import com.zhonglai.luhui.action.BaseController;
  6 +import com.zhonglai.luhui.web.douyin.config.DouyingConfig;
  7 +import com.zhonglai.luhui.web.douyin.dto.DouyinCommentReply;
  8 +import io.swagger.annotations.Api;
  9 +import io.swagger.annotations.ApiOperation;
  10 +import org.springframework.util.StreamUtils;
  11 +import org.springframework.web.bind.annotation.PostMapping;
  12 +import org.springframework.web.bind.annotation.RequestMapping;
  13 +import org.springframework.web.bind.annotation.ResponseBody;
  14 +import org.springframework.web.bind.annotation.RestController;
  15 +
  16 +import javax.servlet.http.HttpServletRequest;
  17 +import java.io.IOException;
  18 +import java.security.MessageDigest;
  19 +import java.security.NoSuchAlgorithmException;
  20 +import java.util.Objects;
  21 +
  22 +@Api(tags = "webhooks")
  23 +@RestController
  24 +@RequestMapping("/douyin/webhooks")
  25 +public class WebhooksController extends BaseController {
  26 + @ApiOperation("webhooks")
  27 + @PostMapping(value = "")
  28 + @ResponseBody
  29 + public String webhooks(HttpServletRequest httpServletRequest)
  30 + {
  31 + try {
  32 + String sReqData = new String(StreamUtils.copyToByteArray(httpServletRequest.getInputStream()));
  33 + String signature = httpServletRequest.getHeader("X-Douyin-Signature");
  34 + if(validateSignature(signature,sReqData))
  35 + {
  36 + JsonObject jsonObject = GsonConstructor.get().fromJson(sReqData, JsonObject.class);
  37 + if(jsonObject.has("event"))
  38 + {
  39 + switch (jsonObject.get("event").getAsString())
  40 + {
  41 + case "verify_webhook":
  42 + JsonObject challenge = jsonObject.get("content").getAsJsonObject();
  43 + return challenge.toString();
  44 + case "item_comment_reply":
  45 + DouyinCommentReply douyinCommentReply = GsonConstructor.get().fromJson(sReqData, DouyinCommentReply.class);
  46 +
  47 + return "";
  48 +
  49 + default:
  50 + logger.info("无法识别的操作:{}",jsonObject);
  51 + return "";
  52 + }
  53 + }
  54 + }
  55 +
  56 + } catch (IOException e) {
  57 + throw new RuntimeException(e);
  58 + }
  59 + return "";
  60 + }
  61 +
  62 +
  63 + public boolean validateSignature(String signature,String sReqData) {
  64 + if (signature == null || signature.isEmpty()) {
  65 + return false;
  66 + }
  67 +
  68 + try {
  69 + String calculatedSignature = calculateSignature(DouyingConfig.client_secret, sReqData);
  70 + return Objects.equals(signature, calculatedSignature);
  71 + } catch (Exception e) {
  72 + return false;
  73 + }
  74 + }
  75 +
  76 + private String calculateSignature(String clientSecret, String body) throws NoSuchAlgorithmException {
  77 + MessageDigest digest = MessageDigest.getInstance("SHA-1");
  78 + byte[] hash = digest.digest((clientSecret + body).getBytes());
  79 + StringBuilder hexString = new StringBuilder();
  80 + for (byte b : hash) {
  81 + String hex = Integer.toHexString(0xff & b);
  82 + if (hex.length() == 1) hexString.append('0');
  83 + hexString.append(hex);
  84 + }
  85 + return hexString.toString();
  86 + }
  87 +}
  1 +package com.zhonglai.luhui.web.douyin.dto;
  2 +
  3 +/**
  4 + * 评论消息内容
  5 + * "comment_id":"", //评论id
  6 + * "comment_user_id", //发评论的用户openid
  7 + * "content":, //评论内容
  8 + * "create_time":123123, //评论创建时间(秒级时间戳)
  9 + * "digg_count":0, //该评论的点赞量
  10 + * "reply_comment_total":1, //该评论下的回复评论量
  11 + * "reply_to_comment_id":"", //该评论回复的上一级评论的评论id
  12 + * "reply_to_item_id":"@9VxT0uuFWsE7M3Koc4olFM791WbsNPGKOp1wrgiiJ1ERbfD060zdRmYqig357zEB1tSgbExoci7R0e1yFxAIMw==",//该评论回复的视频id
  13 + * "at_user_id": "", //评论@的用户uid
  14 + * "avatar": "https://uuue/ehdne", //评论发送方的头像
  15 + * "nick_name": "xiaoming" //评论发送方的昵称
  16 + * "parent_id":"" //二级评论和三级评论的parentId是所属的一级评论id,一级评论parentId为视频ID
  17 + */
  18 +public class DouyinCommentContent {
  19 + /** 评论id */
  20 + private String comment_id;
  21 + /** 发评论的用户openid */
  22 + private String comment_user_id;
  23 + /** 评论内容 */
  24 + private String content;
  25 + /** 评论创建时间(秒级时间戳) */
  26 + private Long create_time;
  27 + /** 该评论的点赞量 */
  28 + private Integer digg_count;
  29 + /** 该评论下的回复评论量 */
  30 + private Integer reply_comment_total;
  31 + /** 该评论回复的上一级评论的评论id */
  32 + private String reply_to_comment_id;
  33 + /** 该评论回复的视频id */
  34 + private String reply_to_item_id;
  35 + /** 评论@的用户uid */
  36 + private String at_user_id;
  37 + /** 评论发送方的头像 */
  38 + private String avatar;
  39 + /** 评论发送方的昵称 */
  40 + private String nick_name;
  41 + /** 所属的一级评论id */
  42 + private String parent_id;
  43 +
  44 + public String getComment_id() {
  45 + return comment_id;
  46 + }
  47 +
  48 + public void setComment_id(String comment_id) {
  49 + this.comment_id = comment_id;
  50 + }
  51 +
  52 + public String getComment_user_id() {
  53 + return comment_user_id;
  54 + }
  55 +
  56 + public void setComment_user_id(String comment_user_id) {
  57 + this.comment_user_id = comment_user_id;
  58 + }
  59 +
  60 + public String getContent() {
  61 + return content;
  62 + }
  63 +
  64 + public void setContent(String content) {
  65 + this.content = content;
  66 + }
  67 +
  68 + public Long getCreate_time() {
  69 + return create_time;
  70 + }
  71 +
  72 + public void setCreate_time(Long create_time) {
  73 + this.create_time = create_time;
  74 + }
  75 +
  76 + public Integer getDigg_count() {
  77 + return digg_count;
  78 + }
  79 +
  80 + public void setDigg_count(Integer digg_count) {
  81 + this.digg_count = digg_count;
  82 + }
  83 +
  84 + public Integer getReply_comment_total() {
  85 + return reply_comment_total;
  86 + }
  87 +
  88 + public void setReply_comment_total(Integer reply_comment_total) {
  89 + this.reply_comment_total = reply_comment_total;
  90 + }
  91 +
  92 + public String getReply_to_comment_id() {
  93 + return reply_to_comment_id;
  94 + }
  95 +
  96 + public void setReply_to_comment_id(String reply_to_comment_id) {
  97 + this.reply_to_comment_id = reply_to_comment_id;
  98 + }
  99 +
  100 + public String getReply_to_item_id() {
  101 + return reply_to_item_id;
  102 + }
  103 +
  104 + public void setReply_to_item_id(String reply_to_item_id) {
  105 + this.reply_to_item_id = reply_to_item_id;
  106 + }
  107 +
  108 + public String getAt_user_id() {
  109 + return at_user_id;
  110 + }
  111 +
  112 + public void setAt_user_id(String at_user_id) {
  113 + this.at_user_id = at_user_id;
  114 + }
  115 +
  116 + public String getAvatar() {
  117 + return avatar;
  118 + }
  119 +
  120 + public void setAvatar(String avatar) {
  121 + this.avatar = avatar;
  122 + }
  123 +
  124 + public String getNick_name() {
  125 + return nick_name;
  126 + }
  127 +
  128 + public void setNick_name(String nick_name) {
  129 + this.nick_name = nick_name;
  130 + }
  131 +
  132 + public String getParent_id() {
  133 + return parent_id;
  134 + }
  135 +
  136 + public void setParent_id(String parent_id) {
  137 + this.parent_id = parent_id;
  138 + }
  139 +}
  1 +package com.zhonglai.luhui.web.douyin.dto;
  2 +
  3 +/**
  4 + * 评论消息
  5 + * "event": "item_comment_reply",
  6 + * "from_user_id": "", //发送评论的用户openid
  7 + * "to_user_id": "", //创建视频的用户openId
  8 + * "client_key": "", //创建视频用户授权的应用id
  9 + * "content": {} //评论内容
  10 + */
  11 +public class DouyinCommentReply {
  12 + /** 发送评论的用户openid */
  13 + private String from_user_id;
  14 + /** 创建视频的用户openId */
  15 + private String to_user_id;
  16 + /** 创建视频用户授权的应用id */
  17 + private String client_key;
  18 + /** 评论内容 */
  19 + private DouyinCommentContent content;
  20 +
  21 + public String getFrom_user_id() {
  22 + return from_user_id;
  23 + }
  24 +
  25 + public void setFrom_user_id(String from_user_id) {
  26 + this.from_user_id = from_user_id;
  27 + }
  28 +
  29 + public String getTo_user_id() {
  30 + return to_user_id;
  31 + }
  32 +
  33 + public void setTo_user_id(String to_user_id) {
  34 + this.to_user_id = to_user_id;
  35 + }
  36 +
  37 + public String getClient_key() {
  38 + return client_key;
  39 + }
  40 +
  41 + public void setClient_key(String client_key) {
  42 + this.client_key = client_key;
  43 + }
  44 +
  45 + public DouyinCommentContent getContent() {
  46 + return content;
  47 + }
  48 +
  49 + public void setContent(DouyinCommentContent content) {
  50 + this.content = content;
  51 + }
  52 +}
  1 +package com.zhonglai.luhui.web.douyin.util;
  2 +
  3 +import cn.hutool.http.HttpUtil;
  4 +import com.google.gson.reflect.TypeToken;
  5 +import com.ruoyi.common.utils.DateUtils;
  6 +import com.ruoyi.common.utils.GsonConstructor;
  7 +import com.zhonglai.luhui.web.douyin.config.DouyingConfig;
  8 +import com.zhonglai.luhui.web.douyin.util.dto.DyAccessTokenResponsData;
  9 +import com.zhonglai.luhui.web.douyin.util.dto.DyRespons;
  10 +import com.zhonglai.luhui.web.douyin.util.dto.DyUserinfoResponsData;
  11 +
  12 +import java.io.UnsupportedEncodingException;
  13 +import java.lang.reflect.Type;
  14 +import java.net.URLEncoder;
  15 +import java.util.HashMap;
  16 +import java.util.Map;
  17 +
  18 +public class DouyinFunctionUtil {
  19 + /**
  20 + * 抖音获取授权码
  21 + * @param scopes
  22 + * @param okRetunUrl
  23 + * @param redirect_uri
  24 + * @return
  25 + */
  26 + public static String oauthUrl(String scopes,String okRetunUrl,String redirect_uri)
  27 + {
  28 + StringBuffer url = new StringBuffer("https://open.douyin.com/platform/oauth/connect?");
  29 + url.append("client_key=").append(DouyingConfig.client_key);
  30 + url.append("&response_type=code");
  31 + url.append("&scope=");
  32 + url.append(scopes);
  33 + String encodedOkReturnUrl = null;
  34 + try {
  35 + encodedOkReturnUrl = URLEncoder.encode(okRetunUrl, "UTF-8");
  36 + } catch (UnsupportedEncodingException e) {
  37 + throw new RuntimeException(e);
  38 + }
  39 + url.append("&redirect_uri=").append(redirect_uri);
  40 + url.append("&state="+encodedOkReturnUrl);
  41 + return url.toString();
  42 + }
  43 +
  44 + /**
  45 + * 获取 access_token
  46 + * @param code
  47 + * @return
  48 + */
  49 + public static DyRespons<DyAccessTokenResponsData> accessToken(String code)
  50 + {
  51 + String url = "https://open.douyin.com/oauth/access_token/";
  52 + Map<String,Object> map = new HashMap<>();
  53 + map.put("client_key",DouyingConfig.client_key);
  54 + map.put("client_secret",DouyingConfig.client_secret);
  55 + map.put("code",code);
  56 + map.put("grant_type","authorization_code");
  57 + String result = HttpUtil.post(url,map);
  58 + return DyRespons.newDyRspons(result,DyAccessTokenResponsData.class);
  59 + }
  60 +
  61 + /**
  62 + * 获取用户公开信息
  63 + * @return
  64 + */
  65 + public static DyRespons<DyUserinfoResponsData> userinfo(String access_token, String open_id)
  66 + {
  67 + String url = "https://open.douyin.com/oauth/userinfo/";
  68 + Map<String,Object> map = new HashMap<>();
  69 + map.put("access_token",access_token);
  70 + map.put("open_id",open_id);
  71 + String result = HttpUtil.post(url,map);
  72 + return DyRespons.newDyRspons(result,DyUserinfoResponsData.class);
  73 + }
  74 +
  75 + /**
  76 + * 刷新tokoen
  77 + * @return
  78 + */
  79 + public static DyRespons<DyAccessTokenResponsData> refreshToken(String access_token, String open_id)
  80 + {
  81 + String url = "https://open.douyin.com/oauth/renew_refresh_token/";
  82 + Map<String,Object> map = new HashMap<>();
  83 + map.put("access_token",access_token);
  84 + map.put("refresh_token",open_id);
  85 + String result = HttpUtil.post(url,map);
  86 + return DyRespons.newDyRspons(result,DyAccessTokenResponsData.class);
  87 + }
  88 +}
  1 +package com.zhonglai.luhui.web.douyin.util.dto;
  2 +
  3 +/**
  4 + * 授权成功数据对象
  5 + * "access_token": "act.f7094fbffab2ecbfc45e9af9c32bc241oYdckvBKe82BPx8T******",
  6 + * "captcha": "",
  7 + * "desc_url": "",
  8 + * "description": "",
  9 + * "error_code": 0,
  10 + * "expires_in": 1296000,
  11 + * "log_id": "20230525105733ED3ED7AC56A******",
  12 + * "open_id": "b9b71865-7fea-44cc-******",
  13 + * "refresh_expires_in": 2592000,
  14 + * "refresh_token": "rft.713900b74edde9f30ec4e246b706da30t******",
  15 + * "scope": "user_info"
  16 + */
  17 +public class DyAccessTokenResponsData extends DyResponsBaseData {
  18 + private String access_token; //接口调用凭证
  19 + private Integer expires_in; //access_token接口调用凭证超时时间,单位(秒)
  20 + private String log_id; //请求唯一标识
  21 + private String open_id; //授权用户唯一标识
  22 + private Integer refresh_expires_in; //refresh_token凭证超时时间,单位(秒)
  23 + private String refresh_token; //用户刷新access_token
  24 + private String scope; //用户授权的作用域(Scope),使用逗号(,)分隔,开放平台几乎每个接口都需要特定的Scope。
  25 +
  26 + public void setAccess_token(String access_token) {
  27 + this.access_token = access_token;
  28 + }
  29 +
  30 + public String getAccess_token() {
  31 + return access_token;
  32 + }
  33 +
  34 + public Integer getExpires_in() {
  35 + return expires_in;
  36 + }
  37 +
  38 + public void setExpires_in(Integer expires_in) {
  39 + this.expires_in = expires_in;
  40 + }
  41 +
  42 + public String getLog_id() {
  43 + return log_id;
  44 + }
  45 +
  46 + public void setLog_id(String log_id) {
  47 + this.log_id = log_id;
  48 + }
  49 +
  50 + public String getOpen_id() {
  51 + return open_id;
  52 + }
  53 +
  54 + public void setOpen_id(String open_id) {
  55 + this.open_id = open_id;
  56 + }
  57 +
  58 + public Integer getRefresh_expires_in() {
  59 + return refresh_expires_in;
  60 + }
  61 +
  62 + public void setRefresh_expires_in(Integer refresh_expires_in) {
  63 + this.refresh_expires_in = refresh_expires_in;
  64 + }
  65 +
  66 + public String getRefresh_token() {
  67 + return refresh_token;
  68 + }
  69 +
  70 + public void setRefresh_token(String refresh_token) {
  71 + this.refresh_token = refresh_token;
  72 + }
  73 +
  74 + public String getScope() {
  75 + return scope;
  76 + }
  77 +
  78 + public void setScope(String scope) {
  79 + this.scope = scope;
  80 + }
  81 +}
  1 +package com.zhonglai.luhui.web.douyin.util.dto;
  2 +
  3 +import com.google.gson.Gson;
  4 +import com.google.gson.JsonObject;
  5 +import com.google.gson.JsonParser;
  6 +import com.google.gson.reflect.TypeToken;
  7 +import com.ruoyi.common.utils.GsonConstructor;
  8 +
  9 +import java.lang.reflect.Type;
  10 +
  11 +public class DyRespons<T> {
  12 + private String message;
  13 + private T data;
  14 +
  15 + public String getMessage() {
  16 + return message;
  17 + }
  18 +
  19 + public void setMessage(String message) {
  20 + this.message = message;
  21 + }
  22 +
  23 + public T getData() {
  24 + return data;
  25 + }
  26 +
  27 + public void setData(T data) {
  28 + this.data = data;
  29 + }
  30 +
  31 + public static <T> DyRespons<T> newDyRspons(String jsonString, Class<T> dataClass) {
  32 +
  33 + // 先解析message
  34 + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject();
  35 + String message = jsonObject.get("message").getAsString();
  36 +
  37 + // 解析data字段
  38 + T dataObject = GsonConstructor.get().fromJson(jsonObject.get("data"), dataClass);
  39 +
  40 + // 构建DyRespons对象
  41 + DyRespons<T> response = new DyRespons<>();
  42 + response.setMessage(message);
  43 + response.setData(dataObject);
  44 +
  45 + return response;
  46 + }
  47 +}
  1 +package com.zhonglai.luhui.web.douyin.util.dto;
  2 +
  3 +public class DyResponsBaseData {
  4 + private String error_code; //错误码
  5 + private String description; //描述
  6 + private String desc_url; //描述地址
  7 + private String captcha; //验证码
  8 +
  9 + public String getError_code() {
  10 + return error_code;
  11 + }
  12 +
  13 + public void setError_code(String error_code) {
  14 + this.error_code = error_code;
  15 + }
  16 +
  17 + public String getDescription() {
  18 + return description;
  19 + }
  20 +
  21 + public void setDescription(String description) {
  22 + this.description = description;
  23 + }
  24 +
  25 + public String getDesc_url() {
  26 + return desc_url;
  27 + }
  28 +
  29 + public void setDesc_url(String desc_url) {
  30 + this.desc_url = desc_url;
  31 + }
  32 +
  33 + public String getCaptcha() {
  34 + return captcha;
  35 + }
  36 +
  37 + public void setCaptcha(String captcha) {
  38 + this.captcha = captcha;
  39 + }
  40 +}
  1 +package com.zhonglai.luhui.web.douyin.util.dto;
  2 +
  3 +/**
  4 + * 用户公开信息接口返回数据
  5 + * avatar String 否 https://example.com/x.jpeg
  6 + * description String 否
  7 + * 错误码描述
  8 + *
  9 + * error_code Int64 否 0
  10 + * 错误码
  11 + *
  12 + * nickname String 否 张伟
  13 + * open_id String 否 0da22181-d833-447f-995f-1beefe******
  14 + * 用户在当前应用的唯一标识
  15 + *
  16 + * union_id String 否 1ad4e099-4a0c-47d1-a410-bffb4f******
  17 + * 用户在当前开发者账号下的唯一标识(未绑定开发者账号没有该字段),即同一企业主体下的入接入多个应用,unionid可用于识别同一个抖音用户
  18 + */
  19 +public class DyUserinfoResponsData extends DyResponsBaseData{
  20 + private String avatar;
  21 + private String nickname;
  22 + private String open_id;
  23 + private String union_id;
  24 +
  25 + public String getAvatar() {
  26 + return avatar;
  27 + }
  28 +
  29 + public void setAvatar(String avatar) {
  30 + this.avatar = avatar;
  31 + }
  32 +
  33 + public String getNickname() {
  34 + return nickname;
  35 + }
  36 +
  37 + public void setNickname(String nickname) {
  38 + this.nickname = nickname;
  39 + }
  40 +
  41 + public String getOpen_id() {
  42 + return open_id;
  43 + }
  44 +
  45 + public void setOpen_id(String open_id) {
  46 + this.open_id = open_id;
  47 + }
  48 +
  49 + public String getUnion_id() {
  50 + return union_id;
  51 + }
  52 +
  53 + public void setUnion_id(String union_id) {
  54 + this.union_id = union_id;
  55 + }
  56 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-modules</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-superweb-jar</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <packaging>pom</packaging>
  21 +
  22 + <modules>
  23 + <module>lh-web-douyin</module>
  24 + </modules>
  25 + <dependencies>
  26 + <dependency>
  27 + <groupId>com.zhonglai.luhui</groupId>
  28 + <artifactId>lh-web-douyin</artifactId>
  29 + <version>${ruoyi.version}</version>
  30 + </dependency>
  31 + </dependencies>
  32 + <description>
  33 + web服务
  34 + </description>
  35 +</project>
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<project xmlns="http://maven.apache.org/POM/4.0.0"
  3 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5 + <modelVersion>4.0.0</modelVersion>
  6 + <parent>
  7 + <groupId>com.zhonglai.luhui</groupId>
  8 + <artifactId>lh-modules</artifactId>
  9 + <version>1.0-SNAPSHOT</version>
  10 + </parent>
  11 +
  12 + <artifactId>lh-superweb</artifactId>
  13 +
  14 + <properties>
  15 + <maven.compiler.source>8</maven.compiler.source>
  16 + <maven.compiler.target>8</maven.compiler.target>
  17 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  18 + </properties>
  19 +
  20 + <dependencies>
  21 + <!-- spring-boot-devtools -->
  22 + <dependency>
  23 + <groupId>org.springframework.boot</groupId>
  24 + <artifactId>spring-boot-devtools</artifactId>
  25 + <optional>true</optional> <!-- 表示依赖不会传递 -->
  26 + </dependency>
  27 +
  28 + <!-- Mysql驱动包 -->
  29 + <dependency>
  30 + <groupId>mysql</groupId>
  31 + <artifactId>mysql-connector-java</artifactId>
  32 + </dependency>
  33 +
  34 + <!-- 核心模块-->
  35 + <dependency>
  36 + <groupId>com.zhonglai.luhui</groupId>
  37 + <artifactId>ruoyi-framework</artifactId>
  38 + </dependency>
  39 + <!-- 文档 -->
  40 + <dependency>
  41 + <groupId>com.zhonglai.luhui</groupId>
  42 + <artifactId>lh-common-swagger</artifactId>
  43 + </dependency>
  44 +
  45 + <dependency>
  46 + <groupId>org.aspectj</groupId>
  47 + <artifactId>aspectjweaver</artifactId>
  48 + </dependency>
  49 + <dependency>
  50 + <groupId>org.aspectj</groupId>
  51 + <artifactId>aspectjrt</artifactId>
  52 + </dependency>
  53 +
  54 + <dependency>
  55 + <groupId>cn.hutool</groupId>
  56 + <artifactId>hutool-all</artifactId>
  57 + </dependency>
  58 + <dependency>
  59 + <groupId>com.jcraft</groupId>
  60 + <artifactId>jsch</artifactId>
  61 + </dependency>
  62 +
  63 + <dependency>
  64 + <groupId>com.zhonglai.luhui</groupId>
  65 + <artifactId>lh-public-dao</artifactId>
  66 + </dependency>
  67 + <dependency>
  68 + <groupId>com.zhonglai.luhui</groupId>
  69 + <artifactId>lh-common-datasource</artifactId>
  70 + </dependency>
  71 + <dependency>
  72 + <groupId>com.zhonglai.luhui</groupId>
  73 + <artifactId>lh-jar-action</artifactId>
  74 + </dependency>
  75 +
  76 + <dependency>
  77 + <groupId>com.zhonglai.luhui</groupId>
  78 + <artifactId>lh-superweb-jar</artifactId>
  79 + </dependency>
  80 + </dependencies>
  81 +</project>
  1 +package com.zhonglai.luhui.superweb;
  2 +
  3 +import org.springframework.boot.SpringApplication;
  4 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  5 +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
  6 +import org.springframework.context.annotation.ComponentScan;
  7 +
  8 +@ComponentScan(basePackages = {
  9 + "com.ruoyi.common",
  10 + "com.zhonglai.luhui.config",
  11 + "com.zhonglai.luhui.datasource",
  12 + "com.zhonglai.luhui.dao",
  13 + "com.zhonglai.luhui.superweb",
  14 + "com.zhonglai.luhui.web",
  15 +})
  16 +@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
  17 +public class SuperwebApplication {
  18 + public static void main(String[] args) {
  19 + SpringApplication.run(SuperwebApplication.class,args);
  20 + System.out.println("启动成功");
  21 + }
  22 +
  23 +}
  1 +package com.zhonglai.luhui.superweb.config;
  2 +
  3 +import com.ruoyi.common.config.RuoYiConfig;
  4 +import io.swagger.annotations.ApiOperation;
  5 +import org.springframework.beans.factory.annotation.Autowired;
  6 +import org.springframework.context.annotation.Bean;
  7 +import org.springframework.context.annotation.Configuration;
  8 +import springfox.documentation.builders.ApiInfoBuilder;
  9 +import springfox.documentation.builders.PathSelectors;
  10 +import springfox.documentation.builders.RequestHandlerSelectors;
  11 +import springfox.documentation.service.ApiInfo;
  12 +import springfox.documentation.service.Contact;
  13 +import springfox.documentation.spi.DocumentationType;
  14 +import springfox.documentation.spring.web.plugins.Docket;
  15 +import springfox.documentation.swagger2.annotations.EnableSwagger2;
  16 +
  17 +
  18 +@Configuration
  19 +@EnableSwagger2
  20 +public class SwaggerConfig {
  21 + /** 系统基础配置 */
  22 + @Autowired
  23 + private RuoYiConfig ruoyiConfig;
  24 + @Bean
  25 + public Docket createRestApi() {
  26 + return new Docket(DocumentationType.SWAGGER_2)
  27 + .groupName("默认")
  28 + .apiInfo(apiInfo())
  29 + .select()
  30 + .apis(RequestHandlerSelectors.basePackage("com.zhonglai.luhui.superweb.controller"))
  31 + .paths(PathSelectors.any())
  32 + .build();
  33 + }
  34 +
  35 + /**
  36 + * 添加摘要信息
  37 + */
  38 + private ApiInfo apiInfo()
  39 + {
  40 + // 用ApiInfoBuilder进行定制
  41 + return new ApiInfoBuilder()
  42 + // 设置标题
  43 + .title("标题:web接口")
  44 + // 描述
  45 + .description("描述:总tomcat代理")
  46 + // 作者信息
  47 + .contact(new Contact(ruoyiConfig.getName(), null, null))
  48 + // 版本
  49 + .version("版本号:" + ruoyiConfig.getVersion())
  50 + .build();
  51 + }
  52 +
  53 +}
  1 +package com.zhonglai.luhui.superweb.controller;
  2 +
  3 +import io.swagger.annotations.Api;
  4 +import io.swagger.annotations.ApiOperation;
  5 +import org.springframework.stereotype.Controller;
  6 +import org.springframework.util.StreamUtils;
  7 +import org.springframework.web.bind.annotation.RequestMapping;
  8 +import org.springframework.web.bind.annotation.RestController;
  9 +
  10 +import javax.servlet.http.HttpServletRequest;
  11 +import javax.servlet.http.HttpServletResponse;
  12 +import java.io.IOException;
  13 +import java.io.UnsupportedEncodingException;
  14 +import java.util.Enumeration;
  15 +import java.util.HashMap;
  16 +import java.util.Map;
  17 +
  18 +
  19 +@Api(tags = "主页")
  20 +@RestController
  21 +@RequestMapping("/")
  22 +public class RootController {
  23 + @ApiOperation("默认主页")
  24 + @RequestMapping(value = "")
  25 + public String index(HttpServletRequest httpServletRequest) throws IOException {
  26 + StringBuffer bodyBytes = new StringBuffer("<html>");
  27 + bodyBytes.append("<head><meta charset=\"UTF-8\"></head>");
  28 + bodyBytes.append("<body>");
  29 + Map<String, String[]> map = httpServletRequest.getParameterMap();
  30 + bodyBytes.append("<b>parameter:</b></br>");
  31 + for (Map.Entry<String, String[]> entry : map.entrySet()) {
  32 + String key = entry.getKey();
  33 + String[] values = entry.getValue();
  34 + if (values.length == 1) {
  35 + bodyBytes.append(key).append(":").append(values[0]).append("</br>");
  36 + } else {
  37 + bodyBytes.append(key).append(":").append(values).append("</br>");
  38 + }
  39 + }
  40 +
  41 + // 打印请求头信息
  42 + bodyBytes.append("<b>header:</b></br>");
  43 + Enumeration<String> headerNames = httpServletRequest.getHeaderNames();
  44 + while (headerNames.hasMoreElements()) {
  45 + String headerName = headerNames.nextElement();
  46 + String headerValue = httpServletRequest.getHeader(headerName);
  47 + bodyBytes.append(headerName).append(":").append(headerValue).append("</br>");
  48 + }
  49 + //获取请求body
  50 + byte[] rbody = StreamUtils.copyToByteArray(httpServletRequest.getInputStream());
  51 + String body = new String(rbody, httpServletRequest.getCharacterEncoding());
  52 + bodyBytes.append("<b>body:</b></br>");
  53 + bodyBytes.append(body);
  54 + bodyBytes.append("</body>");
  55 + bodyBytes.append("</html>");
  56 + return bodyBytes.toString();
  57 + }
  58 +}
  1 +# 数据源配置
  2 +spring:
  3 + datasource:
  4 + type: com.alibaba.druid.pool.DruidDataSource
  5 + driverClassName: com.mysql.cj.jdbc.Driver
  6 + druid:
  7 + # 主库数据源
  8 + master:
  9 + url: jdbc:mysql://rm-wz9740un21f09iokuao.mysql.rds.aliyuncs.com:3306/mqtt_broker?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
  10 + username: luhui
  11 + password: Luhui586
  12 + # 从库数据源
  13 + slave:
  14 + # 从数据源开关/默认关闭
  15 + enabled: false
  16 + url:
  17 + username:
  18 + password:
  19 + # 初始连接数
  20 + initialSize: 5
  21 + # 最小连接池数量
  22 + minIdle: 10
  23 + # 最大连接池数量
  24 + maxActive: 20
  25 + # 配置获取连接等待超时的时间
  26 + maxWait: 60000
  27 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
  28 + timeBetweenEvictionRunsMillis: 60000
  29 + # 配置一个连接在池中最小生存的时间,单位是毫秒
  30 + minEvictableIdleTimeMillis: 300000
  31 + # 配置一个连接在池中最大生存的时间,单位是毫秒
  32 + maxEvictableIdleTimeMillis: 900000
  33 + # 配置检测连接是否有效
  34 + validationQuery: SELECT 1 FROM DUAL
  35 + testWhileIdle: true
  36 + testOnBorrow: false
  37 + testOnReturn: false
  38 + webStatFilter:
  39 + enabled: true
  40 + statViewServlet:
  41 + enabled: true
  42 + # 设置白名单,不填则允许所有访问
  43 + allow:
  44 + url-pattern: /druid/*
  45 + # 控制台管理用户名和密码
  46 + login-username: ruoyi
  47 + login-password: 123456
  48 + filter:
  49 + stat:
  50 + enabled: true
  51 + # 慢SQL记录
  52 + log-slow-sql: true
  53 + slow-sql-millis: 1000
  54 + merge-sql: true
  55 + wall:
  56 + config:
  57 + multi-statement-allow: true
  1 +# 项目相关配置 jhlt: # 名称 name: zhonglai # 版本 version: 3.8.2 # 版权年份 copyrightYear: 2022 # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 port: 8080 servlet: # 应用的访问路径 context-path: /superweb tomcat: # tomcat的URI编码 uri-encoding: UTF-8 # 连接数满后的排队数,默认为100 accept-count: 1000 threads: # tomcat最大线程数,默认为200 max: 800 # Tomcat启动初始化的线程数,默认值10 min-spare: 100 # 日志配置 logging: level: com.ruoyi: debug org.springframework: warn com.zhonglai.luhui: debug # Spring配置 spring: # 资源信息 messages: # 国际化资源文件路径 basename: i18n/messages profiles: active: druid # 文件上传 servlet: multipart: # 单个文件大小 max-file-size: 10MB # 设置总上传的文件大小 max-request-size: 20MB # 服务模块 devtools: restart: # 热部署开关 enabled: true # MyBatis配置 mybatis: # 搜索指定包别名 typeAliasesPackage: com.ruoyi.**.domain,com.zhonglai.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml # PageHelper分页插件 pagehelper: helperDialect: mysql supportMethodsArguments: true params: count=countSql # Swagger配置 swagger: # 是否开启swagger enabled: true # 请求前缀 pathMapping: /dev-api # 防止XSS攻击 xss: # 过滤开关 enabled: true # 排除链接(多个用逗号分隔) excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* sys: ## // 对于登录login 注册register 验证码captchaImage 允许匿名访问 antMatchers: /v2/api-docs
@@ -33,6 +33,9 @@ @@ -33,6 +33,9 @@
33 <module>lh-device-protocol-parser</module> 33 <module>lh-device-protocol-parser</module>
34 <module>lh-device-operation-service</module> 34 <module>lh-device-operation-service</module>
35 <module>lh-alarm-timer</module> 35 <module>lh-alarm-timer</module>
  36 + <module>lh-superweb</module>
  37 + <module>lh-superweb-jar</module>
  38 + <module>lh-ssh-service-lesten</module>
36 </modules> 39 </modules>
37 40
38 <properties> 41 <properties>
@@ -371,11 +371,21 @@ @@ -371,11 +371,21 @@
371 <version>${ruoyi.version}</version> 371 <version>${ruoyi.version}</version>
372 </dependency> 372 </dependency>
373 <dependency> 373 <dependency>
  374 + <groupId>com.zhonglai.luhui</groupId>
  375 + <artifactId>lh-superweb-jar</artifactId>
  376 + <version>${ruoyi.version}</version>
  377 + </dependency>
  378 + <dependency>
374 <groupId>com.zhonglai</groupId> 379 <groupId>com.zhonglai</groupId>
375 <artifactId>ServiceDao</artifactId> 380 <artifactId>ServiceDao</artifactId>
376 <version>1.4.3</version> 381 <version>1.4.3</version>
377 </dependency> 382 </dependency>
378 383
  384 + <dependency>
  385 + <groupId>com.zhonglai.luhui</groupId>
  386 + <artifactId>lh-jar-plugins-init</artifactId>
  387 + <version>${ruoyi.version}</version>
  388 + </dependency>
379 <!-- 支持data --> 389 <!-- 支持data -->
380 <dependency> 390 <dependency>
381 <groupId>org.projectlombok</groupId> 391 <groupId>org.projectlombok</groupId>