首页 > 代码库 > JAVAEE网上商城项目总结

JAVAEE网上商城项目总结

发送邮件实现(使用QQ邮箱发送到指定邮箱)

需要的jar

技术分享

邮件发送类代码:

 1 package util; 2  3 import java.util.Properties; 4  5 import javax.mail.Authenticator; 6 import javax.mail.Message; 7 import javax.mail.MessagingException; 8 import javax.mail.PasswordAuthentication; 9 import javax.mail.Session;10 import javax.mail.Transport;11 import javax.mail.internet.AddressException;12 import javax.mail.internet.InternetAddress;13 import javax.mail.internet.MimeMessage;14 import javax.mail.internet.MimeMessage.RecipientType;15 //用于发送邮件16 public class MailUtils {17 18     public static void sendMail(String email, String emailMsg)19             throws AddressException, MessagingException {20         // 1.创建一个程序与邮件服务器会话对象 Session21 22         Properties props = new Properties();23         props.setProperty("mail.transport.protocol", "SMTP");//邮件发送协议24         props.setProperty("mail.host", "smtp.qq.com");//使用哪个邮件服务器进行邮件的发送25         props.setProperty("mail.smtp.auth", "true");// 指定验证为true26         //props.setProperty("mail.smtp.port","465");27         props.setProperty("mail.smtp.ssl.enable","true");28 29         // 创建验证器30         Authenticator auth = new Authenticator() {31             public PasswordAuthentication getPasswordAuthentication() {32                 //第一个参数是发送人账户,第二个是授权码(需要在邮箱中开启POP3/SMTP服务 然后获得33                 return new PasswordAuthentication("1085974196", "lzwzaasabwqxgaai");34             }35         };36 37         Session session = Session.getInstance(props, auth);38 39         // 2.创建一个Message,它相当于是邮件内容40         Message message = new MimeMessage(session);41         message.setFrom(new InternetAddress("1085974196@qq.com")); // 设置发送者42         System.out.println("发送的目标地址是:"+email);43         message.setRecipient(RecipientType.TO, new InternetAddress(email)); // 设置发送方式与接收者44 45         message.setSubject("好易购商城注册-用户激活");46         // message.setText("这是一封激活邮件,请<a href=http://www.mamicode.com/‘#‘>点击");47 48         message.setContent(emailMsg, "text/html;charset=utf-8");49 50         // 3.创建 Transport用于将邮件发送51 52         Transport.send(message);53     }54 }

发送邮件时直接调用该方法,并且传递目标地址参数以及发送的内容

技术分享

技术分享

-------------------------------

 随机码:

技术分享

单元测试,打印:

技术分享

调用获得(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加密

 1 package util; 2  3 import java.math.BigInteger; 4 import java.security.MessageDigest; 5 import java.security.NoSuchAlgorithmException; 6  7 import org.junit.Test; 8  9 public class MD5Utils {10     /**11      * 使用md5的算法进行加密12      */13     public static String md5(String plainText) {14         byte[] secretBytes = null;15         try {16             secretBytes = MessageDigest.getInstance("md5").digest(17                     plainText.getBytes());18         } catch (NoSuchAlgorithmException e) {19             throw new RuntimeException("没有md5这个算法!");20         }21         String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字22         // 如果生成数字未满32位,需要前面补023         for (int i = 0; i < 32 - md5code.length(); i++) {24             md5code = "0" + md5code;25         }26         return md5code;27     }    28     @Test29     public void test(){30         System.out.println(md5("12345"));31     }32 }

单元测试结果:

827ccb0eea8a706c4c34a16891f84e7b

通过类.方法名 直接调用类中的静态方法

技术分享

技术分享

-------------------------------------------------------------------------------

jquery焦点事件,判断用户输入的手机号是否已经注册

(表单失去焦点之后,通过post异步方式,把手机号提交给相应action,然后做判断,并把后端数据,传给前端)

jsp页面:

 1                     <div id="phonecheck"> 2      3                     </div> 4                     <div class="cell"> 5                         <input id="phone" type="text" value="http://www.mamicode.com/${user.username }" placeholder="请输入手机号码" name="username" id="js-mobile_ipt" class="text" maxlength="11" /> 6                          7                     </div> 8                     <script type="text/javascript"> 9                         $(‘#phone‘).blur(function(){//使用post异步方式进行手机检查 是否注册过了    10                             //先检查位数是否为11位 如果是那么就进行异步判断  11                             var pattern=/1[0-9]{10}/;12                             var phone=$(‘#phone‘).val();13                             var flag=pattern.test(phone);14                 15                             if(flag){//位数是正确的16                                     $.post(17                                     "/shop/UserAction_check.action",//url18                                     {"phone":$("#phone").val()},//value 如果多个参数,中间使用逗号分隔19                                     function(data){//回调函数 data就是后端返回的数据20                                     //data是action中返回的数据checkresult 21                                     // ServletActionContext.getResponse().getWriter().write(checkresult);22                                         23                                         if(datahttp://www.mamicode.com/=="true"){// 可以使用24                                             $("#phonecheck").html("可以的使用手机号!").css("color","#76bf48");25                                         }else{//不能使用26                                             $("#phonecheck").html("对不起,该手机号已经注册,如忘记密码,可以找回!").css("color","red");27                                             //号码已经注册,不能继续使用,所以把表单中的内容清空,让用户重新输入号码28                                             $("#phone").val("");29                                         }30                                     }31                                 32                                     );33                             }else{//位数不正确34                 35                                 $("#phonecheck").html("手机号格式不正确!").css("color","red");36                                 //格式不正确,清空表单中的手机号码,让用户重新输入37                                 $("#phone").val("");38                             }39                             40                         41                         });42                     </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="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="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="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(datahttp://www.mamicode.com/=="UpdateSuccess"){                        numId.value=http://www.mamicode.com/parseInt(numId.value)-1;//点击减号 页面上的数值-1 虽然数据库改变了 但是不刷新页面该值是不会变化的  所以就在更新数据之后  直接改变页面上的显示值  "${pageContext.request.contextPath}/CartAction_changeNumber",            {"product.pid":pid,"flag":flag,"user.uid":uid},            function(data){                if(datahttp://www.mamicode.com/=="UpdateSuccess"){                    numId.value=http://www.mamicode.com/parseInt(numId.value)+1;>

 

首先需要明确 ,无论遍历了多少个对象,‘num_${vs.count}‘的值在某一行上的值是固定的
比如遍历出的第一行数据,它的
 <input id="num_${vs.count }" type="text"  value="http://www.mamicode.com/${entry.number}" class="num_input" readonly="readonly"/>
该行的id永远为1,而且
<img src="http://www.mamicode.com/images/taobao_minus.jpg" alt="minus" onclick="changeNum(‘num_${vs.count}‘,‘minus‘,‘${entry.product.pid}‘,‘${sessionScope.user.uid}‘)" class="hand"/>
<img src="http://www.mamicode.com/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="http://www.mamicode.com/${entry.number}" class="num_input" readonly="readonly"/>
这里的id的值就是1,所以单击某一行时,获得的表单对象正好就是当前 “单击行” 的input
通过这个例子,还可以知道,onclick函数中传递参数的格式,并且还可以传递动态参数
<img src="http://www.mamicode.com/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=http://www.mamicode.com/“”属性,那么鼠标移到上边就不会变成小手的形状

---------------------------------------------------------------
使用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传递数组给后台(一)
技术分享

代码实践

1         var s=["1","2"];2         location.href="http://www.mamicode.com/${pageContext.request.contextPath}/OrderAction_ensure.action?s="+s;
1         String[] array = ServletActionContext.getRequest().getParameterValues("s");2             for (String string : array) {3                 System.out.println(string);4             }

输出结果:

技术分享

--------------------------------------

js传递数组给后台(二)-------动态传递(数组内容动态设置)
复选框中的value是当前循环商品的商品id
技术分享

技术分享

提交,调用js代码:

在js中完成数据的设置,然后传递给action

技术分享

循环输出:
技术分享

 

或者:

技术分享

 

打印结果:

技术分享

 需要注意的是,这个循环只循环了一次,为什么呢,因为从前端得到的数据是一个字符数组,而且所有的数据全部在下标为0的地方,即arrty[0]="21,49,36"

所以要想使用这些数据,还需要进一步转化,把他编程一个一个数字,放在list集合中

技术分享

1         //得到前端传递过来的数据2         String[] pidstr = ServletActionContext.getRequest().getParameterValues("s");3         //获得字符串4         String str=pidstr[0];5         //把字符串转换为字符数组6         String[] pidstring=new String[]{};//创建字符数组7         pidstring=str.split(",");//把str字符串按分号进行分割 把分割得到每一个部分存入字符串数组中8         //需要把字符串数组转换成list数组  9         List pidList=Arrays.asList(pidstring);

然后对list集合就可以方便的进行遍历,取出其中的每一个值了

-----------------------------------------

时间格式化

技术分享

技术分享

-------------

技术分享

技术分享

------------------------------------------------------------------------

接入第三方支付平台,完成真正的支付

支付平台(当然像淘宝,京东这样的大公司都有自己的支付平台):

1.易宝支付

技术分享

 

2.连连支付

技术分享

3.国付宝

技术分享

 

支付流程:

技术分享

 

接入的时候是需要企业级资质的

注册之后 获得一个key=账号(区别不同的企业,将来转账的RMB都将流向该企业注册时填写的账号上) 以及value=http://www.mamicode.com/秘钥(用于加密对比 防止数据被篡改)

技术分享

这个key和value是可以使用的

订单提交之后,选择在线支付

技术分享

选择对应银行之后,点击下一步:提交表单

技术分享

银行标识发送给目标action,完成数据的封装准备,以及数据的加密

技术分享

下面看该action中的代码:

 1 package util; 2 import java.util.ResourceBundle; 3 import org.apache.struts2.ServletActionContext; 4 import org.model.Orders; 5 import com.opensymphony.xwork2.ActionSupport; 6 //支付action 通过第三方平台的支持(这里使用易宝支付,当然需要外网) 7 public class PayOrderAction extends ActionSupport { 8     public String execute()throws Exception{ 9         System.out.println("进入支付action");10         // 获得 支付必须基本数据11         Orders orders=(Orders) ServletActionContext.getRequest().getSession().getAttribute("Orders");12         String orderid = orders.getOid();//获得订单编号13         //String money =orders.getTotal()+"";//获得订单总额 即支付的金额14         //这里做模拟  支付0.01元15         String money="0.01";16         17         //获得银行标识  即选择的是哪一个银行进行支付18         String pd_FrpId =ServletActionContext.getRequest().getParameter("pd_FrpId");19         20 21         // 发给支付公司(易宝支付平台 )需要哪些数据22         String p0_Cmd = "Buy";23         //获得项目src下 merchantInfo.properties文件中 key="p1_MerId"对应的值  即获取企业账户p1_MerId=10001126856 24         //将来交易的金额  流向了该账户的银行卡中(企业注册使用平台服务的时候 肯定预留的有银行卡账号  平台返给企业一个账号 用于区别不同的企业)25         String p1_MerId = ResourceBundle.getBundle("merchantInfo").getString("p1_MerId");26         String p2_Order = orderid;27         String p3_Amt = money;28         String p4_Cur = "CNY";29         String p5_Pid = "";30         String p6_Pcat = "";31         String p7_Pdesc = "";//必须要填写的字段使用""代替32         // 支付成功回调地址 ---- 第三方支付公司会访问、用户访问33         // 第三方支付可以访问网址34         String p8_Url = ResourceBundle.getBundle("merchantInfo").getString("callback");35         String p9_SAF = "";36         String pa_MP = "";37         String pr_NeedResponse = "1";38         // 加密hmac 需要密钥 merchantInfo.properties文件中获取key="keyValue"对应的值39         String keyValue = http://www.mamicode.com/ResourceBundle.getBundle("merchantInfo").getString(40                 "keyValue");41         //PaymentUtil.buildHmac第三平台提供的加密方法  42         //在支付平台把传递过去的【A部分.明文数据】也做加密 与hmac【B部分.加密之后的密文】做对比  防止数据被篡改43         String hmac = PaymentUtil.buildHmac(p0_Cmd, p1_MerId, p2_Order, p3_Amt,44                 p4_Cur, p5_Pid, p6_Pcat, p7_Pdesc, p8_Url, p9_SAF, pa_MP,45                 pd_FrpId, pr_NeedResponse, keyValue);46         // 把数据进行保存在request域中  跳到confirm.jsp中进行确认 然后提交  提交的地址47         //https://www.yeepay.com/app-merchant-proxy/node  是第三方支付平台 携带的数据  就是下面封装的48         //数据,想要完成支付首先需要连接外网  因为这个地址目标不是本地上的页面 49         /*50         //A部分.明文数据51         ServletActionContext.getRequest().setAttribute("pd_FrpId", pd_FrpId);52         ServletActionContext.getRequest().setAttribute("p0_Cmd", p0_Cmd);53         ServletActionContext.getRequest().setAttribute("p1_MerId", p1_MerId);54         ServletActionContext.getRequest().setAttribute("p2_Order", p2_Order);55         ServletActionContext.getRequest().setAttribute("p3_Amt", p3_Amt);56         ServletActionContext.getRequest().setAttribute("p4_Cur", p4_Cur);57         ServletActionContext.getRequest().setAttribute("p5_Pid", p5_Pid);58         ServletActionContext.getRequest().setAttribute("p6_Pcat", p6_Pcat);59         ServletActionContext.getRequest().setAttribute("p7_Pdesc", p7_Pdesc);60         ServletActionContext.getRequest().setAttribute("p8_Url", p8_Url);61         ServletActionContext.getRequest().setAttribute("p9_SAF", p9_SAF);62         ServletActionContext.getRequest().setAttribute("pa_MP", pa_MP);63         ServletActionContext.getRequest().setAttribute("pr_NeedResponse", pr_NeedResponse);64         //B部分.加密之后的密文65         ServletActionContext.getRequest().setAttribute("hmac", hmac);66         //跳转页面67         ServletActionContext.getRequest().getRequestDispatcher("/confirm.jsp").forward(ServletActionContext.getRequest(),ServletActionContext.getResponse());68         */69         //第三方支付平台(易宝支付)url  并且携带支付数据  直接跳到该地址  删除中间页confirm.jsp70         String ThirdpartyUrl="https://www.yeepay.com/app-merchant-proxy/node?pd_FrpId="+pd_FrpId71         +"&p0_Cmd="+p0_Cmd72         +"&p1_MerId="+p1_MerId73         +"&p2_Order="+p2_Order74         +"&p3_Amt="+p3_Amt75         +"&p4_Cur="+p4_Cur76         +"&p5_Pid="+p5_Pid77         +"&p6_Pcat="+p6_Pcat78         +"&p7_Pdesc="+p7_Pdesc79         +"&p8_Url="+p8_Url80         +"&p9_SAF="+p9_SAF81         +"&pa_MP="+pa_MP82         +"&pr_NeedResponse="+pr_NeedResponse83         +"&hmac="+hmac;84         //重定向到第三方支付平台 然后根据传递的数据  链接到对应银行支付页面85         ServletActionContext.getResponse().sendRedirect(ThirdpartyUrl);86         return NONE;87     }88     89 }

 

PaymentUtil.buildHmac是第三平台提供的加密算法工具类
  1 package util;  2   3 import java.io.UnsupportedEncodingException;  4 import java.security.MessageDigest;  5 import java.security.NoSuchAlgorithmException;  6 import java.util.Arrays;  7 //支付过程中需要对传递的数据进行加密  这是第三方支付平台给的加密代码  直接使用即可  8 public class PaymentUtil {  9  10     private static String encodingCharset = "UTF-8"; 11      12     /** 13      * 生成hmac方法 14      *  15      * @param p0_Cmd 业务类型 16      * @param p1_MerId 商户编号 17      * @param p2_Order 商户订单号 18      * @param p3_Amt 支付金额 19      * @param p4_Cur 交易币种 20      * @param p5_Pid 商品名称 21      * @param p6_Pcat 商品种类 22      * @param p7_Pdesc 商品描述 23      * @param p8_Url 商户接收支付成功数据的地址 24      * @param p9_SAF 送货地址 25      * @param pa_MP 商户扩展信息 26      * @param pd_FrpId 银行编码 27      * @param pr_NeedResponse 应答机制 28      * @param keyValue 商户密钥 29      * @return 30      */ 31     public static String buildHmac(String p0_Cmd,String p1_MerId, 32             String p2_Order, String p3_Amt, String p4_Cur,String p5_Pid, String p6_Pcat, 33             String p7_Pdesc,String p8_Url, String p9_SAF,String pa_MP,String pd_FrpId, 34             String pr_NeedResponse,String keyValue) { 35         StringBuilder sValue = http://www.mamicode.com/new StringBuilder(); 36         // 业务类型 37         sValue.append(p0_Cmd); 38         // 商户编号 39         sValue.append(p1_MerId); 40         // 商户订单号 41         sValue.append(p2_Order); 42         // 支付金额 43         sValue.append(p3_Amt); 44         // 交易币种 45         sValue.append(p4_Cur); 46         // 商品名称 47         sValue.append(p5_Pid); 48         // 商品种类 49         sValue.append(p6_Pcat); 50         // 商品描述 51         sValue.append(p7_Pdesc); 52         // 商户接收支付成功数据的地址 53         sValue.append(p8_Url); 54         // 送货地址 55         sValue.append(p9_SAF); 56         // 商户扩展信息 57         sValue.append(pa_MP); 58         // 银行编码 59         sValue.append(pd_FrpId); 60         // 应答机制 61         sValue.append(pr_NeedResponse); 62          63         return PaymentUtil.hmacSign(sValue.toString(), keyValue); 64     } 65      66     /** 67      * 返回校验hmac方法 68      *  69      * @param hmac 支付网关发来的加密验证码 70      * @param p1_MerId 商户编号 71      * @param r0_Cmd 业务类型 72      * @param r1_Code 支付结果 73      * @param r2_TrxId 易宝支付交易流水号 74      * @param r3_Amt 支付金额 75      * @param r4_Cur 交易币种 76      * @param r5_Pid 商品名称 77      * @param r6_Order 商户订单号 78      * @param r7_Uid 易宝支付会员ID 79      * @param r8_MP 商户扩展信息 80      * @param r9_BType 交易结果返回类型 81      * @param keyValue 密钥 82      * @return 83      */ 84     public static boolean verifyCallback(String hmac, String p1_MerId, 85             String r0_Cmd, String r1_Code, String r2_TrxId, String r3_Amt, 86             String r4_Cur, String r5_Pid, String r6_Order, String r7_Uid, 87             String r8_MP, String r9_BType, String keyValue) { 88         StringBuilder sValue = http://www.mamicode.com/new StringBuilder(); 89         // 商户编号 90         sValue.append(p1_MerId); 91         // 业务类型 92         sValue.append(r0_Cmd); 93         // 支付结果 94         sValue.append(r1_Code); 95         // 易宝支付交易流水号 96         sValue.append(r2_TrxId); 97         // 支付金额 98         sValue.append(r3_Amt); 99         // 交易币种100         sValue.append(r4_Cur);101         // 商品名称102         sValue.append(r5_Pid);103         // 商户订单号104         sValue.append(r6_Order);105         // 易宝支付会员ID106         sValue.append(r7_Uid);107         // 商户扩展信息108         sValue.append(r8_MP);109         // 交易结果返回类型110         sValue.append(r9_BType);111         String sNewString = PaymentUtil.hmacSign(sValue.toString(), keyValue);112         return sNewString.equals(hmac);113     }114     115     /**116      * @param aValue117      * @param aKey118      * @return119      */120     public static String hmacSign(String aValue, String aKey) {121         byte k_ipad[] = new byte[64];122         byte k_opad[] = new byte[64];123         byte keyb[];124         byte value[];125         try {126             keyb = aKey.getBytes(encodingCharset);127             value =http://www.mamicode.com/ aValue.getBytes(encodingCharset);128         } catch (UnsupportedEncodingException e) {129             keyb = aKey.getBytes();130             value =http://www.mamicode.com/ aValue.getBytes();131         }132 133         Arrays.fill(k_ipad, keyb.length, 64, (byte) 54);134         Arrays.fill(k_opad, keyb.length, 64, (byte) 92);135         for (int i = 0; i < keyb.length; i++) {136             k_ipad[i] = (byte) (keyb[i] ^ 0x36);137             k_opad[i] = (byte) (keyb[i] ^ 0x5c);138         }139 140         MessageDigest md = null;141         try {142             md = MessageDigest.getInstance("MD5");143         } catch (NoSuchAlgorithmException e) {144 145             return null;146         }147         md.update(k_ipad);148         md.update(value);149         byte dg[] = md.digest();150         md.reset();151         md.update(k_opad);152         md.update(dg, 0, 16);153         dg = md.digest();154         return toHex(dg);155     }156 157     public static String toHex(byte input[]) {158         if (input == null)159             return null;160         StringBuffer output = new StringBuffer(input.length * 2);161         for (int i = 0; i < input.length; i++) {162             int current = input[i] & 0xff;163             if (current < 16)164                 output.append("0");165             output.append(Integer.toString(current, 16));166         }167 168         return output.toString();169     }170 171     /**172      * 173      * @param args174      * @param key175      * @return176      */177     public static String getHmac(String[] args, String key) {178         if (args == null || args.length == 0) {179             return (null);180         }181         StringBuffer str = new StringBuffer();182         for (int i = 0; i < args.length; i++) {183             str.append(args[i]);184         }185         return (hmacSign(str.toString(), key));186     }187 188     /**189      * @param aValue190      * @return191      */192     public static String digest(String aValue) {193         aValue =http://www.mamicode.com/ aValue.trim();194         byte value[];195         try {196             value =http://www.mamicode.com/ aValue.getBytes(encodingCharset);197         } catch (UnsupportedEncodingException e) {198             value =http://www.mamicode.com/ aValue.getBytes();199         }200         MessageDigest md = null;201         try {202             md = MessageDigest.getInstance("SHA");203         } catch (NoSuchAlgorithmException e) {204             e.printStackTrace();205             return null;206         }207         return toHex(md.digest(value));208 209     }210     211 //    public static void main(String[] args) {212 //        System.out.println(hmacSign("AnnulCard1000043252120080620160450.0http://localhost/SZXpro/callback.asp杩?4564868265473632445648682654736324511","8UPp0KE8sq73zVP370vko7C39403rtK1YwX40Td6irH216036H27Eb12792t"));213 //    }214 }

点击下一步之后,跳转到支付确认页面confirm.jsp(完成数据的封装)

 1 <!-- 确认支付form --> 2 <form action="https://www.yeepay.com/app-merchant-proxy/node" method="post"> 3     <h3>订单号:${p2_Order},付款金额 :${p3_Amt }</h3> 4     <input type="hidden" name="pd_FrpId" value="http://www.mamicode.com/${pd_FrpId }" /> 5     <input type="hidden" name="p0_Cmd" value="http://www.mamicode.com/${p0_Cmd }" /> 6     <input type="hidden" name="p1_MerId" value="http://www.mamicode.com/${p1_MerId }" /> 7     <input type="hidden" name="p2_Order" value="http://www.mamicode.com/${p2_Order }" /> 8     <input type="hidden" name="p3_Amt" value="http://www.mamicode.com/${p3_Amt }" /> 9     <input type="hidden" name="p4_Cur" value="http://www.mamicode.com/${p4_Cur }" />10     <input type="hidden" name="p5_Pid" value="http://www.mamicode.com/${p5_Pid }" />11     <input type="hidden" name="p6_Pcat" value="http://www.mamicode.com/${p6_Pcat }" />12     <input type="hidden" name="p7_Pdesc" value="http://www.mamicode.com/${p7_Pdesc }" />13     <input type="hidden" name="p8_Url" value="http://www.mamicode.com/${p8_Url }" />14     <input type="hidden" name="p9_SAF" value="http://www.mamicode.com/${p9_SAF }" />15     <input type="hidden" name="pa_MP" value="http://www.mamicode.com/${pa_MP }" />16     <input type="hidden" name="pr_NeedResponse" value="http://www.mamicode.com/${pr_NeedResponse }" />17     <input type="hidden" name="hmac" value="http://www.mamicode.com/${hmac }" />18     <input type="submit" value="http://www.mamicode.com/确认支付" />19 </form>

表单提交时候,https://www.yeepay.com/app-merchant-proxy/node

这是第三方平台(易宝支付)的地址,会根据你选择的银行信息(提交数据中包含),跳转到指定银行支付页面

技术分享

 

 

 

这是银行支付页面,然后支付成功之后会跳入回调的地址,也在提交数据中包含(支付成功,自动执行该方法,前提:必须配置好,不然回调之后,出现404,但是此时已经支付成功了)

回调地址也作为数据传递给了第三方平台

技术分享

Callback就是回调地址:支付成功之后,跳入该地址:所以需要配置好

技术分享

 

技术分享

回调action(在该action中,可以完成支付成功之后需要进行的操作):

 1 package util; 2 import java.util.ResourceBundle; 3 import org.apache.struts2.ServletActionContext; 4 import org.model.Orders; 5 import org.service.OrderService; 6  7 import com.opensymphony.xwork2.ActionSupport; 8 //支付完成之后调用的回调方法 该action会在支付成功后 进行调用----- 支付公司(第三方平台 易宝支付) 、客户  都将调用该action 9 //回调地址:http://localhost:8888/shop/CallBack  需要对该action进行配置10 public class PayOrderCallBackAction extends ActionSupport {11     //创建orderservice 并且完成注入  在订单支付成功之后 需要调用方法 修改订单标志位12     private OrderService orderService;13     public void setOrderService(OrderService orderService) {14         this.orderService = orderService;15     }16     public String execute()throws Exception{17         System.out.println("支付成功,(进入)执行回调action");18         // 获得回调所有数据19         String p1_MerId = ServletActionContext.getRequest().getParameter("p1_MerId");20         String r0_Cmd = ServletActionContext.getRequest().getParameter("r0_Cmd");21         String r1_Code = ServletActionContext.getRequest().getParameter("r1_Code");22         String r2_TrxId = ServletActionContext.getRequest().getParameter("r2_TrxId");23         String r3_Amt = ServletActionContext.getRequest().getParameter("r3_Amt");24         String r4_Cur = ServletActionContext.getRequest().getParameter("r4_Cur");25         String r5_Pid = ServletActionContext.getRequest().getParameter("r5_Pid");26         String r6_Order = ServletActionContext.getRequest().getParameter("r6_Order");27         String r7_Uid = ServletActionContext.getRequest().getParameter("r7_Uid");28         String r8_MP = ServletActionContext.getRequest().getParameter("r8_MP");29         String r9_BType = ServletActionContext.getRequest().getParameter("r9_BType");30         String rb_BankId = ServletActionContext.getRequest().getParameter("rb_BankId");31         String ro_BankOrderId = ServletActionContext.getRequest().getParameter("ro_BankOrderId");32         String rp_PayDate = ServletActionContext.getRequest().getParameter("rp_PayDate");33         String rq_CardNo = ServletActionContext.getRequest().getParameter("rq_CardNo");34         String ru_Trxtime = ServletActionContext.getRequest().getParameter("ru_Trxtime");35         // 身份校验 --- 判断是不是支付公司通知你36         String hmac = ServletActionContext.getRequest().getParameter("hmac");37         String keyValue = http://www.mamicode.com/ResourceBundle.getBundle("merchantInfo").getString(38                 "keyValue");39 40         // 自己对上面数据进行加密 --- 比较支付公司发过来hamc41         boolean isValid = PaymentUtil.verifyCallback(hmac, p1_MerId, r0_Cmd,42                 r1_Code, r2_TrxId, r3_Amt, r4_Cur, r5_Pid, r6_Order, r7_Uid,43                 r8_MP, r9_BType, keyValue);44         if (isValid) {45             /*46             // 响应数据有效47             if (r9_BType.equals("1")) {48                 // 浏览器重定向49                 ServletActionContext.getResponse().setContentType("text/html;charset=utf-8");50                 ServletActionContext.getResponse().getWriter().println("<h1>付款成功!等待商城进一步操作!等待收货...</h1>");51             } else if (r9_BType.equals("2")) {52                 // 服务器点对点 --- 支付公司通知你53                 System.out.println("付款成功!");54                 // 修改订单状态 为已付款55                 // 回复支付公司56                 ServletActionContext.getResponse().getWriter().print("success");57             }58             */59             //得到session域中保存的订单信息60             Orders orders=(Orders) ServletActionContext.getRequest().getSession().getAttribute("Orders");61             //支付成功之后  需要激活订单 修改订单中的state字段为1 表示该订单用户已经完成支付62             this.orderService.orderReactivated(orders.getOid());63             //跳转到支付结果页面 给用户反馈64             ServletActionContext.getRequest().getRequestDispatcher("/payresult.jsp").forward(ServletActionContext.getRequest(),ServletActionContext.getResponse());65         } else {66             // 数据无效67             System.out.println("数据被篡改!");68         }69         70         return NONE;71     }72     73 }

本代码中,支付成功之后需要激活对应订单,表示用户完成该订单的支付,至orders表中对应订单的state字段为1,并且跳页给用户反馈支付成功信息

技术分享

读秒之后,自动跳入反馈页面/payresult.jsp

技术分享

 -----------------------------------------

读取propperties文件中的内容

技术分享

 

技术分享

 

技术分享

 ---------------------------------------------------------

 

 



 

 

 

 





 


 

JAVAEE网上商城项目总结