方案1:
@Slf4j
@Component
public class ChatdocApiClient {@Value("${chatdoc.app-id}")private String appId;@Value("${chatdoc.secret}")private String secret;@Value("${chatdoc.domain}")private String domain;private final RestTemplate restTemplate = new RestTemplate();/*** 文件上傳*/public Map<String, Object> uploadFile(MultipartFile file, String url, String fileName, String fileType, String parseType, Boolean stepByStep, String callbackUrl, String extend) throws IOException {String apiUrl = "https://" + domain + "/openapi/v1/file/upload";HttpHeaders headers = buildAuthHeaders();headers.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();if (file != null) {body.add("file", file.getResource());}if (url != null) body.add("url", url);if (fileName != null) body.add("fileName", fileName);if (fileType != null) body.add("fileType", fileType);if (parseType != null) body.add("parseType", parseType);if (stepByStep != null) body.add("stepByStep", stepByStep);if (callbackUrl != null) body.add("callbackUrl", callbackUrl);if (extend != null) body.add("extend", extend);HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(body, headers);try {log.info("[Chatdoc] 上傳文件: {}", fileName);ResponseEntity<Map> resp = restTemplate.postForEntity(apiUrl, request, Map.class);return resp.getBody();} catch (RestClientException e) {log.error("[Chatdoc] 文件上傳失敗", e);throw new ChatdocApiException("文件上傳失敗: " + e.getMessage(), e);}}
方案2:
1. 構造函數注入(推薦)
這是 Spring 官方推薦的方式,通過構造函數將 RestTemplate
注入到類中,清晰展示類的依賴關系。
@Slf4j
@Component
public class ChatdocApiClient {@Value("${chatdoc.app-id}")private String appId;@Value("${chatdoc.secret}")private String secret;@Value("${chatdoc.domain}")private String domain;private final RestTemplate restTemplate; // 不再直接new// 構造函數注入RestTemplatepublic ChatdocApiClient(RestTemplate restTemplate) {this.restTemplate = restTemplate;}// 其他代碼不變...
}
注意:使用這種方式需要先在 Spring 容器中定義 RestTemplate
的 Bean
從圖中報錯 “Could not autowire. No beans of ‘RestTemplate’ type found.” 可知,問題是 Spring 容器中找不到 RestTemplate
類型的 Bean,因為沒有配置 RestTemplate
到 Spring 容器。
解決方法:在項目的配置類(一般用 @Configuration
標注)中添加如下代碼,將 RestTemplate
注冊為 Bean ,這樣就能注入了:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class AppConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}
2. 字段注入(@Autowired)
通過 @Autowired
注解直接在字段上注入 RestTemplate
,代碼更簡潔但依賴關系不夠直觀。
@Slf4j
@Component
public class ChatdocApiClient {@Value("${chatdoc.app-id}")private String appId;@Value("${chatdoc.secret}")private String secret;@Value("${chatdoc.domain}")private String domain;@Autowired // 字段注入private RestTemplate restTemplate;// 其他代碼不變...
}
3. Setter 方法注入
通過 Setter 方法注入 RestTemplate
,適合需要在注入后做額外處理的場景。
@Slf4j
@Component
public class ChatdocApiClient {@Value("${chatdoc.app-id}")private String appId;@Value("${chatdoc.secret}")private String secret;@Value("${chatdoc.domain}")private String domain;private RestTemplate restTemplate;// Setter方法注入@Autowiredpublic void setRestTemplate(RestTemplate restTemplate) {this.restTemplate = restTemplate;// 可以在這里添加初始化邏輯}// 其他代碼不變...
}
4. 手動從 Spring 上下文獲取(特殊場景)
通過 ApplicationContext
手動獲取 RestTemplate
,適合非 Spring 管理的類或特殊場景(不推薦常規使用)。
@Slf4j
@Component
public class ChatdocApiClient implements ApplicationContextAware {@Value("${chatdoc.app-id}")private String appId;@Value("${chatdoc.secret}")private String secret;@Value("${chatdoc.domain}")private String domain;private RestTemplate restTemplate;private static ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {context = applicationContext;}// 初始化時獲取RestTemplate@PostConstructpublic void init() {this.restTemplate = context.getBean(RestTemplate.class);}// 其他代碼不變...
}