Skip to content

汇丰技术快速参考卡

适合快速查阅的技术要点


常用命令

Git工作流

bash
# 克隆项目
git clone <repo-url>

# 创建分支
git checkout -b feature/JIRA-1234-description

# 提交代码
git add .
git commit -m "JIRA-1234: Add user authentication"
git push origin feature/JIRA-1234-description

# 常用操作
git fetch origin
git rebase origin/main
git stash        # 暂存当前修改
git stash pop    # 恢复暂存

Docker

bash
# 构建镜像
docker build -t hsbc-app:latest .

# 运行容器
docker run -p 8080:8080 hsbc-app:latest

# 查看日志
docker logs -f <container-id>

# 进入容器
docker exec -it <container-id> /bin/bash

# 查看容器状态
docker ps -a

Kubernetes (K8s)

bash
# 查看Pod
kubectl get pods -n <namespace>

# 查看日志
kubectl logs -f <pod-name> -n <namespace>

# 进入Pod
kubectl exec -it <pod-name> -n <namespace> -- /bin/bash

# 查看Deployment状态
kubectl get deployment -n <namespace>

# 滚动更新
kubectl rollout restart deployment/<name> -n <namespace>

# 回滚
kubectl rollout undo deployment/<name> -n <namespace>

Maven/Gradle

bash
# Maven 构建
mvn clean package -DskipTests
mvn test
mvn dependency:tree

# Gradle 构建
gradle build
gradle test
gradle dependencies

常用配置模板

Spring Boot application.yml

yaml
server:
  port: 8080

spring:
  application:
    name: hsbc-customer-service
  datasource:
    url: jdbc:oracle:thin:@db.hsbc.com:1521:CUSTOMER
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
  redis:
    host: redis.hsbc.com
    port: 6379
    password: ${REDIS_PASSWORD}
    database: 0

# 日志配置
logging:
  level:
    root: INFO
    com.hsbc: DEBUG
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
  file:
    name: /var/log/hsbc/application.log

# 业务配置
business:
  transaction:
    timeout-seconds: 30
    max-retry: 3
  masking:
    enabled: true

Maven pom.xml 关键依赖

xml
<properties>
    <java.version>17</java.version>
    <spring-boot.version>3.2.0</spring-boot.version>
</properties>

<dependencies>
    <!-- Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Validation -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <!-- Oracle/PostgreSQL -->
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
    </dependency>

    <!-- Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <!-- Kafka -->
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka</artifactId>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

代码模板

Spring Boot Controller

java
@RestController
@RequestMapping("/api/v1/customers")
@RequiredArgsConstructor
public class CustomerController {
    
    private final CustomerService customerService;
    
    @GetMapping("/{customerId}")
    public ResponseEntity<CustomerDTO> getCustomer(
            @PathVariable String customerId,
            @RequestHeader("X-Request-ID") String requestId) {
        
        log.info("Fetching customer: {}, requestId: {}", customerId, requestId);
        
        CustomerDTO customer = customerService.findById(customerId)
            .orElseThrow(() -> new CustomerNotFoundException(customerId));
            
        return ResponseEntity.ok(customer);
    }
}

React 组件

tsx
interface CustomerCardProps {
  customerId: string;
  name: string;
  accountType: 'savings' | 'checking' | 'credit';
}

export const CustomerCard: React.FC<CustomerCardProps> = ({
  customerId,
  name,
  accountType
}) => {
  return (
    <Card>
      <CardHeader>
        <Title>{name}</Title>
        <Tag>{accountType}</Tag>
      </CardHeader>
      <CardBody>
        <AccountNumber>{maskAccount(customerId)}</AccountNumber>
      </CardBody>
    </Card>
  );
};

数据脱敏工具类

java
public class DataMaskingUtil {

    // 手机号脱敏
    public static String maskPhone(String phone) {
        if (phone == null) return null;
        return phone.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
    }

    // 身份证脱敏
    public static String maskIdCard(String idCard) {
        if (idCard == null) return null;
        return idCard.replaceAll("(\\d{6})\\d{8}(\\d{4})", "$1********$2");
    }

    // 银行卡脱敏
    public static String maskBankCard(String cardNumber) {
        if (cardNumber == null) return null;
        return "**** **** **** " + cardNumber.substring(cardNumber.length() - 4);
    }

    // 邮箱脱敏
    public static String maskEmail(String email) {
        if (email == null) return null;
        String[] parts = email.split("@");
        if (parts.length != 2) return email;
        String name = parts[0];
        if (name.length() <= 2) return "**@" + parts[1];
        return name.substring(0, 2) + "***@" + parts[1];
    }

    // 姓名脱敏
    public static String maskName(String name) {
        if (name == null) return null;
        if (name.length() <= 1) return "*";
        if (name.length() == 2) return name.charAt(0) + "*";
        return name.charAt(0) + "*".repeat(name.length() - 2) + name.charAt(name.length() - 1);
    }

    // 地址脱敏(只保留省市)
    public static String maskAddress(String address) {
        if (address == null) return null;
        // 简化逻辑:只保留前6个字符
        if (address.length() <= 6) return address;
        return address.substring(0, 6) + "***";
    }
}

审计日志模板

银行系统必须记录关键操作日志:

java
@Slf4j
@Component
@RequiredArgsConstructor
public class AuditLogService {

    private final AuditLogRepository auditLogRepository;

    public void log(String userId, String action, String resourceId, Map<String, Object> details) {
        AuditLog auditLog = AuditLog.builder()
            .userId(userId)
            .action(action)
            .resourceId(resourceId)
            .details(JsonUtil.toJson(details))
            .ipAddress(getClientIp())
            .timestamp(LocalDateTime.now())
            .build();

        auditLogRepository.save(auditLog);
        log.info("AUDIT: user={} action={} resource={}", userId, action, resourceId);
    }

    private String getClientIp() {
        // 从HttpServletRequest获取IP
    }
}

分布式锁模板

java
@Service
@RequiredArgsConstructor
public class PaymentLockService {

    private final RedisTemplate<String, String> redisTemplate;

    private static final String LOCK_PREFIX = "payment:lock:";
    private static final Duration LOCK_TIMEOUT = Duration.ofSeconds(30);

    public Boolean tryLock(String transactionId, String userId) {
        String lockKey = LOCK_PREFIX + transactionId;
        Boolean acquired = redisTemplate.opsForValue()
            .setIfAbsent(lockKey, userId, LOCK_TIMEOUT);

        if (Boolean.TRUE.equals(acquired)) {
            log.info("获取支付锁成功: transactionId={}, userId={}", transactionId, userId);
        } else {
            log.warn("获取支付锁失败: transactionId={}", transactionId);
        }

        return acquired;
    }

    public void unlock(String transactionId, String userId) {
        String lockKey = LOCK_PREFIX + transactionId;
        String lockOwner = redisTemplate.opsForValue().get(lockKey);

        if (userId.equals(lockOwner)) {
            redisTemplate.delete(lockKey);
            log.info("释放支付锁: transactionId={}", transactionId);
        }
    }
}

错误码规范

java
public enum ErrorCode {
    // 通用错误 (1xxx)
    SUCCESS("0000", "成功"),
    SYSTEM_ERROR("1001", "系统错误"),
    PARAM_ERROR("1002", "参数错误"),
    
    // 客户相关 (2xxx)
    CUSTOMER_NOT_FOUND("2001", "客户不存在"),
    CUSTOMER_LOCKED("2002", "账户已锁定"),
    
    // 交易相关 (3xxx)
    INSUFFICIENT_FUNDS("3001", "余额不足"),
    TRANSACTION_TIMEOUT("3002", "交易超时"),
    DUPLICATE_TRANSACTION("3003", "重复交易");
    
    private final String code;
    private final String message;
    
    ErrorCode(String code, String message) {
        this.code = code;
        this.message = message;
    }
}

日志规范

java
// ✅ 正确示例
log.info("Customer {} login from IP {}", customerId, ipAddress);
log.warn("Transaction {} retry attempt {}", transactionId, attempt);
log.error("Payment failed: code={}, message={}", errorCode, errorMessage);

// ❌ 错误示例
log.info("processing customer");
System.out.println("done");  // 禁止使用

API响应格式

json
// 成功响应
{
  "code": "0000",
  "message": "success",
  "data": {
    "customerId": "C123456",
    "name": "张三",
    "accounts": [...]
  },
  "requestId": "req-abc-123",
  "timestamp": "2026-02-26T10:30:00Z"
}

// 错误响应
{
  "code": "2001",
  "message": "客户不存在",
  "requestId": "req-abc-123",
  "timestamp": "2026-02-26T10:30:00Z"
}

// 分页响应
{
  "code": "0000",
  "message": "success",
  "data": {
    "content": [...],
    "page": 0,
    "size": 20,
    "totalElements": 150,
    "totalPages": 8
  },
  "requestId": "req-abc-123"
}

通用响应封装

java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
    private String code;
    private String message;
    private T data;
    private String requestId;
    private String timestamp;

    public static <T> ApiResponse<T> success(T data) {
        return ApiResponse.<T>builder()
            .code("0000")
            .message("success")
            .data(data)
            .requestId(RequestContext.getRequestId())
            .timestamp(LocalDateTime.now().toString())
            .build();
    }

    public static <T> ApiResponse<T> error(String code, String message) {
        return ApiResponse.<T>builder()
            .code(code)
            .message(message)
            .data(null)
            .requestId(RequestContext.getRequestId())
            .timestamp(LocalDateTime.now().toString())
            .build();
    }
}

测试要点

单元测试

java
@ExtendWith(MockitoExtension.class)
class CustomerServiceTest {
    
    @Mock
    private CustomerRepository customerRepository;
    
    @InjectMocks
    private CustomerService customerService;
    
    @Test
    void shouldThrowExceptionWhenCustomerNotFound() {
        when(customerRepository.findById("C999"))
            .thenReturn(Optional.empty());
            
        assertThrows(CustomerNotFoundException.class, 
            () -> customerService.findById("C999"));
    }
}

前端测试

tsx
import { render, screen, fireEvent } from '@testing-library/react';

test('should show masked account number', () => {
  render(<CustomerCard customerId="1234567890" name="Test" accountType="savings" />);
  
  expect(screen.getByText('**** **** **** 7890')).toBeInTheDocument();
});

常用链接

名称链接
GitLabgitlab.hsbc.com
Jirajira.hsbc.com
Confluenceconfluence.hsbc.com
Artifactoryartifactory.hsbc.com
Grafanagrafana.hsbc.com

💡 持续更新中...

> 学而时习之,不亦说乎?