From ac9e656c7b9674bc3a1201d9c222b6ab5f0f56cd Mon Sep 17 00:00:00 2001 From: Fuyuxinge <1876397977@qq.com> Date: Mon, 1 Jun 2026 13:09:41 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E4=E4=B8=AA=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- w10/AnalyzeCommand.java | 63 +++++++++++++++++++++++++++++++++++++ w10/ArticleRepository.java | 35 +++++++++++++++++++++ w11/RetryUtils.java | 30 ++++++++++++++++++ w11/UrlFormatException.java | 12 +++++++ 4 files changed, 140 insertions(+) create mode 100644 w10/AnalyzeCommand.java create mode 100644 w10/ArticleRepository.java create mode 100644 w11/RetryUtils.java create mode 100644 w11/UrlFormatException.java diff --git a/w10/AnalyzeCommand.java b/w10/AnalyzeCommand.java new file mode 100644 index 0000000..3bd6707 --- /dev/null +++ b/w10/AnalyzeCommand.java @@ -0,0 +1,63 @@ +public class AnalyzeCommand implements Command { + + private static final Pattern URL_PATTERN = + Pattern.compile("^(https?://)?([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)*$"); + + private final ConsoleView view; + private final StrategyFactory strategyFactory; + + public AnalyzeCommand(ConsoleView view, StrategyFactory strategyFactory) { + this.view = view; + this.strategyFactory = strategyFactory; + } + + @Override + public String getName() { + return "analyze"; + } + + @Override + public void execute(String[] args, List
unused) { + + if (args.length < 2) { + view.printError("用法:analyze "); + return; + } + + String url = args[1]; + + + if (!isValidUrl(url)) { + view.printError("无效的URL格式:" + url); + return; + } + + try { + + List
parsedArticles = strategyFactory.getStrategy(url).crawl(url); + + + printAnalysisResult(url, parsedArticles); + + } catch (Exception e) { + view.printError("解析失败:" + e.getMessage()); + } + } + + private void printAnalysisResult(String url, List
articles) { + view.printInfo("解析统计结果 "); + view.printInfo("目标 URL:" + url); + view.printInfo("解析到文章数量:" + articles.size()); + + if (!articles.isEmpty()) { + Article first = articles.get(0); + view.printInfo("首篇文章标题:" + first.getTitle()); + view.printInfo("首篇文章作者:" + first.getAuthor()); + view.printInfo("首篇发布日期:" + first.getPublishDate()); + } + } + + private boolean isValidUrl(String url) { + return url != null && URL_PATTERN.matcher(url).matches(); + } +} diff --git a/w10/ArticleRepository.java b/w10/ArticleRepository.java new file mode 100644 index 0000000..62774b0 --- /dev/null +++ b/w10/ArticleRepository.java @@ -0,0 +1,35 @@ +package w10; +public class ArticleRepository { + private final List
articles = new ArrayList<>(); + + public void add(Article article) { + if (article == null) { + throw new IllegalArgumentException("Article cannot be null"); + } + articles.add(article); + } + + public void addAll(List
newArticles) { + if (newArticles == null) { + return; + } + + for (Article article : newArticles) { + if (article != null) { + articles.add(article); + } + } + } + + public List
getAll() { + return Collections.unmodifiableList(articles); + } + + public int size() { + return articles.size(); + } + + public void clear() { + articles.clear(); + } +} diff --git a/w11/RetryUtils.java b/w11/RetryUtils.java new file mode 100644 index 0000000..ec76908 --- /dev/null +++ b/w11/RetryUtils.java @@ -0,0 +1,30 @@ +package w11; + +public class RetryUtils { + + + private static final long BASE_DELAY_MS = 500; + + @FunctionalInterface + public interface RetryTask { + T run() throws Exception; + } + + + public static T retry(int maxRetries, RetryTask task) throws Exception { + int attempt = 0; + while (true) { + try { + return task.run(); + } catch (Exception e) { + if (attempt >= maxRetries) { + throw e; + } + + long delay = BASE_DELAY_MS * (1L << attempt); + Thread.sleep(delay); + attempt++; + } + } + } +} \ No newline at end of file diff --git a/w11/UrlFormatException.java b/w11/UrlFormatException.java new file mode 100644 index 0000000..2334009 --- /dev/null +++ b/w11/UrlFormatException.java @@ -0,0 +1,12 @@ +package w11; + + +public class UrlFormatException extends RuntimeException { + + public UrlFormatException(String message) { + super(message); + } + + public UrlFormatException(String message, Throwable cause) { + super(message, cause); + } \ No newline at end of file