Java使用OSS文件Web直传并进行回调

OSS上传文件的三种模式

1.web端直传种模式

Web端常见的上传方法是用户在浏览器或app端上传文件到应用服务器,然后应用服务器再把文件上传到OSS,如下图所示:在这里插入图片描述
特点:上传慢。先上传到应用服务器,再上传到OSS

2.服务端签名后直传

采用javaScript端向服务端发起签名请求,获取参数后直传OSS
在这里插入图片描述
特点:客户端向服务端请求签名,然后直接上传,不会对服务端产生压力,而且安全可靠。

3.服务端签名后直传并设置上传回调

客户端向服务端发起签名请求后,直传OSS然后OSS会回调对应的服务端回调接口,OSS回调完成后,应用服务器再返回结果给客户端。
在这里插入图片描述
特点:用户上传一个文件到OSS后,OSS会将上传结果返回给应用服务器,然后应用服务器会给OSS响应,然后OSS会将相关响应通知给客户端的用户。

后端(Java)代码案例:

1、导入阿里云的jar

	<!--    OSS    -->
	<dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>2.8.3</version>
    </dependency>
    <!--    日志    -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-logging</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.73</version>
    </dependency>
    <!--    json序列化反序列化    -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-json</artifactId>
    </dependency>
    <!--    lombok    -->
    <dependency>
         <groupId>org.projectlombok</groupId>
         <artifactId>lombok</artifactId>
    </dependency>

在编写代码的时候注意导入的jar是否为此jar,本文引入的为此jar,因为阿里云的jar更新迭代的几个版本有依赖关系。

1、Controller层

@CrossOrigin
@RestController
public class OssController {

    @Autowired
    OssService ossService;

	/**
     * 获取oss系统配置
     * @return
     */
    @PostMapping("/oss/config/get")
    @ApiOperation("获取oss系统配置")
    public JsonResult<Map> getOssConfig(){
        try {
            return JsonResult.ok(ossService.generateOssParam());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取回调
     * @param callBackHost
     * @param callBackInterFace
     * @param callBackBody
     * @param callbackBodyType
     * @return
     * @throws UnsupportedEncodingException
     */
    @PostMapping("/call/back/get")
    @ApiOperation("获取回调")
    public String generateCallBack(String callBackHost, String callBackInterFace, String callBackBody,String callbackBodyType) throws UnsupportedEncodingException {
        return ossService.generateCallBack(callBackHost,callBackInterFace,callBackBody,callbackBodyType);
    }

    /**
     * 获取签名
     * @param callBack 回调信息
     * @return
     */
    @PostMapping("/generateSign/get")
    @ApiOperation("获取签名")
    public JsonResult<Map> generateSign(String callBack){
        try {
            return JsonResult.ok(ossService.generateSign(callBack));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description OSS上传回调
     * @Author
     * @Param [ossCallbackBody, authorization, publicKeyUrlBase64, request, response]
     * @Return com.ejsino.chat.config.domain.JSONResult
     * @return
     */
    @PostMapping("/ossCallBack")
    @ApiOperation("OSS上传回调")
    public JsonResult<String> callBack(@RequestBody String ossCallbackBody, @RequestHeader("Authorization") String authorization,
                                       @RequestHeader("x-oss-pub-key-url") String publicKeyUrlBase64, HttpServletRequest request,
                                       HttpServletResponse response) {
        boolean isCallBack = ossService.verifyOSSCallbackRequest(authorization, publicKeyUrlBase64, ossCallbackBody, request.getQueryString(), request.getRequestURI());
        if (isCallBack) {
            response.setStatus(HttpServletResponse.SC_OK);
            // 此处必须使用json形式返回,不然oss回调报 <Message>Response body is not valid json format.</Message>
            return JsonResult.ok("success");
        } else {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            // 此处必须使用json形式返回,不然oss回调报 <Message>Response body is not valid json format.</Message>
            return JsonResult.ok("error");
        }
    }

2、Service层

@Service
public class OssService {

    private Logger log = LoggerFactory.getLogger("logger");

	 /**
     * @Description OSS上传需要的OSS服务参数获取
     * @Param []
     * @Return java.util.HashMap<java.lang.Stringjava.lang.Object>
     */
    public HashMap<String, Object> generateOssParam() throws Exception {
        try {
            // 获取域名
            String domain = "<填写自己应用服务器地址>";
            // 文件路径
            String dir = "<填写oss文件路径>"; // 例如: 'mytest' 切记不要写成 '/mytest' !!!
            String bucketName = "<oss控制台中的Bucket 域名>";
            String endPoint = "<oss控制台中的Endpoint(地域节点)>";
            String accessKeyId = "<oss的AccessKey管理中的AccessKey ID>";
            String host = "http://" + bucketName;
            HashMap<String, Object> respMap = new LinkedHashMap<String, Object>();
            respMap.put("accessid", accessKeyId);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("domain", domain);
            return respMap;
        } catch (Exception e) {
            log.error("获取OSS上传参数失败:" + e);
            throw new Exception("获取OSS上传参数失败!");
        }
    }

    /**
     * @Description OSS回调系统服务参数生成
     * @Param [callBackHost:要OSS进行回调的服务域名(不带http),
     * callBackInterFace:要进行回调的接口(oss上传结束进行请求的接口),
     * callBackBody:进行回调时携带的参数(以:key=value 的形式进行携带)]
     * @Return java.lang.String
     */
    public String generateCallBack(String callBackHost, String callBackInterFace, String callBackBody,String callbackBodyType) throws UnsupportedEncodingException {
        Map<String, Object> callbackMap = new HashMap<String, Object>();
        callbackMap.put("callbackUrl", "http://" + callBackHost + callBackInterFace);
        callbackMap.put("callbackHost", callBackHost);
        callbackMap.put("callbackBody", callBackBody);
        callbackMap.put("callBackType",callbackBodyType);
        callbackMap.put("callbackBodyType", "application/x-www-form-urlencoded");
        byte[] bytes = JSON.toJSONString(callbackMap).getBytes();
        String callBackString = BinaryUtil.toBase64String(bytes);
        System.err.println(callBackString);
        return callBackString;
    }

    /**
     * @Description 生成签名
     * @Param [callBack :要进行回调的参数,传入为空即默认为不进行回调]
     * @Return java.util.HashMap<java.lang.String       java.lang.Object>
     */
    public HashMap<String, Object> generateSign(String callBack) throws Exception {
        //获取上传oss需要的基本参数
        String endPoint = "<oss控制台中的Endpoint(地域节点)>";
        String accessKeyId = "<oss的AccessKey管理中的AccessKey ID>";
        String accessKeySecret = "<oss的AccessKey管理中的Secret>";
        String dir = "<填写oss文件路径>"; // 例如: 'mytest' 切记不要写成 '/mytest' !!!
       OSSClient client = null;
        try {
            //开启OSS客户端
            client = new OSSClient(endPoint, accessKeyId, accessKeySecret);
            long expireTime = 100;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            //生成的到期时间转换位s,并转换为String
            String expire = String.valueOf(expireEndTime / 1000);
            PolicyConditions policyConditions = new PolicyConditions();
            policyConditions.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConditions.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            //根据到期时间生成policy
            Date expiration = new Date(expireEndTime);
            String postPolicy = client.generatePostPolicy(expiration, policyConditions);
            //生成signature
            String postSignature = client.calculatePostSignature(postPolicy);
            //对policy进行UTF-8编码后转base64
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            //生成上传文件的文件名
            String fileName = "mytest" + UUID.randomUUID().toString();
            //封装生成好的数据进行参数返回
            HashMap<String, Object> respMap = new LinkedHashMap<String, Object>();
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("expire", expire);
            respMap.put("fileName", fileName);
            //callBack不为空时为OSS回调web服务上传
            if (callBack != null && callBack != "") {
                respMap.put("callback", callBack);
            }
            return respMap;
        } catch (Exception e) {
            log.error("生成OSS上传签名失败:" + e);
            throw new Exception("生成OSS上传签名失败!");
        } finally {
            if (client != null) {
                client.shutdown();
            }
        }
    }

    /**
     * @Description OSS回调请求验证
     * @Param [authorizationInput, pubKeyInput, ossCallbackBody, queryString, uri]
     * @Return boolean
     */
    public boolean verifyOSSCallbackRequest(String authorizationInput, String pubKeyInput, String ossCallbackBody, String queryString, String uri){
        boolean ret = false;
        try {
            //将base64编码的数据进行还原
            byte[] authorization = BinaryUtil.fromBase64String(authorizationInput);
            byte[] pubKey = BinaryUtil.fromBase64String(pubKeyInput);
            String pubKeyAddr = new String(pubKey);
            if (!pubKeyAddr.startsWith("http://gosspublic.alicdn.com/") && !pubKeyAddr.startsWith("https://gosspublic.alicdn.com/")) {
                log.error("pub key addr must be oss address");
                return false;
            }
            //获取请求中的公钥信息
            String retString = executeGet(pubKeyAddr);
            retString = retString.replace("-----BEGIN PUBLIC KEY-----", "");
            retString = retString.replace("-----END PUBLIC KEY-----", "");
            String decodeUri = URLDecoder.decode(uri, "utf-8");
            if (queryString != null && !"".equals(queryString)) {
                decodeUri += "?" + queryString;
            }
            decodeUri += "\n" + ossCallbackBody;
            ret = doCheck(decodeUri, authorization, retString);
        } catch (Exception e) {
            ret = false;
            log.error("验证OSS请求出现异常:" + e);
        }
        return ret;
    }

    /**
     * @Description 获取请求中的参数
     * @Param [pubKeyUrl]
     * @Return java.lang.String
     */
    @SuppressWarnings({"finally"})
    private String executeGet(String pubKeyUrl) throws Exception {
        BufferedReader in = null;
        String content = null;
        try {
            // 定义HttpClient
            @SuppressWarnings("resource")
            DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
            // 实例化HTTP方法
            HttpGet request = new HttpGet();
            request.setURI(new URI(pubKeyUrl));
            HttpResponse response = defaultHttpClient.execute(request);
            in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            content = sb.toString();
            return content;
        } catch (Exception e) {
            log.error("解析公钥参数失败:" + e);
            throw new Exception("解析公钥参数失败!");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("关闭BufferedReader出现异常:" + e);
                }
            }
        }
    }

    /**
     * @Description 对请求参数进行规则校验
     * @Param [content, sign, publicKey]
     * @Return boolean
     */
    private boolean doCheck(String content, byte[] sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            byte[] encodedKey = BinaryUtil.fromBase64String(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
            java.security.Signature signature = java.security.Signature.getInstance("MD5withRSA");
            signature.initVerify(pubKey);
            signature.update(content.getBytes());
            boolean bverify = signature.verify(sign);
            return bverify;
        } catch (Exception e) {
            log.error("校验出现异常:" + e);
        }
        return false;
    }

}

至此,Java使用OSS直传就完成啦,其中 ‘<>’ 中的值按照提示更改即可,如遇到 xml 异常可以查询 OSS对象存储错误响应

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值