小翔认为不论是上传文件还是图片其实最重要的就是流这个东东,流他能干嘛呢 ,把文件中的数据信息以流的形式读取,以流的形式写入,以流的形式输入,总而言之,是以流的形式行走各个服务器角落.
通常上传文件后端的接收要么是MultipartFile 类型,要么是String类型的URL, 我们看MultipartFile ,他是继承了InputStreamSource 也是流其中有很多属性,可以从中获取相应的东西
首先咱们说一下接收String类型的URL,现附上一段代码
//此方法是会返回上传图片之后,能够下载图片的地址
private String saveImageToFileLibrary(String imgUrl) {
log.info("上传图片到oss服务器,原图片地址:" + imgUrl);
String saveUrl = "";
//首先根据图片链接获取图片远程服务器,并读取图片中数据信息转换为流
try {
URL urlConnect = new URL(imgUrl);
HttpURLConnection con = (HttpURLConnection) urlConnect.openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(20 * 1000);
//防止屏蔽程序抓取而返回403错误
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
InputStream inStream = con.getInputStream(); //通过输入流获取图片数据
//String fileExtName = imgUrl.substring(imgUrl.lastIndexOf(".") + 1);
//这里我获取的是微信的图片,微信图片地址一般是不带后缀的所以这里写死,其余地址的图片链接可以使用以上方式获取图片后缀
String fileExtName = ".jpeg";
String randomFileName = RandomStringUtils.randomAlphanumeric(32).toLowerCase();
log.info("上传图片到oss服务器,上传的数据:" + randomFileName + fileExtName);
//这里是调用公共的服务
UploadBase64FileResponseDto responseDto = fileManager.uploadInputStreamFile(inStream, randomFileName + fileExtName);
log.info("上传图片到oss服务器,得到的数据:" + JSON.toJSONString(responseDto));
if (responseDto != null) {
saveUrl = responseDto.getUrl();
}
} catch (Exception e) {
log.error("上传图片到oss服务器失败:", e);
}
//如果为空,返回原url
if (StringUtils.isBlank(saveUrl)) {
saveUrl = imgUrl;
}
log.info("上传图片到oss服务器,上传后得到的图片地址:" + saveUrl);
return saveUrl;
}
//接收String类型的URL需要根据图片链接获取图片远程服务器,并读取图片中数据信息转换为流, 代码中fileManager是一个公共的服务,一般我们在写代码的时候需要考虑复用性,能够多方位提供服务,不能单单指为一个功能进行使用,所以将能够复用的代码提取出来称为公共服务这也是一种优秀的代码习惯(这里需要感谢下我老大的指点QvQ)
下面附上fileManager中的代码
@Component
public class FileManager {
private final FileLibraryClient fileLibraryClient;
private Logger logger = LoggerFactory.getLogger(FileManager.class);
@Lazy //使用了懒加载
public FileManager(FileLibraryClient fileLibraryClient) {
this.fileLibraryClient = fileLibraryClient;
}
public BaseResponseDto<List<UploadBase64FileResponseDto>> uploadBase64File(List<UploadBase64FileRequestDto> files) {
BaseRequestDto<List<UploadBase64FileRequestDto>> base64Files = new BaseRequestDto<>();
base64Files.setRequest(files);
try {
//调用文件中心rpc接口
return fileLibraryClient.uploadBase64FilePrd(base64Files);
} catch (IOException e) {
logger.error("上传文件到OSS失败【{}】", e);
e.printStackTrace();
}
return null;
}
public UploadBase64FileResponseDto uploadInputStreamFile(InputStream fis, String name) throws Exception {
List<UploadBase64FileRequestDto> files = new ArrayList<>();
try {
//初始化字节数组
byte[] dataArr = new byte[fis.available()];
//将图片流转变为字节数组
fis.read(dataArr);
//将图片字节数组信息进行Base64加密
String base64Str = Base64.encodeBase64String(dataArr);
UploadBase64FileRequestDto dto = new UploadBase64FileRequestDto();
dto.setBase64String(base64Str);
dto.setFileId(name);
dto.setFileName(name);
files.add(dto);
} catch (Exception e) {
e.printStackTrace();
}
//上传文件
BaseResponseDto<List<UploadBase64FileResponseDto>> res = uploadBase64File(files);
if (null != res) {
List<UploadBase64FileResponseDto> dtoList = res.getData();
if (null == dtoList || 0 == dtoList.size()) {
logger.error("上传文件失败【{}】", res);
throw new Exception("上传文件失败");
} else {
return dtoList.get(0);
}
}
return null;
}
}
下面就是文件中心上传文件所真正需要的操作了
@PostMapping(value = "/uploadBase64FilePrd")
public BaseResponseDto<List<UploadBase64FileResponseDto>> uploadBase64FilePrd(@RequestBody BaseRequestDto<List<UploadBase64FileRequestDto>> base64Files){
List<UploadBase64FileRequestDto> requestDtoList = base64Files.getRequest() ;
if(requestDtoList == null || requestDtoList.size() == 0){
ApplicationExceptionUtil.throwBusinessException("上传文件不能为空");
}
BaseResponseDto<List<UploadBase64FileResponseDto>> baseResponseDto = new BaseResponseDto<>() ;
List<UploadBase64FileResponseDto> responseDtoList = Lists.newArrayList() ;
UploadBase64FileResponseDto responseDto ;
for(UploadBase64FileRequestDto requestDto : requestDtoList){
responseDto = new UploadBase64FileResponseDto() ;
String base64String = requestDto.getBase64String();
String fileName = requestDto.getFileName();
//真正干事的工具类
String ossFileName = microsoftOSSClientUtilPrd.uploadBase64File(base64String, fileName);
if(ossFileName == null){
baseResponseDto.setSuccess(false);
baseResponseDto.setCode("1");
baseResponseDto.setMessage("文件上传失败");
return baseResponseDto ;
}
String fileId = requestDto.getFileId() ;
responseDto.setFileId(fileId);
responseDto.setOssFileName(ossFileName);
//上传之后下载图片的地址 这个就是最终的返回结果 一般都是拼接的 ipAddress为服务器IP ossFileName为编码之后的文件名称
responseDto.setUrl(ipAddress+"/guoke-channel-aggregation-center/api/v1/files/download/"+ossFileName);
responseDtoList.add(responseDto) ;
}
baseResponseDto.setData(responseDtoList);
return baseResponseDto ;
}
真正的操作来喽!
@Component
public class MicrosoftOSSClientUtilPrd {
@Value("${oss.account.name.prd}")//创建连接所需要的名字
public String accountNamePrd ;
@Value("${oss.account.secretKey.prd}")//创建连接所需要的key
public String accountKeyPrd ;
@Value("${oss.account.container.name.prd}")//固定容器名字
public String containerNamePrd ;
@Autowired
private FcCommonFileInfoService fcCommonFileInfoService;
private ContainerURL containerURL;
private static final Logger logger = LoggerFactory.getLogger(MicrosoftOSSClientUtilPrd.class);
public ContainerURL getContainerURLPrdClient() {
try {
// Create a ServiceURL to call the Blob service. We will also use this to construct the ContainerURL
logger.info("----------------初始化微软云文件服务器---------------------");
logger.info("accountName [{}],accountKey [{}],containerName [{}]",accountNamePrd,accountKeyPrd,containerNamePrd);
SharedKeyCredentials creds = new SharedKeyCredentials(accountNamePrd, accountKeyPrd);
// We are using a default pipeline here, you can learn more about it at https://github.com/Azure/azure-storage-java/wiki/Azure-Storage-Java-V10-Overview
final ServiceURL serviceURL = new ServiceURL(new URL("https://" + accountNamePrd + ".blob.core.chinacloudapi.cn"), StorageURL.createPipeline(creds, new PipelineOptions()));
// Let's create a container using a blocking call to Azure Storage
// If container exists, we'll catch and continue
ContainerURL containerURL = serviceURL.createContainerURL(containerNamePrd);
containerURL.create();
logger.info("创建OSS客户端成功");
return containerURL;
} catch (Exception e) {
logger.info("创建OSS客户端失败");
return null;
}
}
/**
* base64String 图片流的加码
* fileName 名字在这里不太重要 是刚开始的随机32为+文件后缀
* 整个过程中重要的是文件的流 流才是真正的数据
* */
public String uploadBase64File(String base64String , String fileName) {
String[] splits = fileName.split("\\.");
String fileExtName = splits[splits.length - 1];
String randomFileName = RandomUtil.randomString(32);
String ossFileName = randomFileName + "." + fileExtName ;
//开始上传文件
File tempFile = null;
try {
//在本地服务器上创建临时文件
tempFile = File.createTempFile(randomFileName, fileExtName);
//以下的4行的作用是将加码的文件流进行解码 将流开始输出复制到本地服务器上创建的临时文件中
// 此时这个临时文件就已经是跟你上传的文件时一模一样了
FileOutputStream outputStream = new FileOutputStream(tempFile);
outputStream.write(new BASE64Decoder().decodeBuffer(base64String));
outputStream.flush();
outputStream.close();
Long length = tempFile.length();
if(null == containerURL){
//初始化微软云文件服务器
containerURL = getContainerURLPrdClient();
}
BlockBlobURL blockBlob = null;
try{
//创建连接微软云链接
blockBlob = containerURL.createBlockBlobURL(ossFileName);
}catch (Exception e){
//如果遇到上传文件失败,可能是客户端连接断开。重新建立连接上传。
containerURL = null;
blockBlob = getContainerURLPrdClient().createBlockBlobURL(ossFileName);
}
//根据临时文件路径异步打开通向微软云管道以流的形式上传文件
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(tempFile.toPath());
//上传文件
TransferManager.uploadFileToBlockBlob(fileChannel, blockBlob, 8 * 1024, null, null).blockingGet().statusCode();
//记录上传文件
try{
FcCommonFileInfoPO po = new FcCommonFileInfoPO();
po.setFileCode(randomFileName);
po.setFileName(fileName);
po.setCompanyId("");
po.setFileSize(new BigDecimal(length));
po.setFileType(fileExtName);
po.setFileUrl(blockBlob.toString());
//将上传的文件存入数据库
fcCommonFileInfoService.createFileInfoPO(po);
}catch (Exception e){
e.printStackTrace();
}
} catch (Exception e) {
logger.info("文件上传失败", e);
ossFileName = null ;
}finally {
if (null != tempFile) {
tempFile.delete();
}
}
return ossFileName ;
}
}
好了这是接收String类型图片URL的java文件上传至微软云 文件的名字不重要重要的是文件流 ,下面是接收MultipartFile类型的参数,其实都是一样的使用流进行的流转
看代码
@PostMapping("/upload")
@ResponseBody
public Payload upload(MultipartFile file) {
if (file.isEmpty()) {
logger.info("文件不能为空");
throw new ApplicationException(ResultEnum.BAD_REQUEAT);
}
//获取上传文件文件名
if (StringUtil.isBlank(file.getOriginalFilename())) {
logger.info("文件名不能为空");
throw new ApplicationException(ResultEnum.BAD_REQUEAT);
}
//获取文件的名字
String fileName = file.getOriginalFilename();
logger.info("上传文件文件名---->{}", fileName);
//获取文件类型,png,txt....
String[] splits = fileName.split("\\.");
if (splits.length <= 1) {
logger.info("获取文件后缀失败");
throw new ApplicationException(ResultEnum.BAD_REQUEAT);
}
String fileExtName = splits[splits.length - 1];
String randomFileName = RandomUtil.randomString(32);
BigDecimal fileSize = new BigDecimal(file.getSize());
//开始上传文件
BlockBlobURL blockBlob = null;
File tempFile = null;
try {
tempFile = File.createTempFile(randomFileName, fileExtName);
logger.info("文件地址:::" + tempFile.getCanonicalPath());
//将文件的字节流输出到临时文件中
FileOutputStream outputStream = new FileOutputStream(tempFile);
outputStream.write(file.getBytes());
outputStream.close();
//创建微软云连接上传图片
blockBlob = container.createBlockBlobURL(randomFileName + "." + fileExtName);
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(tempFile.toPath());
TransferManager.uploadFileToBlockBlob(fileChannel, blockBlob, 8 * 1024, null, null).blockingGet().statusCode();
FileInfoReqDto reqDto = new FileInfoReqDto();
reqDto.setFileCode(randomFileName);
reqDto.setFileName(fileName);
reqDto.setCompanyId(ContextUtil.getCompanyId());
reqDto.setSize(fileSize);
reqDto.setFileType(fileExtName);
reqDto.setFileUrl(blockBlob.toString());
// fileManager.saveFileInfo(reqDto); 保存文件这是另一个中心的服务与上边代码中的
//fileManager不一样
//如果是图片的话直接返回微软云地址,否则需要经过我们服务器去访问微软云文件
String fileAddress = ip + "/guoke-channel-aggregation-center/api/v1/files/download/" + randomFileName + "." + fileExtName;
return new Payload(fileAddress);
} catch (IOException e) {
logger.info("文件上传失败", e);
throw ApplicationExceptionFactory.create("500", "文件上传失败");
}finally {
if (null != tempFile) {
tempFile.delete();
}
}
}
好了这是完整的上传文件微软云的代码 有任何问题 可以在评论区呼我 我随时都在0v0 ! 对了记得在配置文件中配置所使用的微软云服务器得IP地址 名称 和key