《阿里云OSS实现APP版本包上传下载:代码实操指南》

目录

一、引言

二、阿里云OSS简介

三、代码实现

1.数据库

 2.实体类

3.控制层

4.业务层

5.数据层

6.ossUtil工具类

四、总结

一、引言

        在当前的移动互联网时代,APP的版本更新已经成为常态。如何快速、稳定地提供新版本的下载,是每个APP开发者和运营者需要考虑的问题。阿里云OSS(Object Storage Service)提供了一种解决方案,它可以帮助我们轻松实现APP版本包的存储和分发。

二、阿里云OSS简介

        阿里云OSS是一种对象存储服务,它提供了海量、安全、低成本、高可靠的云存储服务。我们可以将APP的版本包上传到OSS,然后通过OSS提供的URL进行下载。详情可以阅读这位博主讲解的基础使用,首先,我们需要在阿里云控制台创建一个OSS存储空间,用于存储APP的版本包。

阿里云对象存储OSS简介和使用icon-default.png?t=N7T8http://t.csdnimg.cn/3mmh4

三、代码实现

 以下是使用阿里云SDK for Java上传APP版本包并下载的示例代码:

1.数据库

CREATE TABLE `app_version` (
  `app_version_id` bigint(20) NOT NULL COMMENT '版本Id',
  `version_number` varchar(50) DEFAULT NULL COMMENT '版本号',
  `release_date` varchar(50) DEFAULT NULL COMMENT '发布日期',
  `description` varchar(255) DEFAULT NULL COMMENT '版本的描述',
  `force_update` tinyint(1) DEFAULT 0 COMMENT '是否需要强制更新',
  `download_link` varchar(255) DEFAULT NULL COMMENT '版本的下载链接',
  `is_deprecated` tinyint(1) DEFAULT NULL COMMENT '版本是否已被停用',
  PRIMARY KEY (`app_version_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 2.实体类

import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.io.Serializable;

@Data
public class AppVersion implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 版本Id
     */
    @TableId
    private Long appVersionId;

    /**
     * 版本号
     */
    private String versionNumber;

    /**
     * 发布日期
     */
    private String releaseDate;

    /**
     * 版本的描述
     */
    private String description;

    /**
     * 是否需要强制更新
     */
    private Integer forceUpdate;

    /**
     * 版本的下载链接
     */
    private String downloadLink;

    /**
     * 版本是否已被停用
     */
    private Integer isDeprecated;

}

3.控制层

@Api(tags = "版本检查更新")
@RestController
@RequestMapping("/appVersion")
public class AppVersionController {
    @Resource
    private AppVersionService appVersionService;

    @ApiOperation(value = "上传安卓apk和修改版本号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "newAppVersion", value = "版本Id", required = true, dataTypeClass = String.class),
            @ApiImplicitParam(name = "isForceUpdate", value = "是否强制更新", required = true, dataTypeClass = String.class)
    })
    @PostMapping("/update/android")
    public @ResponseBody
    Result<Object> updateAndroidVersion(@RequestParam("file") MultipartFile file,
                                        @RequestParam("newAppVersion") String newAppVersion,
                                        @RequestParam("isForceUpdate") String isForceUpdate) {
//ResponseUtil类是一个简单的封装返回结果工具类,重要的是service业务层
        return ResponseUtil.getServiceResponseResult(appVersionService.updateAndroidVersion(file, newAppVersion, Integer.valueOf(isForceUpdate)));
    }



    @ApiOperation(value = "下载安卓apk")
    @GetMapping("/download")
    public String downloadApk(HttpServletResponse response) {
        String resMsg = "";
        try {
            appVersionService.downloadApk(response);
        } catch (Exception me) {
            resMsg = me.getMessage();
        }
        return resMsg;
    }}

4.业务层

import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public interface AppVersionService extends IService<AppVersion> {
    /**
     * 上传安卓apk和修改版本号
     *
     * @param file          新版本软件包
     * @param newAppVersion 新版本的版本号
     * @param isForceUpdate 是否强制更新
     * @return 是否成功
     */
    BaseResult<Object> updateAndroidVersion(MultipartFile file, String newAppVersion, Integer isForceUpdate);

    /**
     * 下载安卓apk
     *
     * @param response 客户端响应对象
     * @throws IOException IO异常
     */
    void downloadApk(HttpServletResponse response) throws IOException;
}
@Service
@RefreshScope
public class AppVersionServiceImpl extends ServiceImpl<AppVersionMapper, AppVersion> implements AppVersionService {
    @Resource
    private AppVersionMapper appVersionMapper;

    @Override
    public BaseResult<Object> updateAndroidVersion(MultipartFile file, String newAppVersion, Integer isForceUpdate) {
        // 文件是否是apk包
        if (Objects.requireNonNull(file.getOriginalFilename()).endsWith(".exe") || Objects.requireNonNull(file.getOriginalFilename()).endsWith(".bat")) {
            throw new MyException(MessageUtilsNew.get("subject.oss.file.upload.format.error"));
        }

        // 保留每个版本的apk包
        String uploadFileName;
        if (!file.isEmpty()) {
            String originalFileName = file.getOriginalFilename();
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmssSSS");
//给上传的文件加一个标识,作为下载时的文件key
            uploadFileName = simpleDateFormat.format(new Date()) + originalFileName;
            try (InputStream stream = file.getInputStream()) {
                OssUtil.uploadFile(uploadFileName, stream);
            } catch (Exception e) {
                throw new MyException(MessageUtilsNew.get("subject.oss.file.save.error"));
            }
        } else {
            throw new MyException(MessageUtilsNew.get("subject.oss.file.upload.empty"));
        }

        // 更新当前apk包的版本信息
        AppVersion appVersion = appVersionMapper.selectByAppVersionId(1L);
        appVersion.setVersionNumber(newAppVersion);
        appVersion.setDownloadLink(uploadFileName);
        appVersion.setForceUpdate(isForceUpdate);
        appVersionMapper.updateByAppVersionId(appVersion);
        return BaseResult.success();
    }


    /**
     * @param response 客户端响应对象
     * downloadlink 下载地址或者oss文件地址
     */
    @Override
    public void downloadApk(HttpServletResponse response) throws IOException {
        // 下载所需的apk包
        AppVersion appVersion = appVersionMapper.selectByAppVersionId(1L);
        if (appVersion != null && appVersion.getDownloadLink() != null && StringUtils.isNotEmpty(appVersion.getDownloadLink())) {
            OssUtil.downloadFile(response, appVersion.getDownloadLink(), appVersion.getDownloadLink().substring(17));
        }
    }

}

5.数据层

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Update;

public interface AppVersionMapper extends BaseMapper<AppVersion> {

    @Update("update app_version set version_number = #{versionNumber},download_link = #{downloadLink},force_update = #{forceUpdate},description = #{description}, is_deprecated = #{isDeprecated} where app_version_id = #{appVersionId}")
    void updateByAppVersionId(AppVersion appVersion);

    @Select("select * from app_version where app_version_id = #{appVersionId}")
    AppVersion selectByAppVersionId(Long appVersionId);

}

6.ossUtil工具类


import com.aliyun.oss.ClientBuilderConfiguration;

@Component
public class OssUtil {
    //这些配置参数设为自己的即可

    private static String bucket;

    private static String endpoint;

    private static String accessKeyId;

    private static String accessKeySecret;

    private static boolean sldEnabled;

    /**
     * 上传文件(fileKey-InputStream)
     */
    public static void uploadFile(String fileKey, InputStream stream) throws IOException {
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSLDEnabled(sldEnabled);
        OSS client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);

        try {
            client.putObject(bucket, fileKey, stream);
        } finally {
            stream.close();
            if (client != null) {
                client.shutdown();
            }
            IOUtils.closeQuietly(stream);
        }
    }


    /**
     * 文件下载
     */
    public static void downloadFile(HttpServletResponse response, String fileKey, String fileName) throws IOException {
        InputStream stream = null;
        BufferedInputStream bufferedInputStream = null;
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSLDEnabled(sldEnabled);
        OSS client = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);
        try {
            stream = client.getObject(bucket, fileKey).getObjectContent();
            response.reset();
            response.setContentType("application/octet-stream");
            response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")
                    .replace("+", "%20"));
            OutputStream outputStream = response.getOutputStream();
            bufferedInputStream = new BufferedInputStream(stream);
            byte[] buf = new byte[16384];
            int bytesRead;
            while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
                outputStream.write(buf, 0, bytesRead);
                outputStream.flush();
            }
        } finally {
            if (client != null) {
                client.shutdown();
            }

            if (bufferedInputStream != null || stream != null) {
                try {
                    bufferedInputStream.close();
                    stream.close();
                } catch (IOException e) {
                    log.error("Oss Download IOException,fileKey:" + fileKey, e);
                }
            }
        }
    }
}



四、总结

        通过阿里云OSS,我们可以方便地实现APP版本包的存储和下载,大大提高了APP更新的效率和用户体验。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

先锋 Coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值