訂單
訂單三張表關係
提交訂單
controller
@RestController
@RequestMapping("/order")
public class OrderController {
@Reference
private OrderService orderService;
@RequestMapping("/add")
public Result add(@RequestBody Order order) {
try {
String userName = SecurityContextHolder.getContext().getAuthentication().getName();
order.setUserId(userName);
orderService.add(order);
return new Result(true, "保存成功!");
} catch (Exception e) {
e.printStackTrace();
return new Result(false, "保存失敗!");
}
}
}
Service
@Service
@Transactional
public class OrderServiceImpl implements OrderService {
@Autowired
private PayLogDao payLogDao;
@Autowired
private OrderDao orderDao;
@Autowired
private OrderItemDao orderItemDao;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private IdWorker idWorker;
@Override
public void add(Order order) {
//1. 從訂單對象中獲取當前登錄用戶用戶名
String userId = order.getUserId();
//2. 根據用戶名獲取購物車集合
List<BuyerCart> cartList = (List<BuyerCart>) redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).get(userId);
List<String> orderIdList = new ArrayList();//訂單ID列表
double total_money = 0;//總金額 (元)
//3. 遍歷購物車集合
if (cartList != null) {
for (BuyerCart cart : cartList) {
//TODO 4. 根據購物車對象保存訂單數據
long orderId = idWorker.nextId();
System.out.println("sellerId:" + cart.getSellerId());
Order tborder = new Order();//新創建訂單對象
tborder.setOrderId(orderId);//訂單ID
tborder.setUserId(order.getUserId());//用戶名
tborder.setPaymentType(order.getPaymentType());//支付類型
tborder.setStatus("1");//狀態:未付款
tborder.setCreateTime(new Date());//訂單創建日期
tborder.setUpdateTime(new Date());//訂單更新日期
tborder.setReceiverAreaName(order.getReceiverAreaName());//地址
tborder.setReceiverMobile(order.getReceiverMobile());//手機號
tborder.setReceiver(order.getReceiver());//收貨人
tborder.setSourceType(order.getSourceType());//訂單來源
tborder.setSellerId(cart.getSellerId());//商家ID
//循環購物車明細
double money = 0;
//5. 從購物車中獲取購物項集合
List<OrderItem> orderItemList = cart.getOrderItemList();
//6. 遍歷購物項集合
if (orderItemList != null) {
for (OrderItem orderItem : orderItemList) {
//TODO 7. 根據購物項對象保存訂單詳情數據
orderItem.setId(idWorker.nextId());
orderItem.setOrderId(orderId);//訂單ID
orderItem.setSellerId(cart.getSellerId());
money += orderItem.getTotalFee().doubleValue();//金額累加
orderItemDao.insertSelective(orderItem);
}
}
tborder.setPayment(new BigDecimal(money));
orderDao.insertSelective(tborder);
orderIdList.add(orderId + "");//添加到訂單列表
total_money += money;//累加到總金額
}
}
//TODO 8. 計算總價錢保存支付日誌數據
if ("1".equals(order.getPaymentType())) {//如果是微信支付
PayLog payLog = new PayLog();
String outTradeNo = idWorker.nextId() + "";//支付訂單號
payLog.setOutTradeNo(outTradeNo);//支付訂單號
payLog.setCreateTime(new Date());//創建時間
//訂單號列表,逗號分隔
String ids = orderIdList.toString().replace("[", "").replace("]", "").replace(" ", "");
payLog.setOrderList(ids);//訂單號列表,逗號分隔
payLog.setPayType("1");//支付類型
payLog.setTotalFee((long) (total_money * 100));//總金額(分)
payLog.setTradeState("0");//支付狀態
payLog.setUserId(order.getUserId());//用戶ID
payLogDao.insertSelective(payLog);//插入到支付日誌表
//TODO 9. 使用當前登錄用戶的用戶名作爲key, 支付日誌對象作爲value存入redis中供支付使用
redisTemplate.boundHashOps("payLog").put(order.getUserId(), payLog);//放入緩存
}
//TODO 10. 根據當前登錄用戶的用戶名刪除購物車
redisTemplate.boundHashOps(Constants.CART_LIST_REDIS).delete(order.getUserId());
}
}
二維碼
介紹
二維碼又稱QR Code,QR全稱Quick Response,是一個近幾年來移動設備上超流行的一種編碼方式,它比傳統的Bar Code條形碼能存更多的信息,也能表示更多的數據類型。
二維條碼/二維碼(2-dimensional bar code)是用某種特定的幾何圖形按一定規律在平面(二維方向上)分佈的黑白相間的圖形記錄數據符號信息的;在代碼編制上巧妙地利用構成計算機內部邏輯基礎的“0”、“1”比特流的概念,使用若干個與二進制相對應的幾何形體來表示文字數值信息,通過圖象輸入設備或光電掃描設備自動識讀以實現信息自動處理:它具有條碼技術的一些共性:每種碼制有其特定的字符集;每個字符佔有一定的寬度;具有一定的校驗功能等。同時還具有對不同行的信息自動識別功能、及處理圖形旋轉變化點。
優勢
信息容量大, 可以容納多達1850個大寫字母或2710個數字或500多個漢字
應用範圍廣, 支持文字,聲音,圖片,指紋等等…
容錯能力強, 即使圖片出現部分破損也能使用
成本低, 容易製作
容錯級別
容錯級別也就是容錯率, 相當於部分二維碼被遮擋仍然可以被掃描出來.
L級(低) 7%的碼字可以被恢復。
M級(中) 的碼字的15%可以被恢復。
Q級(四分)的碼字的25%可以被恢復。
H級(高) 的碼字的30%可以被恢復。
qrious二維碼生成插件
這是前端的二維碼生成工具
<html>
<head>
<title>二維碼入門小demo</title>
</head>
<body>
<img id="qrious">
<script src="qrious.min.js"></script>
<script>
var qr = new QRious({
element:document.getElementById('qrious'),
size:250, level:'H', value:'https://www.baidu.com'
});
</script>
</body>
</html>
微信支付
微信支付流程
紅色部分爲項目需要實現的部分
項目支付流程
生成支付鏈接
controller
/**
* 支付業務
*/
@RestController
@RequestMapping("/pay")
public class PayController {
@Reference
private OrderService orderService;
@Reference
private PayService payService;
/**
* 根據支付單號和總金額調用微信統一下單接口,生成支付鏈接返回
* @return
*/
@RequestMapping("/createNative")
public Map createNative(){
//1.獲取用戶名
String username = SecurityContextHolder.getContext().getAuthentication().getName();
//2.獲取支付日誌對象
PayLog payLog = orderService.getPayLogByUsername(username);
if (payLog!=null){
//3.調用統一下單接口,生成支付鏈接
Map map = payService.createNative(payLog.getOutTradeNo(), "1");//payLog.getTotalFee()
return map;
}
return new HashMap();
}
}
service:注意需要發送https請求,所以要用到HttpClient工具類
@Service
public class PayServiceImpl implements PayService {
//公衆號唯一標識
@Value("${appid}")
private String appid;
//財付通平臺商戶賬號
@Value("${partner}")
private String partner;
//密鑰
@Value("${partnerkey}")
private String partnerkey;
//回調地址
@Value("${notifyurl}")
private String notifyurl;
@Override
public Map createNative(String outTradeNo, String totalFee) {
//1.創建參數
Map<String,String> param=new HashMap();//創建參數
param.put("appid", appid);//公衆號
param.put("mch_id", partner);//商戶號
param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串
param.put("body", "品優購");//商品描述
param.put("out_trade_no", outTradeNo);//商戶訂單號
param.put("total_fee",totalFee);//總金額(分)
param.put("spbill_create_ip", "127.0.0.1");//IP
param.put("notify_url", "http://www.itcast.cn");//回調地址(隨便寫)
param.put("trade_type", "NATIVE");//交易類型
try {
//2.生成要發送的xml
String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
System.out.println(xmlParam);
HttpClient client=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
client.setHttps(true);
client.setXmlParam(xmlParam);
client.post();
//3.獲得結果
String result = client.getContent();
System.out.println(result);
Map<String, String> resultMap = WXPayUtil.xmlToMap(result);
Map<String, String> map=new HashMap<>();
map.put("code_url", resultMap.get("code_url"));//支付地址
map.put("total_fee", totalFee);//總金額
map.put("out_trade_no",outTradeNo);//訂單號
return map;
} catch (Exception e) {
e.printStackTrace();
return new HashMap<>();
}
}
}
HttpClient
/**
* http請求客戶端
*
* @author Administrator
*
*/
public class HttpClient {
private String url;
private Map<String, String> param;
private int statusCode;
private String content;
private String xmlParam;
private boolean isHttps;
public boolean isHttps() {
return isHttps;
}
public void setHttps(boolean isHttps) {
this.isHttps = isHttps;
}
public String getXmlParam() {
return xmlParam;
}
public void setXmlParam(String xmlParam) {
this.xmlParam = xmlParam;
}
public HttpClient(String url, Map<String, String> param) {
this.url = url;
this.param = param;
}
public HttpClient(String url) {
this.url = url;
}
public void setParameter(Map<String, String> map) {
param = map;
}
public void addParameter(String key, String value) {
if (param == null)
param = new HashMap<String, String>();
param.put(key, value);
}
public void post() throws ClientProtocolException, IOException {
HttpPost http = new HttpPost(url);
setEntity(http);
execute(http);
}
public void put() throws ClientProtocolException, IOException {
HttpPut http = new HttpPut(url);
setEntity(http);
execute(http);
}
public void get() throws ClientProtocolException, IOException {
if (param != null) {
StringBuilder url = new StringBuilder(this.url);
boolean isFirst = true;
for (String key : param.keySet()) {
if (isFirst)
url.append("?");
else
url.append("&");
url.append(key).append("=").append(param.get(key));
}
this.url = url.toString();
}
HttpGet http = new HttpGet(url);
execute(http);
}
/**
* set http post,put param
*/
private void setEntity(HttpEntityEnclosingRequestBase http) {
if (param != null) {
List<NameValuePair> nvps = new LinkedList<NameValuePair>();
for (String key : param.keySet())
nvps.add(new BasicNameValuePair(key, param.get(key))); // 參數
http.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8)); // 設置參數
}
if (xmlParam != null) {
http.setEntity(new StringEntity(xmlParam, Consts.UTF_8));
}
}
private void execute(HttpUriRequest http) throws ClientProtocolException,
IOException {
CloseableHttpClient httpClient = null;
try {
if (isHttps) {
SSLContext sslContext = new SSLContextBuilder()
.loadTrustMaterial(null, new TrustStrategy() {
// 信任所有
public boolean isTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext);
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf)
.build();
} else {
httpClient = HttpClients.createDefault();
}
CloseableHttpResponse response = httpClient.execute(http);
try {
if (response != null) {
if (response.getStatusLine() != null)
statusCode = response.getStatusLine().getStatusCode();
HttpEntity entity = response.getEntity();
// 響應內容
content = EntityUtils.toString(entity, Consts.UTF_8);
}
} finally {
response.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
public int getStatusCode() {
return statusCode;
}
public String getContent() throws ParseException, IOException {
return content;
}
}
查詢是否支付成功
controller
/**
* 調用查詢訂單接口,查詢是否支付成功
* @param out_trade_no
* @return
*/
@RequestMapping("/queryPayStatus")
public Result queryPayStatus(String out_trade_no){
String username = SecurityContextHolder.getContext().getAuthentication().getName();
Result result = null;
int flag = 1;
while (true){
//1.判斷支付單號爲空
if (out_trade_no == null){
result = new Result(false,"二維碼超時");
break;
}
//2.調用查詢接口
Map map = payService.queryPayStatus(out_trade_no);
if ("SUCCESS".equals(map.get("trade_state"))){
result = new Result(true,"支付成功");
//3.如果支付成功,支付日誌表和訂單表的支付狀態改爲已支付,redis的支付日誌對象刪除
orderService.updatePayStatus(username);
break;
}
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
//如果5分鐘沒有支付,則支付超時
if (flag > 100){
result = new Result(false,"二維碼超時");
break;
}
flag++;
}
return result;
}
service
@Override
public Map queryPayStatus(String out_trade_no) {
Map param=new HashMap();
param.put("appid", appid);//公衆賬號ID
param.put("mch_id", partner);//商戶號
param.put("out_trade_no", out_trade_no);//訂單號
param.put("nonce_str", WXPayUtil.generateNonceStr());//隨機字符串
String url="https://api.mch.weixin.qq.com/pay/orderquery";
try {
String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);
HttpClient client=new HttpClient(url);
client.setHttps(true);
client.setXmlParam(xmlParam);
client.post();
String result = client.getContent();
Map<String, String> map = WXPayUtil.xmlToMap(result);
System.out.println(map);
return map;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}