• 关于

    try...catch的方式处理异常

    的搜索结果

问题

mysql 事务回滚原理及疑问

蛮大人123 2019-12-01 20:11:48 3903 浏览量 回答数 2

回答

" <img src=""/img/bVDhN3?w=568&h=47"" alt=""clipboard.png"" title=""clipboard.png"" />###### 受检的异常必须要声明抛出或者try catch。###### 这不是异常 这是编译错误###### 首先你要看看书搞懂下JAVA的异常处理机制,内容较多不在这细说。但是其中有一点是可以回答你这个问题的,就是java要求在调用含有异常抛出声明的方法时(也就是方法后面含有 throws xxxxException 的情况)必须对异常进行处理。处理方式有两种: 继续声明抛出异常,将异常处理交给下一个调用者;使用try...catch块进行异常处理; 用你的代码举个栗子: //第一种处理方式 public static void main(String[] args) throws Exception { //使用throws关键字声明抛出异常 //这种处理方式是将异常继续向上抛,大多数情况下不会在main方法中这样做 system.print.out(getDay('xxxx-xx-xx',1)); } //第二种处理方式 public static void main(String[] args) { //使用try..catch块处理异常 //这种处理方式是将异常进行人工处理 try{ system.print.out(getDay('xxxx-xx-xx',1)); }catch(Exception e){ //处理异常代码,比如进行异常信息输出或者记录日志,或者其他符合业务需求的逻辑 } }###### getDay()方法将它的异常 抛给了它的上层(调用它的地方)。在main方法中 没有对getDay()的异常进行处理,所以报错。###### 调用抛出异常的方法必须对异常进行处理或重新抛出" ![image.png](https://ucc.alicdn.com/pic/developer-ecology/def96e23a85749dba53d5c6c71c49fcc.png)

因为相信,所以看见。 2020-05-27 10:09:02 0 浏览量 回答数 0

问题

Mybatis整合Spring配置事务无效问题 : 配置报错 

kun坤 2020-06-03 17:31:23 5 浏览量 回答数 1

阿里云高校特惠,助力学生创业梦!0元体验,快速入门云计算!

学生动手场景应用,快速了解并掌握云服务器的各种新奇玩法!

问题

分析型数据库如何进行业务系统连接并进行查询?

nicenelly 2019-12-01 21:25:47 1036 浏览量 回答数 0

回答

一、Consumer 批量消费 可以通过 [java] view plain copyconsumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 这里需要分为2种情况1、Consumer端先启动 2、Consumer端后启动. 正常情况下:应该是Consumer需要先启动1、Consumer端先启动 Consumer代码如下 [java] view plain copypackage quickstart; import java.util.List; import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere; import com.alibaba.rocketmq.common.message.MessageExt; /** Consumer,订阅消息 */ public class Consumer { public static void main(String[] args) throws InterruptedException, MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4"); consumer.setNamesrvAddr("192.168.100.145:9876;192.168.100.146:9876"); consumer.setConsumeMessageBatchMaxSize(10); /** * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br> * 如果非第一次启动,那么按照上次消费的位置继续消费 */ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { try { System.out.println("msgs的长度" + msgs.size()); System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs); } catch (Exception e) { e.printStackTrace(); return ConsumeConcurrentlyStatus.RECONSUME_LATER; } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); consumer.start(); System.out.println("Consumer Started."); } } 由于这里是Consumer先启动,所以他会去轮询MQ上是否有订阅队列的消息,由于每次producer插入一条,Consumer就拿一条所以测试结果如下(每次size都是1): 2、Consumer端后启动,也就是Producer先启动 由于这里是Consumer后启动,所以MQ上也就堆积了一堆数据,Consumer的 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 所以这段代码就生效了测试结果如下(每次size最多是10): 二、消息重试机制:消息重试分为2种1、Producer端重试 2、Consumer端重试 1、Producer端重试 也就是Producer往MQ上发消息没有发送成功,我们可以设置发送失败重试的次数 [java] view plain copypackage quickstart; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.client.producer.DefaultMQProducer; import com.alibaba.rocketmq.client.producer.SendResult; import com.alibaba.rocketmq.common.message.Message; /** Producer,发送消息 */ public class Producer { public static void main(String[] args) throws MQClientException, InterruptedException { DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name"); producer.setNamesrvAddr("192.168.100.145:9876;192.168.100.146:9876"); producer.setRetryTimesWhenSendFailed(10);//失败的 情况发送10次 producer.start(); for (int i = 0; i < 1000; i++) { try { Message msg = new Message("TopicTest",// topic "TagA",// tag ("Hello RocketMQ " + i).getBytes()// body ); SendResult sendResult = producer.send(msg); System.out.println(sendResult); } catch (Exception e) { e.printStackTrace(); Thread.sleep(1000); } } producer.shutdown(); } } 2、Consumer端重试 2.1、exception的情况,一般重复16次 10s、30s、1分钟、2分钟、3分钟等等 上面的代码中消费异常的情况返回 return ConsumeConcurrentlyStatus.RECONSUME_LATER;//重试 正常则返回: return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;//成功 [java] view plain copypackage quickstart; import java.util.List; import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere; import com.alibaba.rocketmq.common.message.MessageExt; /** Consumer,订阅消息 */ public class Consumer { public static void main(String[] args) throws InterruptedException, MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name_4"); consumer.setNamesrvAddr("192.168.100.145:9876;192.168.100.146:9876"); consumer.setConsumeMessageBatchMaxSize(10); /** * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br> * 如果非第一次启动,那么按照上次消费的位置继续消费 */ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { try { // System.out.println("msgs的长度" + msgs.size()); System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs); for (MessageExt msg : msgs) { String msgbody = new String(msg.getBody(), "utf-8"); if (msgbody.equals("Hello RocketMQ 4")) { System.out.println("======错误======="); int a = 1 / 0; } } } catch (Exception e) { e.printStackTrace(); if(msgs.get(0).getReconsumeTimes()==3){ //记录日志 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功 }else{ return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 重试 } } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功 } }); consumer.start(); System.out.println("Consumer Started."); } } 打印结果: 假如超过了多少次之后我们可以让他不再重试记录 日志。 if(msgs.get(0).getReconsumeTimes()==3){//记录日志 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功} 2.2超时的情况,这种情况MQ会无限制的发送给消费端。 就是由于网络的情况,MQ发送数据之后,Consumer端并没有收到导致超时。也就是消费端没有给我返回return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;这样的就认为没有到达Consumer端。 这里模拟Producer只发送一条数据。consumer端暂停1分钟并且不发送接收状态给MQ [java] view plain copypackage model; import java.util.List; import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere; import com.alibaba.rocketmq.common.message.MessageExt; /** Consumer,订阅消息 */ public class Consumer { public static void main(String[] args) throws InterruptedException, MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("message_consumer"); consumer.setNamesrvAddr("192.168.100.145:9876;192.168.100.146:9876"); consumer.setConsumeMessageBatchMaxSize(10); /** * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br> * 如果非第一次启动,那么按照上次消费的位置继续消费 */ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { try { // 表示业务处理时间 System.out.println("=========开始暂停==============="); Thread.sleep(60000); for (MessageExt msg : msgs) { System.out.println(" Receive New Messages: " + msg); } } catch (Exception e) { e.printStackTrace(); return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 重试 } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功 } }); consumer.start(); System.out.println("Consumer Started."); } } 三、消费模式 广播消费:rocketMQ默认是集群消费,我们可以通过在Consumer来支持广播消费 consumer.setMessageModel(MessageModel.BROADCASTING);// 广播消费 [java] view plain copypackage model; import java.util.List; import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently; import com.alibaba.rocketmq.client.exception.MQClientException; import com.alibaba.rocketmq.common.consumer.ConsumeFromWhere; import com.alibaba.rocketmq.common.message.MessageExt; import com.alibaba.rocketmq.common.protocol.heartbeat.MessageModel; /** Consumer,订阅消息 */ public class Consumer2 { public static void main(String[] args) throws InterruptedException, MQClientException { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("message_consumer"); consumer.setNamesrvAddr("192.168.100.145:9876;192.168.100.146:9876"); consumer.setConsumeMessageBatchMaxSize(10); consumer.setMessageModel(MessageModel.BROADCASTING);// 广播消费 consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { try { for (MessageExt msg : msgs) { System.out.println(" Receive New Messages: " + msg); } } catch (Exception e) { e.printStackTrace(); return ConsumeConcurrentlyStatus.RECONSUME_LATER;// 重试 } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// 成功 } }); consumer.start(); System.out.println("Consumer Started."); } } 如果我们有2台节点(非主关系),2个节点物理上是分开的,Producer往MQ上写入20条数据 其中broker1中拉取了12条 。broker2中拉取了8 条,这种情况下,假如broker1宕机,那么我们消费数据的时候,只能消费到broker2中的8条,broker1中的12条已经持久化到中。需要broker1回复之后这12条数据才能继续被消费。 异步复制和同步双写主要是主和从的关系。消息需要实时消费的,就需要采用主从模式部署 异步复制:比如这里有一主一从,我们发送一条消息到主节点之后,这样消息就算从producer端发送成功了,然后通过异步复制的方法将数据复制到从节点 同步双写:比如这里有一主一从,我们发送一条消息到主节点之后,这样消息就并不算从producer端发送成功了,需要通过同步双写的方法将数据同步到从节点后, 才算数据发送成功。 四、刷盘方式 同步刷盘:在消息到达MQ后,RocketMQ需要将数据持久化,同步刷盘是指数据到达内存之后,必须刷到commitlog日志之后才算成功,然后返回producer数据已经发送成功。 异步刷盘:,同步刷盘是指数据到达内存之后,返回producer说数据已经发送成功。,然后再写入commitlog日志。 commitlog: commitlog就是来存储所有的元信息,包含消息体,类似于Mysql、Oracle的redolog,所以主要有CommitLog在,Consume Queue即使数据丢失,仍然可以恢复出来。 consumequeue:记录数据的位置,以便Consume快速通过consumequeue找到commitlog中的数据

xuning715 2019-12-02 01:11:55 0 浏览量 回答数 0

问题

Java中资源关闭的处理方式

游客bnlxddh3fwntw 2020-04-23 21:18:14 4 浏览量 回答数 1

问题

Java异常的抛出问题

蛮大人123 2019-12-01 19:57:10 911 浏览量 回答数 1

问题

sping4线程池如何获得session??报错

爱吃鱼的程序员 2020-06-09 14:17:26 0 浏览量 回答数 1

回答

本文介绍使用 Java SDK 的详细流程,包括环境要求、安装依赖和快速使用三部分。 环境要求 要使用 Alibaba Cloud SDK for Java,您需要一个云账号以及一对 Access Key ID 和 Access Key Secret。 请在阿里云控制台中的AccessKey 管理页面上创建和查看您的 AccessKey,或者联系您的系统管理员。 要使用 Alibaba Cloud SDK for Java 访问某个产品的 API,您需要事先在阿里云控制台中开通这个产品。 Alibaba Cloud SDK for Java 需要 1.6 以上的 JDK。 安装依赖 无论您要使用哪个产品的开发工具包,都必须安装 aliyun-java-sdk-core。例如,对 Serverless 工作流 SDK 的调用,您需要安装aliyun-java-sdk-core 和 aliyun-java-sdk-fnf。 通过 Maven 来管理项目依赖(推荐) 如果您使用 Apache Maven 来管理 Java 项目,只需在项目的 pom.xml 文件加入相应的依赖项即可。 com.aliyun aliyun-java-sdk-core [4.3.2,5.0.0) com.aliyun aliyun-java-sdk-fnf [1.0.0,5.0.0) 如果 Maven 没有从中央存储库下载 JAR 包,则需要将此依赖项添加到pom.xml文件中,否则将报告 NoClassDefFoundError 异常。 com.google.code.gson gson 2.8.5 快速使用 下文将以创建一个流程,发起一次执行并获取执行详情为例展示如何使用 Java SDK 调用 Serverless 工作流服务。 调用 Alibaba Cloud SDK for Java 的 3 个主要步骤: 创建 DefaultAcsClient 实例并初始化。 创建 API 请求并设置参数。 发起请求并处理应答或异常。 注意 下文仅提供 Serverless 工作流产品的使用流程,如果您在使用过程中遇到调试等问题或希望使用高级功能(连接池、HTTPS、代理、日志)等功能,请参见 README-CN。 请求方式 package com.test; import com.aliyuncs.profile.DefaultProfile; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.IAcsClient; import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.fnf.model.v20190315.*; class FnFOperations { static String flowName = "xxx"; static String execName = "xxx"; static String flowDesc = "xxx"; static String flowDef = "xxx"; static String roleArn = "xxx"; static String flowType = "xxx"; static CreateFlowResponse createFlow(IAcsClient fnfClient) throws ClientException { CreateFlowRequest request = new CreateFlowRequest(); request.setName(flowName); request.setDefinition(flowDef); request.setType(flowType); request.setDescription(flowDesc); request.setRoleArn(roleArn); return fnfClient.getAcsResponse(request); } static StartExecutionResponse startExecution(IAcsClient fnfClient) throws ClientException { StartExecutionRequest request = new StartExecutionRequest(); request.setFlowName(flowName); request.setExecutionName(execName); return fnfClient.getAcsResponse(request); } static DescribeExecutionResponse describeExecution(IAcsClient fnfClient) throws ClientException { DescribeExecutionRequest request = new DescribeExecutionRequest(); request.setFlowName(flowName); request.setExecutionName(execName); return fnfClient.getAcsResponse(request); } static GetExecutionHistoryResponse getExecutionHistory(IAcsClient fnfClient) throws ClientException { GetExecutionHistoryRequest request = new GetExecutionHistoryRequest(); request.setFlowName(flowName); request.setExecutionName(execName); return fnfClient.getAcsResponse(request); } } 创建客户端并利用上述函数发起一系列调用 说明 如果您需要不加改造进行调试的话,请将下述 public 类与上述“请求方式”代码块置于同一个文件中,避免在 import 时报错。 public class Main { public static void main(String[] args) { // Create DefaultAcsClient DefaultProfile profile = DefaultProfile.getProfile( " ", // 地域ID " ", // RAM 账号的AccessKey ID " "); // RAM 账号Access Key Secret IAcsClient client = new DefaultAcsClient(profile); try { // Create Flow CreateFlowResponse creatFlowResponse = FnFOperations.createFlow(client); System.out.println(creatFlowResponse); // Start Execution StartExecutionResponse startExeResp = FnFOperations.startExecution(client); System.out.println(startExeResp); // Describe Execution DescribeExecutionResponse descExeResp = FnFOperations.describeExecution(client); System.out.println(descExeResp); } catch (ClientException e) { e.printStackTrace(); } try { GetExecutionHistoryResponse resp = FnFOperations.getExecutionHistory(client); for (GetExecutionHistoryResponse.EventsItem event:resp.getEvents()) { System.out.printf("event %s status: %s%n", event.getStepName(), event.getType()); } } catch (ClientException e) { e.printStackTrace(); } } }

1934890530796658 2020-03-27 11:21:06 0 浏览量 回答数 0

回答

在函数计算服务使用 Java 编程,需要定义一个 Java 函数作为入口。Java 运行环境根据是否支持 HTTP 触发器分为 普通函数入口 和 HTTP 触发器函数入口 两种函数入口,为函数设置 HTTP 触发器后的函数入口形式会不同,这是为了方便处理发来的 HTTP request 请求并允许用户返回自定义 HTTP header。其中 普通函数入口 又分为 处理函数入口 和 initializer入口。 本文对 普通函数入口 和 HTTP 触发器函数入口 进行详细介绍: 普通函数入口 处理函数入口 StreamRequestHandler PojoRequestHandler initializer 入口 HTTP 触发器函数入口 Java 代码打包 普通函数入口 处理函数入口 用户在使用 Java 编程时,必须要实现函数计算提供的接口类,对于普通函数入口目前有 2 个预定义接口可选择: StreamRequestHandler以流的方式接受调用输入event和返回执行结果,用户需要从inputStream中读取调用函数时的输入,处理完成后把函数执行结果写入到outputStream中来返回。 PojoRequestHandler通过泛型的方式,用户可以自定义输入和输出的类型,但是它们必须是POJO类型。 StreamRequestHandler 一个最简单的处理函数定义如下: package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class HelloFC implements StreamRequestHandler { @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { outputStream.write(new String("hello world").getBytes()); } } 1. 包名/类名 包名和类名可以是任意的,但是需要与创建函数时的 “Handler” 字段相对应:上面的例子包名是 “example”,类名是 “HelloFC”,那么创建函数时指定的 Handler 为 example.HelloFC::handleRequest,”Handler” 的格式为 {package}.{class}::{method}。 实现的接口 用户的代码中必须要实现函数计算预定义的接口。上面的例子中实现了StreamRequestHandler,其中的 inputStream 参数是调用函数时传入的数据,outputStream 用于返回函数的执行结果。 context参数 context 参数中包含一些函数的运行时信息(例如 request id/临时 AK 等)。其类型是 com.aliyun.fc.runtime.Context。 返回值 实现StreamRequestHandler接口的函数通过outputStream参数返回执行结果 引入接口库 其中用到的com.aliyun.fc.runtime这个包的依赖可以通过下面的 pom.xml 引用: com.aliyun.fc.runtime fc-java-core 1.3.0 通过 maven 仓库 可以获取fc-java-core最新的版本号。 在创建函数之前,用户需要将代码及其依赖的 fc-java-core 打包成 jar。关于如何打包,请参见 Java 代码打包。 打包成 jar 后就可以使用 Fun 或者控制台上传代码,以 Fun 为例: 在项目根目录创建一个 template.yml 的文件: ROSTemplateFormatVersion: '2015-09-01' Transform: 'Aliyun::Serverless-2018-04-03' Resources: FunDemo: Type: 'Aliyun::Serverless::Service' javademo: Type: 'Aliyun::Serverless::Function' Properties: Handler: example.HelloFC::handleRequest Runtime: java8 CodeUri: './example.jar' 这个 template.yml 的含义如下:声明一个名为 FunDemo 的 服务,并在这个服务下,再声明一个名为 javademo 的 函数,配置函数入口为 example.HelloFC::handleRequest,以及函数的 runtime 为 java8。并且,我们指定了 CodeUri 为 ./example.jar。在部署时,Fun 会将 CodeUri 指定的目录或文件打包上传。更多的配置规则 请参考。 示例代码包是示例中的 hello world 代码打包成的 jar 包,您可以直接使用 示例代码包 进行测试。 使用 Fun 部署: fun deploy 执行成功时,会看到相关日志: using region: cn-hangzhou using accountId: ***********3557 using accessKeyId: ***********r3Ra using timeout: 300 Waiting for service FunDemo to be deployed... Waiting for function javademo to be deployed... Waiting for packaging function javademo code... package function javademo code done function javademo deploy success service FunDemo deploy success 然后就可以登录控制台查看或直接调用了。 PojoRequestHandler 一个最简单的处理函数定义如下: // HelloFC.java package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.PojoRequestHandler; public class HelloFC implements PojoRequestHandler<SimpleRequest, SimpleResponse> { @Override public SimpleResponse handleRequest(SimpleRequest request, Context context) { String message = "Hello, " + request.getFirstName() + " " + request.getLastName(); return new SimpleResponse(message); } } // SimpleRequest.java package example; public class SimpleRequest { String firstName; String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public SimpleRequest() {} public SimpleRequest(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } // SimpleResponse.java package example; public class SimpleResponse { String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public SimpleResponse() {} public SimpleResponse(String message) { this.message = message; } } 准备调用的输入文件: { "firstName": "FC", "lastName": "aliyun" } 使用 fcli 调用结果: invk hello-java -f /tmp/a.json {"message":"Hello, FC aliyun"} initializer 入口 无论您的函数使用流式输入还是通过泛型的方式自定义输入和输出,当需要在 Java runtime 中添加 initializer 接口时,都需在原有的基础上额外实现 initializer 预定义的接口。 initializer预定义接口如下: package com.aliyun.fc.runtime; import java.io.IOException; public interface FunctionInitializer { /** * The interface to handle a function compute initialize request * * @param context The function compute initialize environment context object. * @throws IOException IOException during I/O handling */ void initialize(Context context) throws IOException; } 一个简单的流式输入的函数和 initializer 结合的 demo 如下: package aliyun.serverless.test.example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.FunctionComputeLogger; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.fc.runtime.FunctionInitializer; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class InitializerAndStreamRequest implements StreamRequestHandler, FunctionInitializer { @Override public void initialize(Context context) { FunctionComputeLogger logger = context.getLogger(); logger.debug(String.format("RequestID is %s %n", context.getRequestId())); } @Override public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException { FunctionComputeLogger logger = context.getLogger(); logger.debug(String.format("RequestID is %s %n", context.getRequestId())); output.write(new String("hello world!").getBytes()); output.flush(); } } 针对 InitializerAndStreamRequest 中新增加的 initialize 方法即是 initializer 接口,特性如下: 包名/类名 initializer 所属包名和类名和处理函数一致,都可以是任意的。”initializer” 的格式同为 {package}.{class}::{method},与 “handler” 不同的是 handler 中的 method 为 handleRequest,initializer 的 method 为 initialize。根据定义可知此示例的 initializer 为 aliyun.serverless.test.example.InitializerAndStreamRequest::initialize。 实现的接口 用户的代码中必须要实现函数计算预定义的接口。上面示例中 initializer 接口实现了FunctionInitializer,initializer 接口只有一个 context 参数。 context参数 context 参数中包含一些函数的运行时信息(例如 request id/临时 AK 等)。其类型是 com.aliyun.fc.runtime.Context。 返回值 实现FunctionInitializer接口的函数无返回结果。 泛型的方式输入的函数和 initializer 结合的 demo 如下: package aliyun.serverless.test.example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.PojoRequestHandler; import com.aliyun.fc.runtime.FunctionInitializer; import com.aliyun.fc.runtime.FunctionComputeLogger; public class InitializerAndPojoRequest implements FunctionInitializer,PojoRequestHandler<SimpleRequest, SimpleResponse> { @Override public void initialize(Context context) { FunctionComputeLogger logger = context.getLogger(); logger.debug(String.format("RequestID is %s %n", context.getRequestId())); } @Override public SimpleResponse handleRequest(SimpleRequest request, Context context) { FunctionComputeLogger logger = context.getLogger(); logger.debug(String.format("RequestID is %s %n", context.getRequestId())); String message = "Hello, " + request.getFirstName() + " " + request.getLastName(); return new SimpleResponse(message); } } HTTP 触发器函数入口 HTTP 触发器函数接口 HTTP 触发器的简单示例 HTTP 触发器支持传统web应用 关于 HTTP 触发器 的使用请参考:HTTP 触发器 HTTP 触发器函数接口 函数计算提供基于 Servlet 协议的 HTTP 触发器入口,具体接口形式如下: public interface HttpRequestHandler { /** * The entrance function of fc http trigger * @param request The servlet request * @param response The servlet response * @param context The fc context * @throws IOException If IO exception happened * @throws ServletException If servlet exception happened */ public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) throws IOException, ServletException; } 使用 HTTP 触发器需将 fc-java-core 库版本升级到 1.3.0 及以上。 HTTP 触发器的简单示例 package com.aliyun.fc.example; import java.io.IOException; import java.io.OutputStream; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.HttpRequestHandler; public class Hello implements HttpRequestHandler { public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) throws IOException, ServletException { String requestPath = (String) request.getAttribute("FC_REQUEST_PATH"); String requestURI = (String) request.getAttribute("FC_REQUEST_URI"); String requestClientIP = (String) request.getAttribute("FC_REQUEST_CLIENT_IP"); response.setStatus(200); response.setHeader("header1", "value1"); response.setHeader("header2", "value2"); String body = String.format("Path: %s\n Uri: %s\n IP: %s\n", requestPath, requestURI, requestClientIP); OutputStream out = response.getOutputStream(); out.write((body).getBytes()); out.flush(); out.close(); } } 1. HttpServletRequest 函数计算 HTTP 触发器的接口直接使用标准的 Servlet 协议。 用户的请求会封装成HttpServletRequest对象,用户请求参数、请求header等均可通过此对象获取。 除此之外,函数计算在HttpServletRequest中预封装了一些属性, 可通过 getAttribute 方法来获取, 具体包括: FC_REQUEST_PATH 获取请求的 Path FC_REQUEST_URI 获取请求的 URI FC_REQUEST_CLIENT_IP 获取请求的 ClientIP HttpServletResponse 用户可通过标准的HttpServletResponse协议对象来返回响应 header 和 body. context参数 context 参数中包含一些函数的运行时信息(例如 request id/临时 AK 等)。其类型是 com.aliyun.fc.runtime.Context。 HTTP 触发器支持传统web应用 基于 Servlet 协议的传统 web 应用能很方便的迁移到函数计算平台,目前支持的主流框架包括 Spring 、 SpringBoot 、 Struts2 等。以下示例如何通过函数计算提供的 fc-java-common 库来加载 web 应用. 打包您的 web 工程,生成 demo.war 包 上传 demo.war 包到 OSS,比如为 demo-bucket 下的 demo.war 创建函数,并设置函数初始化入口和函数入口。 函数示例代码如下: package com.aliyun.fc.example; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.FcAppLoader; import com.aliyun.fc.runtime.FunctionComputeLogger; import com.aliyun.fc.runtime.FunctionInitializer; import com.aliyun.fc.runtime.HttpRequestHandler; public class HelloWeb implements FunctionInitializer, HttpRequestHandler { private FcAppLoader fcAppLoader = new FcAppLoader(); private String ossEndPoint = "YourOSSEndPoint"; private String bucket = "YourOSSBucket"; private String key = "YourWarName"; private String userContextPath = "/2016-08-15/proxy/{YourServiceName}/{YourFunctionName}"; @Override public void initialize(Context context) throws IOException { FunctionComputeLogger fcLogger = context.getLogger(); fcAppLoader.setFCContext(context); // Load code from OSS fcAppLoader.loadCodeFromOSS(ossEndPoint, bucket, key); // Init webapp from code fcAppLoader.initApp(userContextPath, HelloWeb.class.getClassLoader()); } @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context) throws IOException, ServletException { try { fcAppLoader.forward(request, response); } catch (Exception e) { e.printStackTrace(); } } } 引用 Maven 库 com.aliyun.fc.runtime fc-java-core 1.3.0 com.aliyun.fc.runtime fc-java-common 2.2.2 Java 代码打包 使用 maven 打包jar 使用 IDEA 打包jar 使用 maven 打包 jar 在 pom.xml 中添加 maven-assembly-plugin 插件 maven-assembly-plugin 3.1.0 jar-with-dependencies false make-assembly package single org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 打包 mvn package 执行完毕后,生成的 jar 会被存放在 target 目录下。 使用 maven 打包 jar,并将依赖以 jar 的形式存放在 /lib 目录中 随着项目依赖的增加,jar 的体积会变得越来越大。而用户上传的 jar 或者 zip 代码,在执行前,首先会被解压缩,然后才会被加载、执行。因此在刚才的两种实现中,存在的一个问题是我们打包的 jar 中包含了大量的 class 文件,这无疑会增加解压缩的时间,进而增加函数的首次启动时间。 一个更好的实践是将第三方依赖以 jar 的形式,存放于 /lib 目录。 这里提供一种使用 maven-dependency-plugin 实现的方案: org.apache.maven.plugins maven-dependency-plugin copy-dependencies prepare-package copy-dependencies ${project.build.directory}/classes/lib runtime 执行完 mvn package,打包好的 jar 的目录结构为: /.class lib/*.jar 使用 IDEA 打包 jar 配置导出 jar 包的选项: java1 java2 java3 验证打包结果 rockuw-MBP:hello-java (master) $ ls -lrth total 6520 -rw-r--r-- 1 rockuw staff 3.2M Aug 31 21:03 hellofc.jar rockuw-MBP:hello-java (master) $ jar -tf hellofc.jar | head Picked up _JAVA_OPTIONS: -Duser.language=en META-INF/MANIFEST.MF example/ example/HelloFC.class example/SimpleRequest.class example/SimpleResponse.class META-INF/ META-INF// org/ org// org/apache/ 函数计算目前支持以下 Java 运行环境: OpenJDK 1.8.0 (runtime = java8) 对于 Java 运行环境的基本使用请参考Java 函数入口。以下将介绍 Java 运行环境相关特性: 使用 context 使用 logging 使用自定义的模块 异常处理 使用context context 是函数计算在运行时生成的一个对象,其中包含一些运行时的信息,用户在代码中可以使用这些信息。其定义如下,具体实现可以在 这里 找到: package com.aliyun.fc.runtime; public interface Context { public String getRequestId(); public Credentials getExecutionCredentials(); public FunctionParam getFunctionParam(); public FunctionComputeLogger getLogger(); } 可以看到 context 中包含了4个信息: RequestId: 本次调用请求的唯一 id,用户可以把它记录下来在出现问题的时候方便调查 FunctionParam: 当前调用的函数的一些基本信息如函数名/函数入口/函数内存/超时时间 ExecutionCredentials: 函数计算服务通过扮演用户提供的 服务角色获得的一组临时密钥,其有效时间是 5 分钟。用户可以在代码中使用它去访问相应的服务(例如 OSS),这就避免了用户把自己的 AK 信息写死在函数代码里。 Logger: 函数计算封装过的 logger,见下面的 使用logging 例如下面的代码使用临时密钥,向 OSS 中上传了一个文件: package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.Credentials; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.oss.OSSClient; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class HelloFC implements StreamRequestHandler { @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { String endpoint = "oss-cn-shanghai.aliyuncs.com"; String bucketName = "my-bucket"; Credentials creds = context.getExecutionCredentials(); OSSClient client = new OSSClient( endpoint, creds.getAccessKeyId(), creds.getAccessKeySecret(), creds.getSecurityToken()); client.putObject(bucketName, "my-object", new ByteArrayInputStream(new String("hello").getBytes())); outputStream.write(new String("done").getBytes()); } } 使用logging 用户的函数通过 context.getLogger() 打印的内容会被收集到用户在创建 Service 时指定的 LogStore 中: package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class HelloFC implements StreamRequestHandler { @Override public void handleRequest( InputStream inputStream, OutputStream outputStream, Context context) throws IOException { context.getLogger().info("hello world"); outputStream.write(new String("hello world").getBytes()); } } 上面的代码输出的日志内容是: message:2017-07-05T05:13:35.920Z a72df088-f738-cee3-e0fe-323ad89118e5 [INFO] hello world 使用 context.getLogger().warn 和 context.getLogger().error 分别可以打包 WARN/ERROR 级别的日志。 使用自定义的模块 如果用户需要使用自定义的模块,则需要在打包 jar 时,将它们与代码一起打包。以下演示如何将 OSS Java SDK 打包到项目中。 在 pom.xml 中添加 OSS java SDK: com.aliyun.fc.runtime fc-java-core 1.2.1 com.aliyun.oss aliyun-sdk-oss 2.6.1 执行通用打包流程 请参考 Java 代码打包 错误处理 用户的函数在执行过程如果抛出异常,那么函数计算会把异常捕获并将异常信息返回。例如下面的代码: package example; import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class HelloFC implements StreamRequestHandler { @Override public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException { throw new IOException("oops"); } } 调用时收到的响应为: invk hello-java -f /tmp/a.json { "errorMessage" : "oops", "errorType" : "java.io.IOException", "errorCause" : "oops", "stackTrace" : [ "example.HelloFC.handleRequest(HelloFC.java:15)" ] } Error: Request id: 45dd8d90-6b78-cce3-087c-8bf4ebc6c9af. Error type: UnhandledInvocationError 发生异常时,函数调用的响应的HTTP header中会包含X-Fc-Error-Type: UnhandledInvocationError。

1934890530796658 2020-03-27 16:27:27 0 浏览量 回答数 0

问题

如何回收或者关闭OSSClient实例的连接

reformer 2019-12-01 21:06:56 16095 浏览量 回答数 4

问题

适用的开发环境 SDK使用方法:报错

kun坤 2020-06-14 09:47:41 0 浏览量 回答数 0

问题

Java技术1000问(3)【精品问答】

问问小秘 2020-06-02 14:27:10 42 浏览量 回答数 1

回答

Android平台进行数据存储的五大方式,分别如下: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 4 使用ContentProvider存储数据 5 网络存储数据 下面详细讲解这五种方式的特点 第一种: 使用SharedPreferences存储数据 适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等 核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下: Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。 Context.MODE_WORLD_READABLE: 指定该SharedPreferences数据能被其他应用程序读,但不能写。 Context.MODE_WORLD_WRITEABLE: 指定该SharedPreferences数据能被其他应用程序读,写 Editor有如下主要重要方法: SharedPreferences.Editor clear():清空SharedPreferences里所有数据 SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据 SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项 boolean commit(): 当Editor编辑完成后,使用该方法提交修改 实际案例:运行界面如下 这里只提供了两个按钮和一个输入文本框,布局简单,故在此不给出界面布局文件了,程序核心代码如下: 、class ViewOcl implements View.OnClickListener{ @Override public void onClick(View v) { switch(v.getId()){ case R.id.btnSet: //步骤1:获取输入值 String code = txtCode.getText().toString().trim(); //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作 SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_WORLD_WRITEABLE).edit(); //步骤2-2:将获取过来的值放入文件 editor.putString("code", code); //步骤3:提交 editor.commit(); Toast.makeText(getApplicationContext(), "口令设置成功", Toast.LENGTH_LONG).show(); break; case R.id.btnGet: //步骤1:创建一个SharedPreferences接口对象 SharedPreferences read = getSharedPreferences("lock", MODE_WORLD_READABLE); //步骤2:获取文件中的值 String value = read.getString("code", ""); Toast.makeText(getApplicationContext(), "口令为:"+value, Toast.LENGTH_LONG).show(); break; } } } 、读写其他应用的SharedPreferences: 步骤如下 1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取 2、创建其他应用程序对应的Context: Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名 3、使用其他程序的Context获取对应的SharedPreferences SharedPreferences read = pvCount.getSharedPreferences("lock", Context.MODE_WORLD_READABLE); 4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。 SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。 第二种: 文件存储数据 核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选: MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可 以使用Context.MODE_APPEND MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。 MODE_WORLD_READABLE:表示当前文件可以被其他应用读取; MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。 除此之外,Context还提供了如下几个重要的方法: getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录 File getFilesDir():获取该应用程序的数据文件夹得绝对路径 String[] fileList():返回该应用数据文件夹的全部文件 public String read() { try { FileInputStream inStream = this.openFileInput("message.txt"); byte[] buffer = new byte[1024]; int hasRead = 0; StringBuilder sb = new StringBuilder(); while ((hasRead = inStream.read(buffer)) != -1) { sb.append(new String(buffer, 0, hasRead)); } inStream.close(); return sb.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } public void write(String msg){ // 步骤1:获取输入值 if(msg == null) return; try { // 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式 FileOutputStream fos = openFileOutput("message.txt", MODE_APPEND); // 步骤3:将获取过来的值放入文件 fos.write(msg.getBytes()); // 步骤4:关闭数据流 fos.close(); } catch (Exception e) { e.printStackTrace(); } } openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data//files目录,如: /data/data/cn.tony.app/files/message.txt, 下面讲解某些特殊文件读写需要注意的地方: 读写sdcard上的文件 其中读写步骤按如下进行: 1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) 2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录 3、使用IO流操作SD卡上的文件 注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡 必须在AndroidManifest.xml上配置读写SD卡的权限 // 文件写操作函数 private void write(String content) { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 如果sdcard存在 File file = new File(Environment.getExternalStorageDirectory() .toString() + File.separator + DIR + File.separator + FILENAME); // 定义File类对象 if (!file.getParentFile().exists()) { // 父文件夹不存在 file.getParentFile().mkdirs(); // 创建文件夹 } PrintStream out = null; // 打印流对象用于输出 try { out = new PrintStream(new FileOutputStream(file, true)); // 追加文件 out.println(content); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { out.close(); // 关闭打印流 } } } else { // SDCard不存在,使用Toast提示用户 Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show(); } } // 文件读操作函数 private String read() { if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { // 如果sdcard存在 File file = new File(Environment.getExternalStorageDirectory() .toString() + File.separator + DIR + File.separator + FILENAME); // 定义File类对象 if (!file.getParentFile().exists()) { // 父文件夹不存在 file.getParentFile().mkdirs(); // 创建文件夹 } Scanner scan = null; // 扫描输入 StringBuilder sb = new StringBuilder(); try { scan = new Scanner(new FileInputStream(file)); // 实例化Scanner while (scan.hasNext()) { // 循环读取 sb.append(scan.next() + "\n"); // 设置文本 } return sb.toString(); } catch (Exception e) { e.printStackTrace(); } finally { if (scan != null) { scan.close(); // 关闭打印流 } } } else { // SDCard不存在,使用Toast提示用户 Toast.makeText(this, "读取失败,SD卡不存在!", Toast.LENGTH_LONG).show(); } return null; } 复制代码 第三种:SQLite存储数据 SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧 SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用 1 db.executeSQL(String sql); 2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 除了统一的形式之外,他们还有各自的操作方法: 1 db.insert(String table, String nullColumnHack, ContentValues values); 2 db.update(String table, Contentvalues values, String whereClause, String whereArgs); 3 db.delete(String table, String whereClause, String whereArgs);以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样 下面给出demo 数据的添加 1.使用insert方法 复制代码1 ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据2 cv.put("title","you are beautiful");//添加title3 cv.put("weather","sun"); //添加weather4 cv.put("context","xxxx"); //添加context5 String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")6 .format(new Date());7 cv.put("publish ",publish); //添加publish8 db.insert("diary",null,cv);//执行插入操作复制代码2.使用execSQL方式来实现 String sql = "insert into user(username,password) values ('Jack Johnson','iLovePopMuisc');//插入操作的SQL语句db.execSQL(sql);//执行SQL语句数据的删除 同样有2种方式可以实现 String whereClause = "username=?";//删除的条件String[] whereArgs = {"Jack Johnson"};//删除的条件参数db.delete("user",whereClause,whereArgs);//执行删除使用execSQL方式的实现 String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句db.execSQL(sql);//执行删除操作数据修改 同上,仍是2种方式 ContentValues cv = new ContentValues();//实例化ContentValuescv.put("password","iHatePopMusic");//添加要更改的字段及内容String whereClause = "username=?";//修改条件String[] whereArgs = {"Jack Johnson"};//修改条件的参数db.update("user",cv,whereClause,whereArgs);//执行修改使用execSQL方式的实现 String sql = "update user set password = 'iHatePopMusic' where username='Jack Johnson'";//修改的SQL语句db.execSQL(sql);//执行修改数据查询 下面来说说查询操作。查询操作相对于上面的几种操作要复杂些,因为我们经常要面对着各种各样的查询条件,所以系统也考虑到这种复杂性,为我们提供了较为丰富的查询形式: 1 db.rawQuery(String sql, String[] selectionArgs); 2 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy); 3 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 4 db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit); 上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集; 各参数说明: table:表名称colums:表示要查询的列所有名称集selection:表示WHERE之后的条件语句,可以使用占位符selectionArgs:条件语句的参数数组groupBy:指定分组的列名having:指定分组条件,配合groupBy使用orderBy:y指定排序的列名limit:指定分页参数distinct:指定“true”或“false”表示要不要过滤重复值Cursor:返回值,相当于结果集ResultSet最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。下面是Cursor对象的常用方法: 复制代码 1 c.move(int offset); //以当前位置为参考,移动到指定行 2 c.moveToFirst(); //移动到第一行 3 c.moveToLast(); //移动到最后一行 4 c.moveToPosition(int position); //移动到指定行 5 c.moveToPrevious(); //移动到前一行 6 c.moveToNext(); //移动到下一行 7 c.isFirst(); //是否指向第一条 8 c.isLast(); //是否指向最后一条 9 c.isBeforeFirst(); //是否指向第一条之前 10 c.isAfterLast(); //是否指向最后一条之后 11 c.isNull(int columnIndex); //指定列是否为空(列基数为0) 12 c.isClosed(); //游标是否已关闭 13 c.getCount(); //总数据项数 14 c.getPosition(); //返回当前游标所指向的行数 15 c.getColumnIndex(String columnName);//返回某列名对应的列索引值 16 c.getString(int columnIndex); //返回当前行指定列的值 复制代码实现代码 复制代码String[] params = {12345,123456};Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标if(cursor.moveToFirst()){//判断游标是否为空 for(int i=0;i<cursor.getCount();i++){ cursor.move(i);//移动到指定记录 String username = cursor.getString(cursor.getColumnIndex("username"); String password = cursor.getString(cursor.getColumnIndex("password")); } }复制代码通过rawQuery实现的带参数查询 复制代码Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");//Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"}); result.moveToFirst(); while (!result.isAfterLast()) { int id=result.getInt(0); String name=result.getString(1); int inventory=result.getInt(2); // do something useful with these result.moveToNext(); } result.close();复制代码 在上面的代码示例中,已经用到了这几个常用方法中的一些,关于更多的信息,大家可以参考官方文档中的说明。 最后当我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。 上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库,我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。 这里直接使用案例讲解:下面是案例demo的界面 SQLiteOpenHelper类介绍 SQLiteOpenHelper是SQLiteDatabase的一个帮助类,用来管理数据库的创建和版本的更新。一般是建立一个类继承它,并实现它的onCreate和onUpgrade方法。 方法名 方法描述SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version) 构造方法,其中 context 程序上下文环境 即:XXXActivity.this; name :数据库名字; factory:游标工厂,默认为null,即为使用默认工厂; version 数据库版本号 onCreate(SQLiteDatabase db) 创建数据库时调用onUpgrade(SQLiteDatabase db,int oldVersion , int newVersion) 版本更新时调用getReadableDatabase() 创建或打开一个只读数据库getWritableDatabase() 创建或打开一个读写数据库首先创建数据库类 复制代码 1 import android.content.Context; 2 import android.database.sqlite.SQLiteDatabase; 3 import android.database.sqlite.SQLiteDatabase.CursorFactory; 4 import android.database.sqlite.SQLiteOpenHelper; 5 6 public class SqliteDBHelper extends SQLiteOpenHelper { 7 8 // 步骤1:设置常数参量 9 private static final String DATABASE_NAME = "diary_db";10 private static final int VERSION = 1;11 private static final String TABLE_NAME = "diary";12 13 // 步骤2:重载构造方法14 public SqliteDBHelper(Context context) {15 super(context, DATABASE_NAME, null, VERSION);16 }17 18 /*19 * 参数介绍:context 程序上下文环境 即:XXXActivity.this 20 * name 数据库名字 21 * factory 接收数据,一般情况为null22 * version 数据库版本号23 */24 public SqliteDBHelper(Context context, String name, CursorFactory factory,25 int version) {26 super(context, name, factory, version);27 }28 //数据库第一次被创建时,onCreate()会被调用29 @Override30 public void onCreate(SQLiteDatabase db) {31 // 步骤3:数据库表的创建32 String strSQL = "create table "33 + TABLE_NAME34 + "(tid integer primary key autoincrement,title varchar(20),weather varchar(10),context text,publish date)";35 //步骤4:使用参数db,创建对象36 db.execSQL(strSQL);37 }38 //数据库版本变化时,会调用onUpgrade()39 @Override40 public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {41 42 }43 }复制代码正如上面所述,数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。 我们需要一个Dao,来封装我们所有的业务方法,代码如下: 复制代码 1 import android.content.Context; 2 import android.database.Cursor; 3 import android.database.sqlite.SQLiteDatabase; 4 5 import com.chinasoft.dbhelper.SqliteDBHelper; 6 7 public class DiaryDao { 8 9 private SqliteDBHelper sqliteDBHelper;10 private SQLiteDatabase db;11 12 // 重写构造方法13 public DiaryDao(Context context) {14 this.sqliteDBHelper = new SqliteDBHelper(context);15 db = sqliteDBHelper.getWritableDatabase();16 }17 18 // 读操作19 public String execQuery(final String strSQL) {20 try {21 System.out.println("strSQL>" + strSQL);22 // Cursor相当于JDBC中的ResultSet23 Cursor cursor = db.rawQuery(strSQL, null);24 // 始终让cursor指向数据库表的第1行记录25 cursor.moveToFirst();26 // 定义一个StringBuffer的对象,用于动态拼接字符串27 StringBuffer sb = new StringBuffer();28 // 循环游标,如果不是最后一项记录29 while (!cursor.isAfterLast()) {30 sb.append(cursor.getInt(0) + "/" + cursor.getString(1) + "/"31 + cursor.getString(2) + "/" + cursor.getString(3) + "/"32 + cursor.getString(4)+"#");33 //cursor游标移动34 cursor.moveToNext();35 }36 db.close();37 return sb.deleteCharAt(sb.length()-1).toString();38 } catch (RuntimeException e) {39 e.printStackTrace();40 return null;41 }42 43 }44 45 // 写操作46 public boolean execOther(final String strSQL) {47 db.beginTransaction(); //开始事务48 try {49 System.out.println("strSQL" + strSQL);50 db.execSQL(strSQL);51 db.setTransactionSuccessful(); //设置事务成功完成 52 db.close();53 return true;54 } catch (RuntimeException e) {55 e.printStackTrace();56 return false;57 }finally { 58 db.endTransaction(); //结束事务 59 } 60 61 }62 }复制代码我们在Dao构造方法中实例化sqliteDBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在增删改信息时,我们采用了事务处理,确保数据完整性;最后要注意释放数据库资源db.close(),这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记,所以朋友们要注意。 我们获取数据库实例时使用了getWritableDatabase()方法,也许朋友们会有疑问,在getWritableDatabase()和getReadableDatabase()中,你为什么选择前者作为整个应用的数据库实例呢?在这里我想和大家着重分析一下这一点。 我们来看一下SQLiteOpenHelper中的getReadableDatabase()方法: 复制代码 1 public synchronized SQLiteDatabase getReadableDatabase() { 2 if (mDatabase != null && mDatabase.isOpen()) { 3 // 如果发现mDatabase不为空并且已经打开则直接返回 4 return mDatabase; 5 } 6 7 if (mIsInitializing) { 8 // 如果正在初始化则抛出异常 9 throw new IllegalStateException("getReadableDatabase called recursively"); 10 } 11 12 // 开始实例化数据库mDatabase 13 14 try { 15 // 注意这里是调用了getWritableDatabase()方法 16 return getWritableDatabase(); 17 } catch (SQLiteException e) { 18 if (mName == null) 19 throw e; // Can't open a temp database read-only! 20 Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e); 21 } 22 23 // 如果无法以可读写模式打开数据库 则以只读方式打开 24 25 SQLiteDatabase db = null; 26 try { 27 mIsInitializing = true; 28 String path = mContext.getDatabasePath(mName).getPath();// 获取数据库路径 29 // 以只读方式打开数据库 30 db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY); 31 if (db.getVersion() != mNewVersion) { 32 throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to " 33 + mNewVersion + ": " + path); 34 } 35 36 onOpen(db); 37 Log.w(TAG, "Opened " + mName + " in read-only mode"); 38 mDatabase = db;// 为mDatabase指定新打开的数据库 39 return mDatabase;// 返回打开的数据库 40 } finally { 41 mIsInitializing = false; 42 if (db != null && db != mDatabase) 43 db.close(); 44 } 45 }复制代码在getReadableDatabase()方法中,首先判断是否已存在数据库实例并且是打开状态,如果是,则直接返回该实例,否则试图获取一个可读写模式的数据库实例,如果遇到磁盘空间已满等情况获取失败的话,再以只读模式打开数据库,获取数据库实例并返回,然后为mDatabase赋值为最新打开的数据库实例。既然有可能调用到getWritableDatabase()方法,我们就要看一下了: 复制代码public synchronized SQLiteDatabase getWritableDatabase() { if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) { // 如果mDatabase不为空已打开并且不是只读模式 则返回该实例 return mDatabase; } if (mIsInitializing) { throw new IllegalStateException("getWritableDatabase called recursively"); } // If we have a read-only database open, someone could be using it // (though they shouldn't), which would cause a lock to be held on // the file, and our attempts to open the database read-write would // fail waiting for the file lock. To prevent that, we acquire the // lock on the read-only database, which shuts out other users. boolean success = false; SQLiteDatabase db = null; // 如果mDatabase不为空则加锁 阻止其他的操作 if (mDatabase != null) mDatabase.lock(); try { mIsInitializing = true; if (mName == null) { db = SQLiteDatabase.create(null); } else { // 打开或创建数据库 db = mContext.openOrCreateDatabase(mName, 0, mFactory); } // 获取数据库版本(如果刚创建的数据库,版本为0) int version = db.getVersion(); // 比较版本(我们代码中的版本mNewVersion为1) if (version != mNewVersion) { db.beginTransaction();// 开始事务 try { if (version == 0) { // 执行我们的onCreate方法 onCreate(db); } else { // 如果我们应用升级了mNewVersion为2,而原版本为1则执行onUpgrade方法 onUpgrade(db, version, mNewVersion); } db.setVersion(mNewVersion);// 设置最新版本 db.setTransactionSuccessful();// 设置事务成功 } finally { db.endTransaction();// 结束事务 } } onOpen(db); success = true; return db;// 返回可读写模式的数据库实例 } finally { mIsInitializing = false; if (success) { // 打开成功 if (mDatabase != null) { // 如果mDatabase有值则先关闭 try { mDatabase.close(); } catch (Exception e) { } mDatabase.unlock();// 解锁 } mDatabase = db;// 赋值给mDatabase } else { // 打开失败的情况:解锁、关闭 if (mDatabase != null) mDatabase.unlock(); if (db != null) db.close(); } } }复制代码大家可以看到,几个关键步骤是,首先判断mDatabase如果不为空已打开并不是只读模式则直接返回,否则如果mDatabase不为空则加锁,然后开始打开或创建数据库,比较版本,根据版本号来调用相应的方法,为数据库设置新版本号,最后释放旧的不为空的mDatabase并解锁,把新打开的数据库实例赋予mDatabase,并返回最新实例。 看完上面的过程之后,大家或许就清楚了许多,如果不是在遇到磁盘空间已满等情况,getReadableDatabase()一般都会返回和getWritableDatabase()一样的数据库实例,所以我们在DBManager构造方法中使用getWritableDatabase()获取整个应用所使用的数据库实例是可行的。当然如果你真的担心这种情况会发生,那么你可以先用getWritableDatabase()获取数据实例,如果遇到异常,再试图用getReadableDatabase()获取实例,当然这个时候你获取的实例只能读不能写了 最后,让我们看一下如何使用这些数据操作方法来显示数据,界面核心逻辑代码: 复制代码public class SQLiteActivity extends Activity { public DiaryDao diaryDao; //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory); //所以要确保context已初始化,我们可以把实例化Dao的步骤放在Activity的onCreate里 @Override protected void onCreate(Bundle savedInstanceState) { diaryDao = new DiaryDao(SQLiteActivity.this); initDatabase(); } class ViewOcl implements View.OnClickListener { @Override public void onClick(View v) { String strSQL; boolean flag; String message; switch (v.getId()) { case R.id.btnAdd: String title = txtTitle.getText().toString().trim(); String weather = txtWeather.getText().toString().trim();; String context = txtContext.getText().toString().trim();; String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") .format(new Date()); // 动态组件SQL语句 strSQL = "insert into diary values(null,'" + title + "','" + weather + "','" + context + "','" + publish + "')"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"添加成功":"添加失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; case R.id.btnDelete: strSQL = "delete from diary where tid = 1"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"删除成功":"删除失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; case R.id.btnQuery: strSQL = "select * from diary order by publish desc"; String data = diaryDao.execQuery(strSQL); Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show(); break; case R.id.btnUpdate: strSQL = "update diary set title = '测试标题1-1' where tid = 1"; flag = diaryDao.execOther(strSQL); //返回信息 message = flag?"更新成功":"更新失败"; Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); break; } } } private void initDatabase() { // 创建数据库对象 SqliteDBHelper sqliteDBHelper = new SqliteDBHelper(SQLiteActivity.this); sqliteDBHelper.getWritableDatabase(); System.out.println("数据库创建成功"); } }复制代码 Android sqlite3数据库管理工具 Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具。开发者可以方便的使用其对sqlite数据库进行命令行的操作。 程序运行生成的.db文件一般位于"/data/data/项目名(包括所处包名)/databases/.db",因此要对数据库文件进行操作需要先找到数据库文件: 1、进入shell 命令 adb shell2、找到数据库文件 cd data/data ls --列出所有项目 cd project_name --进入所需项目名 cd databases ls --列出现寸的数据库文件 3、进入数据库 sqlite3 test_db --进入所需数据库 会出现类似如下字样: SQLite version 3.6.22Enter ".help" for instructionsEnter SQL statements terminated with a ";"sqlite>至此,可对数据库进行sql操作。 4、sqlite常用命令 .databases --产看当前数据库.tables --查看当前数据库中的表.help --sqlite3帮助.schema --各个表的生成语句 原文地址https://www.cnblogs.com/ITtangtang/p/3920916.html

auto_answer 2019-12-02 01:50:21 0 浏览量 回答数 0

问题

彻底解决PHP SDK依赖的问题

rockuw 2019-12-01 22:05:24 5123 浏览量 回答数 1

回答

1、jsonp必须遵循一个固定的格式。即请求的URL的search中必须存在一个jsonpcallback=functionName;响应的格式为functionName(/ json data /); 原理就是利用script不受同源策略限制的特点。2、在server返回数据之后,尽量删掉这个script。因为页面中有n多个jsonp,就会有n多个生成的script标签。造成dom臃肿。并且别人也可以通过观察html来指导你jsonp的请求细节。3、是看重写的mimeType是不是和server返回的一样。如果一样就没必要重写mimeType了。除此之外还用了setRequestHeader、overriderMimeType、abort等方法。4、看代码流程即可。我写了一个简单点的例子 (function (global) { // 防止低版本ie里,undefined被重写 var undefined = void(0); // 定义命名空间 var namespace = {}; // 默认的参数列表 var defaultOptions = { // ajax请求的路径是什么 url: '', // 往服务器发送的数据 data: '', // 使用什么http方法 type: 'get', // ajax请求方式,同步还是异步。默认为异步 async: true, // 成功时执行的函数 success: function (data) { }, // 失败时执行的函数 error: function (errInfo) { }, // 自定义请求首部列表 header: {}, // 重写的mimeType overrideMimeType: '', // 是否走缓存 cache: false, // 超时毫秒数。默认为0 表示不执行超时逻辑 timeout: 0, // 是否格式化参数为uri string processData: true, // 请求的mime类型 默认为表单提交 contentType: 'application/x-www-form-urlencoded', // 返回的数据格式 text|json dataType: 'text' }; /** * CORE * @param {Object} options 用户输入的参数 * @throw TypeError */ var ajax = function (options) { // 判断参数是否为对象,如果不是则抛出类型错误 if (!tool.isObject(options)) { throw new TypeError('参数类型错误'); } // 合并用户输入的参数列表和默认的参数列表 返回一个全新的参数列表对象 var userOptions = tool.extend(defaultOptions, options); // ajax第一步:获取ajax对象 var xhr = tool.getXHR(); // 1、如果是get系 需要把data拼接到url后面 if (/^(get|delete|head)$/img.test(userOptions.type)) { var data = tool.encodeToURIString(userOptions.data); userOptions.url = tool.hasSearch(userOptions.url, data); // 因为get系不需要传send参数,所以设置为null userOptions.data = null; } // 2、是否走缓存,如果不走缓存则在url后面加一个随机数来防止缓存 if (userOptions.cache === false) { // 因为search是有固定格式的 key=value 如果只写一个value是不合法的,所以必须构造一个key,而且这个key不能和已有的key重复 var random = '_=' + (Math.random() * 0xffffff).toFixed(0); userOptions.url = tool.hasSearch(userOptions.url, random); } // ajax操作第二步 xhr.open(userOptions.type, userOptions.url, userOptions.async); // 2.1 设置自定义请求首部信息 if (userOptions.header && tool.isObject(userOptions.header)) { tool.eachObject(userOptions.header, function (key, value) { xhr.setRequestHeader(key, value); }) } // 2.2 设置content-type http里表现mimeType的字段就是content-type // 设置请求的mimeType if (userOptions.contentType && tool.isString(userOptions.contentType)) { xhr.setRequestHeader('content-type', userOptions.contentType); } // 2.3 设置重写的mime类型 // 设置响应的mimeType if (userOptions.overrideMimeType && tool.isString(userOptions.overrideMimeType)) { xhr.overrideMimeType(userOptions.overrideMimeType); } // 2.4 判断是否执行超时逻辑 if (tool.isNumber(userOptions.timeout) && userOptions.timeout > 0) { xhr.timeout = userOptions.timeout; // 标准浏览器 if ('ontimeout' in xhr) { xhr.ontimeout = function () { userOptions.error('timeout'); } } else { // 低版本ie setTimeout(function () { // http的事务是否还没有完成 if (xhr.readyState !== 4) { // 强制终止http事务 xhr.abort(); } }, xhr.timeout); } } // 2.5 是否需要处理给服务器发送的数据,判断processData是否为true // 当给服务器发送的数据为二进制或者formData的时候,不需要处理这个数据 // 要把processData设置为false if (/^(post|put)$/igm.test(userOptions.type) && userOptions.processData === true) { userOptions.data = tool.encodeToURIString(userOptions.data); } // ajax第三步:接收响应 xhr.onreadystatechange = function () { // http的事务是否完成 if (xhr.readyState === 4) { // 获取响应主体 var responseText = xhr.responseText; // 判断状态码是否成功 if (/^2\d{2}$/.test(xhr.status)) { // 判断是否需要把响应主体格式化为json对象 if (userOptions.dataType === 'json') { // 因为不合法的json字符串无法转换为json对象,会出异常 try { responseText = tool.JSONParse(responseText); } catch (ex) { userOptions.error(ex); return; } } userOptions.success(responseText); // R如果响应码是错误的类型 } else if (/^(4|5)\d{2}$/.test(xhr.status)) { // 直接执行error userOptions.error(xhr.status); } } }; // ajax第四步:发送 xhr.send(userOptions.data); }; /** * 利用闭包,实现获取数据类型 * @param {string} type 数据类型 * @returns {Function} */ var getType = function (type) { return function (obj) { // 为什么要用Object.prototype.toString来判断类型? return Object.prototype.toString.call(obj) === '[object ' + type + ']'; } }; var tool = { /** * 利用惰性函数,实现获取ajax对象的方法 */ getXHR: (function () { var list = [function () { return new XMLHttpRequest; }, function () { return new ActiveXObject('Microsoft.XMLHTTP'); }, function () { return new ActiveXObject("Msxml2.XMLHTTP"); }, function () { return new ActiveXObject("Msxml3.XMLHTTP"); }]; var len = list.length; var xhr = null; while (len--) { try { list[len](); xhr = list[len]; break; } catch (ex) { continue; } } if (xhr !== null) { return xhr; } throw new Error('当前浏览器不支持此方法'); })(), /** * 合并多个对象 * @returns {{}} 合并后的对象 */ extend: function () { // 因为参数长度不固定,所以把参数列表转成数组 // var params = [].slice.call(arguments, 0); var voidObj = {}; this.each(arguments, function (item) { // item为每一个参数对象 tool.eachObject(item, function (key, value) { voidObj[key] = value; }); }); return voidObj; }, /** * 循环帮助函数,利用惰性函数 */ each: (function () { if ([].forEach) { return function (list, callback, context) { [].forEach.call(list, callback, context); } } return function (list, callback, context) { for (var i = 0, j = list.length; i < j; i++) { callback.call(context, list[i], i, list); } } })(), /** * 循环对象 * @param {Object} obj 要循环的对象 * @param {Function} callback 回调函数 * @param {Object|undefined} context 回调函数里头的上下文对象 */ eachObject: function (obj, callback, context) { for (var n in obj) { if (!obj.hasOwnProperty(n)) continue; callback.call(context, n, obj[n]); } }, /** * 给tool动态添加判断数据类型的方法 */ init: function () { this.each(['Object', 'Function', 'Array', 'String', 'Number'], function (item) { tool['is' + item] = getType(item); }) }, /** * 把一个对象格式化为uri string * @param {*} data 需要格式化的数据 * @return {string} 格式化之后得到的uri string */ encodeToURIString: function (data) { if (this.isString(data)) return data; if (!this.isObject(data)) return ''; var arr = []; this.eachObject(data, function (key, value) { arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); }); return arr.join('&'); }, /** * 往url后面拼接参数的方法 * @param {string} url url * @param {string} padString 要拼接的参数 * @returns {string} 拼接之后的url */ hasSearch: function (url, padString) { if (!padString) return url; // 如果有问号,说明url里已经有参数了,因为参数和参数之间用&来分隔 /*if (/\?/.test(url)) { return url + '&' + padString; } else { return url + '?' + padString; }*/ return url + (/\?/.test(url) ? '&' : '?') + padString; }, /** * 把json字符串格式化为json对象 * @param {string} jsonString json字符串 * @return {Object} json对象 */ JSONParse: function (jsonString) { if (window.JSON) { return JSON.parse(jsonString) } return eval('(' + jsonString + ')'); } }; tool.init(); // 把ajax方法放入命名空间中 namespace.ajax = ajax; tool.each(['get', 'post'], function (item) { /** * 动态添加get和post方法 * @param {string} url 请求的url * @param {Object} data 往服务器发送的数据 * @param {Function} callback 成功的回调函数 * @param {string} dataType 数据格式 */ namespace[item] = function (url, data, callback, dataType) { ajax({ url: url, type: item, data: data, success: callback, dataType: dataType }); } }); // 先把全局里已经存在的x先放到一边 var globalX = global.x; /** * 解决全局变量名冲突 * @param {string|undefined} symbol 更改的全局变量名 * @returns {Object} */ namespace.noConflict = function (symbol) { if (symbol && tool.isString(symbol)) { window[symbol] = namespace; } global!==undefined&&(window.x = globalX); return namespace; }; // 暴露到全局环境中 global.x = namespace; })(this); 用法和jquery的一样。不过我暴露的是x变量,不是$.

小旋风柴进 2019-12-02 02:28:33 0 浏览量 回答数 0

问题

是否可以创建带有双重输入的异常处理方法,该方法可以在Java中初始化变量?

montos 2020-03-22 22:37:09 1 浏览量 回答数 1

回答

1.如上面一哥们说的,但是不建议使用 method(@RequestBodyMapmap){map.get("code");} 2.直接将requestcontent转换为JSONObject(配置Converter,springmvc会帮我们做) method(@RequestBodyJSONObjectjsonObj){jsonObj.getString("code");} 自动转不了吧,还是要对象或者map,因为是JSON过来之后是LinkedHashMap回复 @puras:既然选择使用json和服务端交互,那么用JSON对象来接收数据肯定是最好的,不知道你指的复杂情况是什么情况,性能?你说的这种是简单的情况,有时一些复杂的情况,Spring的自动转换也没有办法帮我转换成我想要的东西。比如对象嵌套3层以上的时候。有啥好办法?或是建议使用的办法么?感觉这样略麻烦,不建议用map的原因是什么?如果装配成对象不如直接在@RequestBody的时候直接装配就好了 实现方式: @JsonArg("$.resource")Stringcode 步骤: 1、自定义注解 @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public@interfaceJsonArg{publicStringvalue()default"";} 2、实现  HandlerMethodArgumentResolver  : publicclassJsonArgumentResolverimplementsHandlerMethodArgumentResolver{privatestaticfinalStringJSONBODYATTRIBUTE="JSON_REQUEST_BODY";@OverridepublicbooleansupportsParameter(MethodParameterparameter){returnparameter.hasParameterAnnotation(JsonArg.class);}@OverridepublicObjectresolveArgument(MethodParameterparameter,ModelAndViewContainermavContainer,NativeWebRequestwebRequest,WebDataBinderFactorybinderFactory)throwsException{Stringbody=getRequestBody(webRequest);Stringarg=parameter.getParameterAnnotation(JsonArg.class).value();if(StringUtils.isEmpty(arg)){arg=parameter.getParameterName();}Objectval=JsonPath.parse(body).read(arg,parameter.getParameterType());returnval;}privateStringgetRequestBody(NativeWebRequestwebRequest){HttpServletRequestservletRequest=webRequest.getNativeRequest(HttpServletRequest.class);StringjsonBody=(String)webRequest.getAttribute(JSONBODYATTRIBUTE,NativeWebRequest.SCOPE_REQUEST);if(jsonBody==null){try{jsonBody=IOUtils.toString(servletRequest.getInputStream());webRequest.setAttribute(JSONBODYATTRIBUTE,jsonBody,NativeWebRequest.SCOPE_REQUEST);}catch(IOExceptione){thrownewRuntimeException(e);}}returnjsonBody;}} 3、spring-mvc中声明: <mvc:annotation-driven><mvc:argument-resolvers><beans:beanclass="com.redcollar.bl.commons.extension.JsonArgumentResolver"/></mvc:argument-resolvers></mvc:annotation-driven> 回复 @徐建兴:com.jayway.jsonpath.JsonPath和jacksonhttp://stackoverflow.com/questions/12893566/passing-multple-variables-in-requestbody-to-a-spring-mvc-controller-using-ajax真正的大神! @RequestParam(value="code")Stringcode 即可获取到绝逼获取不到这样获取不到吧IOUtils.toString(request.getInputStream()) 测试单元里面code=ddfg这个参数名和后面content(jsonStr)冲突了吧 对,那个是粘贴的时候的错误,已经修改过来了。谢谢指正。 请求包的contentType要设置成multipart/form-data,这样Servlet容器才不会解析请求包体 另外这个东西和Spring的multipart文件上传组件冲突 这样的: @RequestMapping(value="reset_passwd.json",method=RequestMethod.POST)@ResponseBodypublicObjectresetPasswd(@RequestBodyStringrequestJson){Stringmessage=null;Map<String,Object>jsonData=StringUtils.parseJson(requestJson);Stringemployee=(String)jsonData.get("employee");//...}而发起这个请求是: /***使用POST模拟文件上传提交一个json对象,注意这个方法提交的数据为json对象的字符串表示而非标准文件上传请求包**@paramurl*@paramparams*@return*@throwsIOException*/publicstaticStringdoJson(Stringurl,Objectdata)throwsIOException{HttpURLConnectionconnection=(HttpURLConnection)newURL(url).openConnection();connection.setDoOutput(true);connection.setConnectTimeout(Const.DEFAULT_HTTP_CONNECT_TIMEOUT);connection.setReadTimeout(Const.DEFAULT_HTTP_READ_TIMEOUT);connection.setUseCaches(false);connection.setRequestMethod("POST");connection.setRequestProperty("Content-Type","multipart/form-data");BufferedOutputStreamout=null;try{out=newBufferedOutputStream(connection.getOutputStream());out.write(StringUtils.toJson(data).getBytes(Const.DEFAULT_CHARSET));out.flush();}finally{if(out!=null){out.close();out=null;}}//...后面读取结果} 回复 @逝水fox:您好,我现在需要使用这种方法上传json,同时我还要上传文件,上面您说这种方式回合MultipartFile冲突,那请问有什么好的解决方案呢?回复 @Kent_Chen:如果不用mutipart,首先是Tomcat有默认的2M的请求包大小限制,另外如果用application/json,SpringMVC的MessageConverter也会处理(这个并不只对@ResponseBody有效,对@RequestBody仍然是有效的),如果要自己String处理以便在json字符串异常的时候自己能有处理,这个是不方便的我又不上传为什么需要multipart/form-data method(@RequestBodyMapmap){ map.get("code"); }感谢指点,非常有用,看了下JSON被转成了LinkedHashMap只能用Map或者对象接收回复 @Kent_Chen:记得给最佳哈。谢谢,这个是可以的:) 不是method(HttpServletRequestrequest){ request.getParameter("code"); }就好? @Kent_Chen我一直用的getParameter,是可以取到值的,确定是POST方法POST放在REQUESTBODY里的,getParameter是取不到的有兴趣的可以试一下参数过来是串,想直接用肯定还需要转换?要么自带提供的有,要么自己转可以用post 请求把json数据作为值,例如value=jsondata,这个时候用 getParameter可以取到,剩下的你想怎么转就怎么转,还有一种方法,自定义ConversionService

爱吃鱼的程序员 2020-06-15 19:51:03 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档用户可以通过以下方式向OSS中上传文件: 以下示例代码中的catch语法,请自行学习下es6 promise、async/await。仔细阅读下sdk的使用方式,传送门。 上传本地文件流式上传上传Buffer内容分片上传断点上传 上传本地文件通过put接口来上传一个本地文件到OSS: let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function put () { try { let result = await client.put('object-key', 'local-file'); console.log(result); } catch (e) { console.log(er); }}put(); 流式上传通过putStream接口来上传一个Stream中的内容,stream参数可以是任何实现了Readable Stream的对象,包含文件流,网络流等。当使用putStream接口时,SDK默认会发起一个chunked encoding的HTTP PUT请求。如果在options指定了contentLength参数,则不会使用chunked encoding。 let OSS = require('ali-oss');let fs = require('fs');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putStream () { try { // use 'chunked encoding' let stream = fs.createReadStream('local-file'); let result = yield client.putStream('object-key', stream); console.log(result); // don't use 'chunked encoding' let stream = fs.createReadStream('local-file'); let size = fs.statSync('local-file').size; let result = await client.putStream( 'object-key', stream, {contentLength: size}); console.log(result); } catch (e) { console.log(e) }}putStream(); 上传Buffer内容用户也可以通过put接口简单地将Buffer中的内容上传到OSS: let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putBuffer () { try { let result = await client.put('object-key', new Buffer('hello world')); console.log(result); } catch (e) { console.log(e); }}putBuffer(); 分片上传在需要上传的文件较大时,可以通过multipartUpload接口进行分片上传。分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了。一般对于大于100MB的文件,建议采用分片上传的方法。 在使用multipartUpload接口如果遇到ConnectionTimeoutError超时问题,业务方需要自己处理超时逻辑。如何处理超时,可以缩小分片大小、加大超时时间、重试请求,或者业务上捕获ConnectionTimeoutError错误,然后给用户提示。 相关参数: name {String} object 名称file {String|File} file path or HTML5 Web File[options] {Object} 额外参数 [checkpoint] {Object} 断点记录点,可以进行断点续传, 如果设置这个参数,上传会从断点开始,如果没有设置,就会重新上传.[parallel] {Number} 并发上传的分片个数[partSize] {Number} 分片大小[progress] {Function} async函数形式, 回调函数包含三个参数 (percentage {Number} 进度百分比(0-1之间小数)checkpoint {Object} 断点记录点res {Object}) 单次part成功返回的response [meta] {Object} 用户自定义header meta信息, header前缀 x-oss-meta-[headers] {Object} extra headers, detail see RFC 2616 ‘Cache-Control’ 通用消息头被用于在http 请求和响应中通过指定指令来实现缓存机制, e.g.: Cache-Control: public, no-cache‘Content-Disposition’ 指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地, e.g.: Content-Disposition: somename‘Content-Encoding’ 用于对特定媒体类型的数据进行压缩, e.g.: Content-Encoding: gzip‘Expires’ 过期时间, e.g.: Expires: 3600000 let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function multipartUpload () { try { let result = await client.multipartUpload('object-key', 'local-file', { progress, meta: { year: 2017, people: 'test' } }); console.log(result); let head = await client.head('object-key'); console.log(head); } catch (e) { // 捕获超时异常 if (e.code === 'ConnectionTimeoutError') { console.log("Woops,超时啦!"); // do ConnectionTimeoutError operation } console.log(e) }} 上面的progress参数是一个进度回调函数,用于获取上传进度。progress可以是一个async函数: const progress = async function (p) { console.log(p);}; 上面的meta参数是一个用户自定义的元数据,通过head接口可以获取到object的meta数据。 断点上传分片上传提供progress参数允许用户传递一个进度回调,在回调中SDK将当前已经上传成功的比例和断点信息作为参数。为了实现断点上传,可以在上传过程中保存断点信息(checkpoint),发生错误后,再将已保存的checkpoint作为参数传递给multipartUpload,此时将从上次失败的地方继续上传。 let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});let checkpoint;async function resumeUpload() { // retry 5 times for (let i = 0; i < 5; i++) { try { const result = await client.multipartUpload('object-key', filePath, { checkpoint, async progress(percentage, cpt) { checkpoint = cpt; }, }); console.log(result); break; // break if success } catch (e) { console.log(e); } }}resumeUpload(); 上面的代码只是将checkpoint保存在变量中,如果程序崩溃的话就丢失了,用户也可以将它保存在文件中,然后在程序重启后将checkpoint信息从文件中读取出来。

2019-12-01 23:14:15 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档用户可以通过以下方式向OSS中上传文件: 以下示例代码中的catch语法,请自行学习下es6 promise、async/await。仔细阅读下sdk的使用方式,传送门。 上传本地文件流式上传上传Buffer内容分片上传断点上传 上传本地文件通过put接口来上传一个本地文件到OSS: let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function put () { try { let result = await client.put('object-key', 'local-file'); console.log(result); } catch (e) { console.log(er); }}put(); 流式上传通过putStream接口来上传一个Stream中的内容,stream参数可以是任何实现了Readable Stream的对象,包含文件流,网络流等。当使用putStream接口时,SDK默认会发起一个chunked encoding的HTTP PUT请求。如果在options指定了contentLength参数,则不会使用chunked encoding。 let OSS = require('ali-oss');let fs = require('fs');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putStream () { try { // use 'chunked encoding' let stream = fs.createReadStream('local-file'); let result = yield client.putStream('object-key', stream); console.log(result); // don't use 'chunked encoding' let stream = fs.createReadStream('local-file'); let size = fs.statSync('local-file').size; let result = await client.putStream( 'object-key', stream, {contentLength: size}); console.log(result); } catch (e) { console.log(e) }}putStream(); 上传Buffer内容用户也可以通过put接口简单地将Buffer中的内容上传到OSS: let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putBuffer () { try { let result = await client.put('object-key', new Buffer('hello world')); console.log(result); } catch (e) { console.log(e); }}putBuffer(); 分片上传在需要上传的文件较大时,可以通过multipartUpload接口进行分片上传。分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了。一般对于大于100MB的文件,建议采用分片上传的方法。 在使用multipartUpload接口如果遇到ConnectionTimeoutError超时问题,业务方需要自己处理超时逻辑。如何处理超时,可以缩小分片大小、加大超时时间、重试请求,或者业务上捕获ConnectionTimeoutError错误,然后给用户提示。 相关参数: name {String} object 名称file {String|File} file path or HTML5 Web File[options] {Object} 额外参数 [checkpoint] {Object} 断点记录点,可以进行断点续传, 如果设置这个参数,上传会从断点开始,如果没有设置,就会重新上传.[parallel] {Number} 并发上传的分片个数[partSize] {Number} 分片大小[progress] {Function} async函数形式, 回调函数包含三个参数 (percentage {Number} 进度百分比(0-1之间小数)checkpoint {Object} 断点记录点res {Object}) 单次part成功返回的response [meta] {Object} 用户自定义header meta信息, header前缀 x-oss-meta-[headers] {Object} extra headers, detail see RFC 2616 ‘Cache-Control’ 通用消息头被用于在http 请求和响应中通过指定指令来实现缓存机制, e.g.: Cache-Control: public, no-cache‘Content-Disposition’ 指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地, e.g.: Content-Disposition: somename‘Content-Encoding’ 用于对特定媒体类型的数据进行压缩, e.g.: Content-Encoding: gzip‘Expires’ 过期时间, e.g.: Expires: 3600000 let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function multipartUpload () { try { let result = await client.multipartUpload('object-key', 'local-file', { progress, meta: { year: 2017, people: 'test' } }); console.log(result); let head = await client.head('object-key'); console.log(head); } catch (e) { // 捕获超时异常 if (e.code === 'ConnectionTimeoutError') { console.log("Woops,超时啦!"); // do ConnectionTimeoutError operation } console.log(e) }} 上面的progress参数是一个进度回调函数,用于获取上传进度。progress可以是一个async函数: const progress = async function (p) { console.log(p);}; 上面的meta参数是一个用户自定义的元数据,通过head接口可以获取到object的meta数据。 断点上传分片上传提供progress参数允许用户传递一个进度回调,在回调中SDK将当前已经上传成功的比例和断点信息作为参数。为了实现断点上传,可以在上传过程中保存断点信息(checkpoint),发生错误后,再将已保存的checkpoint作为参数传递给multipartUpload,此时将从上次失败的地方继续上传。 let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});let checkpoint;async function resumeUpload() { // retry 5 times for (let i = 0; i < 5; i++) { try { const result = await client.multipartUpload('object-key', filePath, { checkpoint, async progress(percentage, cpt) { checkpoint = cpt; }, }); console.log(result); break; // break if success } catch (e) { console.log(e); } }}resumeUpload(); 上面的代码只是将checkpoint保存在变量中,如果程序崩溃的话就丢失了,用户也可以将它保存在文件中,然后在程序重启后将checkpoint信息从文件中读取出来。

2019-12-01 23:14:15 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档用户可以通过以下方式向OSS中上传文件: 以下示例代码中的catch语法,请自行学习下es6 promise、async/await。仔细阅读下sdk的使用方式,传送门。 上传本地文件流式上传上传Buffer内容分片上传断点上传 上传本地文件通过put接口来上传一个本地文件到OSS: let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function put () { try { let result = await client.put('object-key', 'local-file'); console.log(result); } catch (e) { console.log(er); }}put(); 流式上传通过putStream接口来上传一个Stream中的内容,stream参数可以是任何实现了Readable Stream的对象,包含文件流,网络流等。当使用putStream接口时,SDK默认会发起一个chunked encoding的HTTP PUT请求。如果在options指定了contentLength参数,则不会使用chunked encoding。 let OSS = require('ali-oss');let fs = require('fs');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putStream () { try { // use 'chunked encoding' let stream = fs.createReadStream('local-file'); let result = yield client.putStream('object-key', stream); console.log(result); // don't use 'chunked encoding' let stream = fs.createReadStream('local-file'); let size = fs.statSync('local-file').size; let result = await client.putStream( 'object-key', stream, {contentLength: size}); console.log(result); } catch (e) { console.log(e) }}putStream(); 上传Buffer内容用户也可以通过put接口简单地将Buffer中的内容上传到OSS: let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putBuffer () { try { let result = await client.put('object-key', new Buffer('hello world')); console.log(result); } catch (e) { console.log(e); }}putBuffer(); 分片上传在需要上传的文件较大时,可以通过multipartUpload接口进行分片上传。分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了。一般对于大于100MB的文件,建议采用分片上传的方法。 在使用multipartUpload接口如果遇到ConnectionTimeoutError超时问题,业务方需要自己处理超时逻辑。如何处理超时,可以缩小分片大小、加大超时时间、重试请求,或者业务上捕获ConnectionTimeoutError错误,然后给用户提示。 相关参数: name {String} object 名称file {String|File} file path or HTML5 Web File[options] {Object} 额外参数 [checkpoint] {Object} 断点记录点,可以进行断点续传, 如果设置这个参数,上传会从断点开始,如果没有设置,就会重新上传.[parallel] {Number} 并发上传的分片个数[partSize] {Number} 分片大小[progress] {Function} async函数形式, 回调函数包含三个参数 (percentage {Number} 进度百分比(0-1之间小数)checkpoint {Object} 断点记录点res {Object}) 单次part成功返回的response [meta] {Object} 用户自定义header meta信息, header前缀 x-oss-meta-[headers] {Object} extra headers, detail see RFC 2616 ‘Cache-Control’ 通用消息头被用于在http 请求和响应中通过指定指令来实现缓存机制, e.g.: Cache-Control: public, no-cache‘Content-Disposition’ 指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地, e.g.: Content-Disposition: somename‘Content-Encoding’ 用于对特定媒体类型的数据进行压缩, e.g.: Content-Encoding: gzip‘Expires’ 过期时间, e.g.: Expires: 3600000 let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function multipartUpload () { try { let result = await client.multipartUpload('object-key', 'local-file', { progress, meta: { year: 2017, people: 'test' } }); console.log(result); let head = await client.head('object-key'); console.log(head); } catch (e) { // 捕获超时异常 if (e.code === 'ConnectionTimeoutError') { console.log("Woops,超时啦!"); // do ConnectionTimeoutError operation } console.log(e) }} 上面的progress参数是一个进度回调函数,用于获取上传进度。progress可以是一个async函数: const progress = async function (p) { console.log(p);}; 上面的meta参数是一个用户自定义的元数据,通过head接口可以获取到object的meta数据。 断点上传分片上传提供progress参数允许用户传递一个进度回调,在回调中SDK将当前已经上传成功的比例和断点信息作为参数。为了实现断点上传,可以在上传过程中保存断点信息(checkpoint),发生错误后,再将已保存的checkpoint作为参数传递给multipartUpload,此时将从上次失败的地方继续上传。 let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});let checkpoint;async function resumeUpload() { // retry 5 times for (let i = 0; i < 5; i++) { try { const result = await client.multipartUpload('object-key', filePath, { checkpoint, async progress(percentage, cpt) { checkpoint = cpt; }, }); console.log(result); break; // break if success } catch (e) { console.log(e); } }}resumeUpload(); 上面的代码只是将checkpoint保存在变量中,如果程序崩溃的话就丢失了,用户也可以将它保存在文件中,然后在程序重启后将checkpoint信息从文件中读取出来。

2019-12-01 23:14:15 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档用户可以通过以下方式向OSS中上传文件: 以下示例代码中的catch语法,请自行学习下es6 promise、async/await。仔细阅读下sdk的使用方式,传送门。 上传本地文件流式上传上传Buffer内容分片上传断点上传 上传本地文件通过put接口来上传一个本地文件到OSS: let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function put () { try { let result = await client.put('object-key', 'local-file'); console.log(result); } catch (e) { console.log(er); }}put(); 流式上传通过putStream接口来上传一个Stream中的内容,stream参数可以是任何实现了Readable Stream的对象,包含文件流,网络流等。当使用putStream接口时,SDK默认会发起一个chunked encoding的HTTP PUT请求。如果在options指定了contentLength参数,则不会使用chunked encoding。 let OSS = require('ali-oss');let fs = require('fs');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putStream () { try { // use 'chunked encoding' let stream = fs.createReadStream('local-file'); let result = yield client.putStream('object-key', stream); console.log(result); // don't use 'chunked encoding' let stream = fs.createReadStream('local-file'); let size = fs.statSync('local-file').size; let result = await client.putStream( 'object-key', stream, {contentLength: size}); console.log(result); } catch (e) { console.log(e) }}putStream(); 上传Buffer内容用户也可以通过put接口简单地将Buffer中的内容上传到OSS: let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putBuffer () { try { let result = await client.put('object-key', new Buffer('hello world')); console.log(result); } catch (e) { console.log(e); }}putBuffer(); 分片上传在需要上传的文件较大时,可以通过multipartUpload接口进行分片上传。分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了。一般对于大于100MB的文件,建议采用分片上传的方法。 在使用multipartUpload接口如果遇到ConnectionTimeoutError超时问题,业务方需要自己处理超时逻辑。如何处理超时,可以缩小分片大小、加大超时时间、重试请求,或者业务上捕获ConnectionTimeoutError错误,然后给用户提示。 相关参数: name {String} object 名称file {String|File} file path or HTML5 Web File[options] {Object} 额外参数 [checkpoint] {Object} 断点记录点,可以进行断点续传, 如果设置这个参数,上传会从断点开始,如果没有设置,就会重新上传.[parallel] {Number} 并发上传的分片个数[partSize] {Number} 分片大小[progress] {Function} async函数形式, 回调函数包含三个参数 (percentage {Number} 进度百分比(0-1之间小数)checkpoint {Object} 断点记录点res {Object}) 单次part成功返回的response [meta] {Object} 用户自定义header meta信息, header前缀 x-oss-meta-[headers] {Object} extra headers, detail see RFC 2616 ‘Cache-Control’ 通用消息头被用于在http 请求和响应中通过指定指令来实现缓存机制, e.g.: Cache-Control: public, no-cache‘Content-Disposition’ 指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地, e.g.: Content-Disposition: somename‘Content-Encoding’ 用于对特定媒体类型的数据进行压缩, e.g.: Content-Encoding: gzip‘Expires’ 过期时间, e.g.: Expires: 3600000 let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function multipartUpload () { try { let result = await client.multipartUpload('object-key', 'local-file', { progress, meta: { year: 2017, people: 'test' } }); console.log(result); let head = await client.head('object-key'); console.log(head); } catch (e) { // 捕获超时异常 if (e.code === 'ConnectionTimeoutError') { console.log("Woops,超时啦!"); // do ConnectionTimeoutError operation } console.log(e) }} 上面的progress参数是一个进度回调函数,用于获取上传进度。progress可以是一个async函数: const progress = async function (p) { console.log(p);}; 上面的meta参数是一个用户自定义的元数据,通过head接口可以获取到object的meta数据。 断点上传分片上传提供progress参数允许用户传递一个进度回调,在回调中SDK将当前已经上传成功的比例和断点信息作为参数。为了实现断点上传,可以在上传过程中保存断点信息(checkpoint),发生错误后,再将已保存的checkpoint作为参数传递给multipartUpload,此时将从上次失败的地方继续上传。 let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});let checkpoint;async function resumeUpload() { // retry 5 times for (let i = 0; i < 5; i++) { try { const result = await client.multipartUpload('object-key', filePath, { checkpoint, async progress(percentage, cpt) { checkpoint = cpt; }, }); console.log(result); break; // break if success } catch (e) { console.log(e); } }}resumeUpload(); 上面的代码只是将checkpoint保存在变量中,如果程序崩溃的话就丢失了,用户也可以将它保存在文件中,然后在程序重启后将checkpoint信息从文件中读取出来。

2019-12-01 23:14:15 0 浏览量 回答数 0

回答

详细解答可以参考官方帮助文档用户可以通过以下方式向OSS中上传文件: 以下示例代码中的catch语法,请自行学习下es6 promise、async/await。仔细阅读下sdk的使用方式,传送门。 上传本地文件流式上传上传Buffer内容分片上传断点上传 上传本地文件通过put接口来上传一个本地文件到OSS: let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function put () { try { let result = await client.put('object-key', 'local-file'); console.log(result); } catch (e) { console.log(er); }}put(); 流式上传通过putStream接口来上传一个Stream中的内容,stream参数可以是任何实现了Readable Stream的对象,包含文件流,网络流等。当使用putStream接口时,SDK默认会发起一个chunked encoding的HTTP PUT请求。如果在options指定了contentLength参数,则不会使用chunked encoding。 let OSS = require('ali-oss');let fs = require('fs');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putStream () { try { // use 'chunked encoding' let stream = fs.createReadStream('local-file'); let result = yield client.putStream('object-key', stream); console.log(result); // don't use 'chunked encoding' let stream = fs.createReadStream('local-file'); let size = fs.statSync('local-file').size; let result = await client.putStream( 'object-key', stream, {contentLength: size}); console.log(result); } catch (e) { console.log(e) }}putStream(); 上传Buffer内容用户也可以通过put接口简单地将Buffer中的内容上传到OSS: let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function putBuffer () { try { let result = await client.put('object-key', new Buffer('hello world')); console.log(result); } catch (e) { console.log(e); }}putBuffer(); 分片上传在需要上传的文件较大时,可以通过multipartUpload接口进行分片上传。分片上传的好处是将一个大请求分成多个小请求来执行,这样当其中一些请求失败后,不需要重新上传整个文件,而只需要上传失败的分片就可以了。一般对于大于100MB的文件,建议采用分片上传的方法。 在使用multipartUpload接口如果遇到ConnectionTimeoutError超时问题,业务方需要自己处理超时逻辑。如何处理超时,可以缩小分片大小、加大超时时间、重试请求,或者业务上捕获ConnectionTimeoutError错误,然后给用户提示。 相关参数: name {String} object 名称file {String|File} file path or HTML5 Web File[options] {Object} 额外参数 [checkpoint] {Object} 断点记录点,可以进行断点续传, 如果设置这个参数,上传会从断点开始,如果没有设置,就会重新上传.[parallel] {Number} 并发上传的分片个数[partSize] {Number} 分片大小[progress] {Function} async函数形式, 回调函数包含三个参数 (percentage {Number} 进度百分比(0-1之间小数)checkpoint {Object} 断点记录点res {Object}) 单次part成功返回的response [meta] {Object} 用户自定义header meta信息, header前缀 x-oss-meta-[headers] {Object} extra headers, detail see RFC 2616 ‘Cache-Control’ 通用消息头被用于在http 请求和响应中通过指定指令来实现缓存机制, e.g.: Cache-Control: public, no-cache‘Content-Disposition’ 指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地, e.g.: Content-Disposition: somename‘Content-Encoding’ 用于对特定媒体类型的数据进行压缩, e.g.: Content-Encoding: gzip‘Expires’ 过期时间, e.g.: Expires: 3600000 let OSS = require('ali-oss')let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});async function multipartUpload () { try { let result = await client.multipartUpload('object-key', 'local-file', { progress, meta: { year: 2017, people: 'test' } }); console.log(result); let head = await client.head('object-key'); console.log(head); } catch (e) { // 捕获超时异常 if (e.code === 'ConnectionTimeoutError') { console.log("Woops,超时啦!"); // do ConnectionTimeoutError operation } console.log(e) }} 上面的progress参数是一个进度回调函数,用于获取上传进度。progress可以是一个async函数: const progress = async function (p) { console.log(p);}; 上面的meta参数是一个用户自定义的元数据,通过head接口可以获取到object的meta数据。 断点上传分片上传提供progress参数允许用户传递一个进度回调,在回调中SDK将当前已经上传成功的比例和断点信息作为参数。为了实现断点上传,可以在上传过程中保存断点信息(checkpoint),发生错误后,再将已保存的checkpoint作为参数传递给multipartUpload,此时将从上次失败的地方继续上传。 let OSS = require('ali-oss');let client = new OSS({ region: '<Your region>', accessKeyId: '<Your AccessKeyId>', accessKeySecret: '<Your AccessKeySecret>', bucket: 'Your bucket name'});let checkpoint;async function resumeUpload() { // retry 5 times for (let i = 0; i < 5; i++) { try { const result = await client.multipartUpload('object-key', filePath, { checkpoint, async progress(percentage, cpt) { checkpoint = cpt; }, }); console.log(result); break; // break if success } catch (e) { console.log(e); } }}resumeUpload(); 上面的代码只是将checkpoint保存在变量中,如果程序崩溃的话就丢失了,用户也可以将它保存在文件中,然后在程序重启后将checkpoint信息从文件中读取出来。

2019-12-01 23:14:15 0 浏览量 回答数 0

问题

JDBC 使用经验之谈 为什么选择JDBC JDBC使用经验:报错

kun坤 2020-06-09 22:12:13 0 浏览量 回答数 1

回答

使用 Spring 的 AOP,具体代码如下(仅做参考): @Component @Aspect public class AopLog { private static final Logger log = LoggerFactory.getLogger(AopLog.class);     // 提示信息格式     private final static String msg = "\r\nIP:{}\r\nURL:{}\r\nHTTP_METHOD:{}\r\nCLASS_METHOD:{}\r\nARGS:{}\r\nResult:{}\r\nConsuming:{}ms\r\n";          @Pointcut("execution(public * com.hong..*Controller.*(..))")     public void log() {     }     @Around("log()")     public Object before(ProceedingJoinPoint joinPoint) throws Throwable {         long startTime = System.currentTimeMillis();        // 方法开始执行的时间         String args = Arrays.toString(joinPoint.getArgs()); // 方法参数         String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();    // 调用的方法         Object result = null;         /*          * 获取 request 信息          */         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();         String url = "", httpMethod = "", ip = "";         if(attributes != null) {             HttpServletRequest request = attributes.getRequest();             // 记录下请求内容             url = request.getRequestURL().toString();             httpMethod = request.getMethod();             ip = getIpAddr(request);         }                  long methodEnd;                  // 执行方法,如果有异常,则进行记录         try {             result = joinPoint.proceed();         } catch (Exception e) {             methodEnd = System.currentTimeMillis();     // 记录出现异常时的执行时间                          result = e.getMessage();                          log.error(msg, ip, url, httpMethod, classMethod, args, result, methodEnd - startTime, e);                          throw e;         }                  methodEnd = System.currentTimeMillis();     // 记录方法正常执行后时间         log.info(msg, ip, url, httpMethod, classMethod, args, result, methodEnd - startTime);                  return result;     }          /**      * 获取客户端IP      * @param request       HttpServletReqeust信息      * @return              IP      */     private String getIpAddr(HttpServletRequest request) {         String ip = request.getHeader("x-forwarded-for");                  if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {             ip = request.getHeader("Proxy-Client-IP");         }                  if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {             ip = request.getHeader("WL-Proxy-Client-IP");         }                  if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {             ip = request.getRemoteAddr();         }                  return ip;     } }  ###### org.springframework.web.servlet.handler.HandlerInterceptorAdapter 不知道有用不 ######现在就是用这种方式处理的,但是如果在interceptor里面读取了流里面的body内容,到达controller的时候,就读不到body了,因为流里面的内容被读取过就没有了###### aop aspectJ ###### 楼主解决了吗??求指点。

kun坤 2020-06-06 16:28:37 0 浏览量 回答数 0

问题

RESTful API是什么?

nicenelly 2019-12-01 21:28:05 1910 浏览量 回答数 0

问题

java 线程安全问题:报错

kun坤 2020-06-09 23:07:33 0 浏览量 回答数 1

问题

Android-SDK之如何实现快速入门?

青衫无名 2019-12-01 21:41:14 982 浏览量 回答数 0

问题

分析型数据库如何进行业务系统连接并进行查询?(1)

nicenelly 2019-12-01 21:15:53 1087 浏览量 回答数 0

问题

HibernateDaoSupport : 配置报错 

kun坤 2020-06-04 11:25:28 5 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站