Compare commits
2 Commits
ddb78e29a3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7838f84e81 | |||
| a7e57e63a9 |
7
pom.xml
7
pom.xml
@@ -18,6 +18,7 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -62,6 +63,12 @@
|
||||
<!-- <artifactId>gson</artifactId>-->
|
||||
<!-- <version>2.10.1</version>-->
|
||||
<!-- </dependency>-->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>4.40.806.ALL</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
27
src/main/java/com/ping/study/config/AlipayConfig.java
Normal file
27
src/main/java/com/ping/study/config/AlipayConfig.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package com.ping.study.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "alipay")
|
||||
public class AlipayConfig {
|
||||
|
||||
private String gatewayUrl;
|
||||
|
||||
private String appId;
|
||||
|
||||
private String privateKey;
|
||||
|
||||
private String alipayPublicKey;
|
||||
|
||||
private String notifyUrl;
|
||||
|
||||
private String charset;
|
||||
|
||||
private String format;
|
||||
|
||||
private String signType;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class WebMvc implements WebMvcConfigurer {
|
||||
.allowedOrigins("http://jrs77.xyz","https://jrs77.xyz",
|
||||
"http://localhost:5173", "https://nba.1024x.icu",
|
||||
"http://nba.1024x.icu","http://167.253.156.235:9006",
|
||||
"http://116.62.173.2:9001")
|
||||
"http://116.62.173.2:9001","http://dns.1024x.icu:9005")
|
||||
.allowedMethods("GET","POST","PUT","DELETE","OPTIONS")
|
||||
.allowedHeaders("X-Timestamp","X-Sign","*")
|
||||
.allowCredentials(true) // 若不用 Cookie 也可为 false
|
||||
|
||||
@@ -143,10 +143,10 @@ public class NbaController {
|
||||
if (loginUser == null){
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body("请先登录");
|
||||
}
|
||||
log.info("{}:获取直播链接开始",loginUser.getEmail());
|
||||
// log.info("{}:获取直播链接开始",loginUser.getEmail());
|
||||
String ip = userUtil.getClientIp(request);
|
||||
String url = urlsService.findUrlByGameIdAndType(gameId, playType);
|
||||
// log.info("来自ip:{} 用户:{}:获取直播链接成功:{}",ip,loginUser.getEmail(),url);
|
||||
log.info("来自ip:{} 用户:{}:获取直播链接成功:{}",ip,loginUser.getEmail(),url);
|
||||
return ResponseEntity.ok(url);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.ping.study.controller.pay;
|
||||
|
||||
import com.ping.study.config.AlipayConfig;
|
||||
import com.ping.study.model.dto.pay.CreateRewardOrderDto;
|
||||
import com.ping.study.model.vo.pay.AlipayQrCodeVo;
|
||||
import com.ping.study.model.vo.pay.PayOrderStatusVo;
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
import com.ping.study.service.pay.AlipayService;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/pay/alipay")
|
||||
@Slf4j
|
||||
public class AlipayController {
|
||||
|
||||
private final AlipayService alipayService;
|
||||
private final AlipayConfig alipayConfig;
|
||||
|
||||
public AlipayController(AlipayService alipayService, AlipayConfig alipayConfig) {
|
||||
this.alipayService = alipayService;
|
||||
this.alipayConfig = alipayConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付宝打赏二维码订单。
|
||||
* 当前允许匿名打赏;如果用户已登录,会自动绑定 userId。
|
||||
*/
|
||||
@PostMapping("/reward/create")
|
||||
public AlipayQrCodeVo createRewardOrder(@Valid @RequestBody CreateRewardOrderDto dto, HttpSession session) throws Exception {
|
||||
NbaUser loginUser = (NbaUser) session.getAttribute("loginUser");
|
||||
return alipayService.createRewardOrder(dto, loginUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝异步通知。
|
||||
* 注意:该接口必须公网可访问,且不能要求登录。支付宝要求处理成功后返回纯文本 success。
|
||||
*/
|
||||
@PostMapping("/notify")
|
||||
public String notify(HttpServletRequest request) throws Exception {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
Map<String, String[]> requestParams = request.getParameterMap();
|
||||
for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
|
||||
String[] values = entry.getValue();
|
||||
if (values != null && values.length > 0) {
|
||||
params.put(entry.getKey(), values[0]);
|
||||
}
|
||||
}
|
||||
log.info("收到支付宝异步通知,orderNo={}, tradeStatus={}", params.get("out_trade_no"), params.get("trade_status"));
|
||||
return alipayService.handleNotify(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端展示二维码后可轮询该接口获取支付状态。
|
||||
*/
|
||||
@GetMapping("/status/{orderNo}")
|
||||
public PayOrderStatusVo queryOrderStatus(@PathVariable String orderNo) {
|
||||
return alipayService.queryOrderStatus(orderNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于前端或部署后快速确认 notifyUrl 是否配置正确。
|
||||
*/
|
||||
@GetMapping("/config/notify-url")
|
||||
public String notifyUrl() {
|
||||
return alipayConfig.getNotifyUrl();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.ping.study.controller.user;
|
||||
|
||||
|
||||
import com.ping.study.mapper.PayOrderMapper;
|
||||
import com.ping.study.model.dto.DtoUpdateUser;
|
||||
import com.ping.study.model.dto.registerUserDto;
|
||||
|
||||
import com.ping.study.model.vo.user.CurrentUserVo;
|
||||
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
import com.ping.study.service.NbaUserService;
|
||||
import com.ping.study.utils.MailUtil;
|
||||
@@ -38,6 +41,9 @@ public class UserController {
|
||||
@Autowired
|
||||
private UserUtil userUtil;
|
||||
|
||||
@Autowired
|
||||
private PayOrderMapper payOrderMapper;
|
||||
|
||||
//发送验证码
|
||||
@RequestMapping("/send")
|
||||
public String send(String email,Integer type) {
|
||||
@@ -124,7 +130,7 @@ public class UserController {
|
||||
// 1. session 已登录
|
||||
NbaUser loginUser = (NbaUser) session.getAttribute("loginUser");
|
||||
if (loginUser != null) {
|
||||
return loginUser.getEmail();
|
||||
return buildCurrentUserVo(loginUser);
|
||||
}
|
||||
|
||||
// 2. 尝试自动登录(记住我)
|
||||
@@ -136,12 +142,17 @@ public class UserController {
|
||||
session.setAttribute("loginUser", user);
|
||||
|
||||
log.info("自动登录成功 -> {}", user.getEmail());
|
||||
return user.getEmail();
|
||||
return buildCurrentUserVo(user);
|
||||
}
|
||||
}
|
||||
return "未登录";
|
||||
}
|
||||
|
||||
private CurrentUserVo buildCurrentUserVo(NbaUser user) {
|
||||
int rewardUser = payOrderMapper.countSuccessRewardByUserId(Long.valueOf(user.getId())) > 0 ? 1 : 0;
|
||||
return new CurrentUserVo(user.getEmail(), rewardUser);
|
||||
}
|
||||
|
||||
// 退出登录(清 session + 清 token + 清 cookie)
|
||||
@PostMapping("/logout")
|
||||
public String logout(
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.ping.study.mapper;
|
||||
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
* @description 针对表【nba_user】的数据库操作Mapper
|
||||
@@ -35,4 +37,6 @@ public interface NbaUserMapper {
|
||||
NbaUser selectByEmail(String email);
|
||||
|
||||
void updatePasswordByEmail(String email, String password);
|
||||
|
||||
List<String> selectAllUserEmail();
|
||||
}
|
||||
|
||||
24
src/main/java/com/ping/study/mapper/PayOrderMapper.java
Normal file
24
src/main/java/com/ping/study/mapper/PayOrderMapper.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package com.ping.study.mapper;
|
||||
|
||||
import com.ping.study.pojo.PayOrder;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface PayOrderMapper {
|
||||
|
||||
int insert(PayOrder record);
|
||||
|
||||
PayOrder selectByOrderNo(@Param("orderNo") String orderNo);
|
||||
|
||||
int updateQrCodeAndStatus(@Param("orderNo") String orderNo,
|
||||
@Param("qrCode") String qrCode,
|
||||
@Param("status") String status);
|
||||
|
||||
int updatePaidByOrderNo(@Param("orderNo") String orderNo,
|
||||
@Param("alipayTradeNo") String alipayTradeNo,
|
||||
@Param("status") String status);
|
||||
|
||||
int updateStatusByOrderNo(@Param("orderNo") String orderNo,
|
||||
@Param("status") String status);
|
||||
|
||||
int countSuccessRewardByUserId(@Param("userId") Long userId);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ping.study.model.dto.pay;
|
||||
|
||||
import jakarta.validation.constraints.DecimalMin;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class CreateRewardOrderDto {
|
||||
|
||||
@NotNull(message = "打赏金额不能为空")
|
||||
@DecimalMin(value = "0.01", message = "打赏金额不能小于0.01元")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@Size(max = 128, message = "打赏备注不能超过128个字符")
|
||||
private String subject;
|
||||
|
||||
@Size(max = 500, message = "留言不能超过500个字符")
|
||||
private String liuyan;
|
||||
}
|
||||
@@ -16,5 +16,6 @@ public class LiveUrl {
|
||||
private Integer id;
|
||||
private String type;
|
||||
private String url;
|
||||
private String m3u8_url;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ping.study.model.vo.pay;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AlipayQrCodeVo {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private String qrCode;
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ping.study.model.vo.pay;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PayOrderStatusVo {
|
||||
|
||||
private String orderNo;
|
||||
|
||||
private String status;
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
private String alipayTradeNo;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.ping.study.model.vo.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CurrentUserVo {
|
||||
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 是否为赞赏用户:1 是,0 否
|
||||
*/
|
||||
private Integer rewardUser;
|
||||
}
|
||||
59
src/main/java/com/ping/study/pojo/PayOrder.java
Normal file
59
src/main/java/com/ping/study/pojo/PayOrder.java
Normal file
@@ -0,0 +1,59 @@
|
||||
package com.ping.study.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class PayOrder implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 商户订单号
|
||||
*/
|
||||
private String orderNo;
|
||||
|
||||
/**
|
||||
* 登录用户ID,匿名打赏时为空
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 订单标题/打赏备注
|
||||
*/
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* 打赏留言
|
||||
*/
|
||||
private String liuyan;
|
||||
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
/**
|
||||
* WAIT_PAY / SUCCESS / CLOSED / FAILED
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 支付宝交易号
|
||||
*/
|
||||
private String alipayTradeNo;
|
||||
|
||||
/**
|
||||
* 支付宝返回的二维码链接
|
||||
*/
|
||||
private String qrCode;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private Date updateTime;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import com.ping.study.model.dto.DtoUpdateUser;
|
||||
import com.ping.study.model.dto.registerUserDto;
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
* @description 针对表【nba_user】的数据库操作Service
|
||||
@@ -24,4 +26,6 @@ public interface NbaUserService{
|
||||
String updateUser(DtoUpdateUser dtoUpdateUser);
|
||||
|
||||
NbaUser findByEmail(String email);
|
||||
|
||||
List<String> selectAllUserEmail();
|
||||
}
|
||||
|
||||
@@ -8,15 +8,14 @@ import com.ping.study.pojo.LoginLog;
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
import com.ping.study.service.NbaUserService;
|
||||
|
||||
import com.ping.study.utils.UserUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -109,4 +108,10 @@ public class NbaUserServiceImpl implements NbaUserService {
|
||||
return nbaUserMapper.findByEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> selectAllUserEmail() {
|
||||
List<String> emailList = nbaUserMapper.selectAllUserEmail();
|
||||
return emailList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.ping.study.mapper.UrlsMapper;
|
||||
import com.ping.study.model.dto.addUrls;
|
||||
import com.ping.study.model.vo.live.LiveUrl;
|
||||
import com.ping.study.service.UrlsService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
@@ -15,6 +16,7 @@ import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UrlsServiceImpl implements UrlsService {
|
||||
|
||||
@Autowired
|
||||
@@ -73,6 +75,7 @@ public class UrlsServiceImpl implements UrlsService {
|
||||
|
||||
@Override
|
||||
public void addUrls(addUrls addUrls) {
|
||||
log.info("addUrls:{}",addUrls);
|
||||
urlsMapper.insertUrlsWithGameId(addUrls.getGameId(), addUrls.getUrls());
|
||||
//删除redis缓存
|
||||
redisTemplate.delete("live:urls:all");
|
||||
|
||||
17
src/main/java/com/ping/study/service/pay/AlipayService.java
Normal file
17
src/main/java/com/ping/study/service/pay/AlipayService.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.ping.study.service.pay;
|
||||
|
||||
import com.ping.study.model.dto.pay.CreateRewardOrderDto;
|
||||
import com.ping.study.model.vo.pay.AlipayQrCodeVo;
|
||||
import com.ping.study.model.vo.pay.PayOrderStatusVo;
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface AlipayService {
|
||||
|
||||
AlipayQrCodeVo createRewardOrder(CreateRewardOrderDto dto, NbaUser loginUser) throws Exception;
|
||||
|
||||
String handleNotify(Map<String, String> params) throws Exception;
|
||||
|
||||
PayOrderStatusVo queryOrderStatus(String orderNo);
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.ping.study.service.pay.impl;
|
||||
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import com.alipay.api.internal.util.AlipaySignature;
|
||||
import com.alipay.api.request.AlipayTradePrecreateRequest;
|
||||
import com.alipay.api.response.AlipayTradePrecreateResponse;
|
||||
import com.alipay.api.domain.AlipayTradePrecreateModel;
|
||||
import com.ping.study.config.AlipayConfig;
|
||||
import com.ping.study.mapper.PayOrderMapper;
|
||||
import com.ping.study.model.dto.pay.CreateRewardOrderDto;
|
||||
import com.ping.study.model.vo.pay.AlipayQrCodeVo;
|
||||
import com.ping.study.model.vo.pay.PayOrderStatusVo;
|
||||
import com.ping.study.pojo.NbaUser;
|
||||
import com.ping.study.pojo.PayOrder;
|
||||
import com.ping.study.service.pay.AlipayService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AlipayServiceImpl implements AlipayService {
|
||||
|
||||
private static final String STATUS_WAIT_PAY = "WAIT_PAY";
|
||||
private static final String STATUS_SUCCESS = "SUCCESS";
|
||||
private static final String STATUS_FAILED = "FAILED";
|
||||
|
||||
private final AlipayConfig alipayConfig;
|
||||
private final PayOrderMapper payOrderMapper;
|
||||
|
||||
public AlipayServiceImpl(AlipayConfig alipayConfig, PayOrderMapper payOrderMapper) {
|
||||
this.alipayConfig = alipayConfig;
|
||||
this.payOrderMapper = payOrderMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AlipayQrCodeVo createRewardOrder(CreateRewardOrderDto dto, NbaUser loginUser) throws Exception {
|
||||
BigDecimal totalAmount = dto.getTotalAmount().setScale(2, RoundingMode.HALF_UP);
|
||||
String subject = StringUtils.hasText(dto.getSubject()) ? dto.getSubject() : "NBA赛事平台打赏";
|
||||
String liuyan = StringUtils.hasText(dto.getLiuyan()) ? dto.getLiuyan() : null;
|
||||
String orderNo = generateOrderNo();
|
||||
|
||||
PayOrder order = new PayOrder();
|
||||
order.setOrderNo(orderNo);
|
||||
order.setUserId(loginUser == null ? null : Long.valueOf(loginUser.getId()));
|
||||
order.setSubject(subject);
|
||||
order.setLiuyan(liuyan);
|
||||
order.setTotalAmount(totalAmount);
|
||||
order.setStatus(STATUS_WAIT_PAY);
|
||||
order.setCreateTime(new Date());
|
||||
order.setUpdateTime(new Date());
|
||||
payOrderMapper.insert(order);
|
||||
|
||||
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
|
||||
request.setNotifyUrl(alipayConfig.getNotifyUrl());
|
||||
|
||||
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
|
||||
model.setOutTradeNo(orderNo);
|
||||
model.setTotalAmount(totalAmount.toPlainString());
|
||||
model.setSubject(subject);
|
||||
model.setTimeoutExpress("30m");
|
||||
request.setBizModel(model);
|
||||
|
||||
AlipayTradePrecreateResponse response = buildAlipayClient().execute(request);
|
||||
if (response.isSuccess()) {
|
||||
String qrCode = response.getQrCode();
|
||||
payOrderMapper.updateQrCodeAndStatus(orderNo, qrCode, STATUS_WAIT_PAY);
|
||||
return new AlipayQrCodeVo(orderNo, qrCode, totalAmount, STATUS_WAIT_PAY);
|
||||
}
|
||||
|
||||
payOrderMapper.updateStatusByOrderNo(orderNo, STATUS_FAILED);
|
||||
log.error("支付宝预下单失败,orderNo={}, code={}, subCode={}, msg={}, subMsg={}",
|
||||
orderNo, response.getCode(), response.getSubCode(), response.getMsg(), response.getSubMsg());
|
||||
throw new RuntimeException("支付宝预下单失败:" + response.getSubMsg());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String handleNotify(Map<String, String> params) throws Exception {
|
||||
boolean signVerified = AlipaySignature.rsaCheckV1(
|
||||
params,
|
||||
alipayConfig.getAlipayPublicKey(),
|
||||
alipayConfig.getCharset(),
|
||||
alipayConfig.getSignType()
|
||||
);
|
||||
|
||||
if (!signVerified) {
|
||||
log.warn("支付宝异步通知验签失败:{}", params);
|
||||
return "failure";
|
||||
}
|
||||
|
||||
String tradeStatus = params.get("trade_status");
|
||||
String outTradeNo = params.get("out_trade_no");
|
||||
String tradeNo = params.get("trade_no");
|
||||
String totalAmount = params.get("total_amount");
|
||||
String appId = params.get("app_id");
|
||||
|
||||
if (!Objects.equals(appId, alipayConfig.getAppId())) {
|
||||
log.warn("支付宝异步通知app_id不匹配,orderNo={}, notifyAppId={}", outTradeNo, appId);
|
||||
return "failure";
|
||||
}
|
||||
|
||||
PayOrder order = payOrderMapper.selectByOrderNo(outTradeNo);
|
||||
if (order == null) {
|
||||
log.warn("支付宝异步通知订单不存在,orderNo={}", outTradeNo);
|
||||
return "failure";
|
||||
}
|
||||
|
||||
if (!amountEquals(order.getTotalAmount(), new BigDecimal(totalAmount))) {
|
||||
log.warn("支付宝异步通知金额不匹配,orderNo={}, localAmount={}, notifyAmount={}",
|
||||
outTradeNo, order.getTotalAmount(), totalAmount);
|
||||
return "failure";
|
||||
}
|
||||
|
||||
if (STATUS_SUCCESS.equals(order.getStatus())) {
|
||||
return "success";
|
||||
}
|
||||
|
||||
if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
|
||||
payOrderMapper.updatePaidByOrderNo(outTradeNo, tradeNo, STATUS_SUCCESS);
|
||||
log.info("支付宝打赏支付成功,orderNo={}, tradeNo={}, amount={}", outTradeNo, tradeNo, totalAmount);
|
||||
}
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayOrderStatusVo queryOrderStatus(String orderNo) {
|
||||
PayOrder order = payOrderMapper.selectByOrderNo(orderNo);
|
||||
if (order == null) {
|
||||
throw new RuntimeException("订单不存在");
|
||||
}
|
||||
return new PayOrderStatusVo(order.getOrderNo(), order.getStatus(), order.getTotalAmount(), order.getAlipayTradeNo());
|
||||
}
|
||||
|
||||
private AlipayClient buildAlipayClient() {
|
||||
return new DefaultAlipayClient(
|
||||
alipayConfig.getGatewayUrl(),
|
||||
alipayConfig.getAppId(),
|
||||
alipayConfig.getPrivateKey(),
|
||||
alipayConfig.getFormat(),
|
||||
alipayConfig.getCharset(),
|
||||
alipayConfig.getAlipayPublicKey(),
|
||||
alipayConfig.getSignType()
|
||||
);
|
||||
}
|
||||
|
||||
private String generateOrderNo() {
|
||||
String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
|
||||
String random = UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase();
|
||||
return "REWARD" + time + random;
|
||||
}
|
||||
|
||||
private boolean amountEquals(BigDecimal localAmount, BigDecimal notifyAmount) {
|
||||
return localAmount.setScale(2, RoundingMode.HALF_UP)
|
||||
.compareTo(notifyAmount.setScale(2, RoundingMode.HALF_UP)) == 0;
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,11 @@ import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.mail.MailAuthenticationException;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.mail.javamail.JavaMailSender;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -27,10 +28,12 @@ public class MailUtil {
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
private final JavaMailSender javaMailSender;
|
||||
private final String fromAddress;
|
||||
|
||||
@Autowired
|
||||
public MailUtil(JavaMailSender javaMailSender) {
|
||||
public MailUtil(JavaMailSender javaMailSender, @Value("${spring.mail.username}") String fromAddress) {
|
||||
this.javaMailSender = javaMailSender;
|
||||
this.fromAddress = fromAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +59,7 @@ public class MailUtil {
|
||||
String verificationCode = generateVerificationCode();
|
||||
// 构造邮件
|
||||
SimpleMailMessage message = new SimpleMailMessage();
|
||||
message.setFrom("xdd9@vip.qq.com");
|
||||
message.setFrom(fromAddress);
|
||||
message.setTo(to);
|
||||
message.setSubject("【NBA轻松看验证码】");
|
||||
message.setText("您的验证码是:" + verificationCode + ",有效期 5 分钟"+"。请勿回复此邮件。"+"\n反馈邮箱:super@2026123.xyz"+"\n发布页:2026123.xyz");
|
||||
@@ -87,25 +90,74 @@ public class MailUtil {
|
||||
* @param text 邮件内容
|
||||
*/
|
||||
public String sendEmail2(String to,String subject,String text) {
|
||||
Assert.hasText(to, "邮箱不能为空");
|
||||
SendMailResult result = sendEmailResult(to, subject, text);
|
||||
return result.isSuccess() ? "发送成功" : "发送邮件失败";
|
||||
}
|
||||
|
||||
public SendMailResult sendEmailResult(String to, String subject, String text) {
|
||||
Assert.hasText(to, "邮箱不能为空");
|
||||
Assert.hasText(subject, "邮件主题不能为空");
|
||||
Assert.hasText(text, "邮件内容不能为空");
|
||||
|
||||
// 构造邮件
|
||||
SimpleMailMessage message = new SimpleMailMessage();
|
||||
message.setFrom("xdd9@vip.qq.com");
|
||||
message.setFrom(fromAddress);
|
||||
message.setTo(to);
|
||||
message.setSubject(subject);
|
||||
message.setText(text);
|
||||
// message.setText("发布页:2026123.xyz");
|
||||
// 发送邮件
|
||||
|
||||
try {
|
||||
javaMailSender.send(message);
|
||||
return "发送成功";
|
||||
// return verificationCode;
|
||||
}catch (Exception e){
|
||||
log.info("发送邮件失败:{}", e.getMessage());
|
||||
return "发送邮件失败";
|
||||
javaMailSender.send(message);
|
||||
return SendMailResult.success();
|
||||
} catch (Exception e) {
|
||||
boolean authenticationFailure = isAuthenticationFailure(e);
|
||||
log.info("发送邮件失败:{},原因:{}", to, e.getMessage(), e);
|
||||
return SendMailResult.failure(authenticationFailure, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAuthenticationFailure(Throwable throwable) {
|
||||
while (throwable != null) {
|
||||
if (throwable instanceof MailAuthenticationException
|
||||
|| throwable.getClass().getName().contains("AuthenticationFailedException")) {
|
||||
return true;
|
||||
}
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class SendMailResult {
|
||||
private final boolean success;
|
||||
private final boolean authenticationFailure;
|
||||
private final String message;
|
||||
|
||||
private SendMailResult(boolean success, boolean authenticationFailure, String message) {
|
||||
this.success = success;
|
||||
this.authenticationFailure = authenticationFailure;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public static SendMailResult success() {
|
||||
return new SendMailResult(true, false, "发送成功");
|
||||
}
|
||||
|
||||
public static SendMailResult failure(boolean authenticationFailure, String message) {
|
||||
return new SendMailResult(false, authenticationFailure, message);
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public boolean isAuthenticationFailure() {
|
||||
return authenticationFailure;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param map
|
||||
@@ -115,7 +167,7 @@ public class MailUtil {
|
||||
|
||||
// 构造邮件
|
||||
SimpleMailMessage message = new SimpleMailMessage();
|
||||
message.setFrom("xdd9@vip.qq.com");
|
||||
message.setFrom(fromAddress);
|
||||
message.setTo(map.get("mail"));
|
||||
message.setSubject(map.get("subject"));
|
||||
message.setText(map.get("text"));
|
||||
@@ -130,13 +182,14 @@ public class MailUtil {
|
||||
* @param subject 邮件主题
|
||||
* @param html HTML 内容
|
||||
*/
|
||||
public void sendHtmlEmail(String to, String subject, String html) throws MessagingException, jakarta.mail.MessagingException {
|
||||
public void sendHtmlEmail(String to, String subject, String html) throws MessagingException, MessagingException {
|
||||
Assert.hasText(to, "邮箱不能为空");
|
||||
Assert.hasText(subject, "邮件主题不能为空");
|
||||
Assert.hasText(html, "HTML 内容不能为空");
|
||||
|
||||
jakarta.mail.internet.MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setFrom(fromAddress);
|
||||
helper.setTo(to);
|
||||
helper.setSubject(subject);
|
||||
helper.setText(html, true); // true 表示支持 HTML
|
||||
@@ -151,14 +204,15 @@ public class MailUtil {
|
||||
* @param text 邮件内容
|
||||
* @param attachments 附件文件列表
|
||||
*/
|
||||
public void sendEmailWithAttachments(String to, String subject, String text, List<File> attachments) throws MessagingException, jakarta.mail.MessagingException {
|
||||
public void sendEmailWithAttachments(String to, String subject, String text, List<File> attachments) throws MessagingException, MessagingException {
|
||||
Assert.hasText(to, "收件人邮箱不能为空");
|
||||
Assert.hasText(subject, "邮件主题不能为空");
|
||||
Assert.hasText(text, "邮件内容不能为空");
|
||||
Assert.notEmpty(attachments, "附件列表不能为空");
|
||||
|
||||
jakarta.mail.internet.MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setFrom(fromAddress);
|
||||
helper.setTo(to);
|
||||
helper.setSubject(subject);
|
||||
helper.setText(text);
|
||||
@@ -179,7 +233,7 @@ public class MailUtil {
|
||||
* @param html HTML 内容
|
||||
* @param inlineFiles 内联资源文件列表
|
||||
*/
|
||||
public void sendHtmlEmailWithInline(String to, String subject, String html, List<File> inlineFiles) throws MessagingException, jakarta.mail.MessagingException {
|
||||
public void sendHtmlEmailWithInline(String to, String subject, String html, List<File> inlineFiles) throws MessagingException, MessagingException {
|
||||
Assert.hasText(to, "收件人邮箱不能为空");
|
||||
Assert.hasText(subject, "邮件主题不能为空");
|
||||
Assert.hasText(html, "HTML 内容不能为空");
|
||||
@@ -187,6 +241,7 @@ public class MailUtil {
|
||||
|
||||
MimeMessage message = javaMailSender.createMimeMessage();
|
||||
MimeMessageHelper helper = new MimeMessageHelper(message, true);
|
||||
helper.setFrom(fromAddress);
|
||||
helper.setTo(to);
|
||||
helper.setSubject(subject);
|
||||
helper.setText(html, true);
|
||||
|
||||
@@ -29,8 +29,8 @@ spring:
|
||||
name: NBA
|
||||
datasource:
|
||||
#mysql5.7.4配置
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/nba?useUnicode=true&characterEncoding=utf-8&useSSL=false
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://localhost:3306/nba?useSSL=true&trustServerCertificate=true&serverTimezone=UTC
|
||||
# url: jdbc:mysql://116.62.173.2:3306/nba?useUnicode=true&characterEncoding=utf-8&useSSL=false
|
||||
# url: jdbc:mysql://154.36.154.211:9002/nba?useUnicode=true&characterEncoding=utf-8&useSSL=false
|
||||
username: root
|
||||
@@ -43,24 +43,32 @@ spring:
|
||||
mail:
|
||||
host: smtp.qq.com
|
||||
port: 465
|
||||
username: xdd9@vip.qq.com
|
||||
password: qhcladjicfydbejj
|
||||
username: ${MAIL_USERNAME:xdd9@vip.qq.com}
|
||||
password: ${MAIL_PASSWORD:qhcladjicfydbejj}
|
||||
default-encoding: UTF-8
|
||||
properties:
|
||||
mail.smtp.auth: true
|
||||
mail.smtp.ssl.enable: true
|
||||
mail.smtp.ssl.trust: smtp.qq.com
|
||||
mail.smtp.starttls.enable: false
|
||||
mail.smtp.starttls.required: false
|
||||
mail.smtp.connectiontimeout: 5000 # 连接超时 5 秒
|
||||
mail.smtp.timeout: 5000 # 读超时 5 秒
|
||||
mail.smtp.writetimeout: 5000 # 写超时 5 秒
|
||||
mail:
|
||||
smtp:
|
||||
auth: true
|
||||
ssl:
|
||||
enable: true
|
||||
starttls:
|
||||
enable: true
|
||||
required: true
|
||||
mybatis:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
|
||||
type-aliases-package: com.ping.study.pojo
|
||||
mapper-locations: classpath:mapper/*.xml
|
||||
mapper-locations: classpath:mapper/*.xml
|
||||
alipay:
|
||||
# 沙箱网关:https://openapi-sandbox.dl.alipaydev.com/gateway.do
|
||||
# 正式网关:https://openapi.alipay.com/gateway.do
|
||||
gateway-url: ${ALIPAY_GATEWAY_URL:https://openapi.alipay.com/gateway.do}
|
||||
app-id: ${ALIPAY_APP_ID:2021002176680273}
|
||||
private-key: ${ALIPAY_PRIVATE_KEY:MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDuAjvOJA0WdAkKIJu/TVUqjtA7eSB1HjYpfPWSRB1wE7N+J5Wf8aw9ieI9UIlaO5KzhL6+fRy6hKtZoFtVZarKhSmbZhL3ccgP3ulK5FZwe6UgqQi13J9Akr8sRy/XTBrRmPyntjktKTO8830K5s5it1KT5einVWf4T976WQnyz0/MQ2dMT0Cpatl+d8LYZeeGrW7tlpKY+dEBORLF+nI2OXCakeprnAPcDjqEccdLcA8rwVyduDJrrJwhp/tKmOPjzG/B7GOciv9M/N6IXHmQJbqQDy6Qgku+ALuvu9HJsdWZuetv8K9nX7ofJhdApKZLYBiap7GrMrDK5QwtMANXAgMBAAECggEATzp/HgfyM189AxoHvo7HovsXZjTUESiVbwoh1SbHhd+JCJ20uSGB7JpRrYd5sYfTNd8if9a2EYDIaXVv8eV+DRx21TwNZEGED4RstHl+LMN8HHsoYyGmAaDX8q1fx5OV+d+re0i1j8r/Zg7HuTFL0qCj5IfMAqfzjD1KRJwPK7wit6nNTn9t6RPQRo0QHSazkGjoHKAcYkKTxor9D6HKVU/fQnoI6Hu6bnsTC7VXSY28am+Is79z0cvMc4n3PpBQBdA2VRKowc0frBkusDLhdMvWrvCOgRsKtgrbvZRT3qo+YJdPC5QKokslVlY3nC51dCWxAfR9YQyBEXWIGOBOgQKBgQD9MoQroPOSRN5TwfDLRDZYEL+tzeVTkDXKum40vca3WL9mT5Xuq1NVv9kHQzfmpmTEphsqZX0qjN9Vteic5J644jHVq1gP/xC75U81Lk74KwI/2/OU4YjxZrZU+zksGLUZxrk6ZkvHu4uvamf0hMTv0ThHXWaNc26fcYIPe5RQfwKBgQDwpK1uo/rv6Y0R3ZpSPLULMyFhTiiNBHWpO3Ks53PrCLpKqhDIvzJltLEZQ/Gm1HyHihvhQo4dupH3SoizQY76ZoSWFVjttRC6tQWvP+/SOeS6scUTm+YoStVpJAjHc51L5AV7xqyfsBQp2wCfv6bOAm05ojNZeXT/0Xh3aJFhKQKBgCbkop7dC201fP1atjVTFhHzCK6XCRoL9eddOd6KJEM3s7bwlLRjxtpOLPVLowOgHayDY3rguhhWKVxOJBwtliAKRuNufYl/gb+LGt6tbV37pU3P6Ju/BT0nrOxi5sZaST9bYkqROiTFL1DTxIIv/txjxARaWY1y5NRDKFpefkrbAoGAZ4VgOoV+cPDWyAW92nzVIVFIndSCq09s0nWJeopDGqvxgCcy+zkNFCWsPgM1lKA6RhCKt9fqzS0yl+BPeFXOjTfG982NKQ1IehlfralioNxY4luRPUNGurSepBFlWXAKDdi05y9rmXKk6fCVjyNiPaNbm3yEfIw8YcSZ/zxTtikCgYBMQAUvZrsgeHj0RXIBY2HPHOjjB/lpAXwvjkjeHInjnDUP2jbY2SJxmU2kn37QnjayvTCdMtDDdEcAajyXMJ7RC8uICIRXLVckx1JJvyEnogsaucPVAm4CbXRDaFNc8R+HoO+LbWE3c6gHY3mL8nNYUTdzkOULfCVvUy2vr/lKMg==}
|
||||
alipay-public-key: ${ALIPAY_PUBLIC_KEY:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh8inNmeH0tPN5U4AW1+o7EJjaDqLs+gk+4ZnBX/ZkgOldB7NAeXCPzzANNyNYih7cR/M0DnwoH9URm4m4b3fKRlYq18/SrxG0jF6wISMhgc3EMQRBzQ3mkn5Szs/YEwrg/UjcAleLbKl89eDRneXrHv6R6ArFgkwPNtsVCac3P0yEu6F+pCLDsKCDQQIOWUbnjKvOFUebh53nXVnUIGSiWC9fYS7KpdM2JetjnD+u9lH4b/7RlM/R06+K3cPZx6LmANksFfH8gO/dtwaklavNq1KnSVCjgnejocj8zEi2PRmOEZpTHqM+T/0dMCN4zvwji/xoQ8sLV3ywm52o9Ew7wIDAQAB}
|
||||
notify-url: ${ALIPAY_NOTIFY_URL:https://api9.jrs77.xyz/pay/alipay/notify}
|
||||
charset: UTF-8
|
||||
format: JSON
|
||||
sign-type: RSA2
|
||||
|
||||
@@ -136,4 +136,10 @@
|
||||
update nba_user set password = #{password} where email = #{email}
|
||||
</update>
|
||||
|
||||
<select id="selectAllUserEmail">
|
||||
select email from nba_user where email is not null
|
||||
-- select email from nba_user where email like "113130%"
|
||||
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
69
src/main/resources/mapper/PayOrderMapper.xml
Normal file
69
src/main/resources/mapper/PayOrderMapper.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ping.study.mapper.PayOrderMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.ping.study.pojo.PayOrder">
|
||||
<id property="id" column="id"/>
|
||||
<result property="orderNo" column="order_no"/>
|
||||
<result property="userId" column="user_id"/>
|
||||
<result property="subject" column="subject"/>
|
||||
<result property="liuyan" column="liuyan"/>
|
||||
<result property="totalAmount" column="total_amount"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="alipayTradeNo" column="alipay_trade_no"/>
|
||||
<result property="qrCode" column="qr_code"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id, order_no, user_id, subject, liuyan, total_amount, status, alipay_trade_no, qr_code, create_time, update_time
|
||||
</sql>
|
||||
|
||||
<insert id="insert" parameterType="com.ping.study.pojo.PayOrder" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
|
||||
insert into pay_order
|
||||
(order_no, user_id, subject, liuyan, total_amount, status, alipay_trade_no, qr_code, create_time, update_time)
|
||||
values
|
||||
(#{orderNo}, #{userId}, #{subject}, #{liuyan}, #{totalAmount}, #{status}, #{alipayTradeNo}, #{qrCode}, #{createTime}, #{updateTime})
|
||||
</insert>
|
||||
|
||||
<select id="selectByOrderNo" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List"/>
|
||||
from pay_order
|
||||
where order_no = #{orderNo}
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<update id="updateQrCodeAndStatus">
|
||||
update pay_order
|
||||
set qr_code = #{qrCode},
|
||||
status = #{status},
|
||||
update_time = now()
|
||||
where order_no = #{orderNo}
|
||||
</update>
|
||||
|
||||
<update id="updatePaidByOrderNo">
|
||||
update pay_order
|
||||
set alipay_trade_no = #{alipayTradeNo},
|
||||
status = #{status},
|
||||
update_time = now()
|
||||
where order_no = #{orderNo}
|
||||
and status != 'SUCCESS'
|
||||
</update>
|
||||
|
||||
<update id="updateStatusByOrderNo">
|
||||
update pay_order
|
||||
set status = #{status},
|
||||
update_time = now()
|
||||
where order_no = #{orderNo}
|
||||
</update>
|
||||
<select id="countSuccessRewardByUserId" resultType="int">
|
||||
select count(1)
|
||||
from pay_order
|
||||
where user_id = #{userId}
|
||||
and status = 'SUCCESS'
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -89,7 +89,7 @@
|
||||
(game_id, m3u8_url, type)
|
||||
values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{gameId}, #{item.url}, #{item.type})
|
||||
(#{gameId}, #{item.m3u8_url}, #{item.type})
|
||||
</foreach>
|
||||
</insert>
|
||||
<delete id="deleteUrlById" parameterType="java.lang.Integer">
|
||||
|
||||
Reference in New Issue
Block a user