捕鱼达人Java游戏开发实战:源码分析与功能扩展
通过对《捕鱼达人》Java源码的剖析,我们不仅学习了游戏开发的基本范式(游戏循环、对象管理、碰撞检测),更重要的是掌握了对其进行现代化改造的思路与方法。从简单的AWT/Swing演示项目,到基于LibGDX框架、具备丰富功能、支持网络互动的完整游戏,这个过程本身就是一次宝贵的学习之旅。随着技术的演进,我们甚至可以探索将AI技术融入例如使用机器学习模型来识别鱼的游动模式,实现“智能自瞄”等趣味功能。
好的,请看这篇根据您的要求撰写的,符合CSDN社区风格的技术文章。
《捕鱼达人》Java游戏开发实战:从源码剖析到现代技术栈的功能扩展
摘要:作为一款经典的休闲游戏,《捕鱼达人》是许多开发者入门游戏开发的绝佳练手项目。本文将以一个典型的Java版《捕鱼达人》源码为基础,深入剖析其核心架构与实现原理,并重点探讨如何利用现代技术栈对其进行功能扩展与性能优化,赋予经典项目新的生命力。
关键词:Java游戏开发、捕鱼达人、源码分析、游戏循环、对象池、功能扩展、LibGDX
一、 经典源码核心架构剖析
一个基础的《捕鱼达人》Java实现(通常基于AWT/Swing或早期游戏框架)通常包含以下几个核心模块,理解它们是进行功能扩展的前提。
1. 游戏循环与线程管理
游戏的核心是“循环”。源码中通常会有一个主线程(或游戏线程)负责驱动整个游戏逻辑。
```java
// 简化的游戏循环伪代码
public void run() {
while (running) {
long startTime = System.nanoTime();
// 1. 处理用户输入(点击发射、退出等)
processInput();
// 2. 更新游戏状态(鱼群移动、子弹飞行、碰撞检测)
updateGameLogic();
// 3. 渲染画面(绘制背景、鱼、子弹、炮台、UI)
render();
// 4. 睡眠控制,稳定FPS
long updateTime = System.nanoTime() - startTime;
long targetTime = 1_000_000_000L / TARGET_FPS; // 例如 60FPS
if (updateTime < targetTime) {
Thread.sleep((targetTime - updateTime) / 1_000_000);
}
}
}
``
技术要点:早期的实现可能直接使用
Thread.sleep` 进行帧率控制,但这并不精确。现代做法更倾向于使用时间步长固定游戏逻辑,并与渲染帧率解耦,以保证在不同性能设备上游戏体验的一致性。
2. 游戏对象管理:鱼、子弹、特效
游戏中有大量动态生成和销毁的对象,如鱼群和子弹。直接new
和由GC回收会带来性能抖动。
- 对象池模式:优秀的源码会采用对象池来管理这些短生命周期对象。例如,创建一个
BulletPool
和FishPool
。当需要发射子弹时,从对象池中获取一个可用的子弹对象并初始化其状态(位置、角度等),而不是新建。当子弹命中或出界后,将其状态重置并放回池中,等待下次使用。这极大地减少了JVM垃圾回收的压力,是保证游戏流畅的关键。
3. 碰撞检测
《捕鱼达人》的碰撞检测相对简单,通常是圆形或矩形边界框检测。
实现:遍历所有子弹和所有鱼,计算两者中心的距离,若距离小于子弹半径与鱼半径之和,则判定为碰撞。
优化:可以通过空间划分(如网格法)来优化,避免不必要的遍历。例如,将屏幕划分为网格,只检测与子弹处于同一网格或相邻网格的鱼。
二、 功能扩展与现代化改造实战
在理解了经典架构后,我们可以对其进行大刀阔斧的扩展,使其更接近现代手游的水平。
1. 使用现代游戏框架:从AWT/Swing迁移到LibGDX
AWT/Swing并非为高性能游戏设计。强烈建议将项目迁移至专业的Java游戏框架,如LibGDX。LibGDX提供了强大的2D/3D图形渲染、音频管理、输入处理和跨平台部署支持。
- 优势:
- 高性能渲染:基于OpenGL,充分利用GPU硬件加速。
- 精灵批处理:
SpriteBatch
能将多个绘制调用合并,极大提升渲染效率。 - 强大的工具链:内置了纹理打包器(TexturePacker)、粒子编辑器等,方便资源管理。
- 一次编写,多平台部署:可轻松发布为Desktop(Windows/Linux/macOS)、Android、iOS和Web版本。
2. 扩展丰富的游戏功能
-
武器系统升级:
- 实现多种炮台:*冻炮(减速鱼)、激光炮(穿透)、散射炮(一次多发)。这需要为子弹添加新的属性(如
bulletType
、damage
、specialEffect
),并在碰撞检测后触发不同效果。 - 技能系统:实现“全屏炸弹”、“金币翻倍”等限时技能。这涉及到技能CD管理、全局状态影响和炫酷的全屏特效。
-
关卡与剧情模式:
- 设计由易到难的关卡,每关有特定的目标(如捕获指定种类的鱼、在限定时间内获得一定金币)。
- 引入Boss战,在特定波次出现拥有高血量和高攻击力的Boss鱼,击败后获得大量奖励。
-
网络功能集成:
- 排行榜:集成第三方服务(如腾讯的LeanCloud、友盟)或自建后端,实现本地和全球排行榜,激发玩家竞争欲望。
- 多人同屏:这是一个高级扩展。可以使用Netty或WebSocket库实现简单的多人联机,多个玩家在同一个场景中捕鱼,可以看到彼此的炮台和捕获效果,增加互动性。此时,游戏逻辑(鱼群生成、移动、碰撞)需要在服务端进行权威计算,客户端主要负责表现和输入转发。
3. 性能与体验优化进阶
- 粒子系统替代简单动画:使用LibGDX的粒子效果编辑器创建爆炸、水波纹、捕获金币等特效,视觉效果远超简单的图片序列帧动画。
- 资源异步加载:在场景切换时(如从主菜单进入游戏),使用进度条和异步加载方式加载图片、声音资源,避免界面卡顿。
- 音频管理:统一管理音效和背景音乐,实现音量控制、音效池(避免同一音效短时间高频播放造成的重叠和中断)。
三、 总结与展望
通过对《捕鱼达人》Java源码的剖析,我们不仅学习了游戏开发的基本范式(游戏循环、对象管理、碰撞检测),更重要的是掌握了对其进行现代化改造的思路与方法。
从简单的AWT/Swing演示项目,到基于LibGDX框架、具备丰富功能、支持网络互动的完整游戏,这个过程本身就是一次宝贵的学习之旅。随着技术的演进,我们甚至可以探索将AI技术融入例如使用机器学习模型来识别鱼的游动模式,实现“智能自瞄”等趣味功能。
参考资料:
1. LibGDX官方Wiki与API文档 (https://libgdx.com/wiki/) - 现代Java游戏开发首选框架。
2. 《Game Programming Patterns》 by Robert Nystrom - 深入理解游戏循环、对象池等设计模式。
3. Agora(声网)实时互动API文档 - 如需实现实时语音聊天等高级网络功能。
4. Box2D物理引擎文档 - 如需为游戏加入更复杂的物理效果(如鱼的受击反馈)。
经典项目的价值在于其清晰的逻辑,而我们的任务就是用当今最强大的技术工具,去挖掘和实现其更多的可能性。希望本文能为你的《捕鱼达人》重构与扩展之路带来启发。
面向OWASP Top 10的Java安全扫描工具:漏洞规则库与特征匹配模块深度解析
摘要
本文深入探讨了面向OWASP Top 10的Java安全扫描工具的核心设计原理,重点分析漏洞规则库构建与特征匹配模块的实现机制。通过详细的代码实例和架构设计解析,为开发人员构建企业级安全扫描工具提供实践指导。
1. 引言
OWASP Top 10作为Web应用程序安全风险的权威指南,为安全扫描工具提供了明确的目标。本文将基于最新的OWASP Top 10 2021版本,构建一个专业的Java安全扫描工具,重点解析其核心组件——漏洞规则库和特征匹配模块。
2. 漏洞规则库架构设计
2.1 规则库整体架构
```java
// 规则库核心接口定义
public interface VulnerabilityRule {
String getRuleId();
String getCWEId();
RiskLevel getRiskLevel();
boolean match(ScanContext context);
VulnerabilityDetail getVulnerabilityDetail();
}
// 规则库管理器
@Component
public class RuleManager {
private Map ruleRegistry = new ConcurrentHashMap<>();
private RuleLoader ruleLoader;
public void loadRules(String rulePath) {
List<VulnerabilityRule> rules = ruleLoader.loadFromDirectory(rulePath);
rules.forEach(rule -> ruleRegistry.put(rule.getRuleId(), rule));
}
public List<VulnerabilityRule> getRulesByCategory(RuleCategory category) {
return ruleRegistry.values().stream()
.filter(rule -> rule.getCategory() == category)
.collect(Collectors.toList());
}
}
```
2.2 基于YAML的规则定义
```yaml
rules/sql-injection.yaml
ruleId: "SQLI-001"
name: "SQL Injection Detection"
category: "INJECTION"
cwe: "CWE-89"
riskLevel: "HIGH"
description: "Detects potential SQL injection vulnerabilities"
patterns:
- type: "CODE_PATTERN"
pattern: "Statement\.executeQuery\(.\+.\)"
confidence: "HIGH"
- type: "API_PATTERN"
pattern: "PreparedStatement|ParameterizedQuery"
isSafe: true
confidence: "MEDIUM"
triggers:
- sink: "executeQuery"
sources: ["request.getParameter", "request.getHeader"]
```
2.3 动态规则加载机制
```java
@Configuration
@EnableConfigurationProperties(RuleProperties.class)
public class RuleConfiguration {
@Bean
@ConditionalOnProperty(name = "scanner.rules.auto-reload", havingValue = "true")
public FileWatchService fileWatchService(RuleManager ruleManager) {
return new FileWatchService(ruleManager);
}
}
// 文件监*服务,支持热更新规则
public class FileWatchService implements InitializingBean {
private final RuleManager ruleManager;
private WatchService watchService;
@Override
public void afterPropertiesSet() throws Exception {
Path rulesPath = Paths.get("rules");
watchService = FileSystems.getDefault().newWatchService();
rulesPath.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
new Thread(this::watchRuleChanges).start();
}
private void watchRuleChanges() {
while (true) {
WatchKey key = watchService.take();
for (WatchEvent<?> event : key.pollEvents()) {
if (event.kind() == ENTRY_MODIFY) {
ruleManager.reloadRules();
}
}
key.reset();
}
}
}
```
3. 特征匹配引擎设计
3.1 多模式匹配算法
```java
public class PatternMatcher {
private AhoCorasickDoubleArrayTrie acdat;
private List patternRules;
public void buildMatcher(List<PatternRule> rules) {
this.patternRules = rules;
TreeMap<String, String> map = new TreeMap<>();
for (PatternRule rule : rules) {
map.put(rule.getPattern(), rule.getRuleId());
}
acdat = new AhoCorasickDoubleArrayTrie<>();
acdat.build(map);
}
public List<MatchResult> match(String text) {
List<MatchResult> results = new ArrayList<>();
acdat.parseText(text, (begin, end, value) -> {
results.add(new MatchResult(begin, end, value, text.substring(begin, end)));
});
return results;
}
}
// 匹配结果封装
@Data
@AllArgsConstructor
class MatchResult {
private int start;
private int end;
private String ruleId;
private String matchedText;
private double confidence;
public MatchResult(int start, int end, String ruleId, String matchedText) {
this(start, end, ruleId, matchedText, 1.0);
}
}
```
3.2 抽象语法树(AST)分析
```java
// 基于JavaParser的AST分析器
@Component
public class ASTAnalyzer {
private final JavaParser javaParser;
public ASTAnalysisResult analyze(File javaFile) {
try {
CompilationUnit cu = javaParser.parse(javaFile).getResult().get();
return analyzeCompilationUnit(cu);
} catch (FileNotFoundException e) {
throw new AnalysisException("File not found: " + javaFile.getPath(), e);
}
}
private ASTAnalysisResult analyzeCompilationUnit(CompilationUnit cu) {
ASTAnalysisResult result = new ASTAnalysisResult();
// 查找危险的方法调用
new MethodCallVisitor().visit(cu, result);
// 查找数据流
new DataFlowVisitor().visit(cu, result);
return result;
}
// 方法调用访问器
private static class MethodCallVisitor extends VoidVisitorAdapter<ASTAnalysisResult> {
@Override
public void visit(MethodCallExpr n, ASTAnalysisResult result) {
super.visit(n, result);
String methodName = n.getNameAsString();
if (isDangerousMethod(methodName)) {
result.addFinding(new Finding(
FindingType.DANGEROUS_METHOD,
n.getRange().orElse(null),
methodName
));
}
}
private boolean isDangerousMethod(String methodName) {
return DANGEROUS_METHODS.contains(methodName) ||
methodName.contains("execute") ||
methodName.contains("eval");
}
}
}
```
3.3 数据流跟踪分析
```java
// 污点分析引擎
@Component
public class TaintAnalysisEngine {
private final ControlFlowGraphBuilder cfgBuilder;
private final TaintTrackingRuleManager ruleManager;
public TaintAnalysisResult analyze(MethodDeclaration method) {
ControlFlowGraph cfg = cfgBuilder.build(method);
TaintAnalysisResult result = new TaintAnalysisResult();
// 构建数据流图
DataFlowGraph dataFlowGraph = buildDataFlowGraph(cfg);
// 执行污点传播分析
performTaintPropagation(dataFlowGraph, result);
return result;
}
private void performTaintPropagation(DataFlowGraph graph, TaintAnalysisResult result) {
Queue<DataFlowNode> queue = new LinkedList<>();
// 找到所有污点源
graph.getNodes().stream()
.filter(node -> isSource(node.getExpression()))
.forEach(node -> {
node.setTainted(true);
queue.add(node);
});
// 传播污点
while (!queue.isEmpty()) {
DataFlowNode current = queue.poll();
for (DataFlowEdge edge : graph.getOutEdges(current)) {
DataFlowNode successor = edge.getTarget();
if (!successor.isTainted() && isPropagator(edge)) {
successor.setTainted(true);
queue.add(successor);
// 检查是否是漏洞点
if (isSink(successor.getExpression())) {
result.addVulnerability(createVulnerability(current, successor));
}
}
}
}
}
}
```
4. OWASP Top 10漏洞检测实现
4.1 SQL注入检测
```java
@Component
public class SQLInjectionDetector implements VulnerabilityDetector {
private static final Pattern SQL_PATTERN =
Pattern.compile("(?i)(select|update|delete|insert).where.\$|\+");
@Override
public List<Vulnerability> detect(ScanContext context) {
List<Vulnerability> vulnerabilities = new ArrayList<>();
// 检测字符串拼接的SQL查询
context.getSourceFiles().forEach(file -> {
detectStringConcatenationSQL(file, vulnerabilities);
detectUnpreparedStatements(file, vulnerabilities);
});
return vulnerabilities;
}
private void detectStringConcatenationSQL(File file, List<Vulnerability> vulnerabilities) {
try {
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
Matcher matcher = SQL_PATTERN.matcher(content);
while (matcher.find()) {
Vulnerability vuln = Vulnerability.builder()
.type("SQL_INJECTION")
.file(file.getPath())
.lineNumber(calculateLineNumber(content, matcher.start()))
.description("Potential SQL injection vulnerability")
.severity(Severity.HIGH)
.build();
vulnerabilities.add(vuln);
}
} catch (IOException e) {
logger.error("Error reading file: " + file.getPath(), e);
}
}
}
```
4.2 XSS漏洞检测
```java
@Component
public class XSSDetector implements VulnerabilityDetector {
private final List
Pattern.compile("response\.getWriter\(\)\.write\(.\+.\)"),
Pattern.compile("out\.print\(.\+.\)")
);
@Override
public List<Vulnerability> detect(ScanContext context) {
return context.getSourceFiles().stream()
.flatMap(file -> detectXSSInFile(file).stream())
.collect(Collectors.toList());
}
private List<Vulnerability> detectXSSInFile(File file) {
List<Vulnerability> vulnerabilities = new ArrayList<>();
try {
CompilationUnit cu = JavaParser.parse(file);
new XSSVisitor(vulnerabilities, file).visit(cu, null);
} catch (Exception e) {
logger.error("Error analyzing file for XSS: " + file.getPath(), e);
}
return vulnerabilities;
}
private static class XSSVisitor extends VoidVisitorAdapter<Void> {
private final List<Vulnerability> vulnerabilities;
private final File file;
public XSSVisitor(List<Vulnerability> vulnerabilities, File file) {
this.vulnerabilities = vulnerabilities;
this.file = file;
}
@Override
public void visit(MethodCallExpr n, Void arg) {
if (isResponseWriteMethod(n) && hasUnescapedParameter(n)) {
Vulnerability vuln = createXSSVulnerability(n);
vulnerabilities.add(vuln);
}
super.visit(n, arg);
}
private boolean isResponseWriteMethod(MethodCallExpr n) {
String methodName = n.getNameAsString();
return "write".equals(methodName) || "print".equals(methodName);
}
}
}
```
4.3 敏感数据泄露检测
```java
@Component
public class SensitiveDataExposureDetector implements VulnerabilityDetector {
private final Pattern passwordPattern = Pattern.compile(
"(?i)(password|pwd|passwd|secret|key|token)=[\"']?([^\"'&]+)[\"']?"
);
private final Set<String> sensitiveHeaders = Set.of(
"authorization", "cookie", "x-api-key", "x-auth-token"
);
@Override
public List<Vulnerability> detect(ScanContext context) {
List<Vulnerability> vulnerabilities = new ArrayList<>();
detectHardcodedCredentials(context, vulnerabilities);
detectUnencryptedSensitiveData(context, vulnerabilities);
detectSensitiveHeadersLogging(context, vulnerabilities);
return vulnerabilities;
}
private void detectHardcodedCredentials(ScanContext context,
List<Vulnerability> vulnerabilities) {
context.getSourceFiles().forEach(file -> {
try {
String content = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
detectHardcodedPasswords(content, file, vulnerabilities);
} catch (IOException e) {
logger.error("Error reading file: " + file.getPath(), e);
}
});
}
private void detectHardcodedPasswords(String content, File file,
List<Vulnerability> vulnerabilities) {
Matcher matcher = passwordPattern.matcher(content);
while (matcher.find()) {
// 排除常见的测试密码和占位符
String passwordValue = matcher.group(2);
if (!isPlaceholderPassword(passwordValue)) {
vulnerabilities.add(createSensitiveDataVulnerability(
file, matcher.start(), "Hardcoded credential detected"));
}
}
}
}
```
5. 性能优化策略
5.1 并行扫描优化
```java
@Component
public class ParallelScanEngine {
private final ExecutorService executorService;
private final List detectors;
@Async
public CompletableFuture<ScanResult> scanProject(Project project) {
List<CompletableFuture<List<Vulnerability>>> futures = detectors.stream()
.map(detector -> CompletableFuture.supplyAsync(
() -> detector.detect(new ScanContext(project)), executorService))
.collect(Collectors.toList());
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> {
List<Vulnerability> allVulnerabilities = futures.stream()
.flatMap(future -> future.join().stream())
.collect(Collectors.toList());
return new ScanResult(project, allVulnerabilities);
});
}
@PreDestroy
public void shutdown() {
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
```
5.2 增量扫描机制
```java
@Component
public class IncrementalScanner {
private final GitService gitService;
private final FileHashService fileHashService;
public ScanResult incrementalScan(Project project) {
Set<String> modifiedFiles = getModifiedFilesSinceLastScan(project);
ScanContext context = new ScanContext(project, modifiedFiles);
if (modifiedFiles.isEmpty()) {
return ScanResult.empty(project);
}
List<Vulnerability> vulnerabilities = detectors.stream()
.parallel()
.flatMap(detector -> detector.detect(context).stream())
.collect(Collectors.toList());
return new ScanResult(project, vulnerabilities);
}
private Set<String> getModifiedFilesSinceLastScan(Project project) {
if (project.isGitRepository()) {
return gitService.getModifiedFilesSince(project.getLastScanCommit());
} else {
return fileHashService.getModifiedFilesSince(project.getLastScanTime());
}
}
}
```
6. 测试与验证
6.1 单元测试示例
```java
@SpringBootTest
class SQLInjectionDetectorTest {
@Autowired
private SQLInjectionDetector detector;
@Test
void testSQLInjectionDetection() {
// 准备测试数据
File testFile = createTestFile("Test.java",
"String sql = \"SELECT FROM users WHERE id = \" + request.getParameter(\"id\");\n" +
"statement.executeQuery(sql);");
ScanContext context = new ScanContext(Collections.singletonList(testFile));
// 执行检测
List<Vulnerability> vulnerabilities = detector.detect(context);
// 验证结果
assertThat(vulnerabilities).hasSize(1);
assertThat(vulnerabilities.get(0).getType()).isEqualTo("SQL_INJECTION");
}
@Test
void testSafeSQLDetection() {
File testFile = createTestFile("SafeTest.java",
"String sql = \"SELECT FROM users WHERE id = ?\";\n" +
"PreparedStatement stmt = connection.prepareStatement(sql);\n" +
"stmt.setString(1, request.getParameter(\"id\"));\n" +
"stmt.executeQuery();");
ScanContext context = new ScanContext(Collections.singletonList(testFile));
List<Vulnerability> vulnerabilities = detector.detect(context);
assertThat(vulnerabilities).isEmpty();
}
}
```
7. 总结与展望
本文详细介绍了面向OWASP Top 10的Java安全扫描工具中漏洞规则库构建与特征匹配模块的设计与实现。通过合理的架构设计、高效的匹配算法和完整的检测规则,构建了一个可扩展的企业级安全扫描工具。
未来的工作方向包括:
1. 支持更多漏洞类型的检测规则
2. 集成机器学习技术提高检测准确率
3. 增强跨语言扫描能力
4. 提供更详细的修复建议和自动化修复功能
通过持续优化和改进,这样的安全扫描工具将在软件开发生命周期中发挥越来越重要的作用,帮助开发团队及早发现和修复安全漏洞。
参考文献
- OWASP Top 10 2021 - https://owasp.org/www-project-top-ten/
- JavaParser: https://javaparser.org/
- Aho-Corasick算法论文
- 《Java安全编码标准》
本文代码示例基于Spring Boot框架和Java 11,实际使用时请根据具体环境进行调整。建议在生产环境中添加适当的异常处理和日志记录机制。
```java
public class IsInstanceDemo {
public static void main(String[] args) {
Object obj = "Hello World";
Number num = Integer.valueOf(42);
// 使用isInstance进行类型检查
System.out.println("obj是String类型: " + String.class.isInstance(obj));
System.out.println("obj是Integer类型: " + Integer.class.isInstance(obj));
System.out.println("num是Number类型: " + Number.class.isInstance(num));
System.out.println("num是Double类型: " + Double.class.isInstance(num));
// 与instanceof操作符对比
System.out.println("obj instanceof String: " + (obj instanceof String));
System.out.println("num instanceof Number: " + (num instanceof Number));
}
@IgnoreAuth
@PostMapping(value = "/login")
public R login(String username, String password, String captcha, HttpServletRequest request) {
UsersEntity user = userService.selectOne(new EntityWrapper<UsersEntity>().eq("username", username));
if(user==null || !user.getPassword().equals(password)) {
return R.error("账号或密码不正确");
}
String token = tokenService.generateToken(user.getId(),username, "users", user.getRole());
return R.ok().put("token", token);
}
@Override
public String generateToken(Long userid,String username, String tableName, String role) {
TokenEntity tokenEntity = this.selectOne(new EntityWrapper<TokenEntity>().eq("userid", userid).eq("role", role));
String token = CommonUtil.getRandomString(32);
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.add(Calendar.HOUR_OF_DAY, 1);
if(tokenEntity!=null) {
tokenEntity.setToken(token);
tokenEntity.setExpiratedtime(cal.getTime());
this.updateById(tokenEntity);
} else {
this.insert(new TokenEntity(userid,username, tableName, role, token, cal.getTime()));
}
return token;
}
/**
* 权限(Token)验证
*/
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
public static final String LOGIN_TOKEN_KEY = "Token";
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//支持跨域请求
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Token, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// 跨域时会首先发送一个OPTIONS请求,这里我们给OPTIONS请求直接返回正常状态
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
response.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth annotation;
if (handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
//从header中获取token
String token = request.getHeader(LOGIN_TOKEN_KEY);
/**
* 不需要验证权限的方法直接放过
*/
if(annotation!=null) {
return true;
}
TokenEntity tokenEntity = null;
if(StringUtils.isNotBlank(token)) {
tokenEntity = tokenService.getTokenEntity(token);
}
if(tokenEntity != null) {
request.getSession().setAttribute("userId", tokenEntity.getUserid());
request.getSession().setAttribute("role", tokenEntity.getRole());
request.getSession().setAttribute("tableName", tokenEntity.getTablename());
request.getSession().setAttribute("username", tokenEntity.getUsername());
return true;
}
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(JSONObject.toJSONString(R.error(401, "请先登录")));
} finally {
if(writer != null){
writer.close();
}
}
// throw new EIException("请先登录", 401);
return false;
}
}
文章来源:https://blog.csdn.net/uxtxlq_601/article/details/153650340
技术支持:https://blog.csdn.net/2509_93841485/article/details/153678544
参考资料:https://blog.csdn.net/veswmn_619/article/details/153650378
文章来源①:https://blog.csdn.net/2509_93866873/article/details/153685279
技术支持②:https://blog.csdn.net/2509_93884312/article/details/153692363
参考资料③:https://blog.csdn.net/2509_93841585/article/details/153680638
更多推荐
所有评论(0)