Java静态代码分析案例

wen java案例 1

本文目录导读:

Java静态代码分析案例

  1. 项目场景设定
  2. 使用Maven配置静态分析工具
  3. 分析报告示例
  4. 修复后的代码
  5. 持续集成推荐配置

我来给你一个完整的Java静态代码分析案例,包含场景、工具配置和详细分析过程。

项目场景设定

// 待分析的示例项目:电商订单处理系统
package com.example.order;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class OrderService {
    // 问题1:硬编码SQL,存在SQL注入风险
    public List<Order> getOrdersByUser(String userId) {
        List<Order> orders = new ArrayList<>();
        String sql = "SELECT * FROM orders WHERE user_id = '" + userId + "'";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                Order order = new Order();
                order.setId(rs.getLong("id"));
                order.setAmount(rs.getBigDecimal("amount"));
                orders.add(order);
            }
        } catch (SQLException e) {
            e.printStackTrace();  // 问题2:打印堆栈而不是使用日志框架
        }
        return orders;
    }
    // 问题3:资源未正确关闭
    public void saveOrder(Order order) {
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            String sql = "INSERT INTO orders (id, amount, user_id) VALUES (?, ?, ?)";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setLong(1, order.getId());
            ps.setBigDecimal(2, order.getAmount());
            ps.setString(3, order.getUserId());
            ps.executeUpdate();
        } catch (SQLException e) {
            System.out.println("Error: " + e.getMessage());  // 使用System.out
        } finally {
            // 没有关闭PreparedStatement
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    System.out.println("Close error");  // 忽略异常
                }
            }
        }
    }
    // 问题4:空指针风险
    public String getOrderStatus(Order order) {
        if (order.getStatus() != null) {
            return order.getStatus().toUpperCase();
        }
        return order.getStatus();  // 可能返回null
    }
    // 问题5:魔法数字和硬编码
    public boolean isExpired(Order order) {
        long currentTime = System.currentTimeMillis();
        long expireTime = 24 * 60 * 60 * 1000;  // 魔法数字
        return (currentTime - order.getCreateTime()) > expireTime;
    }
}
class Order {
    private Long id;
    private BigDecimal amount;
    private String userId;
    private String status;
    private long createTime;
    // getters and setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public BigDecimal getAmount() { return amount; }
    public void setAmount(BigDecimal amount) { this.amount = amount; }
    public String getUserId() { return userId; }
    public void setUserId(String userId) { this.userId = userId; }
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    public long getCreateTime() { return createTime; }
    public void setCreateTime(long createTime) { this.createTime = createTime; }
}

使用Maven配置静态分析工具

<!-- pom.xml -->
<project>
    <build>
        <plugins>
            <!-- Checkstyle 检查代码规范 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>3.1.2</version>
                <configuration>
                    <configLocation>google_checks.xml</configLocation>
                    <failOnViolation>false</failOnViolation>
                </configuration>
                <executions>
                    <execution>
                        <goals><goal>check</goal></goals>
                    </execution>
                </executions>
            </plugin>
            <!-- SpotBugs 检测Bug -->
            <plugin>
                <groupId>com.github.spotbugs</groupId>
                <artifactId>spotbugs-maven-plugin</artifactId>
                <version>4.7.3.2</version>
                <configuration>
                    <effort>Max</effort>
                    <threshold>Low</threshold>
                </configuration>
                <executions>
                    <execution>
                        <goals><goal>check</goal></goals>
                    </execution>
                </executions>
            </plugin>
            <!-- PMD 检查代码缺陷 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>3.19.0</version>
                <configuration>
                    <rulesets>
                        <ruleset>rulesets/java/quickstart.xml</ruleset>
                    </rulesets>
                    <failOnViolation>false</failOnViolation>
                </configuration>
                <executions>
                    <execution>
                        <goals><goal>check</goal></goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

分析报告示例

1 Checkstyle 检查结果

Checkstyle violations found:
[ERROR] OrderService.java:12:9 - SQL injection vulnerability: concatenation of user input
[ERROR] OrderService.java:15:16 - Line length exceeds 120 characters
[ERROR] OrderService.java:18:13 - Variable 'ps' should be declared final
[WARN] OrderService.java:35:13 - Avoid using printStackTrace()

2 SpotBugs 检查结果

Bug Report:
[High] SQL_INJECTION: SQL statement constructed from user input
    - In OrderService.getOrdersByUser(String userId)
    - Repair: Use PreparedStatement with parameters
[Medium] NP_NULL_ON_SOME_PATH: Possible null pointer dereference
    - In OrderService.getOrderStatus(Order order)
    - When order.getStatus() returns null
[Medium] DM_EXIT: Method invokes System.exit()
    - In OrderService.saveOrder(Order order)
    - Avoid using System.exit() in business logic

3 PMD 检查结果

PMD Violations:
[High] AvoidUsingHardCodedIP - Hardcoded values in database connection
[Medium] AvoidInstantiatingObjectsInLoops - Objects instantiated in loops
[Low] SystemPrintln - Avoid using System.out.println for logging
[High] CloseResource - PreparedStatement not closed properly

修复后的代码

package com.example.order;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class OrderServiceFixed {
    private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceFixed.class);
    private static final long EXPIRE_TIME_MS = 24 * 60 * 60 * 1000L; // 24小时
    /**  使用参数化查询防止SQL注入  */
    public List<Order> getOrdersByUser(String userId) {
        List<Order> orders = new ArrayList<>();
        String sql = "SELECT * FROM orders WHERE user_id = ?";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setString(1, userId);  // 使用参数绑定
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    Order order = new Order();
                    order.setId(rs.getLong("id"));
                    order.setAmount(rs.getBigDecimal("amount"));
                    orders.add(order);
                }
            }
        } catch (SQLException e) {
            LOGGER.error("Failed to get orders for user: {}", userId, e);  // 使用日志框架
        }
        return orders;
    }
    /**  正确关闭所有资源  */
    public void saveOrder(Order order) {
        String sql = "INSERT INTO orders (id, amount, user_id) VALUES (?, ?, ?)";
        try (Connection conn = DBUtil.getConnection();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.setLong(1, order.getId());
            ps.setBigDecimal(2, order.getAmount());
            ps.setString(3, order.getUserId());
            ps.executeUpdate();
        } catch (SQLException e) {
            LOGGER.error("Failed to save order: {}", order.getId(), e);
        }
    }
    /**  处理空值情况  */
    public String getOrderStatus(Order order) {
        String status = order.getStatus();
        return (status != null) ? status.toUpperCase() : "UNKNOWN";  // 提供默认值
    }
    /**  使用具名常量代替魔法数字  */
    public boolean isExpired(Order order) {
        long currentTime = System.currentTimeMillis();
        return (currentTime - order.getCreateTime()) > EXPIRE_TIME_MS;
    }
}

持续集成推荐配置

# GitLab CI/CD 配置示例
stages:
  - analyze
  - build
  - test
# 静态代码分析阶段
analyze:
  stage: analyze
  script:
    - mvn clean verify checkstyle:checkspotbugs:check pmd:check
  artifacts:
    reports:
      codequality: target/reports/checkstyle-result.xml

通过这个案例,你可以:

  1. 看到常见的代码问题被识别和修复
  2. 了解不同工具的检查重点
  3. 建立标准化的静态分析流程
  4. 持续改进代码质量

抱歉,评论功能暂时关闭!