JAVAEE网上商城项目总结
发送邮件实现(使用QQ邮箱发送到指定邮箱)
需要的jar
邮件发送类代码:
package util; import java.util.Properties; import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
//用于发送邮件
public class MailUtils { public static void sendMail(String email, String emailMsg)
throws AddressException, MessagingException {
// 1.创建一个程序与邮件服务器会话对象 Session Properties props = new Properties();
props.setProperty("mail.transport.protocol", "SMTP");//邮件发送协议
props.setProperty("mail.host", "smtp.qq.com");//使用哪个邮件服务器进行邮件的发送
props.setProperty("mail.smtp.auth", "true");// 指定验证为true
//props.setProperty("mail.smtp.port","465");
props.setProperty("mail.smtp.ssl.enable","true"); // 创建验证器
Authenticator auth = new Authenticator() {
public PasswordAuthentication getPasswordAuthentication() {
//第一个参数是发送人账户,第二个是授权码(需要在邮箱中开启POP3/SMTP服务 然后获得
return new PasswordAuthentication("1085974196", "lzwzaasabwqxgaai");
}
}; Session session = Session.getInstance(props, auth); // 2.创建一个Message,它相当于是邮件内容
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("1085974196@qq.com")); // 设置发送者
System.out.println("发送的目标地址是:"+email);
message.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者 message.setSubject("好易购商城注册-用户激活");
// message.setText("这是一封激活邮件,请<a href='#'>点击</a>"); message.setContent(emailMsg, "text/html;charset=utf-8"); // 3.创建 Transport用于将邮件发送 Transport.send(message);
}
}
发送邮件时直接调用该方法,并且传递目标地址参数以及发送的内容
-------------------------------
随机码:
单元测试,打印:
调用获得(static类型,直接通过类名称进行调用):
---------------------------
短信验证码的发送(这里使用云片短息服务平台)
导入jar
通过ajax异步操作,在用户滑动滑块的时候向指定action中传递在表单中获得的电话号码
//TODO
//********发送手机验证码使用Ajax 跳入action 执行指定方法 在action中调用第三方平台 发送短信*******
$.post(
"/shop/SendSMS.action",
{"phone":$("#phone").val()}
);
跳到指定的action中,发送验证码之后不需要任何跳转,如下代码:
package util; import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionSupport;
//在滑动滑块之后,调用js代码,通过异步的方式进入该action 进行验证码的发送 通过第三方平台的支持(这里使用云片短信服务)
public class SendSMSAction extends ActionSupport {
//智能匹配模版发送接口的http地址
private static String URI_SEND_SMS = "https://sms.yunpian.com/v2/sms/single_send.json"; //编码格式。发送编码格式统一用UTF-8
private static String ENCODING = "UTF-8"; public String execute()throws Exception{
System.out.println("进入发送验证码action,通过第三方平台");
//获取手机号码
String phone = ServletActionContext.getRequest().getParameter("phone");
//获取src下的sms.properties文件
ResourceBundle rb = ResourceBundle.getBundle("sms");
//获得第三方短信平台 给与标识
String apikey = rb.getString("apiKey");
//对手机号进行编码
String mobile = URLEncoder.encode(phone,ENCODING);
//产生随机的验证码
String smsCode = (""+Math.random()*1000000).substring(0,6);
//拼接短信信息 必须使用云片服务平台审核通过的模板和签名 不然无法完成发送
String text ="【好易购】欢迎您注册,您的验证码是"+smsCode+"。如非本人操作,请忽略本短信";
System.out.println(text); //短信发送
String sendSms = sendSms(apikey, text, mobile);
//将验证码存到session域中
ServletActionContext.getRequest().getSession().setAttribute("smsCode", smsCode); System.out.println("发送验证码action执行完毕,验证码已经发送。"); return NONE;
}
/**
* 智能匹配模版接口发短信
*
* @param apikey apikey
* @param text 短信内容
* @param mobile 接受的手机号
* @return json格式字符串
* @throws IOException
*/ public String sendSms(String apikey, String text, String mobile) throws IOException {
Map<String, String> params = new HashMap<String, String>();
params.put("apikey", apikey);
params.put("text", text);
params.put("mobile", mobile);
return post(URI_SEND_SMS, params);
} /**
* 基于HttpClient 4.3的通用POST方法
*
* @param url 提交的URL
* @param paramsMap 提交<参数,值>Map
* @return 提交响应
*/ public String post(String url, Map<String, String> paramsMap) {
CloseableHttpClient client = HttpClients.createDefault();
String responseText = "";
CloseableHttpResponse response = null;
try {
HttpPost method = new HttpPost(url);
if (paramsMap != null) {
List<NameValuePair> paramList = new ArrayList<NameValuePair>();
for (Map.Entry<String, String> param : paramsMap.entrySet()) {
NameValuePair pair = new BasicNameValuePair(param.getKey(), param.getValue());
paramList.add(pair);
}
method.setEntity(new UrlEncodedFormEntity(paramList, ENCODING));
}
response = client.execute(method);
HttpEntity entity = response.getEntity();
if (entity != null) {
responseText = EntityUtils.toString(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return responseText;
} }
上面需要注意的是,使用短信服务,需要注册一个短信服务平台,这里使用云片短信服务平台
就是上面这个apikey(注册免费送10条,用完的话你可以花50大洋,购买1000条短信服务)
然后表单中输入正确的验证码,既可以完成注册
------------------------------
MD5加密
package util; import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import org.junit.Test; public class MD5Utils {
/**
* 使用md5的算法进行加密
*/
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
@Test
public void test(){
System.out.println(md5("12345"));
}
}
单元测试结果:
827ccb0eea8a706c4c34a16891f84e7b
通过类.方法名 直接调用类中的静态方法
-------------------------------------------------------------------------------
jquery焦点事件,判断用户输入的手机号是否已经注册
(表单失去焦点之后,通过post异步方式,把手机号提交给相应action,然后做判断,并把后端数据,传给前端)
jsp页面:
<div id="phonecheck"> </div>
<div class="cell">
<input id="phone" type="text" value="${user.username }" placeholder="请输入手机号码" name="username" id="js-mobile_ipt" class="text" maxlength="11" /> </div>
<script type="text/javascript">
$('#phone').blur(function(){//使用post异步方式进行手机检查 是否注册过了
//先检查位数是否为11位 如果是那么就进行异步判断
var pattern=/1[0-9]{10}/;
var phone=$('#phone').val();
var flag=pattern.test(phone); if(flag){//位数是正确的
$.post(
"/shop/UserAction_check.action",//url
{"phone":$("#phone").val()},//value 如果多个参数,中间使用逗号分隔
function(data){//回调函数 data就是后端返回的数据
//data是action中返回的数据checkresult
// ServletActionContext.getResponse().getWriter().write(checkresult); if(data=="true"){// 可以使用
$("#phonecheck").html("可以的使用手机号!").css("color","#76bf48");
}else{//不能使用
$("#phonecheck").html("对不起,该手机号已经注册,如忘记密码,可以找回!").css("color","red");
//号码已经注册,不能继续使用,所以把表单中的内容清空,让用户重新输入号码
$("#phone").val("");
}
} );
}else{//位数不正确 $("#phonecheck").html("手机号格式不正确!").css("color","red");
//格式不正确,清空表单中的手机号码,让用户重新输入
$("#phone").val("");
} });
</script>
传给后台多个参数(参数名 加不加引号都无所谓)
struts.xml
action中代码:
//检查手机号是否已经注册了 并把查询结果按照字符串的方式传递到前端 在ajax回调函数获取
public void check(){
String phone=ServletActionContext.getRequest().getParameter("phone");
String checkresult=null;
if(!userService.check(phone)){
checkresult="false";
}else{
checkresult="true";
}
try {
ServletActionContext.getResponse().setCharacterEncoding("utf-8");//设置字符编码
ServletActionContext.getResponse().getWriter().write(checkresult);//把传递的内容传递到前端 在回调函数中可以获得
} catch (IOException e) {
e.printStackTrace();
}
}
ServletActionContext.getResponse().getWriter().write(checkresult);//把传递的内容传递到前端 在回调函数中可以获得
运行效果:
--------------------------------------------------------
动态设置标签的id值,并且单击该标签之后,获得设置的id
------------------------------------------------------
点击button,跳转到后台action
----------------------------------
巧妙设置id
先看下面的截图:
使用例子:
<c:forEach items="${listCart }" var="entry" varStatus="vs"> <tr id="product1" class="${entry.product.pid}" style="height:150px">
<td class="cart_td_1" width="5%"><input name="cartCheckBox" type="checkbox" value="product1" onclick="selectSingle()" /></td>
<td class="cart_td_2" width="18%"><img src="${pageContext.request.contextPath }/${entry.product.pimage}" alt="shopping"/></td>
<td class="cart_td_3" width="33%"><a href="#">${entry.product.pname}</a><br />
颜色:棕色 尺码:37<br />
保障:<img src="data:images/taobao_icon_01.jpg" alt="icon" /></td>
<td class="cart_td_4" width="5%">5</td>
<td class="cart_td_5" width="10%">${entry.product.shop_price}</td>
<td class="cart_td_6" width="10%">
<img src="data:images/taobao_minus.jpg" alt="minus" onclick="changeNum('num_${vs.count}','minus','${entry.product.pid}','${sessionScope.user.uid}')" class="hand"/>
<input id="num_${vs.count }" type="text" value="${entry.number}" class="num_input" readonly="readonly"/>
<img src="data:images/taobao_adding.jpg" alt="add" onclick="changeNum('num_${vs.count}','add','${entry.product.pid}','${sessionScope.user.uid}')" class="hand"/>
</td>
<td class="cart_td_7" width="10"></td>
<!-- <td class="cart_td_8" width="10"><a href="javascript:deleteRow('product1');">删除</a></td> -->
<td class="cart_td_8" width="10"><a id="${entry.product.pid}" onclick="GetPid(this)">删除</a></td>
</tr> </c:forEach>
js代码:
//购物车计算
function changeNum(numId,flag,pid,uid){
var numId=document.getElementById(numId);
if(flag=="minus"){
if(numId.value<=1){
//alert("商品不能小于一件");
win.alert("好易购-商品数量警告", "商品不能小于一件!");
return false;
}
else{
//发送ajax减少购物车中的商品数量
$.post(
"${pageContext.request.contextPath}/CartAction_changeNumber",
{"product.pid":pid,"flag":flag,"user.uid":uid},
function(data){
if(data=="UpdateSuccess"){
numId.value=parseInt(numId.value)-1;//点击减号 页面上的数值-1 虽然数据库改变了 但是不刷新页面该值是不会变化的 所以就在更新数据之后 直接改变页面上的显示值
productCount();//调整数量之后,执行该函数把订单总价改变
}
}
);
}
}else{
//发送ajax添加购物车中的商品数量
$.post(
"${pageContext.request.contextPath}/CartAction_changeNumber",
{"product.pid":pid,"flag":flag,"user.uid":uid},
function(data){
if(data=="UpdateSuccess"){
numId.value=parseInt(numId.value)+1;
productCount();//调整数量之后,执行该函数把订单总价改变
}
}
);
}
}
首先需要明确 ,无论遍历了多少个对象,'num_${vs.count}'的值在某一行上的值是固定的
比如遍历出的第一行数据,它的
<input id="num_${vs.count }" type="text" value="${entry.number}" class="num_input" readonly="readonly"/>
该行的id永远为1,而且
<img src="data:images/taobao_minus.jpg" alt="minus" onclick="changeNum('num_${vs.count}','minus','${entry.product.pid}','${sessionScope.user.uid}')" class="hand"/>
<img src="data:images/taobao_adding.jpg" alt="add" onclick="changeNum('num_${vs.count}','add','${entry.product.pid}','${sessionScope.user.uid}')" class="hand"/>
在单击之后,会调用changeNum函数,传递的第一个参数也是1,这三行的vs。count永远是保持一致的
遍历出的页面
上面的三条语句在页面的显示效果就是图中的三个标记,一个+,一个-,还有一c个就是input
使用varStatus属性就是为了保证在单击每一行的时候,在js中获得的input表单对象
【
var numId=document.getElementById(numId);
】
为当前点击的这一行。
比如单击第一行的时候(单击 - 号),调用函数,并且传递了参数给该函数,参数此时如下
changeNum(numId,flag,pid,uid)
changeNum('1','minus',xx,xx)
执行该代码:
var numId=document.getElementById(numId); numId的值为1,相当于:
var numId=document.getElementById(1);
因为单击的是第一行,所以
<input id="num_${vs.count }" type="text" value="${entry.number}" class="num_input" readonly="readonly"/>
这里的id的值就是1,所以单击某一行时,获得的表单对象正好就是当前 “单击行” 的input
通过这个例子,还可以知道,onclick函数中传递参数的格式,并且还可以传递动态参数
<img src="data:images/taobao_minus.jpg" alt="minus" onclick="changeNum('num_${vs.count}','minus','${entry.product.pid}','${sessionScope.user.uid}')" class="hand"/>
鼠标移到button或者超链接上,没有变手型指针,那么在该标签中加入style="cursor: pointer"属性 即可完成变化,比如
<td class="cart_td_8" width="10"><a id="${entry.product.pid}" onclick="GetPid(this)">删除</a></td>
中没有href=“”属性,那么鼠标移到上边就不会变成小手的形状
---------------------------------------------------------------
使用El表达式在遍历中实现累加的功能
代码实践:
<c:set var="count" value="0.0"></c:set>
<c:forEach items="${listCart }" var="entry">
<dd class="item clearfix">
<div class="item-row">
<div class="col col-1">
<div class="g-pic">
<img src="${pageContext.request.contextPath }/${entry.product.pimage}" width="40" height="40" />
</div>
<div class="g-info">
${entry.product.pname}
</div>
</div> <div class="col col-2">${entry.univalence}元</div>
<div class="col col-3">${entry.number}</div>
<div class="col col-4">${entry.subtotal}元</div>
</div>
</dd>
<c:set var="count" value="${count+entry.subtotal }"></c:set>
</c:forEach>
运行效果:
--------------------------------------------
js传递数组给后台(一)
代码实践
var s=["1","2"];
location.href="${pageContext.request.contextPath}/OrderAction_ensure.action?s="+s;
String[] array = ServletActionContext.getRequest().getParameterValues("s");
for (String string : array) {
System.out.println(string);
}
输出结果:
--------------------------------------
js传递数组给后台(二)-------动态传递(数组内容动态设置)
复选框中的value是当前循环商品的商品id
提交,调用js代码:
在js中完成数据的设置,然后传递给action
循环输出:
或者:
打印结果:
需要注意的是,这个循环只循环了一次,为什么呢,因为从前端得到的数据是一个字符数组,而且所有的数据全部在下标为0的地方,即arrty[0]="21,49,36"
所以要想使用这些数据,还需要进一步转化,把他编程一个一个数字,放在list集合中
//得到前端传递过来的数据
String[] pidstr = ServletActionContext.getRequest().getParameterValues("s");
//获得字符串
String str=pidstr[0];
//把字符串转换为字符数组
String[] pidstring=new String[]{};//创建字符数组
pidstring=str.split(",");//把str字符串按分号进行分割 把分割得到每一个部分存入字符串数组中
//需要把字符串数组转换成list数组
List pidList=Arrays.asList(pidstring);
然后对list集合就可以方便的进行遍历,取出其中的每一个值了
-----------------------------------------
时间格式化
-------------
------------------------------------------------------------------------
接入第三方支付平台,完成真正的支付
支付平台(当然像淘宝,京东这样的大公司都有自己的支付平台):
1.易宝支付
2.连连支付
3.国付宝
支付流程:
接入的时候是需要企业级资质的
注册之后 获得一个key=账号(区别不同的企业,将来转账的RMB都将流向该企业注册时填写的账号上) 以及value=秘钥(用于加密对比 防止数据被篡改)
这个key和value是可以使用的
订单提交之后,选择在线支付
选择对应银行之后,点击下一步:提交表单
银行标识发送给目标action,完成数据的封装准备,以及数据的加密
下面看该action中的代码:
package util;
import java.util.ResourceBundle;
import org.apache.struts2.ServletActionContext;
import org.model.Orders;
import com.opensymphony.xwork2.ActionSupport;
//支付action 通过第三方平台的支持(这里使用易宝支付,当然需要外网)
public class PayOrderAction extends ActionSupport {
public String execute()throws Exception{
System.out.println("进入支付action");
// 获得 支付必须基本数据
Orders orders=(Orders) ServletActionContext.getRequest().getSession().getAttribute("Orders");
String orderid = orders.getOid();//获得订单编号
//String money =orders.getTotal()+"";//获得订单总额 即支付的金额
//这里做模拟 支付0.01元
String money="0.01"; //获得银行标识 即选择的是哪一个银行进行支付
String pd_FrpId =ServletActionContext.getRequest().getParameter("pd_FrpId"); // 发给支付公司(易宝支付平台 )需要哪些数据
String p0_Cmd = "Buy";
//获得项目src下 merchantInfo.properties文件中 key="p1_MerId"对应的值 即获取企业账户p1_MerId=10001126856
//将来交易的金额 流向了该账户的银行卡中(企业注册使用平台服务的时候 肯定预留的有银行卡账号 平台返给企业一个账号 用于区别不同的企业)
String p1_MerId = ResourceBundle.getBundle("merchantInfo").getString("p1_MerId");
String p2_Order = orderid;
String p3_Amt = money;
String p4_Cur = "CNY";
String p5_Pid = "";
String p6_Pcat = "";
String p7_Pdesc = "";//必须要填写的字段使用""代替
// 支付成功回调地址 ---- 第三方支付公司会访问、用户访问
// 第三方支付可以访问网址
String p8_Url = ResourceBundle.getBundle("merchantInfo").getString("callback");
String p9_SAF = "";
String pa_MP = "";
String pr_NeedResponse = "1";
// 加密hmac 需要密钥 merchantInfo.properties文件中获取key="keyValue"对应的值
String keyValue = ResourceBundle.getBundle("merchantInfo").getString(
"keyValue");
//PaymentUtil.buildHmac第三平台提供的加密方法
//在支付平台把传递过去的【A部分.明文数据】也做加密 与hmac【B部分.加密之后的密文】做对比 防止数据被篡改
String hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt,
p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP,
pd_FrpId, pr_NeedResponse, keyValue);
// 把数据进行保存在request域中 跳到confirm.jsp中进行确认 然后提交 提交的地址
//https://www.yeepay.com/app-merchant-proxy/node 是第三方支付平台 携带的数据 就是下面封装的
//数据,想要完成支付首先需要连接外网 因为这个地址目标不是本地上的页面
/*
//A部分.明文数据
ServletActionContext.getRequest().setAttribute("pd_FrpId", pd_FrpId);
ServletActionContext.getRequest().setAttribute("p0_Cmd", p0_Cmd);
ServletActionContext.getRequest().setAttribute("p1_MerId", p1_MerId);
ServletActionContext.getRequest().setAttribute("p2_Order", p2_Order);
ServletActionContext.getRequest().setAttribute("p3_Amt", p3_Amt);
ServletActionContext.getRequest().setAttribute("p4_Cur", p4_Cur);
ServletActionContext.getRequest().setAttribute("p5_Pid", p5_Pid);
ServletActionContext.getRequest().setAttribute("p6_Pcat", p6_Pcat);
ServletActionContext.getRequest().setAttribute("p7_Pdesc", p7_Pdesc);
ServletActionContext.getRequest().setAttribute("p8_Url", p8_Url);
ServletActionContext.getRequest().setAttribute("p9_SAF", p9_SAF);
ServletActionContext.getRequest().setAttribute("pa_MP", pa_MP);
ServletActionContext.getRequest().setAttribute("pr_NeedResponse", pr_NeedResponse);
//B部分.加密之后的密文
ServletActionContext.getRequest().setAttribute("hmac", hmac);
//跳转页面
ServletActionContext.getRequest().getRequestDispatcher("/confirm.jsp").forward(ServletActionContext.getRequest(),ServletActionContext.getResponse());
*/
//第三方支付平台(易宝支付)url 并且携带支付数据 直接跳到该地址 删除中间页confirm.jsp
String ThirdpartyUrl="https://www.yeepay.com/app-merchant-proxy/node?pd_FrpId="+pd_FrpId
+"&p0_Cmd="+p0_Cmd
+"&p1_MerId="+p1_MerId
+"&p2_Order="+p2_Order
+"&p3_Amt="+p3_Amt
+"&p4_Cur="+p4_Cur
+"&p5_Pid="+p5_Pid
+"&p6_Pcat="+p6_Pcat
+"&p7_Pdesc="+p7_Pdesc
+"&p8_Url="+p8_Url
+"&p9_SAF="+p9_SAF
+"&pa_MP="+pa_MP
+"&pr_NeedResponse="+pr_NeedResponse
+"&hmac="+hmac;
//重定向到第三方支付平台 然后根据传递的数据 链接到对应银行支付页面
ServletActionContext.getResponse().sendRedirect(ThirdpartyUrl);
return NONE;
} }
PaymentUtil.buildHmac是第三平台提供的加密算法工具类
package util; import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
//支付过程中需要对传递的数据进行加密 这是第三方支付平台给的加密代码 直接使用即可
public class PaymentUtil { private static String encodingCharset = "UTF-8"; /**
* 生成hmac方法
*
* @param p0_Cmd 业务类型
* @param p1_MerId 商户编号
* @param p2_Order 商户订单号
* @param p3_Amt 支付金额
* @param p4_Cur 交易币种
* @param p5_Pid 商品名称
* @param p6_Pcat 商品种类
* @param p7_Pdesc 商品描述
* @param p8_Url 商户接收支付成功数据的地址
* @param p9_SAF 送货地址
* @param pa_MP 商户扩展信息
* @param pd_FrpId 银行编码
* @param pr_NeedResponse 应答机制
* @param keyValue 商户密钥
* @return
*/
public static String buildHmac(String p0_Cmd,String p1_MerId,
String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat,
String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId,
String pr_NeedResponse,String keyValue) {
StringBuilder sValue = new StringBuilder();
// 业务类型
sValue.append(p0_Cmd);
// 商户编号
sValue.append(p1_MerId);
// 商户订单号
sValue.append(p2_Order);
// 支付金额
sValue.append(p3_Amt);
// 交易币种
sValue.append(p4_Cur);
// 商品名称
sValue.append(p5_Pid);
// 商品种类
sValue.append(p6_Pcat);
// 商品描述
sValue.append(p7_Pdesc);
// 商户接收支付成功数据的地址
sValue.append(p8_Url);
// 送货地址
sValue.append(p9_SAF);
// 商户扩展信息
sValue.append(pa_MP);
// 银行编码
sValue.append(pd_FrpId);
// 应答机制
sValue.append(pr_NeedResponse); return PaymentUtil.hmacSign(sValue.toString(), keyValue);
} /**
* 返回校验hmac方法
*
* @param hmac 支付网关发来的加密验证码
* @param p1_MerId 商户编号
* @param r0_Cmd 业务类型
* @param r1_Code 支付结果
* @param r2_TrxId 易宝支付交易流水号
* @param r3_Amt 支付金额
* @param r4_Cur 交易币种
* @param r5_Pid 商品名称
* @param r6_Order 商户订单号
* @param r7_Uid 易宝支付会员ID
* @param r8_MP 商户扩展信息
* @param r9_BType 交易结果返回类型
* @param keyValue 密钥
* @return
*/
public static boolean verifyCallback(String hmac, String p1_MerId,
String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt,
String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid,
String r8_MP, String r9_BType, String keyValue) {
StringBuilder sValue = new StringBuilder();
// 商户编号
sValue.append(p1_MerId);
// 业务类型
sValue.append(r0_Cmd);
// 支付结果
sValue.append(r1_Code);
// 易宝支付交易流水号
sValue.append(r2_TrxId);
// 支付金额
sValue.append(r3_Amt);
// 交易币种
sValue.append(r4_Cur);
// 商品名称
sValue.append(r5_Pid);
// 商户订单号
sValue.append(r6_Order);
// 易宝支付会员ID
sValue.append(r7_Uid);
// 商户扩展信息
sValue.append(r8_MP);
// 交易结果返回类型
sValue.append(r9_BType);
String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);
return sNewString.equals(hmac);
} /**
* @param aValue
* @param aKey
* @return
*/
public static String hmacSign(String aValue, String aKey) {
byte k_ipad[] = new byte[64];
byte k_opad[] = new byte[64];
byte keyb[];
byte value[];
try {
keyb = aKey.getBytes(encodingCharset);
value = aValue.getBytes(encodingCharset);
} catch (UnsupportedEncodingException e) {
keyb = aKey.getBytes();
value = aValue.getBytes();
} Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);
Arrays.fill(k_opad, keyb.length, 64, (byte) 92);
for (int i = 0; i < keyb.length; i++) {
k_ipad[i] = (byte) (keyb[i] ^ 0x36);
k_opad[i] = (byte) (keyb[i] ^ 0x5c);
} MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) { return null;
}
md.update(k_ipad);
md.update(value);
byte dg[] = md.digest();
md.reset();
md.update(k_opad);
md.update(dg, 0, 16);
dg = md.digest();
return toHex(dg);
} public static String toHex(byte input[]) {
if (input == null)
return null;
StringBuffer output = new StringBuffer(input.length * 2);
for (int i = 0; i < input.length; i++) {
int current = input[i] & 0xff;
if (current < 16)
output.append("0");
output.append(Integer.toString(current, 16));
} return output.toString();
} /**
*
* @param args
* @param key
* @return
*/
public static String getHmac(String[] args, String key) {
if (args == null || args.length == 0) {
return (null);
}
StringBuffer str = new StringBuffer();
for (int i = 0; i < args.length; i++) {
str.append(args[i]);
}
return (hmacSign(str.toString(), key));
} /**
* @param aValue
* @return
*/
public static String digest(String aValue) {
aValue = aValue.trim();
byte value[];
try {
value = aValue.getBytes(encodingCharset);
} catch (UnsupportedEncodingException e) {
value = aValue.getBytes();
}
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
return toHex(md.digest(value)); } // public static void main(String[] args) {
// System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp杩?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t"));
// }
}
点击下一步之后,跳转到支付确认页面confirm.jsp(完成数据的封装)
<!-- 确认支付form -->
<form action="https://www.yeepay.com/app-merchant-proxy/node" method="post">
<h3>订单号:${p2_Order},付款金额 :${p3_Amt }</h3>
<input type="hidden" name="pd_FrpId" value="${pd_FrpId }" />
<input type="hidden" name="p0_Cmd" value="${p0_Cmd }" />
<input type="hidden" name="p1_MerId" value="${p1_MerId }" />
<input type="hidden" name="p2_Order" value="${p2_Order }" />
<input type="hidden" name="p3_Amt" value="${p3_Amt }" />
<input type="hidden" name="p4_Cur" value="${p4_Cur }" />
<input type="hidden" name="p5_Pid" value="${p5_Pid }" />
<input type="hidden" name="p6_Pcat" value="${p6_Pcat }" />
<input type="hidden" name="p7_Pdesc" value="${p7_Pdesc }" />
<input type="hidden" name="p8_Url" value="${p8_Url }" />
<input type="hidden" name="p9_SAF" value="${p9_SAF }" />
<input type="hidden" name="pa_MP" value="${pa_MP }" />
<input type="hidden" name="pr_NeedResponse" value="${pr_NeedResponse }" />
<input type="hidden" name="hmac" value="${hmac }" />
<input type="submit" value="确认支付" />
</form>
表单提交时候,https://www.yeepay.com/app-merchant-proxy/node
这是第三方平台(易宝支付)的地址,会根据你选择的银行信息(提交数据中包含),跳转到指定银行支付页面
这是银行支付页面,然后支付成功之后会跳入回调的地址,也在提交数据中包含(支付成功,自动执行该方法,前提:必须配置好,不然回调之后,出现404,但是此时已经支付成功了)
回调地址也作为数据传递给了第三方平台
Callback就是回调地址:支付成功之后,跳入该地址:所以需要配置好
回调action(在该action中,可以完成支付成功之后需要进行的操作):
package util;
import java.util.ResourceBundle;
import org.apache.struts2.ServletActionContext;
import org.model.Orders;
import org.service.OrderService; import com.opensymphony.xwork2.ActionSupport;
//支付完成之后调用的回调方法 该action会在支付成功后 进行调用----- 支付公司(第三方平台 易宝支付) 、客户 都将调用该action
//回调地址:http://localhost:8888/shop/CallBack 需要对该action进行配置
public class PayOrderCallBackAction extends ActionSupport {
//创建orderservice 并且完成注入 在订单支付成功之后 需要调用方法 修改订单标志位
private OrderService orderService;
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
public String execute()throws Exception{
System.out.println("支付成功,(进入)执行回调action");
// 获得回调所有数据
String p1_MerId = ServletActionContext.getRequest().getParameter("p1_MerId");
String r0_Cmd = ServletActionContext.getRequest().getParameter("r0_Cmd");
String r1_Code = ServletActionContext.getRequest().getParameter("r1_Code");
String r2_TrxId = ServletActionContext.getRequest().getParameter("r2_TrxId");
String r3_Amt = ServletActionContext.getRequest().getParameter("r3_Amt");
String r4_Cur = ServletActionContext.getRequest().getParameter("r4_Cur");
String r5_Pid = ServletActionContext.getRequest().getParameter("r5_Pid");
String r6_Order = ServletActionContext.getRequest().getParameter("r6_Order");
String r7_Uid = ServletActionContext.getRequest().getParameter("r7_Uid");
String r8_MP = ServletActionContext.getRequest().getParameter("r8_MP");
String r9_BType = ServletActionContext.getRequest().getParameter("r9_BType");
String rb_BankId = ServletActionContext.getRequest().getParameter("rb_BankId");
String ro_BankOrderId = ServletActionContext.getRequest().getParameter("ro_BankOrderId");
String rp_PayDate = ServletActionContext.getRequest().getParameter("rp_PayDate");
String rq_CardNo = ServletActionContext.getRequest().getParameter("rq_CardNo");
String ru_Trxtime = ServletActionContext.getRequest().getParameter("ru_Trxtime");
// 身份校验 --- 判断是不是支付公司通知你
String hmac = ServletActionContext.getRequest().getParameter("hmac");
String keyValue = ResourceBundle.getBundle("merchantInfo").getString(
"keyValue"); // 自己对上面数据进行加密 --- 比较支付公司发过来hamc
boolean isValid = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd,
r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid,
r8_MP, r9_BType, keyValue);
if (isValid) {
/*
// 响应数据有效
if (r9_BType.equals("1")) {
// 浏览器重定向
ServletActionContext.getResponse().setContentType("text/html;charset=utf-8");
ServletActionContext.getResponse().getWriter().println("<h1>付款成功!等待商城进一步操作!等待收货...</h1>");
} else if (r9_BType.equals("2")) {
// 服务器点对点 --- 支付公司通知你
System.out.println("付款成功!");
// 修改订单状态 为已付款
// 回复支付公司
ServletActionContext.getResponse().getWriter().print("success");
}
*/
//得到session域中保存的订单信息
Orders orders=(Orders) ServletActionContext.getRequest().getSession().getAttribute("Orders");
//支付成功之后 需要激活订单 修改订单中的state字段为1 表示该订单用户已经完成支付
this.orderService.orderReactivated(orders.getOid());
//跳转到支付结果页面 给用户反馈
ServletActionContext.getRequest().getRequestDispatcher("/payresult.jsp").forward(ServletActionContext.getRequest(),ServletActionContext.getResponse());
} else {
// 数据无效
System.out.println("数据被篡改!");
} return NONE;
} }
本代码中,支付成功之后需要激活对应订单,表示用户完成该订单的支付,至orders表中对应订单的state字段为1,并且跳页给用户反馈支付成功信息
读秒之后,自动跳入反馈页面/payresult.jsp
-----------------------------------------
读取propperties文件中的内容
---------------------------------------------------------
JAVAEE网上商城项目总结的更多相关文章
- 新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial
新巴巴运动网上商城 项目 快速搭建 教程 The new babar sports online mall project quickly builds a tutorial 作者:韩梦飞沙 Auth ...
- 【SSH网上商城项目实战27】域名空间的申请和项目的部署及发布
转自:https://blog.csdn.net/wwww_com/article/details/54405355 前面陆陆续续的完成了网上商城的一些基本功能,虽然还有很多地方有待完善,但是不影响 ...
- 【SSH网上商城项目实战21】从Demo中看易宝支付的流程
转自: https://blog.csdn.net/eson_15/article/details/51447492 这一节我们先写一个简单点的Demo来测试易宝支付的流程,熟悉这个流程后, ...
- 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示
转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...
- 【SSH网上商城项目实战01】整合Struts2、Hibernate4.3和Spring4.2
转自:https://blog.csdn.net/eson_15/article/details/51277324 今天开始做一个网上商城的项目,首先从搭建环境开始,一步步整合S2SH.这篇博文主要总 ...
- 【SSH网上商城项目实战30】项目总结
转自:https://blog.csdn.net/eson_15/article/details/51479994 0. 写在前面 项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了 ...
- 【SSH网上商城项目实战25】使用java email给用户发送邮件
转自: https://blog.csdn.net/eson_15/article/details/51475046 当用户购买完商品后,我们应该向用户发送一封邮件,告诉他订单已生成之类的信息, ...
- 【SSH网上商城项目实战15】线程、定时器同步首页数据(类似于博客定期更新排名)
转自:https://blog.csdn.net/eson_15/article/details/51387378 上一节我们做完了首页UI界面,但是有个问题:如果我在后台添加了一个商品,那么我必须重 ...
- 【SSH网上商城项目实战30】项目总结(附源码下载地址)
项目基本完成了,加上这个总结,与这个项目相关的博客也写了30篇了,积少成多,写博客的过程是固化思路的一个过程,对自己很有用,同时也能帮助别人.顺便说个题外话,在学习的过程中肯定会遇到很多异常出现,我们 ...
随机推荐
- 【FastDev4Android框架开发】打造QQ6.X最新版本号側滑界面效果(三十八)
转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/50253925 本文出自:[江清清的博客] (一).前言: [好消息] ...
- UVA10862 - Connect the Cable Wires(递推 + java的大数)
UVA10862 - Connect the Cable Wires(递推 + java的大数) 题目链接 题目大意:给你n座房子位于一条直线上,然后仅仅给你一个cable service.要求每座房 ...
- Linux黑洞
1 什么是Linux黑洞 在Linux系统中,/dev/null是一个虚设的设备.俗称"Linux黑洞". 不论什么对/dev/null的写入都会成功.但数据会消失得无影无踪.没有 ...
- PHP之实现双向链表(代码篇)
<?php/** * PHP之实现双向链表 */class Hero{ public $pre=null; public $no; public $name; public $next=null ...
- Controller methods and views
https://docs.asp.net/en/latest/tutorials/first-mvc-app/controller-methods-views.html We have a good ...
- redis 学习笔记-cluster集群搭建
一.下载最新版redis 编译 目前最新版是3.0.7,下载地址:http://www.redis.io/download 编译很简单,一个make命令即可,不清楚的同学,可参考我之前的笔记: red ...
- Vue.js和Nodejs的关系
首先vue.js 是库,不是框架,不是框架,不是框架. Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据. Vue.js 的核心是一个允许你 ...
- Git Learning Part II - Working locally
file status life circle basic: modified: Examples: untracked: unmodified: modified: Git branching ...
- javascript中模块化知识总结
JavaScript 模块化开发 1. 模块化介绍 掌握模块化基本概念以及使用模块化带来的好处 当你的网站开发越来越复杂的时候,会经常遇到什么问题? 恼人的命名冲突 繁琐的文件依赖 历史上,JavaS ...
- App测试- adb monkey测试
一. 安装和配置SDK 1. 下载Android SDK并解压.如下图:(如果不存在tool和platform_tool,请点击SDK Manager在线下载和更新) 2.下载完成后,配置SDK环境变 ...