JavaWeb项目练习--支付模块、后台部分模块(手风琴下拉菜单、上传技术)

版权声明:转载请联系作者本人!!! https://blog.csdn.net/qq_41307491/article/details/82810253

易宝支付

在这里插入图片描述

在线支付的两种形式:
	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>

猜你喜欢

转载自blog.csdn.net/qq_41307491/article/details/82810253