问题
之前写了一个配置类,读取config.yml配置文件里写好的阿里云oss的一些参数配置。配置类读取并无问题,但是在另一个普通类里自动注入该配置类时,引用配置类属性却报NullPointer异常。然后终于发现问题原因了。
代码
1. 配置文件
application-oss.properties
aliyun.oss.endpoint=oss-ap-southeast-1.aliyuncs.com
aliyun.oss.bucket-name=tms-oss-singapore
aliyun.oss.key-id=LTAI5tN999G8YVxnJ8ss8ouh
aliyun.oss.key-secret=dSk4kGrtHFT2quUBwO4KNJFcQLwFZc
2. 配置类
package com.yunsystem.common.utils;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@Data
@PropertySource(value = {"classpath:application-oss.properties"})
@SpringBootApplication
public class OssProperties {
@Value(value = "${aliyun.oss.endpoint}")
private String endpoint; // bucket所在地域对应的endpoint
@Value(value = "${aliyun.oss.key-id}")
private String keyid; // accesskey的id
@Value(value = "${aliyun.oss.key-secret}")
private String keysecret; // accesskey的密钥
@Value(value = "${aliyun.oss.bucket-name}")
private String bucketname; // 存储桶名称
}
3. 调用配置类的普通类
以下类为OSS上传文件类
package com.yunsystem.common.utils;
import com.aliyun.oss.*;
import com.aliyun.oss.model.ObjectMetadata;
import com.yunsystem.common.error.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
public class OssUpload {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private OssProperties ossProperties; // 这里即注解自动装配
/**
* 使用aliyun-sdk实现上传
* @param inputStream 上传的文件流
* @param module oss目录
* @param originalFileName 文件名
* @return
* @throws BusinessException
*/
public Map upload(InputStream inputStream, String module, String originalFileName) throws BusinessException {
/**
* 获取oss的属性
*/
String endpoint = ossProperties.getEndpoint();
String accessKeyId = ossProperties.getKeyid();
String accessKeySecret = ossProperties.getKeysecret();
String bucketName = ossProperties.getBucketname();
String objectName = "";
Map<String, String> map = new HashMap<>();
// 创建上传文件的元信息,可以通过文件元信息设置HTTP header。
ObjectMetadata meta = new ObjectMetadata();
// 创建OSSClient实例。
OSS ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
String folder = simpleDateFormat.format(new Date());
// 文件名 sn+开始结束时间戳
String fileName = originalFileName.substring(0, originalFileName.lastIndexOf(".")); //UUID.randomUUID().toString();
//文件扩展名
String fileExtention = originalFileName.substring(originalFileName.lastIndexOf("."));
if (StringUtils.isNotEmpty(module)) {
//最终的路径 类似actionRec/abnormal/2023-01-05-09:52:41/xxxxxxxxx.jpg
objectName = module + "/" + folder + "/" + fileName + fileExtention;
} else {
objectName = folder + "/" + fileName + fileExtention;
}
meta.setContentType("text/plain");
meta.setContentDisposition("inline");
// 上传文件
ossClient.putObject(bucketName, objectName, inputStream, meta); // bucket名称,上传文件路径和名称,上传文件输入流
//https://rxt.oss-cn-beijing.aliyuncs.com/avatar/01.jpeg
map.put("fileUrl", "https://" + bucketName + "." + endpoint + "/" + objectName);
return map;
} catch (OSSException oe) {
logger.error("Error Message: " + oe.getErrorMessage());
throw new ServiceException(oe.getMessage());
} catch (ClientException ce) {
logger.error("Error Message: " + ce.getMessage());
throw new ServiceException(ce.getMessage());
} finally {
if (ossClient != null) {
// 关闭OSSClient。
ossClient.shutdown();
}
}
}
}
4. 业务类ServiceImpl调用oss上传工具类实现业务文件上传
@Transactional
@Service
public class DeviceActiveInfoImpl implements DeviceActiveInfoService {
...
public void uploadFile(MultipartFile file) {
...
// 1. 解析文件数据
String fileName = file.getOriginalFilename();
File newFile = new File(fileName);
try {
FileUtils.copyInputStreamToFile(file.getInputStream(), newFile);
} catch (IOException e) {
e.printStackTrace();
}
newFile.deleteOnExit(); // JVM停止后删除临时文件
// newFile.delete(); 调用完立即删除临时文件
// 2. 调用上传文件接口
OssUpload ossUpload = new OssUpload(); // !!! 注意这里,问题在这!!!
// 2.1. 上传文件
InputStream inputStream = null;
try {
inputStream = file.getInputStream(); // 获取文件流
} catch (IOException e) {
e.printStackTrace();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String extName = fileName.substring(fileName.lastIndexOf(".")); // 后缀名
//fileName = sn + sdf.format(startTimeStamp) + extName;
String module = "ScanKMS/error"; // 存储空间目录文件夹
Map map = ossUpload.upload(inputStream, module, fileName);
// 2. 保存记录到数据库
String filePath = (String) map.get("fileUrl");
for (DeviceActiveInfo deviceActiveInfo : deviceActiveInfos) {
deviceActiveInfo.setFile_url(filePath);
deviceActiveInfoMapper.updateByPrimaryKeySelective(deviceActiveInfo);
}
}
}
原因
读取配置没问题,但是在普通类@Autowired注入失败,原因是 我的普通类是oss上传工具类,然后在业务类方法中调用时使用了new 的方式!!!
// 2. 调用上传文件接口
OssUpload ossUpload = new OssUpload();
解决
业务类业务方法调用oss上传工具类时, 同样使用 @Autowired 自动注入的方式注入而不是new的方式!!!
@Autowired
private OssUpload ossUpload;
—— 以下引用自:风兮雨露——:
1、描述
有时候我们在某个类用@Autowired 进行注入时,会发现注入参数为null,这时候会有疑惑。
可能存在的原因:
(1)该类没有托管给spring 管理,一般在类的上面添加@Component
(2)你的这个类有被new出来的实例的,new 过的对象不会交给Spring容器管理 所以里面的 service或者dao注入不进来。一般是指引用某些框架,你是继承某个接口,但是这些框架默认new过这个方法,比如MVC拦截的HandlerInterceptor类。
2、解决方式
对于(1)其实就加入@Component 就可以了。接下来讲怎么解决第(2)种情况:
有时候你确实需要在这个new 的类去注入某些类,但是用@Autowired 又注入为null,这时候我们需要手动去弄Spring容器中的Bean实现ApplicationContextAware接口。
(1)比如我想在某个类实现RedisUtils 类的注入,但是用@autowired 会报null
(2)这时候我们就要手动实现这个功能,写个BeanUtils 类 实现ApplicationContextAware接口
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class BeanUtils implements ApplicationContextAware {
protected static ApplicationContext applicationContext ;
@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
if (applicationContext == null) {
applicationContext = arg0;
}
}
public static Object getBean(String name) {
//name表示其他要注入的注解name名
return applicationContext.getBean(name);
}
/**
* 拿到ApplicationContext对象实例后就可以手动获取Bean的注入实例对象
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
}
注意,该类必须用@Component 注解
(3)使用时用以下方式
/**
* 由于不能用@Autowired进行注入,则使用这种手动注入方式
*/
private RedisUtils redisUtils = BeanUtils.getBean(RedisUtils.class);
这样就要正常引用redisUtils ,这样手动出来的跟@Autowire 一样的。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/157192.html