我们有两个主要功能:
功能1:对外提供接口,接收一个JSON字符串(格式为{“encryptMsg”:“加密字符串”}),使用DES解密(密钥为"JcXmSjjs20250801"),解密后的字符串是一个JSON,然后将其保存到MySQL数据库,并返回{ “result”:“success”}。
注意:用户提供的解密方法是AES,但实际需求是DES。我们需要实现DES解密。根据引用[3],DES密钥实际是56位,但通常使用8字节(64位)的密钥,其中每个字节的最后一位是奇偶校验位。这里密钥"JcXmSjjs20250801"长度超过8字节,我们只需要取前8个字节(即"JcXmSjjs")作为DES密钥。
功能2:定时任务,每分钟调用外部系统的GET和POST接口(具体接口未知),解析返回的数据并保存到MySQL。
设计思路:
-
功能1:使用Spring Boot构建一个REST接口,接收POST请求,解析请求体,解密,保存数据库,返回响应。
-
功能2:使用Spring的@Scheduled注解实现定时任务,调用外部API(由于具体接口未知,我们先设计一个框架,后续可以配置具体的URL和参数)。
步骤:
一、功能1:解密接口
1.1 创建实体类,用于接收请求体(只包含一个字段encryptMsg)
1.2 使用DES解密(密钥取前8个字节),解密后得到JSON字符串
1.3 将解密后的JSON字符串整个保存到数据库(或者解析后存储到具体字段,但需求没有明确,这里我们先保存整个字符串)
1.4 返回固定响应
二、功能2:定时任务
2.1 配置定时任务,每分钟执行一次
2.2 在定时任务中,调用外部系统的GET和POST接口(可以分别调用,也可以配置多个)
2.3 解析响应数据(假设响应为JSON),并将数据保存到数据库(这里同样先保存整个响应内容,或根据实际结构设计实体)
注意:由于外部API未知,我们可以设计一个可配置的机制,但根据需求,我们先实现一个简单的版本,即硬编码几个URL,然后分别调用。
详细设计:
-
数据库表设计:
功能1需要一张表存储解密后的数据,功能2需要另一张表存储从外部API获取的数据。表1:decrypted_messages
id: 自增主键
content: TEXT (存储解密后的整个JSON字符串)
create_time: 创建时间表2:external_api_data
id: 自增主键
api_type: ENUM(‘GET’, ‘POST’) 或 VARCHAR(10) 记录调用的API类型
content: TEXT (存储响应的整个JSON字符串)
create_time: 创建时间 -
实体类:
DecryptedMessage:
- Long id
- String content
- LocalDateTime createTimeExternalApiData:
- Long id
- String apiType
- String content
- LocalDateTime createTime -
仓库接口(Spring Data JPA):
DecryptedMessageRepository
ExternalApiDataRepository -
DES解密工具类:
根据引用[3]和引用[4](Base64工具),我们实现DES解密。注意:解密方法中,传入的加密字符串是Base64编码的,所以先Base64解码,再用DES解密。 -
定时任务类:使用@Scheduled(fixedRate = 60000) // 60秒
-
调用外部API:使用RestTemplate或WebClient。这里使用RestTemplate。
代码实现:
步骤一:添加依赖(Spring Boot Starter Web, Spring Data JPA, MySQL Driver, Spring Boot Starter Scheduling)
步骤二:配置数据库连接和JPA(application.properties)
步骤三:实现各个组件。
由于代码较长,下面分部分实现:
-
数据库表对应的实体类:
DecryptedMessage.java
ExternalApiData.java -
仓库接口:
DecryptedMessageRepository.java
ExternalApiDataRepository.java -
DES工具类:DESUtils.java
-
控制器:DecryptController.java (处理功能1)
-
定时任务:ScheduledTasks.java (功能2)
-
配置RestTemplate Bean
注意:由于密钥是"JcXmSjjs20250801",我们只需要前8个字节(即"JcXmSjjs")。
DES解密工具类实现:
根据引用[3],DES算法使用56位密钥(8字节中的每字节最后1位为校验位),我们使用Java的DES解密实现。
注意:加密模式和解密模式需要一致。由于用户没有指定,我们默认使用ECB模式(不推荐,但简单),填充方式为PKCS5Padding(对应Java的DES/ECB/PKCS5Padding)。
代码示例:
由于用户给出的示例是AES,我们需要改为DES。
具体实现如下:
一、DESUtils 工具类
Java
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import java.util.Base64; public class DESUtils { private static final String ALGORITHM = "DES/ECB/PKCS5Padding"; // 使用DES的ECB模式,PKCS5Padding填充 public static String decrypt(String data, String key) throws Exception { // 密钥只取前8位 if (key == null || key.length() < 8) { throw new IllegalArgumentException("密钥长度至少8位"); } key = key.substring(0, 8); byte[] encryptedData = Base64.getDecoder().decode(data.getBytes()); DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] decryptedData = cipher.doFinal(encryptedData); return new String(decryptedData); } }
二、控制器
Java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; @RestController public class DecryptController { @Autowired private DecryptedMessageRepository repository; private static final String SECRET_KEY = "JcXmSjjs20250801"; // 实际只取前8位 @PostMapping("/api/decrypt") public ResponseResult decryptAndSave(@RequestBody EncryptedMessageRequest request) { try { // 解密 String decryptedContent = DESUtils.decrypt(request.getEncryptMsg(), SECRET_KEY); // 保存到数据库 DecryptedMessage message = new DecryptedMessage(); message.setContent(decryptedContent); message.setCreateTime(LocalDateTime.now()); repository.save(message); return new ResponseResult("success"); } catch (Exception e) { return new ResponseResult("error: " + e.getMessage()); } } // 内部类用于接收请求 static class EncryptedMessageRequest { private String encryptMsg; public String getEncryptMsg() { return encryptMsg; } public void setEncryptMsg(String encryptMsg) { this.encryptMsg = encryptMsg; } } // 内部类用于响应 static class ResponseResult { private String result; public ResponseResult(String result) { this.result = result; } public String getResult() { return result; } } }
三、定时任务
Java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import java.time.LocalDateTime; @Component public class ScheduledTasks { @Autowired private ExternalApiDataRepository repository; @Autowired private RestTemplate restTemplate; // 每分钟执行一次 @Scheduled(fixedRate = 60000) public void callExternalApis() { // 假设我们有两个外部API:一个GET,一个POST String getUrl = "http://example.com/api/data1"; String postUrl = "http://example.com/api/data2"; // 调用GET接口 try { String getResponse = restTemplate.getForObject(getUrl, String.class); ExternalApiData getData = new ExternalApiData(); getData.setApiType("GET"); getData.setContent(getResponse); getData.setCreateTime(LocalDateTime.now()); repository.save(getData); } catch (Exception e) { // 异常处理,记录日志 e.printStackTrace(); } // 调用POST接口(这里假设不需要请求体,如果有请求体,需要构建) try { // 如果POST请求需要传递参数,可以使用HttpEntity,这里假设无参数 String postResponse = restTemplate.postForObject(postUrl, null, String.class); ExternalApiData postData = new ExternalApiData(); postData.setApiType("POST"); postData.setContent(postResponse); postData.setCreateTime(LocalDateTime.now()); repository.save(postData); } catch (Exception e) { e.printStackTrace(); } } }
四、配置RestTemplate(在启动类或配置类中)
Java
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class AppConfig { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
五、实体类和仓库接口
Java
import jakarta.persistence.*; import java.time.LocalDateTime; @Entity public class DecryptedMessage { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Lob // 大文本 private String content; private LocalDateTime createTime; // getters and setters } @Entity public class ExternalApiData { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String apiType; // 可以是GET或POST @Lob private String content; private LocalDateTime createTime; // getters and setters }
仓库接口:
Java
import org.springframework.data.jpa.repository.JpaRepository; public interface DecryptedMessageRepository extends JpaRepository<DecryptedMessage, Long> { } public interface ExternalApiDataRepository extends JpaRepository<ExternalApiData, Long> { }
六、application.properties配置(示例)
properties
spring.datasource.url=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=your_password spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
注意事项:
-
由于DES的ECB模式不安全,实际生产环境应使用更安全的模式(如CBC)和更安全的算法(如AES)。这里按照需求使用DES。
-
定时任务中的外部API地址是硬编码,实际应该配置在配置文件中。
-
异常处理需要根据实际情况完善(如记录日志,而不是仅打印异常)。
-
数据库表字段设计可以根据实际返回的数据结构调整(例如,如果返回的JSON有固定结构,可以拆分成多个字段存储)。
由于需求中外部API未知,我们只能先保存整个响应内容。后续如果知道具体结构,可以修改实体类。
返回固定响应:解密接口返回{“result”:“success”},如果出错则返回{“result”:“error: …”}。
定时任务:每分钟调用外部API,并将返回数据保存到数据库中。
相关问题:
-
如何改进DES解密的安全性(避免使用ECB模式)?
-
定时任务中如何动态配置多个外部API调用?
-
如何优化数据库存储,避免大文本字段影响查询效率?
-
如果外部API需要认证(如Token),如何实现?
Java接口处理程序设计方案
我将设计一个完整的Spring Boot应用,实现两个核心功能:解密接收数据和定时调用外部API。整个设计分为接口模块、定时任务模块和数据持久化模块。
核心架构设计
mermaid
graph TD
A[客户端请求] --> B[接收解密接口]
C[定时任务] --> D[调用外部API]
B --> E[DES解密]
E --> F[数据持久化]
D --> F
F --> G[MySQL数据库]
B --> H[返回结果]
C --> H
subgraph 业务模块
B
C
end
代码实现
1. DES解密工具类(修复实现)
Java
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.util.Base64;
public class DESUtils {
private static final String ALGORITHM = "DES/ECB/PKCS5Padding";
public static String decrypt(String data, String fullKey) throws Exception {
// DES密钥只需前8字节(56位有效密钥+8位奇偶校验)
String key = fullKey.substring(0, 8);
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] encryptedData = Base64.getDecoder().decode(data);
byte[] decryptedData = cipher.doFinal(encryptedData);
return new String(decryptedData);
}
}
2. 实体类设计
Java
// 解密数据实体
@Entity
public class DecryptedData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String originalId;
private String appKey;
private String appId;
private String msgType;
private Long timestamp;
private String bizContent; // 存储JSON格式的业务数据
private LocalDateTime createTime;
// getters/setters
}
// 外部API数据实体
@Entity
public class ExternalApiData {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String apiType; // GET/POST
private String endpoint;
private String responseData;
private LocalDateTime callTime;
// getters/setters
}
3. 控制器接口
Java
@RestController
@RequestMapping("/api")
public class DataController {
private static final String SECRET_KEY = "JcXmSjjs20250801";
@Autowired
private DecryptedDataRepository decryptedDataRepo;
@PostMapping("/decrypt")
public ResponseEntity<Map<String, String>> handleDecrypt(
@RequestBody Map<String, String> request) {
try {
String encryptedMsg = request.get("encryptMsg");
String decryptedJson = DESUtils.decrypt(encryptedMsg, SECRET_KEY);
// 解析JSON
JsonNode rootNode = new ObjectMapper().readTree(decryptedJson);
DecryptedData data = new DecryptedData();
data.setOriginalId(rootNode.path("id").asText());
data.setAppKey(rootNode.path("appKey").asText());
data.setAppId(rootNode.path("appId").asText());
data.setMsgType(rootNode.path("msgType").asText());
data.setTimestamp(rootNode.path("time").asLong());
data.setBizContent(rootNode.path("bizContent").toString());
data.setCreateTime(LocalDateTime.now());
decryptedDataRepo.save(data);
return ResponseEntity.ok(Collections.singletonMap("result", "success"));
} catch (Exception e) {
return ResponseEntity.status(500)
.body(Collections.singletonMap("error", e.getMessage()));
}
}
}
4. 定时任务实现
Java
@Component
public class ApiScheduler {
@Autowired
private ExternalApiDataRepository apiDataRepo;
@Autowired
private RestTemplate restTemplate;
// 每分钟执行一次(60,000毫秒)
@Scheduled(fixedRate = 60000)
public void callExternalApis() {
// 实际中应从配置读取API列表
List<ApiConfig> apis = Arrays.asList(
new ApiConfig("GET", "https://api.example.com/data1"),
new ApiConfig("POST", "https://api.example.com/data2", "payload")
);
for (ApiConfig api : apis) {
try {
ExternalApiData record = new ExternalApiData();
record.setApiType(api.getMethod());
record.setEndpoint(api.getUrl());
record.setCallTime(LocalDateTime.now());
if ("GET".equalsIgnoreCase(api.getMethod())) {
String response = restTemplate.getForObject(api.getUrl(), String.class);
record.setResponseData(response);
} else if ("POST".equalsIgnoreCase(api.getMethod())) {
HttpEntity<String> request = new HttpEntity<>(api.getPayload());
String response = restTemplate.postForObject(api.getUrl(), request, String.class);
record.setResponseData(response);
}
apiDataRepo.save(record);
} catch (Exception e) {
// 记录错误日志
}
}
}
// API配置内部类
@Value
@AllArgsConstructor
private static class ApiConfig {
private String method;
private String url;
private String payload = "";
}
}
5. 数据库配置(APPLICATION.YML)
YAML
spring:
datasource:
url: jdbc:mysql://localhost:3306/data_db
username: root
password: secure_password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
scheduling:
external-apis:
- method: GET
url: https://api.example.com/data1
- method: POST
url: https://api.example.com/data2
payload: '{"param":"value"}'
关键技术说明
-
DES解密处理:
-
使用
DES/ECB/PKCS5Padding模式 -
密钥截取前8字节(56位有效密钥+8位奇偶校验)
-
Base64解码后解密数据4
-
-
定时任务优化:
-
使用Spring的
@Scheduled注解 -
支持GET/POST多种请求方式
-
异常处理避免任务中断
-
-
数据存储策略:
-
解密数据结构化存储
-
API响应原始数据保存
-
自动记录操作时间戳
-
性能优化建议
-
连接池配置:
YAML
spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000 -
定时任务线程池:
Java
@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
}
}
-
批量插入优化:
Java
@Transactional
public void batchSave(List<ExternalApiData> records) {
for (int i = 0; i < records.size(); i++) {
entityManager.persist(records.get(i));
if (i % 50 == 0) {
entityManager.flush();
entityManager.clear();
}
}
}
安全问题处理
-
密钥管理:
Java
// 从安全配置获取密钥
@Value("${app.security.des-key}")
private String secretKey; -
输入验证:
Java
if (!StringUtils.hasText(encryptedMsg) || encryptedMsg.length() < 64) {
throw new IllegalArgumentException("无效的加密数据");
} -
HTTPS支持:
Java
@@Bean
public RestTemplate restTemplate() throws Exception {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[]{new BlindTrustManager()}, null);
return new RestTemplate(new HttpComponentsClientHttpRequestFactory(
HttpClients.custom().setSSLContext(context).build()
));
}
部署注意事项
-
启动参数:
java -jar app.jar \ --spring.datasource.password=${DB_PASSWORD} \ --app.security.des-key=${DES_KEY} -
健康检查端点:
Java
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "UP";
}
} -
日志配置:
YAML
logging:
level:
root: INFO
org.springframework.web: DEBUG
file:
name: logs/app.log
此设计实现了需求的两个核心功能:DES解密接口和定时API调用,采用模块化设计便于扩展,配置驱动增强灵活性,多层验证保障安全性。实际部署时建议添加API限流、请求签名验证等安全措施

被折叠的 条评论
为什么被折叠?



