今天完成了任务7的内容:
1.学员报名系统加上手机,邮箱,头像的字段,接口中添加对应的字段。
2.去容联申请免费的短信通道(或者是收钱的我不知道),SendCloud申请邮箱的,去金山云或者是七牛云去申请图片存储的。所有的账号和密码都只能通过Spring的配置文件完成。
3.分别按照Demo,测试短信,邮件,图片能否正常上传,账号是否可以正常使用,再去集成到自己的学员报名系统中。
4.分别做好异常处理,要知道第三方Api是很容易出问题的,最常见的方式就是当出现异常的时候,记录错误日志,然后每天晚上跑脚本,看看当天的邮件,短信,图片上传的失败率有多少。
5.编写图片迁移程序:假设是从金山云迁到七牛云,以及从七牛云迁到金山云。
部分代码:
控制器增加两个方法,一个注册,一个获取验证码。
注册控制器中,有6个参数,分别是,一个new 的用户对象,密码,验证码,头像图片的文件,用户选择的储存服务,Request。先校验验证码,再上传图片,再将用户数据插入数据库,再发送欢迎邮件,最后返回成功JSP页面。
验证码控制器中,使用SessionId和SessionLastAccessTime防止恶意发送验证码(本来应该使用定时运行功能,但配置起来过于麻烦,就暂时这样实现了),同一个Session半个小时不能超过三次取得验证码。
@PostMapping("/register")
public String registerHandler(User user,
@RequestParam("password") String password,
@RequestParam("code") String code,
@RequestParam("file") MultipartFile file,
@RequestParam(value = "service", required = false) Integer serviceNum,
HttpServletRequest request) throws Throwable {
//首先校验短信验证码
if (!smsCodeService.checkSmsCode(user.getPhone(), Integer.parseInt(code))){
request.setAttribute("message", "验证码错误!");
return "register";
}
//上传图片到七牛(或阿里)
if(serviceNum == 1){
storageService = aliService;
}else{
storageService = qiniuService;
}
if (!file.isEmpty()) {
byte[] bytes = file.getBytes();
storageService.upload(bytes, user.getUsername());
}
//将密码转为token
String token = md5Cipher.MD5(password);
user.setPasswordToken(token);
//数据库中加入用户
userService.insertUser(user);
//发送确认邮件
emailService.sendWelcome(user);
request.setAttribute("user", user);
return "success";
}
@PostMapping("/getcode")
public String smscodeHandler(@RequestParam("phone") String phone, HttpServletRequest request){
String session = request.getRequestedSessionId();
if(!sessionMap.containsKey(session)){
sessionMap.put(session, 1);
sessionTimeMap.put(session, request.getSession().getLastAccessedTime());
smsCodeService.sendSmsCode(phone);
return "register";
}
if(isExpired(30, sessionTimeMap.get(session))){
sessionTimeMap.remove(session);
sessionMap.remove(session);
smsCodeService.sendSmsCode(phone);
return "register";
}
if(sessionMap.get(session) <= 2){
sessionMap.put(session, sessionMap.get(session) + 1);
smsCodeService.sendSmsCode(phone);
return "register";
}
else {
return "redirect:/smscode.jsp";
}
下面是使用的第三方SDK写的服务类:
阿里对象储存:
@Service
public class AliService implements StorageService{
@Autowired
private OSSClient ossClient;
public boolean upload(byte [] bytes, String key){
ossClient.putObject("zt1106", key, new ByteArrayInputStream(bytes));
return true;
}
public byte [] download(String key) throws IOException {
OSSObject ossObject = ossClient.getObject("zt1106", key);
InputStream content = ossObject.getObjectContent();
if (content != null) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(content, output);
byte [] bytes = output.toByteArray();
content.close();
return bytes;
}
return null;
}
}
七牛对象储存:
public class QiniuService implements StorageService{
@Autowired
private Logger logger;
private String accessKey;
private String secretKey;
private String bucket;
//private String key = "file key";
//构造一个带指定Zone对象的配置类
//zone1代表华北地区
private Configuration cfg;
//...其他参数参考类注释
private UploadManager uploadManager;
//...生成上传凭证,然后准备上传
private Auth auth;
public QiniuService(){
cfg = new Configuration(Zone.zone1());
uploadManager = new UploadManager(cfg);
}
public QiniuService(String accessKey, String secretKey, String bucket) {
this();
this.accessKey = accessKey;
this.secretKey = secretKey;
this.bucket = bucket;
auth = Auth.create(accessKey, secretKey);
}
public boolean upload(byte [] bytes, String key){
String upToken = auth.uploadToken(bucket, key);
try {
Response response = uploadManager.put(bytes, key, upToken);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
//System.out.println(putRet.key);
//System.out.println(putRet.hash);
return true;
} catch (QiniuException ex) {
Response r = ex.response;
logger.error("picture upload failed" + r.toString());
try {
System.err.println(r.bodyString());
} catch (QiniuException ex2) {
//ignore
}
}
return false;
}
public byte [] download(String key) throws UnsupportedEncodingException, MalformedURLException {
String encodedFileName = URLEncoder.encode(key, "utf-8");
String finalUrl = String.format("%s/%s", domainOfBucket, encodedFileName);
URL url = new URL(finalUrl);
try {
URLConnection conn = url.openConnection();
InputStream inStream = conn.getInputStream();
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(inStream, output);
byte [] bytes = output.toByteArray();
return bytes;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
邮件服务方法(SendCloud):
public void sendWelcome(User user) throws Throwable {
MailAddressReceiver receiver = new MailAddressReceiver();
receiver.addTo(user.getEmail());
MailBody body = new MailBody();
body.setFromName("zt1106");
body.setSubject("注册成功!!");
TextContent content = new TextContent();
content.setContent_type(TextContent.ScContentType.html);
content.setText("<html><p>" + user.getUsername() + " 您已注册成功</p></html>");
SendCloudMail mail = new SendCloudMail();
mail.setTo(receiver);
mail.setBody(body);
mail.setContent(content);
SendCloud sc = null;
try {
sc = SendCloudBuilder.build();
} catch (Exception e) {
logger.error("send email failed, unknown error " + e.getMessage());
}
ResponseData res = sc.sendMail(mail);
if(res.getStatusCode() != 200){
logger.error("send email failed, " + res.getInfo());
}
短信验证码方法(一家不知名网站的):
public void sendSmsCode(String phone){
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(Url);
client.getParams().setContentCharset("UTF-8");
method.setRequestHeader("ContentType","application/x-www-form-urlencoded;charset=UTF-8");
int mobile_code = (int)((Math.random()*9+1)*100000);
map.put(phone, mobile_code);
String content = "您的验证码是:" + mobile_code + "。请不要把验证码泄露给其他人。";
NameValuePair[] data = {
new NameValuePair("account", account),//APIID
new NameValuePair("password", password), //APIKEY
new NameValuePair("mobile", phone),
new NameValuePair("content", content),
};
method.setRequestBody(data);
try {
client.executeMethod(method);
//String SubmitResult =method.getResponseBodyAsString();
}
catch (HttpException e) {
logger.error("sms code http failed " + e.getMessage());
} catch (IOException e) {
logger.error("sms code io failed " + e.getMessage());
}
阿里云和七牛云互相迁移方法:
@Autowired
public PictureTransfer(UserService userService, AliService aliService, QiniuService qiniuService) {
this.userService = userService;
this.aliService = aliService;
this.qiniuService = qiniuService;
}
public void transferToAli() throws Exception {
transfer(qiniuService, aliService);
}
public void transferToQiniu() throws Exception {
transfer(aliService, qiniuService);
}
public void transfer(StorageService from, StorageService to) throws Exception {
List<User> userList = userService.getAllUsers();
for (User user : userList){
if (user.getUsername() != null) {
to.upload(from.download(user.getUsername()), user.getUsername());
}
}
所有的第三方Service类都在Spring容器中进行配置,使用同一的config.properties配置文件配置用户名密码URL等属性。
在成功页面JSP显示刚注册好的用户的信息,和他在七牛云的照片:
<body>
用户信息:<br>
user information <%= request.getAttribute("user") %>
<br>
<%
User user = (User) request.getAttribute("user");
%>
<img src="<%=link%>"/>
</body>
明天:开始学习任务8的新内容。
问题:
1. 对于控制器返回值的写法还是比较乱,总是搞混视图和路径,也搞不清楚路径和视图的名字的命名规范是什么。
2. 基础还是不牢,很多东西现查,然后查完了还记不住。
3. 项目越来越大,依赖的问题越来越频繁,在加载第三方SDK时,需要更多乱七八糟的jar包,导致maven里臃肿不堪。
总结:任务中的易容联和SendCloud的短信服务都不能用了,一个要企业认证,一个要充500块钱,建议找一些小网站,管的没那么严;对象储存很便宜,阿里云100GB一年才4块钱。
评论