package com.webchat.pay.service; import com.webchat.common.bean.APIPageResponseBean; import com.webchat.common.constants.WebConstant; import com.webchat.common.enums.CommonStatusEnum; import com.webchat.common.enums.RedisKeyEnum; import com.webchat.common.service.RedisService; import com.webchat.common.util.AkSkGenerator; import com.webchat.common.util.JsonUtil; import com.webchat.domain.vo.dto.payment.AppAkSkDTO; import com.webchat.domain.vo.request.payment.CreateAppRequestVO; import com.webchat.domain.vo.response.payment.AppBaseResponseVO; import com.webchat.domain.vo.response.payment.CreateAppResponseVO; import com.webchat.pay.repository.dao.IAppDAO; import com.webchat.pay.repository.entity.AppEntity; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @Service public class PaymentAppService { @Autowired private IAppDAO appDAO; @Autowired private RedisService redisService; @Autowired private AccountService accountService; /** * 获取接入方访问凭证,走redis * * @param appId * @return */ public AppAkSkDTO getAppAkSk(Long appId) { String akskCacheKey = RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getKey(); String cache = redisService.hget(akskCacheKey, String.valueOf(appId)); if (StringUtils.isNotBlank(cache)) { return JsonUtil.fromJson(cache, AppAkSkDTO.class); } return this.refreshAppAkSkCache(appId); } /** * 查询应用详情信息,走redis * * @param appId * @return */ public AppBaseResponseVO appInfo(Long appId) { String appCacheKey = this.appCacheKey(appId); String cache = redisService.get(appCacheKey); if (StringUtils.isNotBlank(cache)) { return JsonUtil.fromJson(cache, AppBaseResponseVO.class); } // 缓存防止击穿 String defaultCache = redisService.get(defaultAppCacheKey(appId)); if (ObjectUtils.equals(defaultCache, WebConstant.CACHE_NONE)) { return null; } AppBaseResponseVO appBase = this.refreshAppInfoCache(appId); if (appBase == null) { this.setDefaultAppCache(appId); } return appBase; } /** * 创建应用,接入支付平台 * * @param createAppRequest * @return */ public CreateAppResponseVO saveApp(CreateAppRequestVO createAppRequest) { /** * 1. 持久化:创建 Or 更新 */ boolean isFirstCreate = createAppRequest.getId() == null; AppEntity appEntity = convert(createAppRequest); String sk = null; if (isFirstCreate) { /** * 首次创建为应用生成支付凭证 */ String ak = AkSkGenerator.generateAk(); sk = AkSkGenerator.generateSk(); String secretHashKey = AkSkGenerator.hashKey(sk); appEntity.setAccessKey(ak); appEntity.setSecretHashKey(secretHashKey); } appEntity = appDAO.save(appEntity); /** * 2. 创建缓存 */ this.createOrUpdateRedisCache(appEntity); /** * 3. 构造应用信息页面响应VO */ AppBaseResponseVO appBaseResponseVO = covertResponseVo(appEntity);; CreateAppResponseVO createAppResponseVO = new CreateAppResponseVO(); BeanUtils.copyProperties(appBaseResponseVO, createAppResponseVO); createAppResponseVO.setSecretKey(sk); createAppResponseVO.setAdminInfo(accountService.accountInfo(appEntity.getAdmin())); return createAppResponseVO; } /** * 发布应用 * @param appId */ public void publishApp(Long appId) { this.updateAppStatus(appId, CommonStatusEnum.PUBLISHED); } /** * 删除应用 * @param appId */ public void deleteApp(Long appId) { this.updateAppStatus(appId, CommonStatusEnum.DELETED); } private void updateAppStatus(Long appId, CommonStatusEnum status) { AppEntity appEntity = appDAO.findById(appId).orElse(null); Assert.notNull(appEntity, "状态修改失败: 应用不存在"); appEntity.setStatus(status.getStatusCode()); appDAO.save(appEntity); // 刷新应用详情信息缓存 this.refreshAppInfoCache(appEntity); } /** * 查询应用列表 * * @param keywords * @param pageNo * @param pageSize * @return */ public APIPageResponseBean page(String keywords, Integer pageNo, Integer pageSize) { Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id")); List statusList = new ArrayList<>(); statusList.add(CommonStatusEnum.NEW.getStatusCode()); statusList.add(CommonStatusEnum.PUBLISHED.getStatusCode()); Page appEntities; if (StringUtils.isBlank(keywords)) { appEntities = appDAO.findAllByStatusIn(statusList, pageable); } else { appEntities = appDAO.findAllByNameLikeAndStatusIn("%" + keywords + "%", statusList, pageable); } List vos = new ArrayList<>(); if (appEntities != null && CollectionUtils.isNotEmpty(appEntities.getContent())) { vos = appEntities.getContent().stream().map(this::covertResponseVo).collect(Collectors.toList()); } return APIPageResponseBean.success(pageNo, pageSize, appEntities.getTotalElements(), vos); } private AppBaseResponseVO covertResponseVo(AppEntity appEntity) { AppBaseResponseVO response = new AppBaseResponseVO(); BeanUtils.copyProperties(appEntity, response); return response; } /** * 创建或者更新应用信息Redis缓存 */ private void createOrUpdateRedisCache(AppEntity appEntity) { // 1. 刷新应用最新详情缓存 this.refreshAppInfoCache(appEntity); // 2. 创建或更新AK-SK缓存 this.refreshAppAkSkCache(appEntity.getId(), appEntity.getAccessKey(), appEntity.getSecretHashKey()); } /** * 刷新应用访问支付平台凭证缓存 * * @param appId * @return */ private AppAkSkDTO refreshAppAkSkCache(Long appId) { AppEntity app = appDAO.findById(appId).orElse(null); return this.refreshAppAkSkCache(app.getId(), app.getAccessKey(), app.getSecretHashKey()); } private AppAkSkDTO refreshAppAkSkCache(Long appId, String accessKey, String secretHashKey) { String akskCacheKey = RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getKey(); AppAkSkDTO appAkSkDTO = new AppAkSkDTO(accessKey, secretHashKey); redisService.hset(akskCacheKey, String.valueOf(appId), JsonUtil.toJsonString(appAkSkDTO), RedisKeyEnum.PAYMENT_APP_AK_SK_CACHE.getExpireTime()); return appAkSkDTO; } private void setDefaultAppCache(Long appId) { String defaultKey = this.defaultAppCacheKey(appId); redisService.set(defaultKey, WebConstant.CACHE_NONE, RedisKeyEnum.PAYMENT_DEFAULT_APP_INFO_CACHE.getExpireTime()); } private AppBaseResponseVO refreshAppInfoCache(Long appId) { AppEntity appEntity = appDAO.findById(appId).orElse(null); return this.refreshAppInfoCache(appEntity); } /** * 刷新应用信息详情缓存 * * @param appEntity * @return */ private AppBaseResponseVO refreshAppInfoCache(AppEntity appEntity) { if (appEntity == null) { return null; } AppBaseResponseVO appBaseResponseVO = this.covertResponseVo(appEntity); String appCacheKey = this.appCacheKey(appEntity.getId()); redisService.set(appCacheKey, JsonUtil.toJsonString(appBaseResponseVO), RedisKeyEnum.PAYMENT_APP_INFO_CACHE.getExpireTime()); return appBaseResponseVO; } private String defaultAppCacheKey(Long appId) { return RedisKeyEnum.PAYMENT_DEFAULT_APP_INFO_CACHE.getKey(String.valueOf(appId)); } private String appCacheKey(Long appId) { return RedisKeyEnum.PAYMENT_APP_INFO_CACHE.getKey(String.valueOf(appId)); } private AppEntity convert(CreateAppRequestVO createAppRequest) { AppEntity appEntity; if (createAppRequest.getId() != null) { appEntity = appDAO.findById(createAppRequest.getId()).orElse(null); Assert.notNull(appEntity, "应用信息更新失败:应用不存在!"); } else { appEntity = new AppEntity(); appEntity.setAdmin(createAppRequest.getUserId()); appEntity.setCreateBy(createAppRequest.getUserId()); // 后面改成默认新建状态 appEntity.setStatus(CommonStatusEnum.NEW.getStatusCode()); } appEntity.setLogo(createAppRequest.getLogo()); appEntity.setName(createAppRequest.getName()); appEntity.setDescription(createAppRequest.getDescription()); appEntity.setUpdateBy(createAppRequest.getUserId()); return appEntity; } }