5 changed files with 248 additions and 0 deletions
@ -0,0 +1,11 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
/** |
||||
|
* 命令接口 - 命令模式 |
||||
|
* 课堂知识点:命令模式、接口 |
||||
|
*/ |
||||
|
public interface Command { |
||||
|
void execute() throws CrawlerException; |
||||
|
void undo(); |
||||
|
String getDescription(); |
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
/** |
||||
|
* 命令调用器 - 命令模式 |
||||
|
* 课堂知识点:命令模式、集合框架 |
||||
|
*/ |
||||
|
public class CommandInvoker { |
||||
|
private final List<Command> history = new ArrayList<>(); |
||||
|
private int currentIndex = -1; |
||||
|
|
||||
|
public void execute(Command cmd) throws CrawlerException { |
||||
|
cmd.execute(); |
||||
|
if (currentIndex < history.size() - 1) { |
||||
|
history.subList(currentIndex + 1, history.size()).clear(); |
||||
|
} |
||||
|
history.add(cmd); |
||||
|
currentIndex++; |
||||
|
} |
||||
|
|
||||
|
public void undo() { |
||||
|
if (currentIndex < 0) { |
||||
|
System.out.println("没有可撤销的命令"); |
||||
|
return; |
||||
|
} |
||||
|
history.get(currentIndex).undo(); |
||||
|
currentIndex--; |
||||
|
} |
||||
|
|
||||
|
public void showHistory() { |
||||
|
System.out.println("\n========== 命令历史 =========="); |
||||
|
if (history.isEmpty()) { |
||||
|
System.out.println("暂无命令历史"); |
||||
|
} else { |
||||
|
for (int i = 0; i < history.size(); i++) { |
||||
|
String marker = (i == currentIndex) ? "→" : " "; |
||||
|
System.out.printf("%s %2d. %s\n", marker, i + 1, history.get(i).getDescription()); |
||||
|
} |
||||
|
} |
||||
|
System.out.println("=============================="); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,106 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* 爬虫基类 - 定义爬虫的通用行为和属性 |
||||
|
* 课堂知识点:继承、抽象类、封装 |
||||
|
*/ |
||||
|
public abstract class Crawler { |
||||
|
|
||||
|
/** |
||||
|
* 请求间隔时间(毫秒)- 避免被网站封禁 |
||||
|
*/ |
||||
|
protected static final int DELAY_MS = 1000; |
||||
|
|
||||
|
/** |
||||
|
* 爬取状态:是否成功 |
||||
|
*/ |
||||
|
private boolean success; |
||||
|
|
||||
|
/** |
||||
|
* 爬取的数据数量 |
||||
|
*/ |
||||
|
private int dataCount; |
||||
|
|
||||
|
/** |
||||
|
* 爬取数据 - 抽象方法,子类必须实现 |
||||
|
* 课堂知识点:抽象方法 |
||||
|
*/ |
||||
|
public abstract void crawl(); |
||||
|
|
||||
|
/** |
||||
|
* 打印结果 - 抽象方法,子类必须实现 |
||||
|
*/ |
||||
|
public abstract void printResults(); |
||||
|
|
||||
|
/** |
||||
|
* 保存数据到文件 - 抽象方法,子类必须实现 |
||||
|
*/ |
||||
|
public abstract void saveToFile(String filename) throws IOException; |
||||
|
|
||||
|
/** |
||||
|
* 保存数据到数据库 - 抽象方法,子类必须实现 |
||||
|
* 课堂知识点:JDBC、数据库持久化 |
||||
|
*/ |
||||
|
public abstract void saveToDatabase(); |
||||
|
|
||||
|
/** |
||||
|
* 检查网络状态 |
||||
|
* @return 网络是否可用 |
||||
|
*/ |
||||
|
protected boolean isNetworkAvailable() { |
||||
|
return HttpCrawler.isNetworkAvailable(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 添加请求延迟,避免被封禁 |
||||
|
*/ |
||||
|
protected void delay() { |
||||
|
try { |
||||
|
Thread.sleep(DELAY_MS); |
||||
|
} catch (InterruptedException e) { |
||||
|
Thread.currentThread().interrupt(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取爬取状态 |
||||
|
* @return 是否成功 |
||||
|
*/ |
||||
|
public boolean isSuccess() { |
||||
|
return success; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置爬取状态 |
||||
|
* @param success 是否成功 |
||||
|
*/ |
||||
|
protected void setSuccess(boolean success) { |
||||
|
this.success = success; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取数据数量 |
||||
|
* @return 数据数量 |
||||
|
*/ |
||||
|
public int getDataCount() { |
||||
|
return dataCount; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置数据数量 |
||||
|
* @param dataCount 数据数量 |
||||
|
*/ |
||||
|
protected void setDataCount(int dataCount) { |
||||
|
this.dataCount = dataCount; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取爬虫名称(默认实现,子类可重写) |
||||
|
* @return 爬虫名称 |
||||
|
*/ |
||||
|
public String getCrawlerName() { |
||||
|
return this.getClass().getSimpleName(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
/** |
||||
|
* 爬虫命令 - 命令模式实现 |
||||
|
*/ |
||||
|
public class CrawlerCommand implements Command { |
||||
|
private final Crawler crawler; |
||||
|
private final String filename; |
||||
|
private boolean executed; |
||||
|
|
||||
|
public CrawlerCommand(Crawler crawler, String filename) { |
||||
|
this.crawler = crawler; |
||||
|
this.filename = filename; |
||||
|
this.executed = false; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void execute() throws CrawlerException { |
||||
|
if (executed) { |
||||
|
throw new CrawlerException("命令已经执行过"); |
||||
|
} |
||||
|
try { |
||||
|
System.out.println("执行: " + getDescription()); |
||||
|
crawler.crawl(); |
||||
|
crawler.printResults(); |
||||
|
crawler.saveToFile(filename); |
||||
|
executed = true; |
||||
|
} catch (Exception e) { |
||||
|
throw new CrawlerException("执行失败: " + e.getMessage(), e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void undo() { |
||||
|
if (!executed) { |
||||
|
System.out.println("命令未执行,无法撤销"); |
||||
|
return; |
||||
|
} |
||||
|
System.out.println("撤销: " + getDescription()); |
||||
|
executed = false; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getDescription() { |
||||
|
return crawler.getCrawlerName() + " -> " + filename; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
package com.example; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
/** |
||||
|
* 爬虫异常基类 - 异常体系 |
||||
|
* 课堂知识点:自定义异常、异常继承体系 |
||||
|
*/ |
||||
|
public class CrawlerException extends Exception { |
||||
|
public CrawlerException(String message) { |
||||
|
super(message); |
||||
|
} |
||||
|
public CrawlerException(String message, Throwable cause) { |
||||
|
super(message, cause); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 网络异常 - 网络连接失败 |
||||
|
*/ |
||||
|
class NetworkException extends CrawlerException { |
||||
|
public NetworkException(String message) { super(message); } |
||||
|
public NetworkException(String message, Throwable cause) { super(message, cause); } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 数据解析异常 - HTML/JSON解析失败 |
||||
|
*/ |
||||
|
class DataParseException extends CrawlerException { |
||||
|
public DataParseException(String message) { super(message); } |
||||
|
public DataParseException(String message, Throwable cause) { super(message, cause); } |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 文件保存异常 - 文件写入失败 |
||||
|
*/ |
||||
|
class FileSaveException extends CrawlerException { |
||||
|
public FileSaveException(String message) { super(message); } |
||||
|
public FileSaveException(String message, IOException cause) { super(message, cause); } |
||||
|
} |
||||
Loading…
Reference in new issue