From b9a30294333a88b62fc4ce92108c0bf265a4cc84 Mon Sep 17 00:00:00 2001 From: Mengxinyao Date: Thu, 4 Jun 2026 22:07:54 +0800 Subject: [PATCH] =?UTF-8?q?feat(w12):W12-=E5=AD=9F=E9=91=AB=E5=9E=9A-20250?= =?UTF-8?q?6010204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- w12/.DS_Store | Bin 0 -> 6148 bytes w12/App.java | 63 ++++++++++++++ w12/repository/ArticleRepository.java | 18 ++++ w12/repository/InMemoryArticleRepository.java | 78 ++++++++++++++++++ 4 files changed, 159 insertions(+) create mode 100644 w12/.DS_Store create mode 100644 w12/App.java create mode 100644 w12/repository/ArticleRepository.java create mode 100644 w12/repository/InMemoryArticleRepository.java diff --git a/w12/.DS_Store b/w12/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..97af285e71ee97f5a3de39f6cc0d56d28e6bfee7 GIT binary patch literal 6148 zcmeHK%TDVs5FM9taY0C3Tm(x?Y%3^;*VWyG0t>bT!2(c8XmxKO#8r|~p{i20@G~s= z6MhF~Y!`tF5-UJxCK{iyJtvRj$PWMzjc#iRpb7vIov>8F;tivI@)0Y!mNKF+_c(_D zt{~Wr_1Q=^H+)A0XzV0xLI|8iK8s9*B?Y_tUUf}LQcpjdE)=qJwFffZq^9WBdYCd9f!j>2oIum zuUY-QrIS2}l6GncQLBw9$A?kU(!GZ6CauhHecK@`veK;1_WP^rHMP97F{r8jpXGW@ zt*osK1{FCozxa2rc@bYG`o?@P2>iW`O*+Hy78bDwO;{?T zr3!b%5SEVZ%H??u3yYQx!W}+@d$MpR6k(o@_g5wzglCaUR)7_Ft-zSAR%!j;dH?+X zn#46$fED;r3W)Nyzumx3a%=0z$I)7=&`;6HD6g>iOu@h`#h6P=@f^A_Y*!Q@dJYSV R*n-9z0V4w!tiY!#@B}4gX~F;i literal 0 HcmV?d00001 diff --git a/w12/App.java b/w12/App.java new file mode 100644 index 0000000..a7b17d4 --- /dev/null +++ b/w12/App.java @@ -0,0 +1,63 @@ +package com.crawler; + +import com.crawler.command.*; +import com.crawler.controller.CrawlerController; +import com.crawler.repository.ArticleRepository; +import com.crawler.repository.InMemoryArticleRepository; +import com.crawler.view.ConsoleView; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +public class App { + private final Map commands = new HashMap<>(); + private final ConsoleView view; + private final AtomicBoolean running = new AtomicBoolean(true); + + public App() { + view = new ConsoleView(); + ArticleRepository repository = new InMemoryArticleRepository(); + CrawlerController controller = new CrawlerController(repository, view); + + commands.put("crawl", new CrawlCommand(controller, view)); + commands.put("list", new ListCommand(controller)); + commands.put("save", new SaveCommand(controller)); + commands.put("load", new LoadCommand(controller)); + commands.put("help", new HelpCommand(view)); + commands.put("exit", new ExitCommand(view, () -> running.set(false))); + } + + public void run() { + view.displayWelcome(); + view.displayHelp(); + + while (running.get()) { + try { + String input = view.readInput(); + if (input.isEmpty()) { + continue; + } + + String[] parts = input.split("\\s+", 3); + String commandName = parts[0].toLowerCase(); + String[] args = parts.length > 1 ? java.util.Arrays.copyOfRange(parts, 1, parts.length) : new String[0]; + + Command command = commands.get(commandName); + if (command != null) { + command.execute(args); + } else { + view.displayError("Unknown command: " + commandName); + view.displayInfo("Type 'help' for available commands"); + } + } catch (Exception e) { + view.displayError("Error: " + e.getMessage()); + } + } + } + + public static void main(String[] args) { + App app = new App(); + app.run(); + } +} diff --git a/w12/repository/ArticleRepository.java b/w12/repository/ArticleRepository.java new file mode 100644 index 0000000..0feb516 --- /dev/null +++ b/w12/repository/ArticleRepository.java @@ -0,0 +1,18 @@ +package com.crawler.repository; + +import com.crawler.model.Article; +import java.util.List; +import java.util.Optional; + +public interface ArticleRepository { + void save(Article article); + void saveAll(List
articles); + Optional
findById(String id); + Optional
findByUrl(String url); + List
findAll(); + List
findBySource(String source); + void deleteById(String id); + void deleteAll(); + int count(); + boolean existsByUrl(String url); +} diff --git a/w12/repository/InMemoryArticleRepository.java b/w12/repository/InMemoryArticleRepository.java new file mode 100644 index 0000000..31c5578 --- /dev/null +++ b/w12/repository/InMemoryArticleRepository.java @@ -0,0 +1,78 @@ +package com.crawler.repository; + +import com.crawler.model.Article; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class InMemoryArticleRepository implements ArticleRepository { + private final Map articles = new ConcurrentHashMap<>(); + private final Map urlToIdMap = new ConcurrentHashMap<>(); + private final AtomicInteger idGenerator = new AtomicInteger(1); + + @Override + public void save(Article article) { + if (article.getId() == null) { + article.setId(String.valueOf(idGenerator.getAndIncrement())); + } + articles.put(article.getId(), article); + if (article.getUrl() != null) { + urlToIdMap.put(article.getUrl(), article.getId()); + } + } + + @Override + public void saveAll(List
articleList) { + for (Article article : articleList) { + save(article); + } + } + + @Override + public Optional
findById(String id) { + return Optional.ofNullable(articles.get(id)); + } + + @Override + public Optional
findByUrl(String url) { + String id = urlToIdMap.get(url); + return id != null ? Optional.ofNullable(articles.get(id)) : Optional.empty(); + } + + @Override + public List
findAll() { + return new ArrayList<>(articles.values()); + } + + @Override + public List
findBySource(String source) { + return articles.values().stream() + .filter(a -> source.equals(a.getSource())) + .collect(Collectors.toList()); + } + + @Override + public void deleteById(String id) { + Article article = articles.remove(id); + if (article != null && article.getUrl() != null) { + urlToIdMap.remove(article.getUrl()); + } + } + + @Override + public void deleteAll() { + articles.clear(); + urlToIdMap.clear(); + } + + @Override + public int count() { + return articles.size(); + } + + @Override + public boolean existsByUrl(String url) { + return urlToIdMap.containsKey(url); + } +}