MOD:更换为Vertx框架 提高效率

This commit is contained in:
leosam1024
2023-06-15 15:56:41 +08:00
parent 08fe94f020
commit d78c34d18a
21 changed files with 913 additions and 325 deletions
@@ -0,0 +1,123 @@
package com.leosam.tvbox.mv;
import com.leosam.tvbox.mv.data.MvResult;
import com.leosam.tvbox.mv.data.VodResult;
import com.leosam.tvbox.mv.service.MvService;
import com.leosam.tvbox.mv.utils.NumberUtils;
import com.leosam.tvbox.mv.utils.StringUtils;
import com.leosam.tvbox.mv.utils.VertxUtils;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.json.Json;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
public class MainVerticle extends AbstractVerticle {
private static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);
private static MvService mvService;
private static int port = 0;
static {
CompletableFuture.runAsync(MainVerticle::initIndex)
.thenAcceptAsync((a) -> {
if (port > 0) {
logger.info("索引完成,可以请求数据了, HTTP server port " + port);
} else {
logger.info("索引完成,可以请求数据了");
}
});
}
private static void initIndex() {
try {
MvService mvService = new MvService();
mvService.initIndex();
MainVerticle.mvService = mvService;
} catch (Exception e) {
logger.error("初始化索引失败", e);
}
}
@Override
public void start(Promise<Void> startPromise) throws Exception {
HttpServer httpServer = vertx.createHttpServer();
Router router = Router.router(vertx);
router.route("/mv/search").handler(this::searchMv);
router.route("/mv/vod").handler(this::searchMvVod);
router.route().handler(req -> req.response().putHeader("content-type", "text/plain").end("Hello from Vert.x!"));
httpServer.requestHandler(router);
httpServer.listen(7777, http -> {
if (http.succeeded()) {
startPromise.complete();
logger.info("HTTP server started on port 7777");
} else {
startPromise.fail(http.cause());
}
});
port = httpServer.actualPort();
}
private void searchMvVod(RoutingContext req) {
// 获取参数
String wd = VertxUtils.queryParam(req, "wd");
String ac = VertxUtils.queryParam(req, "ac");
String ids = VertxUtils.queryParam(req, "ids");
String maxCount = VertxUtils.queryParam(req, "maxCount");
int max = Math.min(Math.max(NumberUtils.toInt(maxCount, 100), 10), 1000);
String query = StringUtils.isNotEmpty(wd) ? wd : ids;
// 处理结果
VodResult vodResult = null;
try {
if (mvService != null) {
vodResult = mvService.searchVod(query, max);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// 返回数据
String jsonString = Json.encode(vodResult);
req.response()
.putHeader("content-type", "application/json")
.end(jsonString);
}
private void searchMv(RoutingContext req) {
// 获取参数
String query = VertxUtils.queryParam(req, "query");
String maxCount = VertxUtils.queryParam(req, "maxCount");
int max = Math.min(Math.max(NumberUtils.toInt(maxCount, 100), 10), 1000);
// 处理结果
MvResult search = null;
try {
if (mvService != null) {
search = mvService.search(query, max);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// 返回数据
String jsonString = Json.encode(search);
req.response()
.putHeader("content-type", "application/json")
.end(jsonString);
}
public static void main(String[] args) throws Exception {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new MainVerticle());
}
}
@@ -1,13 +0,0 @@
package com.leosam.tvbox.mv;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TvboxMvApplication {
public static void main(String[] args) {
SpringApplication.run(TvboxMvApplication.class, args);
}
}
@@ -1,26 +0,0 @@
package com.leosam.tvbox.mv.controller;
import com.leosam.tvbox.mv.data.MvResult;
import com.leosam.tvbox.mv.service.MvService;
import com.leosam.tvbox.mv.utils.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
* @since 2023/6/10 17:34
*/
@RestController
public class IndexController {
@Autowired
private MvService mvService;
@RequestMapping(value = {"/mv/search"})
public MvResult searchMv(String query, String maxCount) throws Exception {
int max = Math.min(Math.max(NumberUtils.toInt(maxCount, 100), 10), 1000);
return mvService.search(query, max);
}
}
@@ -1,28 +0,0 @@
package com.leosam.tvbox.mv.controller;
import com.leosam.tvbox.mv.data.VodResult;
import com.leosam.tvbox.mv.service.MvService;
import com.leosam.tvbox.mv.utils.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author admin
* @since 2023/6/11 18:54
*/
@RestController
public class VodController {
@Autowired
private MvService mvService;
@RequestMapping(value = {"/mv/vod"})
public VodResult searchVod(String wd, String ac, String ids, String maxCount) throws Exception {
int max = Math.min(Math.max(NumberUtils.toInt(maxCount, 100), 10), 1000);
String query = StringUtils.hasText(wd) ? wd : ids;
return mvService.searchVod(query, max);
}
}
@@ -1,10 +1,12 @@
package com.leosam.tvbox.mv.lucene;
import io.vertx.ext.web.impl.LRUCache;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.StoredFields;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@@ -24,39 +26,58 @@ import java.nio.file.Paths;
public class MvSearcher {
private IndexReader reader;
private IndexSearcher searcher;
private StoredFields storedFields;
private final LRUCache<Integer, Document> documentLruCache = new LRUCache<>(1000);
private final LRUCache<String, TopDocs> topDocsLruCache = new LRUCache<>(100);
public MvSearcher(String indexDirectoryPath) throws IOException {
Path indexPath = Paths.get(indexDirectoryPath);
Directory directory = FSDirectory.open(indexPath);
reader = DirectoryReader.open(directory);
searcher = new IndexSearcher(reader);
storedFields = reader.storedFields();
}
public TopDocs searchTopDocs(String field, String queryStr, int maxHit) throws Exception {
String cacheKey = field + "_" + queryStr + "_" + maxHit;
TopDocs topDocs = topDocsLruCache.get(cacheKey);
if (topDocs != null) {
return topDocs;
}
Analyzer analyzer = new SmartChineseAnalyzer();
// Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(queryStr);
TopDocs docs = searcher.search(query, maxHit);
topDocsLruCache.put(cacheKey, docs);
return docs;
}
public void search(String field, String queryStr) throws Exception {
Analyzer analyzer = new SmartChineseAnalyzer();
// Analyzer analyzer = new StandardAnalyzer();
// Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(queryStr);
TopDocs docs = searcher.search(query, 200);
// 处理搜索结果
for (ScoreDoc scoreDoc : docs.scoreDocs) {
Document document = searcher.doc(scoreDoc.doc);
Document document = getDocument(scoreDoc.doc);
System.out.println(document.get("name") + "," + document.get("url") + " score=" + scoreDoc.score);
}
}
public Document getDocument(int docID) throws IOException {
Document document = searcher.doc(docID);
public Document getDocument(int docId) throws IOException {
Document document = documentLruCache.get(docId);
if (document != null) {
return document;
}
document = storedFields.document(docId);
if (document != null) {
documentLruCache.put(docId, document);
}
return document;
}
@@ -7,6 +7,9 @@ import com.leosam.tvbox.mv.data.VodResult;
import com.leosam.tvbox.mv.lucene.MvIndex;
import com.leosam.tvbox.mv.lucene.MvSearcher;
import com.leosam.tvbox.mv.utils.ClassPathReaderUtils;
import com.leosam.tvbox.mv.utils.CollectionUtils;
import com.leosam.tvbox.mv.utils.StopWatch;
import com.leosam.tvbox.mv.utils.StringUtils;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
@@ -15,14 +18,10 @@ import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.LinkedList;
@@ -34,16 +33,16 @@ import java.util.concurrent.atomic.AtomicInteger;
* @author admin
* @since 2023/6/10 17:35
*/
@Service
public class MvService implements InitializingBean {
public class MvService {
private static final Logger logger = LoggerFactory.getLogger(MvService.class);
private static final String indexDirectoryPath = "index";
private static final String MV_FILE = "tvbox/16wMV.txt";
private MvSearcher mvSearcher;
public MvResult search(String query, int max) throws Exception {
if (!StringUtils.hasText(query)) {
if (StringUtils.isEmpty(query) || mvSearcher == null) {
return new MvResult();
}
@@ -55,7 +54,7 @@ public class MvService implements InitializingBean {
MvResult result = new MvResult();
result.setQuery(query);
result.setTotalHits(topDocs.totalHits.value);
result.setList(new LinkedList<>());
result.setList(new ArrayList<>(topDocs.scoreDocs.length));
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
Document document = mvSearcher.getDocument(scoreDoc.doc);
if (document == null) {
@@ -66,8 +65,9 @@ public class MvService implements InitializingBean {
String songName = name;
String songUser = null;
if (name.contains("-")) {
songUser = name.split("-", 2)[0];
songName = name.split("-", 2)[1];
String[] split = name.split("-", 2);
songUser = split[0];
songName = split[1];
}
String url = document.get("url");
if (!url.startsWith("http")) {
@@ -96,12 +96,13 @@ public class MvService implements InitializingBean {
vod.setVodId(wd);
vod.setVodName(wd);
vod.setVodPlayFrom("mv");
vod.setVodPic("http://m4.auto.itc.cn/auto/content/20230611/45d65d8a001f0c5aa008030f41c98666.jpeg");
vod.setVodPic("http://yanxuan.nosdn.127.net/b6fb987ce79f308949e44f5129a4b51c.jpeg");
// vod.setVodPic("http://m4.auto.itc.cn/auto/content/20230611/45d65d8a001f0c5aa008030f41c98666.jpeg");
List<String> playUrlList = new LinkedList<>();
Set<String> vodActorList = new LinkedHashSet<>();
for (MvContent content : search.getList()) {
playUrlList.add(content.getName() + "$" + content.getUrl());
if (vodActorList.size() < 5 && StringUtils.hasText(content.getSongUser())) {
if (vodActorList.size() < 5 && StringUtils.isNotEmpty(content.getSongUser())) {
vodActorList.add(content.getSongUser());
}
}
@@ -115,8 +116,8 @@ public class MvService implements InitializingBean {
return vodResult;
}
@Override
public void afterPropertiesSet() throws Exception {
public void initIndex() throws Exception {
// 重建索引
String indexAbsolutePath = new File(indexDirectoryPath).getAbsoluteFile().getAbsolutePath();
reBuildIndex(indexAbsolutePath);
@@ -130,13 +131,22 @@ public class MvService implements InitializingBean {
private static void reBuildIndex(String indexDirectoryPath) throws IOException {
File file = new File(indexDirectoryPath).getAbsoluteFile();
int mvFileSize = ClassPathReaderUtils.getSize(MV_FILE);
File mvFileSizeTxt = Path.of(file.getAbsolutePath(), "" + mvFileSize + ".txt").toFile();
if (mvFileSizeTxt.exists()) {
logger.info("{}已经索引, 跳过索引", MV_FILE);
return;
}
StopWatch stopWatch = new StopWatch();
logger.info("重建索引中....");
// 清空以前的索引
stopWatch.start("清空以前索引");
logger.info("清空历史索引....");
File file = new File(indexDirectoryPath).getAbsoluteFile();
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File file1 : files) {
@@ -152,7 +162,7 @@ public class MvService implements InitializingBean {
logger.info("创建索引中....");
AtomicInteger line = new AtomicInteger();
MvIndex mvIndex = new MvIndex(indexDirectoryPath);
ClassPathReaderUtils.getBufferedReader("tvbox/16wMV.txt").lines()
ClassPathReaderUtils.getBufferedReader(MV_FILE).lines()
.filter(l -> l.contains(",h"))
.filter(l -> l.contains("-"))
.forEach(l -> {
@@ -182,6 +192,7 @@ public class MvService implements InitializingBean {
}
});
mvIndex.close();
mvFileSizeTxt.createNewFile();
logger.info("创建索引中....完成, 总共{}条", line.get());
stopWatch.stop();
logger.info("重建索引中....完成,耗时 {} 毫秒, 索引位置:{}", stopWatch.getTotalTimeMillis(), file.getPath());
@@ -1,12 +1,12 @@
package com.leosam.tvbox.mv.utils;
import org.springframework.core.io.ClassPathResource;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
/**
* @author admin
@@ -14,19 +14,33 @@ import java.util.Properties;
*/
public class ClassPathReaderUtils {
public static int getSize(String path) {
try {
ClassPathResource resource = new ClassPathResource(path);
InputStream inputStream = resource.getInputStream();
int available = inputStream.available();
return available;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static InputStreamReader getInputStreamReader(String path) {
try {
ClassPathResource resource = new ClassPathResource(path);
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream(),StandardCharsets.UTF_8);
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8);
return inputStreamReader;
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static BufferedReader getBufferedReader(String path) {
try {
ClassPathResource resource = new ClassPathResource(path);
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream(),StandardCharsets.UTF_8);
BufferedReader reader = new BufferedReader(inputStreamReader);
return reader;
@@ -35,17 +49,6 @@ public class ClassPathReaderUtils {
}
}
public static Properties getProperties(String path) {
Properties properties = new Properties();
try {
ClassPathResource resource = new ClassPathResource(path);
InputStreamReader inputStreamReader = new InputStreamReader(resource.getInputStream());
properties.load(new BufferedReader(inputStreamReader));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return properties;
}
public static String getContent(String path) {
StringBuilder content = new StringBuilder();
@@ -70,5 +73,52 @@ public class ClassPathReaderUtils {
System.out.println(json);
}
public static class ClassPathResource {
private final String path;
private final ClassLoader classLoader;
public ClassPathResource(String path) {
this.path = path;
this.classLoader = getDefaultClassLoader();
}
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
} else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(path + " cannot be opened because it does not exist");
}
return is;
}
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassPathResource.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
} catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
}
}
@@ -0,0 +1,15 @@
package com.leosam.tvbox.mv.utils;
import java.util.Collection;
/**
* @author admin
* @since 2023/6/12 21:15
*/
public class CollectionUtils {
public static boolean isEmpty(Collection<?> collection) {
return (collection == null || collection.isEmpty());
}
}
@@ -1,93 +0,0 @@
package com.leosam.tvbox.mv.utils;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
/**
*
*/
public class JsonUtils {
private static final Logger LOG = LoggerFactory.getLogger(JsonUtils.class);
private static final TypeReference<HashMap<String, String>> TYPE_MAP =
new TypeReference<HashMap<String, String>>() {
};
public static ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.registerModule(new Jdk8Module());
objectMapper.enable(JsonParser.Feature.ALLOW_COMMENTS);
}
public static String writeValue(Object o) {
try {
return writeValueThrowException(o);
} catch (Exception e) {
return "";
}
}
public static String writeValuePrettyPrinter(Object o) {
try {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(o);
} catch (Exception e) {
LOG.error("exception occur when Json serializePretty", e);
return "";
}
}
public static String writeValueThrowException(Object o) throws JsonProcessingException {
try {
return objectMapper.writeValueAsString(o);
} catch (Exception e) {
LOG.error("exception occur when Json serialize", e);
throw e;
}
}
public static <T> T readValue(String json, Class<T> clazz) {
try {
return readValueThrowException(json, clazz);
} catch (IOException e) {
return null;
}
}
public static <T> T readValueThrowException(String json, Class<T> clazz) throws IOException {
try {
return objectMapper.readValue(json, clazz);
} catch (IOException e) {
LOG.warn("Failed to deserialize from JSON string", e);
throw e;
}
}
public static <T> T readValue(String json, TypeReference<T> typeReference) {
try {
return readValueThrowException(json, typeReference);
} catch (IOException e) {
return null;
}
}
public static <T> T readValueThrowException(String json, TypeReference<T> typeReference) throws IOException {
try {
return objectMapper.readValue(json, typeReference);
} catch (IOException e) {
LOG.warn("Failed to deserialize from JSON string", e);
throw e;
}
}
}
@@ -7,7 +7,7 @@ package com.leosam.tvbox.mv.utils;
public class NumberUtils {
public static int toInt(final String str, final int defaultValue) {
if (str == null) {
if (str == null || str.length() == 0) {
return defaultValue;
}
try {
@@ -0,0 +1,392 @@
package com.leosam.tvbox.mv.utils;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Simple stop watch, allowing for timing of a number of tasks, exposing total
* running time and running time for each named task.
*
* <p>Conceals use of {@link System#nanoTime()}, improving the readability of
* application code and reducing the likelihood of calculation errors.
*
* <p>Note that this object is not designed to be thread-safe and does not use
* synchronization.
*
* <p>This class is normally used to verify performance during proof-of-concept
* work and in development, rather than as part of production applications.
*
* <p>As of Spring Framework 5.2, running time is tracked and reported in
* nanoseconds.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since May 2, 2001
*/
public class StopWatch {
/**
* Identifier of this {@code StopWatch}.
* <p>Handy when we have output from multiple stop watches and need to
* distinguish between them in log or console output.
*/
private final String id;
private boolean keepTaskList = true;
private final List<TaskInfo> taskList = new ArrayList<>(1);
/**
* Start time of the current task.
*/
private long startTimeNanos;
/**
* Name of the current task.
*/
private String currentTaskName;
private TaskInfo lastTaskInfo;
private int taskCount;
/**
* Total running time.
*/
private long totalTimeNanos;
/**
* Construct a new {@code StopWatch}.
* <p>Does not start any task.
*/
public StopWatch() {
this("");
}
/**
* Construct a new {@code StopWatch} with the given ID.
* <p>The ID is handy when we have output from multiple stop watches and need
* to distinguish between them.
* <p>Does not start any task.
*
* @param id identifier for this stop watch
*/
public StopWatch(String id) {
this.id = id;
}
/**
* Get the ID of this {@code StopWatch}, as specified on construction.
*
* @return the ID (empty String by default)
* @see #StopWatch(String)
* @since 4.2.2
*/
public String getId() {
return this.id;
}
/**
* Configure whether the {@link StopWatch.TaskInfo} array is built over time.
* <p>Set this to {@code false} when using a {@code StopWatch} for millions
* of intervals; otherwise, the {@code TaskInfo} structure will consume
* excessive memory.
* <p>Default is {@code true}.
*/
public void setKeepTaskList(boolean keepTaskList) {
this.keepTaskList = keepTaskList;
}
/**
* Start an unnamed task.
* <p>The results are undefined if {@link #stop()} or timing methods are
* called without invoking this method first.
*
* @see #start(String)
* @see #stop()
*/
public void start() throws IllegalStateException {
start("");
}
/**
* Start a named task.
* <p>The results are undefined if {@link #stop()} or timing methods are
* called without invoking this method first.
*
* @param taskName the name of the task to start
* @see #start()
* @see #stop()
*/
public void start(String taskName) throws IllegalStateException {
if (this.currentTaskName != null) {
throw new IllegalStateException("Can't start StopWatch: it's already running");
}
this.currentTaskName = taskName;
this.startTimeNanos = System.nanoTime();
}
/**
* Stop the current task.
* <p>The results are undefined if timing methods are called without invoking
* at least one pair of {@code start()} / {@code stop()} methods.
*
* @see #start()
* @see #start(String)
*/
public void stop() throws IllegalStateException {
if (this.currentTaskName == null) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
}
long lastTime = System.nanoTime() - this.startTimeNanos;
this.totalTimeNanos += lastTime;
this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(this.lastTaskInfo);
}
++this.taskCount;
this.currentTaskName = null;
}
/**
* Determine whether this {@code StopWatch} is currently running.
*
* @see #currentTaskName()
*/
public boolean isRunning() {
return (this.currentTaskName != null);
}
/**
* Get the name of the currently running task, if any.
*
* @see #isRunning()
* @since 4.2.2
*/
public String currentTaskName() {
return this.currentTaskName;
}
/**
* Get the time taken by the last task in nanoseconds.
*
* @see #getLastTaskTimeMillis()
* @since 5.2
*/
public long getLastTaskTimeNanos() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task interval");
}
return this.lastTaskInfo.getTimeNanos();
}
/**
* Get the time taken by the last task in milliseconds.
*
* @see #getLastTaskTimeNanos()
*/
public long getLastTaskTimeMillis() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task interval");
}
return this.lastTaskInfo.getTimeMillis();
}
/**
* Get the name of the last task.
*/
public String getLastTaskName() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task name");
}
return this.lastTaskInfo.getTaskName();
}
/**
* Get the last task as a {@link StopWatch.TaskInfo} object.
*/
public StopWatch.TaskInfo getLastTaskInfo() throws IllegalStateException {
if (this.lastTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task info");
}
return this.lastTaskInfo;
}
/**
* Get the total time in nanoseconds for all tasks.
*
* @see #getTotalTimeMillis()
* @see #getTotalTimeSeconds()
* @since 5.2
*/
public long getTotalTimeNanos() {
return this.totalTimeNanos;
}
/**
* Get the total time in milliseconds for all tasks.
*
* @see #getTotalTimeNanos()
* @see #getTotalTimeSeconds()
*/
public long getTotalTimeMillis() {
return nanosToMillis(this.totalTimeNanos);
}
/**
* Get the total time in seconds for all tasks.
*
* @see #getTotalTimeNanos()
* @see #getTotalTimeMillis()
*/
public double getTotalTimeSeconds() {
return nanosToSeconds(this.totalTimeNanos);
}
/**
* Get the number of tasks timed.
*/
public int getTaskCount() {
return this.taskCount;
}
/**
* Get an array of the data for tasks performed.
*/
public StopWatch.TaskInfo[] getTaskInfo() {
if (!this.keepTaskList) {
throw new UnsupportedOperationException("Task info is not being kept!");
}
return this.taskList.toArray(new StopWatch.TaskInfo[0]);
}
/**
* Get a short description of the total running time.
*/
public String shortSummary() {
return "StopWatch '" + getId() + "': running time = " + getTotalTimeNanos() + " ns";
}
/**
* Generate a string with a table describing all tasks performed.
* <p>For custom reporting, call {@link #getTaskInfo()} and use the task info
* directly.
*/
public String prettyPrint() {
StringBuilder sb = new StringBuilder(shortSummary());
sb.append('\n');
if (!this.keepTaskList) {
sb.append("No task info kept");
} else {
sb.append("---------------------------------------------\n");
sb.append("ns % Task name\n");
sb.append("---------------------------------------------\n");
NumberFormat nf = NumberFormat.getNumberInstance();
nf.setMinimumIntegerDigits(9);
nf.setGroupingUsed(false);
NumberFormat pf = NumberFormat.getPercentInstance();
pf.setMinimumIntegerDigits(3);
pf.setGroupingUsed(false);
for (StopWatch.TaskInfo task : getTaskInfo()) {
sb.append(nf.format(task.getTimeNanos())).append(" ");
sb.append(pf.format((double) task.getTimeNanos() / getTotalTimeNanos())).append(" ");
sb.append(task.getTaskName()).append('\n');
}
}
return sb.toString();
}
/**
* Generate an informative string describing all tasks performed
* <p>For custom reporting, call {@link #getTaskInfo()} and use the task info
* directly.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(shortSummary());
if (this.keepTaskList) {
for (StopWatch.TaskInfo task : getTaskInfo()) {
sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeNanos()).append(" ns");
long percent = Math.round(100.0 * task.getTimeNanos() / getTotalTimeNanos());
sb.append(" = ").append(percent).append('%');
}
} else {
sb.append("; no task info kept");
}
return sb.toString();
}
private static long nanosToMillis(long duration) {
return TimeUnit.NANOSECONDS.toMillis(duration);
}
private static double nanosToSeconds(long duration) {
return duration / 1_000_000_000.0;
}
/**
* Nested class to hold data about one task executed within the {@code StopWatch}.
*/
public static final class TaskInfo {
private final String taskName;
private final long timeNanos;
TaskInfo(String taskName, long timeNanos) {
this.taskName = taskName;
this.timeNanos = timeNanos;
}
/**
* Get the name of this task.
*/
public String getTaskName() {
return this.taskName;
}
/**
* Get the time in nanoseconds this task took.
*
* @see #getTimeMillis()
* @see #getTimeSeconds()
* @since 5.2
*/
public long getTimeNanos() {
return this.timeNanos;
}
/**
* Get the time in milliseconds this task took.
*
* @see #getTimeNanos()
* @see #getTimeSeconds()
*/
public long getTimeMillis() {
return nanosToMillis(this.timeNanos);
}
/**
* Get the time in seconds this task took.
*
* @see #getTimeMillis()
* @see #getTimeNanos()
*/
public double getTimeSeconds() {
return nanosToSeconds(this.timeNanos);
}
}
}
@@ -0,0 +1,16 @@
package com.leosam.tvbox.mv.utils;
/**
* @author admin
* @since 2023/6/12 21:32
*/
public class StringUtils {
public static boolean isNotEmpty(final CharSequence cs) {
return !isEmpty(cs);
}
public static boolean isEmpty(final CharSequence cs) {
return cs == null || cs.length() == 0;
}
}
@@ -0,0 +1,20 @@
package com.leosam.tvbox.mv.utils;
import io.vertx.ext.web.RoutingContext;
import java.util.List;
/**
* @author admin
* @since 2023/6/12 21:16
*/
public class VertxUtils {
public static String queryParam(RoutingContext context, String wd) {
List<String> param = context.queryParam(wd);
if (param != null && param.size() > 0) {
return param.get(0);
}
return "";
}
}
@@ -1,40 +0,0 @@
package com.leosam.tvbox.mv.view;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* @author admin
* @since 2023/6/11 20:03
*/
public class MyTimeInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(MyTimeInterceptor.class);
/**
* 线程变量 - 开始执行时间
*/
private final ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
startTime.set(System.nanoTime());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if (startTime.get() == null) {
return;
}
long processTime = System.nanoTime() - startTime.get();
if (logger.isInfoEnabled()) {
logger.info("RequestURL[{}], Referer[{}], TIME[{} ms]", request.getRequestURL().toString(), request.getHeader("Referer"), String.format("%.3f", (processTime / 1_000_000.0)));
}
startTime.remove();
}
}
@@ -1,27 +0,0 @@
package com.leosam.tvbox.mv.view;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author admin
*/
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 页面运行时间统计
registry.addInterceptor(new MyTimeInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**")
.excludePathPatterns("/favicon.ico");
}
}