|
@@ -1,46 +1,140 @@
|
|
|
package com.kym.miniapp.controller;
|
|
package com.kym.miniapp.controller;
|
|
|
|
|
|
|
|
import cn.dev33.satoken.annotation.SaIgnore;
|
|
import cn.dev33.satoken.annotation.SaIgnore;
|
|
|
|
|
+import com.kym.common.utils.HttpUtil;
|
|
|
|
|
+import com.kym.entity.User;
|
|
|
|
|
+import com.kym.entity.WashOrder;
|
|
|
|
|
+import com.kym.service.MpMsgTemplateService;
|
|
|
|
|
+import com.kym.service.UserService;
|
|
|
import com.kym.service.WashOrderService;
|
|
import com.kym.service.WashOrderService;
|
|
|
import com.kym.service.cache.KymCache;
|
|
import com.kym.service.cache.KymCache;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
|
|
+import java.net.URL;
|
|
|
|
|
+import java.util.UUID;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 停车优惠链接跳转
|
|
* 停车优惠链接跳转
|
|
|
* @author skyline
|
|
* @author skyline
|
|
|
* @since 2024-08-07
|
|
* @since 2024-08-07
|
|
|
*/
|
|
*/
|
|
|
|
|
+@Slf4j
|
|
|
@RestController
|
|
@RestController
|
|
|
@RequestMapping("/parking-coupon")
|
|
@RequestMapping("/parking-coupon")
|
|
|
public class ParkingCouponController {
|
|
public class ParkingCouponController {
|
|
|
|
|
|
|
|
- private final WashOrderService washOrderService;
|
|
|
|
|
|
|
+ private static final int MAX_REDIRECT_URL_LENGTH = 2000;
|
|
|
|
|
|
|
|
- public ParkingCouponController(WashOrderService washOrderService) {
|
|
|
|
|
|
|
+ private final WashOrderService washOrderService;
|
|
|
|
|
+ private final MpMsgTemplateService mpMsgTemplateService;
|
|
|
|
|
+ private final UserService userService;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${kym.domain}")
|
|
|
|
|
+ private String DOMAIN;
|
|
|
|
|
+
|
|
|
|
|
+ public ParkingCouponController(WashOrderService washOrderService,
|
|
|
|
|
+ MpMsgTemplateService mpMsgTemplateService,
|
|
|
|
|
+ UserService userService) {
|
|
|
this.washOrderService = washOrderService;
|
|
this.washOrderService = washOrderService;
|
|
|
|
|
+ this.mpMsgTemplateService = mpMsgTemplateService;
|
|
|
|
|
+ this.userService = userService;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 停车优惠链接跳转
|
|
|
|
|
+ */
|
|
|
|
|
+ @SaIgnore
|
|
|
|
|
+ @GetMapping
|
|
|
|
|
+ public void jump(HttpServletResponse response, @RequestParam String code) throws IOException {
|
|
|
|
|
+ var url = KymCache.INSTANCE.getParkingCouponUrl(code);
|
|
|
|
|
+ if (url == null || url.isEmpty()) {
|
|
|
|
|
+ response.setContentType("text/html; charset=utf-8");
|
|
|
|
|
+ response.getWriter().write("""
|
|
|
|
|
+ <!DOCTYPE html>
|
|
|
|
|
+ <html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
|
|
|
+ <title>链接已失效</title>
|
|
|
|
|
+ <style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f5}
|
|
|
|
|
+ .card{background:#fff;padding:32px 24px;border-radius:8px;text-align:center;box-shadow:0 2px 12px rgba(0,0,0,.08)}
|
|
|
|
|
+ h2{color:#e74c3c;margin:0 0 8px}p{color:#666;margin:0}</style>
|
|
|
|
|
+ </head><body><div class="card"><h2>链接已失效</h2><p>停车优惠券链接已过期或不存在,请联系客服</p></div></body></html>""");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (url.length() < MAX_REDIRECT_URL_LENGTH) {
|
|
|
|
|
+ response.sendRedirect(url);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // URL 过长时使用服务端代理,避免浏览器 GET 请求触发第三方服务器 414
|
|
|
|
|
+ try {
|
|
|
|
|
+ String content = HttpUtil.get(url);
|
|
|
|
|
+ String origin = extractOrigin(url);
|
|
|
|
|
+ content = content.replaceAll("(?i)<head([^>]*)>", "<head$1><base href=\"" + origin + "\">");
|
|
|
|
|
+ response.setContentType("text/html; charset=utf-8");
|
|
|
|
|
+ response.getWriter().write(content);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("代理停车券页面失败, url: {}", url, e);
|
|
|
|
|
+ response.sendRedirect(url);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 查询是否符合停车优惠
|
|
|
|
|
+ */
|
|
|
|
|
+ @SaIgnore
|
|
|
|
|
+ @GetMapping("/checkParkingCoupon")
|
|
|
|
|
+ public String checkParkingCoupon(@RequestParam String mobilePhone) {
|
|
|
|
|
+ return washOrderService.checkParkingCoupon(mobilePhone);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 停车优惠链接跳转
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ * [测试] 生成停车券短链接,返回 url 可直接在浏览器打开测试
|
|
|
|
|
+ */
|
|
|
@SaIgnore
|
|
@SaIgnore
|
|
|
- @GetMapping
|
|
|
|
|
- public void jump(HttpServletResponse response, @RequestParam String code) throws IOException {
|
|
|
|
|
- // 从缓存中获取链接并跳转
|
|
|
|
|
- var url = KymCache.INSTANCE.getParkingCouponUrl(code);
|
|
|
|
|
- response.sendRedirect(url);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * 查询是否符合停车优惠
|
|
|
|
|
- */
|
|
|
|
|
|
|
+ @GetMapping("/testLink")
|
|
|
|
|
+ public String testLink(@RequestParam String mobilePhone) {
|
|
|
|
|
+ return washOrderService.checkParkingCoupon(mobilePhone);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * [测试] 发送停车券微信模板消息,需要用户已关注公众号且有 mpOpenid
|
|
|
|
|
+ */
|
|
|
@SaIgnore
|
|
@SaIgnore
|
|
|
- @GetMapping("/checkParkingCoupon")
|
|
|
|
|
- public String checkParkingCoupon(@RequestParam String mobilePhone) {
|
|
|
|
|
- return washOrderService.checkParkingCoupon(mobilePhone);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ @GetMapping("/testSend")
|
|
|
|
|
+ public String testSend(@RequestParam String mobilePhone) {
|
|
|
|
|
+ var user = userService.lambdaQuery().eq(User::getMobilePhone, mobilePhone).one();
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ return "用户不存在: " + mobilePhone;
|
|
|
|
|
+ }
|
|
|
|
|
+ var orders = washOrderService.lambdaQuery()
|
|
|
|
|
+ .eq(WashOrder::getUserId, user.getId())
|
|
|
|
|
+ .eq(WashOrder::getPayStatus, WashOrder.PAY_STATUS_已支付)
|
|
|
|
|
+ .orderByDesc(WashOrder::getId)
|
|
|
|
|
+ .list();
|
|
|
|
|
+ if (orders.isEmpty()) {
|
|
|
|
|
+ return "该用户没有已支付订单,无法构造模板消息参数";
|
|
|
|
|
+ }
|
|
|
|
|
+ var washOrder = orders.get(0);
|
|
|
|
|
+ var parkingCouponUrl = KymCache.INSTANCE.getParkingQrCodeUrlByStationId(washOrder.getStationId());
|
|
|
|
|
+ var code = UUID.randomUUID().toString();
|
|
|
|
|
+ KymCache.INSTANCE.setParkingCouponCode(code, parkingCouponUrl, 3600 * 2L);
|
|
|
|
|
+ var url = DOMAIN + "/api/parking-coupon?code=" + code;
|
|
|
|
|
+ mpMsgTemplateService.sendParkingCouponMsg(washOrder, url);
|
|
|
|
|
+ return "已发送, url=" + url;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static String extractOrigin(String url) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ URL u = new URL(url);
|
|
|
|
|
+ int port = u.getPort();
|
|
|
|
|
+ return u.getProtocol() + "://" + u.getHost() + (port > 0 ? ":" + port : "") + "/";
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return url;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
}
|
|
}
|