方案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);}// 其他代码不变...
}