11 changed files with 283 additions and 0 deletions
@ -0,0 +1,21 @@ |
|||
package src.main.java.com.example.datacollect; |
|||
|
|||
import src.main.java.com.example.datacollect.controller.CrawlerController; |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
public class Main { |
|||
|
|||
public static void main(String[] args) { |
|||
ConsoleView view = new ConsoleView(); |
|||
List<Article> articles = new ArrayList<>(); |
|||
CrawlerController controller = new CrawlerController(view, articles); |
|||
|
|||
view.printSuccess("Welcome to CLI Crawler (w9_1)! Type help for commands."); |
|||
while (true) { |
|||
controller.handle(view.readLine()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import java.util.List; |
|||
|
|||
public interface Command { |
|||
String getName(); |
|||
void execute(String[] args, List<Article> articles); |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.List; |
|||
|
|||
public class CrawlCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public CrawlCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "crawl"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args, List<Article> articles) { |
|||
if (args.length < 2) { |
|||
view.printError("Usage: crawl <url>"); |
|||
return; |
|||
} |
|||
view.printInfo("Stub: would crawl " + args[1]); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.List; |
|||
|
|||
public class ExitCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public ExitCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "exit"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args, List<Article> articles) { |
|||
view.printSuccess("Bye!"); |
|||
System.exit(0); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.List; |
|||
|
|||
public class HelpCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public HelpCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "help"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args, List<Article> articles) { |
|||
view.printInfo("Commands: crawl <url>, list, help, exit"); |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.List; |
|||
|
|||
public class ListCommand implements Command { |
|||
private final ConsoleView view; |
|||
|
|||
public ListCommand(ConsoleView view) { |
|||
this.view = view; |
|||
} |
|||
|
|||
@Override |
|||
public String getName() { |
|||
return "list"; |
|||
} |
|||
|
|||
@Override |
|||
public void execute(String[] args, List<Article> articles) { |
|||
view.display(articles); |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
package src.main.java.com.example.datacollect.controller; |
|||
|
|||
import Command; |
|||
import com.example.datacollect.command.CrawlCommand; |
|||
import ExitCommand; |
|||
import HelpCommand; |
|||
import ListCommand; |
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import src.main.java.com.example.datacollect.view.ConsoleView; |
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
public class CrawlerController { |
|||
private final Map<String, Command> commands = new HashMap<>(); |
|||
private final ConsoleView view; |
|||
private final List<Article> articles; |
|||
|
|||
public CrawlerController(ConsoleView view, List<Article> articles) { |
|||
this.view = view; |
|||
this.articles = articles; |
|||
register(new HelpCommand(view)); |
|||
register(new ListCommand(view)); |
|||
register(new CrawlCommand(view)); |
|||
register(new ExitCommand(view)); |
|||
} |
|||
|
|||
private void register(Command command) { |
|||
commands.put(command.getName(), command); |
|||
} |
|||
|
|||
public void handle(String input) { |
|||
String text = input == null ? "" : input.trim(); |
|||
if (text.isEmpty()) { |
|||
return; |
|||
} |
|||
|
|||
String[] args = text.split("\\s+"); |
|||
String cmdName = args[0].toLowerCase(); |
|||
Command command = commands.get(cmdName); |
|||
if (command == null) { |
|||
view.printError("Unknown command: " + cmdName); |
|||
return; |
|||
} |
|||
command.execute(args, articles); |
|||
} |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
package src.main.java.com.example.datacollect.model; |
|||
|
|||
import java.time.LocalDateTime; |
|||
import java.time.format.DateTimeFormatter; |
|||
|
|||
public class Article { |
|||
private String title; |
|||
private String url; |
|||
private String content; |
|||
|
|||
// ========== 新增字段 ==========
|
|||
private String author; // 作者
|
|||
private LocalDateTime publishDate; // 发布日期
|
|||
// ============================
|
|||
|
|||
// ========== 原有构造器(保留兼容性)==========
|
|||
public Article(String title, String url, String content) { |
|||
this.title = title; |
|||
this.url = url; |
|||
this.content = content; |
|||
this.author = "未知"; // 默认值
|
|||
this.publishDate = LocalDateTime.now(); // 默认当前时间
|
|||
} |
|||
|
|||
// ========== 新增全参数构造器(推荐使用)==========
|
|||
public Article(String title, String url, String content, String author, LocalDateTime publishDate) { |
|||
this.title = title; |
|||
this.url = url; |
|||
this.content = content; |
|||
this.author = author; |
|||
this.publishDate = publishDate; |
|||
} |
|||
|
|||
// ========== Getter / Setter ==========
|
|||
public String getTitle() { return title; } |
|||
public void setTitle(String title) { this.title = title; } |
|||
|
|||
public String getUrl() { return url; } |
|||
public void setUrl(String url) { this.url = url; } |
|||
|
|||
public String getContent() { return content; } |
|||
public void setContent(String content) { this.content = content; } |
|||
|
|||
// ========== 新增字段的 Getter / Setter ==========
|
|||
public String getAuthor() { return author; } |
|||
public void setAuthor(String author) { this.author = author; } |
|||
|
|||
public LocalDateTime getPublishDate() { return publishDate; } |
|||
public void setPublishDate(LocalDateTime publishDate) { this.publishDate = publishDate; } |
|||
|
|||
// ========== 日期格式化辅助方法 ==========
|
|||
public String getFormattedPublishDate() { |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
|||
return publishDate.format(formatter); |
|||
} |
|||
|
|||
public String getFormattedPublishDate(String pattern) { |
|||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); |
|||
return publishDate.format(formatter); |
|||
} |
|||
|
|||
// ========== 修改 toString() 包含新字段 ==========
|
|||
@Override |
|||
public String toString() { |
|||
return "Article{" + |
|||
"title='" + title + '\'' + |
|||
", url='" + url + '\'' + |
|||
", author='" + author + '\'' + |
|||
", publishDate=" + getFormattedPublishDate() + |
|||
'}'; |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
package src.main.java.com.example.datacollect.view; |
|||
|
|||
import src.main.java.com.example.datacollect.model.Article; |
|||
import java.util.List; |
|||
import java.util.Scanner; |
|||
|
|||
public class ConsoleView { |
|||
private static final String ANSI_RESET = "\u001B[0m"; |
|||
private static final String ANSI_GREEN = "\u001B[32m"; |
|||
private static final String ANSI_RED = "\u001B[31m"; |
|||
private static final String ANSI_BLUE = "\u001B[34m"; |
|||
|
|||
private final Scanner scanner = new Scanner(System.in); |
|||
|
|||
public String readLine() { |
|||
System.out.print("> "); |
|||
return scanner.nextLine(); |
|||
} |
|||
|
|||
public void printSuccess(String msg) { |
|||
System.out.println(ANSI_GREEN + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void printError(String msg) { |
|||
System.out.println(ANSI_RED + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void printInfo(String msg) { |
|||
System.out.println(ANSI_BLUE + msg + ANSI_RESET); |
|||
} |
|||
|
|||
public void display(List<Article> articles) { |
|||
if (articles.isEmpty()) { |
|||
printInfo("暂无文章,请先执行 crawl。"); |
|||
return; |
|||
} |
|||
for (int i = 0; i < articles.size(); i++) { |
|||
Article a = articles.get(i); |
|||
System.out.println((i + 1) + ". " + a.getTitle() + " | " + a.getUrl()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
#Generated by Maven |
|||
#Thu Apr 30 11:50:54 CST 2026 |
|||
artifactId=datacollect-cli |
|||
groupId=com.example |
|||
version=0.1.0 |
|||
Loading…
Reference in new issue