JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)
黑马商城项目(六)
今天任务
- 在线支付
- 后台查询商品分类
- 后台添加商品分类
- 后台商品分类名回显
- 后台商品分类名删除
- 提交订单页面跳转
在线支付
准备工作
配置文件,里面有商家编号、密钥、回调地址
易宝给的支付工具类
前端
js部分
//订单确认按钮事件
function pay(){
//取出订单编号
var oid = HM.getParameter("oid");
//取出表单数据
var params = $("#orderForm").serialize();
//发送请求,提交数据
HM.ajax("/order?method=pay",params+"&oid="+oid,function(data){
if(data.code==1){
location.href=data.obj;
}
});
}
表单数据
<form id="orderForm" class="form-horizontal" style="margin-top:5px;margin-left:150px;">
<div class="form-group">
<label for="username" class="col-sm-1 control-label">地址</label>
<div class="col-sm-5">
<input type="text" name="address" class="form-control" id="username" placeholder="请输入收货地址">
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-1 control-label">收货人</label>
<div class="col-sm-5">
<input type="text" name="name" class="form-control" id="inputPassword3" placeholder="请输收货人">
</div>
</div>
<div class="form-group">
<label for="confirmpwd" class="col-sm-1 control-label">电话</label>
<div class="col-sm-5">
<input type="text" name="telephone" class="form-control" id="confirmpwd" placeholder="请输入联系方式">
</div>
</div>
<hr/>
<div style="margin-top:5px;margin-left:150px;">
<strong>选择银行:</strong>
<p>
<br/>
<input type="radio" name="pd_FrpId" value="ICBC-NET-B2C" checked="checked" />工商银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/icbc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="BOC-NET-B2C" />中国银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/bc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="ABC-NET-B2C" />农业银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/abc.bmp" align="middle" />
<br/>
<br/>
<input type="radio" name="pd_FrpId" value="BOCO-NET-B2C" />交通银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/bcc.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="PINGANBANK-NET" />平安银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/pingan.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="CCB-NET-B2C" />建设银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/ccb.bmp" align="middle" />
<br/>
<br/>
<input type="radio" name="pd_FrpId" value="CEB-NET-B2C" />光大银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/guangda.bmp" align="middle" />
<input type="radio" name="pd_FrpId" value="CMBCHINA-NET-B2C" />招商银行
<img src="http://www.itheima331.com:8020/web/resources/bank_img/cmb.bmp" align="middle" />
</p>
<hr/>
<p style="text-align:right;margin-right:100px;">
<a href="javascript:;" onclick="pay()">
<img src="http://www.itheima331.com:8020/web/resources/img/finalbutton.gif" width="204" height="51" border="0" />
</a>
</p>
<hr/>
</form>
支付成功的页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
.content{
background-color:#FFFFCC;
width: 60%;
margin: 0px auto;
min-height: 200px;
}
</style>
<script>
var num=5;
setInterval(function(){
num--;
if(num<1){
location.href="http://www.itheima331.com:8020/web/view/order/info.html?oid=${oid}";
}else{
document.getElementById("time").innerHTML=num;
}
},1000);
</script>
</head>
<body>
<div>
<div style="margin-left: 200px;">
<h3>黑马收银台</h3>
</div>
<div style="text-align: center;">
<div class="content">
<div id="info">
${msg}
</div>
<div >
<span id="time">5</span>秒之后跳转商城页面!!!
</div>
</div>
</div>
</div>
</body>
</html>
OrdersDao
/*
修改订单状态为已付款
*/
@Override
public void updateOrderState(String oid) throws SQLException {
String sql = "update orders set state = ? where oid = ?";
qr.update(sql, Constr.PAID,oid);
}
/*
修改订单方法
收货人,地址,电话
*/
@Override
public void updateOrder(String name, String address, String telephone, String oid) throws SQLException {
String sql = "update orders set name=?, address=?, telephone=? where oid = ?";
Object[] params = {
name,address,telephone,oid
};
qr.update(sql,params);
}
OrdersService
@Override
public void updateOrderState(String oid) {
try {
ordersDao.updateOrderState(oid);
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
*/
@Override
public void updateOrder(String name, String address, String telephone, String oid) {
try {
ordersDao.updateOrder(name,address,telephone,oid);
} catch (SQLException e) {
e.printStackTrace();
}
}
OrdersServlet
/*
支付成功后的回调方法
*/
public String callback(HttpServletRequest request,HttpServletResponse response) throws Exception{
String p1_MerId = request.getParameter("p1_MerId");
String r0_Cmd = request.getParameter("r0_Cmd");
String r1_Code = request.getParameter("r1_Code");
String r2_TrxId = request.getParameter("r2_TrxId");
String r3_Amt = request.getParameter("r3_Amt");
String r4_Cur = request.getParameter("r4_Cur");
String r5_Pid = request.getParameter("r5_Pid");
String r6_Order = request.getParameter("r6_Order");
String r7_Uid = request.getParameter("r7_Uid");
String r8_MP = request.getParameter("r8_MP");
String r9_BType = request.getParameter("r9_BType");
String rb_BankId = request.getParameter("rb_BankId");
String ro_BankOrderId = request.getParameter("ro_BankOrderId");
String rp_PayDate = request.getParameter("rp_PayDate");
String rq_CardNo = request.getParameter("rq_CardNo");
String ru_Trxtime = request.getParameter("ru_Trxtime");
// 身份校验 --- 判断是不是支付公司通知你
String hmac = request.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")) {
// 浏览器重定向
System.out.println("111");
request.setAttribute("msg", "您的订单号为:"+r6_Order+",金额为:"+r3_Amt+"已经支付成功,等待发货~~");
//request域对象,存储订单号
request.setAttribute("oid",r6_Order);
} else if (r9_BType.equals("2")) {
// 服务器点对点 --- 支付公司通知你
System.out.println("付款成功!222");
// 修改订单状态 为已付款
// 回复支付公司
response.getWriter().print("success");
}
//订单状态,修改为已付款
ordersService.updateOrderState(r6_Order);
} else {
// 数据无效
System.out.println("数据被篡改!");
}
//页面转发到success.jsp
request.getRequestDispatcher("/success.jsp").forward(request,response);
return "/jsp/msg.jsp";
}
/*
支付请求方法
*/
public void pay(HttpServletRequest request,HttpServletResponse response) throws Exception{
//接受参数
String address=request.getParameter("address");
String name=request.getParameter("name");
String telephone=request.getParameter("telephone");
String oid=request.getParameter("oid");
//业务层方法,修改订单信息
ordersService.updateOrder(name,address,telephone,oid);
//通过id获取order
/* OrderService s=new OrderService();
Order order = s.getOrderByOid(oid);
order.setAddress(address);
order.setName(name);
order.setTelephone(telephone);
//更新order
s.updateOrder(order);*/
// 组织发送支付公司需要哪些数据
String pd_FrpId = request.getParameter("pd_FrpId");
String p0_Cmd = "Buy";
String p1_MerId = ResourceBundle.getBundle("merchantInfo").getString("p1_MerId");
String p2_Order = oid;
String p3_Amt = "0.01";
String p4_Cur = "CNY";
String p5_Pid = "";
String p6_Pcat = "";
String p7_Pdesc = "";
// 支付成功回调地址 ---- 第三方支付公司会访问、用户访问
// 第三方支付可以访问网址
String p8_Url = ResourceBundle.getBundle("merchantInfo").getString("responseURL");
String p9_SAF = "";
String pa_MP = "";
String pr_NeedResponse = "1";
// 加密hmac 需要密钥
String keyValue = ResourceBundle.getBundle("merchantInfo").getString("keyValue");
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);
//发送给第三方
StringBuffer sb = new StringBuffer("https://www.yeepay.com/app-merchant-proxy/node?");
sb.append("p0_Cmd=").append(p0_Cmd).append("&");
sb.append("p1_MerId=").append(p1_MerId).append("&");
sb.append("p2_Order=").append(p2_Order).append("&");
sb.append("p3_Amt=").append(p3_Amt).append("&");
sb.append("p4_Cur=").append(p4_Cur).append("&");
sb.append("p5_Pid=").append(p5_Pid).append("&");
sb.append("p6_Pcat=").append(p6_Pcat).append("&");
sb.append("p7_Pdesc=").append(p7_Pdesc).append("&");
sb.append("p8_Url=").append(p8_Url).append("&");
sb.append("p9_SAF=").append(p9_SAF).append("&");
sb.append("pa_MP=").append(pa_MP).append("&");
sb.append("pd_FrpId=").append(pd_FrpId).append("&");
sb.append("pr_NeedResponse=").append(pr_NeedResponse).append("&");
sb.append("hmac=").append(hmac);
//respone.sendRedirect(sb.toString());
Result result = new Result(Result.SUCCESS,"",sb.toString());
response.getWriter().print(JSONObject.fromObject(result));
}
后台查询商品分类
实现步骤
- 分类列表页面发送AJAX请求
- Servlet查询所有分类信息数据
- JSON数据格式响应客户端
- 判断奇数偶数行,显示数据
前端
<script type="text/javascript">
$(function(){
//直接发送请求,获取所有商品的分类信息
HM.ajax("/admin?method=findAll","",function(data){
//data响应回来的json,就是分类数据
//json取出分类信息数组
var category = data.obj;
$.each(category, function(index,element) {
//判断奇数偶数
var css = index%2 ==0?"cate_tr tr_even":"cate_tr tr_odd";
var str = "<tr class='"+css+"'>\n" +
"\t\t\t\t\t\t\t\t<td>\n" +
"\t\t\t\t\t\t\t\t\t"+(index+1)+"\n" +
"\t\t\t\t\t\t\t\t</td>\n" +
"\t\t\t\t\t\t\t\t<td>\n" +
"\t\t\t\t\t\t\t\t\t"+element.cname+"\n" +
"\t\t\t\t\t\t\t\t</td>\n" +
"\t\t\t\t\t\t\t\t<td >\n" +
"\t\t\t\t\t\t\t\t\t<a href=\"http://www.itheima331.com:8020/web/view/admin/category/edit.html\" class=\"a_button_edit\"></a>\n" +
"\t\t\t\t\t\t\t\t\t \n" +
"\t\t\t\t\t\t\t\t\t<a href=\"#\" οnclick=\"return confirm('您确定要删除吗?')\" class=\"a_button_del\"></a>\n" +
"\t\t\t\t\t\t\t\t</td>\n" +
"\t\t\t\t\t\t\t</tr>";
$("#category").append(str);
});
});
});
</script>
AdminServlet
service层和dao层复用,调用CategoryService和CategoryDao的方法即可
package com.itheima.web;
import com.itheima.domain.Category;
import com.itheima.service.CategoryService;
import com.itheima.utils.BeanFactory;
import net.sf.json.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet(urlPatterns = "/admin")
public class AdminServlet extends BaseServlet {
//bean工厂,获取业务层category
private CategoryService categoryService = BeanFactory.newInstance(CategoryService.class);
/*
查询所有的商品分类
找业务层查询,返回集合
转成json响应
*/
public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Category> categoryList = categoryService.findAll();
Result result = new Result(Result.SUCCESS,"查询成功",categoryList);
response.getWriter().print(JSONObject.fromObject(result));
}
}
后台添加商品分类
实现步骤
- 添加页面发起AJAX请求,提交填写的分类数据
- Servlet 接收数据,并调用业务层保存数据
- 业务层调用持久层保存数据,并清空数据库缓存
- Servlet响应添加成功信息
前端
<script type="text/javascript">
function addCategory(){
//获取文本框填写的分类名称
var cname = $("#cname").val();
//发送ajax请求
HM.ajax("/admin?method=addCategory","cname="+cname,function(data){
if(data.code==1){
//页面跳转到列表页
location.href="http://www.itheima331.com:8020/web/view/admin/category/list.html";
}
});
}
</script>
CategoryDao
/*
添加新分类方法
传递分类名
*/
@Override
public void addCategory(String cname) throws SQLException {
String sql = "insert into category values(?,?)";
qr.update(sql, UUIDUtils.getUUID(),cname);
}
CategoryService
注意:添加了分类之后,redis中的数据也需要被更新
/*
添加新分类方法
注意需要更新redis数据库
*/
@Override
public void addCategory(String cname) {
try {
categoryDao.addCategory(cname);
clearRedis();
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
清空redis数据库
*/
private void clearRedis(){
Jedis jedis = JedisUtils.getJedis();
jedis.del("category");
JedisUtils.close(jedis);
}
AdminServlet
/*
添加新的分类
获取新的分类名称
调用业务层传递名称
*/
public void addCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String cname = request.getParameter("cname");
categoryService.addCategory(cname);
Result result = new Result(Result.SUCCESS,"添加成功");
response.getWriter().print(JSONObject.fromObject(result));
}
后台商品分类名回显
实现步骤
可以直接使用js获取页面传递的分类名称,但为了练习,发送ajax请求到服务端,让服务端从数据库中取出分类名称回显到页面中
前端
<script type="text/javascript">
$(function(){
//获取点击编辑按钮,传递过来的主键
var cid = HM.getParameter("cid");
//发送ajax请求查询该主键下的分类信息
HM.ajax("/admin?method=findById","cid="+cid,function(data){
//取出category对象
if(data.code==1){
var category = data.obj;
$("#cname").val(category.cname);
}
});
});
</script>
CategoryDao
/*
业务层传递分类的主键
查询数据,返回Category对象
*/
@Override
public Category findById(String cid) throws SQLException {
String sql = "select * from category where cid = ?";
return qr.query(sql,new BeanHandler<Category>(Category.class),cid);
}
CategoryService
/*
传递分类主键,返回category对象
*/
@Override
public Category findById(String cid) {
Category category = null;
try {
category = categoryDao.findById(cid);
} catch (SQLException e) {
e.printStackTrace();
}
return category;
}
AdminServlet
/*
根据分类主键查询分类信息
获取页面提交的分类信息主键
传递到业务层,返回分类信息对象Category
响应,对象转成json
*/
public void findById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String cid = request.getParameter("cid");
Category category = categoryService.findById(cid);
Result result = new Result(Result.SUCCESS,"查询成功",category);
response.getWriter().print(JSONObject.fromObject(result));
}
后台商品分类名更新
实现步骤
- 分类编辑页面发送请求,提交主键和分类名称
- Servlet接收参数,传递到业务层修改数据
- 修改完毕后清空redis数据缓存
- 显示修改完毕后的信息
前端
//修改按钮的点击事件
function updateCategory(){
//获取文本框填写的新的分类名称,获取到分类主键
var cid = $("#cid").val();
var cname = $("#cname").val();
var params = "cid="+cid+"&cname="+cname;
//发送ajax请求,提交主键和分类名称
HM.ajax("/admin?method=updateCategory",params,function(data){
if(data.code==1){
//页面回到分类列表页面
location.href="http://www.itheima331.com:8020/web/view/admin/category/list.html";
}
});
}
CategoryDao
/*
更新分类数据
业务层传递分类主键和名称
*/
@Override
public void updateCategory(String cid, String cname) throws SQLException {
String sql = "update category set cname = ? where cid = ?";
qr.update(sql,cname,cid);
}
CategoryService
/*
更新分类数据
web层传递分类主键和名称
更新内存数据库
*/
@Override
public void updateCategory(String cid, String cname) {
try {
categoryDao.updateCategory(cid,cname);
clearRedis();
} catch (SQLException e) {
e.printStackTrace();
}
}
AdminServlet
/*
更新分类名称方法
获取页面提交的分类名称和主键
数据传递到业务层
响应
*/
public void updateCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String cid = request.getParameter("cid");
String cname = request.getParameter("cname");
categoryService.updateCategory(cid,cname);
Result result = new Result(Result.SUCCESS,"更新成功");
response.getWriter().print(JSONObject.fromObject(result));
}
后台删除商品分类
实现步骤
注意:不是简单的删除!如果数据库中分类表的子表中有对应的数据,就无法删除该分类表的某一分类。
- 提示用户是否确认删除
- 发送AJAX请求,提交分类主键
- 删除该商品分类,并清空redis数据库缓存
- 如果该分类下有商品,则不能删除
自定义一个不能删除异常
package com.itheima.exception;
/*
自定义异常
不能删除的异常
必须继承父类
Exception:编译期异常,可以被处理,处理完以后,程序可以继续执行
RuntimeException:运行时期异常,一旦程序抛出运行异常,程序必须停止,修改源代码
如:空指针异常,数组越界异常,类型转换异常,无效参数异常
*/
public class CanNotDeleteException extends Exception{
public CanNotDeleteException(String msg) {
super(msg);
}
}
ProductDao
/*
传递商品表外键
查询是否有数据
*/
@Override
public long getProductCount(String cid) throws SQLException {
String sql = "select count(*) from product where cid = ?";
return qr.query(sql,new ScalarHandler<Long>(),cid);
}
CategoryDao
/*
删除分类
业务层传递分类主键
*/
@Override
public void delCategory(String cid) throws SQLException {
String sql = "delete from category where cid = ?";
qr.update(sql,cid);
}
CategoryService
/*
删除分类信息
接收web层的分类主键
调用dao删除
注意:更新redis数据库
注意:如果删除的分类数据
分类下无数据:直接删除
分类下有数据:不能删除
根据能否删除结果,来通知web层,用异常
删除之前,查询一次是否在分类下有数据
*/
@Override
public void delCategory(String cid) throws CanNotDeleteException {
try {
//查询分类下是否有数据
long count = productDao.getProductCount(cid);
//判断返回值,>0有数据,不能删除
if (count > 0) {
//查询有数据,分类不能删除
//通知web层不能删除,利用异常
//自定义一个不能删除的异常
throw new CanNotDeleteException("该分类有数据,不能删除!");
} else {
//没有数据
categoryDao.delCategory(cid);
clearRedis();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
AdminServlet
/*
删除商品分类
获取页面提交的分类主键
调用业务层删除
*/
public void delCategory(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//取出分类主键
String cid = request.getParameter("cid");
//调用业务层方法,如果没有异常,就删除;否则不能删除
try {
categoryService.delCategory(cid);
Result result = new Result(Result.SUCCESS,"删除成功");
response.getWriter().print(JSONObject.fromObject(result));
} catch (CanNotDeleteException e) {
System.out.println(e);
Result result = new Result(Result.FAILS,"该分类有数据,无法删除!");
response.getWriter().print(JSONObject.fromObject(result));
}
}
提交订单页面跳转
修改OrderServlet中的submitOrder方法,让订单主键响应回页面,然后页面点击提交订单,转发到订单页面
修改OrderServlet
//把生成的订单号响应回去
Result result = new Result(Result.SUCCESS, "订单创建成功",UUID);
response.getWriter().print(JSONObject.fromObject(result));
修改前端
//提交订单的函数
function submitOrder(){
//发送ajax请求
HM.ajax("/order?method=submitOrder","",function(data){
//判断响应的状态码
if(data.code==2){
//没有登录,跳转到登录页面
alert(data.message);
location.href="http://www.itheima331.com:8020/web/login.html";
}
if(data.code==0){
//购物车是空的
alert(data.message);
}
if(data.code==1){
//订单生成完毕,json中获取订单号
var oid = data.obj;
//页面跳转到订单详情
location.href="http://www.itheima331.com:8020/web/view/order/info.html?oid="+oid;
}
});
}
</script>