汇丰技术快速参考卡
适合快速查阅的技术要点
常用命令
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 -aKubernetes (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: trueMaven 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();
});常用链接
| 名称 | 链接 |
|---|---|
| GitLab | gitlab.hsbc.com |
| Jira | jira.hsbc.com |
| Confluence | confluence.hsbc.com |
| Artifactory | artifactory.hsbc.com |
| Grafana | grafana.hsbc.com |
💡 持续更新中...