JavaWeb專案練習--支付模組、後臺部分模組(手風琴下拉選單、上傳技術)
阿新 • • 發佈:2018-11-03
易寶支付
線上支付的兩種形式: 1. 電商與銀行直連! 安全 不收手續費 不與小電商合作! 2. 第三臺支付平臺 支付寶 易寶 財富通 好處: 不安全 收手續費(1%) 小電商可以與其合作! 需要在第三方註冊賬戶 需要認證! 我們有一個易寶的測試賬戶 錢轉過去就要不回來了! 易寶支付 1 去銀行 易寶給了我們一個網址(支付閘道器),重定向到這個地址即可! 還需要給這個地址後新增13+1個引數! https://www.yeepay.com/app-merchant-proxy/node? p0_Cmd=Buy &p1_MerId=10001126856 &p2_Order=123456 &p3_Amt=1234.56 &p4_Cur=CNY &p5_Pid= &p6_Pcat=& p7_Pdesc= &p8_Url=http://localhost:8080/bookstore/OrderServlet?method=back &p9_SAF= &pa_MP= &pd_FrpId= ICBC-NET-B2C &pr_NeedResponse=1 &hmac=dd17580a3ca176ba62d6d348583ba88b 易寶回撥: 點對點:易寶直接訪問電商,這裡沒有客戶端什麼事了。 • 這種方式是必須要使用的,我們這種方式是收不到的!因為我們沒有固定IP • 易寶有一個重發機制,如果它訪問你,你不給它回信息,它會一直重發! • 電商需要返回一個以SUCCESS開頭的字串即可! 引導客戶端瀏覽器重定向到電商。是讓客戶端訪問電商! • 可以不使用的! hmac:13引數值+keyValue(金鑰) + 演算法(md5) 13引數值:自己設定的! keyValue:易寶在我們註冊後發給我們的,這個東東只有我們和易寶知道! 底層為md5的演算法:PaymentUtil.buildHmac(14個),它返回hmac 1) 支付(去銀行) 重定向! 13+1個引數!
2) 支付(銀行回饋)
校驗訪問者是否為易寶
修改訂單的狀態
servlet
/** * 支付(去銀行) * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String pay(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Properties props = new Properties(); InputStream input = this.getClass().getClassLoader() .getResourceAsStream("merchantInfo.properties"); props.load(input); /* * 準備13引數 */ String p0_Cmd = "Buy"; String p1_MerId = props.getProperty("p1_MerId"); String p2_Order = request.getParameter("oid"); String p3_Amt = "0.01"; String p4_Cur = "CNY"; String p5_Pid = ""; String p6_Pcat = ""; String p7_Pdesc = ""; String p8_Url = props.getProperty("p8_Url"); String p9_SAF = ""; String pa_MP = ""; String pd_FrpId = request.getParameter("pd_FrpId"); String pr_NeedResponse = "1"; //計算hmac String keyValue = props.getProperty("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); //連線易寶網址和 13+1 個引數 StringBuilder url = new StringBuilder(props.getProperty("url")); url.append("?p0_Cmd=").append(p0_Cmd); url.append("&p1_MerId=").append(p1_MerId); url.append("&p2_Order=").append(p2_Order); url.append("&p3_Amt=").append(p3_Amt); url.append("&p4_Cur=").append(p4_Cur); url.append("&p5_Pid=").append(p5_Pid); url.append("&p6_Pcat=").append(p6_Pcat); url.append("&p7_Pdesc=").append(p7_Pdesc); url.append("&p8_Url=").append(p8_Url); url.append("&p9_SAF=").append(p9_SAF); url.append("&pa_MP=").append(pa_MP); url.append("&pd_FrpId=").append(pd_FrpId); url.append("&pr_NeedResponse=").append(pr_NeedResponse); url.append("&hmac=").append(hmac); //重定向到易寶 response.sendRedirect(url.toString()); return null; } /** * 易寶回撥方法 * 我們需要判斷呼叫此方法的是否為易寶 * @param request * @param response * @return * @throws ServletException * @throws IOException */ public String back(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* * 1. 獲取11 + 1 */ 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 hmac = request.getParameter("hmac"); /* * 2. 校驗訪問者是否為易寶! */ Properties props = new Properties(); InputStream input = this.getClass().getClassLoader() .getResourceAsStream("merchantInfo.properties"); props.load(input); String keyValue = props.getProperty("keyValue"); boolean bool = 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(!bool) {//如果校驗失敗 request.setAttribute("msg", "請走正常流程支付!"); return "f:/jsps/msg.jsp"; } /* * 3. 獲取狀態訂單,確定是否要修改訂單狀態,以及新增積分等業務操作 */ orderService.pay(r6_Order);//有可能對資料庫進行操作,也可能不操作! /* * 4. 判斷當前回撥方式 * 如果為點對點,需要回饋以success開頭的字串 */ if(r9_BType.equals("2")) { response.getWriter().print("success"); } /* * 5. 儲存成功資訊,轉發到msg.jsp */ request.setAttribute("msg", "支付成功!賣家發貨中···"); return "f:/jsps/msg.jsp"; }
merchantInfo.properties
p1_MerId=10001126856
keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
p8_Url=http\://localhost\:8080/bookstore/OrderServlet?method\=back
url=https\://www.yeepay.com/app-merchant-proxy/node
PaymentUtil
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")); // } }
後臺模組(部分示例)
後臺的內容,必須要設定許可權!
使用者可以訪問一個網站的哪些內容?
dao:不行
service:不行
servlet:能!
jsp:能!
使用者可以訪問的只有WEB層!
1 分類管理
分類管理:
新增分類
檢視所有分類
刪除分類
按id查詢
修改分類
1.1 相關類建立
domain:Category
dao:CategoryDao
service:CategoryService
admin.web.servlet:AdminCategoryServlet(為管理員提供單獨的Servlet,然後給這個Servlet新增過濾器!)
1.2 檢視所有分類
left.jsp上的選單修改一下指向:AdminCategoryServlet#findAll()
findAll():
呼叫service得到所有的分類List<Category>
儲存到request域,轉發到/adminjsps/admin/category/list.jsp
list.jsp:修改頁面,顯示所有分類!
1.3 新增分類
add.jsp(表單頁面)
AdminCatetgoryServlet#add():
封裝表單資料;
補全:cid
呼叫service方法完成新增工作
呼叫findAll()方法
service#add(Category c):略
dao#add(Catetgory c):略
1.4 刪除分類
list.jsp(刪除連結)
AdminCategoryServlet#delete()
獲取引數:cid
呼叫service方法完成刪除!
如果出現異常,儲存異常資訊,轉發到msg.jsp顯示
呼叫findAll()
service#delete(String cid):
通過cid檢視該分類下的圖書本數,如果大於0,丟擲異常;
如果等於0,刪除該分類;
1.5 修改分類
修改分為兩步:1、載入分類, 2、修改分類
第一步:載入分類
list.jsp(修改連結)
AdminCategoryServlet#editPre()
獲取cid
通過cid來呼叫service方法,得到Category物件
儲存到request域中,轉發到mod.jsp
mod.jsp:把當前的Category物件顯示到表單中
第二步:修改分類
mod.jsp(提交表單)
AdminCategoryServlet#edit()
封裝表單資料
呼叫service方法完成修改工作
呼叫findAll()
2 圖書管理
圖書管理(我的)
檢視所有圖書
按id查詢
刪除圖書
修改圖書
新增圖書(上傳圖片)
2.1 相關類建立
web.servlet.admin:
AdminBookServlet;
AdminAddBookServlet(新增圖書,包含上傳):上傳不能使用BaseServlet,因為BaseServlet中需要使用getParameter()方法,而上傳getParameter()方法就不能再使用了。
2.2 查詢所有圖書
left.jsp(選單項(檢視圖書連結))
AdminBookServlet#findAll()
查詢所有圖書,儲存到request
轉發到/adminjsps/admin/book/list.jsp
list.jsp:迴圈遍歷所有圖書
2.3 載入圖書
list.jsp(點選圖名或圖片)
AdminBookServlet#load()
獲取bid,通過bid呼叫BookService方法得到Book物件
儲存到request中,轉發到/adminjsps/admin/book/desc.jsp
desc.jsp:把當前book物件顯示到表單中
2.4 新增圖書
新增圖書分兩步:
1. 載入所有分類,到add.jsp中顯示!
left.jsp(選單項:新增圖書)
AdminBookServlet#addPre():
查詢所有分類,儲存到request域,轉發到add.jsp
在add.jsp中迴圈遍歷所有分類,顯示在<select>中
2. 新增圖書
上傳三步:
建立工廠
建立解析器
解析request得到表單欄位!
把表單欄位封裝到Book物件中
儲存上傳檔案,把儲存的路徑設定給Book的image屬性。
呼叫service方法儲存Book物件到資料庫中
呼叫findAll()
2.5 刪除圖書
book表與orderitem有關聯關係!
刪除圖書不是真的資料庫表中刪除記錄,而是給book表新增一個del欄位,它是booleanod型別,表示是否已刪除!
沒有被刪除的圖書,該列的值為false,否則為true
處理問題:
修改BookDao:所有與查詢相關的方法,都需要新增where條件,即del=false
修改Book類,新增del屬性!
刪除圖書:其實就是把表的del列修改為true!
desc.jsp(del按鈕)
AdminBookServlet#del()
獲取bid
呼叫service方法完成刪除
返回列表,即呼叫findAll()
2.6 編輯圖書
dsec.jsp(編輯按鈕)
AdminBookServlet#edit()
封裝表單資料(必須讓頁面保證把image傳遞過來)
要求頁面必須新增一個隱藏欄位,把原來的圖片路徑傳遞過來!
呼叫service方法完成刪除
return findAll()
servet (上傳技術新增圖書)
public class AdminAddBookServlet extends HttpServlet {
private BookService bookService = new BookService();
private CategoryService categoryService = new CategoryService();
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 一.把表達那資料封裝到Book物件中
* 上傳三步:1.建立工廠、 2.得到解析器、 3. 使用解析器解析request物件得到List<FileItem>
*
*/
//1.建立工廠
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.使用工廠得到解析器
ServletFileUpload sfu = new ServletFileUpload(factory);
try {
//3.使用解析器解析request,得到FileItem集合
List<FileItem> fileItemList = sfu.parseRequest(request);
/*
* 把fileItemList中的資料封裝到Book物件中(包含上傳內容,所以不能一鍵封裝)
*
* 解決:將所有的普通文字表單遍歷進map,然後對map一鍵封裝
* 做法:
* 1.把所有的普通文字表單資料封裝到map中
* 2.把map中資料封裝到Book物件中
*/
//遍歷:將所有普通文字欄位資料放入map
Map<String,String> map = new HashMap<String, String>();
for (FileItem fileItem : fileItemList) {
if(fileItem.isFormField()){ //判斷是否為普通文字欄位資料
map.put(fileItem.getFieldName(), fileItem.getString("UTF-8"));
}
}
//一鍵封裝map
Book book = CommonUtils.toBean(map, Book.class);
//對book設定uuid
book.setBid(CommonUtils.uuid());
//將Map中cid封裝到Category物件中,再將category設定給book
Category category = CommonUtils.toBean(map, Category.class);
book.setCategory(category);
/*
* 二、儲存上傳的檔案
* 1.得到儲存目錄路徑、檔名
* 2.使用檔名和目錄建立目標檔案
* 3.儲存上傳檔案到目標檔案中
*/
//得到圖片的儲存路徑
String savepath = this.getServletContext().getRealPath("/book_img");
//得到表單項集合中第一個元素的name,並新增uuid字首避免檔名衝突
String fileName = CommonUtils.uuid()+"_"+fileItemList.get(1).getName();
/*
* 校驗檔案的副檔名
*/
if(!fileName.toLowerCase().endsWith("jpg")) {
request.setAttribute("msg", "您上傳的圖片不是JPG副檔名!");
request.setAttribute("categoryList", categoryService.findAllCategory());
request.getRequestDispatcher("/adminjsps/admin/book/add.jsp")
.forward(request, response);
return;
}
//2.使用路徑和檔名 建立目標檔案
File destFile = new File(savepath,fileName);
//3.儲存上傳檔案到目標檔案中
fileItemList.get(1).write(destFile);
//三、把圖片的路徑設定為Book的image
book.setImage("book_img/" + fileName);
//使用BookService完成儲存
bookService.add(book);
//轉發請求另一個servlet,呼叫其中findAll,對新增圖書進行顯示
request.getRequestDispatcher("/admin/AdminBookServlet?method=findAllBook").forward(request, response);
} catch (Exception e) {
}
}
}
jsp
手風琴式下拉選單使用
<script language="javascript">
/*
* 手風琴式下拉選單指令碼使用規定:
* bar1:引數名必須與物件名相同
* ITCAST網路圖書商城:大標題
*/
var bar1 = new Q6MenuBar("bar1", "ywnxbx網路圖書商城");
function load() {
//設定配色方案(四種):0、1、2、3 (內部為陣列下標)
bar1.colorStyle = 2;
//設定圖片所在目錄 (手風琴式下拉選單加減號圖片)
bar1.config.imgDir = "<c:url value='/menu/img/'/>";
/*
* 選單間是否相互排斥
* false(不排斥):擴充套件選單可以全部開啟、
* true(排斥):只能開啟一項擴充套件選單,已開啟的會被自動關閉)
*/
bar1.config.radioButton=false;
/*
add方法:
第一個引數:被新增的選單
第二個引數:新增項
第三個引數:新增項的內容(請求地址)
第四個引數:顯示內容的框架名稱
*/
bar1.add("分類管理", "檢視分類", "<c:url value='/admin/AdminCategoryServlet?method=findAll'/>", "body");
bar1.add("分類管理", "新增分類", "<c:url value='/adminjsps/admin/category/add.jsp'/>", "body");
bar1.add("圖書管理", "檢視圖書", "<c:url value='/admin/AdminBookServlet?method=findAllBook'/>", "body");
bar1.add("圖書管理", "新增圖書", "<c:url value='/admin/AdminBookServlet?method=addPre'/>", "body");
bar1.add("訂單管理", "所有訂單", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body");
bar1.add("訂單管理", "未付款訂單", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body");
bar1.add("訂單管理", "已付款訂單", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body");
bar1.add("訂單管理", "未收貨訂單", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body");
bar1.add("訂單管理", "已完成訂單", "<c:url value='/adminjsps/admin/order/list.jsp'/>", "body");
//獲取div元素
var d = document.getElementById("menu");
//將選單物件轉換成字串物件 賦給div
d.innerHTML = bar1.toString();
}
</script>
</head>
<body onload="load()" style="margin: 0px; background: rgb(254,238,189);">
<div id="menu"></div>
</body>