Compare commits
2 Commits
644f238d39
...
b52a272802
| Author | SHA1 | Date |
|---|---|---|
|
|
b52a272802 | 1 month ago |
|
|
0f9933df8e | 2 months ago |
13 changed files with 338 additions and 0 deletions
@ -0,0 +1,38 @@ |
|||||
|
public class Pair<K, V> { |
||||
|
private K key; |
||||
|
private V value; |
||||
|
|
||||
|
// 构造方法
|
||||
|
public Pair(K key, V value) { |
||||
|
this.key = key; |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
// Getter/Setter
|
||||
|
public K getKey() { |
||||
|
return key; |
||||
|
} |
||||
|
|
||||
|
public void setKey(K key) { |
||||
|
this.key = key; |
||||
|
} |
||||
|
|
||||
|
public V getValue() { |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
public void setValue(V value) { |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
// ✅ 修复后的静态 swap 方法
|
||||
|
public static <K, V> Pair<V, K> swap(Pair<K, V> pair) { |
||||
|
return new Pair<>(pair.getValue(), pair.getKey()); |
||||
|
} |
||||
|
|
||||
|
// 重写 toString
|
||||
|
@Override |
||||
|
public String toString() { |
||||
|
return "Pair{" + "key=" + key + ", value=" + value + '}'; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
public class TestPairSwap { |
||||
|
public static void main(String[] args) { |
||||
|
// 1. 原始 Pair:String + Integer(姓名-年龄)
|
||||
|
Pair<String, Integer> person = new Pair<>("张三", 20); |
||||
|
System.out.println("交换前:" + person); |
||||
|
|
||||
|
// 2. 调用静态 swap 方法,得到交换后的 Pair
|
||||
|
Pair<Integer, String> swappedPerson = Pair.swap(person); |
||||
|
System.out.println("交换后:" + swappedPerson); |
||||
|
|
||||
|
// 3. 相同类型的 Pair 也可以正常使用
|
||||
|
Pair<Double, Double> point = new Pair<>(116.40, 39.90); |
||||
|
System.out.println("交换前坐标:" + point); |
||||
|
Pair<Double, Double> swappedPoint = Pair.swap(point); |
||||
|
System.out.println("交换后坐标:" + swappedPoint); |
||||
|
} |
||||
|
} |
||||
@ -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