正在显示
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 | } |
lh-jar/lh-jar-plugins-init/pom.xml
0 → 100644
| 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> |
lh-jar/lh-jar-plugins-init/src/main/java/com/zhonglai/luhui/plugins/FileChangeListener.java
0 → 100644
| 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 | +} |
lh-jar/lh-jar-plugins-init/src/main/java/com/zhonglai/luhui/plugins/config/PluginsClassLoader.java
0 → 100644
| 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 | + <!--<!– https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui –>--> | ||
| 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 | +} |
lh-modules/lh-http-service/src/main/java/com/zhonglai/luhui/http/service/model/LogMessageDto.java
0 → 100644
| 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 | +} |
lh-modules/lh-http-service/src/main/java/com/zhonglai/luhui/http/service/service/HttpCallback.java
0 → 100644
| 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 | +} |
lh-modules/lh-http-service/src/main/java/com/zhonglai/luhui/http/service/service/JedisService.java
0 → 100644
| 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 | -restart.include.json=/com.alibaba.fastjson.*.jar |
| 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> |
| 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 | +} |
lh-modules/lh-mqtt-service/src/main/java/com/zhonglai/luhui/mqtt/LogServerInitializer.java
0 → 100644
| 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 |
lh-modules/lh-ssh-service-lesten/pom.xml
0 → 100644
| 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.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 | +} |
lh-modules/lh-superweb-jar/pom.xml
0 → 100644
| 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> |
lh-modules/lh-superweb/pom.xml
0 → 100644
| 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> |
lh-modules/lh-superweb/src/main/java/com/zhonglai/luhui/superweb/SuperwebApplication.java
0 → 100644
| 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 | +} |
lh-modules/lh-superweb/src/main/java/com/zhonglai/luhui/superweb/config/SwaggerConfig.java
0 → 100644
| 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 | +} |
lh-modules/lh-superweb/src/main/java/com/zhonglai/luhui/superweb/controller/RootController.java
0 → 100644
| 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> |
-
请 注册 或 登录 后发表评论