1.HttpURLConnection
任何网络连接都需要经过socket才能连接,HttpURLConnection不需要设置socket,所以,HttpURLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么HttpURLConneciton只是一个抽象类,自身不能被实例化的原因。HttpURLConnection只能通过URL.openConnection()方法创建具体的实例。
虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStream或OutputStream的close()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket。
2.代码示例
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Date;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
/**
* @author 作 者:小杜
* @version 创建时间:2017-2-8 下午6:48:40
* @Description 描述:发送手机短信
*/
@Service
public class SendVerlifyCodeImpl implements ISendVerlifyCode {
//发送短信平台的网址地址
@Value("${sms.host}")
private String host;
//注册发送短信平台的用户名
@Value("${sms.username}")
private String username;
//注册发送短信平台的网址密码
@Value("${sms.password}")
private String password;
//注册发送短信平台的网址的密钥
@Value("${sms.apikey}")
private String apikey;
/**
* 验证码的生成和发送到手机
*/
@SuppressWarnings("unused")
@Override
public void SendVerlifyCode(String phoneNumber) {
VerlifyCode vc = UserContext.getVerlifyCode();
//1判断是否能再次发送短信,即当前session中没有,或者时间间隔可以响应
if (vc == null
|| (vc != null && DateUtil.getSecondBetween(new Date(), vc.getSendDate()) >= BidConst.SEND_VERLIFY_CODE)) {
//2如果能够发送
//2.1生成一个验证码
vc = new VerlifyCode();
String code = UUID.randomUUID().toString().substring(0, 4);
vc.setPhoneNumber(phoneNumber);
vc.setSendDate(new Date());
vc.setVerlifyCode(code);
//2.2发送短信
String content = "发送短信,你的验证码为" + code + "有效期为" + BidConst.VERLIFYCODE_VERLIFY_INTERVAL + "分钟,请在在有效期内使用!";
// 创建一个URL请求对象
try {
//使用HttpURLConnection来发送短信
URL url = new URL(host);
HttpURLConnection openConnection = (HttpURLConnection) url.openConnection();
//设置请求方法为post,必须为大写
openConnection.setRequestMethod("POST");
//设置为带内容输出
openConnection.setDoOutput(true);
//参数的拼接
StringBuilder params = new StringBuilder().append("?username=" + this.username)
.append("&password=" + this.password).append("&apikey=" + apikey).append("&content=" + content)
.append("?phoneNumber=" + phoneNumber);
//输出参数
openConnection.getOutputStream().write(params.toString().getBytes("UTF-8"));
//连接
openConnection.connect();
//得到响应的内容
String responeText = StreamUtils
.copyToString(openConnection.getInputStream(), Charset.forName("UTF-8"));
if (responeText.startsWith("success")) {
//2.3保存相关信息(发送时间、电话号码,验证码)可以放到session中去,发送短信成功再保存,否则 短信可以没有发送成功
UserContext.putVerlifyCode(vc);
} else {
throw new RuntimeException("发送失败!");
}
} catch (Exception e) {
throw new RuntimeException("发送失败!");
}
} else {
throw new RuntimeException("你的验证码发送过于频繁!");
}
}
}
3.注意事项
超时设置,防止 网络异常的情况下,可能会导致程序僵死而不继续往下执行。
System.setProperty("sun.net.client.defaultConnectTimeout", "30000");
System.setProperty("sun.net.client.defaultReadTimeout", "30000");
其中:
sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)
JDK 1.5以前的版本,只能通过设置这两个系统属性来控制网络超时。在1.5中,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)
例如:
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection .setConnectTimeout(30000);
httpURLConnection .setReadTimeout(30000);
System.setProperty("sun.net.client.defaultReadTimeout", "30000");
其中:
sun.net.client.defaultConnectTimeout:连接主机的超时时间(单位:毫秒)
sun.net.client.defaultReadTimeout:从主机读取数据的超时时间(单位:毫秒)
JDK 1.5以前的版本,只能通过设置这两个系统属性来控制网络超时。在1.5中,还可以使用HttpURLConnection的父类URLConnection的以下两个方法:
setConnectTimeout:设置连接主机超时(单位:毫秒)
setReadTimeout:设置从主机读取数据超时(单位:毫秒)
例如:
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection .setConnectTimeout(30000);
httpURLConnection .setReadTimeout(30000);