身份验证
parent
aa0a5492e3
commit
403b4c34c8
|
@ -2,14 +2,13 @@ package com.group.auth.service.impl;
|
|||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.group.auth.feign.UserService;
|
||||
import com.group.auth.service.AuthService;
|
||||
import com.group.auth.strategy.LoginContext;
|
||||
import com.group.auth.strategy.LoginType;
|
||||
import com.group.common.config.JwtUtils;
|
||||
import com.group.common.constants.JwtConstants;
|
||||
import com.group.common.constants.TokenConstants;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.domin.request.ReqLogin;
|
||||
import com.group.common.redis.RedisCache;
|
||||
import com.group.common.result.R;
|
||||
|
@ -17,7 +16,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.group.auth.strategy;
|
|||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.group.auth.feign.UserService;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.domin.request.ReqLogin;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
|
@ -2,9 +2,8 @@ package com.group.auth.strategy;
|
|||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.group.auth.feign.UserService;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.domin.request.ReqLogin;
|
||||
import com.group.common.handle.BizException;
|
||||
import com.group.common.redis.RedisCache;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.group.auth.strategy;
|
||||
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.domin.request.ReqLogin;
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- bootstrap 启动器 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
|
@ -134,5 +138,15 @@
|
|||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>3.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<version>3.15.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,4 +1,4 @@
|
|||
package com.group.user.pojo;
|
||||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
|
@ -0,0 +1,42 @@
|
|||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 秒杀订单表
|
||||
*/
|
||||
@Data
|
||||
@TableName("t_kill_order")
|
||||
public class KillOrderEntity {
|
||||
/**
|
||||
* 秒杀订单主键
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id ;
|
||||
/**
|
||||
* 秒杀商品id
|
||||
*/
|
||||
private Integer goodsId ;
|
||||
/**
|
||||
* 购买人id
|
||||
*/
|
||||
private Integer userId ;
|
||||
/**
|
||||
* 秒杀订单编号
|
||||
*/
|
||||
private String killId ;
|
||||
/**
|
||||
* 秒杀订单状态 1-未支付 2-支付成功 3-支付失败
|
||||
*/
|
||||
private Integer killState ;
|
||||
/**
|
||||
* 秒杀订单创建时间
|
||||
*/
|
||||
private Date orderCreate ;
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 订单支付详情类
|
||||
*/
|
||||
@TableName("t_pay_detail")
|
||||
@Data
|
||||
@Builder
|
||||
public class PayDetail {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId
|
||||
private Integer payId ;
|
||||
/**
|
||||
* 订单支付金额
|
||||
*/
|
||||
@TableField("pay_title")
|
||||
private BigDecimal payTitle ;
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
@TableField("pay_order")
|
||||
private Integer payOrder ;
|
||||
/**
|
||||
* 支付宝编号
|
||||
*/
|
||||
@TableField("pay_pay")
|
||||
private String payPay ;
|
||||
/**
|
||||
* 明细状态 1-待支付 2-已支付 3-支付失败
|
||||
*/
|
||||
@TableField("pay_state")
|
||||
private Integer payState ;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("pay_create")
|
||||
private Date payCreate ;
|
||||
/**
|
||||
* 支付时间
|
||||
*/
|
||||
@TableField("pay_payed")
|
||||
private Date payPayed ;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.group.user.pojo;
|
||||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
@ -0,0 +1,49 @@
|
|||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 秒杀表
|
||||
|
||||
*
|
||||
* @author song
|
||||
* @email song@gmail.com
|
||||
* @date 2024-04-20 10:24:59
|
||||
*/
|
||||
@Data
|
||||
@TableName("t_seckill")
|
||||
public class SeckillEntity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 秒杀id
|
||||
*/
|
||||
@TableId
|
||||
private Integer seckillId;
|
||||
/**
|
||||
* 商品详情id
|
||||
*/
|
||||
private Integer seckillGoodsDetail;
|
||||
/**
|
||||
* 秒杀活动商品库存
|
||||
*/
|
||||
private String seckillInventory;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date seckillCreate;
|
||||
/**
|
||||
* 秒杀价格
|
||||
*/
|
||||
private BigDecimal seckillPrice;
|
||||
/**
|
||||
* 场次id
|
||||
*/
|
||||
private Integer sessionId;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 场次实体表
|
||||
*/
|
||||
@Data
|
||||
@TableName("t_session")
|
||||
public class SessionEntity {
|
||||
/**
|
||||
* 场次id
|
||||
*/
|
||||
private Integer sessionId;
|
||||
/**
|
||||
* 场次开始id
|
||||
*/
|
||||
private Date sessionBegin;
|
||||
/**
|
||||
* 场次结束id
|
||||
*/
|
||||
private Date sessionEnd;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.group.common.domin;
|
||||
package com.group.common.domin.pojo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
|
@ -29,34 +30,57 @@ public class UserEntity implements Serializable {
|
|||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@TableField("user_name")
|
||||
private String userName;
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
@TableField("user_pwd")
|
||||
private String userPwd;
|
||||
/**
|
||||
* 用户手机
|
||||
*/
|
||||
@TableField("user_phone")
|
||||
private String userPhone;
|
||||
/**
|
||||
* 会员登记
|
||||
*/
|
||||
@TableField("user_honor")
|
||||
private Integer userHonor;
|
||||
/**
|
||||
* 用户余额
|
||||
*/
|
||||
@TableField("user_residue")
|
||||
private BigDecimal userResidue;
|
||||
/**
|
||||
* 用户积分
|
||||
*/
|
||||
@TableField("user_score")
|
||||
private Integer userScore;
|
||||
/**
|
||||
* 用户角色(0-普通用户 1-团长 2-客服)
|
||||
*/
|
||||
@TableField("user_role")
|
||||
private Integer userRole;
|
||||
/**
|
||||
* 用户地址
|
||||
*/
|
||||
@TableField("user_address")
|
||||
private String userAddress;
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
@TableField("user_card")
|
||||
private String userCard;
|
||||
/**
|
||||
* 用户真实姓名
|
||||
*/
|
||||
@TableField("user_real_name")
|
||||
private String userRealName;
|
||||
/**
|
||||
* 用户户籍所在地
|
||||
*/
|
||||
@TableField("user_real_address")
|
||||
private String userRealAddress;
|
||||
|
||||
}
|
|
@ -257,4 +257,11 @@ public class RedisCache {
|
|||
public Collection<String> keys (final String pattern) {
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将键对应的值递减
|
||||
*/
|
||||
public void decreaseKey(String key){
|
||||
redisTemplate.opsForValue().decrement(key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package com.group.common.redis;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* redisson配置类
|
||||
*/
|
||||
@Configuration
|
||||
public class RedissonConfig {
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.group.common.util;
|
||||
|
||||
|
||||
import com.group.common.constants.JwtConstants;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 用户工具类
|
||||
*/
|
||||
public class UserUtil {
|
||||
public static Integer getUserId(HttpServletRequest servletRequest){
|
||||
return Integer.valueOf(servletRequest.getHeader(JwtConstants.DETAILS_USER_ID));
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package com.group.gateway.config;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
|
||||
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @deprecation: 网关限流控件
|
||||
* @author DongZl
|
||||
*/
|
||||
@Configuration
|
||||
public class GatewaySentinelConfig {
|
||||
/**
|
||||
* 查看解析器
|
||||
*/
|
||||
private final List<ViewResolver> viewResolvers;
|
||||
/**
|
||||
* 服务器编解码器配置
|
||||
*/
|
||||
private final ServerCodecConfigurer serverCodecConfigurer;
|
||||
public GatewaySentinelConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider,
|
||||
ServerCodecConfigurer serverCodecConfigurer) {
|
||||
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
|
||||
this.serverCodecConfigurer = serverCodecConfigurer;
|
||||
}
|
||||
/**
|
||||
* Sentinel 网关块异常处理程序
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
|
||||
// 给 Spring Cloud Gateway 注册块异常处理程序。
|
||||
return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化网关配置
|
||||
*/
|
||||
@PostConstruct
|
||||
public void doInit() {
|
||||
initGatewayRules();
|
||||
}
|
||||
/**
|
||||
* 配置限流规则
|
||||
*/
|
||||
private void initGatewayRules() {
|
||||
Set<GatewayFlowRule> rules = new HashSet<>();
|
||||
rules.add(new GatewayFlowRule("cloud-user")
|
||||
// 限流阈值
|
||||
.setCount(1)
|
||||
// 统计时间窗口,单位是秒,默认是 1 秒
|
||||
.setIntervalSec(5)
|
||||
);
|
||||
//添加到限流规则当中
|
||||
GatewayRuleManager.loadRules(rules);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ spring:
|
|||
allow-circular-references: true
|
||||
# 允许定义相同的bean对象 去覆盖原有的
|
||||
allow-bean-definition-overriding: true
|
||||
web-application-type: reactive
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
|
@ -26,4 +27,4 @@ spring:
|
|||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
|
@ -0,0 +1,49 @@
|
|||
package com.group.user.config;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.SelfDTO;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.Console;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 身份检测实现类
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class CheckLifeImpl {
|
||||
|
||||
|
||||
@Value("${song.life.url}")
|
||||
private String httpUrl;
|
||||
|
||||
@Value("${song.appCode}")
|
||||
private String appCode;
|
||||
|
||||
public R checkLife(String url,String motions){
|
||||
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("complexity", "1");
|
||||
params.put("motions", motions);
|
||||
params.put("url", url);
|
||||
String body = HttpRequest.post(httpUrl)
|
||||
.header("Authorization", "APPCODE "+appCode)
|
||||
.form(params)
|
||||
.execute()
|
||||
.body();
|
||||
if (!new JSONObject(body).get("code").equals(200)){
|
||||
return R.error("视频上传不合格,请重新上传");
|
||||
}
|
||||
log.info(body);
|
||||
return R.ok();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package com.group.user.config;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.IdCardPeople;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 身份证照片
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class IdCardConfig {
|
||||
|
||||
@Value("${song.appCode}")
|
||||
private String appCode;
|
||||
|
||||
@Value("${song.card.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${song.card.path}")
|
||||
private String path;
|
||||
|
||||
@Autowired
|
||||
private OssConfig ossConfig;
|
||||
|
||||
public IdCardPeople checkCard(MultipartFile file,String side){
|
||||
|
||||
|
||||
String fileString = ossConfig.upload(file);
|
||||
|
||||
|
||||
//configure配置
|
||||
JSONObject configObj = new JSONObject();
|
||||
configObj.put("side", side);
|
||||
configObj.put("quality_info",false);
|
||||
String config_str = configObj.toString();
|
||||
|
||||
//拼装请求body的json字符串
|
||||
JSONObject requestObj = new JSONObject();
|
||||
requestObj.put("image",fileString);
|
||||
if (!configObj.isEmpty()){
|
||||
requestObj.put("configure",config_str);
|
||||
}
|
||||
String body = requestObj.toString();
|
||||
|
||||
String string = HttpRequest.post(host + path)
|
||||
.header("Authorization", "APPCODE " + appCode)
|
||||
.header("Content-Type", "application/json; charset=UTF-8")
|
||||
.body(body)
|
||||
.execute()
|
||||
.body();
|
||||
log.info(string);
|
||||
|
||||
IdCardPeople idCardPeople = null;
|
||||
try {
|
||||
idCardPeople = JSON.parseObject(string, IdCardPeople.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("身份证格式不对");
|
||||
}
|
||||
return idCardPeople;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package com.group.user.config;
|
||||
|
||||
import com.aliyun.oss.*;
|
||||
import com.aliyun.oss.common.comm.ResponseMessage;
|
||||
import lombok.Data;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.aliyun.oss.common.auth.*;
|
||||
import com.aliyun.oss.model.PutObjectRequest;
|
||||
import com.aliyun.oss.model.PutObjectResult;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* oss相关配置
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class OssConfig {
|
||||
|
||||
@Value("${song.oss.endpoint}")
|
||||
private String endpoint;
|
||||
@Value("${song.oss.accessKeyId}")
|
||||
private String accessKeyId;
|
||||
@Value("${song.oss.secretAccessKey}")
|
||||
private String secretAccessKey;
|
||||
@Value("${song.oss.bucketName}")
|
||||
private String bucketName;
|
||||
@Value("${song.oss.objectName}")
|
||||
private String objectName;
|
||||
|
||||
public String upload(MultipartFile file) {
|
||||
|
||||
try {
|
||||
|
||||
InputStream stream = file.getInputStream();
|
||||
|
||||
String fileName = file.getOriginalFilename();
|
||||
//创建oss实例
|
||||
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, secretAccessKey);
|
||||
|
||||
//上传文件
|
||||
PutObjectRequest request = new PutObjectRequest(bucketName, objectName + fileName, stream);
|
||||
|
||||
ossClient.putObject(request);
|
||||
|
||||
Date date = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 7);
|
||||
|
||||
return ossClient.generatePresignedUrl(bucketName, objectName + fileName, date).toString();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.group.user.config;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.IdCard;
|
||||
import com.group.user.pojo.IdCardEntity;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* 身份证和姓名的正确校验
|
||||
*/
|
||||
@Component
|
||||
@Log4j2
|
||||
public class RealID {
|
||||
|
||||
@Value("${song.check.url}")
|
||||
private String url;
|
||||
|
||||
@Value("${song.appCode}")
|
||||
private String appCode;
|
||||
|
||||
public R checkId(IdCard idCard){
|
||||
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("realName",idCard.getRealName());
|
||||
map.put("cardNo",idCard.getCardNo());
|
||||
|
||||
String body = HttpRequest.post(url)
|
||||
.header("Authorization", "APPCODE " + appCode)
|
||||
.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
.form(map)
|
||||
.execute()
|
||||
.body();
|
||||
if (!new JSONObject(body).get("error_code").equals(0)){
|
||||
return R.error("未通过检测");
|
||||
}
|
||||
IdCardEntity idCardEntity = JSON.parseObject(body, IdCardEntity.class);
|
||||
log.info(idCardEntity);
|
||||
return R.ok().put("data",idCardEntity);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,13 +3,19 @@ package com.group.user.controller;
|
|||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.group.common.result.R;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.user.config.IdCardConfig;
|
||||
import com.group.user.config.OssConfig;
|
||||
import com.group.user.config.RealID;
|
||||
import com.group.user.pojo.IdCard;
|
||||
import com.group.user.pojo.ReqGroup;
|
||||
import com.group.user.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* 用户控制层
|
||||
|
@ -38,6 +44,35 @@ public class UserController {
|
|||
public R getUserByName(@PathVariable String name) {
|
||||
UserEntity user = userService.getOne(new LambdaQueryWrapper<UserEntity>()
|
||||
.eq(UserEntity::getUserName, name));
|
||||
return R.ok().put("data",JSON.toJSONString(user) );
|
||||
return R.ok().put("data", JSON.toJSONString(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* 申请成为团长
|
||||
*/
|
||||
@PostMapping("/apply")
|
||||
public R apply(@RequestBody ReqGroup reqGroup) {
|
||||
|
||||
return userService.apply(reqGroup);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private OssConfig ossConfig;
|
||||
|
||||
/**
|
||||
* 上传视频或者照片
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public R upload(@RequestParam("file") MultipartFile file) {
|
||||
return R.ok().put("data",ossConfig.upload(file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传身份证正面照片获取用户真实姓名和身份证号
|
||||
*/
|
||||
@PostMapping("/getRealName")
|
||||
public R getRealName(@RequestParam("file")MultipartFile file){
|
||||
return userService.getRealName(file);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.group.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.user.pojo.CouponEntity;
|
||||
import com.group.common.domin.pojo.CouponEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.group.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.user.pojo.RegistrationEntity;
|
||||
import com.group.common.domin.pojo.RegistrationEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package com.group.user.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.group.user.pojo;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户实名信息
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
public class IdCard {
|
||||
private String realName;
|
||||
private String cardNo;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.group.user.pojo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 持有人的相关信息
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class IdCardEntity {
|
||||
|
||||
@JsonProperty("error_code")
|
||||
private Integer errorCode;
|
||||
@JsonProperty("reason")
|
||||
private String reason;
|
||||
@JsonProperty("result")
|
||||
private ResultDTO result;
|
||||
@JsonProperty("sn")
|
||||
private String sn;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class ResultDTO {
|
||||
@JsonProperty("realname")
|
||||
private String realname;
|
||||
@JsonProperty("idcard")
|
||||
private String idcard;
|
||||
@JsonProperty("isok")
|
||||
private Boolean isok;
|
||||
@JsonProperty("IdCardInfor")
|
||||
private IdCardInforDTO idCardInfor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class IdCardInforDTO {
|
||||
@JsonProperty("province")
|
||||
private String province;
|
||||
@JsonProperty("city")
|
||||
private String city;
|
||||
@JsonProperty("district")
|
||||
private String district;
|
||||
@JsonProperty("area")
|
||||
private String area;
|
||||
@JsonProperty("sex")
|
||||
private String sex;
|
||||
@JsonProperty("birthday")
|
||||
private String birthday;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.group.user.pojo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 身份证正面信息
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class IdCardPeople {
|
||||
|
||||
@JsonProperty("address")
|
||||
private String address;
|
||||
@JsonProperty("angle")
|
||||
private Integer angle;
|
||||
@JsonProperty("birth")
|
||||
private String birth;
|
||||
@JsonProperty("card_region")
|
||||
private List<CardRegionDTO> cardRegion;
|
||||
@JsonProperty("config_str")
|
||||
private String configStr;
|
||||
@JsonProperty("face_rect")
|
||||
private FaceRectDTO faceRect;
|
||||
@JsonProperty("face_rect_vertices")
|
||||
private List<FaceRectVerticesDTO> faceRectVertices;
|
||||
@JsonProperty("is_fake")
|
||||
private Boolean isFake;
|
||||
@JsonProperty("name")
|
||||
private String name;
|
||||
@JsonProperty("nationality")
|
||||
private String nationality;
|
||||
@JsonProperty("num")
|
||||
private String num;
|
||||
@JsonProperty("request_id")
|
||||
private String requestId;
|
||||
@JsonProperty("sex")
|
||||
private String sex;
|
||||
@JsonProperty("success")
|
||||
private Boolean success;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class FaceRectDTO {
|
||||
@JsonProperty("angle")
|
||||
private Integer angle;
|
||||
@JsonProperty("center")
|
||||
private CenterDTO center;
|
||||
@JsonProperty("size")
|
||||
private SizeDTO size;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class CenterDTO {
|
||||
@JsonProperty("x")
|
||||
private Integer x;
|
||||
@JsonProperty("y")
|
||||
private Integer y;
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class SizeDTO {
|
||||
@JsonProperty("height")
|
||||
private Integer height;
|
||||
@JsonProperty("width")
|
||||
private Integer width;
|
||||
}
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class CardRegionDTO {
|
||||
@JsonProperty("x")
|
||||
private Integer x;
|
||||
@JsonProperty("y")
|
||||
private Integer y;
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class FaceRectVerticesDTO {
|
||||
@JsonProperty("x")
|
||||
private Integer x;
|
||||
@JsonProperty("y")
|
||||
private Integer y;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.group.user.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 团长申请表单
|
||||
*/
|
||||
@Data
|
||||
public class ReqGroup {
|
||||
/**
|
||||
* 活体视频 网址
|
||||
*/
|
||||
private String idCardUrl;
|
||||
/**
|
||||
* 用户真实姓名
|
||||
*/
|
||||
private String realName;
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
private String cardNo;
|
||||
/**
|
||||
* 活体视频 动作
|
||||
*/
|
||||
private String motions;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.group.user.pojo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 视频验证结果
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class SelfDTO {
|
||||
@JsonProperty("msg")
|
||||
private String msg;
|
||||
@JsonProperty("success")
|
||||
private Boolean success;
|
||||
@JsonProperty("code")
|
||||
private Integer code;
|
||||
@JsonProperty("data")
|
||||
private DataDTO data;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class DataDTO {
|
||||
@JsonProperty("order_no")
|
||||
private String orderNo;
|
||||
@JsonProperty("motions")
|
||||
private MotionsDTO motions;
|
||||
@JsonProperty("passed")
|
||||
private Boolean passed;
|
||||
@JsonProperty("feature_image_id")
|
||||
private String featureImageId;
|
||||
@JsonProperty("hack_score")
|
||||
private Double hackScore;
|
||||
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public static class MotionsDTO {
|
||||
@JsonProperty("score")
|
||||
private Double score;
|
||||
@JsonProperty("motion")
|
||||
private String motion;
|
||||
@JsonProperty("passed")
|
||||
private Boolean passed;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package com.group.user.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.CouponEntity;
|
||||
import com.group.common.domin.pojo.CouponEntity;
|
||||
|
||||
/**
|
||||
* 优惠券业务层
|
||||
|
|
|
@ -2,7 +2,7 @@ package com.group.user.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.RegistrationEntity;
|
||||
import com.group.common.domin.pojo.RegistrationEntity;
|
||||
|
||||
/**
|
||||
* 签到服务层
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
package com.group.user.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.pojo.ReqGroup;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* 用户服务层
|
||||
*/
|
||||
public interface UserService extends IService<UserEntity> {
|
||||
|
||||
R getRealName(MultipartFile file);
|
||||
|
||||
R apply(ReqGroup reqGroup);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,16 +4,17 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||
import com.group.common.constants.JwtConstants;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.mapper.CouponMapper;
|
||||
import com.group.user.pojo.CouponEntity;
|
||||
import com.group.common.domin.pojo.CouponEntity;
|
||||
import com.group.user.service.CouponService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 优惠券实现层
|
||||
*/
|
||||
@Service
|
||||
public class CouponServiceImpl extends ServiceImpl<CouponMapper, CouponEntity>
|
||||
implements CouponService {
|
||||
|
||||
|
|
|
@ -3,10 +3,11 @@ package com.group.user.service.impl;
|
|||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.group.common.constants.JwtConstants;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.common.result.R;
|
||||
import com.group.common.util.UserUtil;
|
||||
import com.group.user.mapper.RegistrationMapper;
|
||||
import com.group.user.pojo.RegistrationEntity;
|
||||
import com.group.common.domin.pojo.RegistrationEntity;
|
||||
import com.group.user.service.RegistrationService;
|
||||
import com.group.user.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -34,14 +35,12 @@ public class RegistrationServiceImpl extends ServiceImpl<RegistrationMapper, Reg
|
|||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
private Integer getUserId() {
|
||||
return Integer.valueOf(request.getHeader(JwtConstants.DETAILS_USER_ID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public R sign() {
|
||||
Integer userId = UserUtil.getUserId(request);
|
||||
//通过用户id获取用户对象
|
||||
UserEntity user = userService.getById(getUserId());
|
||||
UserEntity user = userService.getById(userId);
|
||||
// 获取当前日期时间
|
||||
LocalDateTime currentDateTime = LocalDateTime.now();
|
||||
// 获取当前日期的零点时间
|
||||
|
@ -53,7 +52,7 @@ public class RegistrationServiceImpl extends ServiceImpl<RegistrationMapper, Reg
|
|||
Date zero = Date.from(startOfToday.atZone(ZoneId.systemDefault()).toInstant());
|
||||
//获取用户的签到记录
|
||||
List<RegistrationEntity> list = list(new LambdaQueryWrapper<RegistrationEntity>()
|
||||
.eq(RegistrationEntity::getUserId, getUserId())
|
||||
.eq(RegistrationEntity::getUserId, userId)
|
||||
.le(RegistrationEntity::getRegistrationDate, date)
|
||||
.ge(RegistrationEntity::getRegistrationDate, seven));
|
||||
//判断今天是否已经 签到过
|
||||
|
@ -76,7 +75,7 @@ public class RegistrationServiceImpl extends ServiceImpl<RegistrationMapper, Reg
|
|||
save(RegistrationEntity
|
||||
.builder()
|
||||
.registrationDate(new Date())
|
||||
.userId(getUserId())
|
||||
.userId(userId)
|
||||
.registrationScore(num)
|
||||
.build());
|
||||
return R.ok("签到成功");
|
||||
|
|
|
@ -1,10 +1,24 @@
|
|||
package com.group.user.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.group.common.constants.JwtConstants;
|
||||
import com.group.common.result.R;
|
||||
import com.group.user.config.CheckLifeImpl;
|
||||
import com.group.user.config.IdCardConfig;
|
||||
import com.group.user.config.OssConfig;
|
||||
import com.group.user.config.RealID;
|
||||
import com.group.user.mapper.UserMapper;
|
||||
import com.group.common.domin.UserEntity;
|
||||
import com.group.common.domin.pojo.UserEntity;
|
||||
import com.group.user.pojo.*;
|
||||
import com.group.user.service.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.xml.transform.Result;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* 用户业务层
|
||||
|
@ -13,4 +27,76 @@ import org.springframework.stereotype.Service;
|
|||
public class UserServiceImpl extends ServiceImpl<UserMapper, UserEntity>
|
||||
implements UserService {
|
||||
|
||||
@Autowired
|
||||
private CheckLifeImpl checkLife;
|
||||
|
||||
|
||||
@Autowired
|
||||
private IdCardConfig idCardConfig;
|
||||
|
||||
|
||||
@Override
|
||||
public R getRealName(MultipartFile file) {
|
||||
|
||||
IdCardPeople idCardPeople = idCardConfig.checkCard(file, "face");
|
||||
|
||||
IdCard idCard = IdCard.builder()
|
||||
.cardNo(idCardPeople.getNum())
|
||||
.realName(idCardPeople.getName())
|
||||
.build();
|
||||
|
||||
return R.ok().put("data", idCard);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private RealID realID;
|
||||
|
||||
@Override
|
||||
public R apply(ReqGroup reqGroup) {
|
||||
//判断用户是否已经修改状态了
|
||||
Integer id = getId();
|
||||
UserEntity user = getById(id);
|
||||
if (user.getUserRole() == 1) {
|
||||
return R.error("用户已经申请过了,请不要重复申请");
|
||||
}
|
||||
//使用异步进行活体检查
|
||||
//checkLife.checkLife(reqGroup.getIdCardUrl(), reqGroup.getMotions())
|
||||
CompletableFuture<R> future1 =
|
||||
CompletableFuture.supplyAsync(() -> {
|
||||
System.out.println("活体检测");
|
||||
return checkLife.checkLife(reqGroup.getIdCardUrl(), reqGroup.getMotions());
|
||||
}
|
||||
);
|
||||
//使用身份证号和姓名校验身份
|
||||
//realID.checkId(IdCard.builder().realName(reqGroup.getRealName()).cardNo(reqGroup.getCardNo()).build()
|
||||
CompletableFuture<R> future2 =
|
||||
CompletableFuture.supplyAsync(() -> {
|
||||
System.out.println("校验身份");
|
||||
return realID.checkId(IdCard.builder().realName(reqGroup.getRealName()).cardNo(reqGroup.getCardNo()).build());
|
||||
}
|
||||
);
|
||||
R result1 = future1.join();
|
||||
R result2 = future2.join();
|
||||
|
||||
// 在这里处理两个结果的逻辑
|
||||
if (result1.get("code").equals(0) && result2.get("code").equals(0)) {
|
||||
IdCardEntity idCard = (IdCardEntity) result2.get("data");
|
||||
user.setUserRealAddress(idCard.getResult().getIdCardInfor().getArea());
|
||||
user.setUserRealName(reqGroup.getRealName());
|
||||
user.setUserCard(reqGroup.getCardNo());
|
||||
user.setUserRole(1);
|
||||
//修改用户状态
|
||||
updateById(user);
|
||||
} else {
|
||||
return R.error("身份认证失败");
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
private Integer getId() {
|
||||
return Integer.valueOf(request.getHeader(JwtConstants.DETAILS_USER_ID));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
package com.group.user.xxl.config;
|
||||
|
||||
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
/**
|
||||
* xxl-job的配置类
|
||||
*/
|
||||
@ComponentScan(basePackages = "com.group.user.xxl.handle")
|
||||
@Configuration
|
||||
@Log4j2
|
||||
public class JobConfig {
|
||||
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
|
||||
@Value("${xxl.job.executor.appname}")
|
||||
private String appName;
|
||||
|
||||
@Value("${xxl.job.executor.ip}")
|
||||
private String ip;
|
||||
|
||||
@Value("${xxl.job.executor.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${xxl.job.accessToken}")
|
||||
private String accessToken;
|
||||
|
||||
@Value("${xxl.job.executor.logpath}")
|
||||
private String logPath;
|
||||
|
||||
@Value("${xxl.job.executor.logretentiondays}")
|
||||
private int logRetentionDays;
|
||||
|
||||
|
||||
@Bean(initMethod = "start", destroyMethod = "destroy")
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
log.info(">>>>>>>>>>> xxl-job config init.");
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
xxlJobSpringExecutor.setAppname(appName);
|
||||
xxlJobSpringExecutor.setIp(ip);
|
||||
xxlJobSpringExecutor.setPort(port);
|
||||
xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
xxlJobSpringExecutor.setLogPath(logPath);
|
||||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
//package com.group.user.xxl.config;
|
||||
//
|
||||
//import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
|
||||
//import lombok.extern.log4j.Log4j2;
|
||||
//import org.springframework.beans.factory.annotation.Value;
|
||||
//import org.springframework.context.annotation.Bean;
|
||||
//import org.springframework.context.annotation.ComponentScan;
|
||||
//import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
//
|
||||
///**
|
||||
// * xxl-job的配置类
|
||||
// */
|
||||
//@ComponentScan(basePackages = "com.group.user.xxl.handle")
|
||||
//@Configuration
|
||||
//@Log4j2
|
||||
//public class JobConfig {
|
||||
//
|
||||
// @Value("${xxl.job.admin.addresses}")
|
||||
// private String adminAddresses;
|
||||
//
|
||||
// @Value("${xxl.job.executor.appname}")
|
||||
// private String appName;
|
||||
//
|
||||
// @Value("${xxl.job.executor.ip}")
|
||||
// private String ip;
|
||||
//
|
||||
// @Value("${xxl.job.executor.port}")
|
||||
// private int port;
|
||||
//
|
||||
// @Value("${xxl.job.accessToken}")
|
||||
// private String accessToken;
|
||||
//
|
||||
// @Value("${xxl.job.executor.logpath}")
|
||||
// private String logPath;
|
||||
//
|
||||
// @Value("${xxl.job.executor.logretentiondays}")
|
||||
// private int logRetentionDays;
|
||||
//
|
||||
//
|
||||
// @Bean(initMethod = "start", destroyMethod = "destroy")
|
||||
// public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
// log.info(">>>>>>>>>>> xxl-job config init.");
|
||||
// XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
// xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
// xxlJobSpringExecutor.setAppname(appName);
|
||||
// xxlJobSpringExecutor.setIp(ip);
|
||||
// xxlJobSpringExecutor.setPort(port);
|
||||
// xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
// xxlJobSpringExecutor.setLogPath(logPath);
|
||||
// xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
// return xxlJobSpringExecutor;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
package com.group.user.xxl.handle;
|
||||
|
||||
import com.xxl.job.core.context.XxlJobHelper;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* xxl任务执行器
|
||||
*/
|
||||
@Component
|
||||
public class XxlHandle {
|
||||
|
||||
@XxlJob("xxl")
|
||||
public void doSomeThing(){
|
||||
System.out.println("hello");
|
||||
}
|
||||
|
||||
}
|
||||
//package com.group.user.xxl.handle;
|
||||
//
|
||||
//import com.xxl.job.core.context.XxlJobHelper;
|
||||
//import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
//import org.springframework.stereotype.Component;
|
||||
//
|
||||
///**
|
||||
// * xxl任务执行器
|
||||
// */
|
||||
//@Component
|
||||
//public class XxlHandle {
|
||||
//
|
||||
// @XxlJob("xxl")
|
||||
// public void doSomeThing(){
|
||||
// System.out.println("hello");
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
|
||||
|
||||
# log config
|
||||
logging.config=classpath:logback.xml
|
||||
|
||||
|
||||
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
|
||||
xxl.job.admin.addresses=http://127.0.0.1:7070/xxl-job-admin
|
||||
|
||||
### xxl-job, access token
|
||||
xxl.job.accessToken=default_token
|
||||
|
||||
### xxl-job executor appname
|
||||
xxl.job.executor.appname=xxl-job-executor-sample
|
||||
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
|
||||
|
||||
### xxl-job executor server-info
|
||||
xxl.job.executor.ip=
|
||||
xxl.job.executor.port=10001
|
||||
### xxl-job executor log-path
|
||||
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
|
||||
### xxl-job executor log-retention-days
|
||||
xxl.job.executor.logretentiondays=30
|
||||
#
|
||||
#
|
||||
## log config
|
||||
#logging.config=classpath:logback.xml
|
||||
#
|
||||
#
|
||||
#### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
|
||||
#xxl.job.admin.addresses=http://127.0.0.1:7070/xxl-job-admin
|
||||
#
|
||||
#### xxl-job, access token
|
||||
#xxl.job.accessToken=default_token
|
||||
#
|
||||
#### xxl-job executor appname
|
||||
#xxl.job.executor.appname=xxl-job-executor-sample
|
||||
#### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
|
||||
#
|
||||
#### xxl-job executor server-info
|
||||
#xxl.job.executor.ip=
|
||||
#xxl.job.executor.port=10001
|
||||
#### xxl-job executor log-path
|
||||
#xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
|
||||
#### xxl-job executor log-retention-days
|
||||
#xxl.job.executor.logretentiondays=30
|
||||
|
|
|
@ -27,3 +27,27 @@ spring:
|
|||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 10MB
|
||||
max-request-size: 10MB
|
||||
|
||||
|
||||
song:
|
||||
life:
|
||||
url: https://life.shumaidata.com/checklife
|
||||
appCode: 5becad81f5c64b36a883ad8c7b66fa66
|
||||
oss:
|
||||
endpoint: oss-cn-shanghai.aliyuncs.com
|
||||
accessKeyId: LTAI5tEhxBCDjWFy6D2SEX3y
|
||||
secretAccessKey: gw5SQHr5T0P2UkCLYiAfgOxBwOpTTN
|
||||
bucketName: song-mp4
|
||||
objectName: mp4/
|
||||
card:
|
||||
host: https://cardnumber.market.alicloudapi.com
|
||||
path: /rest/160601/ocr/ocr_idcard.json
|
||||
check:
|
||||
url: https://zidv2.market.alicloudapi.com/idcheck/Post
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<description>商品模块</description>
|
||||
<parent>
|
||||
<groupId>com.song</groupId>
|
||||
<artifactId>group-module</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>group_goods</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.song</groupId>
|
||||
<artifactId>group-common</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,16 @@
|
|||
package com.group.goods;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* 商品模块启动类
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients("com.group")
|
||||
public class GoodsApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GoodsApplication.class,args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.group.goods.controller;
|
||||
|
||||
import com.group.common.result.R;
|
||||
import com.group.goods.service.SecKillService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 秒杀商品控制层
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/goods/secKill")
|
||||
public class SecKillController {
|
||||
|
||||
@Autowired
|
||||
private SecKillService secKillService;
|
||||
|
||||
/**
|
||||
* 秒杀商品 - 采用最简单方式进行实现
|
||||
*/
|
||||
@GetMapping("/buyGoodsByOne/{id}")
|
||||
public R buyGoodsByOne(@PathVariable("id")Integer id){
|
||||
return secKillService.buyGoodsByOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀方式 -- 采用降低锁粒度的方式实现
|
||||
*/
|
||||
|
||||
/**
|
||||
* 秒杀商品 -- 采用redisson信号量的方式进行解决这个问题
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.goods.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 场次信息控制层
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/session")
|
||||
public class SessionController {
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.group.goods.feign;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 远程调用秒杀订单方法
|
||||
*/
|
||||
@FeignClient(name = "song-order",path = "/order")
|
||||
public interface KillOrderService {
|
||||
|
||||
@GetMapping("/killOrder/exitResult")
|
||||
public boolean exitResult(@RequestParam Integer goodsId, Integer userId);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.goods.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.common.domin.pojo.SeckillEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 秒杀商品持久层
|
||||
*/
|
||||
@Mapper
|
||||
public interface SecKillMapper extends BaseMapper<SeckillEntity> {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.goods.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.common.domin.pojo.SessionEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* session持久层
|
||||
*/
|
||||
@Mapper
|
||||
public interface SessionMapper extends BaseMapper<SessionEntity> {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.goods.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.domin.pojo.SeckillEntity;
|
||||
import com.group.common.result.R;
|
||||
|
||||
/**
|
||||
* 秒杀商品服务层
|
||||
*/
|
||||
public interface SecKillService extends IService<SeckillEntity> {
|
||||
R buyGoodsByOne(Integer id);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.group.goods.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.domin.pojo.SessionEntity;
|
||||
|
||||
/**
|
||||
* 场次服务层
|
||||
*/
|
||||
public interface SessionService extends IService<SessionEntity> {
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.group.goods.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.group.common.domin.pojo.KillOrderEntity;
|
||||
import com.group.common.domin.pojo.SessionEntity;
|
||||
import com.group.common.redis.RedisCache;
|
||||
import com.group.common.result.R;
|
||||
import com.group.common.util.UserUtil;
|
||||
import com.group.goods.feign.KillOrderService;
|
||||
import com.group.goods.mapper.SecKillMapper;
|
||||
import com.group.common.domin.pojo.SeckillEntity;
|
||||
import com.group.goods.service.SecKillService;
|
||||
import com.group.goods.service.SessionService;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RLock;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 秒杀商品业务层
|
||||
*/
|
||||
public class SecKillServiceImpl extends ServiceImpl<SecKillMapper, SeckillEntity>
|
||||
implements SecKillService {
|
||||
|
||||
/**
|
||||
* 场次信息数据获取
|
||||
*/
|
||||
@Autowired
|
||||
private SessionService sessionService;
|
||||
|
||||
@Autowired
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Autowired
|
||||
private KillOrderService killOrderService;
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Autowired
|
||||
private Redisson redisson;
|
||||
|
||||
@Override
|
||||
public R buyGoodsByOne(Integer id) {
|
||||
//通过商品id获取商品信息
|
||||
//获取redis中的所有数据
|
||||
List<SeckillEntity> list = redisCache.getCacheList("secKill");
|
||||
SeckillEntity secKill = list.stream().filter(c -> c.getSeckillId().equals(id)).collect(Collectors.toList()).get(0);
|
||||
//首先校验该商品是否在当前时间段
|
||||
//通过场次id获取商品场次的信息
|
||||
SessionEntity session = sessionService.getById(secKill.getSessionId());
|
||||
//当前时间毫秒值
|
||||
long time = new Date().getTime();
|
||||
if (session.getSessionBegin().getTime()>time){
|
||||
throw new RuntimeException("场次尚未开始");
|
||||
}
|
||||
if (session.getSessionEnd().getTime()<time){
|
||||
throw new RuntimeException("该场次已经结束");
|
||||
}
|
||||
RLock lock = redisson.getLock("productId:" + id);
|
||||
|
||||
//校验用户是否购买过
|
||||
//获取用户id
|
||||
Integer userId = UserUtil.getUserId(request);
|
||||
//通过用户id和秒杀商品id,查询该用户是否第一次购买该商品
|
||||
if (killOrderService.exitResult(id,userId)){
|
||||
throw new RuntimeException("用户已购买该商品");
|
||||
}
|
||||
//根据id查询秒杀商品信息,判断库存是否足够
|
||||
//库存信息存储在redis中,通过键"product_id:"+goods_id 来存储,通过键来获取商品库存
|
||||
|
||||
Integer stock = redisCache.getCacheObject("product_id:" + id);
|
||||
if (stock<=0){
|
||||
throw new RuntimeException("库存不足,请不要再次点击");
|
||||
}
|
||||
//减少库存,把数据同步到数据库和redis中
|
||||
redisCache.decreaseKey("product_id:"+id);
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.group.goods.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.group.common.domin.pojo.SessionEntity;
|
||||
import com.group.goods.mapper.SessionMapper;
|
||||
import com.group.goods.service.SessionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 场次信息业务层
|
||||
*/
|
||||
@Service
|
||||
public class SessionServiceImpl extends ServiceImpl<SessionMapper, SessionEntity>
|
||||
implements SessionService {
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9004
|
||||
# Spring
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true
|
||||
jackson:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
time-zone: GMT+8
|
||||
application:
|
||||
# 应用名称
|
||||
name: song-goods
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 124.221.178.252:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 124.221.178.252:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<description>订单模块</description>
|
||||
<parent>
|
||||
<groupId>com.song</groupId>
|
||||
<artifactId>group-module</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>group_order</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.song</groupId>
|
||||
<artifactId>group-common</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -0,0 +1,14 @@
|
|||
package com.group.order;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* 订单模块启动类
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class OrderApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(OrderApplication.class,args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.group.order.config;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.alipay.api.AlipayApiException;
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.request.AlipayTradePagePayRequest;
|
||||
import com.song.order.entity.PayEntity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 支付宝封装工具
|
||||
*/
|
||||
@Component
|
||||
public class AliPay {
|
||||
|
||||
@Autowired
|
||||
private AlipayClient alipayClient;
|
||||
|
||||
@Autowired
|
||||
private AliPayConfig aliPayConfig;
|
||||
|
||||
public void pay(PayEntity payEntity, HttpServletResponse response) {
|
||||
AlipayTradePagePayRequest request = getAlipayTradePagePayRequest(payEntity);
|
||||
// 执行请求,拿到响应的结果,返回给浏览器
|
||||
String form = "";
|
||||
try {
|
||||
form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
|
||||
} catch (AlipayApiException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
response.setContentType("text/html;charset=" + aliPayConfig.getCharset());
|
||||
try {
|
||||
response.getWriter().write(form);// 直接将完整的表单html输出到页面
|
||||
response.getWriter().flush();
|
||||
response.getWriter().close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private AlipayTradePagePayRequest getAlipayTradePagePayRequest(PayEntity payEntity) {
|
||||
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
|
||||
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
|
||||
JSONObject bizContent = new JSONObject();
|
||||
bizContent.set("out_trade_no", payEntity.getPayId()); // 我们自己生成的订单编号
|
||||
bizContent.set("total_amount", payEntity.getPrice()); // 订单的总金额
|
||||
bizContent.set("subject", payEntity.getOrderTitle()); // 支付的名称
|
||||
bizContent.set("product_code", aliPayConfig.getProductCode());
|
||||
request.setBizContent(bizContent.toString());
|
||||
request.setReturnUrl(aliPayConfig.getReturnUrl());// 支付完成后自动跳转到本地页面的路径
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.group.order.config;
|
||||
|
||||
import com.alipay.api.AlipayClient;
|
||||
import com.alipay.api.DefaultAlipayClient;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "alipay")
|
||||
public class AliPayConfig {
|
||||
|
||||
// 支付宝的AppId
|
||||
private String appId;
|
||||
// 应用私钥
|
||||
private String appPrivateKey;
|
||||
// 支付宝公钥
|
||||
private String alipayPublicKey;
|
||||
// 支付宝通知本地的接口完整地址
|
||||
private String notifyUrl;
|
||||
//支付宝跳转的地址
|
||||
private String gatewayUrl ;
|
||||
private String format;
|
||||
private String charset;
|
||||
//签名方式
|
||||
private String signType;
|
||||
//回调本地地址
|
||||
private String returnUrl;
|
||||
|
||||
private String productCode;
|
||||
|
||||
@Bean
|
||||
public AlipayClient alipayClient(){
|
||||
return new DefaultAlipayClient(gatewayUrl,appId,appPrivateKey,format,charset,alipayPublicKey,signType);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.group.order.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* 跨域配置
|
||||
*/
|
||||
@Configuration
|
||||
public class CorsConfig {
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
|
||||
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
|
||||
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
|
||||
source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置
|
||||
return new CorsFilter(source);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.group.order.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.group.common.domin.pojo.KillOrderEntity;
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import com.group.common.result.R;
|
||||
import com.group.order.payMethod.PayContext;
|
||||
import com.group.order.payMethod.PayType;
|
||||
import com.group.order.pojo.ReqPay;
|
||||
import com.group.order.service.KillOrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 秒杀订单控制层
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/order/killOrder")
|
||||
public class KillOrderController {
|
||||
|
||||
@Autowired
|
||||
private KillOrderService killOrderService;
|
||||
|
||||
/**
|
||||
* 利用商品id和用户id查询有购买记录
|
||||
* 如果结果为false,证明该商品未被该用户购买
|
||||
* 如果为true,证明该用户已经购买过该商品
|
||||
*/
|
||||
@GetMapping("/exitResult")
|
||||
public boolean exitResult(@RequestParam Integer goodsId,Integer userId){
|
||||
KillOrderEntity one = killOrderService.getOne(new LambdaQueryWrapper<KillOrderEntity>()
|
||||
.eq(KillOrderEntity::getGoodsId, goodsId)
|
||||
.eq(KillOrderEntity::getUserId, userId));
|
||||
return one != null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 支付秒杀订单
|
||||
*/
|
||||
@PostMapping("/payKill")
|
||||
public R payKill(@RequestBody ReqPay pay){
|
||||
return killOrderService.payKill(pay);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private PayContext payContext;
|
||||
|
||||
/**
|
||||
* 测试支付模式
|
||||
*/
|
||||
@GetMapping("/test")
|
||||
public R test(@RequestParam Integer type){
|
||||
// PayType pay = payContext.getPay(type);
|
||||
// pay.pay(PayDetail.builder().build());
|
||||
return R.ok("支付成功");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.order.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.common.domin.pojo.KillOrderEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 秒杀订单持久层
|
||||
*/
|
||||
@Mapper
|
||||
public interface KillOrderMapper extends BaseMapper<KillOrderEntity> {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.group.order.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 订单详情持久层
|
||||
*/
|
||||
@Mapper
|
||||
public interface PayDetailMapper extends BaseMapper<PayDetail> {
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 支付宝支付
|
||||
*/
|
||||
@Component
|
||||
public class AliPay implements PayType {
|
||||
@Override
|
||||
public void pay(PayDetail payDetail) {
|
||||
System.out.println("支付宝支付");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return PayEnum.BYALI.getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 银行卡支付
|
||||
*/
|
||||
@Component
|
||||
public class CardPay implements PayType{
|
||||
@Override
|
||||
public void pay(PayDetail payDetail) {
|
||||
System.out.println("银行卡支付");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return PayEnum.BYCARD.getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 支付上下文
|
||||
*/
|
||||
@Component
|
||||
public class PayContext implements InitializingBean, ApplicationContextAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
Map<String,PayType> map = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
applicationContext.getBeansOfType(PayType.class).values()
|
||||
.stream().forEach(type->map.put(type.getName(),type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext=applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过不同的类型数据获取不同的方法
|
||||
*/
|
||||
public PayType getPay(Integer type){
|
||||
String payType=null;
|
||||
if (type==1){
|
||||
payType=PayEnum.BYALI.getName();
|
||||
}
|
||||
if (type==2){
|
||||
payType=PayEnum.BYWECHAT.getName();
|
||||
}
|
||||
if (type==3){
|
||||
payType=PayEnum.BYCARD.getName();
|
||||
}
|
||||
return map.getOrDefault(payType,new AliPay());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 支付类型的枚举
|
||||
*/
|
||||
public enum PayEnum {
|
||||
BYALI(1,"by_ali"),
|
||||
BYWECHAT(2,"by_wechat"),
|
||||
BYCARD(3,"by_card");
|
||||
|
||||
private Integer type;
|
||||
|
||||
@Getter
|
||||
private String name;
|
||||
|
||||
PayEnum(Integer type, String name) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import com.group.common.result.R;
|
||||
|
||||
/**
|
||||
* 抽象接口
|
||||
*/
|
||||
public interface PayType {
|
||||
|
||||
public void pay(PayDetail payDetail);
|
||||
|
||||
public String getName();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.group.order.payMethod;
|
||||
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*微信支付
|
||||
*/
|
||||
@Component
|
||||
public class WeChat implements PayType{
|
||||
@Override
|
||||
public void pay(PayDetail payDetail) {
|
||||
System.out.println("微信支付");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return PayEnum.BYWECHAT.getName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.group.order.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 请求支付类
|
||||
*/
|
||||
@Data
|
||||
public class ReqPay {
|
||||
/**
|
||||
* 订单id
|
||||
*/
|
||||
private Integer orderId;
|
||||
/**
|
||||
* 支付金额
|
||||
*/
|
||||
private BigDecimal price;
|
||||
/**
|
||||
* 支付类型 1-支付宝 2-微信 3-银行卡
|
||||
*/
|
||||
private Integer type;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.group.order.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.group.common.domin.pojo.KillOrderEntity;
|
||||
import com.group.common.result.R;
|
||||
import com.group.order.pojo.ReqPay;
|
||||
|
||||
/**
|
||||
* 秒杀订单服务层
|
||||
*/
|
||||
public interface KillOrderService extends IService<KillOrderEntity> {
|
||||
R payKill(ReqPay pay);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.group.order.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.group.common.domin.pojo.KillOrderEntity;
|
||||
|
||||
import com.group.common.domin.pojo.PayDetail;
|
||||
import com.group.common.result.R;
|
||||
import com.group.order.mapper.KillOrderMapper;
|
||||
import com.group.order.mapper.PayDetailMapper;
|
||||
import com.group.order.payMethod.PayContext;
|
||||
import com.group.order.payMethod.PayType;
|
||||
import com.group.order.pojo.ReqPay;
|
||||
import com.group.order.service.KillOrderService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 秒杀订单实现层
|
||||
*/
|
||||
@Service
|
||||
public class KillOrderServiceImpl extends ServiceImpl<KillOrderMapper, KillOrderEntity>
|
||||
implements KillOrderService {
|
||||
|
||||
@Autowired
|
||||
private PayDetailMapper payDetailMapper;
|
||||
|
||||
@Autowired
|
||||
private PayContext payContext;
|
||||
|
||||
@Override
|
||||
public R payKill(ReqPay pay) {
|
||||
//安全校验
|
||||
//防止幂等性
|
||||
KillOrderEntity order = getById(pay.getOrderId());
|
||||
if (order.getKillState()!=1){
|
||||
return R.error("订单已经支付,请不要重复支付");
|
||||
}
|
||||
//生成详细支付订单
|
||||
PayDetail payDetail = PayDetail.builder()
|
||||
.payPay(IdUtil.getSnowflakeNextIdStr())
|
||||
.payOrder(pay.getOrderId())
|
||||
.payCreate(new Date())
|
||||
.payTitle(pay.getPrice())
|
||||
.build();
|
||||
payDetailMapper.insert(payDetail);
|
||||
PayType pay1 = payContext.getPay(pay.getType());
|
||||
pay1.pay(payDetail);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9004
|
||||
# Spring
|
||||
spring:
|
||||
main:
|
||||
allow-circular-references: true
|
||||
jackson:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
time-zone: GMT+8
|
||||
application:
|
||||
# 应用名称
|
||||
name: song-order
|
||||
profiles:
|
||||
# 环境配置
|
||||
active: dev
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
# 服务注册地址
|
||||
server-addr: 124.221.178.252:8848
|
||||
config:
|
||||
# 配置中心地址
|
||||
server-addr: 124.221.178.252:8848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 10MB
|
||||
max-request-size: 10MB
|
||||
|
||||
|
||||
song:
|
||||
life:
|
||||
url: https://life.shumaidata.com/checklife
|
||||
appCode: 5becad81f5c64b36a883ad8c7b66fa66
|
||||
oss:
|
||||
endpoint: oss-cn-shanghai.aliyuncs.com
|
||||
accessKeyId: LTAI5tEhxBCDjWFy6D2SEX3y
|
||||
secretAccessKey: gw5SQHr5T0P2UkCLYiAfgOxBwOpTTN
|
||||
bucketName: song-mp4
|
||||
objectName: mp4/
|
||||
card:
|
||||
host: https://cardnumber.market.alicloudapi.com
|
||||
path: /rest/160601/ocr/ocr_idcard.json
|
||||
check:
|
||||
url: https://zidv2.market.alicloudapi.com/idcheck/Post
|
||||
|
||||
|
||||
|
|
@ -14,6 +14,8 @@
|
|||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>group-user</module>
|
||||
<module>group_order</module>
|
||||
<module>group_goods</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
Loading…
Reference in New Issue