java实现云端存储、短信、邮件、沙盒支付

一、云端存储(阿里云)

注意:下面操作是基于购买阿里云云端存储服务实现的
1.FileOSSUtils操作类
package com.zking;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLDecoder;
import java.util.Properties;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;

/**
 * 	云端文件在线存储和下载
 */
public class FileOSSUtils {
	
	private Properties p = null;
	// Endpoint以杭州为例,其它Region请按实际情况填写。
	private String endpoint;
	// 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
	private String accessKeyId;
	//密钥
	private String accessKeySecret;
	//根目录
	private String bucketName;
	
	public FileOSSUtils() throws Exception {
		p = getProperties("fileOssConfig.properties");
		endpoint = p.getProperty("endpoint");
		accessKeyId = p.getProperty("accessKeyId");
		accessKeySecret = p.getProperty("accessKeySecret");
		bucketName = p.getProperty("bucketName");
	}
	
	/**
	 * 	文件上传
	 * @param in 需要上传文件的流
	 * @param savePath 存储的路径,包括文件名
	 */
	public void uploadFile(InputStream in, String savePath) {
		// 创建OSSClient实例。操作云端数据的客户端
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
		//调用putObject上传文件
		ossClient.putObject(bucketName, savePath, in);
		// 关闭OSSClient。
		ossClient.shutdown();
	}
	
	/**
	 * 	下载云端文件
	 * @param out 将文件写入本地的一个输出流(也可以是response的输出流)
	 * @param dowloadPath
	 * @param savePath
	 * @throws IOException
	 */
	public void downloadFile(OutputStream out, String dowloadPath) throws IOException {
		// 创建OSSClient实例。
		OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

		// ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
		OSSObject ossObject = ossClient.getObject(bucketName, dowloadPath);
		//获取云端文件的输入流
		InputStream in = ossObject.getObjectContent();
		
		//将文件写入输出流
		int len = 0;
		byte[] b = new byte[1024];
		BufferedOutputStream bos = new BufferedOutputStream(out);
		while ((len = in.read(b)) != -1) {
			bos.write(b, 0, len);
		}
		bos.close();
		in.close();
		// 关闭OSSClient。
		ossClient.shutdown();
	}
	
	
	/**
	 * 	通过这个类的反射获取项目的根目录,最终得到一个Properties对象
	 * @param prosPath Properties文件的路径
	 * @return 加载了Properties文件的对象
	 * @throws Exception 
	 */
	public Properties getProperties(String prosPath) throws Exception {
		//1.创建一个properties对象
		//这个对象里面就有操作这个properties文件所有方法
		Properties pros = new Properties();
		//2.获取源文件的字节输入流
		InputStream inStream = null;
		try {
			//class文件所在的位置的根目录。
			String path = FileOSSUtils.class.getResource("/").getPath();
			//将中文的url编码解析%ert%weq
			path = URLDecoder.decode(path, "utf-8");
			inStream = new FileInputStream(path + "\\" + prosPath);
			//3.properties对象加载源文件
			pros.load(inStream);
		} catch (FileNotFoundException e) {
			throw new FileNotFoundException("Properties文件路径未找到!");
		} catch (IOException e) {
			throw new IOException("Properties文件流加载失败!");
		}
		return pros;
	}
	
}
2.fileOssConfig.properties文件:
endpoint = http://oss-cn-hangzhou.aliyuncs.com
accessKeyId = 账户名
accessKeySecret = 密码
bucketName = 目录名
savePath = 路径名
3.示例调用:
// 下载所有图片和更新未使用图片的方法
	//pics:传过来需要下载图片的信息
	//下载到项目路径下
	private synchronized void dLOrUpdateAllpics(List<Picture> pics) {
		// 获取广告、轮播、展示信息、友情链接图片的文件路径
		String path = this.getServletContext().getRealPath("/img/indexAdImg/");
		// 新建下载文件类的对象
		FileOSSUtils fileOSSUtils;
		if (pics != null) {
			try {
				fileOSSUtils = new FileOSSUtils();
				// 循环所有的图片
				for (int i = 0; i < pics.size(); i++) {
					// 将云端文件夹图片写入项目目录下的文件夹
					String dowloadPath = pics.get(i).getPicload();
					// 截取下载图片的后缀
					String picSuffix = dowloadPath.substring(dowloadPath.indexOf('.'));
					// 存储文件的路径
					String savePath = "";
					// 图片种类
					String picKinds = pics.get(i).getEffect_location();
					if (picKinds.equals("banner1")) {
						savePath = path + "banner1" + picSuffix;
					} else if (picKinds.equals("banner2")) {
						savePath = path + "banner2" + picSuffix;
					} else if (picKinds.equals("banner3")) {
						savePath = path + "banner3" + picSuffix;
					} else if (picKinds.equals("banner4")) {
						savePath = path + "banner4" + picSuffix;
					} else if (picKinds.equals("abanner1")) {
						savePath = path + "abanner1" + picSuffix;
					} else if (picKinds.equals("abanner2")) {
						savePath = path + "abanner2" + picSuffix;
					} else if (picKinds.equals("abanner3")) {
						savePath = path + "abanner3" + picSuffix;
					} else if (picKinds.equals("abanner4")) {
						savePath = path + "abanner4" + picSuffix;
					} else if (picKinds.equals("pro1")) {
						savePath = path + "pro1" + picSuffix;
					} else if (picKinds.equals("pro2")) {
						savePath = path + "pro2" + picSuffix;
					} else if (picKinds.equals("pro3")) {
						savePath = path + "pro3" + picSuffix;
					} else if (picKinds.equals("pro4")) {
						savePath = path + "pro4" + picSuffix;
					} else if (picKinds.equals("pro5")) {
						savePath = path + "pro5" + picSuffix;
					} else if (picKinds.equals("pro6")) {
						savePath = path + "pro6" + picSuffix;
					} else if (picKinds.equals("pro7")) {
						savePath = path + "pro7" + picSuffix;
					} else if (picKinds.equals("pro8")) {
						savePath = path + "pro8" + picSuffix;
					} else if (picKinds.equals("link01")) {
						savePath = path + "link01" + picSuffix;
					} else if (picKinds.equals("link02")) {
						savePath = path + "link02" + picSuffix;
					} else if (picKinds.equals("link03")) {
						savePath = path + "link03" + picSuffix;
					} else if (picKinds.equals("link04")) {
						savePath = path + "link04" + picSuffix;
					} else {
						System.out.println("图片名不存在!");
					}
					// 两个路径都不为空的时候进行下载操作
					if (!savePath.equals("") && !dowloadPath.equals("")) {
						OutputStream out = new FileOutputStream(savePath);
						fileOSSUtils.downloadFile(out, dowloadPath);
						System.out.println("下载成功!");
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

二、短信(阿里云)

注意:下面操作是基于阿里云信息服务实现的(需要申请accesskeyId,accessSecret,然后申请短信模板)

1.进入阿里云官网进行注册登录 https://www.aliyun.com/?utm_content=se_1000301881

2.点击右侧头像 ,点击AccessKey管理,点击继续使用Accesskey,然后创建自己的AccessKey。代码里会用到!

3.搜索短信控制台进入短信服务页面 https://dysms.console.aliyun.com/dysms.htm#/overview 点击 ‘国内信息’

4.进入签名管理创建自己的签名

5.进入模板管理创建相关模板,这里的${code}是和代码中的code对接的.(注意区别个人与企业,如果不成功可以换模板名多试几次,本人同一模板名试了几次才成功)

代码实现:

package com.common.sendsms;

import java.util.Random;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;

public class SendSms {
	public String sendMsg(String phoneNum) {
		DefaultProfile profile = DefaultProfile.getProfile("default", "accessKeyId", "accessKeySecret");
        IAcsClient client = new DefaultAcsClient(profile);
        //短信平台有很多的
        //有的平台就不限制的
        CommonRequest request = new CommonRequest();
        //发送方式
        request.setMethod(MethodType.POST);
        //阿里云域名
        request.setDomain("dysmsapi.aliyuncs.com");
        //版本日期
        request.setVersion("2017-05-25");
        //设置动作为发送消息
        request.setAction("SendSms");
        request.putQueryParameter("RegionId", "default");
        //发送到哪个手机号
        request.putQueryParameter("PhoneNumbers", {phoneNum(传入)});
        //签名
        request.putQueryParameter("SignName", "{模板名}");
        request.putQueryParameter("TemplateCode", "{模板编码}");
        //可填可不填:outId为提供给业务方扩展字段,最终在短信回执消息中将此值带回给调用者
        request.putQueryParameter("OutId", "{回显名}");
        String code = "";
        //随机四位验证码
        Random r = new Random();
        for (int i = 0; i < 6; i++) {
        	code += r.nextInt(10);
		}
        request.putQueryParameter("TemplateParam", "{\"code\":"+code+"}");
        try {
            CommonResponse response = client.getCommonResponse(request);
            //成功就返回这个验证码
            if(response!=null) {
            	return code;
            }
            //System.out.println(response.getData());
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return null;
	}
	public static void main(String[] args) {
        //测试
		//SendSms sendSms=new SendSms();//新建一个发送短信的对象
		//打印信息
		//System.out.println(sendSms.sendMsg("xxxx"));
	}
}

三、邮件

1.首先进入邮箱的设置,打开三方协议POP3/SMPT/IMAP(以下演示是163邮箱)

2.设置授权码,该密码为java代码要使用的授权密码,与登录密码不一样

3.编写工具类:

package com.zking.sendmail;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.Message.RecipientType;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendMail {
	public static void sendMail(String sender,String toMailName,String header,String msg,)throws Exception{
        //注意:同一个ip不要重复的短时间内发邮件,账号容易被冻结
		//1 设置基本参数
		Properties props = new Properties();
		//2.设置主机
		props.setProperty("mail.host", "smtp.163.com");
		//3.确定使用权限验证
		props.setProperty("mail.smtp.auth", "true");
		//4.确定账号与密码 
		Authenticator authenticator = new Authenticator() {
			@Override
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication("{邮箱的账号}", "{授权码}");
			}
		};
		//5.获得连接
		Session session = Session.getInstance(props, authenticator);
		//6.编写消息
		Message message = new MimeMessage(session);
		//7.设置发件人的邮箱和名字(可随意取)
		message.setFrom(new InternetAddress("{设置发件人的邮箱}",sender(参数传入)));
		//8.设置收件人邮箱 , to:收件人   cc:抄送   bcc:暗送
		 message.setRecipient(RecipientType.TO, new InternetAddress(toMailName(参数传入)));
		//{设置多个收件人地址}可选,传入多个就将参数改为数组或集合等
		//message.addRecipient(RecipientType.TO,new InternetAddress("{设置收件人的邮箱}"));
		 
		// 2.3 主题
		message.setSubject(header(参数传入));
		// 2.4 正文,直接html代码的
		message.setContent(msg(参数传入), "text/html;charset=UTF-8");
		//3发送消息
		Transport.send(message);
		System.out.println("发送成功");
		br.close();
	}
}

四、支付宝沙盒支付

1.注册蚂蚁金服开发者账号。注册地址
2.设置app_id和gatewayUrl,登录之后,会弹出商户入驻信息填写界面,点击切换入驻身份,改为自研开发者,然后填写个人信息。
3.填写完成后,点击开发者中心,再点击点击研发服务,会看到沙箱环境的信息。
4.点击沙箱应用,第一个表格中的APPID、支付宝网关、RSA密钥(要自己生成)就是我们java要用到的。生成密钥方法:
- 下载支付宝开放平台开发助手

- 点击左侧栏的生成密钥栏

- 再回到点击开发者中心的沙箱应用设置RSA密钥
  • 沙箱环境中,加签模式选择公钥,然后将工具生成的公钥复制进来,点击保存设置
  • 点保存设置后,会生成一个支付宝公钥(要用到的)
5.编写工具类:
package com.lxf.utils;

import java.io.FileWriter;
import java.io.IOException;

/* *
 *类名:AlipayConfig
 *功能:基础配置类
 *详细:设置帐户有关信息及返回路径
 *修改日期:2017-04-05
 *说明:
 *以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
 */

public class AlipayConfig {
	
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

	// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
	public static String app_id = "{您的APPID}";
	
	// 商户私钥,您的PKCS8格式RSA2私钥									 	
    public static String merchant_private_key = "{商户私钥}";
	
	// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public static String alipay_public_key = "{支付宝公钥}";

	// 服务器退款异步通知页面路径  需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String notify_url = "http://localhost:8080/TrainDemo/buyticket?method=refundSuccess";

	// 支付页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
	public static String return_url = "http://localhost:8080/TrainDemo/buyticket?method=buySuccess";
	

	// 签名方式
	public static String sign_type = "RSA2";
	
	// 字符编码格式
	public static String charset = "utf-8";
	
	// 支付宝网关
	public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";
	
	// 日志生成地址
	public static String log_path = "D:\\";


//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

    /** 
     * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
     * @param sWord 要写入日志里的文本内容
     */
    public static void logResult(String sWord) {
        FileWriter writer = null;
        try {

            writer = new FileWriter(log_path + "alipay_log.txt");
            writer.write(sWord);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
6.支付跳转页面

注意:从你自己支付界面post传入商户订单号、付款金额(必填)、订单名称(必填)、商品描述(可空),以键值对形式传入,key分别为:WIDout_trade_no、WIDtotal_amount、WIDsubject、WIDbody。然后就由支付宝处理了,处理完再返回配置类配置的return_url地址

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>付款</title>
</head>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ page import="com.lxf.utils.*"%>
<%@ page import="com.alipay.api.*"%>
<%@ page import="com.alipay.api.request.*"%>
<%
	//获得初始化的AlipayClient
	AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
	
	//设置请求参数
	AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
	alipayRequest.setReturnUrl(AlipayConfig.return_url);
	alipayRequest.setNotifyUrl(AlipayConfig.notify_url);
	
	//商户订单号,商户网站订单系统中唯一订单号,必填
	String out_trade_no = new String(request.getParameter("WIDout_trade_no").getBytes("ISO-8859-1"),"UTF-8");
	//付款金额,必填
	String total_amount = new String(request.getParameter("WIDtotal_amount").getBytes("ISO-8859-1"),"UTF-8");
	//订单名称,必填
	String subject = new String(request.getParameter("WIDsubject").getBytes("ISO-8859-1"),"UTF-8");
	//商品描述,可空
	String body = new String(request.getParameter("WIDbody").getBytes("ISO-8859-1"),"UTF-8");
	
	alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," 
			+ "\"total_amount\":\""+ total_amount +"\"," 
			+ "\"subject\":\""+ subject +"\"," 
			+ "\"body\":\""+ body +"\"," 
			+ "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
	
	
	//请求
	String result = alipayClient.pageExecute(alipayRequest).getBody();
	
	//输出
	out.println(result);
%>
<body>
</body>
</html>
7.测试(支付)**
//购票或抢票按钮
function tBuy(ticketPM){
	//判断是抢票还是买票
	if(ticketPM.remain_tickets==0){
		//抢票
		$.confirm({
			title: '抢票提示',
			content: "确定用该乘车人信息抢购此车票吗?",
			type: 'orange',
			typeAnimated: true,
			buttons: {
				omg: {
					text: '确定',
					btnClass: 'btn-orange',
					action:function(){
						lightyear.loading('show');
						$.ajax({
							url:'buyticket',
							type:'post',
							data:{
								method:'ticketBuy',
								p_id:passengerInfor.passenger_id,
								ticketPM:JSON.stringify(ticketPM).replace(/\"/g, "'"),
								t_price:$('#t_price').text(),
								t_b_type:2
							},
							dataType:'json',
							success:function(data){
								if(data.buyCode==1){
									lightyear.notify('订单生成成功,正在跳转页面中~',"success",2000);
									setTimeout(function(){
										//alipay.trade.page.pay.jsp
										//进入支付页面
										postOpenWindow('alipay.trade.page.pay.jsp',{
										WIDout_trade_no:data.WIDout_trade_no,//商户订单号:WIDout_trade_no
										WIDsubject:utf8StrChange(data.WIDsubject+"("+ticketPM.start_station+"-"+ticketPM.end_station+")"),//订单名称:WIDsubject
										WIDtotal_amount:data.WIDtotal_amount,//付款金额:WIDtotal_amount
										WIDbody:data.WIDbody//商品描述:WIDbody
										});
									},1000);
								}else if(data.buyCode==-2){
									lightyear.notify('抢票订单中有订单未支付,请先支付!',"danger",2000);
								}else{
									lightyear.notify('订单生成失败!',"danger",2000);
								}
								lightyear.loading('hide');
							},
							error:function(){
								lightyear.notify('请求错误!',"danger",2000);
								lightyear.loading('hide');
							}
						})
					}
				},
				close: {
					text: '关闭'
				}
			}
		});
	}else if(ticketPM.remain_tickets>0){
		//买票
		$.confirm({
			title: '购票提示',
			content: "确定用该乘车人信息购买此车票吗?",
			type: 'orange',
			typeAnimated: true,
			buttons: {
				omg: {
					text: '确定',
					btnClass: 'btn-orange',
					action:function(){
						lightyear.loading('show');
						$.ajax({
							url:'buyticket',
							type:'post',
							data:{
								method:'ticketBuy',
								p_id:passengerInfor.passenger_id,
								ticketPM:JSON.stringify(ticketPM).replace(/\"/g, "'"),
								t_price:$('#t_price').text(),
								t_b_type:1
							},
							dataType:'json',
							success:function(data){
								if(data.buyCode==1){
									lightyear.notify('订单生成成功,正在跳转页面中~',"success",2000);
									setTimeout(function(){
										//alipay.trade.page.pay.jsp
										//进入支付页面
										postOpenWindow('alipay.trade.page.pay.jsp',{
										WIDout_trade_no:data.WIDout_trade_no,//商户订单号:WIDout_trade_no
										WIDsubject:utf8StrChange(data.WIDsubject+"("+ticketPM.start_station+"-"+ticketPM.end_station+")"),//订单名称:WIDsubject
										WIDtotal_amount:data.WIDtotal_amount,//付款金额:WIDtotal_amount
										WIDbody:data.WIDbody//商品描述:WIDbody
										});
									},1000);
								}else if(data.buyCode==-2){
									lightyear.notify('购票订单中有订单未支付,请先支付!',"danger",2000);
								}else{
									lightyear.notify('订单生成失败!',"danger",2000);
								}
								lightyear.loading('hide');
							},
							error:function(){
								lightyear.notify('请求错误!',"danger",2000);
								lightyear.loading('hide');
							}
						})
					}
				},
				close: {
					text: '关闭'
				}
			}
		});
	}else{
		lightyear.notify('余票数量错误!',"danger",2000);
		lightyear.loading('hide');
	}
}
//将字符串的格式转换成utf-8格式
function utf8StrChange(str) {
    return eval('\''+encodeURI(str).replace(/%/gm, '\\x')+'\'');
}
/**
* 以post方式打开另一个新页面 
*/
function postOpenWindow(URL, PARAMS) { 
		var temp_form = document.createElement("form");
		temp_form.action = URL;
		temp_form.target = "_blank";
		temp_form.method = "post";
		temp_form.style.display = "none"; 
		for (var x in PARAMS) { 
		var opt = document.createElement("textarea");
		opt.name = x;
		opt.value = PARAMS[x];
		temp_form .appendChild(opt);
		}
		document.body.appendChild(temp_form);
		temp_form.submit();
}

java支付回调类:

/**
	 * 购票成功返回的界面 成功就修改该订单状态
	 * 
	 * @param request
	 * @param response
	 */
	private void buySuccess(HttpServletRequest request, HttpServletResponse response) {
		// 返回的url和它的参数值:
        // localhost:8080/20200401-aliyun/return_url.jsp?
		// charset=utf-8
		// &out_trade_no=202071217331586
		// &method=alipay.trade.page.pay.return
		// &total_amount=90.00
		// &sign=Pv5BuwOKB2qgm9diKSpR8CylDRE1O1kN2RXkBKRF89YM9RCLR8CtC61J4JzqBKyr6ZbFBNrvVBuhhFOvdVV8kf10UcPcYn93j4mBWwUpH90s%2FNPOM0bc%2F4TpeSy0BYSjm65NNN07e7lPmhSEyJvkj%2BqwPk06KQ3hCvoS1plrZMKO%2FvrqG%2BkKsM7gpko75KK1cuiuIjDhC7yX8EUH5NT2KTabYzUnpSqUrLIyT8EhDx28leKniUJj2T8P%2FtjmsOITFjWHz%2BwbA7kmf7jEFU4y3Tixz%2B6YmctTUMbceOXezAHk6OOeJMfVkw4v4pIMd%2B4OGPVDGZMybtA4jH9dxdvJ3A%3D%3D
		// &trade_no=2020071222001403360500790878
		// &auth_app_id=2016102300745988
		// &version=1.0
		// &app_id=2016102300745988
		// &sign_type=RSA2
		// &seller_id=2088102180784973
		// 时间戳: ×tamp=2020-07-12+17%3A33%3A47
		// 支付宝交易号:trade_no

		// 商户订单号
		String out_trade_no = request.getParameter("out_trade_no");
		// 付款金额
		String total_amount = request.getParameter("out_trade_no");
		if (total_amount != null) {
			if (!total_amount.equals("")) {
				lxfService.addTotalMonery(Double.valueOf(total_amount));
			}
		}
		// 查询购买类型:抢购或者购买
		int t_type = lxfService.queryTicketBuyType(out_trade_no);
		int i = 0;// 购票更新情况
		int j = 0;// 抢票更新情况
		try {
			if (t_type == 1) {
				// 如果订单编号不为空,直接将订单状态改为已支付
				if (out_trade_no != null && !out_trade_no.equals("")) {
					i = lxfService.ChangeBuyStatus(out_trade_no);
				}
				if (i > 0) {
					// 更新成功
					request.setAttribute("buyCode", 1);
				} else {
					// 更新失败
					request.setAttribute("buyCode", -1);
				}
				// 购买成功-->跳到火车票订单界面
				request.getRequestDispatcher("personalCenter-traTicetOrder.jsp").forward(request, response);
			} else if (t_type == 2) {
				if (out_trade_no != null && !out_trade_no.equals("")) {
					j = lxfService.ChangeGrabStatus((User) request.getSession().getAttribute("user"), out_trade_no);
				}
				if (j > 0) {
					// 更新成功
					request.setAttribute("grabCode", 1);
				} else {
					// 更新失败
					request.setAttribute("grabCode", -1);
				}
				// 抢票成功-->跳到本人车票界面
				request.getRequestDispatcher("personalCenter-alternateOrder.jsp").forward(request, response);
			} else {
				// 其它情况,重定向到首页
				response.sendRedirect("HuGongRailwayIndex.jsp");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
8.测试(退款)

注意:从你自己退款界面post传入商户订单号或支付宝交易号(二选一)、需要退款的金额(必填)、退款的原因说明、标识一次退款请求,以键值对形式传入,key分别为:WIDTRout_trade_no,WIDTRtrade_no,WIDTRrefund_amount,WIDTRrefund_reason,WIDTRout_request_no。然后就由支付宝处理了,处理完再返回配置类配置的notify_url地址

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>退款</title>
</head>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ page import="com.zking.alipay.config.*"%>
<%@ page import="com.alipay.api.*"%>
<%@ page import="com.alipay.api.request.*"%>
<%
	//获得初始化的AlipayClient
	AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
	
	//设置请求参数
	AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
	
	//商户订单号,商户网站订单系统中唯一订单号
	String out_trade_no = new String(request.getParameter("WIDTRout_trade_no").getBytes("ISO-8859-1"),"UTF-8");
	//支付宝交易号
	String trade_no = new String(request.getParameter("WIDTRtrade_no").getBytes("ISO-8859-1"),"UTF-8");
	//请二选一设置
	//需要退款的金额,该金额不能大于订单金额,必填
	String refund_amount = new String(request.getParameter("WIDTRrefund_amount").getBytes("ISO-8859-1"),"UTF-8");
	//退款的原因说明
	String refund_reason = new String(request.getParameter("WIDTRrefund_reason").getBytes("ISO-8859-1"),"UTF-8");
	//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传
	String out_request_no = new String(request.getParameter("WIDTRout_request_no").getBytes("ISO-8859-1"),"UTF-8");
	
	alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\"," 
			+ "\"trade_no\":\""+ trade_no +"\"," 
			+ "\"refund_amount\":\""+ refund_amount +"\"," 
			+ "\"refund_reason\":\""+ refund_reason +"\"," 
			+ "\"out_request_no\":\""+ out_request_no +"\"}");
	
	//请求
	String result = alipayClient.execute(alipayRequest).getBody();
	
	//输出
	out.println(result);
%>
<body>
</body>
</html>

java退款回调类:

/* 
	实际验证过程建议商户务必添加以下校验:
	1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
	2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
	3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
	4、验证app_id是否为该商户本身。
	*/
	private void refundSuccess(HttpServletRequest request, HttpServletResponse response) 	{
		boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名

	//——请在这里编写您的程序(以下代码仅作参考)——
	
	/* 实际验证过程建议商户务必添加以下校验:
	1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
	2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
	3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email)
	4、验证app_id是否为该商户本身。
	*/
	if(signVerified) {//验证成功
		//商户订单号
		String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
	
		//支付宝交易号
		String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
	
		//交易状态
		String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
		
		if(trade_status.equals("TRADE_FINISHED")){
			//判断该笔订单是否在商户网站中已经做过处理
			//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
			//如果有做过处理,不执行商户的业务程序
				
			//注意:
			//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
		}else if (trade_status.equals("TRADE_SUCCESS")){
			//判断该笔订单是否在商户网站中已经做过处理
			//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
			//如果有做过处理,不执行商户的业务程序
			
			//注意:
			//付款完成后,支付宝系统发送该交易状态通知
		}
		
		out.println("success");
		
	}else {//验证失败
		out.println("fail");
	
		//调试用,写文本函数记录程序运行情况是否正常
		//String sWord = AlipaySignature.getSignCheckContentV1(params);
		//AlipayConfig.logResult(sWord);
	}
	
			
	}